From 955268e13f8f9422e7e89ee6350ec793dddd1e94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Tue, 1 Nov 2022 09:44:59 +0100 Subject: nixos: try to fix Turris Omnia PCIe on Linux 6.0 Unfortunatelly this seems to not work. --- .../0016-PCI-Assign-PCI-domain-by-ida_alloc.patch | 215 +++++++++++++++++++++ 1 file changed, 215 insertions(+) create mode 100644 nixos/modules/omnia-kernel-patches/0016-PCI-Assign-PCI-domain-by-ida_alloc.patch (limited to 'nixos/modules/omnia-kernel-patches/0016-PCI-Assign-PCI-domain-by-ida_alloc.patch') diff --git a/nixos/modules/omnia-kernel-patches/0016-PCI-Assign-PCI-domain-by-ida_alloc.patch b/nixos/modules/omnia-kernel-patches/0016-PCI-Assign-PCI-domain-by-ida_alloc.patch new file mode 100644 index 0000000..a349fb1 --- /dev/null +++ b/nixos/modules/omnia-kernel-patches/0016-PCI-Assign-PCI-domain-by-ida_alloc.patch @@ -0,0 +1,215 @@ +From 07414acbdce72901154b39226c8707b5a92565b7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pali=20Roh=C3=A1r?= +Date: Sat, 2 Jul 2022 21:37:51 +0200 +Subject: [PATCH 16/53] PCI: Assign PCI domain by ida_alloc() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Replace assignment of PCI domain from atomic_inc_return() to ida_alloc(). + +Use two IDAs, one for static domain allocations (those which are defined in +device tree) and second for dynamic allocations (all other). + +During removal of root bus / host bridge release also allocated domain id. +So released id can be reused again, for example in situation when +dynamically loading and unloading native PCI host bridge drivers. + +This change also allows to mix static device tree assignment and dynamic by +kernel as all static allocations are reserved in dynamic pool. + +Signed-off-by: Pali Rohár +--- + drivers/pci/pci.c | 103 +++++++++++++++++++++++++------------------ + drivers/pci/probe.c | 5 +++ + drivers/pci/remove.c | 6 +++ + include/linux/pci.h | 1 + + 4 files changed, 72 insertions(+), 43 deletions(-) + +diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c +index 95bc329e74c0..4589ad52e4ca 100644 +--- a/drivers/pci/pci.c ++++ b/drivers/pci/pci.c +@@ -6758,60 +6758,70 @@ static void pci_no_domains(void) + } + + #ifdef CONFIG_PCI_DOMAINS_GENERIC +-static atomic_t __domain_nr = ATOMIC_INIT(-1); ++static DEFINE_IDA(pci_domain_nr_static_ida); ++static DEFINE_IDA(pci_domain_nr_dynamic_ida); + +-static int pci_get_new_domain_nr(void) ++static void of_pci_reserve_static_domain_nr(void) + { +- return atomic_inc_return(&__domain_nr); ++ struct device_node *np; ++ int domain_nr; ++ ++ for_each_node_by_type(np, "pci") { ++ domain_nr = of_get_pci_domain_nr(np); ++ if (domain_nr < 0) ++ continue; ++ /* ++ * Permanently allocate domain_nr in dynamic_ida ++ * to prevent it from dynamic allocation. ++ */ ++ ida_alloc_range(&pci_domain_nr_dynamic_ida, ++ domain_nr, domain_nr, GFP_KERNEL); ++ } + } + + static int of_pci_bus_find_domain_nr(struct device *parent) + { +- static int use_dt_domains = -1; +- int domain = -1; ++ static bool static_domains_reserved = false; ++ int domain_nr; + +- if (parent) +- domain = of_get_pci_domain_nr(parent->of_node); ++ /* On the first call scan device tree for static allocations. */ ++ if (!static_domains_reserved) { ++ of_pci_reserve_static_domain_nr(); ++ static_domains_reserved = true; ++ } ++ ++ if (parent) { ++ /* ++ * If domain is in DT then allocate it in static IDA. ++ * This prevent duplicate static allocations in case ++ * of errors in DT. ++ */ ++ domain_nr = of_get_pci_domain_nr(parent->of_node); ++ if (domain_nr >= 0) ++ return ida_alloc_range(&pci_domain_nr_static_ida, ++ domain_nr, domain_nr, ++ GFP_KERNEL); ++ } + + /* +- * Check DT domain and use_dt_domains values. +- * +- * If DT domain property is valid (domain >= 0) and +- * use_dt_domains != 0, the DT assignment is valid since this means +- * we have not previously allocated a domain number by using +- * pci_get_new_domain_nr(); we should also update use_dt_domains to +- * 1, to indicate that we have just assigned a domain number from +- * DT. +- * +- * If DT domain property value is not valid (ie domain < 0), and we +- * have not previously assigned a domain number from DT +- * (use_dt_domains != 1) we should assign a domain number by +- * using the: +- * +- * pci_get_new_domain_nr() +- * +- * API and update the use_dt_domains value to keep track of method we +- * are using to assign domain numbers (use_dt_domains = 0). +- * +- * All other combinations imply we have a platform that is trying +- * to mix domain numbers obtained from DT and pci_get_new_domain_nr(), +- * which is a recipe for domain mishandling and it is prevented by +- * invalidating the domain value (domain = -1) and printing a +- * corresponding error. ++ * If domain was not specified in DT then choose free id from dynamic ++ * allocations. All domain numbers from DT are permanently in dynamic ++ * allocations to prevent assigning them to other DT nodes without ++ * static domain. + */ +- if (domain >= 0 && use_dt_domains) { +- use_dt_domains = 1; +- } else if (domain < 0 && use_dt_domains != 1) { +- use_dt_domains = 0; +- domain = pci_get_new_domain_nr(); +- } else { +- if (parent) +- pr_err("Node %pOF has ", parent->of_node); +- pr_err("Inconsistent \"linux,pci-domain\" property in DT\n"); +- domain = -1; +- } ++ return ida_alloc(&pci_domain_nr_dynamic_ida, GFP_KERNEL); ++} + +- return domain; ++static void of_pci_bus_release_domain_nr(struct pci_bus *bus, struct device *parent) ++{ ++ if (bus->domain_nr < 0) ++ return; ++ ++ /* Release domain from ida in which was it allocated. */ ++ if (of_get_pci_domain_nr(parent->of_node) == bus->domain_nr) ++ ida_free(&pci_domain_nr_static_ida, bus->domain_nr); ++ else ++ ida_free(&pci_domain_nr_dynamic_ida, bus->domain_nr); + } + + int pci_bus_find_domain_nr(struct pci_bus *bus, struct device *parent) +@@ -6819,6 +6829,13 @@ int pci_bus_find_domain_nr(struct pci_bus *bus, struct device *parent) + return acpi_disabled ? of_pci_bus_find_domain_nr(parent) : + acpi_pci_bus_find_domain_nr(bus); + } ++ ++void pci_bus_release_domain_nr(struct pci_bus *bus, struct device *parent) ++{ ++ if (!acpi_disabled) ++ return; ++ of_pci_bus_release_domain_nr(bus, parent); ++} + #endif + + /** +diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c +index c5286b027f00..a8db8bf0f196 100644 +--- a/drivers/pci/probe.c ++++ b/drivers/pci/probe.c +@@ -906,6 +906,8 @@ static int pci_register_host_bridge(struct pci_host_bridge *bridge) + bus->domain_nr = pci_bus_find_domain_nr(bus, parent); + else + bus->domain_nr = bridge->domain_nr; ++ if (bus->domain_nr < 0) ++ goto free; + #endif + + b = pci_find_bus(pci_domain_nr(bus), bridge->busnr); +@@ -1030,6 +1032,9 @@ static int pci_register_host_bridge(struct pci_host_bridge *bridge) + device_del(&bridge->dev); + + free: ++#ifdef CONFIG_PCI_DOMAINS_GENERIC ++ pci_bus_release_domain_nr(bus, parent); ++#endif + kfree(bus); + return err; + } +diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c +index 4c54c75050dc..0145aef1b930 100644 +--- a/drivers/pci/remove.c ++++ b/drivers/pci/remove.c +@@ -160,6 +160,12 @@ void pci_remove_root_bus(struct pci_bus *bus) + pci_remove_bus(bus); + host_bridge->bus = NULL; + ++#ifdef CONFIG_PCI_DOMAINS_GENERIC ++ /* Release domain_nr if it was dynamically allocated */ ++ if (host_bridge->domain_nr == PCI_DOMAIN_NR_NOT_SET) ++ pci_bus_release_domain_nr(bus, host_bridge->dev.parent); ++#endif ++ + /* remove the host bridge */ + device_del(&host_bridge->dev); + } +diff --git a/include/linux/pci.h b/include/linux/pci.h +index 060af91bafcd..c7abe91899d2 100644 +--- a/include/linux/pci.h ++++ b/include/linux/pci.h +@@ -1723,6 +1723,7 @@ static inline int acpi_pci_bus_find_domain_nr(struct pci_bus *bus) + { return 0; } + #endif + int pci_bus_find_domain_nr(struct pci_bus *bus, struct device *parent); ++void pci_bus_release_domain_nr(struct pci_bus *bus, struct device *parent); + #endif + + /* Some architectures require additional setup to direct VGA traffic */ +-- +2.37.3 + -- cgit v1.2.3