diff options
Diffstat (limited to 'drivers/acpi/acpi_ipmi.c')
-rw-r--r-- | drivers/acpi/acpi_ipmi.c | 81 |
1 files changed, 34 insertions, 47 deletions
diff --git a/drivers/acpi/acpi_ipmi.c b/drivers/acpi/acpi_ipmi.c index b285386eb37f..7ec4cd1e7245 100644 --- a/drivers/acpi/acpi_ipmi.c +++ b/drivers/acpi/acpi_ipmi.c | |||
@@ -46,7 +46,6 @@ MODULE_AUTHOR("Zhao Yakui"); | |||
46 | MODULE_DESCRIPTION("ACPI IPMI Opregion driver"); | 46 | MODULE_DESCRIPTION("ACPI IPMI Opregion driver"); |
47 | MODULE_LICENSE("GPL"); | 47 | MODULE_LICENSE("GPL"); |
48 | 48 | ||
49 | #define IPMI_FLAGS_HANDLER_INSTALL 0 | ||
50 | 49 | ||
51 | #define ACPI_IPMI_OK 0 | 50 | #define ACPI_IPMI_OK 0 |
52 | #define ACPI_IPMI_TIMEOUT 0x10 | 51 | #define ACPI_IPMI_TIMEOUT 0x10 |
@@ -66,7 +65,6 @@ struct acpi_ipmi_device { | |||
66 | ipmi_user_t user_interface; | 65 | ipmi_user_t user_interface; |
67 | int ipmi_ifnum; /* IPMI interface number */ | 66 | int ipmi_ifnum; /* IPMI interface number */ |
68 | long curr_msgid; | 67 | long curr_msgid; |
69 | unsigned long flags; | ||
70 | struct ipmi_smi_info smi_data; | 68 | struct ipmi_smi_info smi_data; |
71 | bool dead; | 69 | bool dead; |
72 | struct kref kref; | 70 | struct kref kref; |
@@ -77,6 +75,14 @@ struct ipmi_driver_data { | |||
77 | struct ipmi_smi_watcher bmc_events; | 75 | struct ipmi_smi_watcher bmc_events; |
78 | struct ipmi_user_hndl ipmi_hndlrs; | 76 | struct ipmi_user_hndl ipmi_hndlrs; |
79 | struct mutex ipmi_lock; | 77 | struct mutex ipmi_lock; |
78 | /* | ||
79 | * NOTE: IPMI System Interface Selection | ||
80 | * There is no system interface specified by the IPMI operation | ||
81 | * region access. We try to select one system interface with ACPI | ||
82 | * handle set. IPMI messages passed from the ACPI codes are sent | ||
83 | * to this selected global IPMI system interface. | ||
84 | */ | ||
85 | struct acpi_ipmi_device *selected_smi; | ||
80 | }; | 86 | }; |
81 | 87 | ||
82 | struct acpi_ipmi_msg { | 88 | struct acpi_ipmi_msg { |
@@ -110,8 +116,6 @@ struct acpi_ipmi_buffer { | |||
110 | static void ipmi_register_bmc(int iface, struct device *dev); | 116 | static void ipmi_register_bmc(int iface, struct device *dev); |
111 | static void ipmi_bmc_gone(int iface); | 117 | static void ipmi_bmc_gone(int iface); |
112 | static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data); | 118 | static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data); |
113 | static int ipmi_install_space_handler(struct acpi_ipmi_device *ipmi); | ||
114 | static void ipmi_remove_space_handler(struct acpi_ipmi_device *ipmi); | ||
115 | 119 | ||
116 | static struct ipmi_driver_data driver_data = { | 120 | static struct ipmi_driver_data driver_data = { |
117 | .ipmi_devices = LIST_HEAD_INIT(driver_data.ipmi_devices), | 121 | .ipmi_devices = LIST_HEAD_INIT(driver_data.ipmi_devices), |
@@ -154,14 +158,12 @@ ipmi_dev_alloc(int iface, struct ipmi_smi_info *smi_data, acpi_handle handle) | |||
154 | return NULL; | 158 | return NULL; |
155 | } | 159 | } |
156 | ipmi_device->user_interface = user; | 160 | ipmi_device->user_interface = user; |
157 | ipmi_install_space_handler(ipmi_device); | ||
158 | 161 | ||
159 | return ipmi_device; | 162 | return ipmi_device; |
160 | } | 163 | } |
161 | 164 | ||
162 | static void ipmi_dev_release(struct acpi_ipmi_device *ipmi_device) | 165 | static void ipmi_dev_release(struct acpi_ipmi_device *ipmi_device) |
163 | { | 166 | { |
164 | ipmi_remove_space_handler(ipmi_device); | ||
165 | ipmi_destroy_user(ipmi_device->user_interface); | 167 | ipmi_destroy_user(ipmi_device->user_interface); |
166 | put_device(ipmi_device->smi_data.dev); | 168 | put_device(ipmi_device->smi_data.dev); |
167 | kfree(ipmi_device); | 169 | kfree(ipmi_device); |
@@ -178,6 +180,8 @@ static void ipmi_dev_release_kref(struct kref *kref) | |||
178 | static void __ipmi_dev_kill(struct acpi_ipmi_device *ipmi_device) | 180 | static void __ipmi_dev_kill(struct acpi_ipmi_device *ipmi_device) |
179 | { | 181 | { |
180 | list_del(&ipmi_device->head); | 182 | list_del(&ipmi_device->head); |
183 | if (driver_data.selected_smi == ipmi_device) | ||
184 | driver_data.selected_smi = NULL; | ||
181 | /* | 185 | /* |
182 | * Always setting dead flag after deleting from the list or | 186 | * Always setting dead flag after deleting from the list or |
183 | * list_for_each_entry() codes must get changed. | 187 | * list_for_each_entry() codes must get changed. |
@@ -185,17 +189,14 @@ static void __ipmi_dev_kill(struct acpi_ipmi_device *ipmi_device) | |||
185 | ipmi_device->dead = true; | 189 | ipmi_device->dead = true; |
186 | } | 190 | } |
187 | 191 | ||
188 | static struct acpi_ipmi_device *acpi_ipmi_dev_get(int iface) | 192 | static struct acpi_ipmi_device *acpi_ipmi_dev_get(void) |
189 | { | 193 | { |
190 | struct acpi_ipmi_device *temp, *ipmi_device = NULL; | 194 | struct acpi_ipmi_device *ipmi_device = NULL; |
191 | 195 | ||
192 | mutex_lock(&driver_data.ipmi_lock); | 196 | mutex_lock(&driver_data.ipmi_lock); |
193 | list_for_each_entry(temp, &driver_data.ipmi_devices, head) { | 197 | if (driver_data.selected_smi) { |
194 | if (temp->ipmi_ifnum == iface) { | 198 | ipmi_device = driver_data.selected_smi; |
195 | ipmi_device = temp; | 199 | kref_get(&ipmi_device->kref); |
196 | kref_get(&ipmi_device->kref); | ||
197 | break; | ||
198 | } | ||
199 | } | 200 | } |
200 | mutex_unlock(&driver_data.ipmi_lock); | 201 | mutex_unlock(&driver_data.ipmi_lock); |
201 | 202 | ||
@@ -416,6 +417,8 @@ static void ipmi_register_bmc(int iface, struct device *dev) | |||
416 | goto err_lock; | 417 | goto err_lock; |
417 | } | 418 | } |
418 | 419 | ||
420 | if (!driver_data.selected_smi) | ||
421 | driver_data.selected_smi = ipmi_device; | ||
419 | list_add_tail(&ipmi_device->head, &driver_data.ipmi_devices); | 422 | list_add_tail(&ipmi_device->head, &driver_data.ipmi_devices); |
420 | mutex_unlock(&driver_data.ipmi_lock); | 423 | mutex_unlock(&driver_data.ipmi_lock); |
421 | put_device(smi_data.dev); | 424 | put_device(smi_data.dev); |
@@ -443,6 +446,10 @@ static void ipmi_bmc_gone(int iface) | |||
443 | break; | 446 | break; |
444 | } | 447 | } |
445 | } | 448 | } |
449 | if (!driver_data.selected_smi) | ||
450 | driver_data.selected_smi = list_first_entry_or_null( | ||
451 | &driver_data.ipmi_devices, | ||
452 | struct acpi_ipmi_device, head); | ||
446 | mutex_unlock(&driver_data.ipmi_lock); | 453 | mutex_unlock(&driver_data.ipmi_lock); |
447 | if (dev_found) { | 454 | if (dev_found) { |
448 | ipmi_flush_tx_msg(ipmi_device); | 455 | ipmi_flush_tx_msg(ipmi_device); |
@@ -471,7 +478,6 @@ acpi_ipmi_space_handler(u32 function, acpi_physical_address address, | |||
471 | void *handler_context, void *region_context) | 478 | void *handler_context, void *region_context) |
472 | { | 479 | { |
473 | struct acpi_ipmi_msg *tx_msg; | 480 | struct acpi_ipmi_msg *tx_msg; |
474 | int iface = (long)handler_context; | ||
475 | struct acpi_ipmi_device *ipmi_device; | 481 | struct acpi_ipmi_device *ipmi_device; |
476 | int err; | 482 | int err; |
477 | acpi_status status; | 483 | acpi_status status; |
@@ -485,7 +491,7 @@ acpi_ipmi_space_handler(u32 function, acpi_physical_address address, | |||
485 | if ((function & ACPI_IO_MASK) == ACPI_READ) | 491 | if ((function & ACPI_IO_MASK) == ACPI_READ) |
486 | return AE_TYPE; | 492 | return AE_TYPE; |
487 | 493 | ||
488 | ipmi_device = acpi_ipmi_dev_get(iface); | 494 | ipmi_device = acpi_ipmi_dev_get(); |
489 | if (!ipmi_device) | 495 | if (!ipmi_device) |
490 | return AE_NOT_EXIST; | 496 | return AE_NOT_EXIST; |
491 | 497 | ||
@@ -534,47 +540,26 @@ out_ref: | |||
534 | return status; | 540 | return status; |
535 | } | 541 | } |
536 | 542 | ||
537 | static void ipmi_remove_space_handler(struct acpi_ipmi_device *ipmi) | ||
538 | { | ||
539 | if (!test_bit(IPMI_FLAGS_HANDLER_INSTALL, &ipmi->flags)) | ||
540 | return; | ||
541 | |||
542 | acpi_remove_address_space_handler(ipmi->handle, | ||
543 | ACPI_ADR_SPACE_IPMI, &acpi_ipmi_space_handler); | ||
544 | |||
545 | clear_bit(IPMI_FLAGS_HANDLER_INSTALL, &ipmi->flags); | ||
546 | } | ||
547 | |||
548 | static int ipmi_install_space_handler(struct acpi_ipmi_device *ipmi) | ||
549 | { | ||
550 | acpi_status status; | ||
551 | |||
552 | if (test_bit(IPMI_FLAGS_HANDLER_INSTALL, &ipmi->flags)) | ||
553 | return 0; | ||
554 | |||
555 | status = acpi_install_address_space_handler(ipmi->handle, | ||
556 | ACPI_ADR_SPACE_IPMI, &acpi_ipmi_space_handler, | ||
557 | NULL, (void *)((long)ipmi->ipmi_ifnum)); | ||
558 | if (ACPI_FAILURE(status)) { | ||
559 | struct pnp_dev *pnp_dev = ipmi->pnp_dev; | ||
560 | dev_warn(&pnp_dev->dev, "Can't register IPMI opregion space " | ||
561 | "handle\n"); | ||
562 | return -EINVAL; | ||
563 | } | ||
564 | set_bit(IPMI_FLAGS_HANDLER_INSTALL, &ipmi->flags); | ||
565 | return 0; | ||
566 | } | ||
567 | |||
568 | static int __init acpi_ipmi_init(void) | 543 | static int __init acpi_ipmi_init(void) |
569 | { | 544 | { |
570 | int result = 0; | 545 | int result = 0; |
546 | acpi_status status; | ||
571 | 547 | ||
572 | if (acpi_disabled) | 548 | if (acpi_disabled) |
573 | return result; | 549 | return result; |
574 | 550 | ||
575 | mutex_init(&driver_data.ipmi_lock); | 551 | mutex_init(&driver_data.ipmi_lock); |
576 | 552 | ||
553 | status = acpi_install_address_space_handler(ACPI_ROOT_OBJECT, | ||
554 | ACPI_ADR_SPACE_IPMI, &acpi_ipmi_space_handler, | ||
555 | NULL, NULL); | ||
556 | if (ACPI_FAILURE(status)) { | ||
557 | pr_warn("Can't register IPMI opregion space handle\n"); | ||
558 | return -EINVAL; | ||
559 | } | ||
577 | result = ipmi_smi_watcher_register(&driver_data.bmc_events); | 560 | result = ipmi_smi_watcher_register(&driver_data.bmc_events); |
561 | if (result) | ||
562 | pr_err("Can't register IPMI system interface watcher\n"); | ||
578 | 563 | ||
579 | return result; | 564 | return result; |
580 | } | 565 | } |
@@ -608,6 +593,8 @@ static void __exit acpi_ipmi_exit(void) | |||
608 | mutex_lock(&driver_data.ipmi_lock); | 593 | mutex_lock(&driver_data.ipmi_lock); |
609 | } | 594 | } |
610 | mutex_unlock(&driver_data.ipmi_lock); | 595 | mutex_unlock(&driver_data.ipmi_lock); |
596 | acpi_remove_address_space_handler(ACPI_ROOT_OBJECT, | ||
597 | ACPI_ADR_SPACE_IPMI, &acpi_ipmi_space_handler); | ||
611 | } | 598 | } |
612 | 599 | ||
613 | module_init(acpi_ipmi_init); | 600 | module_init(acpi_ipmi_init); |