aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/char/ipmi/ipmi_msghandler.c51
1 files changed, 35 insertions, 16 deletions
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index efa5581c2f8b..42532f296e93 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -526,6 +526,11 @@ static struct platform_driver ipmidriver = {
526 .bus = &platform_bus_type 526 .bus = &platform_bus_type
527 } 527 }
528}; 528};
529/*
530 * This mutex protects adding/removing BMCs on the ipmidriver's device
531 * list. This way we can pull items out of the driver's list and reuse
532 * them.
533 */
529static DEFINE_MUTEX(ipmidriver_mutex); 534static DEFINE_MUTEX(ipmidriver_mutex);
530 535
531static LIST_HEAD(ipmi_interfaces); 536static LIST_HEAD(ipmi_interfaces);
@@ -2440,16 +2445,23 @@ static int __find_bmc_guid(struct device *dev, void *data)
2440 return memcmp(to_bmc_device(dev)->guid, id, 16) == 0; 2445 return memcmp(to_bmc_device(dev)->guid, id, 16) == 0;
2441} 2446}
2442 2447
2448/*
2449 * Must be called with ipmidriver_mutex held. Returns with the
2450 * bmc's usecount incremented, if it is non-NULL.
2451 */
2443static struct bmc_device *ipmi_find_bmc_guid(struct device_driver *drv, 2452static struct bmc_device *ipmi_find_bmc_guid(struct device_driver *drv,
2444 unsigned char *guid) 2453 unsigned char *guid)
2445{ 2454{
2446 struct device *dev; 2455 struct device *dev;
2456 struct bmc_device *bmc = NULL;
2447 2457
2448 dev = driver_find_device(drv, NULL, guid, __find_bmc_guid); 2458 dev = driver_find_device(drv, NULL, guid, __find_bmc_guid);
2449 if (dev) 2459 if (dev) {
2450 return to_bmc_device(dev); 2460 bmc = to_bmc_device(dev);
2451 else 2461 kref_get(&bmc->usecount);
2452 return NULL; 2462 put_device(dev);
2463 }
2464 return bmc;
2453} 2465}
2454 2466
2455struct prod_dev_id { 2467struct prod_dev_id {
@@ -2470,6 +2482,10 @@ static int __find_bmc_prod_dev_id(struct device *dev, void *data)
2470 && bmc->id.device_id == id->device_id); 2482 && bmc->id.device_id == id->device_id);
2471} 2483}
2472 2484
2485/*
2486 * Must be called with ipmidriver_mutex held. Returns with the
2487 * bmc's usecount incremented, if it is non-NULL.
2488 */
2473static struct bmc_device *ipmi_find_bmc_prod_dev_id( 2489static struct bmc_device *ipmi_find_bmc_prod_dev_id(
2474 struct device_driver *drv, 2490 struct device_driver *drv,
2475 unsigned int product_id, unsigned char device_id) 2491 unsigned int product_id, unsigned char device_id)
@@ -2479,12 +2495,15 @@ static struct bmc_device *ipmi_find_bmc_prod_dev_id(
2479 .device_id = device_id, 2495 .device_id = device_id,
2480 }; 2496 };
2481 struct device *dev; 2497 struct device *dev;
2498 struct bmc_device *bmc = NULL;
2482 2499
2483 dev = driver_find_device(drv, NULL, &id, __find_bmc_prod_dev_id); 2500 dev = driver_find_device(drv, NULL, &id, __find_bmc_prod_dev_id);
2484 if (dev) 2501 if (dev) {
2485 return to_bmc_device(dev); 2502 bmc = to_bmc_device(dev);
2486 else 2503 kref_get(&bmc->usecount);
2487 return NULL; 2504 put_device(dev);
2505 }
2506 return bmc;
2488} 2507}
2489 2508
2490static void 2509static void
@@ -2514,8 +2533,8 @@ static void ipmi_bmc_unregister(ipmi_smi_t intf)
2514 2533
2515 mutex_lock(&ipmidriver_mutex); 2534 mutex_lock(&ipmidriver_mutex);
2516 kref_put(&bmc->usecount, cleanup_bmc_device); 2535 kref_put(&bmc->usecount, cleanup_bmc_device);
2517 intf->bmc = NULL;
2518 mutex_unlock(&ipmidriver_mutex); 2536 mutex_unlock(&ipmidriver_mutex);
2537 intf->bmc = NULL;
2519} 2538}
2520 2539
2521static int ipmi_bmc_register(ipmi_smi_t intf, int ifnum) 2540static int ipmi_bmc_register(ipmi_smi_t intf, int ifnum)
@@ -2524,18 +2543,18 @@ static int ipmi_bmc_register(ipmi_smi_t intf, int ifnum)
2524 struct bmc_device *bmc = intf->bmc; 2543 struct bmc_device *bmc = intf->bmc;
2525 struct bmc_device *old_bmc; 2544 struct bmc_device *old_bmc;
2526 2545
2527 mutex_lock(&ipmidriver_mutex);
2528
2529 /* 2546 /*
2530 * Try to find if there is an bmc_device struct 2547 * Try to find if there is an bmc_device struct
2531 * representing the interfaced BMC already 2548 * representing the interfaced BMC already
2532 */ 2549 */
2550 mutex_lock(&ipmidriver_mutex);
2533 if (bmc->guid_set) 2551 if (bmc->guid_set)
2534 old_bmc = ipmi_find_bmc_guid(&ipmidriver.driver, bmc->guid); 2552 old_bmc = ipmi_find_bmc_guid(&ipmidriver.driver, bmc->guid);
2535 else 2553 else
2536 old_bmc = ipmi_find_bmc_prod_dev_id(&ipmidriver.driver, 2554 old_bmc = ipmi_find_bmc_prod_dev_id(&ipmidriver.driver,
2537 bmc->id.product_id, 2555 bmc->id.product_id,
2538 bmc->id.device_id); 2556 bmc->id.device_id);
2557 mutex_unlock(&ipmidriver_mutex);
2539 2558
2540 /* 2559 /*
2541 * If there is already an bmc_device, free the new one, 2560 * If there is already an bmc_device, free the new one,
@@ -2546,9 +2565,6 @@ static int ipmi_bmc_register(ipmi_smi_t intf, int ifnum)
2546 intf->bmc = old_bmc; 2565 intf->bmc = old_bmc;
2547 bmc = old_bmc; 2566 bmc = old_bmc;
2548 2567
2549 kref_get(&bmc->usecount);
2550 mutex_unlock(&ipmidriver_mutex);
2551
2552 printk(KERN_INFO 2568 printk(KERN_INFO
2553 "ipmi: interfacing existing BMC (man_id: 0x%6.6x," 2569 "ipmi: interfacing existing BMC (man_id: 0x%6.6x,"
2554 " prod_id: 0x%4.4x, dev_id: 0x%2.2x)\n", 2570 " prod_id: 0x%4.4x, dev_id: 0x%2.2x)\n",
@@ -2558,14 +2574,17 @@ static int ipmi_bmc_register(ipmi_smi_t intf, int ifnum)
2558 } else { 2574 } else {
2559 unsigned char orig_dev_id = bmc->id.device_id; 2575 unsigned char orig_dev_id = bmc->id.device_id;
2560 int warn_printed = 0; 2576 int warn_printed = 0;
2577 struct bmc_device *tmp_bmc;
2561 2578
2562 snprintf(bmc->name, sizeof(bmc->name), 2579 snprintf(bmc->name, sizeof(bmc->name),
2563 "ipmi_bmc.%4.4x", bmc->id.product_id); 2580 "ipmi_bmc.%4.4x", bmc->id.product_id);
2564 bmc->pdev.name = bmc->name; 2581 bmc->pdev.name = bmc->name;
2565 2582
2566 while (ipmi_find_bmc_prod_dev_id(&ipmidriver.driver, 2583 mutex_lock(&ipmidriver_mutex);
2584 while ((tmp_bmc = ipmi_find_bmc_prod_dev_id(&ipmidriver.driver,
2567 bmc->id.product_id, 2585 bmc->id.product_id,
2568 bmc->id.device_id)) { 2586 bmc->id.device_id))) {
2587 kref_put(&tmp_bmc->usecount, cleanup_bmc_device);
2569 if (!warn_printed) { 2588 if (!warn_printed) {
2570 printk(KERN_WARNING PFX 2589 printk(KERN_WARNING PFX
2571 "This machine has two different BMCs" 2590 "This machine has two different BMCs"