diff options
author | Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com> | 2009-02-03 01:06:16 -0500 |
---|---|---|
committer | Jesse Barnes <jbarnes@hobbes.lan> | 2009-03-19 22:29:29 -0400 |
commit | 99f0169c17f334a11b0ace91188501c612f3e1e6 (patch) | |
tree | 1dab8a0f010f62611945063abcd6f988dca7bf3e /drivers/pci | |
parent | 81b840cd27e3ee9af67b6e05a4847868f74fce69 (diff) |
PCI: pciehp: enable software notification on empty slots
Current pciehp disables software notification of adapter presence
changed event and MRL changed event when slot is turned off. Because
of this, there is no way to detect those events on empty slots in the
current pciehp implementation.
According to the past discussion(*), this behavior was introduced to
prevent endless loop that could happen if pcie_isr() runs after power
fault is detected on a certain platform whose stickey power-fault bit
remains on till the slot is powered on again.
(*) http://sourceforge.net/mailarchive/message.php?msg_id=20051130135409.A14918%40unix-os.sc.intel.com
I think this endless loop can be avoided using one bit flag that
indicates power fault had been detected, instead of disabling software
notification of adapter present changed event and MRL changed event.
With this patch, we can enable software notification mechanism of
presence changed and MRL changed event on the empty slots again.
Signed-off-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/hotplug/pciehp.h | 1 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehp_hpc.c | 31 |
2 files changed, 12 insertions, 20 deletions
diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index 1f887f64e493..2bf8d28062e8 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h | |||
@@ -112,6 +112,7 @@ struct controller { | |||
112 | unsigned int no_cmd_complete:1; | 112 | unsigned int no_cmd_complete:1; |
113 | unsigned int link_active_reporting:1; | 113 | unsigned int link_active_reporting:1; |
114 | unsigned int notification_enabled:1; | 114 | unsigned int notification_enabled:1; |
115 | unsigned int power_fault_detected; | ||
115 | }; | 116 | }; |
116 | 117 | ||
117 | #define INT_BUTTON_IGNORE 0 | 118 | #define INT_BUTTON_IGNORE 0 |
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index c1a312f24060..07bd32151146 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c | |||
@@ -548,23 +548,21 @@ static int hpc_power_on_slot(struct slot * slot) | |||
548 | 548 | ||
549 | slot_cmd = POWER_ON; | 549 | slot_cmd = POWER_ON; |
550 | cmd_mask = PCI_EXP_SLTCTL_PCC; | 550 | cmd_mask = PCI_EXP_SLTCTL_PCC; |
551 | /* Enable detection that we turned off at slot power-off time */ | ||
552 | if (!pciehp_poll_mode) { | 551 | if (!pciehp_poll_mode) { |
553 | slot_cmd |= (PCI_EXP_SLTCTL_PFDE | PCI_EXP_SLTCTL_MRLSCE | | 552 | /* Enable power fault detection turned off at power off time */ |
554 | PCI_EXP_SLTCTL_PDCE); | 553 | slot_cmd |= PCI_EXP_SLTCTL_PFDE; |
555 | cmd_mask |= (PCI_EXP_SLTCTL_PFDE | PCI_EXP_SLTCTL_MRLSCE | | 554 | cmd_mask |= PCI_EXP_SLTCTL_PFDE; |
556 | PCI_EXP_SLTCTL_PDCE); | ||
557 | } | 555 | } |
558 | 556 | ||
559 | retval = pcie_write_cmd(ctrl, slot_cmd, cmd_mask); | 557 | retval = pcie_write_cmd(ctrl, slot_cmd, cmd_mask); |
560 | |||
561 | if (retval) { | 558 | if (retval) { |
562 | ctrl_err(ctrl, "Write %x command failed!\n", slot_cmd); | 559 | ctrl_err(ctrl, "Write %x command failed!\n", slot_cmd); |
563 | return -1; | 560 | return retval; |
564 | } | 561 | } |
565 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", | 562 | ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", |
566 | __func__, ctrl->cap_base + PCI_EXP_SLTCTL, slot_cmd); | 563 | __func__, ctrl->cap_base + PCI_EXP_SLTCTL, slot_cmd); |
567 | 564 | ||
565 | ctrl->power_fault_detected = 0; | ||
568 | return retval; | 566 | return retval; |
569 | } | 567 | } |
570 | 568 | ||
@@ -621,18 +619,10 @@ static int hpc_power_off_slot(struct slot * slot) | |||
621 | 619 | ||
622 | slot_cmd = POWER_OFF; | 620 | slot_cmd = POWER_OFF; |
623 | cmd_mask = PCI_EXP_SLTCTL_PCC; | 621 | cmd_mask = PCI_EXP_SLTCTL_PCC; |
624 | /* | ||
625 | * If we get MRL or presence detect interrupts now, the isr | ||
626 | * will notice the sticky power-fault bit too and issue power | ||
627 | * indicator change commands. This will lead to an endless loop | ||
628 | * of command completions, since the power-fault bit remains on | ||
629 | * till the slot is powered on again. | ||
630 | */ | ||
631 | if (!pciehp_poll_mode) { | 622 | if (!pciehp_poll_mode) { |
632 | slot_cmd &= ~(PCI_EXP_SLTCTL_PFDE | PCI_EXP_SLTCTL_MRLSCE | | 623 | /* Disable power fault detection */ |
633 | PCI_EXP_SLTCTL_PDCE); | 624 | slot_cmd &= ~PCI_EXP_SLTCTL_PFDE; |
634 | cmd_mask |= (PCI_EXP_SLTCTL_PFDE | PCI_EXP_SLTCTL_MRLSCE | | 625 | cmd_mask |= PCI_EXP_SLTCTL_PFDE; |
635 | PCI_EXP_SLTCTL_PDCE); | ||
636 | } | 626 | } |
637 | 627 | ||
638 | retval = pcie_write_cmd(ctrl, slot_cmd, cmd_mask); | 628 | retval = pcie_write_cmd(ctrl, slot_cmd, cmd_mask); |
@@ -710,9 +700,10 @@ static irqreturn_t pcie_isr(int irq, void *dev_id) | |||
710 | pciehp_handle_presence_change(p_slot); | 700 | pciehp_handle_presence_change(p_slot); |
711 | 701 | ||
712 | /* Check Power Fault Detected */ | 702 | /* Check Power Fault Detected */ |
713 | if (intr_loc & PCI_EXP_SLTSTA_PFD) | 703 | if ((intr_loc & PCI_EXP_SLTSTA_PFD) && !ctrl->power_fault_detected) { |
704 | ctrl->power_fault_detected = 1; | ||
714 | pciehp_handle_power_fault(p_slot); | 705 | pciehp_handle_power_fault(p_slot); |
715 | 706 | } | |
716 | return IRQ_HANDLED; | 707 | return IRQ_HANDLED; |
717 | } | 708 | } |
718 | 709 | ||