diff options
Diffstat (limited to 'arch/x86/pci/common.c')
| -rw-r--r-- | arch/x86/pci/common.c | 264 | 
1 files changed, 126 insertions, 138 deletions
diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c index f7c8a399978..059a76c2973 100644 --- a/arch/x86/pci/common.c +++ b/arch/x86/pci/common.c @@ -6,22 +6,26 @@  #include <linux/sched.h>  #include <linux/pci.h> +#include <linux/pci-acpi.h>  #include <linux/ioport.h>  #include <linux/init.h>  #include <linux/dmi.h>  #include <linux/slab.h> +#include <asm-generic/pci-bridge.h>  #include <asm/acpi.h>  #include <asm/segment.h>  #include <asm/io.h>  #include <asm/smp.h>  #include <asm/pci_x86.h> +#include <asm/setup.h>  unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2 |  				PCI_PROBE_MMCONF;  unsigned int pci_early_dump_regs;  static int pci_bf_sort; +static int smbios_type_b1_flag;  int pci_routeirq;  int noioapicquirk;  #ifdef CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS @@ -31,9 +35,8 @@ int noioapicreroute = 1;  #endif  int pcibios_last_bus = -1;  unsigned long pirq_table_addr; -struct pci_bus *pci_root_bus; -struct pci_raw_ops *raw_pci_ops; -struct pci_raw_ops *raw_pci_ext_ops; +const struct pci_raw_ops *__read_mostly raw_pci_ops; +const struct pci_raw_ops *__read_mostly raw_pci_ext_ops;  int raw_pci_read(unsigned int domain, unsigned int bus, unsigned int devfn,  						int reg, int len, u32 *val) @@ -78,14 +81,14 @@ struct pci_ops pci_root_ops = {   */  DEFINE_RAW_SPINLOCK(pci_config_lock); -static int __devinit can_skip_ioresource_align(const struct dmi_system_id *d) +static int can_skip_ioresource_align(const struct dmi_system_id *d)  {  	pci_probe |= PCI_CAN_SKIP_ISA_ALIGN;  	printk(KERN_INFO "PCI: %s detected, can skip ISA alignment\n", d->ident);  	return 0;  } -static const struct dmi_system_id can_skip_pciprobe_dmi_table[] __devinitconst = { +static const struct dmi_system_id can_skip_pciprobe_dmi_table[] = {  /*   * Systems where PCI IO resource ISA alignment can be skipped   * when the ISA enable bit in the bridge control is not set @@ -122,7 +125,7 @@ void __init dmi_check_skip_isa_align(void)  	dmi_check_system(can_skip_pciprobe_dmi_table);  } -static void __devinit pcibios_fixup_device_resources(struct pci_dev *dev) +static void pcibios_fixup_device_resources(struct pci_dev *dev)  {  	struct resource *rom_r = &dev->resource[PCI_ROM_RESOURCE];  	struct resource *bar_r; @@ -159,24 +162,31 @@ static void __devinit pcibios_fixup_device_resources(struct pci_dev *dev)   *  are examined.   */ -void __devinit pcibios_fixup_bus(struct pci_bus *b) +void pcibios_fixup_bus(struct pci_bus *b)  {  	struct pci_dev *dev; -	/* root bus? */ -	if (!b->parent) -		x86_pci_root_bus_res_quirks(b);  	pci_read_bridge_bases(b);  	list_for_each_entry(dev, &b->devices, bus_list)  		pcibios_fixup_device_resources(dev);  } +void pcibios_add_bus(struct pci_bus *bus) +{ +	acpi_pci_add_bus(bus); +} + +void pcibios_remove_bus(struct pci_bus *bus) +{ +	acpi_pci_remove_bus(bus); +} +  /*   * Only use DMI information to set this if nothing was passed   * on the kernel command line (which was parsed earlier).   */ -static int __devinit set_bf_sort(const struct dmi_system_id *d) +static int set_bf_sort(const struct dmi_system_id *d)  {  	if (pci_bf_sort == pci_bf_sort_default) {  		pci_bf_sort = pci_dmi_bf; @@ -185,11 +195,44 @@ static int __devinit set_bf_sort(const struct dmi_system_id *d)  	return 0;  } +static void read_dmi_type_b1(const struct dmi_header *dm, +				       void *private_data) +{ +	u8 *d = (u8 *)dm + 4; + +	if (dm->type != 0xB1) +		return; +	switch (((*(u32 *)d) >> 9) & 0x03) { +	case 0x00: +		printk(KERN_INFO "dmi type 0xB1 record - unknown flag\n"); +		break; +	case 0x01: /* set pci=bfsort */ +		smbios_type_b1_flag = 1; +		break; +	case 0x02: /* do not set pci=bfsort */ +		smbios_type_b1_flag = 2; +		break; +	default: +		break; +	} +} + +static int find_sort_method(const struct dmi_system_id *d) +{ +	dmi_walk(read_dmi_type_b1, NULL); + +	if (smbios_type_b1_flag == 1) { +		set_bf_sort(d); +		return 0; +	} +	return -1; +} +  /*   * Enable renumbering of PCI bus# ranges to reach all PCI busses (Cardbus)   */  #ifdef __i386__ -static int __devinit assign_all_busses(const struct dmi_system_id *d) +static int assign_all_busses(const struct dmi_system_id *d)  {  	pci_probe |= PCI_ASSIGN_ALL_BUSSES;  	printk(KERN_INFO "%s detected: enabling PCI bus# renumbering" @@ -198,7 +241,15 @@ static int __devinit assign_all_busses(const struct dmi_system_id *d)  }  #endif -static const struct dmi_system_id __devinitconst pciprobe_dmi_table[] = { +static int set_scan_all(const struct dmi_system_id *d) +{ +	printk(KERN_INFO "PCI: %s detected, enabling pci=pcie_scan_all\n", +	       d->ident); +	pci_add_flags(PCI_SCAN_ALL_PCIE_DEVS); +	return 0; +} + +static const struct dmi_system_id pciprobe_dmi_table[] = {  #ifdef __i386__  /*   * Laptops which need pci=assign-busses to see Cardbus cards @@ -253,6 +304,13 @@ static const struct dmi_system_id __devinitconst pciprobe_dmi_table[] = {  		},  	},  	{ +		.callback = find_sort_method, +		.ident = "Dell System", +		.matches = { +			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), +		}, +	}, +	{  		.callback = set_bf_sort,  		.ident = "HP ProLiant BL20p G3",  		.matches = { @@ -382,6 +440,14 @@ static const struct dmi_system_id __devinitconst pciprobe_dmi_table[] = {  			DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant DL585 G2"),  		},  	}, +	{ +		.callback = set_scan_all, +		.ident = "Stratus/NEC ftServer", +		.matches = { +			DMI_MATCH(DMI_SYS_VENDOR, "Stratus"), +			DMI_MATCH(DMI_PRODUCT_NAME, "ftServer"), +		}, +	},  	{}  }; @@ -390,37 +456,27 @@ void __init dmi_check_pciprobe(void)  	dmi_check_system(pciprobe_dmi_table);  } -struct pci_bus * __devinit pcibios_scan_root(int busnum) +void pcibios_scan_root(int busnum)  { -	struct pci_bus *bus = NULL; +	struct pci_bus *bus;  	struct pci_sysdata *sd; +	LIST_HEAD(resources); -	while ((bus = pci_find_next_bus(bus)) != NULL) { -		if (bus->number == busnum) { -			/* Already scanned */ -			return bus; -		} -	} - -	/* Allocate per-root-bus (not per bus) arch-specific data. -	 * TODO: leak; this memory is never freed. -	 * It's arguable whether it's worth the trouble to care. -	 */  	sd = kzalloc(sizeof(*sd), GFP_KERNEL);  	if (!sd) { -		printk(KERN_ERR "PCI: OOM, not probing PCI bus %02x\n", busnum); -		return NULL; +		printk(KERN_ERR "PCI: OOM, skipping PCI bus %02x\n", busnum); +		return;  	} - -	sd->node = get_mp_bus_to_node(busnum); - +	sd->node = x86_pci_root_bus_node(busnum); +	x86_pci_root_bus_resources(busnum, &resources);  	printk(KERN_DEBUG "PCI: Probing PCI hardware (bus %02x)\n", busnum); -	bus = pci_scan_bus_parented(NULL, busnum, &pci_root_ops, sd); -	if (!bus) +	bus = pci_scan_root_bus(NULL, busnum, &pci_root_ops, sd, &resources); +	if (!bus) { +		pci_free_resource_list(&resources);  		kfree(sd); - -	return bus; +	}  } +  void __init pcibios_set_cache_line_size(void)  {  	struct cpuinfo_x86 *c = &boot_cpu_data; @@ -456,7 +512,7 @@ int __init pcibios_init(void)  	return 0;  } -char * __devinit  pcibios_setup(char *str) +char * __init pcibios_setup(char *str)  {  	if (!strcmp(str, "off")) {  		pci_probe = 0; @@ -511,7 +567,6 @@ char * __devinit  pcibios_setup(char *str)  		pci_probe |= PCI_PROBE_NOEARLY;  		return NULL;  	} -#ifndef CONFIG_X86_VISWS  	else if (!strcmp(str, "usepirqmask")) {  		pci_probe |= PCI_USE_PIRQ_MASK;  		return NULL; @@ -521,9 +576,7 @@ char * __devinit  pcibios_setup(char *str)  	} else if (!strncmp(str, "lastbus=", 8)) {  		pcibios_last_bus = simple_strtol(str+8, NULL, 0);  		return NULL; -	} -#endif -	else if (!strcmp(str, "rom")) { +	} else if (!strcmp(str, "rom")) {  		pci_probe |= PCI_ASSIGN_ROMS;  		return NULL;  	} else if (!strcmp(str, "norom")) { @@ -570,6 +623,38 @@ unsigned int pcibios_assign_all_busses(void)  	return (pci_probe & PCI_ASSIGN_ALL_BUSSES) ? 1 : 0;  } +int pcibios_add_device(struct pci_dev *dev) +{ +	struct setup_data *data; +	struct pci_setup_rom *rom; +	u64 pa_data; + +	pa_data = boot_params.hdr.setup_data; +	while (pa_data) { +		data = ioremap(pa_data, sizeof(*rom)); +		if (!data) +			return -ENOMEM; + +		if (data->type == SETUP_PCI) { +			rom = (struct pci_setup_rom *)data; + +			if ((pci_domain_nr(dev->bus) == rom->segment) && +			    (dev->bus->number == rom->bus) && +			    (PCI_SLOT(dev->devfn) == rom->device) && +			    (PCI_FUNC(dev->devfn) == rom->function) && +			    (dev->vendor == rom->vendor) && +			    (dev->device == rom->devid)) { +				dev->rom = pa_data + +				      offsetof(struct pci_setup_rom, romdata); +				dev->romlen = rom->pcilen; +			} +		} +		pa_data = data->next; +		iounmap(data); +	} +	return 0; +} +  int pcibios_enable_device(struct pci_dev *dev, int mask)  {  	int err; @@ -588,107 +673,10 @@ void pcibios_disable_device (struct pci_dev *dev)  		pcibios_disable_irq(dev);  } -int pci_ext_cfg_avail(struct pci_dev *dev) +int pci_ext_cfg_avail(void)  {  	if (raw_pci_ext_ops)  		return 1;  	else  		return 0;  } - -struct pci_bus * __devinit pci_scan_bus_on_node(int busno, struct pci_ops *ops, int node) -{ -	struct pci_bus *bus = NULL; -	struct pci_sysdata *sd; - -	/* -	 * Allocate per-root-bus (not per bus) arch-specific data. -	 * TODO: leak; this memory is never freed. -	 * It's arguable whether it's worth the trouble to care. -	 */ -	sd = kzalloc(sizeof(*sd), GFP_KERNEL); -	if (!sd) { -		printk(KERN_ERR "PCI: OOM, skipping PCI bus %02x\n", busno); -		return NULL; -	} -	sd->node = node; -	bus = pci_scan_bus(busno, ops, sd); -	if (!bus) -		kfree(sd); - -	return bus; -} - -struct pci_bus * __devinit pci_scan_bus_with_sysdata(int busno) -{ -	return pci_scan_bus_on_node(busno, &pci_root_ops, -1); -} - -/* - * NUMA info for PCI busses - * - * Early arch code is responsible for filling in reasonable values here. - * A node id of "-1" means "use current node".  In other words, if a bus - * has a -1 node id, it's not tightly coupled to any particular chunk - * of memory (as is the case on some Nehalem systems). - */ -#ifdef CONFIG_NUMA - -#define BUS_NR 256 - -#ifdef CONFIG_X86_64 - -static int mp_bus_to_node[BUS_NR] = { -	[0 ... BUS_NR - 1] = -1 -}; - -void set_mp_bus_to_node(int busnum, int node) -{ -	if (busnum >= 0 &&  busnum < BUS_NR) -		mp_bus_to_node[busnum] = node; -} - -int get_mp_bus_to_node(int busnum) -{ -	int node = -1; - -	if (busnum < 0 || busnum > (BUS_NR - 1)) -		return node; - -	node = mp_bus_to_node[busnum]; - -	/* -	 * let numa_node_id to decide it later in dma_alloc_pages -	 * if there is no ram on that node -	 */ -	if (node != -1 && !node_online(node)) -		node = -1; - -	return node; -} - -#else /* CONFIG_X86_32 */ - -static int mp_bus_to_node[BUS_NR] = { -	[0 ... BUS_NR - 1] = -1 -}; - -void set_mp_bus_to_node(int busnum, int node) -{ -	if (busnum >= 0 &&  busnum < BUS_NR) -	mp_bus_to_node[busnum] = (unsigned char) node; -} - -int get_mp_bus_to_node(int busnum) -{ -	int node; - -	if (busnum < 0 || busnum > (BUS_NR - 1)) -		return 0; -	node = mp_bus_to_node[busnum]; -	return node; -} - -#endif /* CONFIG_X86_32 */ - -#endif /* CONFIG_NUMA */  | 
