[PATCH] The redefinition of ahci_start_engine() and ahci_stop_engine()
- Make ahci_start_engine() and ahci_stop_engine() more consistent with AHCI spec 1.1 - Change their input parameter from ap to port_mmio - Update the existing users of ahci_start_engine() and ahci_stop_engine() Signed-off-by: Forrest Zhao <forrest.zhao@intel.com> Signed-off-by: Hannes Reinecke <hare@suse.de> Signed-off-by: Jens Axboe <axboe@suse.de> Signed-off-by: Jeff Garzik <jeff@garzik.org>
This commit is contained in:
parent
13abf50df2
commit
5457f2194a
1 changed files with 57 additions and 25 deletions
|
@ -205,6 +205,8 @@ static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs *
|
||||||
static void ahci_irq_clear(struct ata_port *ap);
|
static void ahci_irq_clear(struct ata_port *ap);
|
||||||
static int ahci_port_start(struct ata_port *ap);
|
static int ahci_port_start(struct ata_port *ap);
|
||||||
static void ahci_port_stop(struct ata_port *ap);
|
static void ahci_port_stop(struct ata_port *ap);
|
||||||
|
static int ahci_start_engine(void __iomem *port_mmio);
|
||||||
|
static int ahci_stop_engine(void __iomem *port_mmio);
|
||||||
static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
|
static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
|
||||||
static void ahci_qc_prep(struct ata_queued_cmd *qc);
|
static void ahci_qc_prep(struct ata_queued_cmd *qc);
|
||||||
static u8 ahci_check_status(struct ata_port *ap);
|
static u8 ahci_check_status(struct ata_port *ap);
|
||||||
|
@ -508,41 +510,64 @@ static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg_in,
|
||||||
writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
|
writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ahci_stop_engine(struct ata_port *ap)
|
static int ahci_stop_engine(void __iomem *port_mmio)
|
||||||
{
|
{
|
||||||
void __iomem *mmio = ap->host_set->mmio_base;
|
|
||||||
void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
|
|
||||||
int work;
|
|
||||||
u32 tmp;
|
u32 tmp;
|
||||||
|
|
||||||
tmp = readl(port_mmio + PORT_CMD);
|
tmp = readl(port_mmio + PORT_CMD);
|
||||||
|
|
||||||
|
/* Check if the HBA is idle */
|
||||||
|
if ((tmp & (PORT_CMD_START | PORT_CMD_LIST_ON)) == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Setting HBA to idle */
|
||||||
tmp &= ~PORT_CMD_START;
|
tmp &= ~PORT_CMD_START;
|
||||||
writel(tmp, port_mmio + PORT_CMD);
|
writel(tmp, port_mmio + PORT_CMD);
|
||||||
|
|
||||||
/* wait for engine to stop. TODO: this could be
|
/* wait for engine to stop. This could be
|
||||||
* as long as 500 msec
|
* as long as 500 msec
|
||||||
*/
|
*/
|
||||||
work = 1000;
|
tmp = ata_wait_register(port_mmio + PORT_CMD,
|
||||||
while (work-- > 0) {
|
PORT_CMD_LIST_ON, PORT_CMD_LIST_ON, 1, 500);
|
||||||
tmp = readl(port_mmio + PORT_CMD);
|
if(tmp & PORT_CMD_LIST_ON)
|
||||||
if ((tmp & PORT_CMD_LIST_ON) == 0)
|
return -EIO;
|
||||||
return 0;
|
|
||||||
udelay(10);
|
|
||||||
}
|
|
||||||
|
|
||||||
return -EIO;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ahci_start_engine(struct ata_port *ap)
|
static int ahci_start_engine(void __iomem *port_mmio)
|
||||||
{
|
{
|
||||||
void __iomem *mmio = ap->host_set->mmio_base;
|
|
||||||
void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
|
|
||||||
u32 tmp;
|
u32 tmp;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get current status
|
||||||
|
*/
|
||||||
tmp = readl(port_mmio + PORT_CMD);
|
tmp = readl(port_mmio + PORT_CMD);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* AHCI rev 1.1 section 10.3.1:
|
||||||
|
* Software shall not set PxCMD.ST to '1' until it verifies
|
||||||
|
* that PxCMD.CR is '0' and has set PxCMD.FRE to '1'
|
||||||
|
*/
|
||||||
|
if ((tmp & PORT_CMD_FIS_RX) == 0)
|
||||||
|
return -EPERM;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* wait for engine to become idle.
|
||||||
|
*/
|
||||||
|
tmp = ata_wait_register(port_mmio + PORT_CMD,
|
||||||
|
PORT_CMD_LIST_ON, PORT_CMD_LIST_ON, 1,500);
|
||||||
|
if(tmp & PORT_CMD_LIST_ON)
|
||||||
|
return -EBUSY;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Start DMA
|
||||||
|
*/
|
||||||
tmp |= PORT_CMD_START;
|
tmp |= PORT_CMD_START;
|
||||||
writel(tmp, port_mmio + PORT_CMD);
|
writel(tmp, port_mmio + PORT_CMD);
|
||||||
readl(port_mmio + PORT_CMD); /* flush */
|
readl(port_mmio + PORT_CMD); /* flush */
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int ahci_dev_classify(struct ata_port *ap)
|
static unsigned int ahci_dev_classify(struct ata_port *ap)
|
||||||
|
@ -626,7 +651,7 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* prepare for SRST (AHCI-1.1 10.4.1) */
|
/* prepare for SRST (AHCI-1.1 10.4.1) */
|
||||||
rc = ahci_stop_engine(ap);
|
rc = ahci_stop_engine(port_mmio);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
reason = "failed to stop engine";
|
reason = "failed to stop engine";
|
||||||
goto fail_restart;
|
goto fail_restart;
|
||||||
|
@ -647,7 +672,7 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* restart engine */
|
/* restart engine */
|
||||||
ahci_start_engine(ap);
|
ahci_start_engine(port_mmio);
|
||||||
|
|
||||||
ata_tf_init(ap->device, &tf);
|
ata_tf_init(ap->device, &tf);
|
||||||
fis = pp->cmd_tbl;
|
fis = pp->cmd_tbl;
|
||||||
|
@ -706,7 +731,7 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
fail_restart:
|
fail_restart:
|
||||||
ahci_start_engine(ap);
|
ahci_start_engine(port_mmio);
|
||||||
fail:
|
fail:
|
||||||
ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason);
|
ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason);
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -717,11 +742,13 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class)
|
||||||
struct ahci_port_priv *pp = ap->private_data;
|
struct ahci_port_priv *pp = ap->private_data;
|
||||||
u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
|
u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
|
||||||
struct ata_taskfile tf;
|
struct ata_taskfile tf;
|
||||||
|
void __iomem *mmio = ap->host_set->mmio_base;
|
||||||
|
void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
DPRINTK("ENTER\n");
|
DPRINTK("ENTER\n");
|
||||||
|
|
||||||
ahci_stop_engine(ap);
|
ahci_stop_engine(port_mmio);
|
||||||
|
|
||||||
/* clear D2H reception area to properly wait for D2H FIS */
|
/* clear D2H reception area to properly wait for D2H FIS */
|
||||||
ata_tf_init(ap->device, &tf);
|
ata_tf_init(ap->device, &tf);
|
||||||
|
@ -730,7 +757,7 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class)
|
||||||
|
|
||||||
rc = sata_std_hardreset(ap, class);
|
rc = sata_std_hardreset(ap, class);
|
||||||
|
|
||||||
ahci_start_engine(ap);
|
ahci_start_engine(port_mmio);
|
||||||
|
|
||||||
if (rc == 0 && ata_port_online(ap))
|
if (rc == 0 && ata_port_online(ap))
|
||||||
*class = ahci_dev_classify(ap);
|
*class = ahci_dev_classify(ap);
|
||||||
|
@ -1052,10 +1079,13 @@ static void ahci_thaw(struct ata_port *ap)
|
||||||
|
|
||||||
static void ahci_error_handler(struct ata_port *ap)
|
static void ahci_error_handler(struct ata_port *ap)
|
||||||
{
|
{
|
||||||
|
void __iomem *mmio = ap->host_set->mmio_base;
|
||||||
|
void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
|
||||||
|
|
||||||
if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
|
if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
|
||||||
/* restart engine */
|
/* restart engine */
|
||||||
ahci_stop_engine(ap);
|
ahci_stop_engine(port_mmio);
|
||||||
ahci_start_engine(ap);
|
ahci_start_engine(port_mmio);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* perform recovery */
|
/* perform recovery */
|
||||||
|
@ -1066,14 +1096,16 @@ static void ahci_error_handler(struct ata_port *ap)
|
||||||
static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
|
static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
|
||||||
{
|
{
|
||||||
struct ata_port *ap = qc->ap;
|
struct ata_port *ap = qc->ap;
|
||||||
|
void __iomem *mmio = ap->host_set->mmio_base;
|
||||||
|
void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
|
||||||
|
|
||||||
if (qc->flags & ATA_QCFLAG_FAILED)
|
if (qc->flags & ATA_QCFLAG_FAILED)
|
||||||
qc->err_mask |= AC_ERR_OTHER;
|
qc->err_mask |= AC_ERR_OTHER;
|
||||||
|
|
||||||
if (qc->err_mask) {
|
if (qc->err_mask) {
|
||||||
/* make DMA engine forget about the failed command */
|
/* make DMA engine forget about the failed command */
|
||||||
ahci_stop_engine(ap);
|
ahci_stop_engine(port_mmio);
|
||||||
ahci_start_engine(ap);
|
ahci_start_engine(port_mmio);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue