diff options
| author | Jeff Garzik <jgarzik@pobox.com> | 2005-12-13 11:36:18 -0500 |
|---|---|---|
| committer | Jeff Garzik <jgarzik@pobox.com> | 2005-12-13 11:36:18 -0500 |
| commit | d22a8ccff761c81f2930bd90fa5712e51a0e9a62 (patch) | |
| tree | 52a92cf1b9a65e4440276706c4b4e879d4008a87 /arch/i386 | |
| parent | 783e3385a134305d49d7b431df6e591265e7ec14 (diff) | |
| parent | 98684a9d91bceff829b6dc7adf0f662d59cfa6e3 (diff) | |
Merge branch 'upstream-fixes'
Diffstat (limited to 'arch/i386')
| -rw-r--r-- | arch/i386/kernel/smpboot.c | 3 | ||||
| -rw-r--r-- | arch/i386/mm/ioremap.c | 37 | ||||
| -rw-r--r-- | arch/i386/pci/direct.c | 4 | ||||
| -rw-r--r-- | arch/i386/pci/mmconfig.c | 65 | ||||
| -rw-r--r-- | arch/i386/pci/pci.h | 7 |
5 files changed, 95 insertions, 21 deletions
diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c index d16520da4550..9ed449af8e9f 100644 --- a/arch/i386/kernel/smpboot.c +++ b/arch/i386/kernel/smpboot.c | |||
| @@ -1338,8 +1338,7 @@ int __cpu_disable(void) | |||
| 1338 | if (cpu == 0) | 1338 | if (cpu == 0) |
| 1339 | return -EBUSY; | 1339 | return -EBUSY; |
| 1340 | 1340 | ||
| 1341 | /* We enable the timer again on the exit path of the death loop */ | 1341 | clear_local_APIC(); |
| 1342 | disable_APIC_timer(); | ||
| 1343 | /* Allow any queued timer interrupts to get serviced */ | 1342 | /* Allow any queued timer interrupts to get serviced */ |
| 1344 | local_irq_enable(); | 1343 | local_irq_enable(); |
| 1345 | mdelay(1); | 1344 | mdelay(1); |
diff --git a/arch/i386/mm/ioremap.c b/arch/i386/mm/ioremap.c index 5d09de8d1c6b..8498b5ac3955 100644 --- a/arch/i386/mm/ioremap.c +++ b/arch/i386/mm/ioremap.c | |||
| @@ -223,9 +223,15 @@ void __iomem *ioremap_nocache (unsigned long phys_addr, unsigned long size) | |||
| 223 | } | 223 | } |
| 224 | EXPORT_SYMBOL(ioremap_nocache); | 224 | EXPORT_SYMBOL(ioremap_nocache); |
| 225 | 225 | ||
| 226 | /** | ||
| 227 | * iounmap - Free a IO remapping | ||
| 228 | * @addr: virtual address from ioremap_* | ||
| 229 | * | ||
| 230 | * Caller must ensure there is only one unmapping for the same pointer. | ||
| 231 | */ | ||
| 226 | void iounmap(volatile void __iomem *addr) | 232 | void iounmap(volatile void __iomem *addr) |
| 227 | { | 233 | { |
| 228 | struct vm_struct *p; | 234 | struct vm_struct *p, *o; |
| 229 | 235 | ||
| 230 | if ((void __force *)addr <= high_memory) | 236 | if ((void __force *)addr <= high_memory) |
| 231 | return; | 237 | return; |
| @@ -239,22 +245,37 @@ void iounmap(volatile void __iomem *addr) | |||
| 239 | addr < phys_to_virt(ISA_END_ADDRESS)) | 245 | addr < phys_to_virt(ISA_END_ADDRESS)) |
| 240 | return; | 246 | return; |
| 241 | 247 | ||
| 242 | write_lock(&vmlist_lock); | 248 | addr = (volatile void *)(PAGE_MASK & (unsigned long __force)addr); |
| 243 | p = __remove_vm_area((void *)(PAGE_MASK & (unsigned long __force)addr)); | 249 | |
| 244 | if (!p) { | 250 | /* Use the vm area unlocked, assuming the caller |
| 245 | printk(KERN_WARNING "iounmap: bad address %p\n", addr); | 251 | ensures there isn't another iounmap for the same address |
| 252 | in parallel. Reuse of the virtual address is prevented by | ||
| 253 | leaving it in the global lists until we're done with it. | ||
| 254 | cpa takes care of the direct mappings. */ | ||
| 255 | read_lock(&vmlist_lock); | ||
| 256 | for (p = vmlist; p; p = p->next) { | ||
| 257 | if (p->addr == addr) | ||
| 258 | break; | ||
| 259 | } | ||
| 260 | read_unlock(&vmlist_lock); | ||
| 261 | |||
| 262 | if (!p) { | ||
| 263 | printk("iounmap: bad address %p\n", addr); | ||
| 246 | dump_stack(); | 264 | dump_stack(); |
| 247 | goto out_unlock; | 265 | return; |
| 248 | } | 266 | } |
| 249 | 267 | ||
| 268 | /* Reset the direct mapping. Can block */ | ||
| 250 | if ((p->flags >> 20) && p->phys_addr < virt_to_phys(high_memory) - 1) { | 269 | if ((p->flags >> 20) && p->phys_addr < virt_to_phys(high_memory) - 1) { |
| 251 | change_page_attr(virt_to_page(__va(p->phys_addr)), | 270 | change_page_attr(virt_to_page(__va(p->phys_addr)), |
| 252 | p->size >> PAGE_SHIFT, | 271 | p->size >> PAGE_SHIFT, |
| 253 | PAGE_KERNEL); | 272 | PAGE_KERNEL); |
| 254 | global_flush_tlb(); | 273 | global_flush_tlb(); |
| 255 | } | 274 | } |
| 256 | out_unlock: | 275 | |
| 257 | write_unlock(&vmlist_lock); | 276 | /* Finally remove it */ |
| 277 | o = remove_vm_area((void *)addr); | ||
| 278 | BUG_ON(p != o || o == NULL); | ||
| 258 | kfree(p); | 279 | kfree(p); |
| 259 | } | 280 | } |
| 260 | EXPORT_SYMBOL(iounmap); | 281 | EXPORT_SYMBOL(iounmap); |
diff --git a/arch/i386/pci/direct.c b/arch/i386/pci/direct.c index 94331d6be7a3..e3ac502bf2fb 100644 --- a/arch/i386/pci/direct.c +++ b/arch/i386/pci/direct.c | |||
| @@ -13,7 +13,7 @@ | |||
| 13 | #define PCI_CONF1_ADDRESS(bus, devfn, reg) \ | 13 | #define PCI_CONF1_ADDRESS(bus, devfn, reg) \ |
| 14 | (0x80000000 | (bus << 16) | (devfn << 8) | (reg & ~3)) | 14 | (0x80000000 | (bus << 16) | (devfn << 8) | (reg & ~3)) |
| 15 | 15 | ||
| 16 | static int pci_conf1_read(unsigned int seg, unsigned int bus, | 16 | int pci_conf1_read(unsigned int seg, unsigned int bus, |
| 17 | unsigned int devfn, int reg, int len, u32 *value) | 17 | unsigned int devfn, int reg, int len, u32 *value) |
| 18 | { | 18 | { |
| 19 | unsigned long flags; | 19 | unsigned long flags; |
| @@ -42,7 +42,7 @@ static int pci_conf1_read(unsigned int seg, unsigned int bus, | |||
| 42 | return 0; | 42 | return 0; |
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | static int pci_conf1_write(unsigned int seg, unsigned int bus, | 45 | int pci_conf1_write(unsigned int seg, unsigned int bus, |
| 46 | unsigned int devfn, int reg, int len, u32 value) | 46 | unsigned int devfn, int reg, int len, u32 value) |
| 47 | { | 47 | { |
| 48 | unsigned long flags; | 48 | unsigned long flags; |
diff --git a/arch/i386/pci/mmconfig.c b/arch/i386/pci/mmconfig.c index dfbf80cff834..08a084901212 100644 --- a/arch/i386/pci/mmconfig.c +++ b/arch/i386/pci/mmconfig.c | |||
| @@ -19,21 +19,25 @@ | |||
| 19 | /* The base address of the last MMCONFIG device accessed */ | 19 | /* The base address of the last MMCONFIG device accessed */ |
| 20 | static u32 mmcfg_last_accessed_device; | 20 | static u32 mmcfg_last_accessed_device; |
| 21 | 21 | ||
| 22 | static DECLARE_BITMAP(fallback_slots, 32); | ||
| 23 | |||
| 22 | /* | 24 | /* |
| 23 | * Functions for accessing PCI configuration space with MMCONFIG accesses | 25 | * Functions for accessing PCI configuration space with MMCONFIG accesses |
| 24 | */ | 26 | */ |
| 25 | static u32 get_base_addr(unsigned int seg, int bus) | 27 | static u32 get_base_addr(unsigned int seg, int bus, unsigned devfn) |
| 26 | { | 28 | { |
| 27 | int cfg_num = -1; | 29 | int cfg_num = -1; |
| 28 | struct acpi_table_mcfg_config *cfg; | 30 | struct acpi_table_mcfg_config *cfg; |
| 29 | 31 | ||
| 32 | if (seg == 0 && bus == 0 && | ||
| 33 | test_bit(PCI_SLOT(devfn), fallback_slots)) | ||
| 34 | return 0; | ||
| 35 | |||
| 30 | while (1) { | 36 | while (1) { |
| 31 | ++cfg_num; | 37 | ++cfg_num; |
| 32 | if (cfg_num >= pci_mmcfg_config_num) { | 38 | if (cfg_num >= pci_mmcfg_config_num) { |
| 33 | /* something bad is going on, no cfg table is found. */ | 39 | /* Not found - fallback to type 1 */ |
| 34 | /* so we fall back to the old way we used to do this */ | 40 | return 0; |
| 35 | /* and just rely on the first entry to be correct. */ | ||
| 36 | return pci_mmcfg_config[0].base_address; | ||
| 37 | } | 41 | } |
| 38 | cfg = &pci_mmcfg_config[cfg_num]; | 42 | cfg = &pci_mmcfg_config[cfg_num]; |
| 39 | if (cfg->pci_segment_group_number != seg) | 43 | if (cfg->pci_segment_group_number != seg) |
| @@ -44,9 +48,9 @@ static u32 get_base_addr(unsigned int seg, int bus) | |||
| 44 | } | 48 | } |
| 45 | } | 49 | } |
| 46 | 50 | ||
| 47 | static inline void pci_exp_set_dev_base(unsigned int seg, int bus, int devfn) | 51 | static inline void pci_exp_set_dev_base(unsigned int base, int bus, int devfn) |
| 48 | { | 52 | { |
| 49 | u32 dev_base = get_base_addr(seg, bus) | (bus << 20) | (devfn << 12); | 53 | u32 dev_base = base | (bus << 20) | (devfn << 12); |
| 50 | if (dev_base != mmcfg_last_accessed_device) { | 54 | if (dev_base != mmcfg_last_accessed_device) { |
| 51 | mmcfg_last_accessed_device = dev_base; | 55 | mmcfg_last_accessed_device = dev_base; |
| 52 | set_fixmap_nocache(FIX_PCIE_MCFG, dev_base); | 56 | set_fixmap_nocache(FIX_PCIE_MCFG, dev_base); |
| @@ -57,13 +61,18 @@ static int pci_mmcfg_read(unsigned int seg, unsigned int bus, | |||
| 57 | unsigned int devfn, int reg, int len, u32 *value) | 61 | unsigned int devfn, int reg, int len, u32 *value) |
| 58 | { | 62 | { |
| 59 | unsigned long flags; | 63 | unsigned long flags; |
| 64 | u32 base; | ||
| 60 | 65 | ||
| 61 | if (!value || (bus > 255) || (devfn > 255) || (reg > 4095)) | 66 | if (!value || (bus > 255) || (devfn > 255) || (reg > 4095)) |
| 62 | return -EINVAL; | 67 | return -EINVAL; |
| 63 | 68 | ||
| 69 | base = get_base_addr(seg, bus, devfn); | ||
| 70 | if (!base) | ||
| 71 | return pci_conf1_read(seg,bus,devfn,reg,len,value); | ||
| 72 | |||
| 64 | spin_lock_irqsave(&pci_config_lock, flags); | 73 | spin_lock_irqsave(&pci_config_lock, flags); |
| 65 | 74 | ||
| 66 | pci_exp_set_dev_base(seg, bus, devfn); | 75 | pci_exp_set_dev_base(base, bus, devfn); |
| 67 | 76 | ||
| 68 | switch (len) { | 77 | switch (len) { |
| 69 | case 1: | 78 | case 1: |
| @@ -86,13 +95,18 @@ static int pci_mmcfg_write(unsigned int seg, unsigned int bus, | |||
| 86 | unsigned int devfn, int reg, int len, u32 value) | 95 | unsigned int devfn, int reg, int len, u32 value) |
| 87 | { | 96 | { |
| 88 | unsigned long flags; | 97 | unsigned long flags; |
| 98 | u32 base; | ||
| 89 | 99 | ||
| 90 | if ((bus > 255) || (devfn > 255) || (reg > 4095)) | 100 | if ((bus > 255) || (devfn > 255) || (reg > 4095)) |
| 91 | return -EINVAL; | 101 | return -EINVAL; |
| 92 | 102 | ||
| 103 | base = get_base_addr(seg, bus, devfn); | ||
| 104 | if (!base) | ||
| 105 | return pci_conf1_write(seg,bus,devfn,reg,len,value); | ||
| 106 | |||
| 93 | spin_lock_irqsave(&pci_config_lock, flags); | 107 | spin_lock_irqsave(&pci_config_lock, flags); |
| 94 | 108 | ||
| 95 | pci_exp_set_dev_base(seg, bus, devfn); | 109 | pci_exp_set_dev_base(base, bus, devfn); |
| 96 | 110 | ||
| 97 | switch (len) { | 111 | switch (len) { |
| 98 | case 1: | 112 | case 1: |
| @@ -116,6 +130,37 @@ static struct pci_raw_ops pci_mmcfg = { | |||
| 116 | .write = pci_mmcfg_write, | 130 | .write = pci_mmcfg_write, |
| 117 | }; | 131 | }; |
| 118 | 132 | ||
| 133 | /* K8 systems have some devices (typically in the builtin northbridge) | ||
| 134 | that are only accessible using type1 | ||
| 135 | Normally this can be expressed in the MCFG by not listing them | ||
| 136 | and assigning suitable _SEGs, but this isn't implemented in some BIOS. | ||
| 137 | Instead try to discover all devices on bus 0 that are unreachable using MM | ||
| 138 | and fallback for them. | ||
| 139 | We only do this for bus 0/seg 0 */ | ||
| 140 | static __init void unreachable_devices(void) | ||
| 141 | { | ||
| 142 | int i; | ||
| 143 | unsigned long flags; | ||
| 144 | |||
| 145 | for (i = 0; i < 32; i++) { | ||
| 146 | u32 val1; | ||
| 147 | u32 addr; | ||
| 148 | |||
| 149 | pci_conf1_read(0, 0, PCI_DEVFN(i, 0), 0, 4, &val1); | ||
| 150 | if (val1 == 0xffffffff) | ||
| 151 | continue; | ||
| 152 | |||
| 153 | /* Locking probably not needed, but safer */ | ||
| 154 | spin_lock_irqsave(&pci_config_lock, flags); | ||
| 155 | addr = get_base_addr(0, 0, PCI_DEVFN(i, 0)); | ||
| 156 | if (addr != 0) | ||
| 157 | pci_exp_set_dev_base(addr, 0, PCI_DEVFN(i, 0)); | ||
| 158 | if (addr == 0 || readl((u32 *)addr) != val1) | ||
| 159 | set_bit(i, fallback_slots); | ||
| 160 | spin_unlock_irqrestore(&pci_config_lock, flags); | ||
| 161 | } | ||
| 162 | } | ||
| 163 | |||
| 119 | static int __init pci_mmcfg_init(void) | 164 | static int __init pci_mmcfg_init(void) |
| 120 | { | 165 | { |
| 121 | if ((pci_probe & PCI_PROBE_MMCONF) == 0) | 166 | if ((pci_probe & PCI_PROBE_MMCONF) == 0) |
| @@ -131,6 +176,8 @@ static int __init pci_mmcfg_init(void) | |||
| 131 | raw_pci_ops = &pci_mmcfg; | 176 | raw_pci_ops = &pci_mmcfg; |
| 132 | pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF; | 177 | pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF; |
| 133 | 178 | ||
| 179 | unreachable_devices(); | ||
| 180 | |||
| 134 | out: | 181 | out: |
| 135 | return 0; | 182 | return 0; |
| 136 | } | 183 | } |
diff --git a/arch/i386/pci/pci.h b/arch/i386/pci/pci.h index 127d53ad16be..f550781ec310 100644 --- a/arch/i386/pci/pci.h +++ b/arch/i386/pci/pci.h | |||
| @@ -74,3 +74,10 @@ extern spinlock_t pci_config_lock; | |||
| 74 | 74 | ||
| 75 | extern int (*pcibios_enable_irq)(struct pci_dev *dev); | 75 | extern int (*pcibios_enable_irq)(struct pci_dev *dev); |
| 76 | extern void (*pcibios_disable_irq)(struct pci_dev *dev); | 76 | extern void (*pcibios_disable_irq)(struct pci_dev *dev); |
| 77 | |||
| 78 | extern int pci_conf1_write(unsigned int seg, unsigned int bus, | ||
| 79 | unsigned int devfn, int reg, int len, u32 value); | ||
| 80 | extern int pci_conf1_read(unsigned int seg, unsigned int bus, | ||
| 81 | unsigned int devfn, int reg, int len, u32 *value); | ||
| 82 | |||
| 83 | |||
