diff options
Diffstat (limited to 'drivers/pci/setup-bus.c')
| -rw-r--r-- | drivers/pci/setup-bus.c | 75 | 
1 files changed, 58 insertions, 17 deletions
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index e241f2fd6cb..8fa2d4be88d 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -51,13 +51,6 @@ static void free_list(struct list_head *head)  	}  } -int pci_realloc_enable = 0; -#define pci_realloc_enabled() pci_realloc_enable -void pci_realloc(void) -{ -	pci_realloc_enable = 1; -} -  /**   * add_to_list() - add a new resource tracker to the list   * @head:	Head of the list @@ -1276,6 +1269,58 @@ static int __init pci_get_max_depth(void)  	return depth;  } +/* + * -1: undefined, will auto detect later + *  0: disabled by user + *  1: disabled by auto detect + *  2: enabled by user + *  3: enabled by auto detect + */ +enum enable_type { +	undefined = -1, +	user_disabled, +	auto_disabled, +	user_enabled, +	auto_enabled, +}; + +static enum enable_type pci_realloc_enable __initdata = undefined; +void __init pci_realloc_get_opt(char *str) +{ +	if (!strncmp(str, "off", 3)) +		pci_realloc_enable = user_disabled; +	else if (!strncmp(str, "on", 2)) +		pci_realloc_enable = user_enabled; +} +static bool __init pci_realloc_enabled(void) +{ +	return pci_realloc_enable >= user_enabled; +} + +static void __init pci_realloc_detect(void) +{ +#if defined(CONFIG_PCI_IOV) && defined(CONFIG_PCI_REALLOC_ENABLE_AUTO) +	struct pci_dev *dev = NULL; + +	if (pci_realloc_enable != undefined) +		return; + +	for_each_pci_dev(dev) { +		int i; + +		for (i = PCI_IOV_RESOURCES; i <= PCI_IOV_RESOURCE_END; i++) { +			struct resource *r = &dev->resource[i]; + +			/* Not assigned, or rejected by kernel ? */ +			if (r->flags && !r->start) { +				pci_realloc_enable = auto_enabled; + +				return; +			} +		} +	} +#endif +}  /*   * first try will not touch pci bridge res @@ -1295,10 +1340,10 @@ pci_assign_unassigned_resources(void)  	struct pci_dev_resource *fail_res;  	unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM |  				  IORESOURCE_PREFETCH; -	unsigned long failed_type;  	int pci_try_num = 1;  	/* don't realloc if asked to do so */ +	pci_realloc_detect();  	if (pci_realloc_enabled()) {  		int max_depth = pci_get_max_depth(); @@ -1330,16 +1375,12 @@ again:  	if (list_empty(&fail_head))  		goto enable_and_dump; -	failed_type = 0; -	list_for_each_entry(fail_res, &fail_head, list) -		failed_type |= fail_res->flags; +	if (tried_times >= pci_try_num) { +		if (pci_realloc_enable == undefined) +			printk(KERN_INFO "Some PCI device resources are unassigned, try booting with pci=realloc\n"); +		else if (pci_realloc_enable == auto_enabled) +			printk(KERN_INFO "Automatically enabled pci realloc, if you have problem, try booting with pci=realloc=off\n"); -	/* -	 * io port are tight, don't try extra -	 * or if reach the limit, don't want to try more -	 */ -	failed_type &= type_mask; -	if ((failed_type == IORESOURCE_IO) || (tried_times >= pci_try_num)) {  		free_list(&fail_head);  		goto enable_and_dump;  	}  |