diff options
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.patch | 179 |
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 + |