From 2da2670346795f8fe06acbf499606941303b9cbe Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sat, 25 Nov 2023 15:39:08 +0000 Subject: [PATCH] fix up some 6.5 pci quirk stuff --- ...nterfaces-for-creating-device-node-d.patch | 299 --------- ...o-generate-device-tree-node-for-xili.patch | 50 -- ...i-create-device-tree-node-for-bridge.patch | 587 ------------------ ...et-delay-for-videopropulsion-torrent.patch | 8 +- queue-6.5/series | 3 - 5 files changed, 4 insertions(+), 943 deletions(-) delete mode 100644 queue-6.5/of-dynamic-add-interfaces-for-creating-device-node-d.patch delete mode 100644 queue-6.5/pci-add-quirks-to-generate-device-tree-node-for-xili.patch delete mode 100644 queue-6.5/pci-create-device-tree-node-for-bridge.patch diff --git a/queue-6.5/of-dynamic-add-interfaces-for-creating-device-node-d.patch b/queue-6.5/of-dynamic-add-interfaces-for-creating-device-node-d.patch deleted file mode 100644 index 9fc9ab46d7b..00000000000 --- a/queue-6.5/of-dynamic-add-interfaces-for-creating-device-node-d.patch +++ /dev/null @@ -1,299 +0,0 @@ -From b0dc903a6b9bcabc68b1cb6580c510cb7ab93b38 Mon Sep 17 00:00:00 2001 -From: Sasha Levin -Date: Tue, 15 Aug 2023 10:19:56 -0700 -Subject: of: dynamic: Add interfaces for creating device node dynamically -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -From: Lizhi Hou - -[ Upstream commit b544fc2b8606d718d0cc788ff2ea2492871df488 ] - -of_changeset_create_node() creates device node dynamically and attaches -the newly created node to a changeset. - -Expand of_changeset APIs to handle specific types of properties. - of_changeset_add_prop_string() - of_changeset_add_prop_string_array() - of_changeset_add_prop_u32_array() - -Signed-off-by: Clément Léger -Signed-off-by: Lizhi Hou -Link: https://lore.kernel.org/r/1692120000-46900-2-git-send-email-lizhi.hou@amd.com -Signed-off-by: Rob Herring -Stable-dep-of: c9260693aa0c ("PCI: Lengthen reset delay for VideoPropulsion Torrent QN16e card") -Signed-off-by: Sasha Levin ---- - drivers/of/dynamic.c | 164 ++++++++++++++++++++++++++++++++++++++++++ - drivers/of/unittest.c | 19 ++++- - include/linux/of.h | 23 ++++++ - 3 files changed, 205 insertions(+), 1 deletion(-) - -diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c -index f7bb73cf821e6..cdad63ecb9023 100644 ---- a/drivers/of/dynamic.c -+++ b/drivers/of/dynamic.c -@@ -486,6 +486,38 @@ struct device_node *__of_node_dup(const struct device_node *np, - return NULL; - } - -+/** -+ * of_changeset_create_node - Dynamically create a device node and attach to -+ * a given changeset. -+ * -+ * @ocs: Pointer to changeset -+ * @parent: Pointer to parent device node -+ * @full_name: Node full name -+ * -+ * Return: Pointer to the created device node or NULL in case of an error. -+ */ -+struct device_node *of_changeset_create_node(struct of_changeset *ocs, -+ struct device_node *parent, -+ const char *full_name) -+{ -+ struct device_node *np; -+ int ret; -+ -+ np = __of_node_dup(NULL, full_name); -+ if (!np) -+ return NULL; -+ np->parent = parent; -+ -+ ret = of_changeset_attach_node(ocs, np); -+ if (ret) { -+ of_node_put(np); -+ return NULL; -+ } -+ -+ return np; -+} -+EXPORT_SYMBOL(of_changeset_create_node); -+ - static void __of_changeset_entry_destroy(struct of_changeset_entry *ce) - { - if (ce->action == OF_RECONFIG_ATTACH_NODE && -@@ -947,3 +979,135 @@ int of_changeset_action(struct of_changeset *ocs, unsigned long action, - return 0; - } - EXPORT_SYMBOL_GPL(of_changeset_action); -+ -+static int of_changeset_add_prop_helper(struct of_changeset *ocs, -+ struct device_node *np, -+ const struct property *pp) -+{ -+ struct property *new_pp; -+ int ret; -+ -+ new_pp = __of_prop_dup(pp, GFP_KERNEL); -+ if (!new_pp) -+ return -ENOMEM; -+ -+ ret = of_changeset_add_property(ocs, np, new_pp); -+ if (ret) { -+ kfree(new_pp->name); -+ kfree(new_pp->value); -+ kfree(new_pp); -+ } -+ -+ return ret; -+} -+ -+/** -+ * of_changeset_add_prop_string - Add a string property to a changeset -+ * -+ * @ocs: changeset pointer -+ * @np: device node pointer -+ * @prop_name: name of the property to be added -+ * @str: pointer to null terminated string -+ * -+ * Create a string property and add it to a changeset. -+ * -+ * Return: 0 on success, a negative error value in case of an error. -+ */ -+int of_changeset_add_prop_string(struct of_changeset *ocs, -+ struct device_node *np, -+ const char *prop_name, const char *str) -+{ -+ struct property prop; -+ -+ prop.name = (char *)prop_name; -+ prop.length = strlen(str) + 1; -+ prop.value = (void *)str; -+ -+ return of_changeset_add_prop_helper(ocs, np, &prop); -+} -+EXPORT_SYMBOL_GPL(of_changeset_add_prop_string); -+ -+/** -+ * of_changeset_add_prop_string_array - Add a string list property to -+ * a changeset -+ * -+ * @ocs: changeset pointer -+ * @np: device node pointer -+ * @prop_name: name of the property to be added -+ * @str_array: pointer to an array of null terminated strings -+ * @sz: number of string array elements -+ * -+ * Create a string list property and add it to a changeset. -+ * -+ * Return: 0 on success, a negative error value in case of an error. -+ */ -+int of_changeset_add_prop_string_array(struct of_changeset *ocs, -+ struct device_node *np, -+ const char *prop_name, -+ const char **str_array, size_t sz) -+{ -+ struct property prop; -+ int i, ret; -+ char *vp; -+ -+ prop.name = (char *)prop_name; -+ -+ prop.length = 0; -+ for (i = 0; i < sz; i++) -+ prop.length += strlen(str_array[i]) + 1; -+ -+ prop.value = kmalloc(prop.length, GFP_KERNEL); -+ if (!prop.value) -+ return -ENOMEM; -+ -+ vp = prop.value; -+ for (i = 0; i < sz; i++) { -+ vp += snprintf(vp, (char *)prop.value + prop.length - vp, "%s", -+ str_array[i]) + 1; -+ } -+ ret = of_changeset_add_prop_helper(ocs, np, &prop); -+ kfree(prop.value); -+ -+ return ret; -+} -+EXPORT_SYMBOL_GPL(of_changeset_add_prop_string_array); -+ -+/** -+ * of_changeset_add_prop_u32_array - Add a property of 32 bit integers -+ * property to a changeset -+ * -+ * @ocs: changeset pointer -+ * @np: device node pointer -+ * @prop_name: name of the property to be added -+ * @array: pointer to an array of 32 bit integers -+ * @sz: number of array elements -+ * -+ * Create a property of 32 bit integers and add it to a changeset. -+ * -+ * Return: 0 on success, a negative error value in case of an error. -+ */ -+int of_changeset_add_prop_u32_array(struct of_changeset *ocs, -+ struct device_node *np, -+ const char *prop_name, -+ const u32 *array, size_t sz) -+{ -+ struct property prop; -+ __be32 *val; -+ int i, ret; -+ -+ val = kcalloc(sz, sizeof(__be32), GFP_KERNEL); -+ if (!val) -+ return -ENOMEM; -+ -+ for (i = 0; i < sz; i++) -+ val[i] = cpu_to_be32(array[i]); -+ prop.name = (char *)prop_name; -+ prop.length = sizeof(u32) * sz; -+ prop.value = (void *)val; -+ -+ ret = of_changeset_add_prop_helper(ocs, np, &prop); -+ kfree(val); -+ -+ return ret; -+} -+EXPORT_SYMBOL_GPL(of_changeset_add_prop_u32_array); -diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c -index f6784cce8369b..68e58b085c3db 100644 ---- a/drivers/of/unittest.c -+++ b/drivers/of/unittest.c -@@ -802,7 +802,9 @@ static void __init of_unittest_changeset(void) - struct property *ppname_n21, pname_n21 = { .name = "name", .length = 3, .value = "n21" }; - struct property *ppupdate, pupdate = { .name = "prop-update", .length = 5, .value = "abcd" }; - struct property *ppremove; -- struct device_node *n1, *n2, *n21, *nchangeset, *nremove, *parent, *np; -+ struct device_node *n1, *n2, *n21, *n22, *nchangeset, *nremove, *parent, *np; -+ static const char * const str_array[] = { "str1", "str2", "str3" }; -+ const u32 u32_array[] = { 1, 2, 3 }; - struct of_changeset chgset; - - n1 = __of_node_dup(NULL, "n1"); -@@ -857,6 +859,17 @@ static void __init of_unittest_changeset(void) - unittest(!of_changeset_add_property(&chgset, parent, ppadd), "fail add prop prop-add\n"); - unittest(!of_changeset_update_property(&chgset, parent, ppupdate), "fail update prop\n"); - unittest(!of_changeset_remove_property(&chgset, parent, ppremove), "fail remove prop\n"); -+ n22 = of_changeset_create_node(&chgset, n2, "n22"); -+ unittest(n22, "fail create n22\n"); -+ unittest(!of_changeset_add_prop_string(&chgset, n22, "prop-str", "abcd"), -+ "fail add prop prop-str"); -+ unittest(!of_changeset_add_prop_string_array(&chgset, n22, "prop-str-array", -+ (const char **)str_array, -+ ARRAY_SIZE(str_array)), -+ "fail add prop prop-str-array"); -+ unittest(!of_changeset_add_prop_u32_array(&chgset, n22, "prop-u32-array", -+ u32_array, ARRAY_SIZE(u32_array)), -+ "fail add prop prop-u32-array"); - - unittest(!of_changeset_apply(&chgset), "apply failed\n"); - -@@ -866,6 +879,9 @@ static void __init of_unittest_changeset(void) - unittest((np = of_find_node_by_path("/testcase-data/changeset/n2/n21")), - "'%pOF' not added\n", n21); - of_node_put(np); -+ unittest((np = of_find_node_by_path("/testcase-data/changeset/n2/n22")), -+ "'%pOF' not added\n", n22); -+ of_node_put(np); - - unittest(!of_changeset_revert(&chgset), "revert failed\n"); - -@@ -874,6 +890,7 @@ static void __init of_unittest_changeset(void) - of_node_put(n1); - of_node_put(n2); - of_node_put(n21); -+ of_node_put(n22); - #endif - } - -diff --git a/include/linux/of.h b/include/linux/of.h -index 6ecde0515677d..9b82a6b0f3f55 100644 ---- a/include/linux/of.h -+++ b/include/linux/of.h -@@ -1580,6 +1580,29 @@ static inline int of_changeset_update_property(struct of_changeset *ocs, - { - return of_changeset_action(ocs, OF_RECONFIG_UPDATE_PROPERTY, np, prop); - } -+ -+struct device_node *of_changeset_create_node(struct of_changeset *ocs, -+ struct device_node *parent, -+ const char *full_name); -+int of_changeset_add_prop_string(struct of_changeset *ocs, -+ struct device_node *np, -+ const char *prop_name, const char *str); -+int of_changeset_add_prop_string_array(struct of_changeset *ocs, -+ struct device_node *np, -+ const char *prop_name, -+ const char **str_array, size_t sz); -+int of_changeset_add_prop_u32_array(struct of_changeset *ocs, -+ struct device_node *np, -+ const char *prop_name, -+ const u32 *array, size_t sz); -+static inline int of_changeset_add_prop_u32(struct of_changeset *ocs, -+ struct device_node *np, -+ const char *prop_name, -+ const u32 val) -+{ -+ return of_changeset_add_prop_u32_array(ocs, np, prop_name, &val, 1); -+} -+ - #else /* CONFIG_OF_DYNAMIC */ - static inline int of_reconfig_notifier_register(struct notifier_block *nb) - { --- -2.42.0 - diff --git a/queue-6.5/pci-add-quirks-to-generate-device-tree-node-for-xili.patch b/queue-6.5/pci-add-quirks-to-generate-device-tree-node-for-xili.patch deleted file mode 100644 index 31e98d21e94..00000000000 --- a/queue-6.5/pci-add-quirks-to-generate-device-tree-node-for-xili.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 1bd7f29a9d50fe2ce66158e7e4c6892218dd70f0 Mon Sep 17 00:00:00 2001 -From: Sasha Levin -Date: Tue, 15 Aug 2023 10:19:58 -0700 -Subject: PCI: Add quirks to generate device tree node for Xilinx Alveo U50 - -From: Lizhi Hou - -[ Upstream commit ae9813db1dc5ac987a09889791155a7b8c527f8d ] - -The Xilinx Alveo U50 PCI card exposes multiple hardware peripherals on -its PCI BAR. The card firmware provides a flattened device tree to -describe the hardware peripherals on its BARs. This allows U50 driver to -load the flattened device tree and generate the device tree node for -hardware peripherals underneath. - -To generate device tree node for U50 card, add PCI quirks to call -of_pci_make_dev_node() for U50. - -Acked-by: Bjorn Helgaas -Signed-off-by: Lizhi Hou -Link: https://lore.kernel.org/r/1692120000-46900-4-git-send-email-lizhi.hou@amd.com -Signed-off-by: Rob Herring -Stable-dep-of: c9260693aa0c ("PCI: Lengthen reset delay for VideoPropulsion Torrent QN16e card") -Signed-off-by: Sasha Levin ---- - drivers/pci/quirks.c | 11 +++++++++++ - 1 file changed, 11 insertions(+) - -diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c -index 9fa3c9225bb30..3ec7bcfbf4dc0 100644 ---- a/drivers/pci/quirks.c -+++ b/drivers/pci/quirks.c -@@ -6161,3 +6161,14 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9a2d, dpc_log_size); - DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9a2f, dpc_log_size); - DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9a31, dpc_log_size); - #endif -+ -+/* -+ * For a PCI device with multiple downstream devices, its driver may use -+ * a flattened device tree to describe the downstream devices. -+ * To overlay the flattened device tree, the PCI device and all its ancestor -+ * devices need to have device tree nodes on system base device tree. Thus, -+ * before driver probing, it might need to add a device tree node as the final -+ * fixup. -+ */ -+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_XILINX, 0x5020, of_pci_make_dev_node); -+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_XILINX, 0x5021, of_pci_make_dev_node); --- -2.42.0 - diff --git a/queue-6.5/pci-create-device-tree-node-for-bridge.patch b/queue-6.5/pci-create-device-tree-node-for-bridge.patch deleted file mode 100644 index 23c859619b2..00000000000 --- a/queue-6.5/pci-create-device-tree-node-for-bridge.patch +++ /dev/null @@ -1,587 +0,0 @@ -From 5f5090220d6abc372575d6b4b2bc8e04a5def7f2 Mon Sep 17 00:00:00 2001 -From: Sasha Levin -Date: Tue, 15 Aug 2023 10:19:57 -0700 -Subject: PCI: Create device tree node for bridge - -From: Lizhi Hou - -[ Upstream commit 407d1a51921e9f28c1bcec647c2205925bd1fdab ] - -The PCI endpoint device such as Xilinx Alveo PCI card maps the register -spaces from multiple hardware peripherals to its PCI BAR. Normally, -the PCI core discovers devices and BARs using the PCI enumeration process. -There is no infrastructure to discover the hardware peripherals that are -present in a PCI device, and which can be accessed through the PCI BARs. - -Apparently, the device tree framework requires a device tree node for the -PCI device. Thus, it can generate the device tree nodes for hardware -peripherals underneath. Because PCI is self discoverable bus, there might -not be a device tree node created for PCI devices. Furthermore, if the PCI -device is hot pluggable, when it is plugged in, the device tree nodes for -its parent bridges are required. Add support to generate device tree node -for PCI bridges. - -Add an of_pci_make_dev_node() interface that can be used to create device -tree node for PCI devices. - -Add a PCI_DYNAMIC_OF_NODES config option. When the option is turned on, -the kernel will generate device tree nodes for PCI bridges unconditionally. - -Initially, add the basic properties for the dynamically generated device -tree nodes which include #address-cells, #size-cells, device_type, -compatible, ranges, reg. - -Acked-by: Bjorn Helgaas -Signed-off-by: Lizhi Hou -Link: https://lore.kernel.org/r/1692120000-46900-3-git-send-email-lizhi.hou@amd.com -Signed-off-by: Rob Herring -Stable-dep-of: c9260693aa0c ("PCI: Lengthen reset delay for VideoPropulsion Torrent QN16e card") -Signed-off-by: Sasha Levin ---- - drivers/pci/Kconfig | 12 ++ - drivers/pci/Makefile | 1 + - drivers/pci/bus.c | 2 + - drivers/pci/of.c | 79 +++++++++ - drivers/pci/of_property.c | 355 ++++++++++++++++++++++++++++++++++++++ - drivers/pci/pci.h | 12 ++ - drivers/pci/remove.c | 1 + - 7 files changed, 462 insertions(+) - create mode 100644 drivers/pci/of_property.c - -diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig -index 3c07d8d214b38..49bd09c7dd0a1 100644 ---- a/drivers/pci/Kconfig -+++ b/drivers/pci/Kconfig -@@ -194,6 +194,18 @@ config PCI_HYPERV - The PCI device frontend driver allows the kernel to import arbitrary - PCI devices from a PCI backend to support PCI driver domains. - -+config PCI_DYNAMIC_OF_NODES -+ bool "Create Device tree nodes for PCI devices" -+ depends on OF -+ select OF_DYNAMIC -+ help -+ This option enables support for generating device tree nodes for some -+ PCI devices. Thus, the driver of this kind can load and overlay -+ flattened device tree for its downstream devices. -+ -+ Once this option is selected, the device tree nodes will be generated -+ for all PCI bridges. -+ - choice - prompt "PCI Express hierarchy optimization setting" - default PCIE_BUS_DEFAULT -diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile -index 2680e4c92f0ab..cc8b4e01e29de 100644 ---- a/drivers/pci/Makefile -+++ b/drivers/pci/Makefile -@@ -32,6 +32,7 @@ obj-$(CONFIG_PCI_P2PDMA) += p2pdma.o - obj-$(CONFIG_XEN_PCIDEV_FRONTEND) += xen-pcifront.o - obj-$(CONFIG_VGA_ARB) += vgaarb.o - obj-$(CONFIG_PCI_DOE) += doe.o -+obj-$(CONFIG_PCI_DYNAMIC_OF_NODES) += of_property.o - - # Endpoint library must be initialized before its users - obj-$(CONFIG_PCI_ENDPOINT) += endpoint/ -diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c -index 46b252bbe5000..9c2137dae429a 100644 ---- a/drivers/pci/bus.c -+++ b/drivers/pci/bus.c -@@ -342,6 +342,8 @@ void pci_bus_add_device(struct pci_dev *dev) - */ - pcibios_bus_add_device(dev); - pci_fixup_device(pci_fixup_final, dev); -+ if (pci_is_bridge(dev)) -+ of_pci_make_dev_node(dev); - pci_create_sysfs_dev_files(dev); - pci_proc_attach_device(dev); - pci_bridge_d3_update(dev); -diff --git a/drivers/pci/of.c b/drivers/pci/of.c -index 3c158b17dcb53..2af64bcb7da3a 100644 ---- a/drivers/pci/of.c -+++ b/drivers/pci/of.c -@@ -606,6 +606,85 @@ int devm_of_pci_bridge_init(struct device *dev, struct pci_host_bridge *bridge) - return pci_parse_request_of_pci_ranges(dev, bridge); - } - -+#ifdef CONFIG_PCI_DYNAMIC_OF_NODES -+ -+void of_pci_remove_node(struct pci_dev *pdev) -+{ -+ struct device_node *np; -+ -+ np = pci_device_to_OF_node(pdev); -+ if (!np || !of_node_check_flag(np, OF_DYNAMIC)) -+ return; -+ pdev->dev.of_node = NULL; -+ -+ of_changeset_revert(np->data); -+ of_changeset_destroy(np->data); -+ of_node_put(np); -+} -+ -+void of_pci_make_dev_node(struct pci_dev *pdev) -+{ -+ struct device_node *ppnode, *np = NULL; -+ const char *pci_type; -+ struct of_changeset *cset; -+ const char *name; -+ int ret; -+ -+ /* -+ * If there is already a device tree node linked to this device, -+ * return immediately. -+ */ -+ if (pci_device_to_OF_node(pdev)) -+ return; -+ -+ /* Check if there is device tree node for parent device */ -+ if (!pdev->bus->self) -+ ppnode = pdev->bus->dev.of_node; -+ else -+ ppnode = pdev->bus->self->dev.of_node; -+ if (!ppnode) -+ return; -+ -+ if (pci_is_bridge(pdev)) -+ pci_type = "pci"; -+ else -+ pci_type = "dev"; -+ -+ name = kasprintf(GFP_KERNEL, "%s@%x,%x", pci_type, -+ PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); -+ if (!name) -+ return; -+ -+ cset = kmalloc(sizeof(*cset), GFP_KERNEL); -+ if (!cset) -+ goto failed; -+ of_changeset_init(cset); -+ -+ np = of_changeset_create_node(cset, ppnode, name); -+ if (!np) -+ goto failed; -+ np->data = cset; -+ -+ ret = of_pci_add_properties(pdev, cset, np); -+ if (ret) -+ goto failed; -+ -+ ret = of_changeset_apply(cset); -+ if (ret) -+ goto failed; -+ -+ pdev->dev.of_node = np; -+ kfree(name); -+ -+ return; -+ -+failed: -+ if (np) -+ of_node_put(np); -+ kfree(name); -+} -+#endif -+ - #endif /* CONFIG_PCI */ - - /** -diff --git a/drivers/pci/of_property.c b/drivers/pci/of_property.c -new file mode 100644 -index 0000000000000..710ec35ba4a17 ---- /dev/null -+++ b/drivers/pci/of_property.c -@@ -0,0 +1,355 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * Copyright (C) 2022-2023, Advanced Micro Devices, Inc. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include "pci.h" -+ -+#define OF_PCI_ADDRESS_CELLS 3 -+#define OF_PCI_SIZE_CELLS 2 -+#define OF_PCI_MAX_INT_PIN 4 -+ -+struct of_pci_addr_pair { -+ u32 phys_addr[OF_PCI_ADDRESS_CELLS]; -+ u32 size[OF_PCI_SIZE_CELLS]; -+}; -+ -+/* -+ * Each entry in the ranges table is a tuple containing the child address, -+ * the parent address, and the size of the region in the child address space. -+ * Thus, for PCI, in each entry parent address is an address on the primary -+ * side and the child address is the corresponding address on the secondary -+ * side. -+ */ -+struct of_pci_range { -+ u32 child_addr[OF_PCI_ADDRESS_CELLS]; -+ u32 parent_addr[OF_PCI_ADDRESS_CELLS]; -+ u32 size[OF_PCI_SIZE_CELLS]; -+}; -+ -+#define OF_PCI_ADDR_SPACE_IO 0x1 -+#define OF_PCI_ADDR_SPACE_MEM32 0x2 -+#define OF_PCI_ADDR_SPACE_MEM64 0x3 -+ -+#define OF_PCI_ADDR_FIELD_NONRELOC BIT(31) -+#define OF_PCI_ADDR_FIELD_SS GENMASK(25, 24) -+#define OF_PCI_ADDR_FIELD_PREFETCH BIT(30) -+#define OF_PCI_ADDR_FIELD_BUS GENMASK(23, 16) -+#define OF_PCI_ADDR_FIELD_DEV GENMASK(15, 11) -+#define OF_PCI_ADDR_FIELD_FUNC GENMASK(10, 8) -+#define OF_PCI_ADDR_FIELD_REG GENMASK(7, 0) -+ -+enum of_pci_prop_compatible { -+ PROP_COMPAT_PCI_VVVV_DDDD, -+ PROP_COMPAT_PCICLASS_CCSSPP, -+ PROP_COMPAT_PCICLASS_CCSS, -+ PROP_COMPAT_NUM, -+}; -+ -+static void of_pci_set_address(struct pci_dev *pdev, u32 *prop, u64 addr, -+ u32 reg_num, u32 flags, bool reloc) -+{ -+ prop[0] = FIELD_PREP(OF_PCI_ADDR_FIELD_BUS, pdev->bus->number) | -+ FIELD_PREP(OF_PCI_ADDR_FIELD_DEV, PCI_SLOT(pdev->devfn)) | -+ FIELD_PREP(OF_PCI_ADDR_FIELD_FUNC, PCI_FUNC(pdev->devfn)); -+ prop[0] |= flags | reg_num; -+ if (!reloc) { -+ prop[0] |= OF_PCI_ADDR_FIELD_NONRELOC; -+ prop[1] = upper_32_bits(addr); -+ prop[2] = lower_32_bits(addr); -+ } -+} -+ -+static int of_pci_get_addr_flags(struct resource *res, u32 *flags) -+{ -+ u32 ss; -+ -+ if (res->flags & IORESOURCE_IO) -+ ss = OF_PCI_ADDR_SPACE_IO; -+ else if (res->flags & IORESOURCE_MEM_64) -+ ss = OF_PCI_ADDR_SPACE_MEM64; -+ else if (res->flags & IORESOURCE_MEM) -+ ss = OF_PCI_ADDR_SPACE_MEM32; -+ else -+ return -EINVAL; -+ -+ *flags = 0; -+ if (res->flags & IORESOURCE_PREFETCH) -+ *flags |= OF_PCI_ADDR_FIELD_PREFETCH; -+ -+ *flags |= FIELD_PREP(OF_PCI_ADDR_FIELD_SS, ss); -+ -+ return 0; -+} -+ -+static int of_pci_prop_bus_range(struct pci_dev *pdev, -+ struct of_changeset *ocs, -+ struct device_node *np) -+{ -+ u32 bus_range[] = { pdev->subordinate->busn_res.start, -+ pdev->subordinate->busn_res.end }; -+ -+ return of_changeset_add_prop_u32_array(ocs, np, "bus-range", bus_range, -+ ARRAY_SIZE(bus_range)); -+} -+ -+static int of_pci_prop_ranges(struct pci_dev *pdev, struct of_changeset *ocs, -+ struct device_node *np) -+{ -+ struct of_pci_range *rp; -+ struct resource *res; -+ int i, j, ret; -+ u32 flags, num; -+ u64 val64; -+ -+ if (pci_is_bridge(pdev)) { -+ num = PCI_BRIDGE_RESOURCE_NUM; -+ res = &pdev->resource[PCI_BRIDGE_RESOURCES]; -+ } else { -+ num = PCI_STD_NUM_BARS; -+ res = &pdev->resource[PCI_STD_RESOURCES]; -+ } -+ -+ rp = kcalloc(num, sizeof(*rp), GFP_KERNEL); -+ if (!rp) -+ return -ENOMEM; -+ -+ for (i = 0, j = 0; j < num; j++) { -+ if (!resource_size(&res[j])) -+ continue; -+ -+ if (of_pci_get_addr_flags(&res[j], &flags)) -+ continue; -+ -+ val64 = res[j].start; -+ of_pci_set_address(pdev, rp[i].parent_addr, val64, 0, flags, -+ false); -+ if (pci_is_bridge(pdev)) { -+ memcpy(rp[i].child_addr, rp[i].parent_addr, -+ sizeof(rp[i].child_addr)); -+ } else { -+ /* -+ * For endpoint device, the lower 64-bits of child -+ * address is always zero. -+ */ -+ rp[i].child_addr[0] = j; -+ } -+ -+ val64 = resource_size(&res[j]); -+ rp[i].size[0] = upper_32_bits(val64); -+ rp[i].size[1] = lower_32_bits(val64); -+ -+ i++; -+ } -+ -+ ret = of_changeset_add_prop_u32_array(ocs, np, "ranges", (u32 *)rp, -+ i * sizeof(*rp) / sizeof(u32)); -+ kfree(rp); -+ -+ return ret; -+} -+ -+static int of_pci_prop_reg(struct pci_dev *pdev, struct of_changeset *ocs, -+ struct device_node *np) -+{ -+ struct of_pci_addr_pair reg = { 0 }; -+ -+ /* configuration space */ -+ of_pci_set_address(pdev, reg.phys_addr, 0, 0, 0, true); -+ -+ return of_changeset_add_prop_u32_array(ocs, np, "reg", (u32 *)®, -+ sizeof(reg) / sizeof(u32)); -+} -+ -+static int of_pci_prop_interrupts(struct pci_dev *pdev, -+ struct of_changeset *ocs, -+ struct device_node *np) -+{ -+ int ret; -+ u8 pin; -+ -+ ret = pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &pin); -+ if (ret != 0) -+ return ret; -+ -+ if (!pin) -+ return 0; -+ -+ return of_changeset_add_prop_u32(ocs, np, "interrupts", (u32)pin); -+} -+ -+static int of_pci_prop_intr_map(struct pci_dev *pdev, struct of_changeset *ocs, -+ struct device_node *np) -+{ -+ struct of_phandle_args out_irq[OF_PCI_MAX_INT_PIN]; -+ u32 i, addr_sz[OF_PCI_MAX_INT_PIN], map_sz = 0; -+ __be32 laddr[OF_PCI_ADDRESS_CELLS] = { 0 }; -+ u32 int_map_mask[] = { 0xffff00, 0, 0, 7 }; -+ struct device_node *pnode; -+ struct pci_dev *child; -+ u32 *int_map, *mapp; -+ int ret; -+ u8 pin; -+ -+ pnode = pci_device_to_OF_node(pdev->bus->self); -+ if (!pnode) -+ pnode = pci_bus_to_OF_node(pdev->bus); -+ -+ if (!pnode) { -+ pci_err(pdev, "failed to get parent device node"); -+ return -EINVAL; -+ } -+ -+ laddr[0] = cpu_to_be32((pdev->bus->number << 16) | (pdev->devfn << 8)); -+ for (pin = 1; pin <= OF_PCI_MAX_INT_PIN; pin++) { -+ i = pin - 1; -+ out_irq[i].np = pnode; -+ out_irq[i].args_count = 1; -+ out_irq[i].args[0] = pin; -+ ret = of_irq_parse_raw(laddr, &out_irq[i]); -+ if (ret) { -+ pci_err(pdev, "parse irq %d failed, ret %d", pin, ret); -+ continue; -+ } -+ ret = of_property_read_u32(out_irq[i].np, "#address-cells", -+ &addr_sz[i]); -+ if (ret) -+ addr_sz[i] = 0; -+ } -+ -+ list_for_each_entry(child, &pdev->subordinate->devices, bus_list) { -+ for (pin = 1; pin <= OF_PCI_MAX_INT_PIN; pin++) { -+ i = pci_swizzle_interrupt_pin(child, pin) - 1; -+ map_sz += 5 + addr_sz[i] + out_irq[i].args_count; -+ } -+ } -+ -+ int_map = kcalloc(map_sz, sizeof(u32), GFP_KERNEL); -+ mapp = int_map; -+ -+ list_for_each_entry(child, &pdev->subordinate->devices, bus_list) { -+ for (pin = 1; pin <= OF_PCI_MAX_INT_PIN; pin++) { -+ *mapp = (child->bus->number << 16) | -+ (child->devfn << 8); -+ mapp += OF_PCI_ADDRESS_CELLS; -+ *mapp = pin; -+ mapp++; -+ i = pci_swizzle_interrupt_pin(child, pin) - 1; -+ *mapp = out_irq[i].np->phandle; -+ mapp++; -+ if (addr_sz[i]) { -+ ret = of_property_read_u32_array(out_irq[i].np, -+ "reg", mapp, -+ addr_sz[i]); -+ if (ret) -+ goto failed; -+ } -+ mapp += addr_sz[i]; -+ memcpy(mapp, out_irq[i].args, -+ out_irq[i].args_count * sizeof(u32)); -+ mapp += out_irq[i].args_count; -+ } -+ } -+ -+ ret = of_changeset_add_prop_u32_array(ocs, np, "interrupt-map", int_map, -+ map_sz); -+ if (ret) -+ goto failed; -+ -+ ret = of_changeset_add_prop_u32(ocs, np, "#interrupt-cells", 1); -+ if (ret) -+ goto failed; -+ -+ ret = of_changeset_add_prop_u32_array(ocs, np, "interrupt-map-mask", -+ int_map_mask, -+ ARRAY_SIZE(int_map_mask)); -+ if (ret) -+ goto failed; -+ -+ kfree(int_map); -+ return 0; -+ -+failed: -+ kfree(int_map); -+ return ret; -+} -+ -+static int of_pci_prop_compatible(struct pci_dev *pdev, -+ struct of_changeset *ocs, -+ struct device_node *np) -+{ -+ const char *compat_strs[PROP_COMPAT_NUM] = { 0 }; -+ int i, ret; -+ -+ compat_strs[PROP_COMPAT_PCI_VVVV_DDDD] = -+ kasprintf(GFP_KERNEL, "pci%x,%x", pdev->vendor, pdev->device); -+ compat_strs[PROP_COMPAT_PCICLASS_CCSSPP] = -+ kasprintf(GFP_KERNEL, "pciclass,%06x", pdev->class); -+ compat_strs[PROP_COMPAT_PCICLASS_CCSS] = -+ kasprintf(GFP_KERNEL, "pciclass,%04x", pdev->class >> 8); -+ -+ ret = of_changeset_add_prop_string_array(ocs, np, "compatible", -+ compat_strs, PROP_COMPAT_NUM); -+ for (i = 0; i < PROP_COMPAT_NUM; i++) -+ kfree(compat_strs[i]); -+ -+ return ret; -+} -+ -+int of_pci_add_properties(struct pci_dev *pdev, struct of_changeset *ocs, -+ struct device_node *np) -+{ -+ int ret; -+ -+ /* -+ * The added properties will be released when the -+ * changeset is destroyed. -+ */ -+ if (pci_is_bridge(pdev)) { -+ ret = of_changeset_add_prop_string(ocs, np, "device_type", -+ "pci"); -+ if (ret) -+ return ret; -+ -+ ret = of_pci_prop_bus_range(pdev, ocs, np); -+ if (ret) -+ return ret; -+ -+ ret = of_pci_prop_intr_map(pdev, ocs, np); -+ if (ret) -+ return ret; -+ } -+ -+ ret = of_pci_prop_ranges(pdev, ocs, np); -+ if (ret) -+ return ret; -+ -+ ret = of_changeset_add_prop_u32(ocs, np, "#address-cells", -+ OF_PCI_ADDRESS_CELLS); -+ if (ret) -+ return ret; -+ -+ ret = of_changeset_add_prop_u32(ocs, np, "#size-cells", -+ OF_PCI_SIZE_CELLS); -+ if (ret) -+ return ret; -+ -+ ret = of_pci_prop_reg(pdev, ocs, np); -+ if (ret) -+ return ret; -+ -+ ret = of_pci_prop_compatible(pdev, ocs, np); -+ if (ret) -+ return ret; -+ -+ ret = of_pci_prop_interrupts(pdev, ocs, np); -+ if (ret) -+ return ret; -+ -+ return 0; -+} -diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h -index a4c3974340576..ba717bdd700db 100644 ---- a/drivers/pci/pci.h -+++ b/drivers/pci/pci.h -@@ -679,6 +679,18 @@ static inline int devm_of_pci_bridge_init(struct device *dev, struct pci_host_br - - #endif /* CONFIG_OF */ - -+struct of_changeset; -+ -+#ifdef CONFIG_PCI_DYNAMIC_OF_NODES -+void of_pci_make_dev_node(struct pci_dev *pdev); -+void of_pci_remove_node(struct pci_dev *pdev); -+int of_pci_add_properties(struct pci_dev *pdev, struct of_changeset *ocs, -+ struct device_node *np); -+#else -+static inline void of_pci_make_dev_node(struct pci_dev *pdev) { } -+static inline void of_pci_remove_node(struct pci_dev *pdev) { } -+#endif -+ - #ifdef CONFIG_PCIEAER - void pci_no_aer(void); - void pci_aer_init(struct pci_dev *dev); -diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c -index d68aee29386b4..d749ea8250d65 100644 ---- a/drivers/pci/remove.c -+++ b/drivers/pci/remove.c -@@ -22,6 +22,7 @@ static void pci_stop_dev(struct pci_dev *dev) - device_release_driver(&dev->dev); - pci_proc_detach_device(dev); - pci_remove_sysfs_dev_files(dev); -+ of_pci_remove_node(dev); - - pci_dev_assign_added(dev, false); - } --- -2.42.0 - diff --git a/queue-6.5/pci-lengthen-reset-delay-for-videopropulsion-torrent.patch b/queue-6.5/pci-lengthen-reset-delay-for-videopropulsion-torrent.patch index 1f39a02c3c4..948f1f605aa 100644 --- a/queue-6.5/pci-lengthen-reset-delay-for-videopropulsion-torrent.patch +++ b/queue-6.5/pci-lengthen-reset-delay-for-videopropulsion-torrent.patch @@ -47,10 +47,10 @@ Signed-off-by: Sasha Levin --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c -@@ -6172,3 +6172,15 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_I - */ - DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_XILINX, 0x5020, of_pci_make_dev_node); - DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_XILINX, 0x5021, of_pci_make_dev_node); +@@ -6161,3 +6161,15 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_I + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9a2f, dpc_log_size); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9a31, dpc_log_size); + #endif + +/* + * Devices known to require a longer delay before first config space access diff --git a/queue-6.5/series b/queue-6.5/series index a7c57518828..f8e7d8209b5 100644 --- a/queue-6.5/series +++ b/queue-6.5/series @@ -364,9 +364,6 @@ pmdomain-bcm-bcm2835-power-check-if-the-asb-register.patch pmdomain-amlogic-fix-mask-for-the-second-nna-mem-pd-.patch pmdomain-imx-make-imx-pgc-power-domain-also-set-the-.patch pci-qcom-ep-add-dedicated-callback-for-writing-to-db.patch -of-dynamic-add-interfaces-for-creating-device-node-d.patch -pci-create-device-tree-node-for-bridge.patch -pci-add-quirks-to-generate-device-tree-node-for-xili.patch pci-lengthen-reset-delay-for-videopropulsion-torrent.patch torture-add-a-kthread-creation-callback-to-_torture_.patch torture-add-lock_torture-writer_fifo-module-paramete.patch -- 2.47.3