summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNico Huber <nico.huber@secunet.com>2013-06-17 17:47:24 +0200
committerStefan Reinauer <stefan.reinauer@coreboot.org>2013-06-17 21:32:42 +0200
commita00f9830fb58d3f5061aab71be8553f3ff2e1f70 (patch)
tree1907be0e8aad2a92044aa14ebcefba5fecee5f88
parent3cc151ede0677776f891c959568b92a79b9ecd9a (diff)
libpayload: ahci: Fix command engine shutdown
A timeout while waiting for a device' signature has shown that our error path wasn't correct. The shutdown of the ports command engine always timed out. Fix that by waiting for FR (FIS Receive Running) to be cleared independently from CR (Command List Running) and after clearing FRE (FIS Receive Enable). Change-Id: I50edf426ef0241424456f1489a7fc86a2cfc5753 Signed-off-by: Nico Huber <nico.huber@secunet.com> Reviewed-on: http://review.coreboot.org/3494 Tested-by: build bot (Jenkins) Reviewed-by: Paul Menzel <paulepanter@users.sourceforge.net> Reviewed-by: Marc Jones <marc.jones@se-eng.com> Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
-rw-r--r--payloads/libpayload/drivers/storage/ahci.c17
1 files changed, 14 insertions, 3 deletions
diff --git a/payloads/libpayload/drivers/storage/ahci.c b/payloads/libpayload/drivers/storage/ahci.c
index 72acd0b799..2b33b599f9 100644
--- a/payloads/libpayload/drivers/storage/ahci.c
+++ b/payloads/libpayload/drivers/storage/ahci.c
@@ -73,7 +73,7 @@ static inline int ahci_port_is_active(const hba_port_t *const port)
static int ahci_cmdengine_start(hba_port_t *const port)
{
- /* Wait for the controller to clear CR.
+ /* CR has to be clear before starting the command engine.
This shouldn't take too long, but we should time out nevertheless. */
int timeout = 1000; /* Time out after 1000 * 1us == 1ms. */
while ((port->cmd_stat & HBA_PxCMD_CR) && timeout--)
@@ -92,10 +92,10 @@ static int ahci_cmdengine_stop(hba_port_t *const port)
{
port->cmd_stat &= ~HBA_PxCMD_ST;
- /* Wait for the controller to clear FR and CR.
+ /* Wait for the controller to clear CR.
This shouldn't take too long, but we should time out nevertheless. */
int timeout = 1000; /* Time out after 1000 * 1us == 1ms. */
- while ((port->cmd_stat & (HBA_PxCMD_FR | HBA_PxCMD_CR)) && timeout--)
+ while ((port->cmd_stat & HBA_PxCMD_CR) && timeout--)
udelay(1);
if (timeout < 0) {
printf("ahci: Timeout during stopping of command engine.\n");
@@ -103,6 +103,17 @@ static int ahci_cmdengine_stop(hba_port_t *const port)
}
port->cmd_stat &= ~HBA_PxCMD_FRE;
+
+ /* Wait for the controller to clear FR.
+ This shouldn't take too long, but we should time out nevertheless. */
+ timeout = 1000; /* Time out after 1000 * 1us == 1ms. */
+ while ((port->cmd_stat & HBA_PxCMD_FR) && timeout--)
+ udelay(1);
+ if (timeout < 0) {
+ printf("ahci: Timeout during stopping of command engine.\n");
+ return 1;
+ }
+
return 0;
}