[PATCH 4/4] PCI: Extend pci_reset_function() to support PCI Advanced Feature

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Some PCI device implemented PCI Advanced Feature, which is also support
Function Level Reset(FLR).

Signed-off-by: Sheng Yang <sheng@xxxxxxxxxxxxxxx>
---
 drivers/pci/pci.c |   38 ++++++++++++++++++++++++++++++++++++--
 1 files changed, 36 insertions(+), 2 deletions(-)

diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 2077aee..c432473 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -1752,6 +1752,7 @@ EXPORT_SYMBOL(pci_set_dma_seg_boundary);
 #endif
 
 #define PCI_RESET_FUNC_CAP_PCIE_FLR	    0
+#define PCI_RESET_FUNC_CAP_PCI_AF_FLR	    1
 static int __pci_check_reset_function_cap(struct pci_dev *dev)
 {
 	int cappos;
@@ -1764,6 +1765,13 @@ static int __pci_check_reset_function_cap(struct pci_dev *dev)
 			return PCI_RESET_FUNC_CAP_PCIE_FLR;
 	}
 
+	cappos = pci_find_capability(dev, PCI_CAP_ID_AF);
+	if (cappos) {
+		pci_read_config_byte(dev, cappos + PCI_AF_CAP, (u8 *)&cap);
+		if ((cap & PCI_AF_CAP_TP) && (cap & PCI_AF_CAP_FLR))
+			return PCI_RESET_FUNC_CAP_PCI_AF_FLR;
+	}
+
 	return -ENOTTY;
 }
 
@@ -1798,7 +1806,8 @@ int pci_execute_reset_function(struct pci_dev *dev)
 	r = 0;
 	pci_block_user_cfg_access(dev);
 
-	if (reset_cap == PCI_RESET_FUNC_CAP_PCIE_FLR) {
+	switch (reset_cap) {
+	case PCI_RESET_FUNC_CAP_PCIE_FLR:
 		/* Wait for Transaction Pending bit clean */
 		msleep(100);
 		cappos = pci_find_capability(dev, PCI_CAP_ID_EXP);
@@ -1816,8 +1825,33 @@ int pci_execute_reset_function(struct pci_dev *dev)
 		pci_write_config_word(dev, cappos + PCI_EXP_DEVCTL,
 				PCI_EXP_DEVCTL_BCR_FLR);
 		mdelay(100);
-	} else
+		break;
+
+	case PCI_RESET_FUNC_CAP_PCI_AF_FLR:
+		/* Wait for Transaction Pending bit clean */
+		msleep(100);
+		cappos = pci_find_capability(dev, PCI_CAP_ID_AF);
+		pci_read_config_byte(dev, cappos + PCI_AF_STATUS,
+				    (u8 *)&status);
+		if (status & PCI_AF_STATUS_TP) {
+			dev_info(&dev->dev, "Busy after 100ms while trying to"
+					" reset; sleeping for 1 second\n");
+			ssleep(1);
+			pci_read_config_byte(dev,
+					cappos + PCI_AF_STATUS, (u8 *)&status);
+			if (status & PCI_AF_STATUS_TP)
+				dev_info(&dev->dev, "Still busy after 1s; "
+					"proceeding with reset anyway\n");
+		}
+		pci_write_config_byte(dev, cappos + PCI_AF_CTRL,
+				PCI_AF_CTRL_FLR);
+		mdelay(100);
+		break;
+
+	default:
 		r = -ENOTTY;
+		break;
+	}
 
 	pci_unblock_user_cfg_access(dev);
 	return r;
-- 
1.5.4.5

--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [DMA Engine]     [Linux Coverity]     [Linux USB]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Greybus]

  Powered by Linux