aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/hotplug/pciehp_hpc.c
diff options
context:
space:
mode:
authorKenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>2008-05-27 06:03:16 -0400
committerJesse Barnes <jbarnes@virtuousgeek.org>2008-05-27 18:43:08 -0400
commitdbd79aed1aea2bece0bf43cc2ff3b2f9baf48a08 (patch)
treedf47f2f54a1263ce55b0265237d2f7aaf9f34532 /drivers/pci/hotplug/pciehp_hpc.c
parentb3bd307c628af2f0a581c42d5d7e4bcdbbf64b6a (diff)
pciehp: fix NULL dereference in interrupt handler
Fix the following NULL dereference problem reported from Pierre Ossman and Ingo Molnar. pciehp: HPC vendor_id 8086 device_id 27d0 ss_vid 0 ss_did 0 pciehp: pciehp_find_slot: slot (device=0x0) not found BUG: unable to handle kernel NULL pointer dereference at 0000000000000070 IP: [<ffffffff80494a8b>] pciehp_handle_presence_change+0x7e/0x113 PGD 0 Oops: 0000 [1] CPU 0 Modules linked in: Pid: 1, comm: swapper Tainted: G W 2.6.26-rc3-sched-devel.git-00001-g2b99b26-dirty #170 RIP: 0010:[<ffffffff80494a8b>] [<ffffffff80494a8b>] pciehp_handle_presence_change+0x7e/0x113 RSP: 0000:ffff81003f83fbb0 EFLAGS: 00010046 RAX: 0000000000000039 RBX: 0000000000000000 RCX: 0000000000000000 RDX: 0000000000000000 RSI: 0000000000000001 RDI: 0000000000000046 RBP: ffff81003f83fbd0 R08: 0000000000000001 R09: ffffffff80245103 R10: 0000000000000020 R11: 0000000000000000 R12: ffff81003ea53a30 R13: 0000000000000000 R14: 0000000000000011 R15: ffffffff80495926 FS: 0000000000000000(0000) GS:ffffffff80be7400(0000) knlGS:0000000000000000 CS: 0010 DS: 0018 ES: 0018 CR0: 000000008005003b CR2: 0000000000000070 CR3: 0000000000201000 CR4: 00000000000006a0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Process swapper (pid: 1, threadinfo ffff81003f83e000, task ffff81003f840000) Stack: 0000000000000008 ffff81003f83fbf6 ffff81003ea53a30 0000000000000008 ffff81003f83fc10 ffffffff80495ab4 0000000000000011 0000000000000002 0000000000000202 0000000000000202 00000000fffffff4 ffff81003ea53a30 Call Trace: [<ffffffff80495ab4>] pcie_isr+0x18e/0x1bc [<ffffffff80260831>] request_irq+0x106/0x12f [<ffffffff80495fb6>] pcie_init+0x15e/0x6cc [<ffffffff804933a3>] pciehp_probe+0x64/0x541 [<ffffffff8048f4e7>] pcie_port_probe_service+0x4c/0x76 [<ffffffff8054af70>] driver_probe_device+0xd4/0x1f0 [<ffffffff8054b108>] __driver_attach+0x7c/0x7e [<ffffffff8054b08c>] ? __driver_attach+0x0/0x7e [<ffffffff8054a4b6>] bus_for_each_dev+0x53/0x7d [<ffffffff8054ad3c>] driver_attach+0x1c/0x1e [<ffffffff8054a9c2>] bus_add_driver+0xdd/0x25b [<ffffffff80c09d3d>] ? pcied_init+0x0/0x8b [<ffffffff8054b288>] driver_register+0x5f/0x13e [<ffffffff80c09d3d>] ? pcied_init+0x0/0x8b [<ffffffff8048f441>] pcie_port_service_register+0x47/0x49 [<ffffffff80c09d52>] pcied_init+0x15/0x8b [<ffffffff80bf3938>] kernel_init+0x75/0x243 [<ffffffff808639d2>] ? _spin_unlock_irq+0x2b/0x3a [<ffffffff80228d1f>] ? finish_task_switch+0x57/0x9a [<ffffffff8020c258>] child_rip+0xa/0x12 [<ffffffff8020bcec>] ? restore_args+0x0/0x30 [<ffffffff80bf38c3>] ? kernel_init+0x0/0x243 [<ffffffff8020c24e>] ? child_rip+0x0/0x12 Code: 83 80 00 00 00 48 39 f0 75 e1 0f b6 c9 48 c7 c2 00 0e 8d 80 48 c7 c6 8a 60 a6 80 48 c7 c7 10 db a8 80 31 c0 e8 3f 8d d9 ff 31 db <48> 8b 43 70 48 8d 75 ef 48 89 df ff 50 30 80 7d ef 00 74 37 48 RIP [<ffffffff80494a8b>] pciehp_handle_presence_change+0x7e/0x113 RSP <ffff81003f83fbb0> CR2: 0000000000000070 Kernel panic - not syncing: Fatal exception The situation under which it occurs is hw and timing related: it appears to happen on a system that has PCI hotplug hardware but with no active hotplug cards, and another interrupt in the same (shared) IRQ line arrives too early, before the hotplug-slot entry has been set up - as triggered by CONFIG_DEBUG_SHIRQ=y: This patch contains the following two fixes. (1) Clear all events bits in Slot Status register to prevent the pciehp driver from detecting the spurious events that would have been occur before pciehp loading. (2) Add check whether slot initialization had been already done. This is short term fix. We need more structural fixes to install interrupt handler after slot initialization is done. Signed-off-by: Ingo Molnar <mingo@elte.hu> 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/hotplug/pciehp_hpc.c')
-rw-r--r--drivers/pci/hotplug/pciehp_hpc.c42
1 files changed, 28 insertions, 14 deletions
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
index 891f81a0400c..425a0f609977 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -722,6 +722,7 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
722{ 722{
723 struct controller *ctrl = (struct controller *)dev_id; 723 struct controller *ctrl = (struct controller *)dev_id;
724 u16 detected, intr_loc; 724 u16 detected, intr_loc;
725 struct slot *p_slot;
725 726
726 /* 727 /*
727 * In order to guarantee that all interrupt events are 728 * In order to guarantee that all interrupt events are
@@ -756,21 +757,38 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
756 wake_up_interruptible(&ctrl->queue); 757 wake_up_interruptible(&ctrl->queue);
757 } 758 }
758 759
760 if (!(intr_loc & ~CMD_COMPLETED))
761 return IRQ_HANDLED;
762
763 /*
764 * Return without handling events if this handler routine is
765 * called before controller initialization is done. This may
766 * happen if hotplug event or another interrupt that shares
767 * the IRQ with pciehp arrives before slot initialization is
768 * done after interrupt handler is registered.
769 *
770 * FIXME - Need more structural fixes. We need to be ready to
771 * handle the event before installing interrupt handler.
772 */
773 p_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset);
774 if (!p_slot || !p_slot->hpc_ops)
775 return IRQ_HANDLED;
776
759 /* Check MRL Sensor Changed */ 777 /* Check MRL Sensor Changed */
760 if (intr_loc & MRL_SENS_CHANGED) 778 if (intr_loc & MRL_SENS_CHANGED)
761 pciehp_handle_switch_change(0, ctrl); 779 pciehp_handle_switch_change(p_slot);
762 780
763 /* Check Attention Button Pressed */ 781 /* Check Attention Button Pressed */
764 if (intr_loc & ATTN_BUTTN_PRESSED) 782 if (intr_loc & ATTN_BUTTN_PRESSED)
765 pciehp_handle_attention_button(0, ctrl); 783 pciehp_handle_attention_button(p_slot);
766 784
767 /* Check Presence Detect Changed */ 785 /* Check Presence Detect Changed */
768 if (intr_loc & PRSN_DETECT_CHANGED) 786 if (intr_loc & PRSN_DETECT_CHANGED)
769 pciehp_handle_presence_change(0, ctrl); 787 pciehp_handle_presence_change(p_slot);
770 788
771 /* Check Power Fault Detected */ 789 /* Check Power Fault Detected */
772 if (intr_loc & PWR_FAULT_DETECTED) 790 if (intr_loc & PWR_FAULT_DETECTED)
773 pciehp_handle_power_fault(0, ctrl); 791 pciehp_handle_power_fault(p_slot);
774 792
775 return IRQ_HANDLED; 793 return IRQ_HANDLED;
776} 794}
@@ -1028,6 +1046,12 @@ static int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev)
1028static int pcie_init_hardware_part1(struct controller *ctrl, 1046static int pcie_init_hardware_part1(struct controller *ctrl,
1029 struct pcie_device *dev) 1047 struct pcie_device *dev)
1030{ 1048{
1049 /* Clear all remaining event bits in Slot Status register */
1050 if (pciehp_writew(ctrl, SLOTSTATUS, 0x1f)) {
1051 err("%s: Cannot write to SLOTSTATUS register\n", __func__);
1052 return -1;
1053 }
1054
1031 /* Mask Hot-plug Interrupt Enable */ 1055 /* Mask Hot-plug Interrupt Enable */
1032 if (pcie_write_cmd(ctrl, 0, HP_INTR_ENABLE | CMD_CMPL_INTR_ENABLE)) { 1056 if (pcie_write_cmd(ctrl, 0, HP_INTR_ENABLE | CMD_CMPL_INTR_ENABLE)) {
1033 err("%s: Cannot mask hotplug interrupt enable\n", __func__); 1057 err("%s: Cannot mask hotplug interrupt enable\n", __func__);
@@ -1040,16 +1064,6 @@ int pcie_init_hardware_part2(struct controller *ctrl, struct pcie_device *dev)
1040{ 1064{
1041 u16 cmd, mask; 1065 u16 cmd, mask;
1042 1066
1043 /*
1044 * We need to clear all events before enabling hotplug interrupt
1045 * notification mechanism in order for hotplug controler to
1046 * generate interrupts.
1047 */
1048 if (pciehp_writew(ctrl, SLOTSTATUS, 0x1f)) {
1049 err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__);
1050 return -1;
1051 }
1052
1053 cmd = PRSN_DETECT_ENABLE; 1067 cmd = PRSN_DETECT_ENABLE;
1054 if (ATTN_BUTTN(ctrl)) 1068 if (ATTN_BUTTN(ctrl))
1055 cmd |= ATTN_BUTTN_ENABLE; 1069 cmd |= ATTN_BUTTN_ENABLE;