[PATCH v4 2/3] PCI: Enable support for 10-bit Tag during device enumeration

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

 



Enable support for PCI Express 10-bit Tag.

A requester may use 10-bit Tag only if its "10-bit Tag Requester Enable"
control bit (PCI_EXP_DEVCTL2_10BIT_TAG_REQ) is set. Enable 10-bit Tag
Requester Enable if the requester supports 10-bit Tag Requester capability
and its completer supports 10-bit Tag Completions.

Platform FW may enable 10-bit Tag Requester during boot for performance
reasons as per PCIe r6.0 sec 2.2.6.2 [1]. It states that "For platforms
where the RC supports 10-Bit Tag Completer capability, it is highly
recommended for platform firmware or operating software that configures
PCIe hierarchies to Set the 10-Bit Tag Requester Enable bit automatically
in Endpoints with 10-Bit Tag Requester capability".

And, failure to enable 10-bit Tag appropriately has led to issues reaching
to the device. The device became inaccessible and the port was not able to
be recovered without a system reset when a device with 10-bit Tag was
removed and replaced with a device that didn't support 10-bit Tag.

PCIe r6.0 sec 2.2.6.2 [1], also implies that:

* If a Requester sends a 10-Bit Tag Request to a Completer that lacks
10-Bit Completer capability, the returned Completion(s) will have Tags with
Tag[9:8] equal to 00b. Since the Requester is forbidden to generate these
Tag values for 10-Bit Tags, such Completions will be handled as Unexpected
Completions, which by default are Advisory Non-Fatal Errors. The Requester
must follow standard PCI Express error handling requirements.

* In configurations where a Requester with 10-Bit Tag Requester capability
needs to target multiple Completers, one needs to ensure that the Requester
sends 10-Bit Tag Requests only to Completers that have 10-Bit Tag Completer
capability.

Hence, ensure whether these capabilities are re-negotiated and enable them
appropriately, especially when a device is surprise removed and replaced
with a new one.

[1] PCI Express Base Specification Revision 6.0, Dec 16 2021.
    https://members.pcisig.com/wg/PCI-SIG/document/16609

Signed-off-by: Smita Koralahalli <Smita.KoralahalliChannabasappa@xxxxxxx>
---
 drivers/pci/pci.c             | 59 +++++++++++++++++++++++++++++++++++
 drivers/pci/pci.h             |  1 +
 drivers/pci/probe.c           |  1 +
 include/uapi/linux/pci_regs.h |  3 ++
 4 files changed, 64 insertions(+)

diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 60230da957e0..7e640694fa03 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -3795,6 +3795,65 @@ int pci_rebar_set_size(struct pci_dev *pdev, int bar, int size)
 	return 0;
 }
 
