ahci: use macros to access HBA and port registers
This commit is contained in:
parent
de57a53027
commit
3c55fcbc13
1 changed files with 76 additions and 74 deletions
|
@ -124,6 +124,9 @@ static struct {
|
||||||
int hook_id; /* IRQ hook ID */
|
int hook_id; /* IRQ hook ID */
|
||||||
} hba_state;
|
} hba_state;
|
||||||
|
|
||||||
|
#define hba_read(r) (hba_state.base[r])
|
||||||
|
#define hba_write(r, v) (hba_state.base[r] = (v))
|
||||||
|
|
||||||
/* Port state. */
|
/* Port state. */
|
||||||
static struct port_state {
|
static struct port_state {
|
||||||
int state; /* port state */
|
int state; /* port state */
|
||||||
|
@ -171,6 +174,9 @@ static struct port_state {
|
||||||
} cmd_info[NR_CMDS];
|
} cmd_info[NR_CMDS];
|
||||||
} port_state[NR_PORTS];
|
} port_state[NR_PORTS];
|
||||||
|
|
||||||
|
#define port_read(ps, r) ((ps)->reg[r])
|
||||||
|
#define port_write(ps, r, v) ((ps)->reg[r] = (v))
|
||||||
|
|
||||||
static int ahci_instance; /* driver instance number */
|
static int ahci_instance; /* driver instance number */
|
||||||
|
|
||||||
static int ahci_verbose; /* verbosity level (0..4) */
|
static int ahci_verbose; /* verbosity level (0..4) */
|
||||||
|
@ -918,9 +924,9 @@ static void port_check_cmds(struct port_state *ps)
|
||||||
|
|
||||||
/* See which commands have completed. */
|
/* See which commands have completed. */
|
||||||
if (ps->flags & FLAG_NCQ_MODE)
|
if (ps->flags & FLAG_NCQ_MODE)
|
||||||
mask = ps->reg[AHCI_PORT_SACT];
|
mask = port_read(ps, AHCI_PORT_SACT);
|
||||||
else
|
else
|
||||||
mask = ps->reg[AHCI_PORT_CI];
|
mask = port_read(ps, AHCI_PORT_CI);
|
||||||
|
|
||||||
/* Wake up threads corresponding to completed commands. */
|
/* Wake up threads corresponding to completed commands. */
|
||||||
done = ps->pend_mask & ~mask;
|
done = ps->pend_mask & ~mask;
|
||||||
|
@ -1197,16 +1203,16 @@ static void port_start(struct port_state *ps)
|
||||||
u32_t cmd;
|
u32_t cmd;
|
||||||
|
|
||||||
/* Enable FIS receive. */
|
/* Enable FIS receive. */
|
||||||
cmd = ps->reg[AHCI_PORT_CMD];
|
cmd = port_read(ps, AHCI_PORT_CMD);
|
||||||
ps->reg[AHCI_PORT_CMD] = cmd | AHCI_PORT_CMD_FRE;
|
port_write(ps, AHCI_PORT_CMD, cmd | AHCI_PORT_CMD_FRE);
|
||||||
|
|
||||||
/* Reset status registers. */
|
/* Reset status registers. */
|
||||||
ps->reg[AHCI_PORT_SERR] = ~0;
|
port_write(ps, AHCI_PORT_SERR, ~0);
|
||||||
ps->reg[AHCI_PORT_IS] = ~0;
|
port_write(ps, AHCI_PORT_IS, ~0);
|
||||||
|
|
||||||
/* Start the port. */
|
/* Start the port. */
|
||||||
cmd = ps->reg[AHCI_PORT_CMD];
|
cmd = port_read(ps, AHCI_PORT_CMD);
|
||||||
ps->reg[AHCI_PORT_CMD] = cmd | AHCI_PORT_CMD_ST;
|
port_write(ps, AHCI_PORT_CMD, cmd | AHCI_PORT_CMD_ST);
|
||||||
|
|
||||||
dprintf(V_INFO, ("%s: started\n", ahci_portname(ps)));
|
dprintf(V_INFO, ("%s: started\n", ahci_portname(ps)));
|
||||||
}
|
}
|
||||||
|
@ -1224,26 +1230,26 @@ static void port_restart(struct port_state *ps)
|
||||||
port_fail_cmds(ps);
|
port_fail_cmds(ps);
|
||||||
|
|
||||||
/* Stop the port. */
|
/* Stop the port. */
|
||||||
cmd = ps->reg[AHCI_PORT_CMD];
|
cmd = port_read(ps, AHCI_PORT_CMD);
|
||||||
ps->reg[AHCI_PORT_CMD] = cmd & ~AHCI_PORT_CMD_ST;
|
port_write(ps, AHCI_PORT_CMD, cmd & ~AHCI_PORT_CMD_ST);
|
||||||
|
|
||||||
SPIN_UNTIL(!(ps->reg[AHCI_PORT_CMD] & AHCI_PORT_CMD_CR),
|
SPIN_UNTIL(!(port_read(ps, AHCI_PORT_CMD) & AHCI_PORT_CMD_CR),
|
||||||
PORTREG_DELAY);
|
PORTREG_DELAY);
|
||||||
|
|
||||||
/* Reset status registers. */
|
/* Reset status registers. */
|
||||||
ps->reg[AHCI_PORT_SERR] = ~0;
|
port_write(ps, AHCI_PORT_SERR, ~0);
|
||||||
ps->reg[AHCI_PORT_IS] = ~0;
|
port_write(ps, AHCI_PORT_IS, ~0);
|
||||||
|
|
||||||
/* If the BSY and/or DRQ flags are set, reset the port. */
|
/* If the BSY and/or DRQ flags are set, reset the port. */
|
||||||
if (ps->reg[AHCI_PORT_TFD] &
|
if (port_read(ps, AHCI_PORT_TFD) &
|
||||||
(AHCI_PORT_TFD_STS_BSY | AHCI_PORT_TFD_STS_DRQ)) {
|
(AHCI_PORT_TFD_STS_BSY | AHCI_PORT_TFD_STS_DRQ)) {
|
||||||
|
|
||||||
dprintf(V_ERR, ("%s: port reset\n", ahci_portname(ps)));
|
dprintf(V_ERR, ("%s: port reset\n", ahci_portname(ps)));
|
||||||
|
|
||||||
/* Trigger a port reset. */
|
/* Trigger a port reset. */
|
||||||
ps->reg[AHCI_PORT_SCTL] = AHCI_PORT_SCTL_DET_INIT;
|
port_write(ps, AHCI_PORT_SCTL, AHCI_PORT_SCTL_DET_INIT);
|
||||||
micro_delay(SPINUP_DELAY * 1000);
|
micro_delay(SPINUP_DELAY * 1000);
|
||||||
ps->reg[AHCI_PORT_SCTL] = AHCI_PORT_SCTL_DET_NONE;
|
port_write(ps, AHCI_PORT_SCTL, AHCI_PORT_SCTL_DET_NONE);
|
||||||
|
|
||||||
/* To keep this driver simple, we do not transparently recover
|
/* To keep this driver simple, we do not transparently recover
|
||||||
* ongoing requests. Instead, we mark the failing device as
|
* ongoing requests. Instead, we mark the failing device as
|
||||||
|
@ -1258,8 +1264,8 @@ static void port_restart(struct port_state *ps)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Start the port. */
|
/* Start the port. */
|
||||||
cmd = ps->reg[AHCI_PORT_CMD];
|
cmd = port_read(ps, AHCI_PORT_CMD);
|
||||||
ps->reg[AHCI_PORT_CMD] = cmd | AHCI_PORT_CMD_ST;
|
port_write(ps, AHCI_PORT_CMD, cmd | AHCI_PORT_CMD_ST);
|
||||||
|
|
||||||
dprintf(V_INFO, ("%s: restarted\n", ahci_portname(ps)));
|
dprintf(V_INFO, ("%s: restarted\n", ahci_portname(ps)));
|
||||||
}
|
}
|
||||||
|
@ -1274,36 +1280,34 @@ static void port_stop(struct port_state *ps)
|
||||||
u32_t cmd;
|
u32_t cmd;
|
||||||
|
|
||||||
/* Disable interrupts. */
|
/* Disable interrupts. */
|
||||||
ps->reg[AHCI_PORT_IE] = AHCI_PORT_IE_NONE;
|
port_write(ps, AHCI_PORT_IE, AHCI_PORT_IE_NONE);
|
||||||
|
|
||||||
/* Stop the port. */
|
/* Stop the port. */
|
||||||
cmd = ps->reg[AHCI_PORT_CMD];
|
cmd = port_read(ps, AHCI_PORT_CMD);
|
||||||
|
|
||||||
if (cmd & (AHCI_PORT_CMD_CR | AHCI_PORT_CMD_ST)) {
|
if (cmd & (AHCI_PORT_CMD_CR | AHCI_PORT_CMD_ST)) {
|
||||||
cmd &= ~(AHCI_PORT_CMD_CR | AHCI_PORT_CMD_ST);
|
cmd &= ~(AHCI_PORT_CMD_CR | AHCI_PORT_CMD_ST);
|
||||||
|
|
||||||
ps->reg[AHCI_PORT_CMD] = cmd;
|
port_write(ps, AHCI_PORT_CMD, cmd);
|
||||||
|
|
||||||
SPIN_UNTIL(!(ps->reg[AHCI_PORT_CMD] & AHCI_PORT_CMD_CR),
|
SPIN_UNTIL(!(port_read(ps, AHCI_PORT_CMD) & AHCI_PORT_CMD_CR),
|
||||||
PORTREG_DELAY);
|
PORTREG_DELAY);
|
||||||
|
|
||||||
dprintf(V_INFO, ("%s: stopped\n", ahci_portname(ps)));
|
dprintf(V_INFO, ("%s: stopped\n", ahci_portname(ps)));
|
||||||
|
|
||||||
cmd = ps->reg[AHCI_PORT_CMD];
|
cmd = port_read(ps, AHCI_PORT_CMD);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cmd & (AHCI_PORT_CMD_FR | AHCI_PORT_CMD_FRE)) {
|
if (cmd & (AHCI_PORT_CMD_FR | AHCI_PORT_CMD_FRE)) {
|
||||||
cmd &= ~(AHCI_PORT_CMD_FR | AHCI_PORT_CMD_FRE);
|
port_write(ps, AHCI_PORT_CMD, cmd & ~AHCI_PORT_CMD_FRE);
|
||||||
|
|
||||||
ps->reg[AHCI_PORT_CMD] = cmd;
|
SPIN_UNTIL(!(port_read(ps, AHCI_PORT_CMD) & AHCI_PORT_CMD_FR),
|
||||||
|
|
||||||
SPIN_UNTIL(!(ps->reg[AHCI_PORT_CMD] & AHCI_PORT_CMD_FR),
|
|
||||||
PORTREG_DELAY);
|
PORTREG_DELAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reset status registers. */
|
/* Reset status registers. */
|
||||||
ps->reg[AHCI_PORT_SERR] = ~0;
|
port_write(ps, AHCI_PORT_SERR, ~0);
|
||||||
ps->reg[AHCI_PORT_IS] = ~0;
|
port_write(ps, AHCI_PORT_IS, ~0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
|
@ -1316,7 +1320,7 @@ static void port_sig_check(struct port_state *ps)
|
||||||
*/
|
*/
|
||||||
u32_t tfd, sig;
|
u32_t tfd, sig;
|
||||||
|
|
||||||
tfd = ps->reg[AHCI_PORT_TFD];
|
tfd = port_read(ps, AHCI_PORT_TFD);
|
||||||
|
|
||||||
/* Wait for the BSY flag to be (set and then) cleared first. Note that
|
/* Wait for the BSY flag to be (set and then) cleared first. Note that
|
||||||
* clearing it only happens when PxCMD.FRE is set, which is why we
|
* clearing it only happens when PxCMD.FRE is set, which is why we
|
||||||
|
@ -1356,7 +1360,7 @@ static void port_sig_check(struct port_state *ps)
|
||||||
/* Check the port's signature. We only support the normal ATA and ATAPI
|
/* Check the port's signature. We only support the normal ATA and ATAPI
|
||||||
* signatures. We ignore devices reporting anything else.
|
* signatures. We ignore devices reporting anything else.
|
||||||
*/
|
*/
|
||||||
sig = ps->reg[AHCI_PORT_SIG];
|
sig = port_read(ps, AHCI_PORT_SIG);
|
||||||
|
|
||||||
if (sig != ATA_SIG_ATA && sig != ATA_SIG_ATAPI) {
|
if (sig != ATA_SIG_ATA && sig != ATA_SIG_ATAPI) {
|
||||||
dprintf(V_ERR, ("%s: unsupported signature (%08x)\n",
|
dprintf(V_ERR, ("%s: unsupported signature (%08x)\n",
|
||||||
|
@ -1385,7 +1389,7 @@ static void port_sig_check(struct port_state *ps)
|
||||||
* confusing the timer expiration procedure.
|
* confusing the timer expiration procedure.
|
||||||
*/
|
*/
|
||||||
ps->state = STATE_WAIT_ID;
|
ps->state = STATE_WAIT_ID;
|
||||||
ps->reg[AHCI_PORT_IE] = AHCI_PORT_IE_MASK;
|
port_write(ps, AHCI_PORT_IE, AHCI_PORT_IE_MASK);
|
||||||
|
|
||||||
(void) gen_identify(ps, FALSE /*blocking*/);
|
(void) gen_identify(ps, FALSE /*blocking*/);
|
||||||
}
|
}
|
||||||
|
@ -1450,7 +1454,7 @@ static void port_id_check(struct port_state *ps, int success)
|
||||||
port_stop(ps);
|
port_stop(ps);
|
||||||
|
|
||||||
ps->state = STATE_BAD_DEV;
|
ps->state = STATE_BAD_DEV;
|
||||||
ps->reg[AHCI_PORT_IE] = AHCI_PORT_IE_PRCE;
|
port_write(ps, AHCI_PORT_IE, AHCI_PORT_IE_PRCE);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1499,7 +1503,7 @@ static void port_connect(struct port_state *ps)
|
||||||
ps->state = STATE_WAIT_SIG;
|
ps->state = STATE_WAIT_SIG;
|
||||||
ps->left = ahci_sig_checks;
|
ps->left = ahci_sig_checks;
|
||||||
|
|
||||||
ps->reg[AHCI_PORT_IE] = AHCI_PORT_IE_PRCE;
|
port_write(ps, AHCI_PORT_IE, AHCI_PORT_IE_PRCE);
|
||||||
|
|
||||||
/* Do the first check immediately; who knows, we may get lucky. */
|
/* Do the first check immediately; who knows, we may get lucky. */
|
||||||
port_sig_check(ps);
|
port_sig_check(ps);
|
||||||
|
@ -1519,7 +1523,7 @@ static void port_disconnect(struct port_state *ps)
|
||||||
port_stop(ps);
|
port_stop(ps);
|
||||||
|
|
||||||
ps->state = STATE_NO_DEV;
|
ps->state = STATE_NO_DEV;
|
||||||
ps->reg[AHCI_PORT_IE] = AHCI_PORT_IE_PRCE;
|
port_write(ps, AHCI_PORT_IE, AHCI_PORT_IE_PRCE);
|
||||||
ps->flags &= ~FLAG_BUSY;
|
ps->flags &= ~FLAG_BUSY;
|
||||||
|
|
||||||
/* Fail any ongoing request. The caller may already have done this. */
|
/* Fail any ongoing request. The caller may already have done this. */
|
||||||
|
@ -1552,11 +1556,11 @@ static void port_intr(struct port_state *ps)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
smask = ps->reg[AHCI_PORT_IS];
|
smask = port_read(ps, AHCI_PORT_IS);
|
||||||
emask = smask & ps->reg[AHCI_PORT_IE];
|
emask = smask & port_read(ps, AHCI_PORT_IE);
|
||||||
|
|
||||||
/* Clear the interrupt flags that we saw were set. */
|
/* Clear the interrupt flags that we saw were set. */
|
||||||
ps->reg[AHCI_PORT_IS] = smask;
|
port_write(ps, AHCI_PORT_IS, smask);
|
||||||
|
|
||||||
dprintf(V_REQ, ("%s: interrupt (%08x)\n", ahci_portname(ps), smask));
|
dprintf(V_REQ, ("%s: interrupt (%08x)\n", ahci_portname(ps), smask));
|
||||||
|
|
||||||
|
@ -1565,11 +1569,10 @@ static void port_intr(struct port_state *ps)
|
||||||
|
|
||||||
if (emask & AHCI_PORT_IS_PRCS) {
|
if (emask & AHCI_PORT_IS_PRCS) {
|
||||||
/* Clear the N diagnostics bit to clear this interrupt. */
|
/* Clear the N diagnostics bit to clear this interrupt. */
|
||||||
ps->reg[AHCI_PORT_SERR] = AHCI_PORT_SERR_DIAG_N;
|
port_write(ps, AHCI_PORT_SERR, AHCI_PORT_SERR_DIAG_N);
|
||||||
|
|
||||||
connected =
|
connected = (port_read(ps, AHCI_PORT_SSTS) &
|
||||||
(ps->reg[AHCI_PORT_SSTS] & AHCI_PORT_SSTS_DET_MASK) ==
|
AHCI_PORT_SSTS_DET_MASK) == AHCI_PORT_SSTS_DET_PHY;
|
||||||
AHCI_PORT_SSTS_DET_PHY;
|
|
||||||
|
|
||||||
switch (ps->state) {
|
switch (ps->state) {
|
||||||
case STATE_BAD_DEV:
|
case STATE_BAD_DEV:
|
||||||
|
@ -1598,7 +1601,7 @@ static void port_intr(struct port_state *ps)
|
||||||
/* If we were waiting for ID verification, check now. */
|
/* If we were waiting for ID verification, check now. */
|
||||||
if (ps->state == STATE_WAIT_ID) {
|
if (ps->state == STATE_WAIT_ID) {
|
||||||
ps->flags &= ~FLAG_BUSY;
|
ps->flags &= ~FLAG_BUSY;
|
||||||
port_id_check(ps, !(ps->reg[AHCI_PORT_TFD] &
|
port_id_check(ps, !(port_read(ps, AHCI_PORT_TFD) &
|
||||||
(AHCI_PORT_TFD_STS_ERR |
|
(AHCI_PORT_TFD_STS_ERR |
|
||||||
AHCI_PORT_TFD_STS_DF)));
|
AHCI_PORT_TFD_STS_DF)));
|
||||||
}
|
}
|
||||||
|
@ -1608,7 +1611,7 @@ static void port_intr(struct port_state *ps)
|
||||||
* FIS. In both cases, we just restart the port, failing all
|
* FIS. In both cases, we just restart the port, failing all
|
||||||
* commands in the process.
|
* commands in the process.
|
||||||
*/
|
*/
|
||||||
if ((ps->reg[AHCI_PORT_TFD] &
|
if ((port_read(ps, AHCI_PORT_TFD) &
|
||||||
(AHCI_PORT_TFD_STS_ERR | AHCI_PORT_TFD_STS_DF)) ||
|
(AHCI_PORT_TFD_STS_ERR | AHCI_PORT_TFD_STS_DF)) ||
|
||||||
(smask & AHCI_PORT_IS_RESTART)) {
|
(smask & AHCI_PORT_IS_RESTART)) {
|
||||||
port_restart(ps);
|
port_restart(ps);
|
||||||
|
@ -1651,8 +1654,8 @@ static void port_timeout(struct timer *tp)
|
||||||
* explicit check to see if a device is connected after all.
|
* explicit check to see if a device is connected after all.
|
||||||
* Later hot-(un)plug events will not be detected in this case.
|
* Later hot-(un)plug events will not be detected in this case.
|
||||||
*/
|
*/
|
||||||
if ((ps->reg[AHCI_PORT_SSTS] & AHCI_PORT_SSTS_DET_MASK) ==
|
if ((port_read(ps, AHCI_PORT_SSTS) &
|
||||||
AHCI_PORT_SSTS_DET_PHY) {
|
AHCI_PORT_SSTS_DET_MASK) == AHCI_PORT_SSTS_DET_PHY) {
|
||||||
dprintf(V_INFO, ("%s: no device connection event\n",
|
dprintf(V_INFO, ("%s: no device connection event\n",
|
||||||
ahci_portname(ps)));
|
ahci_portname(ps)));
|
||||||
|
|
||||||
|
@ -1730,7 +1733,7 @@ static void port_issue(struct port_state *ps, int cmd, clock_t timeout)
|
||||||
|
|
||||||
/* Set the corresponding NCQ command bit, if applicable. */
|
/* Set the corresponding NCQ command bit, if applicable. */
|
||||||
if (ps->flags & FLAG_HAS_NCQ)
|
if (ps->flags & FLAG_HAS_NCQ)
|
||||||
ps->reg[AHCI_PORT_SACT] = (1 << cmd);
|
port_write(ps, AHCI_PORT_SACT, 1 << cmd);
|
||||||
|
|
||||||
/* Make sure that the compiler does not delay any previous write
|
/* Make sure that the compiler does not delay any previous write
|
||||||
* operations until after the write to the command issue register.
|
* operations until after the write to the command issue register.
|
||||||
|
@ -1738,7 +1741,7 @@ static void port_issue(struct port_state *ps, int cmd, clock_t timeout)
|
||||||
__insn_barrier();
|
__insn_barrier();
|
||||||
|
|
||||||
/* Tell the controller that a new command is ready. */
|
/* Tell the controller that a new command is ready. */
|
||||||
ps->reg[AHCI_PORT_CI] = (1 << cmd);
|
port_write(ps, AHCI_PORT_CI, 1 << cmd);
|
||||||
|
|
||||||
/* Update pending commands. */
|
/* Update pending commands. */
|
||||||
ps->pend_mask |= 1 << cmd;
|
ps->pend_mask |= 1 << cmd;
|
||||||
|
@ -1841,11 +1844,11 @@ static void port_alloc(struct port_state *ps)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Tell the controller about some of the physical addresses. */
|
/* Tell the controller about some of the physical addresses. */
|
||||||
ps->reg[AHCI_PORT_FBU] = 0;
|
port_write(ps, AHCI_PORT_FBU, 0);
|
||||||
ps->reg[AHCI_PORT_FB] = ps->fis_phys;
|
port_write(ps, AHCI_PORT_FB, ps->fis_phys);
|
||||||
|
|
||||||
ps->reg[AHCI_PORT_CLBU] = 0;
|
port_write(ps, AHCI_PORT_CLBU, 0);
|
||||||
ps->reg[AHCI_PORT_CLB] = ps->cl_phys;
|
port_write(ps, AHCI_PORT_CLB, ps->cl_phys);
|
||||||
|
|
||||||
ps->pad_base = NULL;
|
ps->pad_base = NULL;
|
||||||
ps->pad_size = 0;
|
ps->pad_size = 0;
|
||||||
|
@ -1901,15 +1904,15 @@ static void port_init(struct port_state *ps)
|
||||||
port_alloc(ps);
|
port_alloc(ps);
|
||||||
|
|
||||||
/* Just listen for device status change events for now. */
|
/* Just listen for device status change events for now. */
|
||||||
ps->reg[AHCI_PORT_IE] = AHCI_PORT_IE_PRCE;
|
port_write(ps, AHCI_PORT_IE, AHCI_PORT_IE_PRCE);
|
||||||
|
|
||||||
/* Perform a reset on the device. */
|
/* Perform a reset on the device. */
|
||||||
cmd = ps->reg[AHCI_PORT_CMD];
|
cmd = port_read(ps, AHCI_PORT_CMD);
|
||||||
ps->reg[AHCI_PORT_CMD] = cmd | AHCI_PORT_CMD_SUD;
|
port_write(ps, AHCI_PORT_CMD, cmd | AHCI_PORT_CMD_SUD);
|
||||||
|
|
||||||
ps->reg[AHCI_PORT_SCTL] = AHCI_PORT_SCTL_DET_INIT;
|
port_write(ps, AHCI_PORT_SCTL, AHCI_PORT_SCTL_DET_INIT);
|
||||||
micro_delay(SPINUP_DELAY * 1000); /* SPINUP_DELAY is in ms */
|
micro_delay(SPINUP_DELAY * 1000); /* SPINUP_DELAY is in ms */
|
||||||
ps->reg[AHCI_PORT_SCTL] = AHCI_PORT_SCTL_DET_NONE;
|
port_write(ps, AHCI_PORT_SCTL, AHCI_PORT_SCTL_DET_NONE);
|
||||||
|
|
||||||
set_timer(&ps->cmd_info[0].timer, ahci_spinup_timeout,
|
set_timer(&ps->cmd_info[0].timer, ahci_spinup_timeout,
|
||||||
port_timeout, BUILD_ARG(ps - port_state, 0));
|
port_timeout, BUILD_ARG(ps - port_state, 0));
|
||||||
|
@ -1951,16 +1954,15 @@ static void ahci_reset(void)
|
||||||
*/
|
*/
|
||||||
u32_t ghc;
|
u32_t ghc;
|
||||||
|
|
||||||
ghc = hba_state.base[AHCI_HBA_GHC];
|
ghc = hba_read(AHCI_HBA_GHC);
|
||||||
|
|
||||||
hba_state.base[AHCI_HBA_GHC] = ghc | AHCI_HBA_GHC_AE;
|
hba_write(AHCI_HBA_GHC, ghc | AHCI_HBA_GHC_AE);
|
||||||
|
|
||||||
hba_state.base[AHCI_HBA_GHC] = ghc | AHCI_HBA_GHC_AE | AHCI_HBA_GHC_HR;
|
hba_write(AHCI_HBA_GHC, ghc | AHCI_HBA_GHC_AE | AHCI_HBA_GHC_HR);
|
||||||
|
|
||||||
SPIN_UNTIL(!(hba_state.base[AHCI_HBA_GHC] & AHCI_HBA_GHC_HR),
|
SPIN_UNTIL(!(hba_read(AHCI_HBA_GHC) & AHCI_HBA_GHC_HR), RESET_DELAY);
|
||||||
RESET_DELAY);
|
|
||||||
|
|
||||||
if (hba_state.base[AHCI_HBA_GHC] & AHCI_HBA_GHC_HR)
|
if (hba_read(AHCI_HBA_GHC) & AHCI_HBA_GHC_HR)
|
||||||
panic("unable to reset HBA");
|
panic("unable to reset HBA");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2010,12 +2012,12 @@ static void ahci_init(int devind)
|
||||||
ahci_reset();
|
ahci_reset();
|
||||||
|
|
||||||
/* Enable AHCI and interrupts. */
|
/* Enable AHCI and interrupts. */
|
||||||
ghc = hba_state.base[AHCI_HBA_GHC];
|
ghc = hba_read(AHCI_HBA_GHC);
|
||||||
hba_state.base[AHCI_HBA_GHC] = ghc | AHCI_HBA_GHC_AE | AHCI_HBA_GHC_IE;
|
hba_write(AHCI_HBA_GHC, ghc | AHCI_HBA_GHC_AE | AHCI_HBA_GHC_IE);
|
||||||
|
|
||||||
/* Limit the maximum number of commands to the controller's value. */
|
/* Limit the maximum number of commands to the controller's value. */
|
||||||
/* Note that we currently use only one command anyway. */
|
/* Note that we currently use only one command anyway. */
|
||||||
cap = hba_state.base[AHCI_HBA_CAP];
|
cap = hba_read(AHCI_HBA_CAP);
|
||||||
hba_state.has_ncq = !!(cap & AHCI_HBA_CAP_SNCQ);
|
hba_state.has_ncq = !!(cap & AHCI_HBA_CAP_SNCQ);
|
||||||
hba_state.nr_cmds = MIN(NR_CMDS,
|
hba_state.nr_cmds = MIN(NR_CMDS,
|
||||||
((cap >> AHCI_HBA_CAP_NCS_SHIFT) & AHCI_HBA_CAP_NCS_MASK) + 1);
|
((cap >> AHCI_HBA_CAP_NCS_SHIFT) & AHCI_HBA_CAP_NCS_MASK) + 1);
|
||||||
|
@ -2023,19 +2025,19 @@ static void ahci_init(int devind)
|
||||||
dprintf(V_INFO, ("AHCI%u: HBA v%d.%d%d, %ld ports, %ld commands, "
|
dprintf(V_INFO, ("AHCI%u: HBA v%d.%d%d, %ld ports, %ld commands, "
|
||||||
"%s queuing, IRQ %d\n",
|
"%s queuing, IRQ %d\n",
|
||||||
ahci_instance,
|
ahci_instance,
|
||||||
(int) (hba_state.base[AHCI_HBA_VS] >> 16),
|
(int) (hba_read(AHCI_HBA_VS) >> 16),
|
||||||
(int) ((hba_state.base[AHCI_HBA_VS] >> 8) & 0xFF),
|
(int) ((hba_read(AHCI_HBA_VS) >> 8) & 0xFF),
|
||||||
(int) (hba_state.base[AHCI_HBA_VS] & 0xFF),
|
(int) (hba_read(AHCI_HBA_VS) & 0xFF),
|
||||||
((cap >> AHCI_HBA_CAP_NP_SHIFT) & AHCI_HBA_CAP_NP_MASK) + 1,
|
((cap >> AHCI_HBA_CAP_NP_SHIFT) & AHCI_HBA_CAP_NP_MASK) + 1,
|
||||||
((cap >> AHCI_HBA_CAP_NCS_SHIFT) & AHCI_HBA_CAP_NCS_MASK) + 1,
|
((cap >> AHCI_HBA_CAP_NCS_SHIFT) & AHCI_HBA_CAP_NCS_MASK) + 1,
|
||||||
hba_state.has_ncq ? "supports" : "no", hba_state.irq));
|
hba_state.has_ncq ? "supports" : "no", hba_state.irq));
|
||||||
|
|
||||||
dprintf(V_INFO, ("AHCI%u: CAP %08x, CAP2 %08x, PI %08x\n",
|
dprintf(V_INFO, ("AHCI%u: CAP %08x, CAP2 %08x, PI %08x\n",
|
||||||
ahci_instance, cap, hba_state.base[AHCI_HBA_CAP2],
|
ahci_instance, cap, hba_read(AHCI_HBA_CAP2),
|
||||||
hba_state.base[AHCI_HBA_PI]));
|
hba_read(AHCI_HBA_PI)));
|
||||||
|
|
||||||
/* Initialize each of the implemented ports. We ignore CAP.NP. */
|
/* Initialize each of the implemented ports. We ignore CAP.NP. */
|
||||||
mask = hba_state.base[AHCI_HBA_PI];
|
mask = hba_read(AHCI_HBA_PI);
|
||||||
|
|
||||||
for (port = 0; port < hba_state.nr_ports; port++) {
|
for (port = 0; port < hba_state.nr_ports; port++) {
|
||||||
port_state[port].device = NO_DEVICE;
|
port_state[port].device = NO_DEVICE;
|
||||||
|
@ -2100,7 +2102,7 @@ static void ahci_intr(unsigned int UNUSED(mask))
|
||||||
int r, port;
|
int r, port;
|
||||||
|
|
||||||
/* Handle an interrupt for each port that has the interrupt bit set. */
|
/* Handle an interrupt for each port that has the interrupt bit set. */
|
||||||
mask = hba_state.base[AHCI_HBA_IS];
|
mask = hba_read(AHCI_HBA_IS);
|
||||||
|
|
||||||
for (port = 0; port < hba_state.nr_ports; port++) {
|
for (port = 0; port < hba_state.nr_ports; port++) {
|
||||||
if (mask & (1 << port)) {
|
if (mask & (1 << port)) {
|
||||||
|
@ -2118,7 +2120,7 @@ static void ahci_intr(unsigned int UNUSED(mask))
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clear the bits that we processed. */
|
/* Clear the bits that we processed. */
|
||||||
hba_state.base[AHCI_HBA_IS] = mask;
|
hba_write(AHCI_HBA_IS, mask);
|
||||||
|
|
||||||
/* Reenable the interrupt. */
|
/* Reenable the interrupt. */
|
||||||
if ((r = sys_irqenable(&hba_state.hook_id)) != OK)
|
if ((r = sys_irqenable(&hba_state.hook_id)) != OK)
|
||||||
|
|
Loading…
Reference in a new issue