diff options
Diffstat (limited to 'drivers/pci/pci.c')
| -rw-r--r-- | drivers/pci/pci.c | 105 | 
1 files changed, 62 insertions, 43 deletions
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 2127aba3550b..fba95486caaf 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -6447,6 +6447,8 @@ bool pci_device_is_present(struct pci_dev *pdev)  {  	u32 v; +	/* Check PF if pdev is a VF, since VF Vendor/Device IDs are 0xffff */ +	pdev = pci_physfn(pdev);  	if (pci_dev_is_disconnected(pdev))  		return false;  	return pci_bus_read_dev_vendor_id(pdev->bus, pdev->devfn, &v, 0); @@ -6743,60 +6745,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, 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) @@ -6804,6 +6816,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  /**  | 
