X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fscsi%2Fahci.c;h=813031c01fbaec9028b91bed5dd1cf8710959ee7;hb=b7887196e38da54ff893897b80875d632d1a1114;hp=f1516ca2c52a69c6f4222a48191d512eb9b27fc1;hpb=e36fcd8ae611b91f0bbaf6063b0b98e1ef955880;p=linux-2.6 diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c index f1516ca2c5..813031c01f 100644 --- a/drivers/scsi/ahci.c +++ b/drivers/scsi/ahci.c @@ -92,7 +92,9 @@ enum { HOST_AHCI_EN = (1 << 31), /* AHCI enabled */ /* HOST_CAP bits */ + HOST_CAP_SSC = (1 << 14), /* Slumber capable */ HOST_CAP_CLO = (1 << 24), /* Command List Override support */ + HOST_CAP_SSS = (1 << 27), /* Staggered Spin-up */ HOST_CAP_NCQ = (1 << 30), /* Native Command Queueing */ HOST_CAP_64 = (1 << 31), /* PCI DAC (64-bit DMA) support */ @@ -155,6 +157,7 @@ enum { PORT_CMD_SPIN_UP = (1 << 1), /* Spin up device */ PORT_CMD_START = (1 << 0), /* Enable port DMA engine */ + PORT_CMD_ICC_MASK = (0xf << 28), /* i/f ICC state mask */ PORT_CMD_ICC_ACTIVE = (0x1 << 28), /* Put i/f in active state */ PORT_CMD_ICC_PARTIAL = (0x2 << 28), /* Put i/f in partial state */ PORT_CMD_ICC_SLUMBER = (0x6 << 28), /* Put i/f in slumber state */ @@ -205,8 +208,6 @@ static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs * static void ahci_irq_clear(struct ata_port *ap); static int ahci_port_start(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_qc_prep(struct ata_queued_cmd *qc); static u8 ahci_check_status(struct ata_port *ap); @@ -214,6 +215,10 @@ static void ahci_freeze(struct ata_port *ap); static void ahci_thaw(struct ata_port *ap); static void ahci_error_handler(struct ata_port *ap); static void ahci_post_internal_cmd(struct ata_queued_cmd *qc); +static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg); +static int ahci_port_resume(struct ata_port *ap); +static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg); +static int ahci_pci_device_resume(struct pci_dev *pdev); static void ahci_remove_one (struct pci_dev *pdev); static struct scsi_host_template ahci_sht = { @@ -233,6 +238,8 @@ static struct scsi_host_template ahci_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .suspend = ata_scsi_device_suspend, + .resume = ata_scsi_device_resume, }; static const struct ata_port_operations ahci_ops = { @@ -259,6 +266,9 @@ static const struct ata_port_operations ahci_ops = { .error_handler = ahci_error_handler, .post_internal_cmd = ahci_post_internal_cmd, + .port_suspend = ahci_port_suspend, + .port_resume = ahci_port_resume, + .port_start = ahci_port_start, .port_stop = ahci_port_stop, }; @@ -352,6 +362,14 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VENDOR_ID_NVIDIA, 0x044f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, board_ahci }, /* MCP65 */ + /* SiS */ + { PCI_VENDOR_ID_SI, 0x1184, PCI_ANY_ID, PCI_ANY_ID, 0, 0, + board_ahci }, /* SiS 966 */ + { PCI_VENDOR_ID_SI, 0x1185, PCI_ANY_ID, PCI_ANY_ID, 0, 0, + board_ahci }, /* SiS 966 */ + { PCI_VENDOR_ID_SI, 0x0186, PCI_ANY_ID, PCI_ANY_ID, 0, 0, + board_ahci }, /* SiS 968 */ + { } /* terminate list */ }; @@ -360,6 +378,8 @@ static struct pci_driver ahci_pci_driver = { .name = DRV_NAME, .id_table = ahci_pci_tbl, .probe = ahci_init_one, + .suspend = ahci_pci_device_suspend, + .resume = ahci_pci_device_resume, .remove = ahci_remove_one, }; @@ -374,108 +394,6 @@ static inline void __iomem *ahci_port_base (void __iomem *base, unsigned int por return (void __iomem *) ahci_port_base_ul((unsigned long)base, port); } -static int ahci_port_start(struct ata_port *ap) -{ - struct device *dev = ap->host_set->dev; - struct ahci_host_priv *hpriv = ap->host_set->private_data; - struct ahci_port_priv *pp; - void __iomem *mmio = ap->host_set->mmio_base; - void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); - void *mem; - dma_addr_t mem_dma; - int rc; - - pp = kmalloc(sizeof(*pp), GFP_KERNEL); - if (!pp) - return -ENOMEM; - memset(pp, 0, sizeof(*pp)); - - rc = ata_pad_alloc(ap, dev); - if (rc) { - kfree(pp); - return rc; - } - - mem = dma_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma, GFP_KERNEL); - if (!mem) { - ata_pad_free(ap, dev); - kfree(pp); - return -ENOMEM; - } - memset(mem, 0, AHCI_PORT_PRIV_DMA_SZ); - - /* - * First item in chunk of DMA memory: 32-slot command table, - * 32 bytes each in size - */ - pp->cmd_slot = mem; - pp->cmd_slot_dma = mem_dma; - - mem += AHCI_CMD_SLOT_SZ; - mem_dma += AHCI_CMD_SLOT_SZ; - - /* - * Second item: Received-FIS area - */ - pp->rx_fis = mem; - pp->rx_fis_dma = mem_dma; - - mem += AHCI_RX_FIS_SZ; - mem_dma += AHCI_RX_FIS_SZ; - - /* - * Third item: data area for storing a single command - * and its scatter-gather table - */ - pp->cmd_tbl = mem; - pp->cmd_tbl_dma = mem_dma; - - ap->private_data = pp; - - if (hpriv->cap & HOST_CAP_64) - writel((pp->cmd_slot_dma >> 16) >> 16, port_mmio + PORT_LST_ADDR_HI); - writel(pp->cmd_slot_dma & 0xffffffff, port_mmio + PORT_LST_ADDR); - readl(port_mmio + PORT_LST_ADDR); /* flush */ - - if (hpriv->cap & HOST_CAP_64) - writel((pp->rx_fis_dma >> 16) >> 16, port_mmio + PORT_FIS_ADDR_HI); - writel(pp->rx_fis_dma & 0xffffffff, port_mmio + PORT_FIS_ADDR); - readl(port_mmio + PORT_FIS_ADDR); /* flush */ - - writel(PORT_CMD_ICC_ACTIVE | PORT_CMD_FIS_RX | - PORT_CMD_POWER_ON | PORT_CMD_SPIN_UP | - PORT_CMD_START, port_mmio + PORT_CMD); - readl(port_mmio + PORT_CMD); /* flush */ - - return 0; -} - - -static void ahci_port_stop(struct ata_port *ap) -{ - struct device *dev = ap->host_set->dev; - struct ahci_port_priv *pp = ap->private_data; - void __iomem *mmio = ap->host_set->mmio_base; - void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); - u32 tmp; - - tmp = readl(port_mmio + PORT_CMD); - tmp &= ~(PORT_CMD_START | PORT_CMD_FIS_RX); - writel(tmp, port_mmio + PORT_CMD); - readl(port_mmio + PORT_CMD); /* flush */ - - /* spec says 500 msecs for each PORT_CMD_{START,FIS_RX} bit, so - * this is slightly incorrect. - */ - msleep(500); - - ap->private_data = NULL; - dma_free_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, - pp->cmd_slot, pp->cmd_slot_dma); - ata_pad_free(ap, dev); - kfree(pp); -} - static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg_in) { unsigned int sc_reg; @@ -510,66 +428,256 @@ 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)); } +static void ahci_start_engine(void __iomem *port_mmio) +{ + u32 tmp; + + /* start DMA */ + tmp = readl(port_mmio + PORT_CMD); + tmp |= PORT_CMD_START; + writel(tmp, port_mmio + PORT_CMD); + readl(port_mmio + PORT_CMD); /* flush */ +} + static int ahci_stop_engine(void __iomem *port_mmio) { u32 tmp; tmp = readl(port_mmio + PORT_CMD); - /* Check if the HBA is idle */ + /* check if the HBA is idle */ if ((tmp & (PORT_CMD_START | PORT_CMD_LIST_ON)) == 0) return 0; - /* Setting HBA to idle */ + /* setting HBA to idle */ tmp &= ~PORT_CMD_START; writel(tmp, port_mmio + PORT_CMD); - /* wait for engine to stop. This could be - * as long as 500 msec - */ + /* wait for engine to stop. This could be as long as 500 msec */ tmp = ata_wait_register(port_mmio + PORT_CMD, PORT_CMD_LIST_ON, PORT_CMD_LIST_ON, 1, 500); - if(tmp & PORT_CMD_LIST_ON) + if (tmp & PORT_CMD_LIST_ON) return -EIO; return 0; } -static int ahci_start_engine(void __iomem *port_mmio) +static void ahci_start_fis_rx(void __iomem *port_mmio, u32 cap, + dma_addr_t cmd_slot_dma, dma_addr_t rx_fis_dma) { u32 tmp; - /* - * Get current status - */ + /* set FIS registers */ + if (cap & HOST_CAP_64) + writel((cmd_slot_dma >> 16) >> 16, port_mmio + PORT_LST_ADDR_HI); + writel(cmd_slot_dma & 0xffffffff, port_mmio + PORT_LST_ADDR); + + if (cap & HOST_CAP_64) + writel((rx_fis_dma >> 16) >> 16, port_mmio + PORT_FIS_ADDR_HI); + writel(rx_fis_dma & 0xffffffff, port_mmio + PORT_FIS_ADDR); + + /* enable FIS reception */ tmp = readl(port_mmio + PORT_CMD); + tmp |= PORT_CMD_FIS_RX; + writel(tmp, 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; + /* flush */ + readl(port_mmio + PORT_CMD); +} - /* - * 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) +static int ahci_stop_fis_rx(void __iomem *port_mmio) +{ + u32 tmp; + + /* disable FIS reception */ + tmp = readl(port_mmio + PORT_CMD); + tmp &= ~PORT_CMD_FIS_RX; + writel(tmp, port_mmio + PORT_CMD); + + /* wait for completion, spec says 500ms, give it 1000 */ + tmp = ata_wait_register(port_mmio + PORT_CMD, PORT_CMD_FIS_ON, + PORT_CMD_FIS_ON, 10, 1000); + if (tmp & PORT_CMD_FIS_ON) return -EBUSY; - /* - * Start DMA + return 0; +} + +static void ahci_power_up(void __iomem *port_mmio, u32 cap) +{ + u32 cmd; + + cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK; + + /* spin up device */ + if (cap & HOST_CAP_SSS) { + cmd |= PORT_CMD_SPIN_UP; + writel(cmd, port_mmio + PORT_CMD); + } + + /* wake up link */ + writel(cmd | PORT_CMD_ICC_ACTIVE, port_mmio + PORT_CMD); +} + +static void ahci_power_down(void __iomem *port_mmio, u32 cap) +{ + u32 cmd, scontrol; + + cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK; + + if (cap & HOST_CAP_SSC) { + /* enable transitions to slumber mode */ + scontrol = readl(port_mmio + PORT_SCR_CTL); + if ((scontrol & 0x0f00) > 0x100) { + scontrol &= ~0xf00; + writel(scontrol, port_mmio + PORT_SCR_CTL); + } + + /* put device into slumber mode */ + writel(cmd | PORT_CMD_ICC_SLUMBER, port_mmio + PORT_CMD); + + /* wait for the transition to complete */ + ata_wait_register(port_mmio + PORT_CMD, PORT_CMD_ICC_SLUMBER, + PORT_CMD_ICC_SLUMBER, 1, 50); + } + + /* put device into listen mode */ + if (cap & HOST_CAP_SSS) { + /* first set PxSCTL.DET to 0 */ + scontrol = readl(port_mmio + PORT_SCR_CTL); + scontrol &= ~0xf; + writel(scontrol, port_mmio + PORT_SCR_CTL); + + /* then set PxCMD.SUD to 0 */ + cmd &= ~PORT_CMD_SPIN_UP; + writel(cmd, port_mmio + PORT_CMD); + } +} + +static void ahci_init_port(void __iomem *port_mmio, u32 cap, + dma_addr_t cmd_slot_dma, dma_addr_t rx_fis_dma) +{ + /* power up */ + ahci_power_up(port_mmio, cap); + + /* enable FIS reception */ + ahci_start_fis_rx(port_mmio, cap, cmd_slot_dma, rx_fis_dma); + + /* enable DMA */ + ahci_start_engine(port_mmio); +} + +static int ahci_deinit_port(void __iomem *port_mmio, u32 cap, const char **emsg) +{ + int rc; + + /* disable DMA */ + rc = ahci_stop_engine(port_mmio); + if (rc) { + *emsg = "failed to stop engine"; + return rc; + } + + /* disable FIS reception */ + rc = ahci_stop_fis_rx(port_mmio); + if (rc) { + *emsg = "failed stop FIS RX"; + return rc; + } + + /* put device into slumber mode */ + ahci_power_down(port_mmio, cap); + + return 0; +} + +static int ahci_reset_controller(void __iomem *mmio, struct pci_dev *pdev) +{ + u32 cap_save, tmp; + + cap_save = readl(mmio + HOST_CAP); + cap_save &= ( (1<<28) | (1<<17) ); + cap_save |= (1 << 27); + + /* global controller reset */ + tmp = readl(mmio + HOST_CTL); + if ((tmp & HOST_RESET) == 0) { + writel(tmp | HOST_RESET, mmio + HOST_CTL); + readl(mmio + HOST_CTL); /* flush */ + } + + /* reset must complete within 1 second, or + * the hardware should be considered fried. */ - tmp |= PORT_CMD_START; - writel(tmp, port_mmio + PORT_CMD); - readl(port_mmio + PORT_CMD); /* flush */ + ssleep(1); + + tmp = readl(mmio + HOST_CTL); + if (tmp & HOST_RESET) { + dev_printk(KERN_ERR, &pdev->dev, + "controller reset failed (0x%x)\n", tmp); + return -EIO; + } + + writel(HOST_AHCI_EN, mmio + HOST_CTL); + (void) readl(mmio + HOST_CTL); /* flush */ + writel(cap_save, mmio + HOST_CAP); + writel(0xf, mmio + HOST_PORTS_IMPL); + (void) readl(mmio + HOST_PORTS_IMPL); /* flush */ + + if (pdev->vendor == PCI_VENDOR_ID_INTEL) { + u16 tmp16; + + /* configure PCS */ + pci_read_config_word(pdev, 0x92, &tmp16); + tmp16 |= 0xf; + pci_write_config_word(pdev, 0x92, tmp16); + } return 0; } +static void ahci_init_controller(void __iomem *mmio, struct pci_dev *pdev, + int n_ports, u32 cap) +{ + int i, rc; + u32 tmp; + + for (i = 0; i < n_ports; i++) { + void __iomem *port_mmio = ahci_port_base(mmio, i); + const char *emsg = NULL; + +#if 0 /* BIOSen initialize this incorrectly */ + if (!(hpriv->port_map & (1 << i))) + continue; +#endif + + /* make sure port is not active */ + rc = ahci_deinit_port(port_mmio, cap, &emsg); + if (rc) + dev_printk(KERN_WARNING, &pdev->dev, + "%s (%d)\n", emsg, rc); + + /* clear SError */ + tmp = readl(port_mmio + PORT_SCR_ERR); + VPRINTK("PORT_SCR_ERR 0x%x\n", tmp); + writel(tmp, port_mmio + PORT_SCR_ERR); + + /* clear port IRQ */ + tmp = readl(port_mmio + PORT_IRQ_STAT); + VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp); + if (tmp) + writel(tmp, port_mmio + PORT_IRQ_STAT); + + writel(1 << i, mmio + HOST_IRQ_STAT); + } + + tmp = readl(mmio + HOST_CTL); + VPRINTK("HOST_CTL 0x%x\n", tmp); + writel(tmp | HOST_IRQ_EN, mmio + HOST_CTL); + tmp = readl(mmio + HOST_CTL); + VPRINTK("HOST_CTL 0x%x\n", tmp); +} + static unsigned int ahci_dev_classify(struct ata_port *ap) { void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr; @@ -967,14 +1075,8 @@ static void ahci_host_intr(struct ata_port *ap) return; /* ignore interim PIO setup fis interrupts */ - if (ata_tag_valid(ap->active_tag)) { - struct ata_queued_cmd *qc = - ata_qc_from_tag(ap, ap->active_tag); - - if (qc && qc->tf.protocol == ATA_PROT_PIO && - (status & PORT_IRQ_PIOS_FIS)) - return; - } + if (ata_tag_valid(ap->active_tag) && (status & PORT_IRQ_PIOS_FIS)) + return; if (ata_ratelimit()) ata_port_printk(ap, KERN_INFO, "spurious interrupt " @@ -1109,6 +1211,165 @@ static void ahci_post_internal_cmd(struct ata_queued_cmd *qc) } } +static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg) +{ + struct ahci_host_priv *hpriv = ap->host_set->private_data; + struct ahci_port_priv *pp = ap->private_data; + void __iomem *mmio = ap->host_set->mmio_base; + void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); + const char *emsg = NULL; + int rc; + + rc = ahci_deinit_port(port_mmio, hpriv->cap, &emsg); + if (rc) { + ata_port_printk(ap, KERN_ERR, "%s (%d)\n", emsg, rc); + ahci_init_port(port_mmio, hpriv->cap, + pp->cmd_slot_dma, pp->rx_fis_dma); + } + + return rc; +} + +static int ahci_port_resume(struct ata_port *ap) +{ + struct ahci_port_priv *pp = ap->private_data; + struct ahci_host_priv *hpriv = ap->host_set->private_data; + void __iomem *mmio = ap->host_set->mmio_base; + void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); + + ahci_init_port(port_mmio, hpriv->cap, pp->cmd_slot_dma, pp->rx_fis_dma); + + return 0; +} + +static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg) +{ + struct ata_host_set *host_set = dev_get_drvdata(&pdev->dev); + void __iomem *mmio = host_set->mmio_base; + u32 ctl; + + if (mesg.event == PM_EVENT_SUSPEND) { + /* AHCI spec rev1.1 section 8.3.3: + * Software must disable interrupts prior to requesting a + * transition of the HBA to D3 state. + */ + ctl = readl(mmio + HOST_CTL); + ctl &= ~HOST_IRQ_EN; + writel(ctl, mmio + HOST_CTL); + readl(mmio + HOST_CTL); /* flush */ + } + + return ata_pci_device_suspend(pdev, mesg); +} + +static int ahci_pci_device_resume(struct pci_dev *pdev) +{ + struct ata_host_set *host_set = dev_get_drvdata(&pdev->dev); + struct ahci_host_priv *hpriv = host_set->private_data; + void __iomem *mmio = host_set->mmio_base; + int rc; + + ata_pci_device_do_resume(pdev); + + if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) { + rc = ahci_reset_controller(mmio, pdev); + if (rc) + return rc; + + ahci_init_controller(mmio, pdev, host_set->n_ports, hpriv->cap); + } + + ata_host_set_resume(host_set); + + return 0; +} + +static int ahci_port_start(struct ata_port *ap) +{ + struct device *dev = ap->host_set->dev; + struct ahci_host_priv *hpriv = ap->host_set->private_data; + struct ahci_port_priv *pp; + void __iomem *mmio = ap->host_set->mmio_base; + void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); + void *mem; + dma_addr_t mem_dma; + int rc; + + pp = kmalloc(sizeof(*pp), GFP_KERNEL); + if (!pp) + return -ENOMEM; + memset(pp, 0, sizeof(*pp)); + + rc = ata_pad_alloc(ap, dev); + if (rc) { + kfree(pp); + return rc; + } + + mem = dma_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma, GFP_KERNEL); + if (!mem) { + ata_pad_free(ap, dev); + kfree(pp); + return -ENOMEM; + } + memset(mem, 0, AHCI_PORT_PRIV_DMA_SZ); + + /* + * First item in chunk of DMA memory: 32-slot command table, + * 32 bytes each in size + */ + pp->cmd_slot = mem; + pp->cmd_slot_dma = mem_dma; + + mem += AHCI_CMD_SLOT_SZ; + mem_dma += AHCI_CMD_SLOT_SZ; + + /* + * Second item: Received-FIS area + */ + pp->rx_fis = mem; + pp->rx_fis_dma = mem_dma; + + mem += AHCI_RX_FIS_SZ; + mem_dma += AHCI_RX_FIS_SZ; + + /* + * Third item: data area for storing a single command + * and its scatter-gather table + */ + pp->cmd_tbl = mem; + pp->cmd_tbl_dma = mem_dma; + + ap->private_data = pp; + + /* initialize port */ + ahci_init_port(port_mmio, hpriv->cap, pp->cmd_slot_dma, pp->rx_fis_dma); + + return 0; +} + +static void ahci_port_stop(struct ata_port *ap) +{ + struct device *dev = ap->host_set->dev; + struct ahci_host_priv *hpriv = ap->host_set->private_data; + struct ahci_port_priv *pp = ap->private_data; + void __iomem *mmio = ap->host_set->mmio_base; + void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); + const char *emsg = NULL; + int rc; + + /* de-initialize port */ + rc = ahci_deinit_port(port_mmio, hpriv->cap, &emsg); + if (rc) + ata_port_printk(ap, KERN_WARNING, "%s (%d)\n", emsg, rc); + + ap->private_data = NULL; + dma_free_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, + pp->cmd_slot, pp->cmd_slot_dma); + ata_pad_free(ap, dev); + kfree(pp); +} + static void ahci_setup_port(struct ata_ioports *port, unsigned long base, unsigned int port_idx) { @@ -1127,47 +1388,12 @@ static int ahci_host_init(struct ata_probe_ent *probe_ent) struct ahci_host_priv *hpriv = probe_ent->private_data; struct pci_dev *pdev = to_pci_dev(probe_ent->dev); void __iomem *mmio = probe_ent->mmio_base; - u32 tmp, cap_save; - unsigned int i, j, using_dac; + unsigned int i, using_dac; int rc; - void __iomem *port_mmio; - - cap_save = readl(mmio + HOST_CAP); - cap_save &= ( (1<<28) | (1<<17) ); - cap_save |= (1 << 27); - /* global controller reset */ - tmp = readl(mmio + HOST_CTL); - if ((tmp & HOST_RESET) == 0) { - writel(tmp | HOST_RESET, mmio + HOST_CTL); - readl(mmio + HOST_CTL); /* flush */ - } - - /* reset must complete within 1 second, or - * the hardware should be considered fried. - */ - ssleep(1); - - tmp = readl(mmio + HOST_CTL); - if (tmp & HOST_RESET) { - dev_printk(KERN_ERR, &pdev->dev, - "controller reset failed (0x%x)\n", tmp); - return -EIO; - } - - writel(HOST_AHCI_EN, mmio + HOST_CTL); - (void) readl(mmio + HOST_CTL); /* flush */ - writel(cap_save, mmio + HOST_CAP); - writel(0xf, mmio + HOST_PORTS_IMPL); - (void) readl(mmio + HOST_PORTS_IMPL); /* flush */ - - if (pdev->vendor == PCI_VENDOR_ID_INTEL) { - u16 tmp16; - - pci_read_config_word(pdev, 0x92, &tmp16); - tmp16 |= 0xf; - pci_write_config_word(pdev, 0x92, tmp16); - } + rc = ahci_reset_controller(mmio, pdev); + if (rc) + return rc; hpriv->cap = readl(mmio + HOST_CAP); hpriv->port_map = readl(mmio + HOST_PORTS_IMPL); @@ -1203,63 +1429,10 @@ static int ahci_host_init(struct ata_probe_ent *probe_ent) } } - for (i = 0; i < probe_ent->n_ports; i++) { -#if 0 /* BIOSen initialize this incorrectly */ - if (!(hpriv->port_map & (1 << i))) - continue; -#endif - - port_mmio = ahci_port_base(mmio, i); - VPRINTK("mmio %p port_mmio %p\n", mmio, port_mmio); - - ahci_setup_port(&probe_ent->port[i], - (unsigned long) mmio, i); - - /* make sure port is not active */ - tmp = readl(port_mmio + PORT_CMD); - VPRINTK("PORT_CMD 0x%x\n", tmp); - if (tmp & (PORT_CMD_LIST_ON | PORT_CMD_FIS_ON | - PORT_CMD_FIS_RX | PORT_CMD_START)) { - tmp &= ~(PORT_CMD_LIST_ON | PORT_CMD_FIS_ON | - PORT_CMD_FIS_RX | PORT_CMD_START); - writel(tmp, port_mmio + PORT_CMD); - readl(port_mmio + PORT_CMD); /* flush */ - - /* spec says 500 msecs for each bit, so - * this is slightly incorrect. - */ - msleep(500); - } - - writel(PORT_CMD_SPIN_UP, port_mmio + PORT_CMD); - - j = 0; - while (j < 100) { - msleep(10); - tmp = readl(port_mmio + PORT_SCR_STAT); - if ((tmp & 0xf) == 0x3) - break; - j++; - } - - tmp = readl(port_mmio + PORT_SCR_ERR); - VPRINTK("PORT_SCR_ERR 0x%x\n", tmp); - writel(tmp, port_mmio + PORT_SCR_ERR); - - /* ack any pending irq events for this port */ - tmp = readl(port_mmio + PORT_IRQ_STAT); - VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp); - if (tmp) - writel(tmp, port_mmio + PORT_IRQ_STAT); + for (i = 0; i < probe_ent->n_ports; i++) + ahci_setup_port(&probe_ent->port[i], (unsigned long) mmio, i); - writel(1 << i, mmio + HOST_IRQ_STAT); - } - - tmp = readl(mmio + HOST_CTL); - VPRINTK("HOST_CTL 0x%x\n", tmp); - writel(tmp | HOST_IRQ_EN, mmio + HOST_CTL); - tmp = readl(mmio + HOST_CTL); - VPRINTK("HOST_CTL 0x%x\n", tmp); + ahci_init_controller(mmio, pdev, probe_ent->n_ports, hpriv->cap); pci_set_master(pdev); @@ -1492,7 +1665,7 @@ static void ahci_remove_one (struct pci_dev *pdev) static int __init ahci_init(void) { - return pci_module_init(&ahci_pci_driver); + return pci_register_driver(&ahci_pci_driver); } static void __exit ahci_exit(void)