| From 3100d49d3cd236443faae9d81137c81b22d36003 Mon Sep 17 00:00:00 2001 |
| From: Mikael Pettersson <mikpe@it.uu.se> |
| Date: Sun, 16 Sep 2012 20:53:43 +0200 |
| Subject: sata_promise: fix hardreset lockdep error |
| |
| From: Mikael Pettersson <mikpe@it.uu.se> |
| |
| commit 3100d49d3cd236443faae9d81137c81b22d36003 upstream. |
| |
| sata_promise's pdc_hard_reset_port() needs to serialize because it |
| flips a port-specific bit in controller register that's shared by |
| all ports. The code takes the ata host lock for this, but that's |
| broken because an interrupt may arrive on our irq during the hard |
| reset sequence, and that too will take the ata host lock. With |
| lockdep enabled a big nasty warning is seen. |
| |
| Fixed by adding private state to the ata host structure, containing |
| a second lock used only for serializing the hard reset sequences. |
| This eliminated the lockdep warnings both on my test rig and on |
| the original reporter's machine. |
| |
| Signed-off-by: Mikael Pettersson <mikpe@it.uu.se> |
| Tested-by: Adko Branil <adkobranil@yahoo.com> |
| Signed-off-by: Jeff Garzik <jgarzik@redhat.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/ata/sata_promise.c | 15 +++++++++++++-- |
| 1 file changed, 13 insertions(+), 2 deletions(-) |
| |
| --- a/drivers/ata/sata_promise.c |
| +++ b/drivers/ata/sata_promise.c |
| @@ -147,6 +147,10 @@ struct pdc_port_priv { |
| dma_addr_t pkt_dma; |
| }; |
| |
| +struct pdc_host_priv { |
| + spinlock_t hard_reset_lock; |
| +}; |
| + |
| static int pdc_sata_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val); |
| static int pdc_sata_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val); |
| static int pdc_ata_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); |
| @@ -801,9 +805,10 @@ static void pdc_hard_reset_port(struct a |
| void __iomem *host_mmio = ap->host->iomap[PDC_MMIO_BAR]; |
| void __iomem *pcictl_b1_mmio = host_mmio + PDC_PCI_CTL + 1; |
| unsigned int ata_no = pdc_ata_port_to_ata_no(ap); |
| + struct pdc_host_priv *hpriv = ap->host->private_data; |
| u8 tmp; |
| |
| - spin_lock(&ap->host->lock); |
| + spin_lock(&hpriv->hard_reset_lock); |
| |
| tmp = readb(pcictl_b1_mmio); |
| tmp &= ~(0x10 << ata_no); |
| @@ -814,7 +819,7 @@ static void pdc_hard_reset_port(struct a |
| writeb(tmp, pcictl_b1_mmio); |
| readb(pcictl_b1_mmio); /* flush */ |
| |
| - spin_unlock(&ap->host->lock); |
| + spin_unlock(&hpriv->hard_reset_lock); |
| } |
| |
| static int pdc_sata_hardreset(struct ata_link *link, unsigned int *class, |
| @@ -1183,6 +1188,7 @@ static int pdc_ata_init_one(struct pci_d |
| const struct ata_port_info *pi = &pdc_port_info[ent->driver_data]; |
| const struct ata_port_info *ppi[PDC_MAX_PORTS]; |
| struct ata_host *host; |
| + struct pdc_host_priv *hpriv; |
| void __iomem *host_mmio; |
| int n_ports, i, rc; |
| int is_sataii_tx4; |
| @@ -1220,6 +1226,11 @@ static int pdc_ata_init_one(struct pci_d |
| dev_printk(KERN_ERR, &pdev->dev, "failed to allocate host\n"); |
| return -ENOMEM; |
| } |
| + hpriv = devm_kzalloc(&pdev->dev, sizeof *hpriv, GFP_KERNEL); |
| + if (!hpriv) |
| + return -ENOMEM; |
| + spin_lock_init(&hpriv->hard_reset_lock); |
| + host->private_data = hpriv; |
| host->iomap = pcim_iomap_table(pdev); |
| |
| is_sataii_tx4 = pdc_is_sataii_tx4(pi->flags); |