Loading drivers/acpi/acpi_ipmi.c +65 −40 Original line number Diff line number Diff line Loading @@ -33,7 +33,6 @@ MODULE_AUTHOR("Zhao Yakui"); MODULE_DESCRIPTION("ACPI IPMI Opregion driver"); MODULE_LICENSE("GPL"); #define ACPI_IPMI_OK 0 #define ACPI_IPMI_TIMEOUT 0x10 #define ACPI_IPMI_UNKNOWN 0x07 Loading @@ -44,8 +43,10 @@ MODULE_LICENSE("GPL"); struct acpi_ipmi_device { /* the device list attached to driver_data.ipmi_devices */ struct list_head head; /* the IPMI request message list */ struct list_head tx_msg_list; spinlock_t tx_msg_lock; acpi_handle handle; struct device *dev; Loading @@ -61,6 +62,7 @@ struct ipmi_driver_data { struct ipmi_smi_watcher bmc_events; struct ipmi_user_hndl ipmi_hndlrs; struct mutex ipmi_lock; /* * NOTE: IPMI System Interface Selection * There is no system interface specified by the IPMI operation Loading @@ -73,6 +75,7 @@ struct ipmi_driver_data { struct acpi_ipmi_msg { struct list_head head; /* * General speaking the addr type should be SI_ADDR_TYPE. And * the addr channel should be BMC. Loading @@ -82,13 +85,17 @@ struct acpi_ipmi_msg { */ struct ipmi_addr addr; long tx_msgid; /* it is used to track whether the IPMI message is finished */ struct completion tx_complete; struct kernel_ipmi_msg tx_message; int msg_done; /* tx/rx data . And copy it from/to ACPI object buffer */ u8 data[ACPI_IPMI_MAX_MSG_LENGTH]; u8 rx_len; struct acpi_ipmi_device *device; struct kref kref; }; Loading Loading @@ -132,7 +139,6 @@ ipmi_dev_alloc(int iface, struct device *dev, acpi_handle handle) INIT_LIST_HEAD(&ipmi_device->head); INIT_LIST_HEAD(&ipmi_device->tx_msg_list); spin_lock_init(&ipmi_device->tx_msg_lock); ipmi_device->handle = handle; ipmi_device->dev = get_device(dev); ipmi_device->ipmi_ifnum = iface; Loading Loading @@ -169,6 +175,7 @@ static void __ipmi_dev_kill(struct acpi_ipmi_device *ipmi_device) list_del(&ipmi_device->head); if (driver_data.selected_smi == ipmi_device) driver_data.selected_smi = NULL; /* * Always setting dead flag after deleting from the list or * list_for_each_entry() codes must get changed. Loading Loading @@ -203,16 +210,19 @@ static struct acpi_ipmi_msg *ipmi_msg_alloc(void) ipmi = acpi_ipmi_dev_get(); if (!ipmi) return NULL; ipmi_msg = kzalloc(sizeof(struct acpi_ipmi_msg), GFP_KERNEL); if (!ipmi_msg) { acpi_ipmi_dev_put(ipmi); return NULL; } kref_init(&ipmi_msg->kref); init_completion(&ipmi_msg->tx_complete); INIT_LIST_HEAD(&ipmi_msg->head); ipmi_msg->device = ipmi; ipmi_msg->msg_done = ACPI_IPMI_UNKNOWN; return ipmi_msg; } Loading Loading @@ -254,6 +264,7 @@ static int acpi_format_ipmi_request(struct acpi_ipmi_msg *tx_msg, unsigned long flags; msg = &tx_msg->tx_message; /* * IPMI network function and command are encoded in the address * within the IPMI OpRegion; see ACPI 4.0, sec 5.5.2.4.3. Loading @@ -261,11 +272,13 @@ static int acpi_format_ipmi_request(struct acpi_ipmi_msg *tx_msg, msg->netfn = IPMI_OP_RGN_NETFN(address); msg->cmd = IPMI_OP_RGN_CMD(address); msg->data = tx_msg->data; /* * value is the parameter passed by the IPMI opregion space handler. * It points to the IPMI request message buffer */ buffer = (struct acpi_ipmi_buffer *)value; /* copy the tx message data */ if (buffer->length > ACPI_IPMI_MAX_MSG_LENGTH) { dev_WARN_ONCE(tx_msg->device->dev, true, Loading @@ -275,6 +288,7 @@ static int acpi_format_ipmi_request(struct acpi_ipmi_msg *tx_msg, } msg->data_len = buffer->length; memcpy(tx_msg->data, buffer->data, msg->data_len); /* * now the default type is SYSTEM_INTERFACE and channel type is BMC. * If the netfn is APP_REQUEST and the cmd is SEND_MESSAGE, Loading @@ -288,10 +302,12 @@ static int acpi_format_ipmi_request(struct acpi_ipmi_msg *tx_msg, /* Get the msgid */ device = tx_msg->device; spin_lock_irqsave(&device->tx_msg_lock, flags); device->curr_msgid++; tx_msg->tx_msgid = device->curr_msgid; spin_unlock_irqrestore(&device->tx_msg_lock, flags); return 0; } Loading @@ -305,6 +321,7 @@ static void acpi_format_ipmi_response(struct acpi_ipmi_msg *msg, * IPMI message returned by IPMI command. */ buffer = (struct acpi_ipmi_buffer *)value; /* * If the flag of msg_done is not set, it means that the IPMI command is * not executed correctly. Loading @@ -312,6 +329,7 @@ static void acpi_format_ipmi_response(struct acpi_ipmi_msg *msg, buffer->status = msg->msg_done; if (msg->msg_done != ACPI_IPMI_OK) return; /* * If the IPMI response message is obtained correctly, the status code * will be ACPI_IPMI_OK Loading Loading @@ -379,11 +397,12 @@ static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data) unsigned long flags; if (msg->user != ipmi_device->user_interface) { dev_warn(dev, "Unexpected response is returned. " "returned user %p, expected user %p\n", dev_warn(dev, "Unexpected response is returned. returned user %p, expected user %p\n", msg->user, ipmi_device->user_interface); goto out_msg; } spin_lock_irqsave(&ipmi_device->tx_msg_lock, flags); list_for_each_entry_safe(tx_msg, temp, &ipmi_device->tx_msg_list, head) { if (msg->msgid == tx_msg->tx_msgid) { Loading @@ -395,8 +414,9 @@ static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data) spin_unlock_irqrestore(&ipmi_device->tx_msg_lock, flags); if (!msg_found) { dev_warn(dev, "Unexpected response (msg id %ld) is " "returned.\n", msg->msgid); dev_warn(dev, "Unexpected response (msg id %ld) is returned.\n", msg->msgid); goto out_msg; } Loading @@ -407,6 +427,7 @@ static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data) msg->msg.data_len); goto out_comp; } /* response msg is an error msg */ msg->recv_type = IPMI_RESPONSE_RECV_TYPE; if (msg->recv_type == IPMI_RESPONSE_RECV_TYPE && Loading @@ -418,15 +439,17 @@ static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data) } goto out_comp; } tx_msg->rx_len = msg->msg.data_len; memcpy(tx_msg->data, msg->msg.data, tx_msg->rx_len); tx_msg->msg_done = ACPI_IPMI_OK; out_comp: complete(&tx_msg->tx_complete); acpi_ipmi_msg_put(tx_msg); out_msg: ipmi_free_recv_msg(msg); }; } static void ipmi_register_bmc(int iface, struct device *dev) { Loading @@ -436,7 +459,6 @@ static void ipmi_register_bmc(int iface, struct device *dev) acpi_handle handle; err = ipmi_get_smi_info(iface, &smi_data); if (err) return; Loading @@ -461,11 +483,11 @@ static void ipmi_register_bmc(int iface, struct device *dev) if (temp->handle == handle) goto err_lock; } if (!driver_data.selected_smi) driver_data.selected_smi = ipmi_device; list_add_tail(&ipmi_device->head, &driver_data.ipmi_devices); mutex_unlock(&driver_data.ipmi_lock); put_device(smi_data.dev); return; Loading Loading @@ -496,14 +518,13 @@ static void ipmi_bmc_gone(int iface) &driver_data.ipmi_devices, struct acpi_ipmi_device, head); mutex_unlock(&driver_data.ipmi_lock); if (dev_found) { ipmi_flush_tx_msg(ipmi_device); acpi_ipmi_dev_put(ipmi_device); } } /* -------------------------------------------------------------------------- * Address Space Management * -------------------------------------------------------------------------- */ /* * This is the IPMI opregion space handler. * @function: indicates the read/write. In fact as the IPMI message is driven Loading @@ -516,7 +537,6 @@ static void ipmi_bmc_gone(int iface) * the response IPMI message returned by IPMI command. * @handler_context: IPMI device context. */ static acpi_status acpi_ipmi_space_handler(u32 function, acpi_physical_address address, u32 bits, acpi_integer *value, Loading @@ -527,6 +547,7 @@ acpi_ipmi_space_handler(u32 function, acpi_physical_address address, int err; acpi_status status; unsigned long flags; /* * IPMI opregion message. * IPMI message is firstly written to the BMC and system software Loading @@ -539,13 +560,13 @@ acpi_ipmi_space_handler(u32 function, acpi_physical_address address, tx_msg = ipmi_msg_alloc(); if (!tx_msg) return AE_NOT_EXIST; ipmi_device = tx_msg->device; if (acpi_format_ipmi_request(tx_msg, address, value) != 0) { ipmi_msg_release(tx_msg); return AE_TYPE; } acpi_ipmi_msg_get(tx_msg); mutex_lock(&driver_data.ipmi_lock); /* Do not add a tx_msg that can not be flushed. */ Loading @@ -558,6 +579,7 @@ acpi_ipmi_space_handler(u32 function, acpi_physical_address address, list_add_tail(&tx_msg->head, &ipmi_device->tx_msg_list); spin_unlock_irqrestore(&ipmi_device->tx_msg_lock, flags); mutex_unlock(&driver_data.ipmi_lock); err = ipmi_request_settime(ipmi_device->user_interface, &tx_msg->addr, tx_msg->tx_msgid, Loading @@ -568,6 +590,7 @@ acpi_ipmi_space_handler(u32 function, acpi_physical_address address, goto out_msg; } wait_for_completion(&tx_msg->tx_complete); acpi_format_ipmi_response(tx_msg, value); status = AE_OK; Loading @@ -586,7 +609,8 @@ static int __init acpi_ipmi_init(void) return 0; status = acpi_install_address_space_handler(ACPI_ROOT_OBJECT, ACPI_ADR_SPACE_IPMI, &acpi_ipmi_space_handler, ACPI_ADR_SPACE_IPMI, &acpi_ipmi_space_handler, NULL, NULL); if (ACPI_FAILURE(status)) { pr_warn("Can't register IPMI opregion space handle\n"); Loading Loading @@ -629,7 +653,8 @@ static void __exit acpi_ipmi_exit(void) } mutex_unlock(&driver_data.ipmi_lock); acpi_remove_address_space_handler(ACPI_ROOT_OBJECT, ACPI_ADR_SPACE_IPMI, &acpi_ipmi_space_handler); ACPI_ADR_SPACE_IPMI, &acpi_ipmi_space_handler); } module_init(acpi_ipmi_init); Loading Loading
drivers/acpi/acpi_ipmi.c +65 −40 Original line number Diff line number Diff line Loading @@ -33,7 +33,6 @@ MODULE_AUTHOR("Zhao Yakui"); MODULE_DESCRIPTION("ACPI IPMI Opregion driver"); MODULE_LICENSE("GPL"); #define ACPI_IPMI_OK 0 #define ACPI_IPMI_TIMEOUT 0x10 #define ACPI_IPMI_UNKNOWN 0x07 Loading @@ -44,8 +43,10 @@ MODULE_LICENSE("GPL"); struct acpi_ipmi_device { /* the device list attached to driver_data.ipmi_devices */ struct list_head head; /* the IPMI request message list */ struct list_head tx_msg_list; spinlock_t tx_msg_lock; acpi_handle handle; struct device *dev; Loading @@ -61,6 +62,7 @@ struct ipmi_driver_data { struct ipmi_smi_watcher bmc_events; struct ipmi_user_hndl ipmi_hndlrs; struct mutex ipmi_lock; /* * NOTE: IPMI System Interface Selection * There is no system interface specified by the IPMI operation Loading @@ -73,6 +75,7 @@ struct ipmi_driver_data { struct acpi_ipmi_msg { struct list_head head; /* * General speaking the addr type should be SI_ADDR_TYPE. And * the addr channel should be BMC. Loading @@ -82,13 +85,17 @@ struct acpi_ipmi_msg { */ struct ipmi_addr addr; long tx_msgid; /* it is used to track whether the IPMI message is finished */ struct completion tx_complete; struct kernel_ipmi_msg tx_message; int msg_done; /* tx/rx data . And copy it from/to ACPI object buffer */ u8 data[ACPI_IPMI_MAX_MSG_LENGTH]; u8 rx_len; struct acpi_ipmi_device *device; struct kref kref; }; Loading Loading @@ -132,7 +139,6 @@ ipmi_dev_alloc(int iface, struct device *dev, acpi_handle handle) INIT_LIST_HEAD(&ipmi_device->head); INIT_LIST_HEAD(&ipmi_device->tx_msg_list); spin_lock_init(&ipmi_device->tx_msg_lock); ipmi_device->handle = handle; ipmi_device->dev = get_device(dev); ipmi_device->ipmi_ifnum = iface; Loading Loading @@ -169,6 +175,7 @@ static void __ipmi_dev_kill(struct acpi_ipmi_device *ipmi_device) list_del(&ipmi_device->head); if (driver_data.selected_smi == ipmi_device) driver_data.selected_smi = NULL; /* * Always setting dead flag after deleting from the list or * list_for_each_entry() codes must get changed. Loading Loading @@ -203,16 +210,19 @@ static struct acpi_ipmi_msg *ipmi_msg_alloc(void) ipmi = acpi_ipmi_dev_get(); if (!ipmi) return NULL; ipmi_msg = kzalloc(sizeof(struct acpi_ipmi_msg), GFP_KERNEL); if (!ipmi_msg) { acpi_ipmi_dev_put(ipmi); return NULL; } kref_init(&ipmi_msg->kref); init_completion(&ipmi_msg->tx_complete); INIT_LIST_HEAD(&ipmi_msg->head); ipmi_msg->device = ipmi; ipmi_msg->msg_done = ACPI_IPMI_UNKNOWN; return ipmi_msg; } Loading Loading @@ -254,6 +264,7 @@ static int acpi_format_ipmi_request(struct acpi_ipmi_msg *tx_msg, unsigned long flags; msg = &tx_msg->tx_message; /* * IPMI network function and command are encoded in the address * within the IPMI OpRegion; see ACPI 4.0, sec 5.5.2.4.3. Loading @@ -261,11 +272,13 @@ static int acpi_format_ipmi_request(struct acpi_ipmi_msg *tx_msg, msg->netfn = IPMI_OP_RGN_NETFN(address); msg->cmd = IPMI_OP_RGN_CMD(address); msg->data = tx_msg->data; /* * value is the parameter passed by the IPMI opregion space handler. * It points to the IPMI request message buffer */ buffer = (struct acpi_ipmi_buffer *)value; /* copy the tx message data */ if (buffer->length > ACPI_IPMI_MAX_MSG_LENGTH) { dev_WARN_ONCE(tx_msg->device->dev, true, Loading @@ -275,6 +288,7 @@ static int acpi_format_ipmi_request(struct acpi_ipmi_msg *tx_msg, } msg->data_len = buffer->length; memcpy(tx_msg->data, buffer->data, msg->data_len); /* * now the default type is SYSTEM_INTERFACE and channel type is BMC. * If the netfn is APP_REQUEST and the cmd is SEND_MESSAGE, Loading @@ -288,10 +302,12 @@ static int acpi_format_ipmi_request(struct acpi_ipmi_msg *tx_msg, /* Get the msgid */ device = tx_msg->device; spin_lock_irqsave(&device->tx_msg_lock, flags); device->curr_msgid++; tx_msg->tx_msgid = device->curr_msgid; spin_unlock_irqrestore(&device->tx_msg_lock, flags); return 0; } Loading @@ -305,6 +321,7 @@ static void acpi_format_ipmi_response(struct acpi_ipmi_msg *msg, * IPMI message returned by IPMI command. */ buffer = (struct acpi_ipmi_buffer *)value; /* * If the flag of msg_done is not set, it means that the IPMI command is * not executed correctly. Loading @@ -312,6 +329,7 @@ static void acpi_format_ipmi_response(struct acpi_ipmi_msg *msg, buffer->status = msg->msg_done; if (msg->msg_done != ACPI_IPMI_OK) return; /* * If the IPMI response message is obtained correctly, the status code * will be ACPI_IPMI_OK Loading Loading @@ -379,11 +397,12 @@ static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data) unsigned long flags; if (msg->user != ipmi_device->user_interface) { dev_warn(dev, "Unexpected response is returned. " "returned user %p, expected user %p\n", dev_warn(dev, "Unexpected response is returned. returned user %p, expected user %p\n", msg->user, ipmi_device->user_interface); goto out_msg; } spin_lock_irqsave(&ipmi_device->tx_msg_lock, flags); list_for_each_entry_safe(tx_msg, temp, &ipmi_device->tx_msg_list, head) { if (msg->msgid == tx_msg->tx_msgid) { Loading @@ -395,8 +414,9 @@ static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data) spin_unlock_irqrestore(&ipmi_device->tx_msg_lock, flags); if (!msg_found) { dev_warn(dev, "Unexpected response (msg id %ld) is " "returned.\n", msg->msgid); dev_warn(dev, "Unexpected response (msg id %ld) is returned.\n", msg->msgid); goto out_msg; } Loading @@ -407,6 +427,7 @@ static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data) msg->msg.data_len); goto out_comp; } /* response msg is an error msg */ msg->recv_type = IPMI_RESPONSE_RECV_TYPE; if (msg->recv_type == IPMI_RESPONSE_RECV_TYPE && Loading @@ -418,15 +439,17 @@ static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data) } goto out_comp; } tx_msg->rx_len = msg->msg.data_len; memcpy(tx_msg->data, msg->msg.data, tx_msg->rx_len); tx_msg->msg_done = ACPI_IPMI_OK; out_comp: complete(&tx_msg->tx_complete); acpi_ipmi_msg_put(tx_msg); out_msg: ipmi_free_recv_msg(msg); }; } static void ipmi_register_bmc(int iface, struct device *dev) { Loading @@ -436,7 +459,6 @@ static void ipmi_register_bmc(int iface, struct device *dev) acpi_handle handle; err = ipmi_get_smi_info(iface, &smi_data); if (err) return; Loading @@ -461,11 +483,11 @@ static void ipmi_register_bmc(int iface, struct device *dev) if (temp->handle == handle) goto err_lock; } if (!driver_data.selected_smi) driver_data.selected_smi = ipmi_device; list_add_tail(&ipmi_device->head, &driver_data.ipmi_devices); mutex_unlock(&driver_data.ipmi_lock); put_device(smi_data.dev); return; Loading Loading @@ -496,14 +518,13 @@ static void ipmi_bmc_gone(int iface) &driver_data.ipmi_devices, struct acpi_ipmi_device, head); mutex_unlock(&driver_data.ipmi_lock); if (dev_found) { ipmi_flush_tx_msg(ipmi_device); acpi_ipmi_dev_put(ipmi_device); } } /* -------------------------------------------------------------------------- * Address Space Management * -------------------------------------------------------------------------- */ /* * This is the IPMI opregion space handler. * @function: indicates the read/write. In fact as the IPMI message is driven Loading @@ -516,7 +537,6 @@ static void ipmi_bmc_gone(int iface) * the response IPMI message returned by IPMI command. * @handler_context: IPMI device context. */ static acpi_status acpi_ipmi_space_handler(u32 function, acpi_physical_address address, u32 bits, acpi_integer *value, Loading @@ -527,6 +547,7 @@ acpi_ipmi_space_handler(u32 function, acpi_physical_address address, int err; acpi_status status; unsigned long flags; /* * IPMI opregion message. * IPMI message is firstly written to the BMC and system software Loading @@ -539,13 +560,13 @@ acpi_ipmi_space_handler(u32 function, acpi_physical_address address, tx_msg = ipmi_msg_alloc(); if (!tx_msg) return AE_NOT_EXIST; ipmi_device = tx_msg->device; if (acpi_format_ipmi_request(tx_msg, address, value) != 0) { ipmi_msg_release(tx_msg); return AE_TYPE; } acpi_ipmi_msg_get(tx_msg); mutex_lock(&driver_data.ipmi_lock); /* Do not add a tx_msg that can not be flushed. */ Loading @@ -558,6 +579,7 @@ acpi_ipmi_space_handler(u32 function, acpi_physical_address address, list_add_tail(&tx_msg->head, &ipmi_device->tx_msg_list); spin_unlock_irqrestore(&ipmi_device->tx_msg_lock, flags); mutex_unlock(&driver_data.ipmi_lock); err = ipmi_request_settime(ipmi_device->user_interface, &tx_msg->addr, tx_msg->tx_msgid, Loading @@ -568,6 +590,7 @@ acpi_ipmi_space_handler(u32 function, acpi_physical_address address, goto out_msg; } wait_for_completion(&tx_msg->tx_complete); acpi_format_ipmi_response(tx_msg, value); status = AE_OK; Loading @@ -586,7 +609,8 @@ static int __init acpi_ipmi_init(void) return 0; status = acpi_install_address_space_handler(ACPI_ROOT_OBJECT, ACPI_ADR_SPACE_IPMI, &acpi_ipmi_space_handler, ACPI_ADR_SPACE_IPMI, &acpi_ipmi_space_handler, NULL, NULL); if (ACPI_FAILURE(status)) { pr_warn("Can't register IPMI opregion space handle\n"); Loading Loading @@ -629,7 +653,8 @@ static void __exit acpi_ipmi_exit(void) } mutex_unlock(&driver_data.ipmi_lock); acpi_remove_address_space_handler(ACPI_ROOT_OBJECT, ACPI_ADR_SPACE_IPMI, &acpi_ipmi_space_handler); ACPI_ADR_SPACE_IPMI, &acpi_ipmi_space_handler); } module_init(acpi_ipmi_init); Loading