aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/probe.c
diff options
context:
space:
mode:
authorMatthew Wilcox <matthew@wil.cx>2009-12-13 08:11:33 -0500
committerJesse Barnes <jbarnes@virtuousgeek.org>2010-02-22 19:15:18 -0500
commit9be60ca0497a2563662fde4c9007841c3b79a742 (patch)
treed31bc38997f7591d818d478ba91a7f07dee9bede /drivers/pci/probe.c
parent3749c51ac6c1560aa1cb1520066bed84c6f8152a (diff)
PCI: Add support for detection of PCIe and PCI-X bus speeds
Both PCIe and PCI-X bridges report their secondary bus speed in their respective capabilities. Signed-off-by: Matthew Wilcox <willy@linux.intel.com> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/pci/probe.c')
-rw-r--r--drivers/pci/probe.c66
1 files changed, 66 insertions, 0 deletions
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 51cf8982fec7..188ee9cf0605 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -393,6 +393,25 @@ static struct pci_bus * pci_alloc_bus(void)
393 return b; 393 return b;
394} 394}
395 395
396static unsigned char pcix_bus_speed[] = {
397 PCI_SPEED_UNKNOWN, /* 0 */
398 PCI_SPEED_66MHz_PCIX, /* 1 */
399 PCI_SPEED_100MHz_PCIX, /* 2 */
400 PCI_SPEED_133MHz_PCIX, /* 3 */
401 PCI_SPEED_UNKNOWN, /* 4 */
402 PCI_SPEED_66MHz_PCIX_ECC, /* 5 */
403 PCI_SPEED_100MHz_PCIX_ECC, /* 6 */
404 PCI_SPEED_133MHz_PCIX_ECC, /* 7 */
405 PCI_SPEED_UNKNOWN, /* 8 */
406 PCI_SPEED_66MHz_PCIX_266, /* 9 */
407 PCI_SPEED_100MHz_PCIX_266, /* A */
408 PCI_SPEED_133MHz_PCIX_266, /* B */
409 PCI_SPEED_UNKNOWN, /* C */
410 PCI_SPEED_66MHz_PCIX_533, /* D */
411 PCI_SPEED_100MHz_PCIX_533, /* E */
412 PCI_SPEED_133MHz_PCIX_533 /* F */
413};
414
396static unsigned char pcie_link_speed[] = { 415static unsigned char pcie_link_speed[] = {
397 PCI_SPEED_UNKNOWN, /* 0 */ 416 PCI_SPEED_UNKNOWN, /* 0 */
398 PCIE_SPEED_2_5GT, /* 1 */ 417 PCIE_SPEED_2_5GT, /* 1 */
@@ -418,6 +437,51 @@ void pcie_update_link_speed(struct pci_bus *bus, u16 linksta)
418} 437}
419EXPORT_SYMBOL_GPL(pcie_update_link_speed); 438EXPORT_SYMBOL_GPL(pcie_update_link_speed);
420 439
440static void pci_set_bus_speed(struct pci_bus *bus)
441{
442 struct pci_dev *bridge = bus->self;
443 int pos;
444
445 pos = pci_find_capability(bridge, PCI_CAP_ID_PCIX);
446 if (pos) {
447 u16 status;
448 enum pci_bus_speed max;
449 pci_read_config_word(bridge, pos + 2, &status);
450
451 if (status & 0x8000) {
452 max = PCI_SPEED_133MHz_PCIX_533;
453 } else if (status & 0x4000) {
454 max = PCI_SPEED_133MHz_PCIX_266;
455 } else if (status & 0x0002) {
456 if (((status >> 12) & 0x3) == 2) {
457 max = PCI_SPEED_133MHz_PCIX_ECC;
458 } else {
459 max = PCI_SPEED_133MHz_PCIX;
460 }
461 } else {
462 max = PCI_SPEED_66MHz_PCIX;
463 }
464
465 bus->max_bus_speed = max;
466 bus->cur_bus_speed = pcix_bus_speed[(status >> 6) & 0xf];
467
468 return;
469 }
470
471 pos = pci_find_capability(bridge, PCI_CAP_ID_EXP);
472 if (pos) {
473 u32 linkcap;
474 u16 linksta;
475
476 pci_read_config_dword(bridge, pos + PCI_EXP_LNKCAP, &linkcap);
477 bus->max_bus_speed = pcie_link_speed[linkcap & 0xf];
478
479 pci_read_config_word(bridge, pos + PCI_EXP_LNKSTA, &linksta);
480 pcie_update_link_speed(bus, linksta);
481 }
482}
483
484
421static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent, 485static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent,
422 struct pci_dev *bridge, int busnr) 486 struct pci_dev *bridge, int busnr)
423{ 487{
@@ -457,6 +521,8 @@ static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent,
457 child->self = bridge; 521 child->self = bridge;
458 child->bridge = get_device(&bridge->dev); 522 child->bridge = get_device(&bridge->dev);
459 523
524 pci_set_bus_speed(child);
525
460 /* Set up default resource pointers and names.. */ 526 /* Set up default resource pointers and names.. */
461 for (i = 0; i < PCI_BRIDGE_RESOURCE_NUM; i++) { 527 for (i = 0; i < PCI_BRIDGE_RESOURCE_NUM; i++) {
462 child->resource[i] = &bridge->resource[PCI_BRIDGE_RESOURCES+i]; 528 child->resource[i] = &bridge->resource[PCI_BRIDGE_RESOURCES+i];