Bugzilla – Attachment 73634 Details for
Bug 151517
FSC Lifebook does not resume
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
IDP Log In
|
Forgot Password
[patch]
ahci-update.patch
ahci-update.patch (text/plain), 10.65 KB, created by
Hannes Reinecke
on 2006-03-17 07:53:07 UTC
(
hide
)
Description:
ahci-update.patch
Filename:
MIME Type:
Creator:
Hannes Reinecke
Created:
2006-03-17 07:53:07 UTC
Size:
10.65 KB
patch
obsolete
>From: Hannes Reinecke <hare@suse.de> >Subject: AHCI update > >This patch updates the ahci driver to that version posted to linux-ide. >It corrects the DMA / FIS RX handling somewhat; additionally a bug during >device detection has been fixed. > >Signed-off-by: Hannes Reinecke <hare@suse.de> > >--- linux-2.6.13-SL100_BRANCH/drivers/scsi/ahci.c.orig 2006-03-15 10:46:27.000000000 +0100 >+++ linux-2.6.13-SL100_BRANCH/drivers/scsi/ahci.c 2006-03-17 09:39:15.000000000 +0100 >@@ -176,8 +176,12 @@ static void ahci_scr_write (struct ata_p > static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); > static int ahci_qc_issue(struct ata_queued_cmd *qc); > static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs *regs); >-static void ahci_start_engine(struct ata_port *ap); >-static int ahci_stop_engine(struct ata_port *ap); >+static int ahci_start_engine(void __iomem *port_mmio); >+static int ahci_stop_engine(void __iomem *port_mmio); >+static int ahci_stop_fis_rx(void __iomem *port_mmio); >+static void ahci_start_fis_rx(void __iomem *port_mmio, >+ struct ahci_port_priv *pp, >+ struct ahci_host_priv *hpriv); > static void ahci_phy_reset(struct ata_port *ap); > static void ahci_irq_clear(struct ata_port *ap); > static void ahci_eng_timeout(struct ata_port *ap); >@@ -331,7 +335,10 @@ static void ahci_host_stop(struct ata_ho > 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; > >@@ -378,10 +385,16 @@ static int ahci_port_start(struct ata_po > ap->private_data = pp; > > /* >- * Internal structures are initialized, >- * we can now do a simple resume() >+ * Enable FIS reception >+ */ >+ ahci_start_fis_rx(port_mmio, pp, hpriv); >+ >+ /* >+ * We must not enable DMA here; >+ * according to the spec this should >+ * only be done after ports have been >+ * probed. > */ >- ahci_port_resume(ap); > > return 0; > } >@@ -393,53 +406,45 @@ static void ahci_port_resume(struct ata_ > void *port_mmio = ahci_port_base(mmio, ap->port_no); > struct ahci_host_priv *hpriv = ap->host_set->private_data; > struct ahci_port_priv *pp = ap->private_data; >+ int rc; > >- 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_mmio + PORT_CMD); >- readl(port_mmio + PORT_CMD); /* flush */ >+ /* >+ * Enable FIS reception >+ */ >+ ahci_start_fis_rx(port_mmio, pp, hpriv); > >- ahci_start_engine(ap); >+ /* >+ * Enable DMA >+ */ >+ rc = ahci_start_engine(port_mmio); >+ if (rc) >+ printk(KERN_WARNING "ata%d: cannot start DMA engine (rc %d)\n", >+ ap->id, rc); > } > > static void ahci_port_suspend(struct ata_port *ap) > { > void *mmio = ap->host_set->mmio_base; > void *port_mmio = ahci_port_base(mmio, ap->port_no); >- u32 tmp; >- int work; >- >- ahci_stop_engine(ap); >+ int rc; > > /* >- * Disable FIS reception >+ * Disable DMA > */ >- tmp = readl(port_mmio + PORT_CMD); >- tmp &= ~(PORT_CMD_FIS_RX); >- writel(tmp, port_mmio + PORT_CMD); >- readl(port_mmio + PORT_CMD); /* flush */ >+ rc = ahci_stop_engine(port_mmio); >+ if (rc) { >+ printk(KERN_WARNING "ata%u: DMA engine busy (rc %d)\n", >+ ap->id, rc); >+ return; >+ } > > /* >- * Wait for HBA to acknowledge. >- * This could be as long as 500 msec >+ * Disable FIS reception > */ >- work = 1000; >- while (work-- > 0) { >- tmp = readl(port_mmio + PORT_CMD); >- if ((tmp & PORT_CMD_FIS_ON) == 0) >- break; >- udelay(10); >- } >+ rc = ahci_stop_fis_rx(port_mmio); >+ if (rc) >+ printk(KERN_WARNING "ata%d: FIS RX still running (rc %d)\n", >+ ap->id, rc); > } > > static void ahci_port_stop(struct ata_port *ap) >@@ -504,7 +509,7 @@ static void ahci_phy_reset(struct ata_po > tmp = readl(port_mmio + PORT_SCR_ERR); > writel(tmp, port_mmio + PORT_SCR_ERR); > >- ahci_start_engine(ap); >+ ahci_start_engine(port_mmio); > > if (ap->flags & ATA_FLAG_PORT_DISABLED) > return; >@@ -604,48 +609,60 @@ static void ahci_qc_prep(struct ata_queu > ahci_fill_sg(qc); > } > >-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; >- int work; >+ int work = 1000; > >+ /* >+ * Get current status >+ */ > 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) >- printk(KERN_WARNING "ata%d: dma not running\n",ap->id); >+ return -EPERM; >+ > /* > * wait for engine to become idle. > */ >- work = 1000; >- while (work-- > 0) { >+ while (work-- > 0 && ((tmp & PORT_CMD_LIST_ON) == 0)) { > tmp = readl(port_mmio + PORT_CMD); >- if ((tmp & PORT_CMD_LIST_ON) == 0) >- break; > udelay(10); > } >- >+ >+ if (!work) { >+ /* >+ * We need to do a port reset / HBA reset here >+ */ >+ return -EBUSY; >+ } >+ > /* > * Start DMA > */ > tmp |= PORT_CMD_START; > writel(tmp, port_mmio + PORT_CMD); > readl(port_mmio + PORT_CMD); /* flush */ >+ >+ return 0; > } > >-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; > > 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; > writel(tmp, port_mmio + PORT_CMD); > >@@ -663,17 +680,98 @@ static int ahci_stop_engine(struct ata_p > return -EIO; > } > >+static int ahci_stop_fis_rx(void __iomem *port_mmio) >+{ >+ u32 tmp; >+ int work = 1000; >+ >+ /* >+ * Get current status >+ */ >+ tmp = readl(port_mmio + PORT_CMD); >+ >+ /* Check if FIS RX is already disabled */ >+ if ((tmp & PORT_CMD_FIS_RX) == 0) >+ return 0; >+ >+ /* >+ * AHCI Rev 1.1 section 10.3.2 >+ * Software shall not clear PxCMD.FRE while >+ * PxCMD.ST or PxCMD.CR is set to â1â. >+ */ >+ if (tmp & (PORT_CMD_LIST_ON | PORT_CMD_START)) { >+ return -EPERM; >+ } >+ >+ /* >+ * Disable FIS reception >+ * >+ * AHCI Rev 1.1 Section 10.1.2: >+ * If PxCMD.FRE is set to '1', software should clear it >+ * to '0' and wait at least 500 milliseconds for PxCMD.FR >+ * to return '0' when read. If PxCMD.FR does not clear >+ * '0' correctly, then software may attempt a port reset >+ * or a full HBA reset to recover. >+ */ >+ tmp &= ~(PORT_CMD_FIS_RX); >+ writel(tmp, port_mmio + PORT_CMD); >+ >+ mdelay(100); >+ work = 1000; >+ while (work-- > 0) { >+ tmp = readl(port_mmio + PORT_CMD); >+ if ((tmp & PORT_CMD_FIS_ON) == 0) >+ return 0; >+ udelay(10); >+ } >+ >+ return -EBUSY; >+} >+ >+static void ahci_start_fis_rx(void __iomem *port_mmio, >+ struct ahci_port_priv *pp, >+ struct ahci_host_priv *hpriv) >+{ >+ /* >+ * Enable FIS reception >+ */ >+ 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 */ >+ >+ /* >+ * This is wrong. We should only activate >+ * FIS_RX here; everything else should be handled >+ * separately. >+ * Some bits might not even be settable here >+ * as they depend on the respective feature to be >+ * implemented (Staggered Spin-up, >+ * Cold-presence detection etc.) >+ */ >+ writel(PORT_CMD_ICC_ACTIVE | PORT_CMD_FIS_RX | >+ PORT_CMD_POWER_ON | PORT_CMD_SPIN_UP, >+ port_mmio + PORT_CMD); >+ readl(port_mmio + PORT_CMD); /* flush */ >+} >+ > static void ahci_restart_port(struct ata_port *ap, u32 irq_stat) > { > void *mmio = ap->host_set->mmio_base; > void *port_mmio = ahci_port_base(mmio, ap->port_no); > u32 tmp; >+ int rc; > > if ((ap->device[0].class != ATA_DEV_ATAPI) || > ((irq_stat & PORT_IRQ_TF_ERR) == 0)) > ahci_dump_port_status(ap, irq_stat, "port reset"); > >- ahci_stop_engine(ap); >+ rc = ahci_stop_engine(port_mmio); > > /* clear SATA phy error, if any */ > tmp = readl(port_mmio + PORT_SCR_ERR); >@@ -683,7 +781,7 @@ static void ahci_restart_port(struct ata > * if so, issue COMRESET > */ > tmp = readl(port_mmio + PORT_TFDATA); >- if (tmp & (ATA_BUSY | ATA_DRQ)) { >+ if (rc || (tmp & (ATA_BUSY | ATA_DRQ))) { > writel(0x301, port_mmio + PORT_SCR_CTL); > readl(port_mmio + PORT_SCR_CTL); /* flush */ > udelay(10); >@@ -691,7 +789,11 @@ static void ahci_restart_port(struct ata > readl(port_mmio + PORT_SCR_CTL); /* flush */ > } > >- ahci_start_engine(ap); >+ /* re-start DMA */ >+ rc = ahci_start_engine(port_mmio); >+ if (rc) >+ printk(KERN_WARNING "ata%u: cannot start DMA (rc %d)\n", >+ ap->id, rc); > } > > static void ahci_eng_timeout(struct ata_port *ap) >@@ -910,7 +1012,7 @@ static int ahci_host_init(struct ata_pro > hpriv->port_map = readl(mmio + HOST_PORTS_IMPL); > probe_ent->n_ports = (hpriv->cap & 0x1f) + 1; > >- VPRINTK("cap 0x%x port_map 0x%x n_ports %d\n", >+ DPRINTK("cap 0x%x port_map 0x%x n_ports %d\n", > hpriv->cap, hpriv->port_map, probe_ent->n_ports); > > using_dac = hpriv->cap & HOST_CAP_64; >@@ -1110,11 +1212,16 @@ static int ahci_init_one (struct pci_dev > printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); > > rc = pci_enable_device(pdev); >- if (rc) >+ if (rc) { >+ printk(KERN_ERR DRV_NAME "(%s): cannot enable PCI device\n", >+ pci_name(pdev)); > return rc; >+ } > > rc = pci_request_regions(pdev, DRV_NAME); > if (rc) { >+ printk(KERN_ERR DRV_NAME "(%s): cannot request PCI regions\n", >+ pci_name(pdev)); > pci_dev_busy = 1; > goto err_out; > } >@@ -1139,6 +1246,9 @@ static int ahci_init_one (struct pci_dev > mmio_base = ioremap(pci_resource_start(pdev, AHCI_PCI_BAR), > pci_resource_len(pdev, AHCI_PCI_BAR)); > if (mmio_base == NULL) { >+ printk(KERN_ERR DRV_NAME "(%s): cannot ioremap PCI %lu mmio space at 0x%lx\n", >+ pci_name(pdev), pci_resource_start(pdev, AHCI_PCI_BAR), >+ pci_resource_len(pdev, AHCI_PCI_BAR)); > rc = -ENOMEM; > goto err_out_free_ent; > }
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
Actions:
View
|
Diff
Attachments on
bug 151517
:
68857
|
69602
|
69656
|
70613
| 73634