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

From: Smita Koralahalli
Date: Tue Aug 15 2023 - 17:21:43 EST


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