diff options
Diffstat (limited to 'arch/x86/pci')
-rw-r--r-- | arch/x86/pci/acpi.c | 11 | ||||
-rw-r--r-- | arch/x86/pci/common.c | 63 | ||||
-rw-r--r-- | arch/x86/pci/i386.c | 111 | ||||
-rw-r--r-- | arch/x86/pci/irq.c | 12 | ||||
-rw-r--r-- | arch/x86/pci/numa.c | 32 | ||||
-rw-r--r-- | arch/x86/pci/pcbios.c | 72 | ||||
-rw-r--r-- | arch/x86/pci/pci.h | 4 |
7 files changed, 108 insertions, 197 deletions
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c index 378136fb5044..2664cb3fc96c 100644 --- a/arch/x86/pci/acpi.c +++ b/arch/x86/pci/acpi.c @@ -151,7 +151,7 @@ adjust_transparent_bridge_resources(struct pci_bus *bus) static void get_current_resources(struct acpi_device *device, int busnum, - struct pci_bus *bus) + int domain, struct pci_bus *bus) { struct pci_root_info info; size_t size; @@ -168,10 +168,10 @@ get_current_resources(struct acpi_device *device, int busnum, if (!info.res) goto res_alloc_fail; - info.name = kmalloc(12, GFP_KERNEL); + info.name = kmalloc(16, GFP_KERNEL); if (!info.name) goto name_alloc_fail; - sprintf(info.name, "PCI Bus #%02x", busnum); + sprintf(info.name, "PCI Bus %04x:%02x", domain, busnum); info.res_num = 0; acpi_walk_resources(device->handle, METHOD_NAME__CRS, setup_resource, @@ -247,7 +247,7 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int do #endif if (bus && (pci_probe & PCI_USE__CRS)) - get_current_resources(device, busnum, bus); + get_current_resources(device, busnum, domain, bus); return bus; } @@ -278,8 +278,7 @@ static int __init pci_acpi_init(void) printk(KERN_INFO "PCI: Routing PCI interrupts for all devices because \"pci=routeirq\" specified\n"); for_each_pci_dev(dev) acpi_pci_irq_enable(dev); - } else - printk(KERN_INFO "PCI: If a device doesn't work, try \"pci=routeirq\". If it helps, post a report\n"); + } #ifdef CONFIG_X86_IO_APIC if (acpi_ioapic) diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c index 7b6e3bb9b28c..75fcc29ecf52 100644 --- a/arch/x86/pci/common.c +++ b/arch/x86/pci/common.c @@ -77,59 +77,6 @@ int pcibios_scanned; */ DEFINE_SPINLOCK(pci_config_lock); -/* - * Several buggy motherboards address only 16 devices and mirror - * them to next 16 IDs. We try to detect this `feature' on all - * primary buses (those containing host bridges as they are - * expected to be unique) and remove the ghost devices. - */ - -static void __devinit pcibios_fixup_ghosts(struct pci_bus *b) -{ - struct list_head *ln, *mn; - struct pci_dev *d, *e; - int mirror = PCI_DEVFN(16,0); - int seen_host_bridge = 0; - int i; - - DBG("PCI: Scanning for ghost devices on bus %d\n", b->number); - list_for_each(ln, &b->devices) { - d = pci_dev_b(ln); - if ((d->class >> 8) == PCI_CLASS_BRIDGE_HOST) - seen_host_bridge++; - for (mn=ln->next; mn != &b->devices; mn=mn->next) { - e = pci_dev_b(mn); - if (e->devfn != d->devfn + mirror || - e->vendor != d->vendor || - e->device != d->device || - e->class != d->class) - continue; - for(i=0; i<PCI_NUM_RESOURCES; i++) - if (e->resource[i].start != d->resource[i].start || - e->resource[i].end != d->resource[i].end || - e->resource[i].flags != d->resource[i].flags) - continue; - break; - } - if (mn == &b->devices) - return; - } - if (!seen_host_bridge) - return; - printk(KERN_WARNING "PCI: Ignoring ghost devices on bus %02x\n", b->number); - - ln = &b->devices; - while (ln->next != &b->devices) { - d = pci_dev_b(ln->next); - if (d->devfn >= mirror) { - list_del(&d->global_list); - list_del(&d->bus_list); - kfree(d); - } else - ln = ln->next; - } -} - static void __devinit pcibios_fixup_device_resources(struct pci_dev *dev) { struct resource *rom_r = &dev->resource[PCI_ROM_RESOURCE]; @@ -152,7 +99,6 @@ void __devinit pcibios_fixup_bus(struct pci_bus *b) { struct pci_dev *dev; - pcibios_fixup_ghosts(b); pci_read_bridge_bases(b); list_for_each_entry(dev, &b->devices, bus_list) pcibios_fixup_device_resources(dev); @@ -427,10 +373,6 @@ static int __init pcibios_init(void) if (pci_bf_sort >= pci_force_bf) pci_sort_breadthfirst(); -#ifdef CONFIG_PCI_BIOS - if ((pci_probe & PCI_BIOS_SORT) && !(pci_probe & PCI_NO_SORT)) - pcibios_sort(); -#endif return 0; } @@ -455,9 +397,6 @@ char * __devinit pcibios_setup(char *str) } else if (!strcmp(str, "nobios")) { pci_probe &= ~PCI_PROBE_BIOS; return NULL; - } else if (!strcmp(str, "nosort")) { - pci_probe |= PCI_NO_SORT; - return NULL; } else if (!strcmp(str, "biosirq")) { pci_probe |= PCI_BIOS_IRQ_SCAN; return NULL; @@ -527,7 +466,7 @@ int pcibios_enable_device(struct pci_dev *dev, int mask) { int err; - if ((err = pcibios_enable_resources(dev, mask)) < 0) + if ((err = pci_enable_resources(dev, mask)) < 0) return err; if (!dev->msi_enabled) diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c index 103b9dff1213..94f6c73a53d0 100644 --- a/arch/x86/pci/i386.c +++ b/arch/x86/pci/i386.c @@ -30,6 +30,9 @@ #include <linux/init.h> #include <linux/ioport.h> #include <linux/errno.h> +#include <linux/bootmem.h> + +#include <asm/pat.h> #include "pci.h" @@ -238,44 +241,6 @@ void __init pcibios_resource_survey(void) */ fs_initcall(pcibios_assign_resources); -int pcibios_enable_resources(struct pci_dev *dev, int mask) -{ - u16 cmd, old_cmd; - int idx; - struct resource *r; - - pci_read_config_word(dev, PCI_COMMAND, &cmd); - old_cmd = cmd; - for (idx = 0; idx < PCI_NUM_RESOURCES; idx++) { - /* Only set up the requested stuff */ - if (!(mask & (1 << idx))) - continue; - - r = &dev->resource[idx]; - if (!(r->flags & (IORESOURCE_IO | IORESOURCE_MEM))) - continue; - if ((idx == PCI_ROM_RESOURCE) && - (!(r->flags & IORESOURCE_ROM_ENABLE))) - continue; - if (!r->start && r->end) { - printk(KERN_ERR "PCI: Device %s not available " - "because of resource %d collisions\n", - pci_name(dev), idx); - return -EINVAL; - } - if (r->flags & IORESOURCE_IO) - cmd |= PCI_COMMAND_IO; - if (r->flags & IORESOURCE_MEM) - cmd |= PCI_COMMAND_MEMORY; - } - if (cmd != old_cmd) { - printk("PCI: Enabling device %s (%04x -> %04x)\n", - pci_name(dev), old_cmd, cmd); - pci_write_config_word(dev, PCI_COMMAND, cmd); - } - return 0; -} - /* * If we set up a device for bus mastering, we need to check the latency * timer as certain crappy BIOSes forget to set it properly. @@ -297,10 +262,35 @@ void pcibios_set_master(struct pci_dev *dev) pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat); } +static void pci_unmap_page_range(struct vm_area_struct *vma) +{ + u64 addr = (u64)vma->vm_pgoff << PAGE_SHIFT; + free_memtype(addr, addr + vma->vm_end - vma->vm_start); +} + +static void pci_track_mmap_page_range(struct vm_area_struct *vma) +{ + u64 addr = (u64)vma->vm_pgoff << PAGE_SHIFT; + unsigned long flags = pgprot_val(vma->vm_page_prot) + & _PAGE_CACHE_MASK; + + reserve_memtype(addr, addr + vma->vm_end - vma->vm_start, flags, NULL); +} + +static struct vm_operations_struct pci_mmap_ops = { + .open = pci_track_mmap_page_range, + .close = pci_unmap_page_range, +}; + int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, enum pci_mmap_state mmap_state, int write_combine) { unsigned long prot; + u64 addr = vma->vm_pgoff << PAGE_SHIFT; + unsigned long len = vma->vm_end - vma->vm_start; + unsigned long flags; + unsigned long new_flags; + int retval; /* I/O space cannot be accessed via normal processor loads and * stores on this platform. @@ -308,21 +298,50 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, if (mmap_state == pci_mmap_io) return -EINVAL; - /* Leave vm_pgoff as-is, the PCI space address is the physical - * address on this platform. - */ prot = pgprot_val(vma->vm_page_prot); - if (boot_cpu_data.x86 > 3) - prot |= _PAGE_PCD | _PAGE_PWT; + if (pat_wc_enabled && write_combine) + prot |= _PAGE_CACHE_WC; + else if (boot_cpu_data.x86 > 3) + prot |= _PAGE_CACHE_UC; + vma->vm_page_prot = __pgprot(prot); - /* Write-combine setting is ignored, it is changed via the mtrr - * interfaces on this platform. - */ + flags = pgprot_val(vma->vm_page_prot) & _PAGE_CACHE_MASK; + retval = reserve_memtype(addr, addr + len, flags, &new_flags); + if (retval) + return retval; + + if (flags != new_flags) { + /* + * Do not fallback to certain memory types with certain + * requested type: + * - request is uncached, return cannot be write-back + * - request is uncached, return cannot be write-combine + * - request is write-combine, return cannot be write-back + */ + if ((flags == _PAGE_CACHE_UC && + (new_flags == _PAGE_CACHE_WB || + new_flags == _PAGE_CACHE_WC)) || + (flags == _PAGE_CACHE_WC && + new_flags == _PAGE_CACHE_WB)) { + free_memtype(addr, addr+len); + return -EINVAL; + } + flags = new_flags; + } + + if (vma->vm_pgoff <= max_pfn_mapped && + ioremap_change_attr((unsigned long)__va(addr), len, flags)) { + free_memtype(addr, addr + len); + return -EINVAL; + } + if (io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, vma->vm_end - vma->vm_start, vma->vm_page_prot)) return -EAGAIN; + vma->vm_ops = &pci_mmap_ops; + return 0; } diff --git a/arch/x86/pci/irq.c b/arch/x86/pci/irq.c index a8715861877e..579745ca6b66 100644 --- a/arch/x86/pci/irq.c +++ b/arch/x86/pci/irq.c @@ -200,7 +200,7 @@ static int pirq_ali_get(struct pci_dev *router, struct pci_dev *dev, int pirq) { static const unsigned char irqmap[16] = { 0, 9, 3, 10, 4, 5, 7, 6, 1, 11, 0, 12, 0, 14, 0, 15 }; - WARN_ON_ONCE(pirq >= 16); + WARN_ON_ONCE(pirq > 16); return irqmap[read_config_nybble(router, 0x48, pirq-1)]; } @@ -209,7 +209,7 @@ static int pirq_ali_set(struct pci_dev *router, struct pci_dev *dev, int pirq, i static const unsigned char irqmap[16] = { 0, 8, 0, 2, 4, 5, 7, 6, 0, 1, 3, 9, 11, 0, 13, 15 }; unsigned int val = irqmap[irq]; - WARN_ON_ONCE(pirq >= 16); + WARN_ON_ONCE(pirq > 16); if (val) { write_config_nybble(router, 0x48, pirq-1, val); return 1; @@ -260,7 +260,7 @@ static int pirq_via586_get(struct pci_dev *router, struct pci_dev *dev, int pirq { static const unsigned int pirqmap[5] = { 3, 2, 5, 1, 1 }; - WARN_ON_ONCE(pirq >= 5); + WARN_ON_ONCE(pirq > 5); return read_config_nybble(router, 0x55, pirqmap[pirq-1]); } @@ -268,7 +268,7 @@ static int pirq_via586_set(struct pci_dev *router, struct pci_dev *dev, int pirq { static const unsigned int pirqmap[5] = { 3, 2, 5, 1, 1 }; - WARN_ON_ONCE(pirq >= 5); + WARN_ON_ONCE(pirq > 5); write_config_nybble(router, 0x55, pirqmap[pirq-1], irq); return 1; } @@ -282,7 +282,7 @@ static int pirq_ite_get(struct pci_dev *router, struct pci_dev *dev, int pirq) { static const unsigned char pirqmap[4] = { 1, 0, 2, 3 }; - WARN_ON_ONCE(pirq >= 4); + WARN_ON_ONCE(pirq > 4); return read_config_nybble(router,0x43, pirqmap[pirq-1]); } @@ -290,7 +290,7 @@ static int pirq_ite_set(struct pci_dev *router, struct pci_dev *dev, int pirq, i { static const unsigned char pirqmap[4] = { 1, 0, 2, 3 }; - WARN_ON_ONCE(pirq >= 4); + WARN_ON_ONCE(pirq > 4); write_config_nybble(router, 0x43, pirqmap[pirq-1], irq); return 1; } diff --git a/arch/x86/pci/numa.c b/arch/x86/pci/numa.c index 55270c26237c..d9afbae5092b 100644 --- a/arch/x86/pci/numa.c +++ b/arch/x86/pci/numa.c @@ -11,11 +11,41 @@ #define XQUAD_PORTIO_BASE 0xfe400000 #define XQUAD_PORTIO_QUAD 0x40000 /* 256k per quad. */ +int mp_bus_id_to_node[MAX_MP_BUSSES]; #define BUS2QUAD(global) (mp_bus_id_to_node[global]) + +int mp_bus_id_to_local[MAX_MP_BUSSES]; #define BUS2LOCAL(global) (mp_bus_id_to_local[global]) + +void mpc_oem_bus_info(struct mpc_config_bus *m, char *name, + struct mpc_config_translation *translation) +{ + int quad = translation->trans_quad; + int local = translation->trans_local; + + mp_bus_id_to_node[m->mpc_busid] = quad; + mp_bus_id_to_local[m->mpc_busid] = local; + printk(KERN_INFO "Bus #%d is %s (node %d)\n", + m->mpc_busid, name, quad); +} + +int quad_local_to_mp_bus_id [NR_CPUS/4][4]; #define QUADLOCAL2BUS(quad,local) (quad_local_to_mp_bus_id[quad][local]) +void mpc_oem_pci_bus(struct mpc_config_bus *m, + struct mpc_config_translation *translation) +{ + int quad = translation->trans_quad; + int local = translation->trans_local; + + quad_local_to_mp_bus_id[quad][local] = m->mpc_busid; +} + +/* Where the IO area was mapped on multiquad, always 0 otherwise */ +void *xquad_portio; +#ifdef CONFIG_X86_NUMAQ +EXPORT_SYMBOL(xquad_portio); +#endif -extern void *xquad_portio; /* Where the IO area was mapped */ #define XQUAD_PORT_ADDR(port, quad) (xquad_portio + (XQUAD_PORTIO_QUAD*quad) + port) #define PCI_CONF1_MQ_ADDRESS(bus, devfn, reg) \ diff --git a/arch/x86/pci/pcbios.c b/arch/x86/pci/pcbios.c index 2f7109ac4c15..37472fc6f729 100644 --- a/arch/x86/pci/pcbios.c +++ b/arch/x86/pci/pcbios.c @@ -152,28 +152,6 @@ static int __devinit check_pcibios(void) return 0; } -static int __devinit pci_bios_find_device (unsigned short vendor, unsigned short device_id, - unsigned short index, unsigned char *bus, unsigned char *device_fn) -{ - unsigned short bx; - unsigned short ret; - - __asm__("lcall *(%%edi); cld\n\t" - "jc 1f\n\t" - "xor %%ah, %%ah\n" - "1:" - : "=b" (bx), - "=a" (ret) - : "1" (PCIBIOS_FIND_PCI_DEVICE), - "c" (device_id), - "d" (vendor), - "S" ((int) index), - "D" (&pci_indirect)); - *bus = (bx >> 8) & 0xff; - *device_fn = bx & 0xff; - return (int) (ret & 0xff00) >> 8; -} - static int pci_bios_read(unsigned int seg, unsigned int bus, unsigned int devfn, int reg, int len, u32 *value) { @@ -364,55 +342,6 @@ static struct pci_raw_ops * __devinit pci_find_bios(void) } /* - * Sort the device list according to PCI BIOS. Nasty hack, but since some - * fool forgot to define the `correct' device order in the PCI BIOS specs - * and we want to be (possibly bug-to-bug ;-]) compatible with older kernels - * which used BIOS ordering, we are bound to do this... - */ - -void __devinit pcibios_sort(void) -{ - LIST_HEAD(sorted_devices); - struct list_head *ln; - struct pci_dev *dev, *d; - int idx, found; - unsigned char bus, devfn; - - DBG("PCI: Sorting device list...\n"); - while (!list_empty(&pci_devices)) { - ln = pci_devices.next; - dev = pci_dev_g(ln); - idx = found = 0; - while (pci_bios_find_device(dev->vendor, dev->device, idx, &bus, &devfn) == PCIBIOS_SUCCESSFUL) { - idx++; - list_for_each(ln, &pci_devices) { - d = pci_dev_g(ln); - if (d->bus->number == bus && d->devfn == devfn) { - list_move_tail(&d->global_list, &sorted_devices); - if (d == dev) - found = 1; - break; - } - } - if (ln == &pci_devices) { - printk(KERN_WARNING "PCI: BIOS reporting unknown device %02x:%02x\n", bus, devfn); - /* - * We must not continue scanning as several buggy BIOSes - * return garbage after the last device. Grr. - */ - break; - } - } - if (!found) { - printk(KERN_WARNING "PCI: Device %s not found by BIOS\n", - pci_name(dev)); - list_move_tail(&dev->global_list, &sorted_devices); - } - } - list_splice(&sorted_devices, &pci_devices); -} - -/* * BIOS Functions for IRQ Routing */ @@ -495,7 +424,6 @@ void __init pci_pcbios_init(void) { if ((pci_probe & PCI_PROBE_BIOS) && ((raw_pci_ops = pci_find_bios()))) { - pci_probe |= PCI_BIOS_SORT; pci_bios_present = 1; } } diff --git a/arch/x86/pci/pci.h b/arch/x86/pci/pci.h index 3431518d921a..c4bddaeff619 100644 --- a/arch/x86/pci/pci.h +++ b/arch/x86/pci/pci.h @@ -19,8 +19,6 @@ #define PCI_PROBE_MASK 0x000f #define PCI_PROBE_NOEARLY 0x0010 -#define PCI_NO_SORT 0x0100 -#define PCI_BIOS_SORT 0x0200 #define PCI_NO_CHECKS 0x0400 #define PCI_USE_PIRQ_MASK 0x0800 #define PCI_ASSIGN_ROMS 0x1000 @@ -44,7 +42,6 @@ enum pci_bf_sort_state { extern unsigned int pcibios_max_latency; void pcibios_resource_survey(void); -int pcibios_enable_resources(struct pci_dev *, int); /* pci-pc.c */ @@ -101,7 +98,6 @@ extern int pci_direct_probe(void); extern void pci_direct_init(int type); extern void pci_pcbios_init(void); extern void pci_mmcfg_init(int type); -extern void pcibios_sort(void); /* pci-mmconfig.c */ |