aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/hotplug/pciehp_hpc.c
diff options
context:
space:
mode:
authorKenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>2008-06-19 23:07:08 -0400
committerJesse Barnes <jbarnes@virtuousgeek.org>2008-06-27 16:00:43 -0400
commitc4635eb06af700820d658a163f06aff12e17cfb2 (patch)
tree97bae8af21e7dc26374de8d9ed45e9f112b7de5a /drivers/pci/hotplug/pciehp_hpc.c
parente4ec7a00ed30429030112e5591cf3138645727c2 (diff)
pciehp: fix interrupt initialization
Current pciehp driver's intialization sequence is as follows: (1) initialize controller data structure (2) install interrupt handler (3) enable software notification (4) initialize controller specific slot data structure (5) initialize generic slot data structure and register it to pci hotplug core The interrupt handler of pciehp assumes that controller specific slot data structure is already initialized. However, it is installed at (2) before initializing controller specific slot data structure at (4). Because of this, pciehp driver cannot handle the following cases properly. - If devices that shares IRQ with pciehp raise interrupts between (2) and (4). - If hotplug events (e.g. MRL open) happen between (3) and (4). We already have a workaround for this problem ("pciehp: fix NULL dereference in interrupt handler: dbd79aed1aea2bece0bf43cc2ff3b2f9baf48a08). But we still need fundamental fix. This patch fix the problem by changing the initilization sequence as follows: (1) initialize controller data structure (2) initialize controller specific slot data structure (3) install interrupt handler (4) enable software notification (5) initialize generic slot data structure and register it to pci hotplug core Signed-off-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com> Acked-by: Alex Chiang <achiang@hp.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.c179
1 files changed, 113 insertions, 66 deletions
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
index 59c28093d291..1ce52437e1ed 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -609,23 +609,6 @@ static void hpc_set_green_led_blink(struct slot *slot)
609 __func__, ctrl->cap_base + SLOTCTRL, slot_cmd); 609 __func__, ctrl->cap_base + SLOTCTRL, slot_cmd);
610} 610}
611 611
612static void hpc_release_ctlr(struct controller *ctrl)
613{
614 /* Mask Hot-plug Interrupt Enable */
615 if (pcie_write_cmd(ctrl, 0, HP_INTR_ENABLE | CMD_CMPL_INTR_ENABLE))
616 err("%s: Cannot mask hotplug interrupt enable\n", __func__);
617
618 /* Free interrupt handler or interrupt polling timer */
619 pciehp_free_irq(ctrl);
620
621 /*
622 * If this is the last controller to be released, destroy the
623 * pciehp work queue
624 */
625 if (atomic_dec_and_test(&pciehp_num_controllers))
626 destroy_workqueue(pciehp_wq);
627}
628
629static int hpc_power_on_slot(struct slot * slot) 612static int hpc_power_on_slot(struct slot * slot)
630{ 613{
631 struct controller *ctrl = slot->ctrl; 614 struct controller *ctrl = slot->ctrl;
@@ -798,19 +781,7 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
798 if (!(intr_loc & ~CMD_COMPLETED)) 781 if (!(intr_loc & ~CMD_COMPLETED))
799 return IRQ_HANDLED; 782 return IRQ_HANDLED;
800 783
801 /*
802 * Return without handling events if this handler routine is
803 * called before controller initialization is done. This may
804 * happen if hotplug event or another interrupt that shares
805 * the IRQ with pciehp arrives before slot initialization is
806 * done after interrupt handler is registered.
807 *
808 * FIXME - Need more structural fixes. We need to be ready to
809 * handle the event before installing interrupt handler.
810 */
811 p_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset); 784 p_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset);
812 if (!p_slot || !p_slot->hpc_ops)
813 return IRQ_HANDLED;
814 785
815 /* Check MRL Sensor Changed */ 786 /* Check MRL Sensor Changed */
816 if (intr_loc & MRL_SENS_CHANGED) 787 if (intr_loc & MRL_SENS_CHANGED)
@@ -987,6 +958,7 @@ static int hpc_get_cur_lnk_width(struct slot *slot,
987 return retval; 958 return retval;
988} 959}
989 960
961static void pcie_release_ctrl(struct controller *ctrl);
990static struct hpc_ops pciehp_hpc_ops = { 962static struct hpc_ops pciehp_hpc_ops = {
991 .power_on_slot = hpc_power_on_slot, 963 .power_on_slot = hpc_power_on_slot,
992 .power_off_slot = hpc_power_off_slot, 964 .power_off_slot = hpc_power_off_slot,
@@ -1008,28 +980,11 @@ static struct hpc_ops pciehp_hpc_ops = {
1008 .green_led_off = hpc_set_green_led_off, 980 .green_led_off = hpc_set_green_led_off,
1009 .green_led_blink = hpc_set_green_led_blink, 981 .green_led_blink = hpc_set_green_led_blink,
1010 982
1011 .release_ctlr = hpc_release_ctlr, 983 .release_ctlr = pcie_release_ctrl,
1012 .check_lnk_status = hpc_check_lnk_status, 984 .check_lnk_status = hpc_check_lnk_status,
1013}; 985};
1014 986
1015static int pcie_init_hardware_part1(struct controller *ctrl, 987int pcie_enable_notification(struct controller *ctrl)
1016 struct pcie_device *dev)
1017{
1018 /* Clear all remaining event bits in Slot Status register */
1019 if (pciehp_writew(ctrl, SLOTSTATUS, 0x1f)) {
1020 err("%s: Cannot write to SLOTSTATUS register\n", __func__);
1021 return -1;
1022 }
1023
1024 /* Mask Hot-plug Interrupt Enable */
1025 if (pcie_write_cmd(ctrl, 0, HP_INTR_ENABLE | CMD_CMPL_INTR_ENABLE)) {
1026 err("%s: Cannot mask hotplug interrupt enable\n", __func__);
1027 return -1;
1028 }
1029 return 0;
1030}
1031
1032int pcie_init_hardware_part2(struct controller *ctrl, struct pcie_device *dev)
1033{ 988{
1034 u16 cmd, mask; 989 u16 cmd, mask;
1035 990
@@ -1050,10 +1005,76 @@ int pcie_init_hardware_part2(struct controller *ctrl, struct pcie_device *dev)
1050 err("%s: Cannot enable software notification\n", __func__); 1005 err("%s: Cannot enable software notification\n", __func__);
1051 return -1; 1006 return -1;
1052 } 1007 }
1008 return 0;
1009}
1010
1011static void pcie_disable_notification(struct controller *ctrl)
1012{
1013 u16 mask;
1014 mask = PRSN_DETECT_ENABLE | ATTN_BUTTN_ENABLE | MRL_DETECT_ENABLE |
1015 PWR_FAULT_DETECT_ENABLE | HP_INTR_ENABLE | CMD_CMPL_INTR_ENABLE;
1016 if (pcie_write_cmd(ctrl, 0, mask))
1017 warn("%s: Cannot disable software notification\n", __func__);
1018}
1019
1020static int pcie_init_notification(struct controller *ctrl)
1021{
1022 if (pciehp_request_irq(ctrl))
1023 return -1;
1024 if (pcie_enable_notification(ctrl)) {
1025 pciehp_free_irq(ctrl);
1026 return -1;
1027 }
1028 return 0;
1029}
1030
1031static void pcie_shutdown_notification(struct controller *ctrl)
1032{
1033 pcie_disable_notification(ctrl);
1034 pciehp_free_irq(ctrl);
1035}
1036
1037static void make_slot_name(struct slot *slot)
1038{
1039 if (pciehp_slot_with_bus)
1040 snprintf(slot->name, SLOT_NAME_SIZE, "%04d_%04d",
1041 slot->bus, slot->number);
1042 else
1043 snprintf(slot->name, SLOT_NAME_SIZE, "%d", slot->number);
1044}
1053 1045
1046static int pcie_init_slot(struct controller *ctrl)
1047{
1048 struct slot *slot;
1049
1050 slot = kzalloc(sizeof(*slot), GFP_KERNEL);
1051 if (!slot)
1052 return -ENOMEM;
1053
1054 slot->hp_slot = 0;
1055 slot->ctrl = ctrl;
1056 slot->bus = ctrl->pci_dev->subordinate->number;
1057 slot->device = ctrl->slot_device_offset + slot->hp_slot;
1058 slot->hpc_ops = ctrl->hpc_ops;
1059 slot->number = ctrl->first_slot;
1060 make_slot_name(slot);
1061 mutex_init(&slot->lock);
1062 INIT_DELAYED_WORK(&slot->work, pciehp_queue_pushbutton_work);
1063 list_add(&slot->slot_list, &ctrl->slot_list);
1054 return 0; 1064 return 0;
1055} 1065}
1056 1066
1067static void pcie_cleanup_slot(struct controller *ctrl)
1068{
1069 struct slot *slot;
1070 slot = list_first_entry(&ctrl->slot_list, struct slot, slot_list);
1071 list_del(&slot->slot_list);
1072 cancel_delayed_work(&slot->work);
1073 flush_scheduled_work();
1074 flush_workqueue(pciehp_wq);
1075 kfree(slot);
1076}
1077
1057static inline void dbg_ctrl(struct controller *ctrl) 1078static inline void dbg_ctrl(struct controller *ctrl)
1058{ 1079{
1059 int i; 1080 int i;
@@ -1093,11 +1114,19 @@ static inline void dbg_ctrl(struct controller *ctrl)
1093 dbg("Slot Control : 0x%04x\n", reg16); 1114 dbg("Slot Control : 0x%04x\n", reg16);
1094} 1115}
1095 1116
1096int pcie_init(struct controller *ctrl, struct pcie_device *dev) 1117struct controller *pcie_init(struct pcie_device *dev)
1097{ 1118{
1119 struct controller *ctrl;
1098 u32 slot_cap; 1120 u32 slot_cap;
1099 struct pci_dev *pdev = dev->port; 1121 struct pci_dev *pdev = dev->port;
1100 1122
1123 ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
1124 if (!ctrl) {
1125 err("%s : out of memory\n", __func__);
1126 goto abort;
1127 }
1128 INIT_LIST_HEAD(&ctrl->slot_list);
1129
1101 ctrl->pci_dev = pdev; 1130 ctrl->pci_dev = pdev;
1102 ctrl->cap_base = pci_find_capability(pdev, PCI_CAP_ID_EXP); 1131 ctrl->cap_base = pci_find_capability(pdev, PCI_CAP_ID_EXP);
1103 if (!ctrl->cap_base) { 1132 if (!ctrl->cap_base) {
@@ -1128,15 +1157,12 @@ int pcie_init(struct controller *ctrl, struct pcie_device *dev)
1128 !(POWER_CTRL(ctrl) | ATTN_LED(ctrl) | PWR_LED(ctrl) | EMI(ctrl))) 1157 !(POWER_CTRL(ctrl) | ATTN_LED(ctrl) | PWR_LED(ctrl) | EMI(ctrl)))
1129 ctrl->no_cmd_complete = 1; 1158 ctrl->no_cmd_complete = 1;
1130 1159
1131 info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", 1160 /* Clear all remaining event bits in Slot Status register */
1132 pdev->vendor, pdev->device, 1161 if (pciehp_writew(ctrl, SLOTSTATUS, 0x1f))
1133 pdev->subsystem_vendor, pdev->subsystem_device); 1162 goto abort_ctrl;
1134 1163
1135 if (pcie_init_hardware_part1(ctrl, dev)) 1164 /* Disable sotfware notification */
1136 goto abort; 1165 pcie_disable_notification(ctrl);
1137
1138 if (pciehp_request_irq(ctrl))
1139 goto abort;
1140 1166
1141 /* 1167 /*
1142 * If this is the first controller to be initialized, 1168 * If this is the first controller to be initialized,
@@ -1144,18 +1170,39 @@ int pcie_init(struct controller *ctrl, struct pcie_device *dev)
1144 */ 1170 */
1145 if (atomic_add_return(1, &pciehp_num_controllers) == 1) { 1171 if (atomic_add_return(1, &pciehp_num_controllers) == 1) {
1146 pciehp_wq = create_singlethread_workqueue("pciehpd"); 1172 pciehp_wq = create_singlethread_workqueue("pciehpd");
1147 if (!pciehp_wq) { 1173 if (!pciehp_wq)
1148 goto abort_free_irq; 1174 goto abort_ctrl;
1149 }
1150 } 1175 }
1151 1176
1152 if (pcie_init_hardware_part2(ctrl, dev)) 1177 info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n",
1153 goto abort_free_irq; 1178 pdev->vendor, pdev->device,
1179 pdev->subsystem_vendor, pdev->subsystem_device);
1180
1181 if (pcie_init_slot(ctrl))
1182 goto abort_ctrl;
1154 1183
1155 return 0; 1184 if (pcie_init_notification(ctrl))
1185 goto abort_slot;
1156 1186
1157abort_free_irq: 1187 return ctrl;
1158 pciehp_free_irq(ctrl); 1188
1189abort_slot:
1190 pcie_cleanup_slot(ctrl);
1191abort_ctrl:
1192 kfree(ctrl);
1159abort: 1193abort:
1160 return -1; 1194 return NULL;
1195}
1196
1197void pcie_release_ctrl(struct controller *ctrl)
1198{
1199 pcie_shutdown_notification(ctrl);
1200 pcie_cleanup_slot(ctrl);
1201 /*
1202 * If this is the last controller to be released, destroy the
1203 * pciehp work queue
1204 */
1205 if (atomic_dec_and_test(&pciehp_num_controllers))
1206 destroy_workqueue(pciehp_wq);
1207 kfree(ctrl);
1161} 1208}