aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/probe.c
diff options
context:
space:
mode:
authorYinghai Lu <yinghai.lu@amd.com>2006-11-29 16:53:10 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2007-02-07 18:50:03 -0500
commit07eddf3d597f2d009a37a4e8c7c32a1ffe992f3e (patch)
tree6ed35aff253bdf7aa01572687fcff5f0b7241606 /drivers/pci/probe.c
parent5331be090567d9335476f876b2d85427cd7c4426 (diff)
PCI: check szhi when sz is 0 when 64 bit iomem bigger than 4G
For pci mem resource that size is bigger than 4G, the sz returned by pc_size will be 0. So that resource is skipped, and register contained hi address will be treated as another 32bit resource. We need to use sz64 and pci_sz64 for 64 bit resource for clear logical. Typical usages for this: Opteron system with co-processor and the co-processor could take more than 4G RAM as pre-fetchable mem resource. Signed-off-by: Yinghai Lu <yinghai.lu@amd.com> Cc: Andi Kleen <ak@suse.de> Cc: Andrew Morton <akpm@osdl.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/pci/probe.c')
-rw-r--r--drivers/pci/probe.c69
1 files changed, 56 insertions, 13 deletions
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 0e0401dd02cb..9d7788428642 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -144,6 +144,32 @@ static u32 pci_size(u32 base, u32 maxbase, u32 mask)
144 return size; 144 return size;
145} 145}
146 146
147static u64 pci_size64(u64 base, u64 maxbase, u64 mask)
148{
149 u64 size = mask & maxbase; /* Find the significant bits */
150 if (!size)
151 return 0;
152
153 /* Get the lowest of them to find the decode size, and
154 from that the extent. */
155 size = (size & ~(size-1)) - 1;
156
157 /* base == maxbase can be valid only if the BAR has
158 already been programmed with all 1s. */
159 if (base == maxbase && ((base | size) & mask) != mask)
160 return 0;
161
162 return size;
163}
164
165static inline int is_64bit_memory(u32 mask)
166{
167 if ((mask & (PCI_BASE_ADDRESS_SPACE|PCI_BASE_ADDRESS_MEM_TYPE_MASK)) ==
168 (PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64))
169 return 1;
170 return 0;
171}
172
147static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom) 173static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
148{ 174{
149 unsigned int pos, reg, next; 175 unsigned int pos, reg, next;
@@ -151,6 +177,10 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
151 struct resource *res; 177 struct resource *res;
152 178
153 for(pos=0; pos<howmany; pos = next) { 179 for(pos=0; pos<howmany; pos = next) {
180 u64 l64;
181 u64 sz64;
182 u32 raw_sz;
183
154 next = pos+1; 184 next = pos+1;
155 res = &dev->resource[pos]; 185 res = &dev->resource[pos];
156 res->name = pci_name(dev); 186 res->name = pci_name(dev);
@@ -163,9 +193,16 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
163 continue; 193 continue;
164 if (l == 0xffffffff) 194 if (l == 0xffffffff)
165 l = 0; 195 l = 0;
166 if ((l & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY) { 196 raw_sz = sz;
197 if ((l & PCI_BASE_ADDRESS_SPACE) ==
198 PCI_BASE_ADDRESS_SPACE_MEMORY) {
167 sz = pci_size(l, sz, (u32)PCI_BASE_ADDRESS_MEM_MASK); 199 sz = pci_size(l, sz, (u32)PCI_BASE_ADDRESS_MEM_MASK);
168 if (!sz) 200 /*
201 * For 64bit prefetchable memory sz could be 0, if the
202 * real size is bigger than 4G, so we need to check
203 * szhi for that.
204 */
205 if (!is_64bit_memory(l) && !sz)
169 continue; 206 continue;
170 res->start = l & PCI_BASE_ADDRESS_MEM_MASK; 207 res->start = l & PCI_BASE_ADDRESS_MEM_MASK;
171 res->flags |= l & ~PCI_BASE_ADDRESS_MEM_MASK; 208 res->flags |= l & ~PCI_BASE_ADDRESS_MEM_MASK;
@@ -178,30 +215,36 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
178 } 215 }
179 res->end = res->start + (unsigned long) sz; 216 res->end = res->start + (unsigned long) sz;
180 res->flags |= pci_calc_resource_flags(l); 217 res->flags |= pci_calc_resource_flags(l);
181 if ((l & (PCI_BASE_ADDRESS_SPACE | PCI_BASE_ADDRESS_MEM_TYPE_MASK)) 218 if (is_64bit_memory(l)) {
182 == (PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64)) {
183 u32 szhi, lhi; 219 u32 szhi, lhi;
220
184 pci_read_config_dword(dev, reg+4, &lhi); 221 pci_read_config_dword(dev, reg+4, &lhi);
185 pci_write_config_dword(dev, reg+4, ~0); 222 pci_write_config_dword(dev, reg+4, ~0);
186 pci_read_config_dword(dev, reg+4, &szhi); 223 pci_read_config_dword(dev, reg+4, &szhi);
187 pci_write_config_dword(dev, reg+4, lhi); 224 pci_write_config_dword(dev, reg+4, lhi);
188 szhi = pci_size(lhi, szhi, 0xffffffff); 225 sz64 = ((u64)szhi << 32) | raw_sz;
226 l64 = ((u64)lhi << 32) | l;
227 sz64 = pci_size64(l64, sz64, PCI_BASE_ADDRESS_MEM_MASK);
189 next++; 228 next++;
190#if BITS_PER_LONG == 64 229#if BITS_PER_LONG == 64
191 res->start |= ((unsigned long) lhi) << 32; 230 if (!sz64) {
192 res->end = res->start + sz; 231 res->start = 0;
193 if (szhi) { 232 res->end = 0;
194 /* This BAR needs > 4GB? Wow. */ 233 res->flags = 0;
195 res->end |= (unsigned long)szhi<<32; 234 continue;
196 } 235 }
236 res->start = l64 & PCI_BASE_ADDRESS_MEM_MASK;
237 res->end = res->start + sz64;
197#else 238#else
198 if (szhi) { 239 if (sz64 > 0x100000000ULL) {
199 printk(KERN_ERR "PCI: Unable to handle 64-bit BAR for device %s\n", pci_name(dev)); 240 printk(KERN_ERR "PCI: Unable to handle 64-bit "
241 "BAR for device %s\n", pci_name(dev));
200 res->start = 0; 242 res->start = 0;
201 res->flags = 0; 243 res->flags = 0;
202 } else if (lhi) { 244 } else if (lhi) {
203 /* 64-bit wide address, treat as disabled */ 245 /* 64-bit wide address, treat as disabled */
204 pci_write_config_dword(dev, reg, l & ~(u32)PCI_BASE_ADDRESS_MEM_MASK); 246 pci_write_config_dword(dev, reg,
247 l & ~(u32)PCI_BASE_ADDRESS_MEM_MASK);
205 pci_write_config_dword(dev, reg+4, 0); 248 pci_write_config_dword(dev, reg+4, 0);
206 res->start = 0; 249 res->start = 0;
207 res->end = sz; 250 res->end = sz;