diff options
author | Mark Lord <lkml@rtr.ca> | 2007-11-28 18:11:46 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2008-02-01 18:04:23 -0500 |
commit | 08e7a7d27d71e92305980033ec03c0a86b3efb2d (patch) | |
tree | 4916e6831b974087cf17d3d8c0394563139319b4 | |
parent | 0a3c33d77ff7ad5b988997536a8f09c49e35ad20 (diff) |
PCI: more fixes for PCIe Hotplug so that it works with ExpressCard slots on Dell notebooks (and others?) in conjunction with modparam of pciehp_force=1
Split out the hotplug hardware initialization code from pcie_init()
into pcie_init_enable_events(), without changing any functionality.
Signed-off-by: Mark Lord <mlord@pobox.com>
Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r-- | drivers/pci/hotplug/pciehp_hpc.c | 185 |
1 files changed, 104 insertions, 81 deletions
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 06d025b8b13f..8b11d80bf651 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c | |||
@@ -1067,99 +1067,22 @@ int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev) | |||
1067 | } | 1067 | } |
1068 | #endif | 1068 | #endif |
1069 | 1069 | ||
1070 | int pcie_init(struct controller * ctrl, struct pcie_device *dev) | 1070 | int pcie_init_hardware(struct controller *ctrl, struct pcie_device *dev) |
1071 | { | 1071 | { |
1072 | int rc; | 1072 | int rc; |
1073 | u16 temp_word; | 1073 | u16 temp_word; |
1074 | u16 cap_reg; | ||
1075 | u16 intr_enable = 0; | 1074 | u16 intr_enable = 0; |
1076 | u32 slot_cap; | 1075 | u32 slot_cap; |
1077 | int cap_base; | 1076 | u16 slot_status; |
1078 | u16 slot_status, slot_ctrl; | ||
1079 | struct pci_dev *pdev; | 1077 | struct pci_dev *pdev; |
1080 | 1078 | ||
1081 | pdev = dev->port; | 1079 | pdev = dev->port; |
1082 | ctrl->pci_dev = pdev; /* save pci_dev in context */ | ||
1083 | |||
1084 | dbg("%s: hotplug controller vendor id 0x%x device id 0x%x\n", | ||
1085 | __FUNCTION__, pdev->vendor, pdev->device); | ||
1086 | |||
1087 | if ((cap_base = pci_find_capability(pdev, PCI_CAP_ID_EXP)) == 0) { | ||
1088 | dbg("%s: Can't find PCI_CAP_ID_EXP (0x10)\n", __FUNCTION__); | ||
1089 | goto abort_free_ctlr; | ||
1090 | } | ||
1091 | |||
1092 | ctrl->cap_base = cap_base; | ||
1093 | |||
1094 | dbg("%s: pcie_cap_base %x\n", __FUNCTION__, cap_base); | ||
1095 | |||
1096 | rc = pciehp_readw(ctrl, CAPREG, &cap_reg); | ||
1097 | if (rc) { | ||
1098 | err("%s: Cannot read CAPREG register\n", __FUNCTION__); | ||
1099 | goto abort_free_ctlr; | ||
1100 | } | ||
1101 | dbg("%s: CAPREG offset %x cap_reg %x\n", | ||
1102 | __FUNCTION__, ctrl->cap_base + CAPREG, cap_reg); | ||
1103 | |||
1104 | if (((cap_reg & SLOT_IMPL) == 0) || | ||
1105 | (((cap_reg & DEV_PORT_TYPE) != 0x0040) | ||
1106 | && ((cap_reg & DEV_PORT_TYPE) != 0x0060))) { | ||
1107 | dbg("%s : This is not a root port or the port is not " | ||
1108 | "connected to a slot\n", __FUNCTION__); | ||
1109 | goto abort_free_ctlr; | ||
1110 | } | ||
1111 | 1080 | ||
1112 | rc = pciehp_readl(ctrl, SLOTCAP, &slot_cap); | 1081 | rc = pciehp_readl(ctrl, SLOTCAP, &slot_cap); |
1113 | if (rc) { | 1082 | if (rc) { |
1114 | err("%s: Cannot read SLOTCAP register\n", __FUNCTION__); | 1083 | err("%s: Cannot read SLOTCAP register\n", __FUNCTION__); |
1115 | goto abort_free_ctlr; | 1084 | goto abort_free_ctlr; |
1116 | } | 1085 | } |
1117 | dbg("%s: SLOTCAP offset %x slot_cap %x\n", | ||
1118 | __FUNCTION__, ctrl->cap_base + SLOTCAP, slot_cap); | ||
1119 | |||
1120 | if (!(slot_cap & HP_CAP)) { | ||
1121 | dbg("%s : This slot is not hot-plug capable\n", __FUNCTION__); | ||
1122 | goto abort_free_ctlr; | ||
1123 | } | ||
1124 | /* For debugging purpose */ | ||
1125 | rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); | ||
1126 | if (rc) { | ||
1127 | err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__); | ||
1128 | goto abort_free_ctlr; | ||
1129 | } | ||
1130 | dbg("%s: SLOTSTATUS offset %x slot_status %x\n", | ||
1131 | __FUNCTION__, ctrl->cap_base + SLOTSTATUS, slot_status); | ||
1132 | |||
1133 | rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); | ||
1134 | if (rc) { | ||
1135 | err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); | ||
1136 | goto abort_free_ctlr; | ||
1137 | } | ||
1138 | dbg("%s: SLOTCTRL offset %x slot_ctrl %x\n", | ||
1139 | __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_ctrl); | ||
1140 | |||
1141 | for (rc = 0; rc < DEVICE_COUNT_RESOURCE; rc++) | ||
1142 | if (pci_resource_len(pdev, rc) > 0) | ||
1143 | dbg("pci resource[%d] start=0x%llx(len=0x%llx)\n", rc, | ||
1144 | (unsigned long long)pci_resource_start(pdev, rc), | ||
1145 | (unsigned long long)pci_resource_len(pdev, rc)); | ||
1146 | |||
1147 | info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", | ||
1148 | pdev->vendor, pdev->device, | ||
1149 | pdev->subsystem_vendor, pdev->subsystem_device); | ||
1150 | |||
1151 | mutex_init(&ctrl->crit_sect); | ||
1152 | mutex_init(&ctrl->ctrl_lock); | ||
1153 | spin_lock_init(&ctrl->lock); | ||
1154 | |||
1155 | /* setup wait queue */ | ||
1156 | init_waitqueue_head(&ctrl->queue); | ||
1157 | |||
1158 | /* return PCI Controller Info */ | ||
1159 | ctrl->slot_device_offset = 0; | ||
1160 | ctrl->num_slots = 1; | ||
1161 | ctrl->first_slot = slot_cap >> 19; | ||
1162 | ctrl->ctrlcap = slot_cap & 0x0000007f; | ||
1163 | 1086 | ||
1164 | /* Mask Hot-plug Interrupt Enable */ | 1087 | /* Mask Hot-plug Interrupt Enable */ |
1165 | rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); | 1088 | rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); |
@@ -1280,8 +1203,6 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) | |||
1280 | goto abort_disable_intr; | 1203 | goto abort_disable_intr; |
1281 | } | 1204 | } |
1282 | 1205 | ||
1283 | ctrl->hpc_ops = &pciehp_hpc_ops; | ||
1284 | |||
1285 | return 0; | 1206 | return 0; |
1286 | 1207 | ||
1287 | /* We end up here for the many possible ways to fail this API. */ | 1208 | /* We end up here for the many possible ways to fail this API. */ |
@@ -1303,3 +1224,105 @@ abort_free_irq: | |||
1303 | abort_free_ctlr: | 1224 | abort_free_ctlr: |
1304 | return -1; | 1225 | return -1; |
1305 | } | 1226 | } |
1227 | |||
1228 | int pcie_init(struct controller *ctrl, struct pcie_device *dev) | ||
1229 | { | ||
1230 | int rc; | ||
1231 | u16 cap_reg; | ||
1232 | u32 slot_cap; | ||
1233 | int cap_base; | ||
1234 | u16 slot_status, slot_ctrl; | ||
1235 | struct pci_dev *pdev; | ||
1236 | |||
1237 | pdev = dev->port; | ||
1238 | ctrl->pci_dev = pdev; /* save pci_dev in context */ | ||
1239 | |||
1240 | dbg("%s: hotplug controller vendor id 0x%x device id 0x%x\n", | ||
1241 | __FUNCTION__, pdev->vendor, pdev->device); | ||
1242 | |||
1243 | cap_base = pci_find_capability(pdev, PCI_CAP_ID_EXP); | ||
1244 | if (cap_base == 0) { | ||
1245 | dbg("%s: Can't find PCI_CAP_ID_EXP (0x10)\n", __FUNCTION__); | ||
1246 | goto abort; | ||
1247 | } | ||
1248 | |||
1249 | ctrl->cap_base = cap_base; | ||
1250 | |||
1251 | dbg("%s: pcie_cap_base %x\n", __FUNCTION__, cap_base); | ||
1252 | |||
1253 | rc = pciehp_readw(ctrl, CAPREG, &cap_reg); | ||
1254 | if (rc) { | ||
1255 | err("%s: Cannot read CAPREG register\n", __FUNCTION__); | ||
1256 | goto abort; | ||
1257 | } | ||
1258 | dbg("%s: CAPREG offset %x cap_reg %x\n", | ||
1259 | __FUNCTION__, ctrl->cap_base + CAPREG, cap_reg); | ||
1260 | |||
1261 | if (((cap_reg & SLOT_IMPL) == 0) || | ||
1262 | (((cap_reg & DEV_PORT_TYPE) != 0x0040) | ||
1263 | && ((cap_reg & DEV_PORT_TYPE) != 0x0060))) { | ||
1264 | dbg("%s : This is not a root port or the port is not " | ||
1265 | "connected to a slot\n", __FUNCTION__); | ||
1266 | goto abort; | ||
1267 | } | ||
1268 | |||
1269 | rc = pciehp_readl(ctrl, SLOTCAP, &slot_cap); | ||
1270 | if (rc) { | ||
1271 | err("%s: Cannot read SLOTCAP register\n", __FUNCTION__); | ||
1272 | goto abort; | ||
1273 | } | ||
1274 | dbg("%s: SLOTCAP offset %x slot_cap %x\n", | ||
1275 | __FUNCTION__, ctrl->cap_base + SLOTCAP, slot_cap); | ||
1276 | |||
1277 | if (!(slot_cap & HP_CAP)) { | ||
1278 | dbg("%s : This slot is not hot-plug capable\n", __FUNCTION__); | ||
1279 | goto abort; | ||
1280 | } | ||
1281 | /* For debugging purpose */ | ||
1282 | rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); | ||
1283 | if (rc) { | ||
1284 | err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__); | ||
1285 | goto abort; | ||
1286 | } | ||
1287 | dbg("%s: SLOTSTATUS offset %x slot_status %x\n", | ||
1288 | __FUNCTION__, ctrl->cap_base + SLOTSTATUS, slot_status); | ||
1289 | |||
1290 | rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); | ||
1291 | if (rc) { | ||
1292 | err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); | ||
1293 | goto abort; | ||
1294 | } | ||
1295 | dbg("%s: SLOTCTRL offset %x slot_ctrl %x\n", | ||
1296 | __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_ctrl); | ||
1297 | |||
1298 | for (rc = 0; rc < DEVICE_COUNT_RESOURCE; rc++) | ||
1299 | if (pci_resource_len(pdev, rc) > 0) | ||
1300 | dbg("pci resource[%d] start=0x%llx(len=0x%llx)\n", rc, | ||
1301 | (unsigned long long)pci_resource_start(pdev, rc), | ||
1302 | (unsigned long long)pci_resource_len(pdev, rc)); | ||
1303 | |||
1304 | info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", | ||
1305 | pdev->vendor, pdev->device, | ||
1306 | pdev->subsystem_vendor, pdev->subsystem_device); | ||
1307 | |||
1308 | mutex_init(&ctrl->crit_sect); | ||
1309 | mutex_init(&ctrl->ctrl_lock); | ||
1310 | spin_lock_init(&ctrl->lock); | ||
1311 | |||
1312 | /* setup wait queue */ | ||
1313 | init_waitqueue_head(&ctrl->queue); | ||
1314 | |||
1315 | /* return PCI Controller Info */ | ||
1316 | ctrl->slot_device_offset = 0; | ||
1317 | ctrl->num_slots = 1; | ||
1318 | ctrl->first_slot = slot_cap >> 19; | ||
1319 | ctrl->ctrlcap = slot_cap & 0x0000007f; | ||
1320 | |||
1321 | rc = pcie_init_hardware(ctrl, dev); | ||
1322 | if (rc == 0) { | ||
1323 | ctrl->hpc_ops = &pciehp_hpc_ops; | ||
1324 | return 0; | ||
1325 | } | ||
1326 | abort: | ||
1327 | return -1; | ||
1328 | } | ||