diff options
author | David S. Miller <davem@davemloft.net> | 2010-02-28 22:23:06 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-02-28 22:23:06 -0500 |
commit | 47871889c601d8199c51a4086f77eebd77c29b0b (patch) | |
tree | 40cdcac3bff0ee40cc33dcca61d0577cdf965f77 /drivers/pci/probe.c | |
parent | c16cc0b464b8876cfd57ce1c1dbcb6f9a6a0bce3 (diff) | |
parent | 30ff056c42c665b9ea535d8515890857ae382540 (diff) |
Merge branch 'master' of /home/davem/src/GIT/linux-2.6/
Conflicts:
drivers/firmware/iscsi_ibft.c
Diffstat (limited to 'drivers/pci/probe.c')
-rw-r--r-- | drivers/pci/probe.c | 293 |
1 files changed, 265 insertions, 28 deletions
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 446e4a94d7d3..2a943090a3b7 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c | |||
@@ -89,6 +89,7 @@ static void release_pcibus_dev(struct device *dev) | |||
89 | 89 | ||
90 | if (pci_bus->bridge) | 90 | if (pci_bus->bridge) |
91 | put_device(pci_bus->bridge); | 91 | put_device(pci_bus->bridge); |
92 | pci_bus_remove_resources(pci_bus); | ||
92 | kfree(pci_bus); | 93 | kfree(pci_bus); |
93 | } | 94 | } |
94 | 95 | ||
@@ -281,26 +282,12 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom) | |||
281 | } | 282 | } |
282 | } | 283 | } |
283 | 284 | ||
284 | void __devinit pci_read_bridge_bases(struct pci_bus *child) | 285 | static void __devinit pci_read_bridge_io(struct pci_bus *child) |
285 | { | 286 | { |
286 | struct pci_dev *dev = child->self; | 287 | struct pci_dev *dev = child->self; |
287 | u8 io_base_lo, io_limit_lo; | 288 | u8 io_base_lo, io_limit_lo; |
288 | u16 mem_base_lo, mem_limit_lo; | ||
289 | unsigned long base, limit; | 289 | unsigned long base, limit; |
290 | struct resource *res; | 290 | struct resource *res; |
291 | int i; | ||
292 | |||
293 | if (pci_is_root_bus(child)) /* It's a host bus, nothing to read */ | ||
294 | return; | ||
295 | |||
296 | dev_info(&dev->dev, "PCI bridge to [bus %02x-%02x]%s\n", | ||
297 | child->secondary, child->subordinate, | ||
298 | dev->transparent ? " (subtractive decode)": ""); | ||
299 | |||
300 | if (dev->transparent) { | ||
301 | for(i = 3; i < PCI_BUS_NUM_RESOURCES; i++) | ||
302 | child->resource[i] = child->parent->resource[i - 3]; | ||
303 | } | ||
304 | 291 | ||
305 | res = child->resource[0]; | 292 | res = child->resource[0]; |
306 | pci_read_config_byte(dev, PCI_IO_BASE, &io_base_lo); | 293 | pci_read_config_byte(dev, PCI_IO_BASE, &io_base_lo); |
@@ -316,26 +303,50 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child) | |||
316 | limit |= (io_limit_hi << 16); | 303 | limit |= (io_limit_hi << 16); |
317 | } | 304 | } |
318 | 305 | ||
319 | if (base <= limit) { | 306 | if (base && base <= limit) { |
320 | res->flags = (io_base_lo & PCI_IO_RANGE_TYPE_MASK) | IORESOURCE_IO; | 307 | res->flags = (io_base_lo & PCI_IO_RANGE_TYPE_MASK) | IORESOURCE_IO; |
321 | if (!res->start) | 308 | if (!res->start) |
322 | res->start = base; | 309 | res->start = base; |
323 | if (!res->end) | 310 | if (!res->end) |
324 | res->end = limit + 0xfff; | 311 | res->end = limit + 0xfff; |
325 | dev_printk(KERN_DEBUG, &dev->dev, " bridge window %pR\n", res); | 312 | dev_printk(KERN_DEBUG, &dev->dev, " bridge window %pR\n", res); |
313 | } else { | ||
314 | dev_printk(KERN_DEBUG, &dev->dev, | ||
315 | " bridge window [io %04lx - %04lx] reg reading\n", | ||
316 | base, limit); | ||
326 | } | 317 | } |
318 | } | ||
319 | |||
320 | static void __devinit pci_read_bridge_mmio(struct pci_bus *child) | ||
321 | { | ||
322 | struct pci_dev *dev = child->self; | ||
323 | u16 mem_base_lo, mem_limit_lo; | ||
324 | unsigned long base, limit; | ||
325 | struct resource *res; | ||
327 | 326 | ||
328 | res = child->resource[1]; | 327 | res = child->resource[1]; |
329 | pci_read_config_word(dev, PCI_MEMORY_BASE, &mem_base_lo); | 328 | pci_read_config_word(dev, PCI_MEMORY_BASE, &mem_base_lo); |
330 | pci_read_config_word(dev, PCI_MEMORY_LIMIT, &mem_limit_lo); | 329 | pci_read_config_word(dev, PCI_MEMORY_LIMIT, &mem_limit_lo); |
331 | base = (mem_base_lo & PCI_MEMORY_RANGE_MASK) << 16; | 330 | base = (mem_base_lo & PCI_MEMORY_RANGE_MASK) << 16; |
332 | limit = (mem_limit_lo & PCI_MEMORY_RANGE_MASK) << 16; | 331 | limit = (mem_limit_lo & PCI_MEMORY_RANGE_MASK) << 16; |
333 | if (base <= limit) { | 332 | if (base && base <= limit) { |
334 | res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM; | 333 | res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM; |
335 | res->start = base; | 334 | res->start = base; |
336 | res->end = limit + 0xfffff; | 335 | res->end = limit + 0xfffff; |
337 | dev_printk(KERN_DEBUG, &dev->dev, " bridge window %pR\n", res); | 336 | dev_printk(KERN_DEBUG, &dev->dev, " bridge window %pR\n", res); |
337 | } else { | ||
338 | dev_printk(KERN_DEBUG, &dev->dev, | ||
339 | " bridge window [mem 0x%08lx - 0x%08lx] reg reading\n", | ||
340 | base, limit + 0xfffff); | ||
338 | } | 341 | } |
342 | } | ||
343 | |||
344 | static void __devinit pci_read_bridge_mmio_pref(struct pci_bus *child) | ||
345 | { | ||
346 | struct pci_dev *dev = child->self; | ||
347 | u16 mem_base_lo, mem_limit_lo; | ||
348 | unsigned long base, limit; | ||
349 | struct resource *res; | ||
339 | 350 | ||
340 | res = child->resource[2]; | 351 | res = child->resource[2]; |
341 | pci_read_config_word(dev, PCI_PREF_MEMORY_BASE, &mem_base_lo); | 352 | pci_read_config_word(dev, PCI_PREF_MEMORY_BASE, &mem_base_lo); |
@@ -366,7 +377,7 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child) | |||
366 | #endif | 377 | #endif |
367 | } | 378 | } |
368 | } | 379 | } |
369 | if (base <= limit) { | 380 | if (base && base <= limit) { |
370 | res->flags = (mem_base_lo & PCI_PREF_RANGE_TYPE_MASK) | | 381 | res->flags = (mem_base_lo & PCI_PREF_RANGE_TYPE_MASK) | |
371 | IORESOURCE_MEM | IORESOURCE_PREFETCH; | 382 | IORESOURCE_MEM | IORESOURCE_PREFETCH; |
372 | if (res->flags & PCI_PREF_RANGE_TYPE_64) | 383 | if (res->flags & PCI_PREF_RANGE_TYPE_64) |
@@ -374,6 +385,44 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child) | |||
374 | res->start = base; | 385 | res->start = base; |
375 | res->end = limit + 0xfffff; | 386 | res->end = limit + 0xfffff; |
376 | dev_printk(KERN_DEBUG, &dev->dev, " bridge window %pR\n", res); | 387 | dev_printk(KERN_DEBUG, &dev->dev, " bridge window %pR\n", res); |
388 | } else { | ||
389 | dev_printk(KERN_DEBUG, &dev->dev, | ||
390 | " bridge window [mem 0x%08lx - %08lx pref] reg reading\n", | ||
391 | base, limit + 0xfffff); | ||
392 | } | ||
393 | } | ||
394 | |||
395 | void __devinit pci_read_bridge_bases(struct pci_bus *child) | ||
396 | { | ||
397 | struct pci_dev *dev = child->self; | ||
398 | struct resource *res; | ||
399 | int i; | ||
400 | |||
401 | if (pci_is_root_bus(child)) /* It's a host bus, nothing to read */ | ||
402 | return; | ||
403 | |||
404 | dev_info(&dev->dev, "PCI bridge to [bus %02x-%02x]%s\n", | ||
405 | child->secondary, child->subordinate, | ||
406 | dev->transparent ? " (subtractive decode)" : ""); | ||
407 | |||
408 | pci_bus_remove_resources(child); | ||
409 | for (i = 0; i < PCI_BRIDGE_RESOURCE_NUM; i++) | ||
410 | child->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i]; | ||
411 | |||
412 | pci_read_bridge_io(child); | ||
413 | pci_read_bridge_mmio(child); | ||
414 | pci_read_bridge_mmio_pref(child); | ||
415 | |||
416 | if (dev->transparent) { | ||
417 | pci_bus_for_each_resource(child->parent, res, i) { | ||
418 | if (res) { | ||
419 | pci_bus_add_resource(child, res, | ||
420 | PCI_SUBTRACTIVE_DECODE); | ||
421 | dev_printk(KERN_DEBUG, &dev->dev, | ||
422 | " bridge window %pR (subtractive decode)\n", | ||
423 | res); | ||
424 | } | ||
425 | } | ||
377 | } | 426 | } |
378 | } | 427 | } |
379 | 428 | ||
@@ -387,10 +436,147 @@ static struct pci_bus * pci_alloc_bus(void) | |||
387 | INIT_LIST_HEAD(&b->children); | 436 | INIT_LIST_HEAD(&b->children); |
388 | INIT_LIST_HEAD(&b->devices); | 437 | INIT_LIST_HEAD(&b->devices); |
389 | INIT_LIST_HEAD(&b->slots); | 438 | INIT_LIST_HEAD(&b->slots); |
439 | INIT_LIST_HEAD(&b->resources); | ||
440 | b->max_bus_speed = PCI_SPEED_UNKNOWN; | ||
441 | b->cur_bus_speed = PCI_SPEED_UNKNOWN; | ||
390 | } | 442 | } |
391 | return b; | 443 | return b; |
392 | } | 444 | } |
393 | 445 | ||
446 | static unsigned char pcix_bus_speed[] = { | ||
447 | PCI_SPEED_UNKNOWN, /* 0 */ | ||
448 | PCI_SPEED_66MHz_PCIX, /* 1 */ | ||
449 | PCI_SPEED_100MHz_PCIX, /* 2 */ | ||
450 | PCI_SPEED_133MHz_PCIX, /* 3 */ | ||
451 | PCI_SPEED_UNKNOWN, /* 4 */ | ||
452 | PCI_SPEED_66MHz_PCIX_ECC, /* 5 */ | ||
453 | PCI_SPEED_100MHz_PCIX_ECC, /* 6 */ | ||
454 | PCI_SPEED_133MHz_PCIX_ECC, /* 7 */ | ||
455 | PCI_SPEED_UNKNOWN, /* 8 */ | ||
456 | PCI_SPEED_66MHz_PCIX_266, /* 9 */ | ||
457 | PCI_SPEED_100MHz_PCIX_266, /* A */ | ||
458 | PCI_SPEED_133MHz_PCIX_266, /* B */ | ||
459 | PCI_SPEED_UNKNOWN, /* C */ | ||
460 | PCI_SPEED_66MHz_PCIX_533, /* D */ | ||
461 | PCI_SPEED_100MHz_PCIX_533, /* E */ | ||
462 | PCI_SPEED_133MHz_PCIX_533 /* F */ | ||
463 | }; | ||
464 | |||
465 | static unsigned char pcie_link_speed[] = { | ||
466 | PCI_SPEED_UNKNOWN, /* 0 */ | ||
467 | PCIE_SPEED_2_5GT, /* 1 */ | ||
468 | PCIE_SPEED_5_0GT, /* 2 */ | ||
469 | PCIE_SPEED_8_0GT, /* 3 */ | ||
470 | PCI_SPEED_UNKNOWN, /* 4 */ | ||
471 | PCI_SPEED_UNKNOWN, /* 5 */ | ||
472 | PCI_SPEED_UNKNOWN, /* 6 */ | ||
473 | PCI_SPEED_UNKNOWN, /* 7 */ | ||
474 | PCI_SPEED_UNKNOWN, /* 8 */ | ||
475 | PCI_SPEED_UNKNOWN, /* 9 */ | ||
476 | PCI_SPEED_UNKNOWN, /* A */ | ||
477 | PCI_SPEED_UNKNOWN, /* B */ | ||
478 | PCI_SPEED_UNKNOWN, /* C */ | ||
479 | PCI_SPEED_UNKNOWN, /* D */ | ||
480 | PCI_SPEED_UNKNOWN, /* E */ | ||
481 | PCI_SPEED_UNKNOWN /* F */ | ||
482 | }; | ||
483 | |||
484 | void pcie_update_link_speed(struct pci_bus *bus, u16 linksta) | ||
485 | { | ||
486 | bus->cur_bus_speed = pcie_link_speed[linksta & 0xf]; | ||
487 | } | ||
488 | EXPORT_SYMBOL_GPL(pcie_update_link_speed); | ||
489 | |||
490 | static unsigned char agp_speeds[] = { | ||
491 | AGP_UNKNOWN, | ||
492 | AGP_1X, | ||
493 | AGP_2X, | ||
494 | AGP_4X, | ||
495 | AGP_8X | ||
496 | }; | ||
497 | |||
498 | static enum pci_bus_speed agp_speed(int agp3, int agpstat) | ||
499 | { | ||
500 | int index = 0; | ||
501 | |||
502 | if (agpstat & 4) | ||
503 | index = 3; | ||
504 | else if (agpstat & 2) | ||
505 | index = 2; | ||
506 | else if (agpstat & 1) | ||
507 | index = 1; | ||
508 | else | ||
509 | goto out; | ||
510 | |||
511 | if (agp3) { | ||
512 | index += 2; | ||
513 | if (index == 5) | ||
514 | index = 0; | ||
515 | } | ||
516 | |||
517 | out: | ||
518 | return agp_speeds[index]; | ||
519 | } | ||
520 | |||
521 | |||
522 | static void pci_set_bus_speed(struct pci_bus *bus) | ||
523 | { | ||
524 | struct pci_dev *bridge = bus->self; | ||
525 | int pos; | ||
526 | |||
527 | pos = pci_find_capability(bridge, PCI_CAP_ID_AGP); | ||
528 | if (!pos) | ||
529 | pos = pci_find_capability(bridge, PCI_CAP_ID_AGP3); | ||
530 | if (pos) { | ||
531 | u32 agpstat, agpcmd; | ||
532 | |||
533 | pci_read_config_dword(bridge, pos + PCI_AGP_STATUS, &agpstat); | ||
534 | bus->max_bus_speed = agp_speed(agpstat & 8, agpstat & 7); | ||
535 | |||
536 | pci_read_config_dword(bridge, pos + PCI_AGP_COMMAND, &agpcmd); | ||
537 | bus->cur_bus_speed = agp_speed(agpstat & 8, agpcmd & 7); | ||
538 | } | ||
539 | |||
540 | pos = pci_find_capability(bridge, PCI_CAP_ID_PCIX); | ||
541 | if (pos) { | ||
542 | u16 status; | ||
543 | enum pci_bus_speed max; | ||
544 | pci_read_config_word(bridge, pos + 2, &status); | ||
545 | |||
546 | if (status & 0x8000) { | ||
547 | max = PCI_SPEED_133MHz_PCIX_533; | ||
548 | } else if (status & 0x4000) { | ||
549 | max = PCI_SPEED_133MHz_PCIX_266; | ||
550 | } else if (status & 0x0002) { | ||
551 | if (((status >> 12) & 0x3) == 2) { | ||
552 | max = PCI_SPEED_133MHz_PCIX_ECC; | ||
553 | } else { | ||
554 | max = PCI_SPEED_133MHz_PCIX; | ||
555 | } | ||
556 | } else { | ||
557 | max = PCI_SPEED_66MHz_PCIX; | ||
558 | } | ||
559 | |||
560 | bus->max_bus_speed = max; | ||
561 | bus->cur_bus_speed = pcix_bus_speed[(status >> 6) & 0xf]; | ||
562 | |||
563 | return; | ||
564 | } | ||
565 | |||
566 | pos = pci_find_capability(bridge, PCI_CAP_ID_EXP); | ||
567 | if (pos) { | ||
568 | u32 linkcap; | ||
569 | u16 linksta; | ||
570 | |||
571 | pci_read_config_dword(bridge, pos + PCI_EXP_LNKCAP, &linkcap); | ||
572 | bus->max_bus_speed = pcie_link_speed[linkcap & 0xf]; | ||
573 | |||
574 | pci_read_config_word(bridge, pos + PCI_EXP_LNKSTA, &linksta); | ||
575 | pcie_update_link_speed(bus, linksta); | ||
576 | } | ||
577 | } | ||
578 | |||
579 | |||
394 | static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent, | 580 | static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent, |
395 | struct pci_dev *bridge, int busnr) | 581 | struct pci_dev *bridge, int busnr) |
396 | { | 582 | { |
@@ -430,6 +616,8 @@ static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent, | |||
430 | child->self = bridge; | 616 | child->self = bridge; |
431 | child->bridge = get_device(&bridge->dev); | 617 | child->bridge = get_device(&bridge->dev); |
432 | 618 | ||
619 | pci_set_bus_speed(child); | ||
620 | |||
433 | /* Set up default resource pointers and names.. */ | 621 | /* Set up default resource pointers and names.. */ |
434 | for (i = 0; i < PCI_BRIDGE_RESOURCE_NUM; i++) { | 622 | for (i = 0; i < PCI_BRIDGE_RESOURCE_NUM; i++) { |
435 | child->resource[i] = &bridge->resource[PCI_BRIDGE_RESOURCES+i]; | 623 | child->resource[i] = &bridge->resource[PCI_BRIDGE_RESOURCES+i]; |
@@ -1081,6 +1269,45 @@ struct pci_dev *__ref pci_scan_single_device(struct pci_bus *bus, int devfn) | |||
1081 | } | 1269 | } |
1082 | EXPORT_SYMBOL(pci_scan_single_device); | 1270 | EXPORT_SYMBOL(pci_scan_single_device); |
1083 | 1271 | ||
1272 | static unsigned next_ari_fn(struct pci_dev *dev, unsigned fn) | ||
1273 | { | ||
1274 | u16 cap; | ||
1275 | unsigned pos, next_fn; | ||
1276 | |||
1277 | if (!dev) | ||
1278 | return 0; | ||
1279 | |||
1280 | pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ARI); | ||
1281 | if (!pos) | ||
1282 | return 0; | ||
1283 | pci_read_config_word(dev, pos + 4, &cap); | ||
1284 | next_fn = cap >> 8; | ||
1285 | if (next_fn <= fn) | ||
1286 | return 0; | ||
1287 | return next_fn; | ||
1288 | } | ||
1289 | |||
1290 | static unsigned next_trad_fn(struct pci_dev *dev, unsigned fn) | ||
1291 | { | ||
1292 | return (fn + 1) % 8; | ||
1293 | } | ||
1294 | |||
1295 | static unsigned no_next_fn(struct pci_dev *dev, unsigned fn) | ||
1296 | { | ||
1297 | return 0; | ||
1298 | } | ||
1299 | |||
1300 | static int only_one_child(struct pci_bus *bus) | ||
1301 | { | ||
1302 | struct pci_dev *parent = bus->self; | ||
1303 | if (!parent || !pci_is_pcie(parent)) | ||
1304 | return 0; | ||
1305 | if (parent->pcie_type == PCI_EXP_TYPE_ROOT_PORT || | ||
1306 | parent->pcie_type == PCI_EXP_TYPE_DOWNSTREAM) | ||
1307 | return 1; | ||
1308 | return 0; | ||
1309 | } | ||
1310 | |||
1084 | /** | 1311 | /** |
1085 | * pci_scan_slot - scan a PCI slot on a bus for devices. | 1312 | * pci_scan_slot - scan a PCI slot on a bus for devices. |
1086 | * @bus: PCI bus to scan | 1313 | * @bus: PCI bus to scan |
@@ -1094,21 +1321,30 @@ EXPORT_SYMBOL(pci_scan_single_device); | |||
1094 | */ | 1321 | */ |
1095 | int pci_scan_slot(struct pci_bus *bus, int devfn) | 1322 | int pci_scan_slot(struct pci_bus *bus, int devfn) |
1096 | { | 1323 | { |
1097 | int fn, nr = 0; | 1324 | unsigned fn, nr = 0; |
1098 | struct pci_dev *dev; | 1325 | struct pci_dev *dev; |
1326 | unsigned (*next_fn)(struct pci_dev *, unsigned) = no_next_fn; | ||
1327 | |||
1328 | if (only_one_child(bus) && (devfn > 0)) | ||
1329 | return 0; /* Already scanned the entire slot */ | ||
1099 | 1330 | ||
1100 | dev = pci_scan_single_device(bus, devfn); | 1331 | dev = pci_scan_single_device(bus, devfn); |
1101 | if (dev && !dev->is_added) /* new device? */ | 1332 | if (!dev) |
1333 | return 0; | ||
1334 | if (!dev->is_added) | ||
1102 | nr++; | 1335 | nr++; |
1103 | 1336 | ||
1104 | if (dev && dev->multifunction) { | 1337 | if (pci_ari_enabled(bus)) |
1105 | for (fn = 1; fn < 8; fn++) { | 1338 | next_fn = next_ari_fn; |
1106 | dev = pci_scan_single_device(bus, devfn + fn); | 1339 | else if (dev->multifunction) |
1107 | if (dev) { | 1340 | next_fn = next_trad_fn; |
1108 | if (!dev->is_added) | 1341 | |
1109 | nr++; | 1342 | for (fn = next_fn(dev, 0); fn > 0; fn = next_fn(dev, fn)) { |
1110 | dev->multifunction = 1; | 1343 | dev = pci_scan_single_device(bus, devfn + fn); |
1111 | } | 1344 | if (dev) { |
1345 | if (!dev->is_added) | ||
1346 | nr++; | ||
1347 | dev->multifunction = 1; | ||
1112 | } | 1348 | } |
1113 | } | 1349 | } |
1114 | 1350 | ||
@@ -1200,6 +1436,7 @@ struct pci_bus * pci_create_bus(struct device *parent, | |||
1200 | if (error) | 1436 | if (error) |
1201 | goto dev_reg_err; | 1437 | goto dev_reg_err; |
1202 | b->bridge = get_device(dev); | 1438 | b->bridge = get_device(dev); |
1439 | device_enable_async_suspend(b->bridge); | ||
1203 | 1440 | ||
1204 | if (!parent) | 1441 | if (!parent) |
1205 | set_dev_node(b->bridge, pcibus_to_node(b)); | 1442 | set_dev_node(b->bridge, pcibus_to_node(b)); |