+/*
+ * pci_configure_ten_bit_tag - enable or disable 10-bit Tag Requester
+ * @dev: the PCI device
+ */
+void pci_configure_ten_bit_tag(struct pci_dev *dev)
+{
+	struct pci_dev *bridge;
+	u32 cap;
+
+	if (!pci_is_pcie(dev))
+		return;
+
+	bridge = dev->bus->self;
+	if (!bridge)
+		return;
+
+	/*
+	 * According to PCIe r6.0 sec 7.5.3.16, the result is undefined if
+	 * the value of this bit is changed while the Function has outstanding
+	 * Non-Posted Requests.
+	 */
+	if (!pci_wait_for_pending_transaction(dev)) {
+		pci_info(dev, "Transaction in progress, 10-bit Tag not configured properly\n");
+		return;
+	}
+
+	/*
+	 * According to PCIe r6.0 sec 7.5.3.15, Requester Supported can only be
+	 * set if 10-Bit Tag Completer Supported bit is set.
+	 */
+	pcie_capability_read_dword(bridge, PCI_EXP_DEVCAP2, &cap);
+	if (!(cap & PCI_EXP_DEVCAP2_10BIT_TAG_COMP))
+		goto out;
+
+	if (cap & PCI_EXP_DEVCAP2_10BIT_TAG_REQ) {
+		pcie_capability_read_dword(dev, PCI_EXP_DEVCAP2, &cap);
+
+		if (!(cap & PCI_EXP_DEVCAP2_10BIT_TAG_COMP))
+			goto out;
+
+		pcie_capability_set_word(bridge, PCI_EXP_DEVCTL2,
+					 PCI_EXP_DEVCTL2_10BIT_TAG_REQ);
+
+		if (cap & PCI_EXP_DEVCAP2_10BIT_TAG_REQ)
+			pcie_capability_set_word(dev, PCI_EXP_DEVCTL2,
+						 PCI_EXP_DEVCTL2_10BIT_TAG_REQ);
+		else
+			pcie_capability_clear_word(dev, PCI_EXP_DEVCTL2,
+						   PCI_EXP_DEVCTL2_10BIT_TAG_REQ);
+		return;
+	}
+
+out:
+	pcie_capability_clear_word(bridge, PCI_EXP_DEVCTL2,
+				   PCI_EXP_DEVCTL2_10BIT_TAG_REQ);
+	pcie_capability_clear_word(dev, PCI_EXP_DEVCTL2,
+				   PCI_EXP_DEVCTL2_10BIT_TAG_REQ);
+}
+
 /**
  * pci_enable_atomic_ops_to_root - enable AtomicOp requests to root port
  * @dev: the PCI device
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index a4c397434057..dee6241878fc 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -239,6 +239,7 @@ int pci_setup_device(struct pci_dev *dev);
 int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
 		    struct resource *res, unsigned int reg);
 void pci_configure_ari(struct pci_dev *dev);
+void pci_configure_ten_bit_tag(struct pci_dev *dev);
 void __pci_bus_size_bridges(struct pci_bus *bus,
 			struct list_head *realloc_head);
 void __pci_bus_assign_resources(const struct pci_bus *bus,
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 8bac3ce02609..5a3c1ec6fad6 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -2476,6 +2476,7 @@ static void pci_init_capabilities(struct pci_dev *dev)
 	pci_pm_init(dev);		/* Power Management */
 	pci_vpd_init(dev);		/* Vital Product Data */
 	pci_configure_ari(dev);		/* Alternative Routing-ID Forwarding */
+	pci_configure_ten_bit_tag(dev); /* 10-bit Tag Requester */
 	pci_iov_init(dev);		/* Single Root I/O Virtualization */
 	pci_ats_init(dev);		/* Address Translation Services */
 	pci_pri_init(dev);		/* Page Request Interface */
diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h
index e5f558d96493..b0a41c987ac5 100644
--- a/include/uapi/linux/pci_regs.h
+++ b/include/uapi/linux/pci_regs.h
@@ -656,6 +656,8 @@
 #define  PCI_EXP_DEVCAP2_ATOMIC_COMP128	0x00000200 /* 128b AtomicOp completion */
 #define  PCI_EXP_DEVCAP2_LTR		0x00000800 /* Latency tolerance reporting */
 #define  PCI_EXP_DEVCAP2_OBFF_MASK	0x000c0000 /* OBFF support mechanism */
+#define  PCI_EXP_DEVCAP2_10BIT_TAG_COMP 0x00010000 /* 10-bit Tag Completer */
+#define  PCI_EXP_DEVCAP2_10BIT_TAG_REQ  0x00020000 /* 10-bit Tag Requester */
 #define  PCI_EXP_DEVCAP2_OBFF_MSG	0x00040000 /* New message signaling */
 #define  PCI_EXP_DEVCAP2_OBFF_WAKE	0x00080000 /* Re-use WAKE# for OBFF */
 #define  PCI_EXP_DEVCAP2_EE_PREFIX	0x00200000 /* End-End TLP Prefix */
@@ -668,6 +670,7 @@
 #define  PCI_EXP_DEVCTL2_IDO_REQ_EN	0x0100	/* Allow IDO for requests */
 #define  PCI_EXP_DEVCTL2_IDO_CMP_EN	0x0200	/* Allow IDO for completions */
 #define  PCI_EXP_DEVCTL2_LTR_EN		0x0400	/* Enable LTR mechanism */
+#define  PCI_EXP_DEVCTL2_10BIT_TAG_REQ  0x1000  /* Enable 10-bit Tag Requester */
 #define  PCI_EXP_DEVCTL2_OBFF_MSGA_EN	0x2000	/* Enable OBFF Message type A */
 #define  PCI_EXP_DEVCTL2_OBFF_MSGB_EN	0x4000	/* Enable OBFF Message type B */
 #define  PCI_EXP_DEVCTL2_OBFF_WAKE_EN	0x6000	/* OBFF using WAKE# signaling */
-- 
2.17.1




[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