}
 
 #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, allocate it in static IDA.  This
+                * prevents 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, choose a 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 where it was 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)
        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
 
 /**