aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/edac
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@redhat.com>2009-09-04 23:52:11 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2010-05-10 10:44:58 -0400
commit66607706cee7b6901aa0509198f075859c93ec6a (patch)
treeb55e025bd7149ed9d00f38e596dc94e1f3909b95 /drivers/edac
parenta55456f3446d19853af54b64b3840312f46b6ea5 (diff)
Dynamically allocate memory for PCI devices
Instead of using a static table assuming always 2 CPU sockets, allocate space dynamically for Nehalem PCI devs. This patch is part of a series of patches that changes i7core_edac to allow more than 2 sockets and to properly report one memory controller per socket.
Diffstat (limited to 'drivers/edac')
-rw-r--r--drivers/edac/i7core_edac.c175
1 files changed, 114 insertions, 61 deletions
diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c
index af222ffcfdfc..7bcb5993b501 100644
--- a/drivers/edac/i7core_edac.c
+++ b/drivers/edac/i7core_edac.c
@@ -192,10 +192,9 @@ struct i7core_channel {
192}; 192};
193 193
194struct pci_id_descr { 194struct pci_id_descr {
195 int dev; 195 int dev;
196 int func; 196 int func;
197 int dev_id; 197 int dev_id;
198 struct pci_dev *pdev[NUM_SOCKETS];
199}; 198};
200 199
201struct i7core_pvt { 200struct i7core_pvt {
@@ -229,6 +228,17 @@ struct i7core_pvt {
229 spinlock_t mce_lock; 228 spinlock_t mce_lock;
230}; 229};
231 230
231struct i7core_dev {
232 struct list_head list;
233
234 int socket;
235 struct pci_dev **pdev;
236};
237
238/* Static vars */
239static LIST_HEAD(i7core_edac_list);
240static DEFINE_MUTEX(i7core_edac_lock);
241
232/* Device name and register DID (Device ID) */ 242/* Device name and register DID (Device ID) */
233struct i7core_dev_info { 243struct i7core_dev_info {
234 const char *ctl_name; /* name for this device */ 244 const char *ctl_name; /* name for this device */
@@ -240,7 +250,7 @@ struct i7core_dev_info {
240 .func = (function), \ 250 .func = (function), \
241 .dev_id = (device_id) 251 .dev_id = (device_id)
242 252
243struct pci_id_descr pci_devs[] = { 253struct pci_id_descr pci_dev_descr[] = {
244 /* Memory controller */ 254 /* Memory controller */
245 { PCI_DESCR(3, 0, PCI_DEVICE_ID_INTEL_I7_MCR) }, 255 { PCI_DESCR(3, 0, PCI_DEVICE_ID_INTEL_I7_MCR) },
246 { PCI_DESCR(3, 1, PCI_DEVICE_ID_INTEL_I7_MC_TAD) }, 256 { PCI_DESCR(3, 1, PCI_DEVICE_ID_INTEL_I7_MC_TAD) },
@@ -275,11 +285,10 @@ struct pci_id_descr pci_devs[] = {
275 { PCI_DESCR(0, 0, PCI_DEVICE_ID_INTEL_I7_NOCORE) }, 285 { PCI_DESCR(0, 0, PCI_DEVICE_ID_INTEL_I7_NOCORE) },
276 286
277}; 287};
278#define N_DEVS ARRAY_SIZE(pci_devs) 288#define N_DEVS ARRAY_SIZE(pci_dev_descr)
279 289
280/* 290/*
281 * pci_device_id table for which devices we are looking for 291 * pci_device_id table for which devices we are looking for
282 * This should match the first device at pci_devs table
283 */ 292 */
284static const struct pci_device_id i7core_pci_tbl[] __devinitdata = { 293static const struct pci_device_id i7core_pci_tbl[] __devinitdata = {
285 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_X58_HUB_MGMT)}, 294 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_X58_HUB_MGMT)},
@@ -288,7 +297,7 @@ static const struct pci_device_id i7core_pci_tbl[] __devinitdata = {
288 297
289 298
290/* Table of devices attributes supported by this driver */ 299/* Table of devices attributes supported by this driver */
291static const struct i7core_dev_info i7core_devs[] = { 300static const struct i7core_dev_info i7core_probe_devs[] = {
292 { 301 {
293 .ctl_name = "i7 Core", 302 .ctl_name = "i7 Core",
294 .fsb_mapping_errors = PCI_DEVICE_ID_INTEL_I7_MCR, 303 .fsb_mapping_errors = PCI_DEVICE_ID_INTEL_I7_MCR,
@@ -347,21 +356,37 @@ static inline int numcol(u32 col)
347 return cols[col & 0x3]; 356 return cols[col & 0x3];
348} 357}
349 358
359static struct i7core_dev *get_i7core_dev(int socket)
360{
361 struct i7core_dev *i7core_dev;
362
363 list_for_each_entry(i7core_dev, &i7core_edac_list, list) {
364 if (i7core_dev->socket == socket)
365 return i7core_dev;
366 }
367
368 return NULL;
369}
370
350/**************************************************************************** 371/****************************************************************************
351 Memory check routines 372 Memory check routines
352 ****************************************************************************/ 373 ****************************************************************************/
353static struct pci_dev *get_pdev_slot_func(u8 socket, unsigned slot, 374static struct pci_dev *get_pdev_slot_func(u8 socket, unsigned slot,
354 unsigned func) 375 unsigned func)
355{ 376{
377 struct i7core_dev *i7core_dev = get_i7core_dev(socket);
356 int i; 378 int i;
357 379
380 if (!i7core_dev)
381 return NULL;
382
358 for (i = 0; i < N_DEVS; i++) { 383 for (i = 0; i < N_DEVS; i++) {
359 if (!pci_devs[i].pdev[socket]) 384 if (!i7core_dev->pdev[i])
360 continue; 385 continue;
361 386
362 if (PCI_SLOT(pci_devs[i].pdev[socket]->devfn) == slot && 387 if (PCI_SLOT(i7core_dev->pdev[i]->devfn) == slot &&
363 PCI_FUNC(pci_devs[i].pdev[socket]->devfn) == func) { 388 PCI_FUNC(i7core_dev->pdev[i]->devfn) == func) {
364 return pci_devs[i].pdev[socket]; 389 return i7core_dev->pdev[i];
365 } 390 }
366 } 391 }
367 392
@@ -1153,9 +1178,18 @@ static void i7core_put_devices(void)
1153{ 1178{
1154 int i, j; 1179 int i, j;
1155 1180
1156 for (i = 0; i < NUM_SOCKETS; i++) 1181 for (i = 0; i < NUM_SOCKETS; i++) {
1182 struct i7core_dev *i7core_dev = get_i7core_dev(i);
1183 if (!i7core_dev)
1184 continue;
1185
1157 for (j = 0; j < N_DEVS; j++) 1186 for (j = 0; j < N_DEVS; j++)
1158 pci_dev_put(pci_devs[j].pdev[i]); 1187 pci_dev_put(i7core_dev->pdev[j]);
1188
1189 list_del(&i7core_dev->list);
1190 kfree(i7core_dev->pdev);
1191 kfree(i7core_dev);
1192 }
1159} 1193}
1160 1194
1161static void i7core_xeon_pci_fixup(void) 1195static void i7core_xeon_pci_fixup(void)
@@ -1168,7 +1202,7 @@ static void i7core_xeon_pci_fixup(void)
1168 * to detect them 1202 * to detect them
1169 */ 1203 */
1170 pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 1204 pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
1171 pci_devs[0].dev_id, NULL); 1205 pci_dev_descr[0].dev_id, NULL);
1172 if (unlikely(!pdev)) { 1206 if (unlikely(!pdev)) {
1173 for (i = 0; i < NUM_SOCKETS; i ++) 1207 for (i = 0; i < NUM_SOCKETS; i ++)
1174 pcibios_scan_specific_bus(255-i); 1208 pcibios_scan_specific_bus(255-i);
@@ -1183,19 +1217,21 @@ static void i7core_xeon_pci_fixup(void)
1183 */ 1217 */
1184int i7core_get_onedevice(struct pci_dev **prev, int devno) 1218int i7core_get_onedevice(struct pci_dev **prev, int devno)
1185{ 1219{
1220 struct i7core_dev *i7core_dev;
1221
1186 struct pci_dev *pdev = NULL; 1222 struct pci_dev *pdev = NULL;
1187 u8 bus = 0; 1223 u8 bus = 0;
1188 u8 socket = 0; 1224 u8 socket = 0;
1189 1225
1190 pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 1226 pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
1191 pci_devs[devno].dev_id, *prev); 1227 pci_dev_descr[devno].dev_id, *prev);
1192 1228
1193 /* 1229 /*
1194 * On Xeon 55xx, the Intel Quckpath Arch Generic Non-core regs 1230 * On Xeon 55xx, the Intel Quckpath Arch Generic Non-core regs
1195 * is at addr 8086:2c40, instead of 8086:2c41. So, we need 1231 * is at addr 8086:2c40, instead of 8086:2c41. So, we need
1196 * to probe for the alternate address in case of failure 1232 * to probe for the alternate address in case of failure
1197 */ 1233 */
1198 if (pci_devs[devno].dev_id == PCI_DEVICE_ID_INTEL_I7_NOCORE && !pdev) 1234 if (pci_dev_descr[devno].dev_id == PCI_DEVICE_ID_INTEL_I7_NOCORE && !pdev)
1199 pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 1235 pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
1200 PCI_DEVICE_ID_INTEL_I7_NOCORE_ALT, *prev); 1236 PCI_DEVICE_ID_INTEL_I7_NOCORE_ALT, *prev);
1201 1237
@@ -1209,15 +1245,15 @@ int i7core_get_onedevice(struct pci_dev **prev, int devno)
1209 * Dev 3 function 2 only exists on chips with RDIMMs 1245 * Dev 3 function 2 only exists on chips with RDIMMs
1210 * so, it is ok to not found it 1246 * so, it is ok to not found it
1211 */ 1247 */
1212 if ((pci_devs[devno].dev == 3) && (pci_devs[devno].func == 2)) { 1248 if ((pci_dev_descr[devno].dev == 3) && (pci_dev_descr[devno].func == 2)) {
1213 *prev = pdev; 1249 *prev = pdev;
1214 return 0; 1250 return 0;
1215 } 1251 }
1216 1252
1217 i7core_printk(KERN_ERR, 1253 i7core_printk(KERN_ERR,
1218 "Device not found: dev %02x.%d PCI ID %04x:%04x\n", 1254 "Device not found: dev %02x.%d PCI ID %04x:%04x\n",
1219 pci_devs[devno].dev, pci_devs[devno].func, 1255 pci_dev_descr[devno].dev, pci_dev_descr[devno].func,
1220 PCI_VENDOR_ID_INTEL, pci_devs[devno].dev_id); 1256 PCI_VENDOR_ID_INTEL, pci_dev_descr[devno].dev_id);
1221 1257
1222 /* End of list, leave */ 1258 /* End of list, leave */
1223 return -ENODEV; 1259 return -ENODEV;
@@ -1229,37 +1265,40 @@ int i7core_get_onedevice(struct pci_dev **prev, int devno)
1229 else 1265 else
1230 socket = 255 - bus; 1266 socket = 255 - bus;
1231 1267
1232 if (socket >= NUM_SOCKETS) { 1268 i7core_dev = get_i7core_dev(socket);
1233 i7core_printk(KERN_ERR, 1269 if (!i7core_dev) {
1234 "Unexpected socket for " 1270 i7core_dev = kzalloc(sizeof(*i7core_dev), GFP_KERNEL);
1235 "dev %02x:%02x.%d PCI ID %04x:%04x\n", 1271 if (!i7core_dev)
1236 bus, pci_devs[devno].dev, pci_devs[devno].func, 1272 return -ENOMEM;
1237 PCI_VENDOR_ID_INTEL, pci_devs[devno].dev_id); 1273 i7core_dev->pdev = kzalloc(sizeof(*i7core_dev->pdev) * N_DEVS,
1238 pci_dev_put(pdev); 1274 GFP_KERNEL);
1239 return -ENODEV; 1275 if (!i7core_dev->pdev)
1276 return -ENOMEM;
1277 i7core_dev->socket = socket;
1278 list_add_tail(&i7core_dev->list, &i7core_edac_list);
1240 } 1279 }
1241 1280
1242 if (pci_devs[devno].pdev[socket]) { 1281 if (i7core_dev->pdev[devno]) {
1243 i7core_printk(KERN_ERR, 1282 i7core_printk(KERN_ERR,
1244 "Duplicated device for " 1283 "Duplicated device for "
1245 "dev %02x:%02x.%d PCI ID %04x:%04x\n", 1284 "dev %02x:%02x.%d PCI ID %04x:%04x\n",
1246 bus, pci_devs[devno].dev, pci_devs[devno].func, 1285 bus, pci_dev_descr[devno].dev, pci_dev_descr[devno].func,
1247 PCI_VENDOR_ID_INTEL, pci_devs[devno].dev_id); 1286 PCI_VENDOR_ID_INTEL, pci_dev_descr[devno].dev_id);
1248 pci_dev_put(pdev); 1287 pci_dev_put(pdev);
1249 return -ENODEV; 1288 return -ENODEV;
1250 } 1289 }
1251 1290
1252 pci_devs[devno].pdev[socket] = pdev; 1291 i7core_dev->pdev[devno] = pdev;
1253 1292
1254 /* Sanity check */ 1293 /* Sanity check */
1255 if (unlikely(PCI_SLOT(pdev->devfn) != pci_devs[devno].dev || 1294 if (unlikely(PCI_SLOT(pdev->devfn) != pci_dev_descr[devno].dev ||
1256 PCI_FUNC(pdev->devfn) != pci_devs[devno].func)) { 1295 PCI_FUNC(pdev->devfn) != pci_dev_descr[devno].func)) {
1257 i7core_printk(KERN_ERR, 1296 i7core_printk(KERN_ERR,
1258 "Device PCI ID %04x:%04x " 1297 "Device PCI ID %04x:%04x "
1259 "has dev %02x:%02x.%d instead of dev %02x:%02x.%d\n", 1298 "has dev %02x:%02x.%d instead of dev %02x:%02x.%d\n",
1260 PCI_VENDOR_ID_INTEL, pci_devs[devno].dev_id, 1299 PCI_VENDOR_ID_INTEL, pci_dev_descr[devno].dev_id,
1261 bus, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), 1300 bus, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
1262 bus, pci_devs[devno].dev, pci_devs[devno].func); 1301 bus, pci_dev_descr[devno].dev, pci_dev_descr[devno].func);
1263 return -ENODEV; 1302 return -ENODEV;
1264 } 1303 }
1265 1304
@@ -1268,27 +1307,29 @@ int i7core_get_onedevice(struct pci_dev **prev, int devno)
1268 i7core_printk(KERN_ERR, 1307 i7core_printk(KERN_ERR,
1269 "Couldn't enable " 1308 "Couldn't enable "
1270 "dev %02x:%02x.%d PCI ID %04x:%04x\n", 1309 "dev %02x:%02x.%d PCI ID %04x:%04x\n",
1271 bus, pci_devs[devno].dev, pci_devs[devno].func, 1310 bus, pci_dev_descr[devno].dev, pci_dev_descr[devno].func,
1272 PCI_VENDOR_ID_INTEL, pci_devs[devno].dev_id); 1311 PCI_VENDOR_ID_INTEL, pci_dev_descr[devno].dev_id);
1273 return -ENODEV; 1312 return -ENODEV;
1274 } 1313 }
1275 1314
1276 i7core_printk(KERN_INFO, 1315 i7core_printk(KERN_INFO,
1277 "Registered socket %d " 1316 "Registered socket %d "
1278 "dev %02x:%02x.%d PCI ID %04x:%04x\n", 1317 "dev %02x:%02x.%d PCI ID %04x:%04x\n",
1279 socket, bus, pci_devs[devno].dev, pci_devs[devno].func, 1318 socket, bus, pci_dev_descr[devno].dev, pci_dev_descr[devno].func,
1280 PCI_VENDOR_ID_INTEL, pci_devs[devno].dev_id); 1319 PCI_VENDOR_ID_INTEL, pci_dev_descr[devno].dev_id);
1281 1320
1282 *prev = pdev; 1321 *prev = pdev;
1283 1322
1284 return 0; 1323 return 0;
1285} 1324}
1286 1325
1287static int i7core_get_devices(void) 1326static int i7core_get_devices(u8 *sockets)
1288{ 1327{
1289 int i; 1328 int i;
1290 struct pci_dev *pdev = NULL; 1329 struct pci_dev *pdev = NULL;
1330 struct i7core_dev *i7core_dev = NULL;
1291 1331
1332 *sockets = 0;
1292 for (i = 0; i < N_DEVS; i++) { 1333 for (i = 0; i < N_DEVS; i++) {
1293 pdev = NULL; 1334 pdev = NULL;
1294 do { 1335 do {
@@ -1298,6 +1339,12 @@ static int i7core_get_devices(void)
1298 } 1339 }
1299 } while (pdev); 1340 } while (pdev);
1300 } 1341 }
1342
1343 list_for_each_entry(i7core_dev, &i7core_edac_list, list) {
1344 if (i7core_dev->socket + 1 > *sockets)
1345 *sockets = i7core_dev->socket + 1;
1346 }
1347
1301 return 0; 1348 return 0;
1302} 1349}
1303 1350
@@ -1307,11 +1354,15 @@ static int mci_bind_devs(struct mem_ctl_info *mci)
1307 struct pci_dev *pdev; 1354 struct pci_dev *pdev;
1308 int i, j, func, slot; 1355 int i, j, func, slot;
1309 1356
1310
1311 for (i = 0; i < pvt->sockets; i++) { 1357 for (i = 0; i < pvt->sockets; i++) {
1358 struct i7core_dev *i7core_dev = get_i7core_dev(i);
1359
1360 if (!i7core_dev)
1361 continue;
1362
1312 pvt->is_registered[i] = 0; 1363 pvt->is_registered[i] = 0;
1313 for (j = 0; j < N_DEVS; j++) { 1364 for (j = 0; j < N_DEVS; j++) {
1314 pdev = pci_devs[j].pdev[i]; 1365 pdev = i7core_dev->pdev[j];
1315 if (!pdev) 1366 if (!pdev)
1316 continue; 1367 continue;
1317 1368
@@ -1723,20 +1774,17 @@ static int __devinit i7core_probe(struct pci_dev *pdev,
1723 int rc, i; 1774 int rc, i;
1724 u8 sockets; 1775 u8 sockets;
1725 1776
1726 if (unlikely(dev_idx >= ARRAY_SIZE(i7core_devs))) 1777 /*
1778 * FIXME: All memory controllers are allocated at the first pass.
1779 */
1780 if (unlikely(dev_idx >= 1))
1727 return -EINVAL; 1781 return -EINVAL;
1728 1782
1729 /* get the pci devices we want to reserve for our use */ 1783 /* get the pci devices we want to reserve for our use */
1730 rc = i7core_get_devices(); 1784 mutex_lock(&i7core_edac_lock);
1785 rc = i7core_get_devices(&sockets);
1731 if (unlikely(rc < 0)) 1786 if (unlikely(rc < 0))
1732 return rc; 1787 goto fail0;
1733
1734 sockets = 1;
1735 for (i = NUM_SOCKETS - 1; i > 0; i--)
1736 if (pci_devs[0].pdev[i]) {
1737 sockets = i + 1;
1738 break;
1739 }
1740 1788
1741 for (i = 0; i < sockets; i++) { 1789 for (i = 0; i < sockets; i++) {
1742 int channels; 1790 int channels;
@@ -1745,7 +1793,7 @@ static int __devinit i7core_probe(struct pci_dev *pdev,
1745 /* Check the number of active and not disabled channels */ 1793 /* Check the number of active and not disabled channels */
1746 rc = i7core_get_active_channels(i, &channels, &csrows); 1794 rc = i7core_get_active_channels(i, &channels, &csrows);
1747 if (unlikely(rc < 0)) 1795 if (unlikely(rc < 0))
1748 goto fail0; 1796 goto fail1;
1749 1797
1750 num_channels += channels; 1798 num_channels += channels;
1751 num_csrows += csrows; 1799 num_csrows += csrows;
@@ -1755,7 +1803,7 @@ static int __devinit i7core_probe(struct pci_dev *pdev,
1755 mci = edac_mc_alloc(sizeof(*pvt), num_csrows, num_channels, 0); 1803 mci = edac_mc_alloc(sizeof(*pvt), num_csrows, num_channels, 0);
1756 if (unlikely(!mci)) { 1804 if (unlikely(!mci)) {
1757 rc = -ENOMEM; 1805 rc = -ENOMEM;
1758 goto fail0; 1806 goto fail1;
1759 } 1807 }
1760 1808
1761 debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci); 1809 debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci);
@@ -1776,7 +1824,7 @@ static int __devinit i7core_probe(struct pci_dev *pdev,
1776 mci->edac_cap = EDAC_FLAG_NONE; 1824 mci->edac_cap = EDAC_FLAG_NONE;
1777 mci->mod_name = "i7core_edac.c"; 1825 mci->mod_name = "i7core_edac.c";
1778 mci->mod_ver = I7CORE_REVISION; 1826 mci->mod_ver = I7CORE_REVISION;
1779 mci->ctl_name = i7core_devs[dev_idx].ctl_name; 1827 mci->ctl_name = i7core_probe_devs[dev_idx].ctl_name;
1780 mci->dev_name = pci_name(pdev); 1828 mci->dev_name = pci_name(pdev);
1781 mci->ctl_page_to_phys = NULL; 1829 mci->ctl_page_to_phys = NULL;
1782 mci->mc_driver_sysfs_attributes = i7core_inj_attrs; 1830 mci->mc_driver_sysfs_attributes = i7core_inj_attrs;
@@ -1786,7 +1834,7 @@ static int __devinit i7core_probe(struct pci_dev *pdev,
1786 /* Store pci devices at mci for faster access */ 1834 /* Store pci devices at mci for faster access */
1787 rc = mci_bind_devs(mci); 1835 rc = mci_bind_devs(mci);
1788 if (unlikely(rc < 0)) 1836 if (unlikely(rc < 0))
1789 goto fail1; 1837 goto fail2;
1790 1838
1791 /* Get dimm basic config */ 1839 /* Get dimm basic config */
1792 for (i = 0; i < sockets; i++) 1840 for (i = 0; i < sockets; i++)
@@ -1801,7 +1849,7 @@ static int __devinit i7core_probe(struct pci_dev *pdev,
1801 */ 1849 */
1802 1850
1803 rc = -EINVAL; 1851 rc = -EINVAL;
1804 goto fail1; 1852 goto fail2;
1805 } 1853 }
1806 1854
1807 /* allocating generic PCI control info */ 1855 /* allocating generic PCI control info */
@@ -1832,18 +1880,21 @@ static int __devinit i7core_probe(struct pci_dev *pdev,
1832 if (unlikely(rc < 0)) { 1880 if (unlikely(rc < 0)) {
1833 debugf0("MC: " __FILE__ 1881 debugf0("MC: " __FILE__
1834 ": %s(): failed edac_mce_register()\n", __func__); 1882 ": %s(): failed edac_mce_register()\n", __func__);
1835 goto fail1; 1883 goto fail2;
1836 } 1884 }
1837 1885
1838 i7core_printk(KERN_INFO, "Driver loaded.\n"); 1886 i7core_printk(KERN_INFO, "Driver loaded.\n");
1839 1887
1888 mutex_unlock(&i7core_edac_lock);
1840 return 0; 1889 return 0;
1841 1890
1842fail1: 1891fail2:
1843 edac_mc_free(mci); 1892 edac_mc_free(mci);
1844 1893
1845fail0: 1894fail1:
1846 i7core_put_devices(); 1895 i7core_put_devices();
1896fail0:
1897 mutex_unlock(&i7core_edac_lock);
1847 return rc; 1898 return rc;
1848} 1899}
1849 1900
@@ -1871,7 +1922,9 @@ static void __devexit i7core_remove(struct pci_dev *pdev)
1871 edac_mce_unregister(&pvt->edac_mce); 1922 edac_mce_unregister(&pvt->edac_mce);
1872 1923
1873 /* retrieve references to resources, and free those resources */ 1924 /* retrieve references to resources, and free those resources */
1925 mutex_lock(&i7core_edac_lock);
1874 i7core_put_devices(); 1926 i7core_put_devices();
1927 mutex_unlock(&i7core_edac_lock);
1875 1928
1876 edac_mc_free(mci); 1929 edac_mc_free(mci);
1877} 1930}