diff options
-rw-r--r-- | drivers/char/ipmi/ipmi_msghandler.c | 51 |
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 | */ | ||
529 | static DEFINE_MUTEX(ipmidriver_mutex); | 534 | static DEFINE_MUTEX(ipmidriver_mutex); |
530 | 535 | ||
531 | static LIST_HEAD(ipmi_interfaces); | 536 | static 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 | */ | ||
2443 | static struct bmc_device *ipmi_find_bmc_guid(struct device_driver *drv, | 2452 | static 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 | ||
2455 | struct prod_dev_id { | 2467 | struct 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 | */ | ||
2473 | static struct bmc_device *ipmi_find_bmc_prod_dev_id( | 2489 | static 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 | ||
2490 | static void | 2509 | static 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 | ||
2521 | static int ipmi_bmc_register(ipmi_smi_t intf, int ifnum) | 2540 | static 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" |