diff options
Diffstat (limited to 'drivers/pci/hotplug/pciehp_hpc.c')
-rw-r--r-- | drivers/pci/hotplug/pciehp_hpc.c | 155 |
1 files changed, 51 insertions, 104 deletions
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 9ef4605c1ef6..10040d58c8ef 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c | |||
@@ -45,25 +45,25 @@ static atomic_t pciehp_num_controllers = ATOMIC_INIT(0); | |||
45 | static inline int pciehp_readw(struct controller *ctrl, int reg, u16 *value) | 45 | static inline int pciehp_readw(struct controller *ctrl, int reg, u16 *value) |
46 | { | 46 | { |
47 | struct pci_dev *dev = ctrl->pcie->port; | 47 | struct pci_dev *dev = ctrl->pcie->port; |
48 | return pci_read_config_word(dev, ctrl->cap_base + reg, value); | 48 | return pci_read_config_word(dev, pci_pcie_cap(dev) + reg, value); |
49 | } | 49 | } |
50 | 50 | ||
51 | static inline int pciehp_readl(struct controller *ctrl, int reg, u32 *value) | 51 | static inline int pciehp_readl(struct controller *ctrl, int reg, u32 *value) |
52 | { | 52 | { |
53 | struct pci_dev *dev = ctrl->pcie->port; | 53 | struct pci_dev *dev = ctrl->pcie->port; |
54 | return pci_read_config_dword(dev, ctrl->cap_base + reg, value); | 54 | return pci_read_config_dword(dev, pci_pcie_cap(dev) + reg, value); |
55 | } | 55 | } |
56 | 56 | ||
57 | static inline int pciehp_writew(struct controller *ctrl, int reg, u16 value) | 57 | static inline int pciehp_writew(struct controller *ctrl, int reg, u16 value) |
58 | { | 58 | { |
59 | struct pci_dev *dev = ctrl->pcie->port; | 59 | struct pci_dev *dev = ctrl->pcie->port; |
60 | return pci_write_config_word(dev, ctrl->cap_base + reg, value); | 60 | return pci_write_config_word(dev, pci_pcie_cap(dev) + reg, value); |
61 | } | 61 | } |
62 | 62 | ||
63 | static inline int pciehp_writel(struct controller *ctrl, int reg, u32 value) | 63 | static inline int pciehp_writel(struct controller *ctrl, int reg, u32 value) |
64 | { | 64 | { |
65 | struct pci_dev *dev = ctrl->pcie->port; | 65 | struct pci_dev *dev = ctrl->pcie->port; |
66 | return pci_write_config_dword(dev, ctrl->cap_base + reg, value); | 66 | return pci_write_config_dword(dev, pci_pcie_cap(dev) + reg, value); |
67 | } | 67 | } |
68 | 68 | ||
69 | /* Power Control Command */ | 69 | /* Power Control Command */ |
@@ -318,8 +318,8 @@ int pciehp_get_attention_status(struct slot *slot, u8 *status) | |||
318 | return retval; | 318 | return retval; |
319 | } | 319 | } |
320 | 320 | ||
321 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x, value read %x\n", | 321 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x, value read %x\n", __func__, |
322 | __func__, ctrl->cap_base + PCI_EXP_SLTCTL, slot_ctrl); | 322 | pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_ctrl); |
323 | 323 | ||
324 | atten_led_state = (slot_ctrl & PCI_EXP_SLTCTL_AIC) >> 6; | 324 | atten_led_state = (slot_ctrl & PCI_EXP_SLTCTL_AIC) >> 6; |
325 | 325 | ||
@@ -356,8 +356,8 @@ int pciehp_get_power_status(struct slot *slot, u8 *status) | |||
356 | ctrl_err(ctrl, "%s: Cannot read SLOTCTRL register\n", __func__); | 356 | ctrl_err(ctrl, "%s: Cannot read SLOTCTRL register\n", __func__); |
357 | return retval; | 357 | return retval; |
358 | } | 358 | } |
359 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x value read %x\n", | 359 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x value read %x\n", __func__, |
360 | __func__, ctrl->cap_base + PCI_EXP_SLTCTL, slot_ctrl); | 360 | pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_ctrl); |
361 | 361 | ||
362 | pwr_state = (slot_ctrl & PCI_EXP_SLTCTL_PCC) >> 10; | 362 | pwr_state = (slot_ctrl & PCI_EXP_SLTCTL_PCC) >> 10; |
363 | 363 | ||
@@ -427,27 +427,24 @@ int pciehp_set_attention_status(struct slot *slot, u8 value) | |||
427 | struct controller *ctrl = slot->ctrl; | 427 | struct controller *ctrl = slot->ctrl; |
428 | u16 slot_cmd; | 428 | u16 slot_cmd; |
429 | u16 cmd_mask; | 429 | u16 cmd_mask; |
430 | int rc; | ||
431 | 430 | ||
432 | cmd_mask = PCI_EXP_SLTCTL_AIC; | 431 | cmd_mask = PCI_EXP_SLTCTL_AIC; |
433 | switch (value) { | 432 | switch (value) { |
434 | case 0 : /* turn off */ | 433 | case 0 : /* turn off */ |
435 | slot_cmd = 0x00C0; | 434 | slot_cmd = 0x00C0; |
436 | break; | 435 | break; |
437 | case 1: /* turn on */ | 436 | case 1: /* turn on */ |
438 | slot_cmd = 0x0040; | 437 | slot_cmd = 0x0040; |
439 | break; | 438 | break; |
440 | case 2: /* turn blink */ | 439 | case 2: /* turn blink */ |
441 | slot_cmd = 0x0080; | 440 | slot_cmd = 0x0080; |
442 | break; | 441 | break; |
443 | default: | 442 | default: |
444 | return -1; | 443 | return -EINVAL; |
445 | } | 444 | } |
446 | rc = pcie_write_cmd(ctrl, slot_cmd, cmd_mask); | 445 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, |
447 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", | 446 | pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_cmd); |
448 | __func__, ctrl->cap_base + PCI_EXP_SLTCTL, slot_cmd); | 447 | return pcie_write_cmd(ctrl, slot_cmd, cmd_mask); |
449 | |||
450 | return rc; | ||
451 | } | 448 | } |
452 | 449 | ||
453 | void pciehp_green_led_on(struct slot *slot) | 450 | void pciehp_green_led_on(struct slot *slot) |
@@ -459,8 +456,8 @@ void pciehp_green_led_on(struct slot *slot) | |||
459 | slot_cmd = 0x0100; | 456 | slot_cmd = 0x0100; |
460 | cmd_mask = PCI_EXP_SLTCTL_PIC; | 457 | cmd_mask = PCI_EXP_SLTCTL_PIC; |
461 | pcie_write_cmd(ctrl, slot_cmd, cmd_mask); | 458 | pcie_write_cmd(ctrl, slot_cmd, cmd_mask); |
462 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", | 459 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, |
463 | __func__, ctrl->cap_base + PCI_EXP_SLTCTL, slot_cmd); | 460 | pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_cmd); |
464 | } | 461 | } |
465 | 462 | ||
466 | void pciehp_green_led_off(struct slot *slot) | 463 | void pciehp_green_led_off(struct slot *slot) |
@@ -472,8 +469,8 @@ void pciehp_green_led_off(struct slot *slot) | |||
472 | slot_cmd = 0x0300; | 469 | slot_cmd = 0x0300; |
473 | cmd_mask = PCI_EXP_SLTCTL_PIC; | 470 | cmd_mask = PCI_EXP_SLTCTL_PIC; |
474 | pcie_write_cmd(ctrl, slot_cmd, cmd_mask); | 471 | pcie_write_cmd(ctrl, slot_cmd, cmd_mask); |
475 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", | 472 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, |
476 | __func__, ctrl->cap_base + PCI_EXP_SLTCTL, slot_cmd); | 473 | pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_cmd); |
477 | } | 474 | } |
478 | 475 | ||
479 | void pciehp_green_led_blink(struct slot *slot) | 476 | void pciehp_green_led_blink(struct slot *slot) |
@@ -485,8 +482,8 @@ void pciehp_green_led_blink(struct slot *slot) | |||
485 | slot_cmd = 0x0200; | 482 | slot_cmd = 0x0200; |
486 | cmd_mask = PCI_EXP_SLTCTL_PIC; | 483 | cmd_mask = PCI_EXP_SLTCTL_PIC; |
487 | pcie_write_cmd(ctrl, slot_cmd, cmd_mask); | 484 | pcie_write_cmd(ctrl, slot_cmd, cmd_mask); |
488 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", | 485 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, |
489 | __func__, ctrl->cap_base + PCI_EXP_SLTCTL, slot_cmd); | 486 | pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_cmd); |
490 | } | 487 | } |
491 | 488 | ||
492 | int pciehp_power_on_slot(struct slot * slot) | 489 | int pciehp_power_on_slot(struct slot * slot) |
@@ -514,97 +511,38 @@ int pciehp_power_on_slot(struct slot * slot) | |||
514 | return retval; | 511 | return retval; |
515 | } | 512 | } |
516 | } | 513 | } |
514 | ctrl->power_fault_detected = 0; | ||
517 | 515 | ||
518 | slot_cmd = POWER_ON; | 516 | slot_cmd = POWER_ON; |
519 | cmd_mask = PCI_EXP_SLTCTL_PCC; | 517 | cmd_mask = PCI_EXP_SLTCTL_PCC; |
520 | if (!pciehp_poll_mode) { | ||
521 | /* Enable power fault detection turned off at power off time */ | ||
522 | slot_cmd |= PCI_EXP_SLTCTL_PFDE; | ||
523 | cmd_mask |= PCI_EXP_SLTCTL_PFDE; | ||
524 | } | ||
525 | |||
526 | retval = pcie_write_cmd(ctrl, slot_cmd, cmd_mask); | 518 | retval = pcie_write_cmd(ctrl, slot_cmd, cmd_mask); |
527 | if (retval) { | 519 | if (retval) { |
528 | ctrl_err(ctrl, "Write %x command failed!\n", slot_cmd); | 520 | ctrl_err(ctrl, "Write %x command failed!\n", slot_cmd); |
529 | return retval; | 521 | return retval; |
530 | } | 522 | } |
531 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", | 523 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, |
532 | __func__, ctrl->cap_base + PCI_EXP_SLTCTL, slot_cmd); | 524 | pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_cmd); |
533 | 525 | ||
534 | ctrl->power_fault_detected = 0; | ||
535 | return retval; | 526 | return retval; |
536 | } | 527 | } |
537 | 528 | ||
538 | static inline int pcie_mask_bad_dllp(struct controller *ctrl) | ||
539 | { | ||
540 | struct pci_dev *dev = ctrl->pcie->port; | ||
541 | int pos; | ||
542 | u32 reg; | ||
543 | |||
544 | pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); | ||
545 | if (!pos) | ||
546 | return 0; | ||
547 | pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, ®); | ||
548 | if (reg & PCI_ERR_COR_BAD_DLLP) | ||
549 | return 0; | ||
550 | reg |= PCI_ERR_COR_BAD_DLLP; | ||
551 | pci_write_config_dword(dev, pos + PCI_ERR_COR_MASK, reg); | ||
552 | return 1; | ||
553 | } | ||
554 | |||
555 | static inline void pcie_unmask_bad_dllp(struct controller *ctrl) | ||
556 | { | ||
557 | struct pci_dev *dev = ctrl->pcie->port; | ||
558 | u32 reg; | ||
559 | int pos; | ||
560 | |||
561 | pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); | ||
562 | if (!pos) | ||
563 | return; | ||
564 | pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, ®); | ||
565 | if (!(reg & PCI_ERR_COR_BAD_DLLP)) | ||
566 | return; | ||
567 | reg &= ~PCI_ERR_COR_BAD_DLLP; | ||
568 | pci_write_config_dword(dev, pos + PCI_ERR_COR_MASK, reg); | ||
569 | } | ||
570 | |||
571 | int pciehp_power_off_slot(struct slot * slot) | 529 | int pciehp_power_off_slot(struct slot * slot) |
572 | { | 530 | { |
573 | struct controller *ctrl = slot->ctrl; | 531 | struct controller *ctrl = slot->ctrl; |
574 | u16 slot_cmd; | 532 | u16 slot_cmd; |
575 | u16 cmd_mask; | 533 | u16 cmd_mask; |
576 | int retval = 0; | 534 | int retval; |
577 | int changed; | ||
578 | |||
579 | /* | ||
580 | * Set Bad DLLP Mask bit in Correctable Error Mask | ||
581 | * Register. This is the workaround against Bad DLLP error | ||
582 | * that sometimes happens during turning power off the slot | ||
583 | * which conforms to PCI Express 1.0a spec. | ||
584 | */ | ||
585 | changed = pcie_mask_bad_dllp(ctrl); | ||
586 | 535 | ||
587 | slot_cmd = POWER_OFF; | 536 | slot_cmd = POWER_OFF; |
588 | cmd_mask = PCI_EXP_SLTCTL_PCC; | 537 | cmd_mask = PCI_EXP_SLTCTL_PCC; |
589 | if (!pciehp_poll_mode) { | ||
590 | /* Disable power fault detection */ | ||
591 | slot_cmd &= ~PCI_EXP_SLTCTL_PFDE; | ||
592 | cmd_mask |= PCI_EXP_SLTCTL_PFDE; | ||
593 | } | ||
594 | |||
595 | retval = pcie_write_cmd(ctrl, slot_cmd, cmd_mask); | 538 | retval = pcie_write_cmd(ctrl, slot_cmd, cmd_mask); |
596 | if (retval) { | 539 | if (retval) { |
597 | ctrl_err(ctrl, "Write command failed!\n"); | 540 | ctrl_err(ctrl, "Write command failed!\n"); |
598 | retval = -1; | 541 | return retval; |
599 | goto out; | ||
600 | } | 542 | } |
601 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", | 543 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, |
602 | __func__, ctrl->cap_base + PCI_EXP_SLTCTL, slot_cmd); | 544 | pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_cmd); |
603 | out: | 545 | return 0; |
604 | if (changed) | ||
605 | pcie_unmask_bad_dllp(ctrl); | ||
606 | |||
607 | return retval; | ||
608 | } | 546 | } |
609 | 547 | ||
610 | static irqreturn_t pcie_isr(int irq, void *dev_id) | 548 | static irqreturn_t pcie_isr(int irq, void *dev_id) |
@@ -840,11 +778,19 @@ int pcie_enable_notification(struct controller *ctrl) | |||
840 | { | 778 | { |
841 | u16 cmd, mask; | 779 | u16 cmd, mask; |
842 | 780 | ||
781 | /* | ||
782 | * TBD: Power fault detected software notification support. | ||
783 | * | ||
784 | * Power fault detected software notification is not enabled | ||
785 | * now, because it caused power fault detected interrupt storm | ||
786 | * on some machines. On those machines, power fault detected | ||
787 | * bit in the slot status register was set again immediately | ||
788 | * when it is cleared in the interrupt service routine, and | ||
789 | * next power fault detected interrupt was notified again. | ||
790 | */ | ||
843 | cmd = PCI_EXP_SLTCTL_PDCE; | 791 | cmd = PCI_EXP_SLTCTL_PDCE; |
844 | if (ATTN_BUTTN(ctrl)) | 792 | if (ATTN_BUTTN(ctrl)) |
845 | cmd |= PCI_EXP_SLTCTL_ABPE; | 793 | cmd |= PCI_EXP_SLTCTL_ABPE; |
846 | if (POWER_CTRL(ctrl)) | ||
847 | cmd |= PCI_EXP_SLTCTL_PFDE; | ||
848 | if (MRL_SENS(ctrl)) | 794 | if (MRL_SENS(ctrl)) |
849 | cmd |= PCI_EXP_SLTCTL_MRLSCE; | 795 | cmd |= PCI_EXP_SLTCTL_MRLSCE; |
850 | if (!pciehp_poll_mode) | 796 | if (!pciehp_poll_mode) |
@@ -866,7 +812,8 @@ static void pcie_disable_notification(struct controller *ctrl) | |||
866 | u16 mask; | 812 | u16 mask; |
867 | mask = (PCI_EXP_SLTCTL_PDCE | PCI_EXP_SLTCTL_ABPE | | 813 | mask = (PCI_EXP_SLTCTL_PDCE | PCI_EXP_SLTCTL_ABPE | |
868 | PCI_EXP_SLTCTL_MRLSCE | PCI_EXP_SLTCTL_PFDE | | 814 | PCI_EXP_SLTCTL_MRLSCE | PCI_EXP_SLTCTL_PFDE | |
869 | PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE); | 815 | PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE | |
816 | PCI_EXP_SLTCTL_DLLSCE); | ||
870 | if (pcie_write_cmd(ctrl, 0, mask)) | 817 | if (pcie_write_cmd(ctrl, 0, mask)) |
871 | ctrl_warn(ctrl, "Cannot disable software notification\n"); | 818 | ctrl_warn(ctrl, "Cannot disable software notification\n"); |
872 | } | 819 | } |
@@ -934,7 +881,8 @@ static inline void dbg_ctrl(struct controller *ctrl) | |||
934 | pdev->subsystem_device); | 881 | pdev->subsystem_device); |
935 | ctrl_info(ctrl, " Subsystem Vendor ID : 0x%04x\n", | 882 | ctrl_info(ctrl, " Subsystem Vendor ID : 0x%04x\n", |
936 | pdev->subsystem_vendor); | 883 | pdev->subsystem_vendor); |
937 | ctrl_info(ctrl, " PCIe Cap offset : 0x%02x\n", ctrl->cap_base); | 884 | ctrl_info(ctrl, " PCIe Cap offset : 0x%02x\n", |
885 | pci_pcie_cap(pdev)); | ||
938 | for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { | 886 | for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { |
939 | if (!pci_resource_len(pdev, i)) | 887 | if (!pci_resource_len(pdev, i)) |
940 | continue; | 888 | continue; |
@@ -978,8 +926,7 @@ struct controller *pcie_init(struct pcie_device *dev) | |||
978 | goto abort; | 926 | goto abort; |
979 | } | 927 | } |
980 | ctrl->pcie = dev; | 928 | ctrl->pcie = dev; |
981 | ctrl->cap_base = pci_find_capability(pdev, PCI_CAP_ID_EXP); | 929 | if (!pci_pcie_cap(pdev)) { |
982 | if (!ctrl->cap_base) { | ||
983 | ctrl_err(ctrl, "Cannot find PCI Express capability\n"); | 930 | ctrl_err(ctrl, "Cannot find PCI Express capability\n"); |
984 | goto abort_ctrl; | 931 | goto abort_ctrl; |
985 | } | 932 | } |