aboutsummaryrefslogtreecommitdiff
path: root/pkgs/patches-linux-5.15/0025-PCI-pci-bridge-emul-Add-support-for-PCIe-extended-ca.patch
diff options
context:
space:
mode:
Diffstat (limited to 'pkgs/patches-linux-5.15/0025-PCI-pci-bridge-emul-Add-support-for-PCIe-extended-ca.patch')
-rw-r--r--pkgs/patches-linux-5.15/0025-PCI-pci-bridge-emul-Add-support-for-PCIe-extended-ca.patch179
1 files changed, 179 insertions, 0 deletions
diff --git a/pkgs/patches-linux-5.15/0025-PCI-pci-bridge-emul-Add-support-for-PCIe-extended-ca.patch b/pkgs/patches-linux-5.15/0025-PCI-pci-bridge-emul-Add-support-for-PCIe-extended-ca.patch
new file mode 100644
index 0000000..27e7b57
--- /dev/null
+++ b/pkgs/patches-linux-5.15/0025-PCI-pci-bridge-emul-Add-support-for-PCIe-extended-ca.patch
@@ -0,0 +1,179 @@
+From 09ccac06bf207e939bd00487bb8e2b7bdc1cddf2 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Tue, 2 Feb 2021 13:57:04 +0000
+Subject: [PATCH 25/90] PCI: pci-bridge-emul: Add support for PCIe extended
+ capabilities
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Add support for PCIe extended capabilities, which we just redirect to the
+emulating driver.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+[pali: Fix writing new value with W1C bits]
+Signed-off-by: Pali Rohár <pali@kernel.org>
+Signed-off-by: Marek Behún <kabel@kernel.org>
+---
+ drivers/pci/pci-bridge-emul.c | 77 +++++++++++++++++++++++------------
+ drivers/pci/pci-bridge-emul.h | 15 +++++++
+ 2 files changed, 67 insertions(+), 25 deletions(-)
+
+diff --git a/drivers/pci/pci-bridge-emul.c b/drivers/pci/pci-bridge-emul.c
+index a956408834d6..c4b9837006ff 100644
+--- a/drivers/pci/pci-bridge-emul.c
++++ b/drivers/pci/pci-bridge-emul.c
+@@ -437,10 +437,16 @@ int pci_bridge_emul_conf_read(struct pci_bridge_emul *bridge, int where,
+ read_op = bridge->ops->read_pcie;
+ cfgspace = (__le32 *) &bridge->pcie_conf;
+ behavior = bridge->pcie_cap_regs_behavior;
+- } else {
+- /* Beyond our PCIe space */
++ } else if (reg < PCI_CFG_SPACE_SIZE) {
++ /* Rest of PCI space not implemented */
+ *value = 0;
+ return PCIBIOS_SUCCESSFUL;
++ } else {
++ /* PCIe extended capability space */
++ reg -= PCI_CFG_SPACE_SIZE;
++ read_op = bridge->ops->read_ext;
++ cfgspace = NULL;
++ behavior = NULL;
+ }
+
+ if (read_op)
+@@ -448,15 +454,20 @@ int pci_bridge_emul_conf_read(struct pci_bridge_emul *bridge, int where,
+ else
+ ret = PCI_BRIDGE_EMUL_NOT_HANDLED;
+
+- if (ret == PCI_BRIDGE_EMUL_NOT_HANDLED)
+- *value = le32_to_cpu(cfgspace[reg / 4]);
++ if (ret == PCI_BRIDGE_EMUL_NOT_HANDLED) {
++ if (cfgspace)
++ *value = le32_to_cpu(cfgspace[reg / 4]);
++ else
++ *value = 0;
++ }
+
+ /*
+ * Make sure we never return any reserved bit with a value
+ * different from 0.
+ */
+- *value &= behavior[reg / 4].ro | behavior[reg / 4].rw |
+- behavior[reg / 4].w1c;
++ if (behavior)
++ *value &= behavior[reg / 4].ro | behavior[reg / 4].rw |
++ behavior[reg / 4].w1c;
+
+ if (size == 1)
+ *value = (*value >> (8 * (where & 3))) & 0xff;
+@@ -502,8 +513,15 @@ int pci_bridge_emul_conf_write(struct pci_bridge_emul *bridge, int where,
+ write_op = bridge->ops->write_pcie;
+ cfgspace = (__le32 *) &bridge->pcie_conf;
+ behavior = bridge->pcie_cap_regs_behavior;
+- } else {
++ } else if (reg < PCI_CFG_SPACE_SIZE) {
++ /* Rest of PCI space not implemented */
+ return PCIBIOS_SUCCESSFUL;
++ } else {
++ /* PCIe extended capability space */
++ reg -= PCI_CFG_SPACE_SIZE;
++ write_op = bridge->ops->write_ext;
++ cfgspace = NULL;
++ behavior = NULL;
+ }
+
+ shift = (where & 0x3) * 8;
+@@ -517,29 +535,38 @@ int pci_bridge_emul_conf_write(struct pci_bridge_emul *bridge, int where,
+ else
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+- /* Keep all bits, except the RW bits */
+- new = old & (~mask | ~behavior[reg / 4].rw);
++ if (behavior) {
++ /* Keep all bits, except the RW bits */
++ new = old & (~mask | ~behavior[reg / 4].rw);
+
+- /* Update the value of the RW bits */
+- new |= (value << shift) & (behavior[reg / 4].rw & mask);
++ /* Update the value of the RW bits */
++ new |= (value << shift) & (behavior[reg / 4].rw & mask);
+
+- /* Clear the W1C bits */
+- new &= ~((value << shift) & (behavior[reg / 4].w1c & mask));
++ /* Clear the W1C bits */
++ new &= ~((value << shift) & (behavior[reg / 4].w1c & mask));
++ } else {
++ new = old & ~mask;
++ new |= (value << shift) & mask;
++ }
+
+- /* Save the new value with the cleared W1C bits into the cfgspace */
+- cfgspace[reg / 4] = cpu_to_le32(new);
++ if (cfgspace) {
++ /* Save the new value with the cleared W1C bits into the cfgspace */
++ cfgspace[reg / 4] = cpu_to_le32(new);
++ }
+
+- /*
+- * Clear the W1C bits not specified by the write mask, so that the
+- * write_op() does not clear them.
+- */
+- new &= ~(behavior[reg / 4].w1c & ~mask);
++ if (behavior) {
++ /*
++ * Clear the W1C bits not specified by the write mask, so that the
++ * write_op() does not clear them.
++ */
++ new &= ~(behavior[reg / 4].w1c & ~mask);
+
+- /*
+- * Set the W1C bits specified by the write mask, so that write_op()
+- * knows about that they are to be cleared.
+- */
+- new |= (value << shift) & (behavior[reg / 4].w1c & mask);
++ /*
++ * Set the W1C bits specified by the write mask, so that write_op()
++ * knows about that they are to be cleared.
++ */
++ new |= (value << shift) & (behavior[reg / 4].w1c & mask);
++ }
+
+ if (write_op)
+ write_op(bridge, reg, old, new, mask);
+diff --git a/drivers/pci/pci-bridge-emul.h b/drivers/pci/pci-bridge-emul.h
+index 4953274cac18..6b5f75b2ad02 100644
+--- a/drivers/pci/pci-bridge-emul.h
++++ b/drivers/pci/pci-bridge-emul.h
+@@ -90,6 +90,14 @@ struct pci_bridge_emul_ops {
+ */
+ pci_bridge_emul_read_status_t (*read_pcie)(struct pci_bridge_emul *bridge,
+ int reg, u32 *value);
++
++ /*
++ * Same as ->read_base(), except it is for reading from the
++ * PCIe extended capability configuration space.
++ */
++ pci_bridge_emul_read_status_t (*read_ext)(struct pci_bridge_emul *bridge,
++ int reg, u32 *value);
++
+ /*
+ * Called when writing to the regular PCI bridge configuration
+ * space. old is the current value, new is the new value being
+@@ -105,6 +113,13 @@ struct pci_bridge_emul_ops {
+ */
+ void (*write_pcie)(struct pci_bridge_emul *bridge, int reg,
+ u32 old, u32 new, u32 mask);
++
++ /*
++ * Same as ->write_base(), except it is for writing from the
++ * PCIe extended capability configuration space.
++ */
++ void (*write_ext)(struct pci_bridge_emul *bridge, int reg,
++ u32 old, u32 new, u32 mask);
+ };
+
+ struct pci_bridge_reg_behavior;
+--
+2.34.1
+