summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCasey Leedom <leedom@chelsio.com>2013-08-06 15:48:36 +0530
committerBjorn Helgaas <bhelgaas@google.com>2013-08-12 13:47:09 -0600
commit3775a209d38aa3a0c7ed89a7d0f529e0230f280e (patch)
treec3d6d6e76b2ddbfba682d613b131e7341afa396e
parent3b2f64d00c46e1e4e9bd0bb9bb12619adac27a4b (diff)
downloadlinux-stable-3775a209d38aa3a0c7ed89a7d0f529e0230f280e.tar.gz
linux-stable-3775a209d38aa3a0c7ed89a7d0f529e0230f280e.tar.bz2
linux-stable-3775a209d38aa3a0c7ed89a7d0f529e0230f280e.zip
PCI: Add pci_wait_for_pending_transaction()
New routine to avoid duplication of code to wait for pending PCI transactions to complete. Signed-off-by: Casey Leedom <leedom@chelsio.com> Signed-off-by: Vipul Pandya <vipul@chelsio.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
-rw-r--r--drivers/pci/pci.c38
-rw-r--r--include/linux/pci.h1
2 files changed, 26 insertions, 13 deletions
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index e37fea6e178d..10ab64e8878e 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -3098,19 +3098,17 @@ int pci_set_dma_seg_boundary(struct pci_dev *dev, unsigned long mask)
}
EXPORT_SYMBOL(pci_set_dma_seg_boundary);
-static int pcie_flr(struct pci_dev *dev, int probe)
+/**
+ * pci_wait_for_pending_transaction - waits for pending transaction
+ * @dev: the PCI device to operate on
+ *
+ * Return 0 if transaction is pending 1 otherwise.
+ */
+int pci_wait_for_pending_transaction(struct pci_dev *dev)
{
int i;
- u32 cap;
u16 status;
- pcie_capability_read_dword(dev, PCI_EXP_DEVCAP, &cap);
- if (!(cap & PCI_EXP_DEVCAP_FLR))
- return -ENOTTY;
-
- if (probe)
- return 0;
-
/* Wait for Transaction Pending bit clean */
for (i = 0; i < 4; i++) {
if (i)
@@ -3118,13 +3116,27 @@ static int pcie_flr(struct pci_dev *dev, int probe)
pcie_capability_read_word(dev, PCI_EXP_DEVSTA, &status);
if (!(status & PCI_EXP_DEVSTA_TRPND))
- goto clear;
+ return 1;
}
- dev_err(&dev->dev, "transaction is not cleared; "
- "proceeding with reset anyway\n");
+ return 0;
+}
+EXPORT_SYMBOL(pci_wait_for_pending_transaction);
+
+static int pcie_flr(struct pci_dev *dev, int probe)
+{
+ u32 cap;
+
+ pcie_capability_read_dword(dev, PCI_EXP_DEVCAP, &cap);
+ if (!(cap & PCI_EXP_DEVCAP_FLR))
+ return -ENOTTY;
+
+ if (probe)
+ return 0;
+
+ if (!pci_wait_for_pending_transaction(dev))
+ dev_err(&dev->dev, "transaction is not cleared; proceeding with reset anyway\n");
-clear:
pcie_capability_set_word(dev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_BCR_FLR);
msleep(100);
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 0fd1f1582fa1..e6470016c718 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -914,6 +914,7 @@ bool pci_check_and_unmask_intx(struct pci_dev *dev);
void pci_msi_off(struct pci_dev *dev);
int pci_set_dma_max_seg_size(struct pci_dev *dev, unsigned int size);
int pci_set_dma_seg_boundary(struct pci_dev *dev, unsigned long mask);
+int pci_wait_for_pending_transaction(struct pci_dev *dev);
int pcix_get_max_mmrbc(struct pci_dev *dev);
int pcix_get_mmrbc(struct pci_dev *dev);
int pcix_set_mmrbc(struct pci_dev *dev, int mmrbc);