ahci: centralize, fix port reset

This commit is contained in:
David van Moolenbroek 2013-02-12 13:52:52 +00:00
parent f2de719cfe
commit ad0b58fe83
2 changed files with 25 additions and 11 deletions

View File

@ -1192,6 +1192,21 @@ static ssize_t port_transfer(struct port_state *ps, u64_t pos, u64_t eof,
return size;
}
/*===========================================================================*
* port_hardreset *
*===========================================================================*/
static void port_hardreset(struct port_state *ps)
{
/* Perform a port-level (hard) reset on the given port.
*/
port_write(ps, AHCI_PORT_SCTL, AHCI_PORT_SCTL_DET_INIT);
micro_delay(COMRESET_DELAY * 1000); /* COMRESET_DELAY is in ms */
port_write(ps, AHCI_PORT_SCTL, AHCI_PORT_SCTL_DET_NONE);
}
/*===========================================================================*
* port_start *
*===========================================================================*/
@ -1242,20 +1257,18 @@ static void port_restart(struct port_state *ps)
dprintf(V_ERR, ("%s: port reset\n", ahci_portname(ps)));
/* Trigger a port reset. */
port_write(ps, AHCI_PORT_SCTL, AHCI_PORT_SCTL_DET_INIT);
micro_delay(SPINUP_DELAY * 1000);
port_write(ps, AHCI_PORT_SCTL, AHCI_PORT_SCTL_DET_NONE);
/* To keep this driver simple, we do not transparently recover
* ongoing requests. Instead, we mark the failing device as
* disconnected, and assume that if the reset succeeds, the
* disconnected, and reset it. If the reset succeeds, the
* device (or, perhaps, eventually, another device) will come
* back up. Any current and future requests to this port will
* be failed until the port is fully closed and reopened.
*/
port_disconnect(ps);
/* Trigger a port reset. */
port_hardreset(ps);
return;
}
@ -1907,13 +1920,14 @@ static void port_init(struct port_state *ps)
/* Just listen for device status change events for now. */
port_write(ps, AHCI_PORT_IE, AHCI_PORT_IE_PRCE);
/* Perform a reset on the device. */
/* Enable device spin-up for HBAs that support staggered spin-up.
* This is a no-op for HBAs that do not support it.
*/
cmd = port_read(ps, AHCI_PORT_CMD);
port_write(ps, AHCI_PORT_CMD, cmd | AHCI_PORT_CMD_SUD);
port_write(ps, AHCI_PORT_SCTL, AHCI_PORT_SCTL_DET_INIT);
micro_delay(SPINUP_DELAY * 1000); /* SPINUP_DELAY is in ms */
port_write(ps, AHCI_PORT_SCTL, AHCI_PORT_SCTL_DET_NONE);
/* Trigger a port reset. */
port_hardreset(ps);
set_timer(&ps->cmd_info[0].timer, ahci_spinup_timeout,
port_timeout, BUILD_ARG(ps - port_state, 0));

View File

@ -15,7 +15,7 @@
#define FLUSH_TIMEOUT 60000 /* time to wait for flush cmd (ms) */
/* Time values that are defined by the standards. */
#define SPINUP_DELAY 1 /* time to assert spin-up flag (ms) */
#define COMRESET_DELAY 1 /* time to assert port reset (ms) */
#define RESET_DELAY 1000 /* maximum HBA reset time (ms) */
#define PORTREG_DELAY 500 /* maximum port register update (ms) */