diff options
Diffstat (limited to 'drivers/pci/probe.c')
| -rw-r--r-- | drivers/pci/probe.c | 45 |
1 files changed, 26 insertions, 19 deletions
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index a10ed9dab2c2..f89dbc3738b7 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c | |||
| @@ -180,25 +180,31 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom) | |||
| 180 | res->flags |= pci_calc_resource_flags(l); | 180 | res->flags |= pci_calc_resource_flags(l); |
| 181 | if ((l & (PCI_BASE_ADDRESS_SPACE | PCI_BASE_ADDRESS_MEM_TYPE_MASK)) | 181 | if ((l & (PCI_BASE_ADDRESS_SPACE | PCI_BASE_ADDRESS_MEM_TYPE_MASK)) |
| 182 | == (PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64)) { | 182 | == (PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64)) { |
| 183 | pci_read_config_dword(dev, reg+4, &l); | 183 | u32 szhi, lhi; |
| 184 | pci_read_config_dword(dev, reg+4, &lhi); | ||
| 185 | pci_write_config_dword(dev, reg+4, ~0); | ||
| 186 | pci_read_config_dword(dev, reg+4, &szhi); | ||
| 187 | pci_write_config_dword(dev, reg+4, lhi); | ||
| 188 | szhi = pci_size(lhi, szhi, 0xffffffff); | ||
| 184 | next++; | 189 | next++; |
| 185 | #if BITS_PER_LONG == 64 | 190 | #if BITS_PER_LONG == 64 |
| 186 | res->start |= ((unsigned long) l) << 32; | 191 | res->start |= ((unsigned long) lhi) << 32; |
| 187 | res->end = res->start + sz; | 192 | res->end = res->start + sz; |
| 188 | pci_write_config_dword(dev, reg+4, ~0); | 193 | if (szhi) { |
| 189 | pci_read_config_dword(dev, reg+4, &sz); | ||
| 190 | pci_write_config_dword(dev, reg+4, l); | ||
| 191 | sz = pci_size(l, sz, 0xffffffff); | ||
| 192 | if (sz) { | ||
| 193 | /* This BAR needs > 4GB? Wow. */ | 194 | /* This BAR needs > 4GB? Wow. */ |
| 194 | res->end |= (unsigned long)sz<<32; | 195 | res->end |= (unsigned long)szhi<<32; |
| 195 | } | 196 | } |
| 196 | #else | 197 | #else |
| 197 | if (l) { | 198 | if (szhi) { |
| 198 | printk(KERN_ERR "PCI: Unable to handle 64-bit address for device %s\n", pci_name(dev)); | 199 | printk(KERN_ERR "PCI: Unable to handle 64-bit BAR for device %s\n", pci_name(dev)); |
| 199 | res->start = 0; | 200 | res->start = 0; |
| 200 | res->flags = 0; | 201 | res->flags = 0; |
| 201 | continue; | 202 | } else if (lhi) { |
| 203 | /* 64-bit wide address, treat as disabled */ | ||
| 204 | pci_write_config_dword(dev, reg, l & ~(u32)PCI_BASE_ADDRESS_MEM_MASK); | ||
| 205 | pci_write_config_dword(dev, reg+4, 0); | ||
| 206 | res->start = 0; | ||
| 207 | res->end = sz; | ||
| 202 | } | 208 | } |
| 203 | #endif | 209 | #endif |
| 204 | } | 210 | } |
| @@ -377,9 +383,9 @@ struct pci_bus * __devinit pci_add_new_bus(struct pci_bus *parent, struct pci_de | |||
| 377 | 383 | ||
| 378 | child = pci_alloc_child_bus(parent, dev, busnr); | 384 | child = pci_alloc_child_bus(parent, dev, busnr); |
| 379 | if (child) { | 385 | if (child) { |
| 380 | spin_lock(&pci_bus_lock); | 386 | down_write(&pci_bus_sem); |
| 381 | list_add_tail(&child->node, &parent->children); | 387 | list_add_tail(&child->node, &parent->children); |
| 382 | spin_unlock(&pci_bus_lock); | 388 | up_write(&pci_bus_sem); |
| 383 | } | 389 | } |
| 384 | return child; | 390 | return child; |
| 385 | } | 391 | } |
| @@ -838,9 +844,9 @@ void __devinit pci_device_add(struct pci_dev *dev, struct pci_bus *bus) | |||
| 838 | * and the bus list for fixup functions, etc. | 844 | * and the bus list for fixup functions, etc. |
| 839 | */ | 845 | */ |
| 840 | INIT_LIST_HEAD(&dev->global_list); | 846 | INIT_LIST_HEAD(&dev->global_list); |
| 841 | spin_lock(&pci_bus_lock); | 847 | down_write(&pci_bus_sem); |
| 842 | list_add_tail(&dev->bus_list, &bus->devices); | 848 | list_add_tail(&dev->bus_list, &bus->devices); |
| 843 | spin_unlock(&pci_bus_lock); | 849 | up_write(&pci_bus_sem); |
| 844 | } | 850 | } |
| 845 | 851 | ||
| 846 | struct pci_dev * __devinit | 852 | struct pci_dev * __devinit |
| @@ -975,9 +981,10 @@ struct pci_bus * __devinit pci_create_bus(struct device *parent, | |||
| 975 | pr_debug("PCI: Bus %04x:%02x already known\n", pci_domain_nr(b), bus); | 981 | pr_debug("PCI: Bus %04x:%02x already known\n", pci_domain_nr(b), bus); |
| 976 | goto err_out; | 982 | goto err_out; |
| 977 | } | 983 | } |
| 978 | spin_lock(&pci_bus_lock); | 984 | |
| 985 | down_write(&pci_bus_sem); | ||
| 979 | list_add_tail(&b->node, &pci_root_buses); | 986 | list_add_tail(&b->node, &pci_root_buses); |
| 980 | spin_unlock(&pci_bus_lock); | 987 | up_write(&pci_bus_sem); |
| 981 | 988 | ||
| 982 | memset(dev, 0, sizeof(*dev)); | 989 | memset(dev, 0, sizeof(*dev)); |
| 983 | dev->parent = parent; | 990 | dev->parent = parent; |
| @@ -1017,9 +1024,9 @@ class_dev_create_file_err: | |||
| 1017 | class_dev_reg_err: | 1024 | class_dev_reg_err: |
| 1018 | device_unregister(dev); | 1025 | device_unregister(dev); |
| 1019 | dev_reg_err: | 1026 | dev_reg_err: |
| 1020 | spin_lock(&pci_bus_lock); | 1027 | down_write(&pci_bus_sem); |
| 1021 | list_del(&b->node); | 1028 | list_del(&b->node); |
| 1022 | spin_unlock(&pci_bus_lock); | 1029 | up_write(&pci_bus_sem); |
| 1023 | err_out: | 1030 | err_out: |
| 1024 | kfree(dev); | 1031 | kfree(dev); |
| 1025 | kfree(b); | 1032 | kfree(b); |
