aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci
diff options
context:
space:
mode:
authorKenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>2008-04-25 17:38:57 -0400
committerJesse Barnes <jbarnes@virtuousgeek.org>2008-04-25 17:38:57 -0400
commitc6b069e94601aea8887afbbd922afe20a3580a7d (patch)
tree09c1323f36040f039d3b260e794bcc3c4e16d4f1 /drivers/pci
parent3800345f723fd130d50434d4717b99d4a9f383c8 (diff)
pciehp: Fix interrupt event handlig
Current pciehp implementation disables and re-enables hotplug interrupts in its interrupt handler. This operation might be intend to guarantee that interrupts for the events newly occured during previous events are being handled will be successfully generated. But current implementaion has the following prolems. - Current interrupt service routin clears status changes without waiting command completion. Because of this, events might not be cleared properly. - Current interrupt service routine clears status changes caused by disabling or enabling hotplug interrupts itself. This will lose new events that occurs during previous interrupts are being handled. - Current implementation doesn't have any serialization mechanism between the code to wait for command completion and the interrupt handler that clears the command completion events caused by itself. There is clearly race conditions between them, and it may cause the problem that waiting for command completion doesn't work for example. To fix those problems, this patch stops disabling/re-enabling hotplug interrupts in interrupt service routine. Instead of this, this patch re-inspects Slot Status register after clearing what is presumed to be the last bending interrupt in order to guarantee that all interrupt events are serviced. Signed-off-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com> Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/hotplug/pciehp.h1
-rw-r--r--drivers/pci/hotplug/pciehp_hpc.c148
2 files changed, 29 insertions, 120 deletions
diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h
index f14267e197dd..9dd132925ffa 100644
--- a/drivers/pci/hotplug/pciehp.h
+++ b/drivers/pci/hotplug/pciehp.h
@@ -97,7 +97,6 @@ struct controller {
97 u8 cap_base; 97 u8 cap_base;
98 struct timer_list poll_timer; 98 struct timer_list poll_timer;
99 volatile int cmd_busy; 99 volatile int cmd_busy;
100 spinlock_t lock;
101}; 100};
102 101
103#define INT_BUTTON_IGNORE 0 102#define INT_BUTTON_IGNORE 0
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
index b4bbd07d1e39..51a5055f6965 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -252,7 +252,6 @@ static int pcie_write_cmd(struct slot *slot, u16 cmd, u16 mask)
252 int retval = 0; 252 int retval = 0;
253 u16 slot_status; 253 u16 slot_status;
254 u16 slot_ctrl; 254 u16 slot_ctrl;
255 unsigned long flags;
256 255
257 mutex_lock(&ctrl->ctrl_lock); 256 mutex_lock(&ctrl->ctrl_lock);
258 257
@@ -270,11 +269,10 @@ static int pcie_write_cmd(struct slot *slot, u16 cmd, u16 mask)
270 __func__); 269 __func__);
271 } 270 }
272 271
273 spin_lock_irqsave(&ctrl->lock, flags);
274 retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); 272 retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
275 if (retval) { 273 if (retval) {
276 err("%s: Cannot read SLOTCTRL register\n", __func__); 274 err("%s: Cannot read SLOTCTRL register\n", __func__);
277 goto out_spin_unlock; 275 goto out;
278 } 276 }
279 277
280 slot_ctrl &= ~mask; 278 slot_ctrl &= ~mask;
@@ -285,9 +283,6 @@ static int pcie_write_cmd(struct slot *slot, u16 cmd, u16 mask)
285 if (retval) 283 if (retval)
286 err("%s: Cannot write to SLOTCTRL register\n", __func__); 284 err("%s: Cannot write to SLOTCTRL register\n", __func__);
287 285
288 out_spin_unlock:
289 spin_unlock_irqrestore(&ctrl->lock, flags);
290
291 /* 286 /*
292 * Wait for command completion. 287 * Wait for command completion.
293 */ 288 */
@@ -733,139 +728,55 @@ static int hpc_power_off_slot(struct slot * slot)
733static irqreturn_t pcie_isr(int irq, void *dev_id) 728static irqreturn_t pcie_isr(int irq, void *dev_id)
734{ 729{
735 struct controller *ctrl = (struct controller *)dev_id; 730 struct controller *ctrl = (struct controller *)dev_id;
736 u16 slot_status, intr_detect, intr_loc; 731 u16 detected, intr_loc;
737 u16 temp_word;
738 int hp_slot = 0; /* only 1 slot per PCI Express port */
739 int rc = 0;
740 unsigned long flags;
741
742 rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
743 if (rc) {
744 err("%s: Cannot read SLOTSTATUS register\n", __func__);
745 return IRQ_NONE;
746 }
747 732
748 intr_detect = (ATTN_BUTTN_PRESSED | PWR_FAULT_DETECTED | 733 /*
749 MRL_SENS_CHANGED | PRSN_DETECT_CHANGED | CMD_COMPLETED); 734 * In order to guarantee that all interrupt events are
750 735 * serviced, we need to re-inspect Slot Status register after
751 intr_loc = slot_status & intr_detect; 736 * clearing what is presumed to be the last pending interrupt.
752 737 */
753 /* Check to see if it was our interrupt */ 738 intr_loc = 0;
754 if ( !intr_loc ) 739 do {
755 return IRQ_NONE; 740 if (pciehp_readw(ctrl, SLOTSTATUS, &detected)) {
756 741 err("%s: Cannot read SLOTSTATUS\n", __func__);
757 dbg("%s: intr_loc %x\n", __func__, intr_loc);
758 /* Mask Hot-plug Interrupt Enable */
759 if (!pciehp_poll_mode) {
760 spin_lock_irqsave(&ctrl->lock, flags);
761 rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
762 if (rc) {
763 err("%s: Cannot read SLOT_CTRL register\n",
764 __func__);
765 spin_unlock_irqrestore(&ctrl->lock, flags);
766 return IRQ_NONE; 742 return IRQ_NONE;
767 } 743 }
768 744
769 dbg("%s: pciehp_readw(SLOTCTRL) with value %x\n", 745 detected &= (ATTN_BUTTN_PRESSED | PWR_FAULT_DETECTED |
770 __func__, temp_word); 746 MRL_SENS_CHANGED | PRSN_DETECT_CHANGED |
771 temp_word = (temp_word & ~HP_INTR_ENABLE & 747 CMD_COMPLETED);
772 ~CMD_CMPL_INTR_ENABLE) | 0x00; 748 intr_loc |= detected;
773 rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); 749 if (!intr_loc)
774 if (rc) {
775 err("%s: Cannot write to SLOTCTRL register\n",
776 __func__);
777 spin_unlock_irqrestore(&ctrl->lock, flags);
778 return IRQ_NONE; 750 return IRQ_NONE;
779 } 751 if (pciehp_writew(ctrl, SLOTSTATUS, detected)) {
780 spin_unlock_irqrestore(&ctrl->lock, flags); 752 err("%s: Cannot write to SLOTSTATUS\n", __func__);
781
782 rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
783 if (rc) {
784 err("%s: Cannot read SLOT_STATUS register\n",
785 __func__);
786 return IRQ_NONE; 753 return IRQ_NONE;
787 } 754 }
788 dbg("%s: pciehp_readw(SLOTSTATUS) with value %x\n", 755 } while (detected);
789 __func__, slot_status);
790 756
791 /* Clear command complete interrupt caused by this write */ 757 dbg("%s: intr_loc %x\n", __FUNCTION__, intr_loc);
792 temp_word = 0x1f;
793 rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
794 if (rc) {
795 err("%s: Cannot write to SLOTSTATUS register\n",
796 __func__);
797 return IRQ_NONE;
798 }
799 }
800 758
759 /* Check Command Complete Interrupt Pending */
801 if (intr_loc & CMD_COMPLETED) { 760 if (intr_loc & CMD_COMPLETED) {
802 /*
803 * Command Complete Interrupt Pending
804 */
805 ctrl->cmd_busy = 0; 761 ctrl->cmd_busy = 0;
806 wake_up_interruptible(&ctrl->queue); 762 wake_up_interruptible(&ctrl->queue);
807 } 763 }
808 764
765 /* Check MRL Sensor Changed */
809 if (intr_loc & MRL_SENS_CHANGED) 766 if (intr_loc & MRL_SENS_CHANGED)
810 pciehp_handle_switch_change(hp_slot, ctrl); 767 pciehp_handle_switch_change(0, ctrl);
811 768
769 /* Check Attention Button Pressed */
812 if (intr_loc & ATTN_BUTTN_PRESSED) 770 if (intr_loc & ATTN_BUTTN_PRESSED)
813 pciehp_handle_attention_button(hp_slot, ctrl); 771 pciehp_handle_attention_button(0, ctrl);
814 772
773 /* Check Presence Detect Changed */
815 if (intr_loc & PRSN_DETECT_CHANGED) 774 if (intr_loc & PRSN_DETECT_CHANGED)
816 pciehp_handle_presence_change(hp_slot, ctrl); 775 pciehp_handle_presence_change(0, ctrl);
817 776
777 /* Check Power Fault Detected */
818 if (intr_loc & PWR_FAULT_DETECTED) 778 if (intr_loc & PWR_FAULT_DETECTED)
819 pciehp_handle_power_fault(hp_slot, ctrl); 779 pciehp_handle_power_fault(0, ctrl);
820
821 /* Clear all events after serving them */
822 temp_word = 0x1F;
823 rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
824 if (rc) {
825 err("%s: Cannot write to SLOTSTATUS register\n", __func__);
826 return IRQ_NONE;
827 }
828 /* Unmask Hot-plug Interrupt Enable */
829 if (!pciehp_poll_mode) {
830 spin_lock_irqsave(&ctrl->lock, flags);
831 rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
832 if (rc) {
833 err("%s: Cannot read SLOTCTRL register\n",
834 __func__);
835 spin_unlock_irqrestore(&ctrl->lock, flags);
836 return IRQ_NONE;
837 }
838
839 dbg("%s: Unmask Hot-plug Interrupt Enable\n", __func__);
840 temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE;
841
842 rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
843 if (rc) {
844 err("%s: Cannot write to SLOTCTRL register\n",
845 __func__);
846 spin_unlock_irqrestore(&ctrl->lock, flags);
847 return IRQ_NONE;
848 }
849 spin_unlock_irqrestore(&ctrl->lock, flags);
850
851 rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
852 if (rc) {
853 err("%s: Cannot read SLOT_STATUS register\n",
854 __func__);
855 return IRQ_NONE;
856 }
857
858 /* Clear command complete interrupt caused by this write */
859 temp_word = 0x1F;
860 rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
861 if (rc) {
862 err("%s: Cannot write to SLOTSTATUS failed\n",
863 __func__);
864 return IRQ_NONE;
865 }
866 dbg("%s: pciehp_writew(SLOTSTATUS) with value %x\n",
867 __func__, temp_word);
868 }
869 780
870 return IRQ_HANDLED; 781 return IRQ_HANDLED;
871} 782}
@@ -1334,7 +1245,6 @@ int pcie_init(struct controller *ctrl, struct pcie_device *dev)
1334 1245
1335 mutex_init(&ctrl->crit_sect); 1246 mutex_init(&ctrl->crit_sect);
1336 mutex_init(&ctrl->ctrl_lock); 1247 mutex_init(&ctrl->ctrl_lock);
1337 spin_lock_init(&ctrl->lock);
1338 1248
1339 /* setup wait queue */ 1249 /* setup wait queue */
1340 init_waitqueue_head(&ctrl->queue); 1250 init_waitqueue_head(&ctrl->queue);