aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Lord <lkml@rtr.ca>2007-11-21 18:07:55 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2008-02-01 18:04:23 -0500
commitecdde93962eacd9c417977a4eabd318dbb612c11 (patch)
tree5637b661a33330cd7171f4965a7f430310dec48c
parentcd2fe83a81510acfd1ae29b8ffe04f7ef675c993 (diff)
PCIe: fix double initialization bug
Earlier patches to split out the hardware init for PCIe hotplug resulted in some one-time initializations being redone on every resume cycle. Eg. irq/polling initialization. This patch splits the hardware init into two parts, and separates the one-time initializations from those so that they only ever get done once, as intended. Signed-off-by: Mark Lord <mlord@pobox.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/pci/hotplug/pciehp.h2
-rw-r--r--drivers/pci/hotplug/pciehp_core.c2
-rw-r--r--drivers/pci/hotplug/pciehp_hpc.c119
3 files changed, 69 insertions, 54 deletions
diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h
index e4ad00a3448e..288fc4689103 100644
--- a/drivers/pci/hotplug/pciehp.h
+++ b/drivers/pci/hotplug/pciehp.h
@@ -163,7 +163,7 @@ extern void pciehp_queue_pushbutton_work(struct work_struct *work);
163int pcie_init(struct controller *ctrl, struct pcie_device *dev); 163int pcie_init(struct controller *ctrl, struct pcie_device *dev);
164int pciehp_enable_slot(struct slot *p_slot); 164int pciehp_enable_slot(struct slot *p_slot);
165int pciehp_disable_slot(struct slot *p_slot); 165int pciehp_disable_slot(struct slot *p_slot);
166int pcie_init_hardware(struct controller *ctrl, struct pcie_device *dev); 166int pcie_init_hardware_part2(struct controller *ctrl, struct pcie_device *dev);
167 167
168static inline struct slot *pciehp_find_slot(struct controller *ctrl, u8 device) 168static inline struct slot *pciehp_find_slot(struct controller *ctrl, u8 device)
169{ 169{
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c
index ae3fe318b8fd..310223d037aa 100644
--- a/drivers/pci/hotplug/pciehp_core.c
+++ b/drivers/pci/hotplug/pciehp_core.c
@@ -521,7 +521,7 @@ static int pciehp_resume (struct pcie_device *dev)
521 u8 status; 521 u8 status;
522 522
523 /* reinitialize the chipset's event detection logic */ 523 /* reinitialize the chipset's event detection logic */
524 pcie_init_hardware(ctrl, dev); 524 pcie_init_hardware_part2(ctrl, dev);
525 525
526 t_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset); 526 t_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset);
527 527
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
index 8b11d80bf651..8c2d6c9b92c5 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -1067,28 +1067,25 @@ int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev)
1067} 1067}
1068#endif 1068#endif
1069 1069
1070int pcie_init_hardware(struct controller *ctrl, struct pcie_device *dev) 1070static int pcie_init_hardware_part1(struct controller *ctrl,
1071 struct pcie_device *dev)
1071{ 1072{
1072 int rc; 1073 int rc;
1073 u16 temp_word; 1074 u16 temp_word;
1074 u16 intr_enable = 0;
1075 u32 slot_cap; 1075 u32 slot_cap;
1076 u16 slot_status; 1076 u16 slot_status;
1077 struct pci_dev *pdev;
1078
1079 pdev = dev->port;
1080 1077
1081 rc = pciehp_readl(ctrl, SLOTCAP, &slot_cap); 1078 rc = pciehp_readl(ctrl, SLOTCAP, &slot_cap);
1082 if (rc) { 1079 if (rc) {
1083 err("%s: Cannot read SLOTCAP register\n", __FUNCTION__); 1080 err("%s: Cannot read SLOTCAP register\n", __FUNCTION__);
1084 goto abort_free_ctlr; 1081 return -1;
1085 } 1082 }
1086 1083
1087 /* Mask Hot-plug Interrupt Enable */ 1084 /* Mask Hot-plug Interrupt Enable */
1088 rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); 1085 rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
1089 if (rc) { 1086 if (rc) {
1090 err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); 1087 err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
1091 goto abort_free_ctlr; 1088 return -1;
1092 } 1089 }
1093 1090
1094 dbg("%s: SLOTCTRL %x value read %x\n", 1091 dbg("%s: SLOTCTRL %x value read %x\n",
@@ -1099,62 +1096,46 @@ int pcie_init_hardware(struct controller *ctrl, struct pcie_device *dev)
1099 rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); 1096 rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
1100 if (rc) { 1097 if (rc) {
1101 err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__); 1098 err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__);
1102 goto abort_free_ctlr; 1099 return -1;
1103 } 1100 }
1104 1101
1105 rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); 1102 rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
1106 if (rc) { 1103 if (rc) {
1107 err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__); 1104 err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
1108 goto abort_free_ctlr; 1105 return -1;
1109 } 1106 }
1110 1107
1111 temp_word = 0x1F; /* Clear all events */ 1108 temp_word = 0x1F; /* Clear all events */
1112 rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word); 1109 rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
1113 if (rc) { 1110 if (rc) {
1114 err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__); 1111 err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__);
1115 goto abort_free_ctlr; 1112 return -1;
1116 }
1117
1118 if (pciehp_poll_mode) {
1119 /* Install interrupt polling timer. Start with 10 sec delay */
1120 init_timer(&ctrl->poll_timer);
1121 start_int_poll_timer(ctrl, 10);
1122 } else {
1123 /* Installs the interrupt handler */
1124 rc = request_irq(ctrl->pci_dev->irq, pcie_isr, IRQF_SHARED,
1125 MY_NAME, (void *)ctrl);
1126 dbg("%s: request_irq %d for hpc%d (returns %d)\n",
1127 __FUNCTION__, ctrl->pci_dev->irq,
1128 atomic_read(&pciehp_num_controllers), rc);
1129 if (rc) {
1130 err("Can't get irq %d for the hotplug controller\n",
1131 ctrl->pci_dev->irq);
1132 goto abort_free_ctlr;
1133 }
1134 } 1113 }
1135 dbg("pciehp ctrl b:d:f:irq=0x%x:%x:%x:%x\n", pdev->bus->number, 1114 return 0;
1136 PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), dev->irq); 1115}
1137 1116
1138 /* 1117int pcie_init_hardware_part2(struct controller *ctrl, struct pcie_device *dev)
1139 * If this is the first controller to be initialized, 1118{
1140 * initialize the pciehp work queue 1119 int rc;
1141 */ 1120 u16 temp_word;
1142 if (atomic_add_return(1, &pciehp_num_controllers) == 1) { 1121 u16 intr_enable = 0;
1143 pciehp_wq = create_singlethread_workqueue("pciehpd"); 1122 u32 slot_cap;
1144 if (!pciehp_wq) { 1123 u16 slot_status;
1145 rc = -ENOMEM;
1146 goto abort_free_irq;
1147 }
1148 }
1149 1124
1150 rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); 1125 rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
1151 if (rc) { 1126 if (rc) {
1152 err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); 1127 err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
1153 goto abort_free_irq; 1128 goto abort;
1154 } 1129 }
1155 1130
1156 intr_enable = intr_enable | PRSN_DETECT_ENABLE; 1131 intr_enable = intr_enable | PRSN_DETECT_ENABLE;
1157 1132
1133 rc = pciehp_readl(ctrl, SLOTCAP, &slot_cap);
1134 if (rc) {
1135 err("%s: Cannot read SLOTCAP register\n", __FUNCTION__);
1136 goto abort;
1137 }
1138
1158 if (ATTN_BUTTN(slot_cap)) 1139 if (ATTN_BUTTN(slot_cap))
1159 intr_enable = intr_enable | ATTN_BUTTN_ENABLE; 1140 intr_enable = intr_enable | ATTN_BUTTN_ENABLE;
1160 1141
@@ -1179,7 +1160,7 @@ int pcie_init_hardware(struct controller *ctrl, struct pcie_device *dev)
1179 rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); 1160 rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
1180 if (rc) { 1161 if (rc) {
1181 err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__); 1162 err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__);
1182 goto abort_free_irq; 1163 goto abort;
1183 } 1164 }
1184 rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); 1165 rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
1185 if (rc) { 1166 if (rc) {
@@ -1214,14 +1195,7 @@ abort_disable_intr:
1214 } 1195 }
1215 if (rc) 1196 if (rc)
1216 err("%s : disabling interrupts failed\n", __FUNCTION__); 1197 err("%s : disabling interrupts failed\n", __FUNCTION__);
1217 1198abort:
1218abort_free_irq:
1219 if (pciehp_poll_mode)
1220 del_timer_sync(&ctrl->poll_timer);
1221 else
1222 free_irq(ctrl->pci_dev->irq, ctrl);
1223
1224abort_free_ctlr:
1225 return -1; 1199 return -1;
1226} 1200}
1227 1201
@@ -1318,11 +1292,52 @@ int pcie_init(struct controller *ctrl, struct pcie_device *dev)
1318 ctrl->first_slot = slot_cap >> 19; 1292 ctrl->first_slot = slot_cap >> 19;
1319 ctrl->ctrlcap = slot_cap & 0x0000007f; 1293 ctrl->ctrlcap = slot_cap & 0x0000007f;
1320 1294
1321 rc = pcie_init_hardware(ctrl, dev); 1295 rc = pcie_init_hardware_part1(ctrl, dev);
1296 if (rc)
1297 goto abort;
1298
1299 if (pciehp_poll_mode) {
1300 /* Install interrupt polling timer. Start with 10 sec delay */
1301 init_timer(&ctrl->poll_timer);
1302 start_int_poll_timer(ctrl, 10);
1303 } else {
1304 /* Installs the interrupt handler */
1305 rc = request_irq(ctrl->pci_dev->irq, pcie_isr, IRQF_SHARED,
1306 MY_NAME, (void *)ctrl);
1307 dbg("%s: request_irq %d for hpc%d (returns %d)\n",
1308 __FUNCTION__, ctrl->pci_dev->irq,
1309 atomic_read(&pciehp_num_controllers), rc);
1310 if (rc) {
1311 err("Can't get irq %d for the hotplug controller\n",
1312 ctrl->pci_dev->irq);
1313 goto abort;
1314 }
1315 }
1316 dbg("pciehp ctrl b:d:f:irq=0x%x:%x:%x:%x\n", pdev->bus->number,
1317 PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), dev->irq);
1318
1319 /*
1320 * If this is the first controller to be initialized,
1321 * initialize the pciehp work queue
1322 */
1323 if (atomic_add_return(1, &pciehp_num_controllers) == 1) {
1324 pciehp_wq = create_singlethread_workqueue("pciehpd");
1325 if (!pciehp_wq) {
1326 rc = -ENOMEM;
1327 goto abort_free_irq;
1328 }
1329 }
1330
1331 rc = pcie_init_hardware_part2(ctrl, dev);
1322 if (rc == 0) { 1332 if (rc == 0) {
1323 ctrl->hpc_ops = &pciehp_hpc_ops; 1333 ctrl->hpc_ops = &pciehp_hpc_ops;
1324 return 0; 1334 return 0;
1325 } 1335 }
1336abort_free_irq:
1337 if (pciehp_poll_mode)
1338 del_timer_sync(&ctrl->poll_timer);
1339 else
1340 free_irq(ctrl->pci_dev->irq, ctrl);
1326abort: 1341abort:
1327 return -1; 1342 return -1;
1328} 1343}