aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@c2micro.com>2006-04-18 20:19:52 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2006-06-21 14:59:59 -0400
commit17d6dc8ff098cc8c57941c82f7702804302b1ea1 (patch)
tree866b2243517d1dae26f1fff0986ed08f96e63baa /drivers
parent83821d3f558dc651e555d62182ed0c95651f41a6 (diff)
[PATCH] PCI: Ignore pre-set 64-bit BARs on 32-bit platforms
[pci] Ignore pre-set 64-bit BARs on 32-bit platforms Currently, Linux always rejects a device which has a pre-set 64-bit address on a 32-bit platform. On systems which do not do PCI initialization in firmware, this causes some devices which don't correctly power up with all BARs zero to fail. This patch makes the kernel automatically zero out such an address (thus treating it as if it had not been set at all, meaning it will assign an address if necessary). I have done this only for devices, not bridges. It seems potentially hazardous to do for bridges. Signed-off-by: H. Peter Anvin <hpa@c2micro.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/pci/probe.c28
1 files changed, 17 insertions, 11 deletions
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index a10ed9dab2c2..5c4924c27f09 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 (l) {
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 }