From 719c1b3810898c3d1837df3d7814a44190fff2c7 Mon Sep 17 00:00:00 2001 From: Hanjun Guo Date: Tue, 4 Jul 2017 12:08:09 +0800 Subject: [PATCH 01/48] char: ipmi: eliminate misleading print info when being probed via ACPI When ipmi is probed via ACPI, the boot log shows [ 17.945139] ipmi_si IPI0001:00: probing via device tree [ 17.950369] ipmi_si IPI0001:00: ipmi_si: probing via ACPI [ 17.955795] ipmi_si IPI0001:00: [io 0x00e4-0x3fff] regsize 1 spacing 1 irq 0 [ 17.962932] ipmi_si: Adding ACPI-specified bt state machine which "ipmi_si IPI0001:00: probing via device tree" is misleading with a ACPI HID "IPI0001" but probing via DT. Eliminate this misleading print info by checking of_node is valid or not before calling of_ipmi_probe(). Signed-off-by: Hanjun Guo Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_si_intf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 36f47e8d06a3..ecd3844917a5 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -2784,7 +2784,7 @@ static int acpi_ipmi_probe(struct platform_device *dev) static int ipmi_probe(struct platform_device *dev) { - if (of_ipmi_probe(dev) == 0) + if (dev->dev.of_node && of_ipmi_probe(dev) == 0) return 0; if (acpi_ipmi_probe(dev) == 0) From 392a17b10ec4320d3c0e96e2a23ebaad1123b989 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Sat, 29 Jul 2017 21:14:55 -0500 Subject: [PATCH 02/48] ipmi: fix unsigned long underflow When I set the timeout to a specific value such as 500ms, the timeout event will not happen in time due to the overflow in function check_msg_timeout: ... ent->timeout -= timeout_period; if (ent->timeout > 0) return; ... The type of timeout_period is long, but ent->timeout is unsigned long. This patch makes the type consistent. Reported-by: Weilong Chen Signed-off-by: Corey Minyard Tested-by: Weilong Chen Cc: # 3.16.x --- drivers/char/ipmi/ipmi_msghandler.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 810b138f5897..c82d9fd2f05a 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -4030,7 +4030,8 @@ smi_from_recv_msg(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg, } static void check_msg_timeout(ipmi_smi_t intf, struct seq_table *ent, - struct list_head *timeouts, long timeout_period, + struct list_head *timeouts, + unsigned long timeout_period, int slot, unsigned long *flags, unsigned int *waiting_msgs) { @@ -4043,8 +4044,8 @@ static void check_msg_timeout(ipmi_smi_t intf, struct seq_table *ent, if (!ent->inuse) return; - ent->timeout -= timeout_period; - if (ent->timeout > 0) { + if (timeout_period < ent->timeout) { + ent->timeout -= timeout_period; (*waiting_msgs)++; return; } @@ -4110,7 +4111,8 @@ static void check_msg_timeout(ipmi_smi_t intf, struct seq_table *ent, } } -static unsigned int ipmi_timeout_handler(ipmi_smi_t intf, long timeout_period) +static unsigned int ipmi_timeout_handler(ipmi_smi_t intf, + unsigned long timeout_period) { struct list_head timeouts; struct ipmi_recv_msg *msg, *msg2; From b72fce52a14bbe0a94259a95032cf9dd1b3dd143 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 15 Aug 2017 11:09:58 +0100 Subject: [PATCH 03/48] char: ipmi: make function ipmi_get_info_from_resources static The function ipmi_get_info_from_resources is local to the source and does not need to be in global scope, so make it static. Add in newline to function declaration to make it checkpatch warning clean. Cleans up sparse warnings: symbol 'ipmi_get_info_from_resources' was not declared. Should it be static? Signed-off-by: Colin Ian King Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_si_intf.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index ecd3844917a5..39c55f4052b8 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -2275,8 +2275,9 @@ static void spmi_find_bmc(void) #endif #if defined(CONFIG_DMI) || defined(CONFIG_ACPI) -struct resource *ipmi_get_info_from_resources(struct platform_device *pdev, - struct smi_info *info) +static struct resource * +ipmi_get_info_from_resources(struct platform_device *pdev, + struct smi_info *info) { struct resource *res, *res_second; From 1c9f98d1bfbd0696442f97fa7d43a727e1e16568 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Fri, 18 Aug 2017 17:32:03 -0500 Subject: [PATCH 04/48] ipmi: Make IPMI panic strings always available They were set by config items, but people complained that they were never turned on. So have them always available and enabled by a module parameter. Signed-off-by: Corey Minyard --- Documentation/IPMI.txt | 4 +- drivers/char/ipmi/Kconfig | 27 +++++---- drivers/char/ipmi/ipmi_msghandler.c | 91 ++++++++++++++++++++++++----- 3 files changed, 98 insertions(+), 24 deletions(-) diff --git a/Documentation/IPMI.txt b/Documentation/IPMI.txt index aa77a25a0940..5ef1047e2e66 100644 --- a/Documentation/IPMI.txt +++ b/Documentation/IPMI.txt @@ -81,7 +81,9 @@ If you want the driver to put an event into the event log on a panic, enable the 'Generate a panic event to all BMCs on a panic' option. If you want the whole panic string put into the event log using OEM events, enable the 'Generate OEM events containing the panic string' -option. +option. You can also enable these dynamically by setting the module +parameter named "panic_op" in the ipmi_msghandler module to "event" +or "string". Setting that parameter to "none" disables this function. Basic Design ------------ diff --git a/drivers/char/ipmi/Kconfig b/drivers/char/ipmi/Kconfig index f6fa056a52fc..152ccefdaecb 100644 --- a/drivers/char/ipmi/Kconfig +++ b/drivers/char/ipmi/Kconfig @@ -25,21 +25,28 @@ if IPMI_HANDLER config IPMI_PANIC_EVENT bool 'Generate a panic event to all BMCs on a panic' help - When a panic occurs, this will cause the IPMI message handler to - generate an IPMI event describing the panic to each interface - registered with the message handler. + When a panic occurs, this will cause the IPMI message handler to, + by default, generate an IPMI event describing the panic to each + interface registered with the message handler. This is always + available, the module parameter for ipmi_msghandler named + panic_op can be set to "event" to chose this value, this config + simply causes the default value to be set to "event". config IPMI_PANIC_STRING bool 'Generate OEM events containing the panic string' depends on IPMI_PANIC_EVENT help - When a panic occurs, this will cause the IPMI message handler to - generate IPMI OEM type f0 events holding the IPMB address of the - panic generator (byte 4 of the event), a sequence number for the - string (byte 5 of the event) and part of the string (the rest of the - event). Bytes 1, 2, and 3 are the normal usage for an OEM event. - You can fetch these events and use the sequence numbers to piece the - string together. + When a panic occurs, this will cause the IPMI message handler to, + by default, generate IPMI OEM type f0 events holding the IPMB + address of the panic generator (byte 4 of the event), a sequence + number for the string (byte 5 of the event) and part of the + string (the rest of the event). Bytes 1, 2, and 3 are the normal + usage for an OEM event. You can fetch these events and use the + sequence numbers to piece the string together. This config + parameter sets the default value to generate these events, + the module parameter for ipmi_msghandler named panic_op can + be set to "string" to chose this value, this config simply + causes the default value to be set to "string". config IPMI_DEVICE_INTERFACE tristate 'Device interface for IPMI' diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index c82d9fd2f05a..047ca9fcb29b 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -46,6 +46,7 @@ #include #include #include +#include #define PFX "IPMI message handler: " @@ -61,6 +62,74 @@ static int handle_one_recv_msg(ipmi_smi_t intf, static int initialized; +enum ipmi_panic_event_op { + IPMI_SEND_PANIC_EVENT_NONE, + IPMI_SEND_PANIC_EVENT, + IPMI_SEND_PANIC_EVENT_STRING +}; +#ifdef CONFIG_IPMI_PANIC_STRING +#define IPMI_PANIC_DEFAULT IPMI_SEND_PANIC_EVENT_STRING +#elif defined(CONFIG_IPMI_PANIC_EVENT) +#define IPMI_PANIC_DEFAULT IPMI_SEND_PANIC_EVENT +#else +#define IPMI_PANIC_DEFAULT IPMI_SEND_PANIC_EVENT_NONE +#endif +static enum ipmi_panic_event_op ipmi_send_panic_event = IPMI_PANIC_DEFAULT; + +static int panic_op_write_handler(const char *val, + const struct kernel_param *kp) +{ + char valcp[16]; + char *s; + + strncpy(valcp, val, 16); + valcp[15] = '\0'; + + s = strstrip(valcp); + + if (strcmp(s, "none") == 0) + ipmi_send_panic_event = IPMI_SEND_PANIC_EVENT_NONE; + else if (strcmp(s, "event") == 0) + ipmi_send_panic_event = IPMI_SEND_PANIC_EVENT; + else if (strcmp(s, "string") == 0) + ipmi_send_panic_event = IPMI_SEND_PANIC_EVENT_STRING; + else + return -EINVAL; + + return 0; +} + +static int panic_op_read_handler(char *buffer, const struct kernel_param *kp) +{ + switch (ipmi_send_panic_event) { + case IPMI_SEND_PANIC_EVENT_NONE: + strcpy(buffer, "none"); + break; + + case IPMI_SEND_PANIC_EVENT: + strcpy(buffer, "event"); + break; + + case IPMI_SEND_PANIC_EVENT_STRING: + strcpy(buffer, "string"); + break; + + default: + strcpy(buffer, "???"); + break; + } + + return strlen(buffer); +} + +static const struct kernel_param_ops panic_op_ops = { + .set = panic_op_write_handler, + .get = panic_op_read_handler +}; +module_param_cb(panic_op, &panic_op_ops, NULL, 0600); +MODULE_PARM_DESC(panic_op, "Sets if the IPMI driver will attempt to store panic information in the event log in the event of a panic. Set to 'none' for no, 'event' for a single event, or 'string' for a generic event and the panic string in IPMI OEM events."); + + #ifdef CONFIG_PROC_FS static struct proc_dir_entry *proc_ipmi_root; #endif /* CONFIG_PROC_FS */ @@ -4271,8 +4340,6 @@ void ipmi_free_recv_msg(struct ipmi_recv_msg *msg) } EXPORT_SYMBOL(ipmi_free_recv_msg); -#ifdef CONFIG_IPMI_PANIC_EVENT - static atomic_t panic_done_count = ATOMIC_INIT(0); static void dummy_smi_done_handler(struct ipmi_smi_msg *msg) @@ -4320,7 +4387,6 @@ static void ipmi_panic_request_and_wait(ipmi_smi_t intf, ipmi_poll(intf); } -#ifdef CONFIG_IPMI_PANIC_STRING static void event_receiver_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg) { if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) @@ -4347,7 +4413,6 @@ static void device_id_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg) intf->local_event_generator = (msg->msg.data[6] >> 5) & 1; } } -#endif static void send_panic_events(char *str) { @@ -4357,6 +4422,9 @@ static void send_panic_events(char *str) struct ipmi_system_interface_addr *si; struct ipmi_addr addr; + if (ipmi_send_panic_event == IPMI_SEND_PANIC_EVENT_NONE) + return; + si = (struct ipmi_system_interface_addr *) &addr; si->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; si->channel = IPMI_BMC_CHANNEL; @@ -4385,20 +4453,19 @@ static void send_panic_events(char *str) /* For every registered interface, send the event. */ list_for_each_entry_rcu(intf, &ipmi_interfaces, link) { - if (!intf->handlers) - /* Interface is not ready. */ + if (!intf->handlers || !intf->handlers->poll) + /* Interface is not ready or can't run at panic time. */ continue; /* Send the event announcing the panic. */ ipmi_panic_request_and_wait(intf, &addr, &msg); } -#ifdef CONFIG_IPMI_PANIC_STRING /* * On every interface, dump a bunch of OEM event holding the * string. */ - if (!str) + if (ipmi_send_panic_event != IPMI_SEND_PANIC_EVENT_STRING || !str) return; /* For every registered interface, send the event. */ @@ -4507,9 +4574,7 @@ static void send_panic_events(char *str) ipmi_panic_request_and_wait(intf, &addr, &msg); } } -#endif /* CONFIG_IPMI_PANIC_STRING */ } -#endif /* CONFIG_IPMI_PANIC_EVENT */ static int has_panicked; @@ -4547,12 +4612,12 @@ static int panic_event(struct notifier_block *this, spin_unlock(&intf->waiting_rcv_msgs_lock); intf->run_to_completion = 1; - intf->handlers->set_run_to_completion(intf->send_info, 1); + if (intf->handlers->set_run_to_completion) + intf->handlers->set_run_to_completion(intf->send_info, + 1); } -#ifdef CONFIG_IPMI_PANIC_EVENT send_panic_events(ptr); -#endif return NOTIFY_DONE; } From e6dd76a6e9c20a6cc63406061f216d4eb7c9ae7b Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Mon, 28 Aug 2017 23:38:15 +0530 Subject: [PATCH 05/48] IPMI: make ipmi_poweroff_handler const Make this const as it is only passed to a const argument of the function ipmi_create_user. Signed-off-by: Bhumika Goyal Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_poweroff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/ipmi/ipmi_poweroff.c b/drivers/char/ipmi/ipmi_poweroff.c index 9f2e3be2c5b8..cd0f41fd4a51 100644 --- a/drivers/char/ipmi/ipmi_poweroff.c +++ b/drivers/char/ipmi/ipmi_poweroff.c @@ -133,7 +133,7 @@ static void receive_handler(struct ipmi_recv_msg *recv_msg, void *handler_data) complete(comp); } -static struct ipmi_user_hndl ipmi_poweroff_handler = { +static const struct ipmi_user_hndl ipmi_poweroff_handler = { .ipmi_recv_hndl = receive_handler }; From 72630d9a01c8ba56c55671a1b103aa5e2df57408 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Thu, 7 Sep 2017 07:32:20 -0500 Subject: [PATCH 06/48] ipmi: Fix getting the GUID data It was off by one. Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_msghandler.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 047ca9fcb29b..dbf8c6ac8c73 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -2699,7 +2699,7 @@ guid_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg) goto out; } - memcpy(intf->bmc->guid, msg->msg.data, 16); + memcpy(intf->bmc->guid, msg->msg.data + 1, 16); intf->bmc->guid_set = 1; out: wake_up(&intf->waitq); From f33e4df83e00f629aece2bd3a8d22b533e9d7877 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Fri, 1 Sep 2017 10:43:49 -0500 Subject: [PATCH 07/48] ipmi: Move bmc find routing to below bmc device type No functional change, this is for a later change that uses the bmc device type. Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_msghandler.c | 101 ++++++++++++++-------------- 1 file changed, 51 insertions(+), 50 deletions(-) diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index dbf8c6ac8c73..5780fdf6bc7a 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -2276,56 +2276,6 @@ static void remove_proc_entries(ipmi_smi_t smi) #endif /* CONFIG_PROC_FS */ } -static int __find_bmc_guid(struct device *dev, void *data) -{ - unsigned char *id = data; - struct bmc_device *bmc = to_bmc_device(dev); - return memcmp(bmc->guid, id, 16) == 0; -} - -static struct bmc_device *ipmi_find_bmc_guid(struct device_driver *drv, - unsigned char *guid) -{ - struct device *dev; - - dev = driver_find_device(drv, NULL, guid, __find_bmc_guid); - if (dev) - return to_bmc_device(dev); - else - return NULL; -} - -struct prod_dev_id { - unsigned int product_id; - unsigned char device_id; -}; - -static int __find_bmc_prod_dev_id(struct device *dev, void *data) -{ - struct prod_dev_id *id = data; - struct bmc_device *bmc = to_bmc_device(dev); - - return (bmc->id.product_id == id->product_id - && bmc->id.device_id == id->device_id); -} - -static struct bmc_device *ipmi_find_bmc_prod_dev_id( - struct device_driver *drv, - unsigned int product_id, unsigned char device_id) -{ - struct prod_dev_id id = { - .product_id = product_id, - .device_id = device_id, - }; - struct device *dev; - - dev = driver_find_device(drv, NULL, &id, __find_bmc_prod_dev_id); - if (dev) - return to_bmc_device(dev); - else - return NULL; -} - static ssize_t device_id_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -2480,6 +2430,57 @@ static const struct device_type bmc_device_type = { .groups = bmc_dev_attr_groups, }; +static int __find_bmc_guid(struct device *dev, void *data) +{ + unsigned char *id = data; + struct bmc_device *bmc = to_bmc_device(dev); + + return memcmp(bmc->guid, id, 16) == 0; +} + +static struct bmc_device *ipmi_find_bmc_guid(struct device_driver *drv, + unsigned char *guid) +{ + struct device *dev; + + dev = driver_find_device(drv, NULL, guid, __find_bmc_guid); + if (dev) + return to_bmc_device(dev); + else + return NULL; +} + +struct prod_dev_id { + unsigned int product_id; + unsigned char device_id; +}; + +static int __find_bmc_prod_dev_id(struct device *dev, void *data) +{ + struct prod_dev_id *id = data; + struct bmc_device *bmc = to_bmc_device(dev); + + return (bmc->id.product_id == id->product_id + && bmc->id.device_id == id->device_id); +} + +static struct bmc_device *ipmi_find_bmc_prod_dev_id( + struct device_driver *drv, + unsigned int product_id, unsigned char device_id) +{ + struct prod_dev_id id = { + .product_id = product_id, + .device_id = device_id, + }; + struct device *dev; + + dev = driver_find_device(drv, NULL, &id, __find_bmc_prod_dev_id); + if (dev) + return to_bmc_device(dev); + else + return NULL; +} + static void release_bmc_device(struct device *dev) { From eae4a36a6825302cb08c73c91924cade224d96d3 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Fri, 1 Sep 2017 10:46:47 -0500 Subject: [PATCH 08/48] ipmi: Check that the device type is BMC when scanning device Just an added safety check. Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_msghandler.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 5780fdf6bc7a..efa5581c2f8b 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -2433,9 +2433,11 @@ static const struct device_type bmc_device_type = { static int __find_bmc_guid(struct device *dev, void *data) { unsigned char *id = data; - struct bmc_device *bmc = to_bmc_device(dev); - return memcmp(bmc->guid, id, 16) == 0; + if (dev->type != &bmc_device_type) + return 0; + + return memcmp(to_bmc_device(dev)->guid, id, 16) == 0; } static struct bmc_device *ipmi_find_bmc_guid(struct device_driver *drv, @@ -2458,8 +2460,12 @@ struct prod_dev_id { static int __find_bmc_prod_dev_id(struct device *dev, void *data) { struct prod_dev_id *id = data; - struct bmc_device *bmc = to_bmc_device(dev); + struct bmc_device *bmc; + if (dev->type != &bmc_device_type) + return 0; + + bmc = to_bmc_device(dev); return (bmc->id.product_id == id->product_id && bmc->id.device_id == id->device_id); } From 9ca15af3164f3bb84db101fc7843fde25be3288c Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Fri, 1 Sep 2017 12:52:20 -0500 Subject: [PATCH 09/48] ipmi: Fix issues with BMC refcounts BMC device refcounts were not being decremented after fetching from driver_find_device(). Also, document the use of ipmidriver_mutex and tighten it's span some by incrementing the BMC's usecount in the BMC find routines and not later. This will be important for future changes where a long mutex hold area will complicate things. Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_msghandler.c | 51 ++++++++++++++++++++--------- 1 file 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 = { .bus = &platform_bus_type } }; +/* + * This mutex protects adding/removing BMCs on the ipmidriver's device + * list. This way we can pull items out of the driver's list and reuse + * them. + */ static DEFINE_MUTEX(ipmidriver_mutex); static LIST_HEAD(ipmi_interfaces); @@ -2440,16 +2445,23 @@ static int __find_bmc_guid(struct device *dev, void *data) return memcmp(to_bmc_device(dev)->guid, id, 16) == 0; } +/* + * Must be called with ipmidriver_mutex held. Returns with the + * bmc's usecount incremented, if it is non-NULL. + */ static struct bmc_device *ipmi_find_bmc_guid(struct device_driver *drv, unsigned char *guid) { struct device *dev; + struct bmc_device *bmc = NULL; dev = driver_find_device(drv, NULL, guid, __find_bmc_guid); - if (dev) - return to_bmc_device(dev); - else - return NULL; + if (dev) { + bmc = to_bmc_device(dev); + kref_get(&bmc->usecount); + put_device(dev); + } + return bmc; } struct prod_dev_id { @@ -2470,6 +2482,10 @@ static int __find_bmc_prod_dev_id(struct device *dev, void *data) && bmc->id.device_id == id->device_id); } +/* + * Must be called with ipmidriver_mutex held. Returns with the + * bmc's usecount incremented, if it is non-NULL. + */ static struct bmc_device *ipmi_find_bmc_prod_dev_id( struct device_driver *drv, unsigned int product_id, unsigned char device_id) @@ -2479,12 +2495,15 @@ static struct bmc_device *ipmi_find_bmc_prod_dev_id( .device_id = device_id, }; struct device *dev; + struct bmc_device *bmc = NULL; dev = driver_find_device(drv, NULL, &id, __find_bmc_prod_dev_id); - if (dev) - return to_bmc_device(dev); - else - return NULL; + if (dev) { + bmc = to_bmc_device(dev); + kref_get(&bmc->usecount); + put_device(dev); + } + return bmc; } static void @@ -2514,8 +2533,8 @@ static void ipmi_bmc_unregister(ipmi_smi_t intf) mutex_lock(&ipmidriver_mutex); kref_put(&bmc->usecount, cleanup_bmc_device); - intf->bmc = NULL; mutex_unlock(&ipmidriver_mutex); + intf->bmc = NULL; } 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) struct bmc_device *bmc = intf->bmc; struct bmc_device *old_bmc; - mutex_lock(&ipmidriver_mutex); - /* * Try to find if there is an bmc_device struct * representing the interfaced BMC already */ + mutex_lock(&ipmidriver_mutex); if (bmc->guid_set) old_bmc = ipmi_find_bmc_guid(&ipmidriver.driver, bmc->guid); else old_bmc = ipmi_find_bmc_prod_dev_id(&ipmidriver.driver, bmc->id.product_id, bmc->id.device_id); + mutex_unlock(&ipmidriver_mutex); /* * 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) intf->bmc = old_bmc; bmc = old_bmc; - kref_get(&bmc->usecount); - mutex_unlock(&ipmidriver_mutex); - printk(KERN_INFO "ipmi: interfacing existing BMC (man_id: 0x%6.6x," " 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) } else { unsigned char orig_dev_id = bmc->id.device_id; int warn_printed = 0; + struct bmc_device *tmp_bmc; snprintf(bmc->name, sizeof(bmc->name), "ipmi_bmc.%4.4x", bmc->id.product_id); bmc->pdev.name = bmc->name; - while (ipmi_find_bmc_prod_dev_id(&ipmidriver.driver, + mutex_lock(&ipmidriver_mutex); + while ((tmp_bmc = ipmi_find_bmc_prod_dev_id(&ipmidriver.driver, bmc->id.product_id, - bmc->id.device_id)) { + bmc->id.device_id))) { + kref_put(&tmp_bmc->usecount, cleanup_bmc_device); if (!warn_printed) { printk(KERN_WARNING PFX "This machine has two different BMCs" From 7e030d6dff713250c7dcfb543cad2addaf479b0e Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Fri, 8 Sep 2017 14:05:58 -0500 Subject: [PATCH 10/48] ipmi: Prefer ACPI system interfaces over SMBIOS ones The recent changes to add SMBIOS (DMI) IPMI interfaces as platform devices caused DMI to be selected before ACPI, causing ACPI type of operations to not work. Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_si_intf.c | 33 ++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 39c55f4052b8..f8e28bad6d56 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -3425,7 +3425,7 @@ static inline void wait_for_timer_and_thread(struct smi_info *smi_info) del_timer_sync(&smi_info->si_timer); } -static int is_new_interface(struct smi_info *info) +static struct smi_info *find_dup_si(struct smi_info *info) { struct smi_info *e; @@ -3440,24 +3440,36 @@ static int is_new_interface(struct smi_info *info) */ if (info->slave_addr && !e->slave_addr) e->slave_addr = info->slave_addr; - return 0; + return e; } } - return 1; + return NULL; } static int add_smi(struct smi_info *new_smi) { int rv = 0; + struct smi_info *dup; mutex_lock(&smi_infos_lock); - if (!is_new_interface(new_smi)) { - pr_info(PFX "%s-specified %s state machine: duplicate\n", - ipmi_addr_src_to_str(new_smi->addr_source), - si_to_str[new_smi->si_type]); - rv = -EBUSY; - goto out_err; + dup = find_dup_si(new_smi); + if (dup) { + if (new_smi->addr_source == SI_ACPI && + dup->addr_source == SI_SMBIOS) { + /* We prefer ACPI over SMBIOS. */ + dev_info(dup->dev, + "Removing SMBIOS-specified %s state machine in favor of ACPI\n", + si_to_str[new_smi->si_type]); + cleanup_one_si(dup); + } else { + dev_info(new_smi->dev, + "%s-specified %s state machine: duplicate\n", + ipmi_addr_src_to_str(new_smi->addr_source), + si_to_str[new_smi->si_type]); + rv = -EBUSY; + goto out_err; + } } pr_info(PFX "Adding %s-specified %s state machine\n", @@ -3866,7 +3878,8 @@ static void cleanup_one_si(struct smi_info *to_clean) poll(to_clean); schedule_timeout_uninterruptible(1); } - disable_si_irq(to_clean, false); + if (to_clean->handlers) + disable_si_irq(to_clean, false); while (to_clean->curr_msg || (to_clean->si_state != SI_NORMAL)) { poll(to_clean); schedule_timeout_uninterruptible(1); From a2cb600fa22a877df48e1a9372ac5f02680c1ee3 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Fri, 1 Sep 2017 14:37:07 -0500 Subject: [PATCH 11/48] ipmi: Rework BMC registration There was a certain error case where the BMC wouldn't be deregistered like it should be. Rework the BMC registration to make calling ipmi_bmc_unregister() ok even if it's not registered and to clean up the error handling for ipmi_bmc_register(). Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_msghandler.c | 68 +++++++++++++++++++---------- 1 file changed, 45 insertions(+), 23 deletions(-) diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 42532f296e93..1517f14ee903 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -404,6 +404,7 @@ struct ipmi_smi { wait_queue_head_t waitq; struct bmc_device *bmc; + bool bmc_registered; char *my_dev_name; /* @@ -2524,17 +2525,18 @@ static void ipmi_bmc_unregister(ipmi_smi_t intf) { struct bmc_device *bmc = intf->bmc; + if (!intf->bmc_registered) + return; + sysfs_remove_link(&intf->si_dev->kobj, "bmc"); - if (intf->my_dev_name) { - sysfs_remove_link(&bmc->pdev.dev.kobj, intf->my_dev_name); - kfree(intf->my_dev_name); - intf->my_dev_name = NULL; - } + sysfs_remove_link(&bmc->pdev.dev.kobj, intf->my_dev_name); + kfree(intf->my_dev_name); + intf->my_dev_name = NULL; mutex_lock(&ipmidriver_mutex); kref_put(&bmc->usecount, cleanup_bmc_device); mutex_unlock(&ipmidriver_mutex); - intf->bmc = NULL; + intf->bmc_registered = false; } static int ipmi_bmc_register(ipmi_smi_t intf, int ifnum) @@ -2600,7 +2602,9 @@ static int ipmi_bmc_register(ipmi_smi_t intf, int ifnum) if (bmc->id.device_id == orig_dev_id) { printk(KERN_ERR PFX "Out of device ids!\n"); - break; + mutex_unlock(&ipmidriver_mutex); + rv = -EAGAIN; + goto out; } } @@ -2613,16 +2617,11 @@ static int ipmi_bmc_register(ipmi_smi_t intf, int ifnum) rv = platform_device_register(&bmc->pdev); mutex_unlock(&ipmidriver_mutex); if (rv) { - put_device(&bmc->pdev.dev); printk(KERN_ERR "ipmi_msghandler:" " Unable to register bmc device: %d\n", rv); - /* - * Don't go to out_err, you can only do that if - * the device is registered already. - */ - return rv; + goto out_list_del; } dev_info(intf->si_dev, "Found new BMC (man_id: 0x%6.6x, " @@ -2641,7 +2640,7 @@ static int ipmi_bmc_register(ipmi_smi_t intf, int ifnum) printk(KERN_ERR "ipmi_msghandler: Unable to create bmc symlink: %d\n", rv); - goto out_err; + goto out_put_bmc; } intf->my_dev_name = kasprintf(GFP_KERNEL, "ipmi%d", ifnum); @@ -2650,7 +2649,7 @@ static int ipmi_bmc_register(ipmi_smi_t intf, int ifnum) printk(KERN_ERR "ipmi_msghandler: allocate link from BMC: %d\n", rv); - goto out_err; + goto out_unlink1; } rv = sysfs_create_link(&bmc->pdev.dev.kobj, &intf->si_dev->kobj, @@ -2662,14 +2661,35 @@ static int ipmi_bmc_register(ipmi_smi_t intf, int ifnum) "ipmi_msghandler:" " Unable to create symlink to bmc: %d\n", rv); - goto out_err; + goto out_free_my_dev_name; } - return 0; + intf->bmc_registered = true; -out_err: - ipmi_bmc_unregister(intf); +out: return rv; + + +out_free_my_dev_name: + kfree(intf->my_dev_name); + intf->my_dev_name = NULL; + +out_unlink1: + sysfs_remove_link(&intf->si_dev->kobj, "bmc"); + +out_put_bmc: + mutex_lock(&ipmidriver_mutex); + intf->bmc = NULL; + kref_put(&bmc->usecount, cleanup_bmc_device); + mutex_unlock(&ipmidriver_mutex); + goto out; + +out_list_del: + mutex_lock(&ipmidriver_mutex); + intf->bmc = NULL; + mutex_unlock(&ipmidriver_mutex); + put_device(&bmc->pdev.dev); + goto out; } static int @@ -2959,6 +2979,10 @@ int ipmi_register_smi(const struct ipmi_smi_handlers *handlers, get_guid(intf); + rv = ipmi_bmc_register(intf, i); + if (rv) + goto out; + if ((intf->ipmi_version_major > 1) || ((intf->ipmi_version_major == 1) && (intf->ipmi_version_minor >= 5))) { @@ -2987,13 +3011,11 @@ int ipmi_register_smi(const struct ipmi_smi_handlers *handlers, intf->curr_channel = IPMI_MAX_CHANNELS; } - rv = ipmi_bmc_register(intf, i); - - if (rv == 0) - rv = add_proc_entries(intf, i); + rv = add_proc_entries(intf, i); out: if (rv) { + ipmi_bmc_unregister(intf); if (intf->proc_dir) remove_proc_entries(intf); intf->handlers = NULL; From 9b64a8ba901ff23fa7a91c00e6aec526fb329a97 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Fri, 8 Sep 2017 09:21:58 -0500 Subject: [PATCH 12/48] ipmi: Fix printing the BMC guid It was just wrong. Make it print according to the guid spec. Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_msghandler.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 1517f14ee903..d92767225b15 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -2388,9 +2388,12 @@ static ssize_t guid_show(struct device *dev, struct device_attribute *attr, { struct bmc_device *bmc = to_bmc_device(dev); - return snprintf(buf, 100, "%Lx%Lx\n", - (long long) bmc->guid[0], - (long long) bmc->guid[8]); + return snprintf(buf, 100, + "%2.2x%2.2x%2.2x%2.2x-%2.2x%2.2x-%2.2x%2.2x-%2.2x%2.2x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n", + bmc->guid[3], bmc->guid[2], bmc->guid[1], bmc->guid[0], + bmc->guid[5], bmc->guid[4], bmc->guid[7], bmc->guid[6], + bmc->guid[8], bmc->guid[9], bmc->guid[10], bmc->guid[11], + bmc->guid[12], bmc->guid[13], bmc->guid[14], bmc->guid[15]); } static DEVICE_ATTR(guid, S_IRUGO, guid_show, NULL); From 511d57dc71a22514e106f79a878e788cb22f73e3 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Wed, 30 Aug 2017 08:04:24 -0500 Subject: [PATCH 13/48] ipmi: Get the device id through a function This makes getting the device id consistent, and make it possible to add a function to fetch it dynamically later. Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_msghandler.c | 155 +++++++++++++++++++++------- drivers/char/ipmi/ipmi_watchdog.c | 11 +- include/linux/ipmi.h | 6 +- 3 files changed, 130 insertions(+), 42 deletions(-) diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index d92767225b15..89b72425f9ce 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -272,6 +272,9 @@ struct bmc_device { }; #define to_bmc_device(x) container_of((x), struct bmc_device, pdev.dev) +static int bmc_get_device_id(ipmi_smi_t intf, struct bmc_device *bmc, + struct ipmi_device_id *id); + /* * Various statistics for IPMI, these index stats[] in the ipmi_smi * structure. @@ -396,10 +399,6 @@ struct ipmi_smi { */ struct list_head users; - /* Information to supply to users. */ - unsigned char ipmi_version_major; - unsigned char ipmi_version_minor; - /* Used for wake ups at startup. */ wait_queue_head_t waitq; @@ -1194,12 +1193,21 @@ int ipmi_destroy_user(ipmi_user_t user) } EXPORT_SYMBOL(ipmi_destroy_user); -void ipmi_get_version(ipmi_user_t user, - unsigned char *major, - unsigned char *minor) +int ipmi_get_version(ipmi_user_t user, + unsigned char *major, + unsigned char *minor) { - *major = user->intf->ipmi_version_major; - *minor = user->intf->ipmi_version_minor; + struct ipmi_device_id id; + int rv; + + rv = bmc_get_device_id(user->intf, NULL, &id); + if (rv) + return rv; + + *major = ipmi_version_major(&id); + *minor = ipmi_version_minor(&id); + + return 0; } EXPORT_SYMBOL(ipmi_get_version); @@ -2072,6 +2080,16 @@ int ipmi_request_supply_msgs(ipmi_user_t user, } EXPORT_SYMBOL(ipmi_request_supply_msgs); +static int bmc_get_device_id(ipmi_smi_t intf, struct bmc_device *bmc, + struct ipmi_device_id *id) +{ + if (!bmc) + bmc = intf->bmc; + + *id = bmc->id; + return 0; +} + #ifdef CONFIG_PROC_FS static int smi_ipmb_proc_show(struct seq_file *m, void *v) { @@ -2101,10 +2119,16 @@ static const struct file_operations smi_ipmb_proc_ops = { static int smi_version_proc_show(struct seq_file *m, void *v) { ipmi_smi_t intf = m->private; + struct ipmi_device_id id; + int rv; + + rv = bmc_get_device_id(intf, NULL, &id); + if (rv) + return rv; seq_printf(m, "%u.%u\n", - ipmi_version_major(&intf->bmc->id), - ipmi_version_minor(&intf->bmc->id)); + ipmi_version_major(&id), + ipmi_version_minor(&id)); return 0; } @@ -2287,8 +2311,14 @@ static ssize_t device_id_show(struct device *dev, char *buf) { struct bmc_device *bmc = to_bmc_device(dev); + struct ipmi_device_id id; + int rv; - return snprintf(buf, 10, "%u\n", bmc->id.device_id); + rv = bmc_get_device_id(NULL, bmc, &id); + if (rv) + return rv; + + return snprintf(buf, 10, "%u\n", id.device_id); } static DEVICE_ATTR(device_id, S_IRUGO, device_id_show, NULL); @@ -2297,9 +2327,14 @@ static ssize_t provides_device_sdrs_show(struct device *dev, char *buf) { struct bmc_device *bmc = to_bmc_device(dev); + struct ipmi_device_id id; + int rv; - return snprintf(buf, 10, "%u\n", - (bmc->id.device_revision & 0x80) >> 7); + rv = bmc_get_device_id(NULL, bmc, &id); + if (rv) + return rv; + + return snprintf(buf, 10, "%u\n", (id.device_revision & 0x80) >> 7); } static DEVICE_ATTR(provides_device_sdrs, S_IRUGO, provides_device_sdrs_show, NULL); @@ -2308,9 +2343,14 @@ static ssize_t revision_show(struct device *dev, struct device_attribute *attr, char *buf) { struct bmc_device *bmc = to_bmc_device(dev); + struct ipmi_device_id id; + int rv; - return snprintf(buf, 20, "%u\n", - bmc->id.device_revision & 0x0F); + rv = bmc_get_device_id(NULL, bmc, &id); + if (rv) + return rv; + + return snprintf(buf, 20, "%u\n", id.device_revision & 0x0F); } static DEVICE_ATTR(revision, S_IRUGO, revision_show, NULL); @@ -2319,9 +2359,15 @@ static ssize_t firmware_revision_show(struct device *dev, char *buf) { struct bmc_device *bmc = to_bmc_device(dev); + struct ipmi_device_id id; + int rv; - return snprintf(buf, 20, "%u.%x\n", bmc->id.firmware_revision_1, - bmc->id.firmware_revision_2); + rv = bmc_get_device_id(NULL, bmc, &id); + if (rv) + return rv; + + return snprintf(buf, 20, "%u.%x\n", id.firmware_revision_1, + id.firmware_revision_2); } static DEVICE_ATTR(firmware_revision, S_IRUGO, firmware_revision_show, NULL); @@ -2330,10 +2376,16 @@ static ssize_t ipmi_version_show(struct device *dev, char *buf) { struct bmc_device *bmc = to_bmc_device(dev); + struct ipmi_device_id id; + int rv; + + rv = bmc_get_device_id(NULL, bmc, &id); + if (rv) + return rv; return snprintf(buf, 20, "%u.%u\n", - ipmi_version_major(&bmc->id), - ipmi_version_minor(&bmc->id)); + ipmi_version_major(&id), + ipmi_version_minor(&id)); } static DEVICE_ATTR(ipmi_version, S_IRUGO, ipmi_version_show, NULL); @@ -2342,9 +2394,14 @@ static ssize_t add_dev_support_show(struct device *dev, char *buf) { struct bmc_device *bmc = to_bmc_device(dev); + struct ipmi_device_id id; + int rv; - return snprintf(buf, 10, "0x%02x\n", - bmc->id.additional_device_support); + rv = bmc_get_device_id(NULL, bmc, &id); + if (rv) + return rv; + + return snprintf(buf, 10, "0x%02x\n", id.additional_device_support); } static DEVICE_ATTR(additional_device_support, S_IRUGO, add_dev_support_show, NULL); @@ -2354,8 +2411,14 @@ static ssize_t manufacturer_id_show(struct device *dev, char *buf) { struct bmc_device *bmc = to_bmc_device(dev); + struct ipmi_device_id id; + int rv; - return snprintf(buf, 20, "0x%6.6x\n", bmc->id.manufacturer_id); + rv = bmc_get_device_id(NULL, bmc, &id); + if (rv) + return rv; + + return snprintf(buf, 20, "0x%6.6x\n", id.manufacturer_id); } static DEVICE_ATTR(manufacturer_id, S_IRUGO, manufacturer_id_show, NULL); @@ -2364,8 +2427,14 @@ static ssize_t product_id_show(struct device *dev, char *buf) { struct bmc_device *bmc = to_bmc_device(dev); + struct ipmi_device_id id; + int rv; - return snprintf(buf, 10, "0x%4.4x\n", bmc->id.product_id); + rv = bmc_get_device_id(NULL, bmc, &id); + if (rv) + return rv; + + return snprintf(buf, 10, "0x%4.4x\n", id.product_id); } static DEVICE_ATTR(product_id, S_IRUGO, product_id_show, NULL); @@ -2374,12 +2443,18 @@ static ssize_t aux_firmware_rev_show(struct device *dev, char *buf) { struct bmc_device *bmc = to_bmc_device(dev); + struct ipmi_device_id id; + int rv; + + rv = bmc_get_device_id(NULL, bmc, &id); + if (rv) + return rv; return snprintf(buf, 21, "0x%02x 0x%02x 0x%02x 0x%02x\n", - bmc->id.aux_firmware_revision[3], - bmc->id.aux_firmware_revision[2], - bmc->id.aux_firmware_revision[1], - bmc->id.aux_firmware_revision[0]); + id.aux_firmware_revision[3], + id.aux_firmware_revision[2], + id.aux_firmware_revision[1], + id.aux_firmware_revision[0]); } static DEVICE_ATTR(aux_firmware_revision, S_IRUGO, aux_firmware_rev_show, NULL); @@ -2417,9 +2492,13 @@ static umode_t bmc_dev_attr_is_visible(struct kobject *kobj, struct device *dev = kobj_to_dev(kobj); struct bmc_device *bmc = to_bmc_device(dev); umode_t mode = attr->mode; + struct ipmi_device_id id; + int rv; - if (attr == &dev_attr_aux_firmware_revision.attr) - return bmc->id.aux_firmware_revision_set ? mode : 0; + if (attr == &dev_attr_aux_firmware_revision.attr) { + rv = bmc_get_device_id(NULL, bmc, &id); + return (!rv && id.aux_firmware_revision_set) ? mode : 0; + } if (attr == &dev_attr_guid.attr) return bmc->guid_set ? mode : 0; return mode; @@ -2884,6 +2963,7 @@ int ipmi_register_smi(const struct ipmi_smi_handlers *handlers, ipmi_smi_t intf; ipmi_smi_t tintf; struct list_head *link; + struct ipmi_device_id id; /* * Make sure the driver is actually initialized, this handles @@ -2905,9 +2985,6 @@ int ipmi_register_smi(const struct ipmi_smi_handlers *handlers, if (!intf) return -ENOMEM; - intf->ipmi_version_major = ipmi_version_major(device_id); - intf->ipmi_version_minor = ipmi_version_minor(device_id); - intf->bmc = kzalloc(sizeof(*intf->bmc), GFP_KERNEL); if (!intf->bmc) { kfree(intf); @@ -2982,13 +3059,19 @@ int ipmi_register_smi(const struct ipmi_smi_handlers *handlers, get_guid(intf); + rv = bmc_get_device_id(intf, NULL, &id); + if (rv) { + dev_err(si_dev, "Unable to get the device id: %d\n", rv); + goto out; + } + rv = ipmi_bmc_register(intf, i); if (rv) goto out; - if ((intf->ipmi_version_major > 1) - || ((intf->ipmi_version_major == 1) - && (intf->ipmi_version_minor >= 5))) { + if (ipmi_version_major(&id) > 1 + || (ipmi_version_major(&id) == 1 + && ipmi_version_minor(&id) >= 5)) { /* * Start scanning the channels to see what is * available. diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c index 3d832d0362a4..76b270678b50 100644 --- a/drivers/char/ipmi/ipmi_watchdog.c +++ b/drivers/char/ipmi/ipmi_watchdog.c @@ -1009,9 +1009,14 @@ static void ipmi_register_watchdog(int ipmi_intf) goto out; } - ipmi_get_version(watchdog_user, - &ipmi_version_major, - &ipmi_version_minor); + rv = ipmi_get_version(watchdog_user, + &ipmi_version_major, + &ipmi_version_minor); + if (rv) { + pr_warn(PFX "Unable to get IPMI version, assuming 1.0\n"); + ipmi_version_major = 1; + ipmi_version_minor = 0; + } rv = misc_register(&ipmi_wdog_miscdev); if (rv < 0) { diff --git a/include/linux/ipmi.h b/include/linux/ipmi.h index f1045b2c6a00..80fc3f798984 100644 --- a/include/linux/ipmi.h +++ b/include/linux/ipmi.h @@ -113,9 +113,9 @@ int ipmi_create_user(unsigned int if_num, int ipmi_destroy_user(ipmi_user_t user); /* Get the IPMI version of the BMC we are talking to. */ -void ipmi_get_version(ipmi_user_t user, - unsigned char *major, - unsigned char *minor); +int ipmi_get_version(ipmi_user_t user, + unsigned char *major, + unsigned char *minor); /* Set and get the slave address and LUN that we will use for our source messages. Note that this affects the interface, not just From a9137c3dfae9f371e302ee3fc6658f0fe6b904e7 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Fri, 25 Aug 2017 15:47:22 +0800 Subject: [PATCH 14/48] ipmi: Add a reference from BMC devices to their interfaces In an upcoming change, we'll want to grab a reference to the ipmi_smi_t from a struct bmc_device. This change adds a pointer to allow this. Signed-off-by: Jeremy Kerr Reworked to support multiple interfaces on a BMC. Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_msghandler.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 89b72425f9ce..8814f4bed862 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -265,6 +265,7 @@ struct ipmi_proc_entry { struct bmc_device { struct platform_device pdev; struct ipmi_device_id id; + struct list_head intfs; unsigned char guid[16]; int guid_set; char name[16]; @@ -404,6 +405,7 @@ struct ipmi_smi { struct bmc_device *bmc; bool bmc_registered; + struct list_head bmc_link; char *my_dev_name; /* @@ -2616,6 +2618,8 @@ static void ipmi_bmc_unregister(ipmi_smi_t intf) intf->my_dev_name = NULL; mutex_lock(&ipmidriver_mutex); + list_del(&intf->bmc_link); + intf->bmc = NULL; kref_put(&bmc->usecount, cleanup_bmc_device); mutex_unlock(&ipmidriver_mutex); intf->bmc_registered = false; @@ -2646,7 +2650,10 @@ static int ipmi_bmc_register(ipmi_smi_t intf, int ifnum) */ if (old_bmc) { kfree(bmc); + mutex_lock(&ipmidriver_mutex); intf->bmc = old_bmc; + list_add_tail(&intf->bmc_link, &bmc->intfs); + mutex_unlock(&ipmidriver_mutex); bmc = old_bmc; printk(KERN_INFO @@ -2697,6 +2704,7 @@ static int ipmi_bmc_register(ipmi_smi_t intf, int ifnum) kref_init(&bmc->usecount); rv = platform_device_register(&bmc->pdev); + list_add_tail(&intf->bmc_link, &bmc->intfs); mutex_unlock(&ipmidriver_mutex); if (rv) { printk(KERN_ERR @@ -2761,6 +2769,7 @@ out_unlink1: out_put_bmc: mutex_lock(&ipmidriver_mutex); + list_del(&intf->bmc_link); intf->bmc = NULL; kref_put(&bmc->usecount, cleanup_bmc_device); mutex_unlock(&ipmidriver_mutex); @@ -2768,6 +2777,7 @@ out_put_bmc: out_list_del: mutex_lock(&ipmidriver_mutex); + list_del(&intf->bmc_link); intf->bmc = NULL; mutex_unlock(&ipmidriver_mutex); put_device(&bmc->pdev.dev); @@ -2990,6 +3000,7 @@ int ipmi_register_smi(const struct ipmi_smi_handlers *handlers, kfree(intf); return -ENOMEM; } + INIT_LIST_HEAD(&intf->bmc->intfs); intf->intf_num = -1; /* Mark it invalid for now. */ kref_init(&intf->refcount); intf->bmc->id = *device_id; From c468f911b73beb39b20f7e5f97a35d41f038b31b Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Fri, 25 Aug 2017 15:47:23 +0800 Subject: [PATCH 15/48] ipmi: Make ipmi_demangle_device_id more generic Currently, ipmi_demagle_device_id requires a full response buffer in its data argument. This means we can't use it to parse a response in a struct ipmi_recv_msg, which has the netfn and cmd as separate bytes. This change alters the definition and users of ipmi_demangle_device_id to use a split netfn, cmd and data buffer, so it can be used with non-sequential responses. Signed-off-by: Jeremy Kerr Fixed the ipmi_ssif.c and ipmi_si_intf.c changes to use data from the response, not the data from the message, when passing info to the ipmi_demangle_device_id() function. Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_si_intf.c | 3 ++- drivers/char/ipmi/ipmi_ssif.c | 3 ++- include/linux/ipmi_smi.h | 24 ++++++++++++------------ 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index f8e28bad6d56..bc99369fca49 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -2926,7 +2926,8 @@ static int try_get_dev_id(struct smi_info *smi_info) resp, IPMI_MAX_MSG_LENGTH); /* Check and record info from the get device id, in case we need it. */ - rv = ipmi_demangle_device_id(resp, resp_len, &smi_info->device_id); + rv = ipmi_demangle_device_id(resp[0] >> 2, resp[1], + resp + 2, resp_len - 2, &smi_info->device_id); out: kfree(resp); diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c index 0aea3bcb6158..20ab098cd661 100644 --- a/drivers/char/ipmi/ipmi_ssif.c +++ b/drivers/char/ipmi/ipmi_ssif.c @@ -1491,7 +1491,8 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id) if (rv) goto out; - rv = ipmi_demangle_device_id(resp, len, &ssif_info->device_id); + rv = ipmi_demangle_device_id(resp[0] >> 2, resp[1], + resp + 2, len - 2, &ssif_info->device_id); if (rv) goto out; diff --git a/include/linux/ipmi_smi.h b/include/linux/ipmi_smi.h index f8cea14485dd..75542c837c07 100644 --- a/include/linux/ipmi_smi.h +++ b/include/linux/ipmi_smi.h @@ -162,27 +162,27 @@ struct ipmi_device_id { #define ipmi_version_major(v) ((v)->ipmi_version & 0xf) #define ipmi_version_minor(v) ((v)->ipmi_version >> 4) -/* Take a pointer to a raw data buffer and a length and extract device - id information from it. The first byte of data must point to the - netfn << 2, the data should be of the format: - netfn << 2, cmd, completion code, data - as normally comes from a device interface. */ -static inline int ipmi_demangle_device_id(const unsigned char *data, +/* Take a pointer to an IPMI response and extract device id information from + * it. @netfn is in the IPMI_NETFN_ format, so may need to be shifted from + * a SI response. + */ +static inline int ipmi_demangle_device_id(uint8_t netfn, uint8_t cmd, + const unsigned char *data, unsigned int data_len, struct ipmi_device_id *id) { - if (data_len < 9) + if (data_len < 7) return -EINVAL; - if (data[0] != IPMI_NETFN_APP_RESPONSE << 2 || - data[1] != IPMI_GET_DEVICE_ID_CMD) + if (netfn != IPMI_NETFN_APP_RESPONSE || cmd != IPMI_GET_DEVICE_ID_CMD) /* Strange, didn't get the response we expected. */ return -EINVAL; - if (data[2] != 0) + if (data[0] != 0) /* That's odd, it shouldn't be able to fail. */ return -EINVAL; - data += 3; - data_len -= 3; + data++; + data_len--; + id->device_id = data[0]; id->device_revision = data[1]; id->firmware_revision_1 = data[2]; From 68e7e50f195f34d0d539282779cad073d999192b Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Thu, 7 Sep 2017 08:43:05 -0500 Subject: [PATCH 16/48] ipmi: Don't use BMC product/dev ids in the BMC name There are a lot of bad things that a set of BMCs could do that would really confuse the IPMI driver; it's possible for BMCs with different GUIDs to have the same product/devid (though that's not technically legal), which would result in platform device namespace collisions. Fixing it would involve either using the GUID in the BMC name, which resulted in huge names, or just using an ida for numbering the BMCs. The latter approach was chosen to avoid the huge names. Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_msghandler.c | 45 +++++++---------------------- 1 file changed, 10 insertions(+), 35 deletions(-) diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 8814f4bed862..f42459a27b19 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -268,7 +268,6 @@ struct bmc_device { struct list_head intfs; unsigned char guid[16]; int guid_set; - char name[16]; struct kref usecount; }; #define to_bmc_device(x) container_of((x), struct bmc_device, pdev.dev) @@ -2591,6 +2590,8 @@ static struct bmc_device *ipmi_find_bmc_prod_dev_id( return bmc; } +static DEFINE_IDA(ipmi_bmc_ida); + static void release_bmc_device(struct device *dev) { @@ -2601,8 +2602,10 @@ static void cleanup_bmc_device(struct kref *ref) { struct bmc_device *bmc = container_of(ref, struct bmc_device, usecount); + int id = bmc->pdev.id; /* Unregister overwrites id */ platform_device_unregister(&bmc->pdev); + ida_simple_remove(&ipmi_bmc_ida, id); } static void ipmi_bmc_unregister(ipmi_smi_t intf) @@ -2663,47 +2666,19 @@ static int ipmi_bmc_register(ipmi_smi_t intf, int ifnum) bmc->id.product_id, bmc->id.device_id); } else { - unsigned char orig_dev_id = bmc->id.device_id; - int warn_printed = 0; - struct bmc_device *tmp_bmc; - - snprintf(bmc->name, sizeof(bmc->name), - "ipmi_bmc.%4.4x", bmc->id.product_id); - bmc->pdev.name = bmc->name; - - mutex_lock(&ipmidriver_mutex); - while ((tmp_bmc = ipmi_find_bmc_prod_dev_id(&ipmidriver.driver, - bmc->id.product_id, - bmc->id.device_id))) { - kref_put(&tmp_bmc->usecount, cleanup_bmc_device); - if (!warn_printed) { - printk(KERN_WARNING PFX - "This machine has two different BMCs" - " with the same product id and device" - " id. This is an error in the" - " firmware, but incrementing the" - " device id to work around the problem." - " Prod ID = 0x%x, Dev ID = 0x%x\n", - bmc->id.product_id, bmc->id.device_id); - warn_printed = 1; - } - bmc->id.device_id++; /* Wraps at 255 */ - if (bmc->id.device_id == orig_dev_id) { - printk(KERN_ERR PFX - "Out of device ids!\n"); - mutex_unlock(&ipmidriver_mutex); - rv = -EAGAIN; - goto out; - } - } + bmc->pdev.name = "ipmi_bmc"; + rv = ida_simple_get(&ipmi_bmc_ida, 0, 0, GFP_KERNEL); + if (rv < 0) + goto out; bmc->pdev.dev.driver = &ipmidriver.driver; - bmc->pdev.id = bmc->id.device_id; + bmc->pdev.id = rv; bmc->pdev.dev.release = release_bmc_device; bmc->pdev.dev.type = &bmc_device_type; kref_init(&bmc->usecount); rv = platform_device_register(&bmc->pdev); + mutex_lock(&ipmidriver_mutex); list_add_tail(&intf->bmc_link, &bmc->intfs); mutex_unlock(&ipmidriver_mutex); if (rv) { From aa9c9ab2443e3b9562c6c7cfc245a9e43b557d14 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Fri, 25 Aug 2017 15:47:24 +0800 Subject: [PATCH 17/48] ipmi: allow dynamic BMC version information Currently, it's up to the IPMI SMIs to provide the product & version details of BMCs behind registered IPMI SMI interfaces. This device ID is provided on SMI regsitration, and kept around for all future queries. However, this version information isn't always static. For example, a BMC may be upgraded at runtime, making the old version information stale. This change allows querying the BMC device ID & version information dynamically. If no static device_id argument is provided to ipmi_register_smi, then the IPMI core code will perform a Get Device ID IPMI command to query the version information when needed. We keep a short-term cache of this information so we don't need to re-query for every attribute access. Signed-off-by: Jeremy Kerr I basically rewrote this, I fixed some locking issues and simplified things. Same functional change, though. Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_msghandler.c | 209 +++++++++++++++++++++++++--- 1 file changed, 192 insertions(+), 17 deletions(-) diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index f42459a27b19..9157a9e17c36 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -159,6 +159,9 @@ static struct proc_dir_entry *proc_ipmi_root; */ #define IPMI_REQUEST_EV_TIME (1000 / (IPMI_TIMEOUT_TIME)) +/* How long should we cache dynamic device IDs? */ +#define IPMI_DYN_DEV_ID_EXPIRY (10 * HZ) + /* * The main "user" data structure. */ @@ -264,8 +267,12 @@ struct ipmi_proc_entry { struct bmc_device { struct platform_device pdev; - struct ipmi_device_id id; struct list_head intfs; + struct ipmi_device_id id; + struct ipmi_device_id fetch_id; + int dyn_id_set; + unsigned long dyn_id_expiry; + struct mutex dyn_mutex; /* protects id & dyn* fields */ unsigned char guid[16]; int guid_set; struct kref usecount; @@ -402,6 +409,13 @@ struct ipmi_smi { /* Used for wake ups at startup. */ wait_queue_head_t waitq; + /* + * Prevents the interface from being unregistered when the + * interface is used by being looked up through the BMC + * structure. + */ + struct mutex bmc_reg_mutex; + struct bmc_device *bmc; bool bmc_registered; struct list_head bmc_link; @@ -491,6 +505,11 @@ struct ipmi_smi { * interface comes in with a NULL user, call this routine with * it. Note that the message will still be freed by the * caller. This only works on the system interface. + * + * The only user outside of initialization an panic handling is + * the dynamic device id fetching, so no mutex is currently + * required on this. If more users come along, some sort of + * mutex will be required. */ void (*null_user_handler)(ipmi_smi_t intf, struct ipmi_recv_msg *msg); @@ -2081,14 +2100,158 @@ int ipmi_request_supply_msgs(ipmi_user_t user, } EXPORT_SYMBOL(ipmi_request_supply_msgs); +static void bmc_device_id_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg) +{ + int rv; + + if ((msg->addr.addr_type != IPMI_SYSTEM_INTERFACE_ADDR_TYPE) + || (msg->msg.netfn != IPMI_NETFN_APP_RESPONSE) + || (msg->msg.cmd != IPMI_GET_DEVICE_ID_CMD)) { + pr_warn(PFX "invalid device_id msg: addr_type=%d netfn=%x cmd=%x\n", + msg->addr.addr_type, msg->msg.netfn, msg->msg.cmd); + return; + } + + rv = ipmi_demangle_device_id(msg->msg.netfn, msg->msg.cmd, + msg->msg.data, msg->msg.data_len, &intf->bmc->fetch_id); + if (rv) { + pr_warn(PFX "device id demangle failed: %d\n", rv); + intf->bmc->dyn_id_set = 0; + } else { + /* + * Make sure the id data is available before setting + * dyn_id_set. + */ + smp_wmb(); + intf->bmc->dyn_id_set = 1; + } + + wake_up(&intf->waitq); +} + +static int +send_get_device_id_cmd(ipmi_smi_t intf) +{ + struct ipmi_system_interface_addr si; + struct kernel_ipmi_msg msg; + + si.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + si.channel = IPMI_BMC_CHANNEL; + si.lun = 0; + + msg.netfn = IPMI_NETFN_APP_REQUEST; + msg.cmd = IPMI_GET_DEVICE_ID_CMD; + msg.data = NULL; + msg.data_len = 0; + + return i_ipmi_request(NULL, + intf, + (struct ipmi_addr *) &si, + 0, + &msg, + intf, + NULL, + NULL, + 0, + intf->channels[0].address, + intf->channels[0].lun, + -1, 0); +} + +static int __get_device_id(ipmi_smi_t intf, struct bmc_device *bmc) +{ + int rv; + + bmc->dyn_id_set = 2; + + intf->null_user_handler = bmc_device_id_handler; + + rv = send_get_device_id_cmd(intf); + if (rv) + return rv; + + wait_event(intf->waitq, bmc->dyn_id_set != 2); + + if (!bmc->dyn_id_set) + rv = -EIO; /* Something went wrong in the fetch. */ + + /* dyn_id_set makes the id data available. */ + smp_rmb(); + + intf->null_user_handler = NULL; + + return rv; +} + +/* + * Fetch the device id for the bmc/interface. You must pass in either + * bmc or intf, this code will get the other one. If the data has + * been recently fetched, this will just use the cached data. Otherwise + * it will run a new fetch. + * + * Except for the first time this is called (in ipmi_register_smi()), + * this will always return good data; + */ static int bmc_get_device_id(ipmi_smi_t intf, struct bmc_device *bmc, struct ipmi_device_id *id) { - if (!bmc) - bmc = intf->bmc; + int rv = 0; + int prev_dyn_id_set; - *id = bmc->id; - return 0; + if (!intf) { + mutex_lock(&bmc->dyn_mutex); +retry_bmc_lock: + if (list_empty(&bmc->intfs)) { + mutex_unlock(&bmc->dyn_mutex); + return -ENOENT; + } + intf = list_first_entry(&bmc->intfs, struct ipmi_smi, + bmc_link); + kref_get(&intf->refcount); + mutex_unlock(&bmc->dyn_mutex); + mutex_lock(&intf->bmc_reg_mutex); + mutex_lock(&bmc->dyn_mutex); + if (intf != list_first_entry(&bmc->intfs, struct ipmi_smi, + bmc_link)) { + mutex_unlock(&intf->bmc_reg_mutex); + kref_put(&intf->refcount, intf_free); + goto retry_bmc_lock; + } + } else { + mutex_lock(&intf->bmc_reg_mutex); + bmc = intf->bmc; + mutex_lock(&bmc->dyn_mutex); + kref_get(&intf->refcount); + } + + /* If we have a valid and current ID, just return that. */ + if (bmc->dyn_id_set && time_is_after_jiffies(bmc->dyn_id_expiry)) + goto out; + + prev_dyn_id_set = bmc->dyn_id_set; + + rv = __get_device_id(intf, bmc); + if (rv) + goto out; + + memcpy(&bmc->id, &bmc->fetch_id, sizeof(bmc->id)); + + bmc->dyn_id_expiry = jiffies + IPMI_DYN_DEV_ID_EXPIRY; + +out: + if (rv && prev_dyn_id_set) { + rv = 0; /* Ignore failures if we have previous data. */ + bmc->dyn_id_set = prev_dyn_id_set; + } + + if (id) + *id = bmc->id; + + mutex_unlock(&bmc->dyn_mutex); + mutex_unlock(&intf->bmc_reg_mutex); + + kref_put(&intf->refcount, intf_free); + return rv; } #ifdef CONFIG_PROC_FS @@ -2615,17 +2778,23 @@ static void ipmi_bmc_unregister(ipmi_smi_t intf) if (!intf->bmc_registered) return; + mutex_lock(&intf->bmc_reg_mutex); + sysfs_remove_link(&intf->si_dev->kobj, "bmc"); sysfs_remove_link(&bmc->pdev.dev.kobj, intf->my_dev_name); kfree(intf->my_dev_name); intf->my_dev_name = NULL; - mutex_lock(&ipmidriver_mutex); + mutex_lock(&bmc->dyn_mutex); list_del(&intf->bmc_link); + mutex_unlock(&bmc->dyn_mutex); intf->bmc = NULL; + mutex_lock(&ipmidriver_mutex); kref_put(&bmc->usecount, cleanup_bmc_device); mutex_unlock(&ipmidriver_mutex); intf->bmc_registered = false; + + mutex_unlock(&intf->bmc_reg_mutex); } static int ipmi_bmc_register(ipmi_smi_t intf, int ifnum) @@ -2653,11 +2822,11 @@ static int ipmi_bmc_register(ipmi_smi_t intf, int ifnum) */ if (old_bmc) { kfree(bmc); - mutex_lock(&ipmidriver_mutex); - intf->bmc = old_bmc; - list_add_tail(&intf->bmc_link, &bmc->intfs); - mutex_unlock(&ipmidriver_mutex); bmc = old_bmc; + intf->bmc = old_bmc; + mutex_lock(&bmc->dyn_mutex); + list_add_tail(&intf->bmc_link, &bmc->intfs); + mutex_unlock(&bmc->dyn_mutex); printk(KERN_INFO "ipmi: interfacing existing BMC (man_id: 0x%6.6x," @@ -2677,10 +2846,12 @@ static int ipmi_bmc_register(ipmi_smi_t intf, int ifnum) bmc->pdev.dev.type = &bmc_device_type; kref_init(&bmc->usecount); - rv = platform_device_register(&bmc->pdev); - mutex_lock(&ipmidriver_mutex); + intf->bmc = bmc; + mutex_lock(&bmc->dyn_mutex); list_add_tail(&intf->bmc_link, &bmc->intfs); - mutex_unlock(&ipmidriver_mutex); + mutex_unlock(&bmc->dyn_mutex); + + rv = platform_device_register(&bmc->pdev); if (rv) { printk(KERN_ERR "ipmi_msghandler:" @@ -2743,18 +2914,20 @@ out_unlink1: sysfs_remove_link(&intf->si_dev->kobj, "bmc"); out_put_bmc: - mutex_lock(&ipmidriver_mutex); + mutex_lock(&bmc->dyn_mutex); list_del(&intf->bmc_link); + mutex_unlock(&bmc->dyn_mutex); intf->bmc = NULL; + mutex_lock(&ipmidriver_mutex); kref_put(&bmc->usecount, cleanup_bmc_device); mutex_unlock(&ipmidriver_mutex); goto out; out_list_del: - mutex_lock(&ipmidriver_mutex); + mutex_lock(&bmc->dyn_mutex); list_del(&intf->bmc_link); + mutex_unlock(&bmc->dyn_mutex); intf->bmc = NULL; - mutex_unlock(&ipmidriver_mutex); put_device(&bmc->pdev.dev); goto out; } @@ -2976,9 +3149,11 @@ int ipmi_register_smi(const struct ipmi_smi_handlers *handlers, return -ENOMEM; } INIT_LIST_HEAD(&intf->bmc->intfs); + mutex_init(&intf->bmc->dyn_mutex); + INIT_LIST_HEAD(&intf->bmc_link); + mutex_init(&intf->bmc_reg_mutex); intf->intf_num = -1; /* Mark it invalid for now. */ kref_init(&intf->refcount); - intf->bmc->id = *device_id; intf->si_dev = si_dev; for (j = 0; j < IPMI_MAX_CHANNELS; j++) { intf->channels[j].address = IPMI_BMC_SLAVE_ADDR; From 1e5058ea21010883b1e1d288637f7390bb8d1c61 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Thu, 31 Aug 2017 16:45:40 -0500 Subject: [PATCH 18/48] ipmi: Remove the device id from ipmi_register_smi() It's no longer used, dynamic device id handling is in place now. Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_msghandler.c | 1 - drivers/char/ipmi/ipmi_powernv.c | 4 +--- drivers/char/ipmi/ipmi_si_intf.c | 1 - drivers/char/ipmi/ipmi_ssif.c | 19 ------------------- include/linux/ipmi_smi.h | 1 - 5 files changed, 1 insertion(+), 25 deletions(-) diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 9157a9e17c36..ee108be13348 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -3112,7 +3112,6 @@ EXPORT_SYMBOL(ipmi_poll_interface); int ipmi_register_smi(const struct ipmi_smi_handlers *handlers, void *send_info, - struct ipmi_device_id *device_id, struct device *si_dev, unsigned char slave_addr) { diff --git a/drivers/char/ipmi/ipmi_powernv.c b/drivers/char/ipmi/ipmi_powernv.c index b338a4becbf8..07fddbefefe4 100644 --- a/drivers/char/ipmi/ipmi_powernv.c +++ b/drivers/char/ipmi/ipmi_powernv.c @@ -23,7 +23,6 @@ struct ipmi_smi_powernv { u64 interface_id; - struct ipmi_device_id ipmi_id; ipmi_smi_t intf; unsigned int irq; @@ -266,8 +265,7 @@ static int ipmi_powernv_probe(struct platform_device *pdev) } /* todo: query actual ipmi_device_id */ - rc = ipmi_register_smi(&ipmi_powernv_smi_handlers, ipmi, - &ipmi->ipmi_id, dev, 0); + rc = ipmi_register_smi(&ipmi_powernv_smi_handlers, ipmi, dev, 0); if (rc) { dev_warn(dev, "IPMI SMI registration failed (%d)\n", rc); goto err_free_msg; diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index bc99369fca49..4caa793a6765 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -3631,7 +3631,6 @@ static int try_smi_init(struct smi_info *new_smi) rv = ipmi_register_smi(&handlers, new_smi, - &new_smi->device_id, new_smi->dev, new_smi->slave_addr); if (rv) { diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c index 20ab098cd661..dd716d06ce73 100644 --- a/drivers/char/ipmi/ipmi_ssif.c +++ b/drivers/char/ipmi/ipmi_ssif.c @@ -267,9 +267,6 @@ struct ssif_info { unsigned char *i2c_data; unsigned int i2c_size; - /* From the device id response. */ - struct ipmi_device_id device_id; - struct timer_list retry_timer; int retries_left; @@ -1481,21 +1478,6 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id) ipmi_addr_src_to_str(ssif_info->addr_source), client->addr, client->adapter->name, slave_addr); - /* - * Do a Get Device ID command, since it comes back with some - * useful info. - */ - msg[0] = IPMI_NETFN_APP_REQUEST << 2; - msg[1] = IPMI_GET_DEVICE_ID_CMD; - rv = do_cmd(client, 2, msg, &len, resp); - if (rv) - goto out; - - rv = ipmi_demangle_device_id(resp[0] >> 2, resp[1], - resp + 2, len - 2, &ssif_info->device_id); - if (rv) - goto out; - ssif_info->client = client; i2c_set_clientdata(client, ssif_info); @@ -1685,7 +1667,6 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id) rv = ipmi_register_smi(&ssif_info->handlers, ssif_info, - &ssif_info->device_id, &ssif_info->client->dev, slave_addr); if (rv) { diff --git a/include/linux/ipmi_smi.h b/include/linux/ipmi_smi.h index 75542c837c07..97771e36b7f0 100644 --- a/include/linux/ipmi_smi.h +++ b/include/linux/ipmi_smi.h @@ -214,7 +214,6 @@ static inline int ipmi_demangle_device_id(uint8_t netfn, uint8_t cmd, call. */ int ipmi_register_smi(const struct ipmi_smi_handlers *handlers, void *send_info, - struct ipmi_device_id *device_id, struct device *dev, unsigned char slave_addr); From 39d3fb456009d3619b90236cb8edf156932b1bd4 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Fri, 1 Sep 2017 14:39:18 -0500 Subject: [PATCH 19/48] ipmi: Always fetch the guid through ipmi_get_device_id() This is in preparation for making ipmi_get_device_id() dynamically return the guid and device id. Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_msghandler.c | 93 ++++++++++++++++++++--------- 1 file changed, 65 insertions(+), 28 deletions(-) diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index ee108be13348..9a6b048b1792 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -273,14 +273,15 @@ struct bmc_device { int dyn_id_set; unsigned long dyn_id_expiry; struct mutex dyn_mutex; /* protects id & dyn* fields */ - unsigned char guid[16]; + u8 guid[16]; int guid_set; struct kref usecount; }; #define to_bmc_device(x) container_of((x), struct bmc_device, pdev.dev) static int bmc_get_device_id(ipmi_smi_t intf, struct bmc_device *bmc, - struct ipmi_device_id *id); + struct ipmi_device_id *id, + bool *guid_set, u8 *guid); /* * Various statistics for IPMI, these index stats[] in the ipmi_smi @@ -1220,7 +1221,7 @@ int ipmi_get_version(ipmi_user_t user, struct ipmi_device_id id; int rv; - rv = bmc_get_device_id(user->intf, NULL, &id); + rv = bmc_get_device_id(user->intf, NULL, &id, NULL, NULL); if (rv) return rv; @@ -2193,7 +2194,8 @@ static int __get_device_id(ipmi_smi_t intf, struct bmc_device *bmc) * this will always return good data; */ static int bmc_get_device_id(ipmi_smi_t intf, struct bmc_device *bmc, - struct ipmi_device_id *id) + struct ipmi_device_id *id, + bool *guid_set, u8 *guid) { int rv = 0; int prev_dyn_id_set; @@ -2247,6 +2249,12 @@ out: if (id) *id = bmc->id; + if (guid_set) + *guid_set = bmc->guid_set; + + if (guid && bmc->guid_set) + memcpy(guid, bmc->guid, 16); + mutex_unlock(&bmc->dyn_mutex); mutex_unlock(&intf->bmc_reg_mutex); @@ -2286,7 +2294,7 @@ static int smi_version_proc_show(struct seq_file *m, void *v) struct ipmi_device_id id; int rv; - rv = bmc_get_device_id(intf, NULL, &id); + rv = bmc_get_device_id(intf, NULL, &id, NULL, NULL); if (rv) return rv; @@ -2478,7 +2486,7 @@ static ssize_t device_id_show(struct device *dev, struct ipmi_device_id id; int rv; - rv = bmc_get_device_id(NULL, bmc, &id); + rv = bmc_get_device_id(NULL, bmc, &id, NULL, NULL); if (rv) return rv; @@ -2494,7 +2502,7 @@ static ssize_t provides_device_sdrs_show(struct device *dev, struct ipmi_device_id id; int rv; - rv = bmc_get_device_id(NULL, bmc, &id); + rv = bmc_get_device_id(NULL, bmc, &id, NULL, NULL); if (rv) return rv; @@ -2510,7 +2518,7 @@ static ssize_t revision_show(struct device *dev, struct device_attribute *attr, struct ipmi_device_id id; int rv; - rv = bmc_get_device_id(NULL, bmc, &id); + rv = bmc_get_device_id(NULL, bmc, &id, NULL, NULL); if (rv) return rv; @@ -2526,7 +2534,7 @@ static ssize_t firmware_revision_show(struct device *dev, struct ipmi_device_id id; int rv; - rv = bmc_get_device_id(NULL, bmc, &id); + rv = bmc_get_device_id(NULL, bmc, &id, NULL, NULL); if (rv) return rv; @@ -2543,7 +2551,7 @@ static ssize_t ipmi_version_show(struct device *dev, struct ipmi_device_id id; int rv; - rv = bmc_get_device_id(NULL, bmc, &id); + rv = bmc_get_device_id(NULL, bmc, &id, NULL, NULL); if (rv) return rv; @@ -2561,7 +2569,7 @@ static ssize_t add_dev_support_show(struct device *dev, struct ipmi_device_id id; int rv; - rv = bmc_get_device_id(NULL, bmc, &id); + rv = bmc_get_device_id(NULL, bmc, &id, NULL, NULL); if (rv) return rv; @@ -2578,7 +2586,7 @@ static ssize_t manufacturer_id_show(struct device *dev, struct ipmi_device_id id; int rv; - rv = bmc_get_device_id(NULL, bmc, &id); + rv = bmc_get_device_id(NULL, bmc, &id, NULL, NULL); if (rv) return rv; @@ -2594,7 +2602,7 @@ static ssize_t product_id_show(struct device *dev, struct ipmi_device_id id; int rv; - rv = bmc_get_device_id(NULL, bmc, &id); + rv = bmc_get_device_id(NULL, bmc, &id, NULL, NULL); if (rv) return rv; @@ -2610,7 +2618,7 @@ static ssize_t aux_firmware_rev_show(struct device *dev, struct ipmi_device_id id; int rv; - rv = bmc_get_device_id(NULL, bmc, &id); + rv = bmc_get_device_id(NULL, bmc, &id, NULL, NULL); if (rv) return rv; @@ -2626,13 +2634,22 @@ static ssize_t guid_show(struct device *dev, struct device_attribute *attr, char *buf) { struct bmc_device *bmc = to_bmc_device(dev); + bool guid_set; + u8 guid[16]; + int rv; + + rv = bmc_get_device_id(NULL, bmc, NULL, &guid_set, guid); + if (rv) + return rv; + if (!guid_set) + return -ENOENT; return snprintf(buf, 100, - "%2.2x%2.2x%2.2x%2.2x-%2.2x%2.2x-%2.2x%2.2x-%2.2x%2.2x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n", - bmc->guid[3], bmc->guid[2], bmc->guid[1], bmc->guid[0], - bmc->guid[5], bmc->guid[4], bmc->guid[7], bmc->guid[6], - bmc->guid[8], bmc->guid[9], bmc->guid[10], bmc->guid[11], - bmc->guid[12], bmc->guid[13], bmc->guid[14], bmc->guid[15]); + "%2.2x%2.2x%2.2x%2.2x-%2.2x%2.2x-%2.2x%2.2x-%2.2x%2.2x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n", + guid[3], guid[2], guid[1], guid[0], + guid[5], guid[4], guid[7], guid[6], + guid[8], guid[9], guid[10], guid[11], + guid[12], guid[13], guid[14], guid[15]); } static DEVICE_ATTR(guid, S_IRUGO, guid_show, NULL); @@ -2656,15 +2673,20 @@ static umode_t bmc_dev_attr_is_visible(struct kobject *kobj, struct device *dev = kobj_to_dev(kobj); struct bmc_device *bmc = to_bmc_device(dev); umode_t mode = attr->mode; - struct ipmi_device_id id; int rv; if (attr == &dev_attr_aux_firmware_revision.attr) { - rv = bmc_get_device_id(NULL, bmc, &id); + struct ipmi_device_id id; + + rv = bmc_get_device_id(NULL, bmc, &id, NULL, NULL); return (!rv && id.aux_firmware_revision_set) ? mode : 0; } - if (attr == &dev_attr_guid.attr) - return bmc->guid_set ? mode : 0; + if (attr == &dev_attr_guid.attr) { + bool guid_set; + + rv = bmc_get_device_id(NULL, bmc, NULL, &guid_set, NULL); + return (!rv && guid_set) ? mode : 0; + } return mode; } @@ -2685,11 +2707,20 @@ static const struct device_type bmc_device_type = { static int __find_bmc_guid(struct device *dev, void *data) { unsigned char *id = data; + struct bmc_device *bmc; + bool guid_set; + u8 guid[16]; + int rv; if (dev->type != &bmc_device_type) return 0; - return memcmp(to_bmc_device(dev)->guid, id, 16) == 0; + bmc = to_bmc_device(dev); + rv = bmc_get_device_id(NULL, bmc, NULL, &guid_set, guid); + if (rv || !guid_set) + return 0; + + return memcmp(guid, id, 16) == 0; } /* @@ -2718,15 +2749,21 @@ struct prod_dev_id { static int __find_bmc_prod_dev_id(struct device *dev, void *data) { - struct prod_dev_id *id = data; + struct prod_dev_id *cid = data; struct bmc_device *bmc; + struct ipmi_device_id id; + int rv; if (dev->type != &bmc_device_type) return 0; bmc = to_bmc_device(dev); - return (bmc->id.product_id == id->product_id - && bmc->id.device_id == id->device_id); + rv = bmc_get_device_id(NULL, bmc, &id, NULL, NULL); + if (rv) + return 0; + + return (id.product_id == cid->product_id + && id.device_id == cid->device_id); } /* @@ -3219,7 +3256,7 @@ int ipmi_register_smi(const struct ipmi_smi_handlers *handlers, get_guid(intf); - rv = bmc_get_device_id(intf, NULL, &id); + rv = bmc_get_device_id(intf, NULL, &id, NULL, NULL); if (rv) { dev_err(si_dev, "Unable to get the device id: %d\n", rv); goto out; From 28f26ac7a963901106b64307bc1c93068331a008 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Fri, 1 Sep 2017 15:30:46 -0500 Subject: [PATCH 20/48] ipmi: Dynamically fetch GUID periodically This will catch if the GUID changes. Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_msghandler.c | 61 ++++++++++++++++++++--------- 1 file changed, 42 insertions(+), 19 deletions(-) diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 9a6b048b1792..98318b965de7 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -274,7 +274,8 @@ struct bmc_device { unsigned long dyn_id_expiry; struct mutex dyn_mutex; /* protects id & dyn* fields */ u8 guid[16]; - int guid_set; + u8 fetch_guid[16]; + int dyn_guid_set; struct kref usecount; }; #define to_bmc_device(x) container_of((x), struct bmc_device, pdev.dev) @@ -538,6 +539,8 @@ struct ipmi_smi { }; #define to_si_intf_from_dev(device) container_of(device, struct ipmi_smi, dev) +static void __get_guid(ipmi_smi_t intf); + /** * The driver model view of the IPMI messaging driver. */ @@ -2198,7 +2201,7 @@ static int bmc_get_device_id(ipmi_smi_t intf, struct bmc_device *bmc, bool *guid_set, u8 *guid) { int rv = 0; - int prev_dyn_id_set; + int prev_dyn_id_set, prev_guid_set; if (!intf) { mutex_lock(&bmc->dyn_mutex); @@ -2230,8 +2233,19 @@ retry_bmc_lock: if (bmc->dyn_id_set && time_is_after_jiffies(bmc->dyn_id_expiry)) goto out; - prev_dyn_id_set = bmc->dyn_id_set; + prev_guid_set = bmc->dyn_guid_set; + __get_guid(intf); + if (bmc->dyn_guid_set) + memcpy(bmc->guid, bmc->fetch_guid, 16); + else if (prev_guid_set) + /* + * The guid used to be valid and it failed to fetch, + * just use the cached value. + */ + bmc->dyn_guid_set = prev_guid_set; + + prev_dyn_id_set = bmc->dyn_id_set; rv = __get_device_id(intf, bmc); if (rv) goto out; @@ -2250,9 +2264,9 @@ out: *id = bmc->id; if (guid_set) - *guid_set = bmc->guid_set; + *guid_set = bmc->dyn_guid_set; - if (guid && bmc->guid_set) + if (guid && bmc->dyn_guid_set) memcpy(guid, bmc->guid, 16); mutex_unlock(&bmc->dyn_mutex); @@ -2845,7 +2859,7 @@ static int ipmi_bmc_register(ipmi_smi_t intf, int ifnum) * representing the interfaced BMC already */ mutex_lock(&ipmidriver_mutex); - if (bmc->guid_set) + if (bmc->dyn_guid_set) old_bmc = ipmi_find_bmc_guid(&ipmidriver.driver, bmc->guid); else old_bmc = ipmi_find_bmc_prod_dev_id(&ipmidriver.driver, @@ -2997,9 +3011,10 @@ send_guid_cmd(ipmi_smi_t intf, int chan) -1, 0); } -static void -guid_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg) +static void guid_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg) { + struct bmc_device *bmc = intf->bmc; + if ((msg->addr.addr_type != IPMI_SYSTEM_INTERFACE_ADDR_TYPE) || (msg->msg.netfn != IPMI_NETFN_APP_RESPONSE) || (msg->msg.cmd != IPMI_GET_DEVICE_GUID_CMD)) @@ -3008,12 +3023,12 @@ guid_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg) if (msg->msg.data[0] != 0) { /* Error from getting the GUID, the BMC doesn't have one. */ - intf->bmc->guid_set = 0; + bmc->dyn_guid_set = 0; goto out; } if (msg->msg.data_len < 17) { - intf->bmc->guid_set = 0; + bmc->dyn_guid_set = 0; printk(KERN_WARNING PFX "guid_handler: The GUID response from the BMC was too" " short, it was %d but should have been 17. Assuming" @@ -3022,24 +3037,34 @@ guid_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg) goto out; } - memcpy(intf->bmc->guid, msg->msg.data + 1, 16); - intf->bmc->guid_set = 1; + memcpy(bmc->fetch_guid, msg->msg.data + 1, 16); + /* + * Make sure the guid data is available before setting + * dyn_guid_set. + */ + smp_wmb(); + bmc->dyn_guid_set = 1; out: wake_up(&intf->waitq); } -static void -get_guid(ipmi_smi_t intf) +static void __get_guid(ipmi_smi_t intf) { int rv; + struct bmc_device *bmc = intf->bmc; - intf->bmc->guid_set = 0x2; + bmc->dyn_guid_set = 2; intf->null_user_handler = guid_handler; rv = send_guid_cmd(intf, 0); if (rv) /* Send failed, no GUID available. */ - intf->bmc->guid_set = 0; - wait_event(intf->waitq, intf->bmc->guid_set != 2); + bmc->dyn_guid_set = 0; + + wait_event(intf->waitq, bmc->dyn_guid_set != 2); + + /* dyn_guid_set makes the guid data available. */ + smp_rmb(); + intf->null_user_handler = NULL; } @@ -3254,8 +3279,6 @@ int ipmi_register_smi(const struct ipmi_smi_handlers *handlers, if (rv) goto out; - get_guid(intf); - rv = bmc_get_device_id(intf, NULL, &id, NULL, NULL); if (rv) { dev_err(si_dev, "Unable to get the device id: %d\n", rv); From c659ff34f6303077efd45de884c5cab734b29df5 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Fri, 1 Sep 2017 15:34:10 -0500 Subject: [PATCH 21/48] ipmi: Use a temporary BMC for an interface This is getting ready for the ability to redo the BMC if it's information changes, we need a fallback mechanism. Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_msghandler.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 98318b965de7..9d4a9a94fdc6 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -418,6 +418,7 @@ struct ipmi_smi { */ struct mutex bmc_reg_mutex; + struct bmc_device tmp_bmc; struct bmc_device *bmc; bool bmc_registered; struct list_head bmc_link; @@ -2839,7 +2840,7 @@ static void ipmi_bmc_unregister(ipmi_smi_t intf) mutex_lock(&bmc->dyn_mutex); list_del(&intf->bmc_link); mutex_unlock(&bmc->dyn_mutex); - intf->bmc = NULL; + intf->bmc = &intf->tmp_bmc; mutex_lock(&ipmidriver_mutex); kref_put(&bmc->usecount, cleanup_bmc_device); mutex_unlock(&ipmidriver_mutex); @@ -2872,7 +2873,6 @@ static int ipmi_bmc_register(ipmi_smi_t intf, int ifnum) * otherwise register the new BMC device */ if (old_bmc) { - kfree(bmc); bmc = old_bmc; intf->bmc = old_bmc; mutex_lock(&bmc->dyn_mutex); @@ -2886,6 +2886,14 @@ static int ipmi_bmc_register(ipmi_smi_t intf, int ifnum) bmc->id.product_id, bmc->id.device_id); } else { + bmc = kzalloc(sizeof(*bmc), GFP_KERNEL); + if (!bmc) { + rv = -ENOMEM; + goto out; + } + INIT_LIST_HEAD(&bmc->intfs); + mutex_init(&bmc->dyn_mutex); + bmc->pdev.name = "ipmi_bmc"; rv = ida_simple_get(&ipmi_bmc_ida, 0, 0, GFP_KERNEL); @@ -2968,7 +2976,7 @@ out_put_bmc: mutex_lock(&bmc->dyn_mutex); list_del(&intf->bmc_link); mutex_unlock(&bmc->dyn_mutex); - intf->bmc = NULL; + intf->bmc = &intf->tmp_bmc; mutex_lock(&ipmidriver_mutex); kref_put(&bmc->usecount, cleanup_bmc_device); mutex_unlock(&ipmidriver_mutex); @@ -2978,7 +2986,7 @@ out_list_del: mutex_lock(&bmc->dyn_mutex); list_del(&intf->bmc_link); mutex_unlock(&bmc->dyn_mutex); - intf->bmc = NULL; + intf->bmc = &intf->tmp_bmc; put_device(&bmc->pdev.dev); goto out; } @@ -3204,11 +3212,7 @@ int ipmi_register_smi(const struct ipmi_smi_handlers *handlers, if (!intf) return -ENOMEM; - intf->bmc = kzalloc(sizeof(*intf->bmc), GFP_KERNEL); - if (!intf->bmc) { - kfree(intf); - return -ENOMEM; - } + intf->bmc = &intf->tmp_bmc; INIT_LIST_HEAD(&intf->bmc->intfs); mutex_init(&intf->bmc->dyn_mutex); INIT_LIST_HEAD(&intf->bmc_link); From b2cfd8ab4add53c2070367bfee2f5b738f51698d Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Fri, 1 Sep 2017 16:32:40 -0500 Subject: [PATCH 22/48] ipmi: Rework device id and guid handling to catch changing BMCs A BMC's guid or device id info may change dynamically, this could result in a different configuration that needs to be done. Adjust the BMCs dynamically. Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_msghandler.c | 240 +++++++++++++++++++--------- 1 file changed, 167 insertions(+), 73 deletions(-) diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 9d4a9a94fdc6..1da0b3cca6aa 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -265,18 +265,24 @@ struct ipmi_proc_entry { }; #endif +/* + * Note that the product id, manufacturer id, guid, and device id are + * immutable in this structure, so dyn_mutex is not required for + * accessing those. If those change on a BMC, a new BMC is allocated. + */ struct bmc_device { struct platform_device pdev; - struct list_head intfs; + struct list_head intfs; /* Interfaces on this BMC. */ struct ipmi_device_id id; struct ipmi_device_id fetch_id; int dyn_id_set; unsigned long dyn_id_expiry; - struct mutex dyn_mutex; /* protects id & dyn* fields */ + struct mutex dyn_mutex; /* Protects id, intfs, & dyn* */ u8 guid[16]; u8 fetch_guid[16]; int dyn_guid_set; struct kref usecount; + struct work_struct remove_work; }; #define to_bmc_device(x) container_of((x), struct bmc_device, pdev.dev) @@ -423,6 +429,7 @@ struct ipmi_smi { bool bmc_registered; struct list_head bmc_link; char *my_dev_name; + bool in_bmc_register; /* Handle recursive situations. Yuck. */ /* * This is the lower-layer's sender routine. Note that you @@ -509,10 +516,7 @@ struct ipmi_smi { * it. Note that the message will still be freed by the * caller. This only works on the system interface. * - * The only user outside of initialization an panic handling is - * the dynamic device id fetching, so no mutex is currently - * required on this. If more users come along, some sort of - * mutex will be required. + * Protected by bmc_reg_mutex. */ void (*null_user_handler)(ipmi_smi_t intf, struct ipmi_recv_msg *msg); @@ -541,6 +545,11 @@ struct ipmi_smi { #define to_si_intf_from_dev(device) container_of(device, struct ipmi_smi, dev) static void __get_guid(ipmi_smi_t intf); +static void __ipmi_bmc_unregister(ipmi_smi_t intf); +static int __ipmi_bmc_register(ipmi_smi_t intf, + struct ipmi_device_id *id, + bool guid_set, u8 *guid, int intf_num); + /** * The driver model view of the IPMI messaging driver. @@ -552,9 +561,7 @@ static struct platform_driver ipmidriver = { } }; /* - * This mutex protects adding/removing BMCs on the ipmidriver's device - * list. This way we can pull items out of the driver's list and reuse - * them. + * This mutex keeps us from adding the same BMC twice. */ static DEFINE_MUTEX(ipmidriver_mutex); @@ -2197,12 +2204,13 @@ static int __get_device_id(ipmi_smi_t intf, struct bmc_device *bmc) * Except for the first time this is called (in ipmi_register_smi()), * this will always return good data; */ -static int bmc_get_device_id(ipmi_smi_t intf, struct bmc_device *bmc, - struct ipmi_device_id *id, - bool *guid_set, u8 *guid) +static int __bmc_get_device_id(ipmi_smi_t intf, struct bmc_device *bmc, + struct ipmi_device_id *id, + bool *guid_set, u8 *guid, int intf_num) { int rv = 0; int prev_dyn_id_set, prev_guid_set; + bool intf_set = intf != NULL; if (!intf) { mutex_lock(&bmc->dyn_mutex); @@ -2231,27 +2239,60 @@ retry_bmc_lock: } /* If we have a valid and current ID, just return that. */ - if (bmc->dyn_id_set && time_is_after_jiffies(bmc->dyn_id_expiry)) - goto out; + if (intf->in_bmc_register || + (bmc->dyn_id_set && time_is_after_jiffies(bmc->dyn_id_expiry))) + goto out_noprocessing; prev_guid_set = bmc->dyn_guid_set; __get_guid(intf); - if (bmc->dyn_guid_set) - memcpy(bmc->guid, bmc->fetch_guid, 16); - else if (prev_guid_set) - /* - * The guid used to be valid and it failed to fetch, - * just use the cached value. - */ - bmc->dyn_guid_set = prev_guid_set; - prev_dyn_id_set = bmc->dyn_id_set; rv = __get_device_id(intf, bmc); if (rv) goto out; - memcpy(&bmc->id, &bmc->fetch_id, sizeof(bmc->id)); + /* + * The guid, device id, manufacturer id, and product id should + * not change on a BMC. If it does we have to do some dancing. + */ + if (!intf->bmc_registered + || (!prev_guid_set && bmc->dyn_guid_set) + || (!prev_dyn_id_set && bmc->dyn_id_set) + || (prev_guid_set && bmc->dyn_guid_set + && memcmp(bmc->guid, bmc->fetch_guid, 16)) + || bmc->id.device_id != bmc->fetch_id.device_id + || bmc->id.manufacturer_id != bmc->fetch_id.manufacturer_id + || bmc->id.product_id != bmc->fetch_id.product_id) { + struct ipmi_device_id id = bmc->fetch_id; + int guid_set = bmc->dyn_guid_set; + u8 guid[16]; + + memcpy(guid, bmc->fetch_guid, 16); + mutex_unlock(&bmc->dyn_mutex); + + __ipmi_bmc_unregister(intf); + /* Fill in the temporary BMC for good measure. */ + intf->bmc->id = id; + intf->bmc->dyn_guid_set = guid_set; + memcpy(intf->bmc->guid, guid, 16); + rv = __ipmi_bmc_register(intf, &id, guid_set, guid, intf_num); + + if (!intf_set) { + /* + * We weren't given the interface on the + * command line, so restart the operation on + * the next interface for the BMC. + */ + mutex_unlock(&intf->bmc_reg_mutex); + mutex_lock(&bmc->dyn_mutex); + goto retry_bmc_lock; + } + + /* We have a new BMC, set it up. */ + bmc = intf->bmc; + mutex_lock(&bmc->dyn_mutex); + goto out_noprocessing; + } bmc->dyn_id_expiry = jiffies + IPMI_DYN_DEV_ID_EXPIRY; @@ -2260,15 +2301,28 @@ out: rv = 0; /* Ignore failures if we have previous data. */ bmc->dyn_id_set = prev_dyn_id_set; } + if (!rv) { + bmc->id = bmc->fetch_id; + if (bmc->dyn_guid_set) + memcpy(bmc->guid, bmc->fetch_guid, 16); + else if (prev_guid_set) + /* + * The guid used to be valid and it failed to fetch, + * just use the cached value. + */ + bmc->dyn_guid_set = prev_guid_set; + } +out_noprocessing: + if (!rv) { + if (id) + *id = bmc->id; - if (id) - *id = bmc->id; + if (guid_set) + *guid_set = bmc->dyn_guid_set; - if (guid_set) - *guid_set = bmc->dyn_guid_set; - - if (guid && bmc->dyn_guid_set) - memcpy(guid, bmc->guid, 16); + if (guid && bmc->dyn_guid_set) + memcpy(guid, bmc->guid, 16); + } mutex_unlock(&bmc->dyn_mutex); mutex_unlock(&intf->bmc_reg_mutex); @@ -2277,6 +2331,13 @@ out: return rv; } +static int bmc_get_device_id(ipmi_smi_t intf, struct bmc_device *bmc, + struct ipmi_device_id *id, + bool *guid_set, u8 *guid) +{ + return __bmc_get_device_id(intf, bmc, id, guid_set, guid, -1); +} + #ifdef CONFIG_PROC_FS static int smi_ipmb_proc_show(struct seq_file *m, void *v) { @@ -2721,26 +2782,22 @@ static const struct device_type bmc_device_type = { static int __find_bmc_guid(struct device *dev, void *data) { - unsigned char *id = data; + unsigned char *guid = data; struct bmc_device *bmc; - bool guid_set; - u8 guid[16]; int rv; if (dev->type != &bmc_device_type) return 0; bmc = to_bmc_device(dev); - rv = bmc_get_device_id(NULL, bmc, NULL, &guid_set, guid); - if (rv || !guid_set) - return 0; - - return memcmp(guid, id, 16) == 0; + rv = bmc->dyn_guid_set && memcmp(bmc->guid, guid, 16) == 0; + if (rv) + rv = kref_get_unless_zero(&bmc->usecount); + return rv; } /* - * Must be called with ipmidriver_mutex held. Returns with the - * bmc's usecount incremented, if it is non-NULL. + * Returns with the bmc's usecount incremented, if it is non-NULL. */ static struct bmc_device *ipmi_find_bmc_guid(struct device_driver *drv, unsigned char *guid) @@ -2751,7 +2808,6 @@ static struct bmc_device *ipmi_find_bmc_guid(struct device_driver *drv, dev = driver_find_device(drv, NULL, guid, __find_bmc_guid); if (dev) { bmc = to_bmc_device(dev); - kref_get(&bmc->usecount); put_device(dev); } return bmc; @@ -2766,24 +2822,21 @@ static int __find_bmc_prod_dev_id(struct device *dev, void *data) { struct prod_dev_id *cid = data; struct bmc_device *bmc; - struct ipmi_device_id id; int rv; if (dev->type != &bmc_device_type) return 0; bmc = to_bmc_device(dev); - rv = bmc_get_device_id(NULL, bmc, &id, NULL, NULL); + rv = (bmc->id.product_id == cid->product_id + && bmc->id.device_id == cid->device_id); if (rv) - return 0; - - return (id.product_id == cid->product_id - && id.device_id == cid->device_id); + rv = kref_get_unless_zero(&bmc->usecount); + return rv; } /* - * Must be called with ipmidriver_mutex held. Returns with the - * bmc's usecount incremented, if it is non-NULL. + * Returns with the bmc's usecount incremented, if it is non-NULL. */ static struct bmc_device *ipmi_find_bmc_prod_dev_id( struct device_driver *drv, @@ -2799,7 +2852,6 @@ static struct bmc_device *ipmi_find_bmc_prod_dev_id( dev = driver_find_device(drv, NULL, &id, __find_bmc_prod_dev_id); if (dev) { bmc = to_bmc_device(dev); - kref_get(&bmc->usecount); put_device(dev); } return bmc; @@ -2813,25 +2865,39 @@ release_bmc_device(struct device *dev) kfree(to_bmc_device(dev)); } -static void -cleanup_bmc_device(struct kref *ref) +static void cleanup_bmc_work(struct work_struct *work) { - struct bmc_device *bmc = container_of(ref, struct bmc_device, usecount); + struct bmc_device *bmc = container_of(work, struct bmc_device, + remove_work); int id = bmc->pdev.id; /* Unregister overwrites id */ platform_device_unregister(&bmc->pdev); ida_simple_remove(&ipmi_bmc_ida, id); } -static void ipmi_bmc_unregister(ipmi_smi_t intf) +static void +cleanup_bmc_device(struct kref *ref) +{ + struct bmc_device *bmc = container_of(ref, struct bmc_device, usecount); + + /* + * Remove the platform device in a work queue to avoid issues + * with removing the device attributes while reading a device + * attribute. + */ + schedule_work(&bmc->remove_work); +} + +/* + * Must be called with intf->bmc_reg_mutex held. + */ +static void __ipmi_bmc_unregister(ipmi_smi_t intf) { struct bmc_device *bmc = intf->bmc; if (!intf->bmc_registered) return; - mutex_lock(&intf->bmc_reg_mutex); - sysfs_remove_link(&intf->si_dev->kobj, "bmc"); sysfs_remove_link(&bmc->pdev.dev.kobj, intf->my_dev_name); kfree(intf->my_dev_name); @@ -2841,32 +2907,48 @@ static void ipmi_bmc_unregister(ipmi_smi_t intf) list_del(&intf->bmc_link); mutex_unlock(&bmc->dyn_mutex); intf->bmc = &intf->tmp_bmc; - mutex_lock(&ipmidriver_mutex); kref_put(&bmc->usecount, cleanup_bmc_device); - mutex_unlock(&ipmidriver_mutex); intf->bmc_registered = false; +} +static void ipmi_bmc_unregister(ipmi_smi_t intf) +{ + mutex_lock(&intf->bmc_reg_mutex); + __ipmi_bmc_unregister(intf); mutex_unlock(&intf->bmc_reg_mutex); } -static int ipmi_bmc_register(ipmi_smi_t intf, int ifnum) +/* + * Must be called with intf->bmc_reg_mutex held. + */ +static int __ipmi_bmc_register(ipmi_smi_t intf, + struct ipmi_device_id *id, + bool guid_set, u8 *guid, int intf_num) { int rv; struct bmc_device *bmc = intf->bmc; struct bmc_device *old_bmc; + /* + * platform_device_register() can cause bmc_reg_mutex to + * be claimed because of the is_visible functions of + * the attributes. Eliminate possible recursion and + * release the lock. + */ + intf->in_bmc_register = true; + mutex_unlock(&intf->bmc_reg_mutex); + /* * Try to find if there is an bmc_device struct * representing the interfaced BMC already */ mutex_lock(&ipmidriver_mutex); - if (bmc->dyn_guid_set) - old_bmc = ipmi_find_bmc_guid(&ipmidriver.driver, bmc->guid); + if (guid_set) + old_bmc = ipmi_find_bmc_guid(&ipmidriver.driver, guid); else old_bmc = ipmi_find_bmc_prod_dev_id(&ipmidriver.driver, - bmc->id.product_id, - bmc->id.device_id); - mutex_unlock(&ipmidriver_mutex); + id->product_id, + id->device_id); /* * If there is already an bmc_device, free the new one, @@ -2874,6 +2956,10 @@ static int ipmi_bmc_register(ipmi_smi_t intf, int ifnum) */ if (old_bmc) { bmc = old_bmc; + /* + * Note: old_bmc already has usecount incremented by + * the BMC find functions. + */ intf->bmc = old_bmc; mutex_lock(&bmc->dyn_mutex); list_add_tail(&intf->bmc_link, &bmc->intfs); @@ -2893,6 +2979,13 @@ static int ipmi_bmc_register(ipmi_smi_t intf, int ifnum) } INIT_LIST_HEAD(&bmc->intfs); mutex_init(&bmc->dyn_mutex); + INIT_WORK(&bmc->remove_work, cleanup_bmc_work); + + bmc->id = *id; + bmc->dyn_id_set = 1; + bmc->dyn_guid_set = guid_set; + memcpy(bmc->guid, guid, 16); + bmc->dyn_id_expiry = jiffies + IPMI_DYN_DEV_ID_EXPIRY; bmc->pdev.name = "ipmi_bmc"; @@ -2938,7 +3031,9 @@ static int ipmi_bmc_register(ipmi_smi_t intf, int ifnum) goto out_put_bmc; } - intf->my_dev_name = kasprintf(GFP_KERNEL, "ipmi%d", ifnum); + if (intf_num == -1) + intf_num = intf->intf_num; + intf->my_dev_name = kasprintf(GFP_KERNEL, "ipmi%d", intf_num); if (!intf->my_dev_name) { rv = -ENOMEM; printk(KERN_ERR @@ -2962,6 +3057,9 @@ static int ipmi_bmc_register(ipmi_smi_t intf, int ifnum) intf->bmc_registered = true; out: + mutex_unlock(&ipmidriver_mutex); + mutex_lock(&intf->bmc_reg_mutex); + intf->in_bmc_register = false; return rv; @@ -2977,9 +3075,7 @@ out_put_bmc: list_del(&intf->bmc_link); mutex_unlock(&bmc->dyn_mutex); intf->bmc = &intf->tmp_bmc; - mutex_lock(&ipmidriver_mutex); kref_put(&bmc->usecount, cleanup_bmc_device); - mutex_unlock(&ipmidriver_mutex); goto out; out_list_del: @@ -3283,16 +3379,12 @@ int ipmi_register_smi(const struct ipmi_smi_handlers *handlers, if (rv) goto out; - rv = bmc_get_device_id(intf, NULL, &id, NULL, NULL); + rv = __bmc_get_device_id(intf, NULL, &id, NULL, NULL, i); if (rv) { dev_err(si_dev, "Unable to get the device id: %d\n", rv); goto out; } - rv = ipmi_bmc_register(intf, i); - if (rv) - goto out; - if (ipmi_version_major(&id) > 1 || (ipmi_version_major(&id) == 1 && ipmi_version_minor(&id) >= 5)) { @@ -3300,6 +3392,7 @@ int ipmi_register_smi(const struct ipmi_smi_handlers *handlers, * Start scanning the channels to see what is * available. */ + mutex_lock(&intf->bmc_reg_mutex); intf->null_user_handler = channel_handler; intf->curr_channel = 0; rv = send_channel_info_cmd(intf, 0); @@ -3314,6 +3407,7 @@ int ipmi_register_smi(const struct ipmi_smi_handlers *handlers, wait_event(intf->waitq, intf->curr_channel >= IPMI_MAX_CHANNELS); intf->null_user_handler = NULL; + mutex_unlock(&intf->bmc_reg_mutex); } else { /* Assume a single IPMB channel at zero. */ intf->channels[0].medium = IPMI_CHANNEL_MEDIUM_IPMB; From c0734bd594d43a28afcbe476bbf0d35a5bbffa4c Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Thu, 31 Aug 2017 17:09:03 -0500 Subject: [PATCH 23/48] ipmi: Retry BMC registration on a failure If the BMC fails to register, just set up to retry periodically. Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_msghandler.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 1da0b3cca6aa..c6ee1de8d76b 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -47,6 +47,7 @@ #include #include #include +#include #define PFX "IPMI message handler: " @@ -430,6 +431,7 @@ struct ipmi_smi { struct list_head bmc_link; char *my_dev_name; bool in_bmc_register; /* Handle recursive situations. Yuck. */ + struct work_struct bmc_reg_work; /* * This is the lower-layer's sender routine. Note that you @@ -2275,7 +2277,8 @@ retry_bmc_lock: intf->bmc->id = id; intf->bmc->dyn_guid_set = guid_set; memcpy(intf->bmc->guid, guid, 16); - rv = __ipmi_bmc_register(intf, &id, guid_set, guid, intf_num); + if (__ipmi_bmc_register(intf, &id, guid_set, guid, intf_num)) + need_waiter(intf); /* Retry later on an error. */ if (!intf_set) { /* @@ -3276,6 +3279,16 @@ void ipmi_poll_interface(ipmi_user_t user) } EXPORT_SYMBOL(ipmi_poll_interface); +static void redo_bmc_reg(struct work_struct *work) +{ + ipmi_smi_t intf = container_of(work, struct ipmi_smi, bmc_reg_work); + + if (!intf->in_shutdown) + bmc_get_device_id(intf, NULL, NULL, NULL, NULL); + + kref_put(&intf->refcount, intf_free); +} + int ipmi_register_smi(const struct ipmi_smi_handlers *handlers, void *send_info, struct device *si_dev, @@ -3315,6 +3328,7 @@ int ipmi_register_smi(const struct ipmi_smi_handlers *handlers, mutex_init(&intf->bmc_reg_mutex); intf->intf_num = -1; /* Mark it invalid for now. */ kref_init(&intf->refcount); + INIT_WORK(&intf->bmc_reg_work, redo_bmc_reg); intf->si_dev = si_dev; for (j = 0; j < IPMI_MAX_CHANNELS; j++) { intf->channels[j].address = IPMI_BMC_SLAVE_ADDR; @@ -4641,6 +4655,14 @@ static unsigned int ipmi_timeout_handler(ipmi_smi_t intf, int i; unsigned int waiting_msgs = 0; + if (!intf->bmc_registered) { + kref_get(&intf->refcount); + if (!schedule_work(&intf->bmc_reg_work)) { + kref_put(&intf->refcount, intf_free); + waiting_msgs++; + } + } + /* * Go through the seq table and find any messages that * have timed out, putting them in the timeouts From 5fdb1fb2abe6478e0b415fffa978c71d3f7cf3e4 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Tue, 5 Sep 2017 15:50:12 -0500 Subject: [PATCH 24/48] ipmi: Move lun and address out of channel struct Put it in it's own struct, getting ready for channel information being dynamically changed. Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_msghandler.c | 47 +++++++++++++++-------------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index c6ee1de8d76b..58cecebe950f 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -245,7 +245,9 @@ struct seq_table { struct ipmi_channel { unsigned char medium; unsigned char protocol; +}; +struct ipmi_my_addrinfo { /* * My slave address. This is initialized to IPMI_BMC_SLAVE_ADDR, * but may be changed by the user. @@ -530,6 +532,7 @@ struct ipmi_smi { /* Channel information */ struct ipmi_channel channels[IPMI_MAX_CHANNELS]; + struct ipmi_my_addrinfo addrinfo[IPMI_MAX_CHANNELS]; /* Proc FS stuff. */ struct proc_dir_entry *proc_dir; @@ -1251,7 +1254,7 @@ int ipmi_set_my_address(ipmi_user_t user, { if (channel >= IPMI_MAX_CHANNELS) return -EINVAL; - user->intf->channels[channel].address = address; + user->intf->addrinfo[channel].address = address; return 0; } EXPORT_SYMBOL(ipmi_set_my_address); @@ -1262,7 +1265,7 @@ int ipmi_get_my_address(ipmi_user_t user, { if (channel >= IPMI_MAX_CHANNELS) return -EINVAL; - *address = user->intf->channels[channel].address; + *address = user->intf->addrinfo[channel].address; return 0; } EXPORT_SYMBOL(ipmi_get_my_address); @@ -1273,7 +1276,7 @@ int ipmi_set_my_LUN(ipmi_user_t user, { if (channel >= IPMI_MAX_CHANNELS) return -EINVAL; - user->intf->channels[channel].lun = LUN & 0x3; + user->intf->addrinfo[channel].lun = LUN & 0x3; return 0; } EXPORT_SYMBOL(ipmi_set_my_LUN); @@ -1284,7 +1287,7 @@ int ipmi_get_my_LUN(ipmi_user_t user, { if (channel >= IPMI_MAX_CHANNELS) return -EINVAL; - *address = user->intf->channels[channel].lun; + *address = user->intf->addrinfo[channel].lun; return 0; } EXPORT_SYMBOL(ipmi_get_my_LUN); @@ -2045,8 +2048,8 @@ static int check_addr(ipmi_smi_t intf, { if (addr->channel >= IPMI_MAX_CHANNELS) return -EINVAL; - *lun = intf->channels[addr->channel].lun; - *saddr = intf->channels[addr->channel].address; + *lun = intf->addrinfo[addr->channel].lun; + *saddr = intf->addrinfo[addr->channel].address; return 0; } @@ -2167,8 +2170,8 @@ send_get_device_id_cmd(ipmi_smi_t intf) NULL, NULL, 0, - intf->channels[0].address, - intf->channels[0].lun, + intf->addrinfo[0].address, + intf->addrinfo[0].lun, -1, 0); } @@ -2347,9 +2350,9 @@ static int smi_ipmb_proc_show(struct seq_file *m, void *v) ipmi_smi_t intf = m->private; int i; - seq_printf(m, "%x", intf->channels[0].address); + seq_printf(m, "%x", intf->addrinfo[0].address); for (i = 1; i < IPMI_MAX_CHANNELS; i++) - seq_printf(m, " %x", intf->channels[i].address); + seq_printf(m, " %x", intf->addrinfo[i].address); seq_putc(m, '\n'); return 0; @@ -3113,8 +3116,8 @@ send_guid_cmd(ipmi_smi_t intf, int chan) NULL, NULL, 0, - intf->channels[0].address, - intf->channels[0].lun, + intf->addrinfo[0].address, + intf->addrinfo[0].lun, -1, 0); } @@ -3200,8 +3203,8 @@ send_channel_info_cmd(ipmi_smi_t intf, int chan) NULL, NULL, 0, - intf->channels[0].address, - intf->channels[0].lun, + intf->addrinfo[0].address, + intf->addrinfo[0].lun, -1, 0); } @@ -3331,11 +3334,11 @@ int ipmi_register_smi(const struct ipmi_smi_handlers *handlers, INIT_WORK(&intf->bmc_reg_work, redo_bmc_reg); intf->si_dev = si_dev; for (j = 0; j < IPMI_MAX_CHANNELS; j++) { - intf->channels[j].address = IPMI_BMC_SLAVE_ADDR; - intf->channels[j].lun = 2; + intf->addrinfo[j].address = IPMI_BMC_SLAVE_ADDR; + intf->addrinfo[j].lun = 2; } if (slave_addr != 0) - intf->channels[0].address = slave_addr; + intf->addrinfo[0].address = slave_addr; INIT_LIST_HEAD(&intf->users); intf->handlers = handlers; intf->send_info = send_info; @@ -3665,7 +3668,7 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf, msg->data[3] = msg->rsp[6]; msg->data[4] = ((netfn + 1) << 2) | (msg->rsp[7] & 0x3); msg->data[5] = ipmb_checksum(&(msg->data[3]), 2); - msg->data[6] = intf->channels[msg->rsp[3] & 0xf].address; + msg->data[6] = intf->addrinfo[msg->rsp[3] & 0xf].address; /* rqseq/lun */ msg->data[7] = (msg->rsp[7] & 0xfc) | (msg->rsp[4] & 0x3); msg->data[8] = msg->rsp[8]; /* cmd */ @@ -4849,8 +4852,8 @@ static void ipmi_panic_request_and_wait(ipmi_smi_t intf, &smi_msg, &recv_msg, 0, - intf->channels[0].address, - intf->channels[0].lun, + intf->addrinfo[0].address, + intf->addrinfo[0].lun, 0, 1); /* Don't retry, and don't wait. */ if (rv) atomic_sub(2, &panic_done_count); @@ -4999,7 +5002,7 @@ static void send_panic_events(char *str) */ if (((intf->event_receiver & 1) == 0) && (intf->event_receiver != 0) - && (intf->event_receiver != intf->channels[0].address)) { + && (intf->event_receiver != intf->addrinfo[0].address)) { /* * The event receiver is valid, send an IPMB * message. @@ -5036,7 +5039,7 @@ static void send_panic_events(char *str) data[0] = 0; data[1] = 0; data[2] = 0xf0; /* OEM event without timestamp. */ - data[3] = intf->channels[0].address; + data[3] = intf->addrinfo[0].address; data[4] = j++; /* sequence # */ /* * Always give 11 bytes, so strncpy will fill From 31b0b0730ad2a813bf6b01c5f1f3629c09c73466 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Wed, 6 Sep 2017 08:23:31 -0500 Subject: [PATCH 25/48] ipmi: Rescan channel list on BMC changes If the BMC changes versions or a change is otherwise detected, rescan the channels on the BMC. Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_msghandler.c | 169 ++++++++++++++++++---------- 1 file changed, 111 insertions(+), 58 deletions(-) diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 58cecebe950f..b5fc150e5128 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -242,11 +242,16 @@ struct seq_table { #define NEXT_SEQID(seqid) (((seqid) + 1) & 0x3ffffff) +#define IPMI_MAX_CHANNELS 16 struct ipmi_channel { unsigned char medium; unsigned char protocol; }; +struct ipmi_channel_set { + struct ipmi_channel c[IPMI_MAX_CHANNELS]; +}; + struct ipmi_my_addrinfo { /* * My slave address. This is initialized to IPMI_BMC_SLAVE_ADDR, @@ -398,7 +403,6 @@ enum ipmi_stat_indexes { #define IPMI_IPMB_NUM_SEQ 64 -#define IPMI_MAX_CHANNELS 16 struct ipmi_smi { /* What interface number are we? */ int intf_num; @@ -531,8 +535,11 @@ struct ipmi_smi { int curr_channel; /* Channel information */ - struct ipmi_channel channels[IPMI_MAX_CHANNELS]; + struct ipmi_channel_set *channel_list; + unsigned int curr_working_cset; /* First index into the following. */ + struct ipmi_channel_set wchannels[2]; struct ipmi_my_addrinfo addrinfo[IPMI_MAX_CHANNELS]; + bool channels_ready; /* Proc FS stuff. */ struct proc_dir_entry *proc_dir; @@ -554,6 +561,7 @@ static void __ipmi_bmc_unregister(ipmi_smi_t intf); static int __ipmi_bmc_register(ipmi_smi_t intf, struct ipmi_device_id *id, bool guid_set, u8 *guid, int intf_num); +static int __scan_channels(ipmi_smi_t intf, struct ipmi_device_id *id); /** @@ -1775,6 +1783,7 @@ static int i_ipmi_request(ipmi_user_t user, unsigned char ipmb_seq; long seqid; int broadcast = 0; + struct ipmi_channel *chans; if (addr->channel >= IPMI_MAX_CHANNELS) { ipmi_inc_stat(intf, sent_invalid_commands); @@ -1782,8 +1791,9 @@ static int i_ipmi_request(ipmi_user_t user, goto out_err; } - if (intf->channels[addr->channel].medium - != IPMI_CHANNEL_MEDIUM_IPMB) { + chans = READ_ONCE(intf->channel_list)->c; + + if (chans[addr->channel].medium != IPMI_CHANNEL_MEDIUM_IPMB) { ipmi_inc_stat(intf, sent_invalid_commands); rv = -EINVAL; goto out_err; @@ -1905,6 +1915,7 @@ static int i_ipmi_request(ipmi_user_t user, struct ipmi_lan_addr *lan_addr; unsigned char ipmb_seq; long seqid; + struct ipmi_channel *chans; if (addr->channel >= IPMI_MAX_CHANNELS) { ipmi_inc_stat(intf, sent_invalid_commands); @@ -1912,9 +1923,11 @@ static int i_ipmi_request(ipmi_user_t user, goto out_err; } - if ((intf->channels[addr->channel].medium + chans = READ_ONCE(intf->channel_list)->c; + + if ((chans[addr->channel].medium != IPMI_CHANNEL_MEDIUM_8023LAN) - && (intf->channels[addr->channel].medium + && (chans[addr->channel].medium != IPMI_CHANNEL_MEDIUM_ASYNC)) { ipmi_inc_stat(intf, sent_invalid_commands); rv = -EINVAL; @@ -2282,6 +2295,9 @@ retry_bmc_lock: memcpy(intf->bmc->guid, guid, 16); if (__ipmi_bmc_register(intf, &id, guid_set, guid, intf_num)) need_waiter(intf); /* Retry later on an error. */ + else + __scan_channels(intf, &id); + if (!intf_set) { /* @@ -2298,7 +2314,9 @@ retry_bmc_lock: bmc = intf->bmc; mutex_lock(&bmc->dyn_mutex); goto out_noprocessing; - } + } else if (memcmp(&bmc->fetch_id, &bmc->id, sizeof(bmc->id))) + /* Version info changes, scan the channels again. */ + __scan_channels(intf, &bmc->fetch_id); bmc->dyn_id_expiry = jiffies + IPMI_DYN_DEV_ID_EXPIRY; @@ -3212,7 +3230,9 @@ static void channel_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg) { int rv = 0; - int chan; + int ch; + unsigned int set = intf->curr_working_cset; + struct ipmi_channel *chans; if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE) @@ -3228,12 +3248,13 @@ channel_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg) * assume it has one IPMB at channel * zero. */ - intf->channels[0].medium + intf->wchannels[set].c[0].medium = IPMI_CHANNEL_MEDIUM_IPMB; - intf->channels[0].protocol + intf->wchannels[set].c[0].protocol = IPMI_CHANNEL_PROTOCOL_IPMB; - intf->curr_channel = IPMI_MAX_CHANNELS; + intf->channel_list = intf->wchannels + set; + intf->channels_ready = true; wake_up(&intf->waitq); goto out; } @@ -3243,16 +3264,22 @@ channel_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg) /* Message not big enough, just go on. */ goto next_channel; } - chan = intf->curr_channel; - intf->channels[chan].medium = msg->msg.data[2] & 0x7f; - intf->channels[chan].protocol = msg->msg.data[3] & 0x1f; + ch = intf->curr_channel; + chans = intf->wchannels[set].c; + chans[ch].medium = msg->msg.data[2] & 0x7f; + chans[ch].protocol = msg->msg.data[3] & 0x1f; next_channel: intf->curr_channel++; - if (intf->curr_channel >= IPMI_MAX_CHANNELS) + if (intf->curr_channel >= IPMI_MAX_CHANNELS) { + intf->channel_list = intf->wchannels + set; + intf->channels_ready = true; wake_up(&intf->waitq); - else + } else { + intf->channel_list = intf->wchannels + set; + intf->channels_ready = true; rv = send_channel_info_cmd(intf, intf->curr_channel); + } if (rv) { /* Got an error somehow, just give up. */ @@ -3260,7 +3287,8 @@ channel_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg) "Error sending channel information for channel" " %d: %d\n", intf->curr_channel, rv); - intf->curr_channel = IPMI_MAX_CHANNELS; + intf->channel_list = intf->wchannels + set; + intf->channels_ready = true; wake_up(&intf->waitq); } } @@ -3268,6 +3296,53 @@ channel_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg) return; } +/* + * Must be holding intf->bmc_reg_mutex to call this. + */ +static int __scan_channels(ipmi_smi_t intf, struct ipmi_device_id *id) +{ + int rv; + + if (ipmi_version_major(id) > 1 + || (ipmi_version_major(id) == 1 + && ipmi_version_minor(id) >= 5)) { + unsigned int set; + + /* + * Start scanning the channels to see what is + * available. + */ + set = !intf->curr_working_cset; + intf->curr_working_cset = set; + memset(&intf->wchannels[set], 0, + sizeof(struct ipmi_channel_set)); + + intf->null_user_handler = channel_handler; + intf->curr_channel = 0; + rv = send_channel_info_cmd(intf, 0); + if (rv) { + dev_warn(intf->si_dev, + "Error sending channel information for channel 0, %d\n", + rv); + return -EIO; + } + + /* Wait for the channel info to be read. */ + wait_event(intf->waitq, intf->channels_ready); + intf->null_user_handler = NULL; + } else { + unsigned int set = intf->curr_working_cset; + + /* Assume a single IPMB channel at zero. */ + intf->wchannels[set].c[0].medium = IPMI_CHANNEL_MEDIUM_IPMB; + intf->wchannels[set].c[0].protocol = IPMI_CHANNEL_PROTOCOL_IPMB; + intf->channel_list = intf->wchannels + set; + intf->channels_ready = true; + } + + return 0; +} + static void ipmi_poll(ipmi_smi_t intf) { if (intf->handlers->poll) @@ -3402,35 +3477,11 @@ int ipmi_register_smi(const struct ipmi_smi_handlers *handlers, goto out; } - if (ipmi_version_major(&id) > 1 - || (ipmi_version_major(&id) == 1 - && ipmi_version_minor(&id) >= 5)) { - /* - * Start scanning the channels to see what is - * available. - */ - mutex_lock(&intf->bmc_reg_mutex); - intf->null_user_handler = channel_handler; - intf->curr_channel = 0; - rv = send_channel_info_cmd(intf, 0); - if (rv) { - printk(KERN_WARNING PFX - "Error sending channel information for channel" - " 0, %d\n", rv); - goto out; - } - - /* Wait for the channel info to be read. */ - wait_event(intf->waitq, - intf->curr_channel >= IPMI_MAX_CHANNELS); - intf->null_user_handler = NULL; - mutex_unlock(&intf->bmc_reg_mutex); - } else { - /* Assume a single IPMB channel at zero. */ - intf->channels[0].medium = IPMI_CHANNEL_MEDIUM_IPMB; - intf->channels[0].protocol = IPMI_CHANNEL_PROTOCOL_IPMB; - intf->curr_channel = IPMI_MAX_CHANNELS; - } + mutex_lock(&intf->bmc_reg_mutex); + rv = __scan_channels(intf, &id); + mutex_unlock(&intf->bmc_reg_mutex); + if (rv) + goto out; rv = add_proc_entries(intf, i); @@ -4259,6 +4310,8 @@ static int handle_one_recv_msg(ipmi_smi_t intf, deliver_response(recv_msg); } else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2)) && (msg->rsp[1] == IPMI_GET_MSG_CMD)) { + struct ipmi_channel *chans; + /* It's from the receive queue. */ chan = msg->rsp[3] & 0xf; if (chan >= IPMI_MAX_CHANNELS) { @@ -4273,12 +4326,14 @@ static int handle_one_recv_msg(ipmi_smi_t intf, * equal to or greater than IPMI_MAX_CHANNELS when all the * channels for this interface have been initialized. */ - if (intf->curr_channel < IPMI_MAX_CHANNELS) { + if (!intf->channels_ready) { requeue = 0; /* Throw the message away */ goto out; } - switch (intf->channels[chan].medium) { + chans = READ_ONCE(intf->channel_list)->c; + + switch (chans[chan].medium) { case IPMI_CHANNEL_MEDIUM_IPMB: if (msg->rsp[4] & 0x04) { /* @@ -4315,9 +4370,8 @@ static int handle_one_recv_msg(ipmi_smi_t intf, default: /* Check for OEM Channels. Clients had better register for these commands. */ - if ((intf->channels[chan].medium - >= IPMI_CHANNEL_MEDIUM_OEM_MIN) - && (intf->channels[chan].medium + if ((chans[chan].medium >= IPMI_CHANNEL_MEDIUM_OEM_MIN) + && (chans[chan].medium <= IPMI_CHANNEL_MEDIUM_OEM_MAX)) { requeue = handle_oem_get_msg_cmd(intf, msg); } else { @@ -4479,15 +4533,14 @@ void ipmi_smi_msg_received(ipmi_smi_t intf, && (msg->rsp[2] != IPMI_LOST_ARBITRATION_ERR) && (msg->rsp[2] != IPMI_BUS_ERR) && (msg->rsp[2] != IPMI_NAK_ON_WRITE_ERR)) { - int chan = msg->rsp[3] & 0xf; + int ch = msg->rsp[3] & 0xf; + struct ipmi_channel *chans; /* Got an error sending the message, handle it. */ - if (chan >= IPMI_MAX_CHANNELS) - ; /* This shouldn't happen */ - else if ((intf->channels[chan].medium - == IPMI_CHANNEL_MEDIUM_8023LAN) - || (intf->channels[chan].medium - == IPMI_CHANNEL_MEDIUM_ASYNC)) + + chans = READ_ONCE(intf->channel_list)->c; + if ((chans[ch].medium == IPMI_CHANNEL_MEDIUM_8023LAN) + || (chans[ch].medium == IPMI_CHANNEL_MEDIUM_ASYNC)) ipmi_inc_stat(intf, sent_lan_command_errs); else ipmi_inc_stat(intf, sent_ipmb_command_errs); From 3fd32f9ec84f57ff6d86e762012d7626a9b31124 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Fri, 1 Sep 2017 19:34:33 -0500 Subject: [PATCH 26/48] ipmi: Convert IPMI GUID over to Linux guid_t Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_msghandler.c | 50 +++++++++++++---------------- 1 file changed, 23 insertions(+), 27 deletions(-) diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index b5fc150e5128..1c8bef2e1dc1 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -48,6 +48,7 @@ #include #include #include +#include #define PFX "IPMI message handler: " @@ -286,8 +287,8 @@ struct bmc_device { int dyn_id_set; unsigned long dyn_id_expiry; struct mutex dyn_mutex; /* Protects id, intfs, & dyn* */ - u8 guid[16]; - u8 fetch_guid[16]; + guid_t guid; + guid_t fetch_guid; int dyn_guid_set; struct kref usecount; struct work_struct remove_work; @@ -296,7 +297,7 @@ struct bmc_device { static int bmc_get_device_id(ipmi_smi_t intf, struct bmc_device *bmc, struct ipmi_device_id *id, - bool *guid_set, u8 *guid); + bool *guid_set, guid_t *guid); /* * Various statistics for IPMI, these index stats[] in the ipmi_smi @@ -560,7 +561,7 @@ static void __get_guid(ipmi_smi_t intf); static void __ipmi_bmc_unregister(ipmi_smi_t intf); static int __ipmi_bmc_register(ipmi_smi_t intf, struct ipmi_device_id *id, - bool guid_set, u8 *guid, int intf_num); + bool guid_set, guid_t *guid, int intf_num); static int __scan_channels(ipmi_smi_t intf, struct ipmi_device_id *id); @@ -2224,7 +2225,7 @@ static int __get_device_id(ipmi_smi_t intf, struct bmc_device *bmc) */ static int __bmc_get_device_id(ipmi_smi_t intf, struct bmc_device *bmc, struct ipmi_device_id *id, - bool *guid_set, u8 *guid, int intf_num) + bool *guid_set, guid_t *guid, int intf_num) { int rv = 0; int prev_dyn_id_set, prev_guid_set; @@ -2277,23 +2278,23 @@ retry_bmc_lock: || (!prev_guid_set && bmc->dyn_guid_set) || (!prev_dyn_id_set && bmc->dyn_id_set) || (prev_guid_set && bmc->dyn_guid_set - && memcmp(bmc->guid, bmc->fetch_guid, 16)) + && !guid_equal(&bmc->guid, &bmc->fetch_guid)) || bmc->id.device_id != bmc->fetch_id.device_id || bmc->id.manufacturer_id != bmc->fetch_id.manufacturer_id || bmc->id.product_id != bmc->fetch_id.product_id) { struct ipmi_device_id id = bmc->fetch_id; int guid_set = bmc->dyn_guid_set; - u8 guid[16]; + guid_t guid; - memcpy(guid, bmc->fetch_guid, 16); + guid = bmc->fetch_guid; mutex_unlock(&bmc->dyn_mutex); __ipmi_bmc_unregister(intf); /* Fill in the temporary BMC for good measure. */ intf->bmc->id = id; intf->bmc->dyn_guid_set = guid_set; - memcpy(intf->bmc->guid, guid, 16); - if (__ipmi_bmc_register(intf, &id, guid_set, guid, intf_num)) + intf->bmc->guid = guid; + if (__ipmi_bmc_register(intf, &id, guid_set, &guid, intf_num)) need_waiter(intf); /* Retry later on an error. */ else __scan_channels(intf, &id); @@ -2328,7 +2329,7 @@ out: if (!rv) { bmc->id = bmc->fetch_id; if (bmc->dyn_guid_set) - memcpy(bmc->guid, bmc->fetch_guid, 16); + bmc->guid = bmc->fetch_guid; else if (prev_guid_set) /* * The guid used to be valid and it failed to fetch, @@ -2345,7 +2346,7 @@ out_noprocessing: *guid_set = bmc->dyn_guid_set; if (guid && bmc->dyn_guid_set) - memcpy(guid, bmc->guid, 16); + *guid = bmc->guid; } mutex_unlock(&bmc->dyn_mutex); @@ -2357,7 +2358,7 @@ out_noprocessing: static int bmc_get_device_id(ipmi_smi_t intf, struct bmc_device *bmc, struct ipmi_device_id *id, - bool *guid_set, u8 *guid) + bool *guid_set, guid_t *guid) { return __bmc_get_device_id(intf, bmc, id, guid_set, guid, -1); } @@ -2735,21 +2736,16 @@ static ssize_t guid_show(struct device *dev, struct device_attribute *attr, { struct bmc_device *bmc = to_bmc_device(dev); bool guid_set; - u8 guid[16]; + guid_t guid; int rv; - rv = bmc_get_device_id(NULL, bmc, NULL, &guid_set, guid); + rv = bmc_get_device_id(NULL, bmc, NULL, &guid_set, &guid); if (rv) return rv; if (!guid_set) return -ENOENT; - return snprintf(buf, 100, - "%2.2x%2.2x%2.2x%2.2x-%2.2x%2.2x-%2.2x%2.2x-%2.2x%2.2x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n", - guid[3], guid[2], guid[1], guid[0], - guid[5], guid[4], guid[7], guid[6], - guid[8], guid[9], guid[10], guid[11], - guid[12], guid[13], guid[14], guid[15]); + return snprintf(buf, 38, "%pUl\n", guid.b); } static DEVICE_ATTR(guid, S_IRUGO, guid_show, NULL); @@ -2806,7 +2802,7 @@ static const struct device_type bmc_device_type = { static int __find_bmc_guid(struct device *dev, void *data) { - unsigned char *guid = data; + guid_t *guid = data; struct bmc_device *bmc; int rv; @@ -2814,7 +2810,7 @@ static int __find_bmc_guid(struct device *dev, void *data) return 0; bmc = to_bmc_device(dev); - rv = bmc->dyn_guid_set && memcmp(bmc->guid, guid, 16) == 0; + rv = bmc->dyn_guid_set && guid_equal(&bmc->guid, guid); if (rv) rv = kref_get_unless_zero(&bmc->usecount); return rv; @@ -2824,7 +2820,7 @@ static int __find_bmc_guid(struct device *dev, void *data) * Returns with the bmc's usecount incremented, if it is non-NULL. */ static struct bmc_device *ipmi_find_bmc_guid(struct device_driver *drv, - unsigned char *guid) + guid_t *guid) { struct device *dev; struct bmc_device *bmc = NULL; @@ -2947,7 +2943,7 @@ static void ipmi_bmc_unregister(ipmi_smi_t intf) */ static int __ipmi_bmc_register(ipmi_smi_t intf, struct ipmi_device_id *id, - bool guid_set, u8 *guid, int intf_num) + bool guid_set, guid_t *guid, int intf_num) { int rv; struct bmc_device *bmc = intf->bmc; @@ -3008,7 +3004,7 @@ static int __ipmi_bmc_register(ipmi_smi_t intf, bmc->id = *id; bmc->dyn_id_set = 1; bmc->dyn_guid_set = guid_set; - memcpy(bmc->guid, guid, 16); + bmc->guid = *guid; bmc->dyn_id_expiry = jiffies + IPMI_DYN_DEV_ID_EXPIRY; bmc->pdev.name = "ipmi_bmc"; @@ -3165,7 +3161,7 @@ static void guid_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg) goto out; } - memcpy(bmc->fetch_guid, msg->msg.data + 1, 16); + memcpy(bmc->fetch_guid.b, msg->msg.data + 1, 16); /* * Make sure the guid data is available before setting * dyn_guid_set. From 1e89a499e55f353115b1427c5bcb9f9244a20200 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Tue, 12 Sep 2017 13:52:13 -0500 Subject: [PATCH 27/48] ipmi_si: Rename function to add smi, make it global Getting ready for moving the platform-specific stuff into their own files. Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_si.h | 18 ++++++++++++++++++ drivers/char/ipmi/ipmi_si_intf.c | 26 ++++++++++---------------- 2 files changed, 28 insertions(+), 16 deletions(-) create mode 100644 drivers/char/ipmi/ipmi_si.h diff --git a/drivers/char/ipmi/ipmi_si.h b/drivers/char/ipmi/ipmi_si.h new file mode 100644 index 000000000000..a4d993b1fe66 --- /dev/null +++ b/drivers/char/ipmi/ipmi_si.h @@ -0,0 +1,18 @@ +/* + * ipmi_si.h + * + * Interface from the device-specific interfaces (OF, DMI, ACPI, PCI, + * etc) to the base ipmi system interface code. + */ + +#include "ipmi_si_sm.h" + +#define IPMI_IO_ADDR_SPACE 0 +#define IPMI_MEM_ADDR_SPACE 1 + +#define DEFAULT_REGSPACING 1 +#define DEFAULT_REGSIZE 1 + +struct smi_info; + +int ipmi_si_add_smi(struct smi_info *info); diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 4caa793a6765..6ba70c2fc25f 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -60,7 +60,7 @@ #include #include #include -#include "ipmi_si_sm.h" +#include "ipmi_si.h" #include "ipmi_dmi.h" #include #include @@ -332,7 +332,6 @@ static int num_max_busy_us; static bool unload_when_empty = true; -static int add_smi(struct smi_info *smi); static int try_smi_init(struct smi_info *smi); static void cleanup_one_si(struct smi_info *to_clean); static void cleanup_ipmi_si(void); @@ -1310,9 +1309,6 @@ static LIST_HEAD(smi_infos); static DEFINE_MUTEX(smi_infos_lock); static int smi_num; /* Used to sequence the SMIs */ -#define DEFAULT_REGSPACING 1 -#define DEFAULT_REGSIZE 1 - #ifdef CONFIG_ACPI static bool si_tryacpi = true; #endif @@ -1341,8 +1337,6 @@ static unsigned int num_regshifts; static int slave_addrs[SI_MAX_PARMS]; /* Leaving 0 chooses the default value */ static unsigned int num_slave_addrs; -#define IPMI_IO_ADDR_SPACE 0 -#define IPMI_MEM_ADDR_SPACE 1 static const char * const addr_space_to_str[] = { "i/o", "mem" }; static int hotmod_handler(const char *val, struct kernel_param *kp); @@ -1950,7 +1944,7 @@ static int hotmod_handler(const char *val, struct kernel_param *kp) info->irq_setup = std_irq_setup; info->slave_addr = ipmb; - rv = add_smi(info); + rv = ipmi_si_add_smi(info); if (rv) { kfree(info); goto out; @@ -2044,7 +2038,7 @@ static int hardcode_find_bmc(void) info->irq_setup = std_irq_setup; info->slave_addr = slave_addrs[i]; - if (!add_smi(info)) { + if (!ipmi_si_add_smi(info)) { mutex_lock(&smi_infos_lock); if (try_smi_init(info)) cleanup_one_si(info); @@ -2244,7 +2238,7 @@ static int try_init_spmi(struct SPMITable *spmi) info->io.addr_data, info->io.regsize, info->io.regspacing, info->irq); - rv = add_smi(info); + rv = ipmi_si_add_smi(info); if (rv) kfree(info); @@ -2380,7 +2374,7 @@ static int dmi_ipmi_probe(struct platform_device *pdev) info->io.addr_data, info->io.regsize, info->io.regspacing, info->irq); - if (add_smi(info)) + if (ipmi_si_add_smi(info)) kfree(info); return 0; @@ -2515,7 +2509,7 @@ static int ipmi_pci_probe(struct pci_dev *pdev, &pdev->resource[0], info->io.regsize, info->io.regspacing, info->irq); - rv = add_smi(info); + rv = ipmi_si_add_smi(info); if (rv) { kfree(info); pci_disable_device(pdev); @@ -2635,7 +2629,7 @@ static int of_ipmi_probe(struct platform_device *dev) dev_set_drvdata(&dev->dev, info); - ret = add_smi(info); + ret = ipmi_si_add_smi(info); if (ret) { kfree(info); return ret; @@ -2760,7 +2754,7 @@ static int acpi_ipmi_probe(struct platform_device *dev) res, info->io.regsize, info->io.regspacing, info->irq); - rv = add_smi(info); + rv = ipmi_si_add_smi(info); if (rv) kfree(info); @@ -2842,7 +2836,7 @@ static int __init ipmi_parisc_probe(struct parisc_device *dev) dev_set_drvdata(&dev->dev, info); - rv = add_smi(info); + rv = ipmi_si_add_smi(info); if (rv) { kfree(info); return rv; @@ -3448,7 +3442,7 @@ static struct smi_info *find_dup_si(struct smi_info *info) return NULL; } -static int add_smi(struct smi_info *new_smi) +int ipmi_si_add_smi(struct smi_info *new_smi) { int rv = 0; struct smi_info *dup; From 910840f24bb7f9ea80fce4073445329becfdcb58 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Tue, 12 Sep 2017 14:41:56 -0500 Subject: [PATCH 28/48] ipmi_si: Move some platform data into the io structure That's where it belongs, and we are getting ready for moving the platform handling out of the main ipmi_si_intf.c file. Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_si_intf.c | 415 +++++++++++++++---------------- drivers/char/ipmi/ipmi_si_sm.h | 14 ++ 2 files changed, 213 insertions(+), 216 deletions(-) diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 6ba70c2fc25f..8cc101ea82d9 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -104,10 +104,6 @@ enum si_intf_state { #define IPMI_BT_INTMASK_CLEAR_IRQ_BIT 2 #define IPMI_BT_INTMASK_ENABLE_IRQ_BIT 1 -enum si_type { - SI_KCS, SI_SMIC, SI_BT -}; - static const char * const si_to_str[] = { "kcs", "smic", "bt" }; #define DEVICE_NAME "ipmi_si" @@ -167,7 +163,6 @@ struct smi_info { ipmi_smi_t intf; struct si_sm_data *si_sm; const struct si_sm_handlers *handlers; - enum si_type si_type; spinlock_t si_lock; struct ipmi_smi_msg *waiting_msg; struct ipmi_smi_msg *curr_msg; @@ -183,9 +178,6 @@ struct smi_info { int (*irq_setup)(struct smi_info *info); void (*irq_cleanup)(struct smi_info *info); unsigned int io_size; - enum ipmi_addr_src addr_source; /* ACPI, PCI, SMBIOS, hardcode, etc. */ - void (*addr_source_cleanup)(struct smi_info *info); - void *addr_source_data; /* * Per-OEM handler, called from handle_flags(). Returns 1 @@ -236,9 +228,6 @@ struct smi_info { */ unsigned int spacing; - /* zero if no irq; */ - int irq; - /* The timer for this si. */ struct timer_list si_timer; @@ -289,19 +278,9 @@ struct smi_info { /* From the get device id response... */ struct ipmi_device_id device_id; - /* Driver model stuff. */ - struct device *dev; + /* Default driver model device. */ struct platform_device *pdev; - /* - * True if we allocated the device, false if it came from - * someplace else (like PCI). - */ - bool dev_registered; - - /* Slave address, could be reported from DMI. */ - unsigned char slave_addr; - /* Counters and things for the proc filesystem. */ atomic_t stats[SI_NUM_STATS]; @@ -498,7 +477,7 @@ static void start_getting_events(struct smi_info *smi_info) */ static inline bool disable_si_irq(struct smi_info *smi_info, bool start_timer) { - if ((smi_info->irq) && (!smi_info->interrupt_disabled)) { + if ((smi_info->io.irq) && (!smi_info->interrupt_disabled)) { smi_info->interrupt_disabled = true; start_check_enables(smi_info, start_timer); return true; @@ -508,7 +487,7 @@ static inline bool disable_si_irq(struct smi_info *smi_info, bool start_timer) static inline bool enable_si_irq(struct smi_info *smi_info) { - if ((smi_info->irq) && (smi_info->interrupt_disabled)) { + if ((smi_info->io.irq) && (smi_info->interrupt_disabled)) { smi_info->interrupt_disabled = false; start_check_enables(smi_info, true); return true; @@ -584,13 +563,13 @@ static u8 current_global_enables(struct smi_info *smi_info, u8 base, if (smi_info->supports_event_msg_buff) enables |= IPMI_BMC_EVT_MSG_BUFF; - if (((smi_info->irq && !smi_info->interrupt_disabled) || + if (((smi_info->io.irq && !smi_info->interrupt_disabled) || smi_info->cannot_disable_irq) && !smi_info->irq_enable_broken) enables |= IPMI_BMC_RCV_MSG_INTR; if (smi_info->supports_event_msg_buff && - smi_info->irq && !smi_info->interrupt_disabled && + smi_info->io.irq && !smi_info->interrupt_disabled && !smi_info->irq_enable_broken) enables |= IPMI_BMC_EVT_MSG_INTR; @@ -672,7 +651,7 @@ static void handle_transaction_done(struct smi_info *smi_info) smi_info->handlers->get_result(smi_info->si_sm, msg, 3); if (msg[2] != 0) { /* Error clearing flags */ - dev_warn(smi_info->dev, + dev_warn(smi_info->io.dev, "Error clearing flags: %2.2x\n", msg[2]); } smi_info->si_state = SI_NORMAL; @@ -764,15 +743,15 @@ static void handle_transaction_done(struct smi_info *smi_info) /* We got the flags from the SMI, now handle them. */ smi_info->handlers->get_result(smi_info->si_sm, msg, 4); if (msg[2] != 0) { - dev_warn(smi_info->dev, + dev_warn(smi_info->io.dev, "Couldn't get irq info: %x.\n", msg[2]); - dev_warn(smi_info->dev, + dev_warn(smi_info->io.dev, "Maybe ok, but ipmi might run very slowly.\n"); smi_info->si_state = SI_NORMAL; break; } enables = current_global_enables(smi_info, 0, &irq_on); - if (smi_info->si_type == SI_BT) + if (smi_info->io.si_type == SI_BT) /* BT has its own interrupt enable bit. */ check_bt_irq(smi_info, irq_on); if (enables != (msg[3] & GLOBAL_ENABLES_MASK)) { @@ -802,7 +781,7 @@ static void handle_transaction_done(struct smi_info *smi_info) smi_info->handlers->get_result(smi_info->si_sm, msg, 4); if (msg[2] != 0) - dev_warn(smi_info->dev, + dev_warn(smi_info->io.dev, "Could not set the global enables: 0x%x.\n", msg[2]); @@ -926,7 +905,7 @@ restart: * asynchronously reset, and may thus get interrupts * disable and messages disabled. */ - if (smi_info->supports_event_msg_buff || smi_info->irq) { + if (smi_info->supports_event_msg_buff || smi_info->io.irq) { start_check_enables(smi_info, true); } else { smi_info->curr_msg = alloc_msg_handle_irq(smi_info); @@ -1171,7 +1150,7 @@ static void smi_timeout(unsigned long data) * SI_USEC_PER_JIFFY); smi_result = smi_event_handler(smi_info, time_diff); - if ((smi_info->irq) && (!smi_info->interrupt_disabled)) { + if ((smi_info->io.irq) && (!smi_info->interrupt_disabled)) { /* Running with interrupts, only do long timeouts. */ timeout = jiffies + SI_TIMEOUT_JIFFIES; smi_inc_stat(smi_info, long_timeouts); @@ -1249,14 +1228,14 @@ static int smi_start_processing(void *send_info, * The BT interface is efficient enough to not need a thread, * and there is no need for a thread if we have interrupts. */ - else if ((new_smi->si_type != SI_BT) && (!new_smi->irq)) + else if ((new_smi->io.si_type != SI_BT) && (!new_smi->io.irq)) enable = 1; if (enable) { new_smi->thread = kthread_run(ipmi_thread, new_smi, "kipmi%d", new_smi->intf_num); if (IS_ERR(new_smi->thread)) { - dev_notice(new_smi->dev, "Could not start" + dev_notice(new_smi->io.dev, "Could not start" " kernel thread due to error %ld, only using" " timers to drive the interface\n", PTR_ERR(new_smi->thread)); @@ -1271,10 +1250,10 @@ static int get_smi_info(void *send_info, struct ipmi_smi_info *data) { struct smi_info *smi = send_info; - data->addr_src = smi->addr_source; - data->dev = smi->dev; + data->addr_src = smi->io.addr_source; + data->dev = smi->io.dev; data->addr_info = smi->addr_info; - get_device(smi->dev); + get_device(smi->io.dev); return 0; } @@ -1424,21 +1403,21 @@ MODULE_PARM_DESC(kipmid_max_busy_us, static void std_irq_cleanup(struct smi_info *info) { - if (info->si_type == SI_BT) + if (info->io.si_type == SI_BT) /* Disable the interrupt in the BT interface. */ info->io.outputb(&info->io, IPMI_BT_INTMASK_REG, 0); - free_irq(info->irq, info); + free_irq(info->io.irq, info); } static int std_irq_setup(struct smi_info *info) { int rv; - if (!info->irq) + if (!info->io.irq) return 0; - if (info->si_type == SI_BT) { - rv = request_irq(info->irq, + if (info->io.si_type == SI_BT) { + rv = request_irq(info->io.irq, si_bt_irq_handler, IRQF_SHARED, DEVICE_NAME, @@ -1448,19 +1427,19 @@ static int std_irq_setup(struct smi_info *info) info->io.outputb(&info->io, IPMI_BT_INTMASK_REG, IPMI_BT_INTMASK_ENABLE_IRQ_BIT); } else - rv = request_irq(info->irq, + rv = request_irq(info->io.irq, si_irq_handler, IRQF_SHARED, DEVICE_NAME, info); if (rv) { - dev_warn(info->dev, "%s unable to claim interrupt %d," + dev_warn(info->io.dev, "%s unable to claim interrupt %d," " running polled\n", - DEVICE_NAME, info->irq); - info->irq = 0; + DEVICE_NAME, info->io.irq); + info->io.irq = 0; } else { info->irq_cleanup = std_irq_cleanup; - dev_info(info->dev, "Using irq %d\n", info->irq); + dev_info(info->io.dev, "Using irq %d\n", info->io.irq); } return rv; @@ -1551,7 +1530,7 @@ static int port_setup(struct smi_info *info) info->io.outputb = port_outl; break; default: - dev_warn(info->dev, "Invalid register size: %d\n", + dev_warn(info->io.dev, "Invalid register size: %d\n", info->io.regsize); return -EINVAL; } @@ -1679,7 +1658,7 @@ static int mem_setup(struct smi_info *info) break; #endif default: - dev_warn(info->dev, "Invalid register size: %d\n", + dev_warn(info->io.dev, "Invalid register size: %d\n", info->io.regsize); return -EINVAL; } @@ -1922,8 +1901,8 @@ static int hotmod_handler(const char *val, struct kernel_param *kp) goto out; } - info->addr_source = SI_HOTMOD; - info->si_type = si_type; + info->io.addr_source = SI_HOTMOD; + info->io.si_type = si_type; info->io.addr_data = addr; info->io.addr_type = addr_space; if (addr_space == IPMI_MEM_ADDR_SPACE) @@ -1939,10 +1918,10 @@ static int hotmod_handler(const char *val, struct kernel_param *kp) if (!info->io.regsize) info->io.regsize = DEFAULT_REGSIZE; info->io.regshift = regshift; - info->irq = irq; - if (info->irq) + info->io.irq = irq; + if (info->io.irq) info->irq_setup = std_irq_setup; - info->slave_addr = ipmb; + info->io.slave_addr = ipmb; rv = ipmi_si_add_smi(info); if (rv) { @@ -1964,7 +1943,7 @@ static int hotmod_handler(const char *val, struct kernel_param *kp) list_for_each_entry_safe(e, tmp_e, &smi_infos, link) { if (e->io.addr_type != addr_space) continue; - if (e->si_type != si_type) + if (e->io.si_type != si_type) continue; if (e->io.addr_data == addr) cleanup_one_si(e); @@ -1992,15 +1971,15 @@ static int hardcode_find_bmc(void) if (!info) return -ENOMEM; - info->addr_source = SI_HARDCODED; + info->io.addr_source = SI_HARDCODED; pr_info(PFX "probing via hardcoded address\n"); if (!si_type[i] || strcmp(si_type[i], "kcs") == 0) { - info->si_type = SI_KCS; + info->io.si_type = SI_KCS; } else if (strcmp(si_type[i], "smic") == 0) { - info->si_type = SI_SMIC; + info->io.si_type = SI_SMIC; } else if (strcmp(si_type[i], "bt") == 0) { - info->si_type = SI_BT; + info->io.si_type = SI_BT; } else { pr_warn(PFX "Interface type specified for interface %d, was invalid: %s\n", i, si_type[i]); @@ -2033,10 +2012,10 @@ static int hardcode_find_bmc(void) if (!info->io.regsize) info->io.regsize = DEFAULT_REGSIZE; info->io.regshift = regshifts[i]; - info->irq = irqs[i]; - if (info->irq) + info->io.irq = irqs[i]; + if (info->io.irq) info->irq_setup = std_irq_setup; - info->slave_addr = slave_addrs[i]; + info->io.slave_addr = slave_addrs[i]; if (!ipmi_si_add_smi(info)) { mutex_lock(&smi_infos_lock); @@ -2081,32 +2060,32 @@ static u32 ipmi_acpi_gpe(acpi_handle gpe_device, static void acpi_gpe_irq_cleanup(struct smi_info *info) { - if (!info->irq) + if (!info->io.irq) return; - acpi_remove_gpe_handler(NULL, info->irq, &ipmi_acpi_gpe); + acpi_remove_gpe_handler(NULL, info->io.irq, &ipmi_acpi_gpe); } static int acpi_gpe_irq_setup(struct smi_info *info) { acpi_status status; - if (!info->irq) + if (!info->io.irq) return 0; status = acpi_install_gpe_handler(NULL, - info->irq, + info->io.irq, ACPI_GPE_LEVEL_TRIGGERED, &ipmi_acpi_gpe, info); if (status != AE_OK) { - dev_warn(info->dev, "%s unable to claim ACPI GPE %d," - " running polled\n", DEVICE_NAME, info->irq); - info->irq = 0; + dev_warn(info->io.dev, "%s unable to claim ACPI GPE %d," + " running polled\n", DEVICE_NAME, info->io.irq); + info->io.irq = 0; return -EINVAL; } else { info->irq_cleanup = acpi_gpe_irq_cleanup; - dev_info(info->dev, "Using ACPI GPE %d\n", info->irq); + dev_info(info->io.dev, "Using ACPI GPE %d\n", info->io.irq); return 0; } } @@ -2173,19 +2152,19 @@ static int try_init_spmi(struct SPMITable *spmi) return -ENOMEM; } - info->addr_source = SI_SPMI; + info->io.addr_source = SI_SPMI; pr_info(PFX "probing via SPMI\n"); /* Figure out the interface type. */ switch (spmi->InterfaceType) { case 1: /* KCS */ - info->si_type = SI_KCS; + info->io.si_type = SI_KCS; break; case 2: /* SMIC */ - info->si_type = SI_SMIC; + info->io.si_type = SI_SMIC; break; case 3: /* BT */ - info->si_type = SI_BT; + info->io.si_type = SI_BT; break; case 4: /* SSIF, just ignore */ kfree(info); @@ -2199,15 +2178,15 @@ static int try_init_spmi(struct SPMITable *spmi) if (spmi->InterruptType & 1) { /* We've got a GPE interrupt. */ - info->irq = spmi->GPE; + info->io.irq = spmi->GPE; info->irq_setup = acpi_gpe_irq_setup; } else if (spmi->InterruptType & 2) { /* We've got an APIC/SAPIC interrupt. */ - info->irq = spmi->GlobalSystemInterrupt; + info->io.irq = spmi->GlobalSystemInterrupt; info->irq_setup = std_irq_setup; } else { /* Use the default interrupt setting. */ - info->irq = 0; + info->io.irq = 0; info->irq_setup = NULL; } @@ -2236,7 +2215,7 @@ static int try_init_spmi(struct SPMITable *spmi) pr_info("ipmi_si: SPMI: %s %#lx regsize %d spacing %d irq %d\n", (info->io.addr_type == IPMI_IO_ADDR_SPACE) ? "io" : "mem", info->io.addr_data, info->io.regsize, info->io.regspacing, - info->irq); + info->io.irq); rv = ipmi_si_add_smi(info); if (rv) @@ -2330,18 +2309,18 @@ static int dmi_ipmi_probe(struct platform_device *pdev) return -ENOMEM; } - info->addr_source = SI_SMBIOS; + info->io.addr_source = SI_SMBIOS; pr_info(PFX "probing via SMBIOS\n"); switch (type) { case IPMI_DMI_TYPE_KCS: - info->si_type = SI_KCS; + info->io.si_type = SI_KCS; break; case IPMI_DMI_TYPE_SMIC: - info->si_type = SI_SMIC; + info->io.si_type = SI_SMIC; break; case IPMI_DMI_TYPE_BT: - info->si_type = SI_BT; + info->io.si_type = SI_BT; break; default: kfree(info); @@ -2356,23 +2335,23 @@ static int dmi_ipmi_probe(struct platform_device *pdev) rv = device_property_read_u8(&pdev->dev, "slave-addr", &slave_addr); if (rv) { dev_warn(&pdev->dev, "device has no slave-addr property"); - info->slave_addr = 0x20; + info->io.slave_addr = 0x20; } else { - info->slave_addr = slave_addr; + info->io.slave_addr = slave_addr; } - info->irq = platform_get_irq(pdev, 0); - if (info->irq > 0) + info->io.irq = platform_get_irq(pdev, 0); + if (info->io.irq > 0) info->irq_setup = std_irq_setup; else - info->irq = 0; + info->io.irq = 0; - info->dev = &pdev->dev; + info->io.dev = &pdev->dev; pr_info("ipmi_si: SMBIOS: %s %#lx regsize %d spacing %d irq %d\n", (info->io.addr_type == IPMI_IO_ADDR_SPACE) ? "io" : "mem", info->io.addr_data, info->io.regsize, info->io.regspacing, - info->irq); + info->io.irq); if (ipmi_si_add_smi(info)) kfree(info); @@ -2403,16 +2382,16 @@ static int dmi_ipmi_probe(struct platform_device *pdev) #define PCI_MMC_DEVICE_ID 0x121A #define PCI_MMC_ADDR_CW 0x10 -static void ipmi_pci_cleanup(struct smi_info *info) +static void ipmi_pci_cleanup(struct si_sm_io *io) { - struct pci_dev *pdev = info->addr_source_data; + struct pci_dev *pdev = io->addr_source_data; pci_disable_device(pdev); } static int ipmi_pci_probe_regspacing(struct smi_info *info) { - if (info->si_type == SI_KCS) { + if (info->io.si_type == SI_KCS) { unsigned char status; int regspacing; @@ -2425,7 +2404,7 @@ static int ipmi_pci_probe_regspacing(struct smi_info *info) for (regspacing = DEFAULT_REGSPACING; regspacing <= 16;) { info->io.regspacing = regspacing; if (info->io_setup(info)) { - dev_err(info->dev, + dev_err(info->io.dev, "Could not setup I/O space\n"); return DEFAULT_REGSPACING; } @@ -2453,20 +2432,20 @@ static int ipmi_pci_probe(struct pci_dev *pdev, if (!info) return -ENOMEM; - info->addr_source = SI_PCI; + info->io.addr_source = SI_PCI; dev_info(&pdev->dev, "probing via PCI"); switch (class_type) { case PCI_ERMC_CLASSCODE_TYPE_SMIC: - info->si_type = SI_SMIC; + info->io.si_type = SI_SMIC; break; case PCI_ERMC_CLASSCODE_TYPE_KCS: - info->si_type = SI_KCS; + info->io.si_type = SI_KCS; break; case PCI_ERMC_CLASSCODE_TYPE_BT: - info->si_type = SI_BT; + info->io.si_type = SI_BT; break; default: @@ -2482,8 +2461,8 @@ static int ipmi_pci_probe(struct pci_dev *pdev, return rv; } - info->addr_source_cleanup = ipmi_pci_cleanup; - info->addr_source_data = pdev; + info->io.addr_source_cleanup = ipmi_pci_cleanup; + info->io.addr_source_data = pdev; if (pci_resource_flags(pdev, 0) & IORESOURCE_IO) { info->io_setup = port_setup; @@ -2498,16 +2477,16 @@ static int ipmi_pci_probe(struct pci_dev *pdev, info->io.regsize = DEFAULT_REGSIZE; info->io.regshift = 0; - info->irq = pdev->irq; - if (info->irq) + info->io.irq = pdev->irq; + if (info->io.irq) info->irq_setup = std_irq_setup; - info->dev = &pdev->dev; + info->io.dev = &pdev->dev; pci_set_drvdata(pdev, info); dev_info(&pdev->dev, "%pR regsize %d spacing %d irq %d\n", &pdev->resource[0], info->io.regsize, info->io.regspacing, - info->irq); + info->io.irq); rv = ipmi_si_add_smi(info); if (rv) { @@ -2551,19 +2530,19 @@ static const struct of_device_id of_ipmi_match[] = { }; MODULE_DEVICE_TABLE(of, of_ipmi_match); -static int of_ipmi_probe(struct platform_device *dev) +static int of_ipmi_probe(struct platform_device *pdev) { const struct of_device_id *match; struct smi_info *info; struct resource resource; const __be32 *regsize, *regspacing, *regshift; - struct device_node *np = dev->dev.of_node; + struct device_node *np = pdev->dev.of_node; int ret; int proplen; - dev_info(&dev->dev, "probing via device tree\n"); + dev_info(&pdev->dev, "probing via device tree\n"); - match = of_match_device(of_ipmi_match, &dev->dev); + match = of_match_device(of_ipmi_match, &pdev->dev); if (!match) return -ENODEV; @@ -2572,39 +2551,39 @@ static int of_ipmi_probe(struct platform_device *dev) ret = of_address_to_resource(np, 0, &resource); if (ret) { - dev_warn(&dev->dev, PFX "invalid address from OF\n"); + dev_warn(&pdev->dev, PFX "invalid address from OF\n"); return ret; } regsize = of_get_property(np, "reg-size", &proplen); if (regsize && proplen != 4) { - dev_warn(&dev->dev, PFX "invalid regsize from OF\n"); + dev_warn(&pdev->dev, PFX "invalid regsize from OF\n"); return -EINVAL; } regspacing = of_get_property(np, "reg-spacing", &proplen); if (regspacing && proplen != 4) { - dev_warn(&dev->dev, PFX "invalid regspacing from OF\n"); + dev_warn(&pdev->dev, PFX "invalid regspacing from OF\n"); return -EINVAL; } regshift = of_get_property(np, "reg-shift", &proplen); if (regshift && proplen != 4) { - dev_warn(&dev->dev, PFX "invalid regshift from OF\n"); + dev_warn(&pdev->dev, PFX "invalid regshift from OF\n"); return -EINVAL; } info = smi_info_alloc(); if (!info) { - dev_err(&dev->dev, + dev_err(&pdev->dev, "could not allocate memory for OF probe\n"); return -ENOMEM; } - info->si_type = (enum si_type) match->data; - info->addr_source = SI_DEVICETREE; - info->irq_setup = std_irq_setup; + info->io.si_type = (enum si_type) match->data; + info->io.addr_source = SI_DEVICETREE; + info->io.irq_setup = std_irq_setup; if (resource.flags & IORESOURCE_IO) { info->io_setup = port_setup; @@ -2620,14 +2599,14 @@ static int of_ipmi_probe(struct platform_device *dev) info->io.regspacing = regspacing ? be32_to_cpup(regspacing) : DEFAULT_REGSPACING; info->io.regshift = regshift ? be32_to_cpup(regshift) : 0; - info->irq = irq_of_parse_and_map(dev->dev.of_node, 0); - info->dev = &dev->dev; + info->io.irq = irq_of_parse_and_map(pdev->dev.of_node, 0); + info->io.dev = &pdev->dev; - dev_dbg(&dev->dev, "addr 0x%lx regsize %d spacing %d irq %d\n", + dev_dbg(&pdev->dev, "addr 0x%lx regsize %d spacing %d irq %d\n", info->io.addr_data, info->io.regsize, info->io.regspacing, - info->irq); + info->io.irq); - dev_set_drvdata(&dev->dev, info); + dev_set_drvdata(&pdev->dev, info); ret = ipmi_si_add_smi(info); if (ret) { @@ -2652,7 +2631,7 @@ static int find_slave_address(struct smi_info *info, int slave_addr) int type = -1; u32 flags = IORESOURCE_IO; - switch (info->si_type) { + switch (info->io.si_type) { case SI_KCS: type = IPMI_DMI_TYPE_KCS; break; @@ -2675,7 +2654,7 @@ static int find_slave_address(struct smi_info *info, int slave_addr) return slave_addr; } -static int acpi_ipmi_probe(struct platform_device *dev) +static int acpi_ipmi_probe(struct platform_device *pdev) { struct smi_info *info; acpi_handle handle; @@ -2687,7 +2666,7 @@ static int acpi_ipmi_probe(struct platform_device *dev) if (!si_tryacpi) return -ENODEV; - handle = ACPI_HANDLE(&dev->dev); + handle = ACPI_HANDLE(&pdev->dev); if (!handle) return -ENODEV; @@ -2695,37 +2674,38 @@ static int acpi_ipmi_probe(struct platform_device *dev) if (!info) return -ENOMEM; - info->addr_source = SI_ACPI; - dev_info(&dev->dev, PFX "probing via ACPI\n"); + info->io.addr_source = SI_ACPI; + dev_info(&pdev->dev, PFX "probing via ACPI\n"); info->addr_info.acpi_info.acpi_handle = handle; /* _IFT tells us the interface type: KCS, BT, etc */ status = acpi_evaluate_integer(handle, "_IFT", NULL, &tmp); if (ACPI_FAILURE(status)) { - dev_err(&dev->dev, "Could not find ACPI IPMI interface type\n"); + dev_err(&pdev->dev, + "Could not find ACPI IPMI interface type\n"); goto err_free; } switch (tmp) { case 1: - info->si_type = SI_KCS; + info->io.si_type = SI_KCS; break; case 2: - info->si_type = SI_SMIC; + info->io.si_type = SI_SMIC; break; case 3: - info->si_type = SI_BT; + info->io.si_type = SI_BT; break; case 4: /* SSIF, just ignore */ rv = -ENODEV; goto err_free; default: - dev_info(&dev->dev, "unknown IPMI type %lld\n", tmp); + dev_info(&pdev->dev, "unknown IPMI type %lld\n", tmp); goto err_free; } - res = ipmi_get_info_from_resources(dev, info); + res = ipmi_get_info_from_resources(pdev, info); if (!res) { rv = -EINVAL; goto err_free; @@ -2734,25 +2714,25 @@ static int acpi_ipmi_probe(struct platform_device *dev) /* If _GPE exists, use it; otherwise use standard interrupts */ status = acpi_evaluate_integer(handle, "_GPE", NULL, &tmp); if (ACPI_SUCCESS(status)) { - info->irq = tmp; + info->io.irq = tmp; info->irq_setup = acpi_gpe_irq_setup; } else { - int irq = platform_get_irq(dev, 0); + int irq = platform_get_irq(pdev, 0); if (irq > 0) { - info->irq = irq; + info->io.irq = irq; info->irq_setup = std_irq_setup; } } - info->slave_addr = find_slave_address(info, info->slave_addr); + info->io.slave_addr = find_slave_address(info, info->io.slave_addr); - info->dev = &dev->dev; - platform_set_drvdata(dev, info); + info->io.dev = &pdev->dev; + platform_set_drvdata(pdev, info); - dev_info(info->dev, "%pR regsize %d spacing %d irq %d\n", + dev_info(info->io.dev, "%pR regsize %d spacing %d irq %d\n", res, info->io.regsize, info->io.regspacing, - info->irq); + info->io.irq); rv = ipmi_si_add_smi(info); if (rv) @@ -2777,20 +2757,20 @@ static int acpi_ipmi_probe(struct platform_device *dev) } #endif -static int ipmi_probe(struct platform_device *dev) +static int ipmi_probe(struct platform_device *pdev) { - if (dev->dev.of_node && of_ipmi_probe(dev) == 0) + if (pdev->dev.of_node && of_ipmi_probe(pdev) == 0) return 0; - if (acpi_ipmi_probe(dev) == 0) + if (acpi_ipmi_probe(pdev) == 0) return 0; - return dmi_ipmi_probe(dev); + return dmi_ipmi_probe(pdev); } -static int ipmi_remove(struct platform_device *dev) +static int ipmi_remove(struct platform_device *pdev) { - struct smi_info *info = dev_get_drvdata(&dev->dev); + struct smi_info *info = dev_get_drvdata(&pdev->dev); cleanup_one_si(info); return 0; @@ -2820,17 +2800,17 @@ static int __init ipmi_parisc_probe(struct parisc_device *dev) return -ENOMEM; } - info->si_type = SI_KCS; - info->addr_source = SI_DEVICETREE; + info->io.si_type = SI_KCS; + info->io.addr_source = SI_DEVICETREE; info->io_setup = mem_setup; info->io.addr_type = IPMI_MEM_ADDR_SPACE; info->io.addr_data = dev->hpa.start; info->io.regsize = 1; info->io.regspacing = 1; info->io.regshift = 0; - info->irq = 0; /* no interrupt */ + info->io.irq = 0; /* no interrupt */ info->irq_setup = NULL; - info->dev = &dev->dev; + info->io.dev = &dev->dev; dev_dbg(&dev->dev, "addr 0x%lx\n", info->io.addr_data); @@ -2945,7 +2925,7 @@ static int get_global_enables(struct smi_info *smi_info, u8 *enables) rv = wait_for_msg_done(smi_info); if (rv) { - dev_warn(smi_info->dev, + dev_warn(smi_info->io.dev, "Error getting response from get global enables command: %d\n", rv); goto out; @@ -2958,7 +2938,7 @@ static int get_global_enables(struct smi_info *smi_info, u8 *enables) resp[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2 || resp[1] != IPMI_GET_BMC_GLOBAL_ENABLES_CMD || resp[2] != 0) { - dev_warn(smi_info->dev, + dev_warn(smi_info->io.dev, "Invalid return from get global enables command: %ld %x %x %x\n", resp_len, resp[0], resp[1], resp[2]); rv = -EINVAL; @@ -2993,7 +2973,7 @@ static int set_global_enables(struct smi_info *smi_info, u8 enables) rv = wait_for_msg_done(smi_info); if (rv) { - dev_warn(smi_info->dev, + dev_warn(smi_info->io.dev, "Error getting response from set global enables command: %d\n", rv); goto out; @@ -3005,7 +2985,7 @@ static int set_global_enables(struct smi_info *smi_info, u8 enables) if (resp_len < 3 || resp[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2 || resp[1] != IPMI_SET_BMC_GLOBAL_ENABLES_CMD) { - dev_warn(smi_info->dev, + dev_warn(smi_info->io.dev, "Invalid return from set global enables command: %ld %x %x\n", resp_len, resp[0], resp[1]); rv = -EINVAL; @@ -3041,7 +3021,7 @@ static void check_clr_rcv_irq(struct smi_info *smi_info) } if (rv < 0) { - dev_err(smi_info->dev, + dev_err(smi_info->io.dev, "Cannot check clearing the rcv irq: %d\n", rv); return; } @@ -3051,7 +3031,7 @@ static void check_clr_rcv_irq(struct smi_info *smi_info) * An error when setting the event buffer bit means * clearing the bit is not supported. */ - dev_warn(smi_info->dev, + dev_warn(smi_info->io.dev, "The BMC does not support clearing the recv irq bit, compensating, but the BMC needs to be fixed.\n"); smi_info->cannot_disable_irq = true; } @@ -3067,7 +3047,7 @@ static void check_set_rcv_irq(struct smi_info *smi_info) u8 enables = 0; int rv; - if (!smi_info->irq) + if (!smi_info->io.irq) return; rv = get_global_enables(smi_info, &enables); @@ -3077,7 +3057,7 @@ static void check_set_rcv_irq(struct smi_info *smi_info) } if (rv < 0) { - dev_err(smi_info->dev, + dev_err(smi_info->io.dev, "Cannot check setting the rcv irq: %d\n", rv); return; } @@ -3087,7 +3067,7 @@ static void check_set_rcv_irq(struct smi_info *smi_info) * An error when setting the event buffer bit means * setting the bit is not supported. */ - dev_warn(smi_info->dev, + dev_warn(smi_info->io.dev, "The BMC does not support setting the recv irq bit, compensating, but the BMC needs to be fixed.\n"); smi_info->cannot_disable_irq = true; smi_info->irq_enable_broken = true; @@ -3173,7 +3153,7 @@ static int smi_type_proc_show(struct seq_file *m, void *v) { struct smi_info *smi = m->private; - seq_printf(m, "%s\n", si_to_str[smi->si_type]); + seq_printf(m, "%s\n", si_to_str[smi->io.si_type]); return 0; } @@ -3195,7 +3175,7 @@ static int smi_si_stats_proc_show(struct seq_file *m, void *v) struct smi_info *smi = m->private; seq_printf(m, "interrupts_enabled: %d\n", - smi->irq && !smi->interrupt_disabled); + smi->io.irq && !smi->interrupt_disabled); seq_printf(m, "short_timeouts: %u\n", smi_get_stat(smi, short_timeouts)); seq_printf(m, "long_timeouts: %u\n", @@ -3239,14 +3219,14 @@ static int smi_params_proc_show(struct seq_file *m, void *v) seq_printf(m, "%s,%s,0x%lx,rsp=%d,rsi=%d,rsh=%d,irq=%d,ipmb=%d\n", - si_to_str[smi->si_type], + si_to_str[smi->io.si_type], addr_space_to_str[smi->io.addr_type], smi->io.addr_data, smi->io.regspacing, smi->io.regsize, smi->io.regshift, - smi->irq, - smi->slave_addr); + smi->io.irq, + smi->io.slave_addr); return 0; } @@ -3384,7 +3364,7 @@ setup_dell_poweredge_bt_xaction_handler(struct smi_info *smi_info) { struct ipmi_device_id *id = &smi_info->device_id; if (id->manufacturer_id == DELL_IANA_MFR_ID && - smi_info->si_type == SI_BT) + smi_info->io.si_type == SI_BT) register_xaction_notifier(&dell_poweredge_bt_xaction_notifier); } @@ -3433,8 +3413,8 @@ static struct smi_info *find_dup_si(struct smi_info *info) * slave address but SMBIOS does. Pick it up from * any source that has it available. */ - if (info->slave_addr && !e->slave_addr) - e->slave_addr = info->slave_addr; + if (info->io.slave_addr && !e->io.slave_addr) + e->io.slave_addr = info->io.slave_addr; return e; } } @@ -3450,26 +3430,26 @@ int ipmi_si_add_smi(struct smi_info *new_smi) mutex_lock(&smi_infos_lock); dup = find_dup_si(new_smi); if (dup) { - if (new_smi->addr_source == SI_ACPI && - dup->addr_source == SI_SMBIOS) { + if (new_smi->io.addr_source == SI_ACPI && + dup->io.addr_source == SI_SMBIOS) { /* We prefer ACPI over SMBIOS. */ - dev_info(dup->dev, + dev_info(dup->io.dev, "Removing SMBIOS-specified %s state machine in favor of ACPI\n", - si_to_str[new_smi->si_type]); + si_to_str[new_smi->io.si_type]); cleanup_one_si(dup); } else { - dev_info(new_smi->dev, + dev_info(new_smi->io.dev, "%s-specified %s state machine: duplicate\n", - ipmi_addr_src_to_str(new_smi->addr_source), - si_to_str[new_smi->si_type]); + ipmi_addr_src_to_str(new_smi->io.addr_source), + si_to_str[new_smi->io.si_type]); rv = -EBUSY; goto out_err; } } pr_info(PFX "Adding %s-specified %s state machine\n", - ipmi_addr_src_to_str(new_smi->addr_source), - si_to_str[new_smi->si_type]); + ipmi_addr_src_to_str(new_smi->io.addr_source), + si_to_str[new_smi->io.si_type]); /* So we know not to free it unless we have allocated one. */ new_smi->intf = NULL; @@ -3495,13 +3475,13 @@ static int try_smi_init(struct smi_info *new_smi) char *init_name = NULL; pr_info(PFX "Trying %s-specified %s state machine at %s address 0x%lx, slave address 0x%x, irq %d\n", - ipmi_addr_src_to_str(new_smi->addr_source), - si_to_str[new_smi->si_type], + ipmi_addr_src_to_str(new_smi->io.addr_source), + si_to_str[new_smi->io.si_type], addr_space_to_str[new_smi->io.addr_type], new_smi->io.addr_data, - new_smi->slave_addr, new_smi->irq); + new_smi->io.slave_addr, new_smi->io.irq); - switch (new_smi->si_type) { + switch (new_smi->io.si_type) { case SI_KCS: new_smi->handlers = &kcs_smi_handlers; break; @@ -3523,7 +3503,7 @@ static int try_smi_init(struct smi_info *new_smi) new_smi->intf_num = smi_num; /* Do this early so it's available for logs. */ - if (!new_smi->dev) { + if (!new_smi->io.dev) { init_name = kasprintf(GFP_KERNEL, "ipmi_si.%d", new_smi->intf_num); @@ -3537,10 +3517,10 @@ static int try_smi_init(struct smi_info *new_smi) pr_err(PFX "Unable to allocate platform device\n"); goto out_err; } - new_smi->dev = &new_smi->pdev->dev; - new_smi->dev->driver = &ipmi_driver.driver; + new_smi->io.dev = &new_smi->pdev->dev; + new_smi->io.dev->driver = &ipmi_driver.driver; /* Nulled by device_add() */ - new_smi->dev->init_name = init_name; + new_smi->io.dev->init_name = init_name; } /* Allocate the state machine's data and initialize it. */ @@ -3556,14 +3536,15 @@ static int try_smi_init(struct smi_info *new_smi) /* Now that we know the I/O size, we can set up the I/O. */ rv = new_smi->io_setup(new_smi); if (rv) { - dev_err(new_smi->dev, "Could not set up I/O space\n"); + dev_err(new_smi->io.dev, "Could not set up I/O space\n"); goto out_err; } /* Do low-level detection first. */ if (new_smi->handlers->detect(new_smi->si_sm)) { - if (new_smi->addr_source) - dev_err(new_smi->dev, "Interface detection failed\n"); + if (new_smi->io.addr_source) + dev_err(new_smi->io.dev, + "Interface detection failed\n"); rv = -ENODEV; goto out_err; } @@ -3574,8 +3555,9 @@ static int try_smi_init(struct smi_info *new_smi) */ rv = try_get_dev_id(new_smi); if (rv) { - if (new_smi->addr_source) - dev_err(new_smi->dev, "There appears to be no BMC at this location\n"); + if (new_smi->io.addr_source) + dev_err(new_smi->io.dev, + "There appears to be no BMC at this location\n"); goto out_err; } @@ -3607,7 +3589,7 @@ static int try_smi_init(struct smi_info *new_smi) * IRQ is defined to be set when non-zero. req_events will * cause a global flags check that will enable interrupts. */ - if (new_smi->irq) { + if (new_smi->io.irq) { new_smi->interrupt_disabled = false; atomic_set(&new_smi->req_events, 1); } @@ -3615,20 +3597,20 @@ static int try_smi_init(struct smi_info *new_smi) if (new_smi->pdev) { rv = platform_device_add(new_smi->pdev); if (rv) { - dev_err(new_smi->dev, + dev_err(new_smi->io.dev, "Unable to register system interface device: %d\n", rv); goto out_err; } - new_smi->dev_registered = true; } rv = ipmi_register_smi(&handlers, new_smi, - new_smi->dev, - new_smi->slave_addr); + new_smi->io.dev, + new_smi->io.slave_addr); if (rv) { - dev_err(new_smi->dev, "Unable to register device: error %d\n", + dev_err(new_smi->io.dev, + "Unable to register device: error %d\n", rv); goto out_err_stop_timer; } @@ -3637,7 +3619,8 @@ static int try_smi_init(struct smi_info *new_smi) &smi_type_proc_ops, new_smi); if (rv) { - dev_err(new_smi->dev, "Unable to create proc entry: %d\n", rv); + dev_err(new_smi->io.dev, + "Unable to create proc entry: %d\n", rv); goto out_err_stop_timer; } @@ -3645,7 +3628,8 @@ static int try_smi_init(struct smi_info *new_smi) &smi_si_stats_proc_ops, new_smi); if (rv) { - dev_err(new_smi->dev, "Unable to create proc entry: %d\n", rv); + dev_err(new_smi->io.dev, + "Unable to create proc entry: %d\n", rv); goto out_err_stop_timer; } @@ -3653,17 +3637,18 @@ static int try_smi_init(struct smi_info *new_smi) &smi_params_proc_ops, new_smi); if (rv) { - dev_err(new_smi->dev, "Unable to create proc entry: %d\n", rv); + dev_err(new_smi->io.dev, + "Unable to create proc entry: %d\n", rv); goto out_err_stop_timer; } /* Don't increment till we know we have succeeded. */ smi_num++; - dev_info(new_smi->dev, "IPMI %s interface initialized\n", - si_to_str[new_smi->si_type]); + dev_info(new_smi->io.dev, "IPMI %s interface initialized\n", + si_to_str[new_smi->io.si_type]); - WARN_ON(new_smi->dev->init_name != NULL); + WARN_ON(new_smi->io.dev->init_name != NULL); kfree(init_name); return 0; @@ -3698,22 +3683,20 @@ out_err: kfree(new_smi->si_sm); new_smi->si_sm = NULL; } - if (new_smi->addr_source_cleanup) { - new_smi->addr_source_cleanup(new_smi); - new_smi->addr_source_cleanup = NULL; + if (new_smi->io.addr_source_cleanup) { + new_smi->io.addr_source_cleanup(&new_smi->io); + new_smi->io.addr_source_cleanup = NULL; } if (new_smi->io_cleanup) { new_smi->io_cleanup(new_smi); new_smi->io_cleanup = NULL; } - if (new_smi->dev_registered) { + if (new_smi->pdev) { platform_device_unregister(new_smi->pdev); - new_smi->dev_registered = false; new_smi->pdev = NULL; } else if (new_smi->pdev) { platform_device_put(new_smi->pdev); - new_smi->pdev = NULL; } kfree(init_name); @@ -3792,9 +3775,9 @@ static int init_ipmi_si(void) /* Try to register a device if it has an IRQ and we either haven't successfully registered a device yet or this device has the same type as one we successfully registered */ - if (e->irq && (!type || e->addr_source == type)) { + if (e->io.irq && (!type || e->io.addr_source == type)) { if (!try_smi_init(e)) { - type = e->addr_source; + type = e->io.addr_source; } } } @@ -3808,9 +3791,9 @@ static int init_ipmi_si(void) /* Fall back to the preferred device */ list_for_each_entry(e, &smi_infos, link) { - if (!e->irq && (!type || e->addr_source == type)) { + if (!e->io.irq && (!type || e->io.addr_source == type)) { if (!try_smi_init(e)) { - type = e->addr_source; + type = e->io.addr_source; } } } @@ -3850,8 +3833,8 @@ static void cleanup_one_si(struct smi_info *to_clean) } } - if (to_clean->dev) - dev_set_drvdata(to_clean->dev, NULL); + if (to_clean->io.dev) + dev_set_drvdata(to_clean->io.dev, NULL); list_del(&to_clean->link); @@ -3884,12 +3867,12 @@ static void cleanup_one_si(struct smi_info *to_clean) kfree(to_clean->si_sm); - if (to_clean->addr_source_cleanup) - to_clean->addr_source_cleanup(to_clean); + if (to_clean->io.addr_source_cleanup) + to_clean->io.addr_source_cleanup(&to_clean->io); if (to_clean->io_cleanup) to_clean->io_cleanup(to_clean); - if (to_clean->dev_registered) + if (to_clean->pdev) platform_device_unregister(to_clean->pdev); kfree(to_clean); diff --git a/drivers/char/ipmi/ipmi_si_sm.h b/drivers/char/ipmi/ipmi_si_sm.h index a705027c0493..ffbf67f630a9 100644 --- a/drivers/char/ipmi/ipmi_si_sm.h +++ b/drivers/char/ipmi/ipmi_si_sm.h @@ -34,12 +34,18 @@ * 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include + /* * This is defined by the state machines themselves, it is an opaque * data type for them to use. */ struct si_sm_data; +enum si_type { + SI_KCS, SI_SMIC, SI_BT +}; + /* * The structure for doing I/O in the state machine. The state * machine doesn't have the actual I/O routines, they are done through @@ -61,6 +67,14 @@ struct si_sm_io { int regshift; int addr_type; long addr_data; + enum ipmi_addr_src addr_source; /* ACPI, PCI, SMBIOS, hardcode, etc. */ + void (*addr_source_cleanup)(struct si_sm_io *io); + void *addr_source_data; + + int irq; + u8 slave_addr; + enum si_type si_type; + struct device *dev; }; /* Results of SMI events. */ From 4f3e8199c34dda46b6554191fe7a444dd6fa911f Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Tue, 12 Sep 2017 15:10:22 -0500 Subject: [PATCH 29/48] ipmi_si: Move irq setup handling into the io struct So the platform code can do it without having to access the smi info, getting ready for pulling the platform handling section to their own files. Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_si.h | 5 + drivers/char/ipmi/ipmi_si_intf.c | 158 +++++++++++++++---------------- drivers/char/ipmi/ipmi_si_sm.h | 4 + 3 files changed, 84 insertions(+), 83 deletions(-) diff --git a/drivers/char/ipmi/ipmi_si.h b/drivers/char/ipmi/ipmi_si.h index a4d993b1fe66..e84651acd772 100644 --- a/drivers/char/ipmi/ipmi_si.h +++ b/drivers/char/ipmi/ipmi_si.h @@ -5,6 +5,7 @@ * etc) to the base ipmi system interface code. */ +#include #include "ipmi_si_sm.h" #define IPMI_IO_ADDR_SPACE 0 @@ -16,3 +17,7 @@ struct smi_info; int ipmi_si_add_smi(struct smi_info *info); +irqreturn_t ipmi_si_irq_handler(int irq, void *data); +void ipmi_irq_start_cleanup(struct si_sm_io *io); +int ipmi_std_irq_setup(struct si_sm_io *io); +void ipmi_irq_finish_setup(struct si_sm_io *io); diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 8cc101ea82d9..4b832b96d02b 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -175,8 +175,6 @@ struct smi_info { struct si_sm_io io; int (*io_setup)(struct smi_info *info); void (*io_cleanup)(struct smi_info *info); - int (*irq_setup)(struct smi_info *info); - void (*irq_cleanup)(struct smi_info *info); unsigned int io_size; /* @@ -1177,11 +1175,17 @@ do_mod_timer: spin_unlock_irqrestore(&(smi_info->si_lock), flags); } -static irqreturn_t si_irq_handler(int irq, void *data) +irqreturn_t ipmi_si_irq_handler(int irq, void *data) { struct smi_info *smi_info = data; unsigned long flags; + if (smi_info->io.si_type == SI_BT) + /* We need to clear the IRQ flag for the BT interface. */ + smi_info->io.outputb(&smi_info->io, IPMI_BT_INTMASK_REG, + IPMI_BT_INTMASK_CLEAR_IRQ_BIT + | IPMI_BT_INTMASK_ENABLE_IRQ_BIT); + spin_lock_irqsave(&(smi_info->si_lock), flags); smi_inc_stat(smi_info, interrupts); @@ -1193,16 +1197,6 @@ static irqreturn_t si_irq_handler(int irq, void *data) return IRQ_HANDLED; } -static irqreturn_t si_bt_irq_handler(int irq, void *data) -{ - struct smi_info *smi_info = data; - /* We need to clear the IRQ flag for the BT interface. */ - smi_info->io.outputb(&smi_info->io, IPMI_BT_INTMASK_REG, - IPMI_BT_INTMASK_CLEAR_IRQ_BIT - | IPMI_BT_INTMASK_ENABLE_IRQ_BIT); - return si_irq_handler(irq, data); -} - static int smi_start_processing(void *send_info, ipmi_smi_t intf) { @@ -1216,8 +1210,10 @@ static int smi_start_processing(void *send_info, smi_mod_timer(new_smi, jiffies + SI_TIMEOUT_JIFFIES); /* Try to claim any interrupts. */ - if (new_smi->irq_setup) - new_smi->irq_setup(new_smi); + if (new_smi->io.irq_setup) { + new_smi->io.irq_handler_data = new_smi; + new_smi->io.irq_setup(&new_smi->io); + } /* * Check if the user forcefully enabled the daemon. @@ -1400,46 +1396,48 @@ MODULE_PARM_DESC(kipmid_max_busy_us, " sleeping. 0 (default) means to wait forever. Set to 100-500" " if kipmid is using up a lot of CPU time."); - -static void std_irq_cleanup(struct smi_info *info) +void ipmi_irq_finish_setup(struct si_sm_io *io) { - if (info->io.si_type == SI_BT) - /* Disable the interrupt in the BT interface. */ - info->io.outputb(&info->io, IPMI_BT_INTMASK_REG, 0); - free_irq(info->io.irq, info); + if (io->si_type == SI_BT) + /* Enable the interrupt in the BT interface. */ + io->outputb(io, IPMI_BT_INTMASK_REG, + IPMI_BT_INTMASK_ENABLE_IRQ_BIT); } -static int std_irq_setup(struct smi_info *info) +void ipmi_irq_start_cleanup(struct si_sm_io *io) +{ + if (io->si_type == SI_BT) + /* Disable the interrupt in the BT interface. */ + io->outputb(io, IPMI_BT_INTMASK_REG, 0); +} + +static void std_irq_cleanup(struct si_sm_io *io) +{ + ipmi_irq_start_cleanup(io); + free_irq(io->irq, io->irq_handler_data); +} + +int ipmi_std_irq_setup(struct si_sm_io *io) { int rv; - if (!info->io.irq) + if (!io->irq) return 0; - if (info->io.si_type == SI_BT) { - rv = request_irq(info->io.irq, - si_bt_irq_handler, - IRQF_SHARED, - DEVICE_NAME, - info); - if (!rv) - /* Enable the interrupt in the BT interface. */ - info->io.outputb(&info->io, IPMI_BT_INTMASK_REG, - IPMI_BT_INTMASK_ENABLE_IRQ_BIT); - } else - rv = request_irq(info->io.irq, - si_irq_handler, - IRQF_SHARED, - DEVICE_NAME, - info); + rv = request_irq(io->irq, + ipmi_si_irq_handler, + IRQF_SHARED, + DEVICE_NAME, + io->irq_handler_data); if (rv) { - dev_warn(info->io.dev, "%s unable to claim interrupt %d," + dev_warn(io->dev, "%s unable to claim interrupt %d," " running polled\n", - DEVICE_NAME, info->io.irq); - info->io.irq = 0; + DEVICE_NAME, io->irq); + io->irq = 0; } else { - info->irq_cleanup = std_irq_cleanup; - dev_info(info->io.dev, "Using irq %d\n", info->io.irq); + io->irq_cleanup = std_irq_cleanup; + ipmi_irq_finish_setup(io); + dev_info(io->dev, "Using irq %d\n", io->irq); } return rv; @@ -1920,7 +1918,7 @@ static int hotmod_handler(const char *val, struct kernel_param *kp) info->io.regshift = regshift; info->io.irq = irq; if (info->io.irq) - info->irq_setup = std_irq_setup; + info->io.irq_setup = ipmi_std_irq_setup; info->io.slave_addr = ipmb; rv = ipmi_si_add_smi(info); @@ -2014,7 +2012,7 @@ static int hardcode_find_bmc(void) info->io.regshift = regshifts[i]; info->io.irq = irqs[i]; if (info->io.irq) - info->irq_setup = std_irq_setup; + info->io.irq_setup = ipmi_std_irq_setup; info->io.slave_addr = slave_addrs[i]; if (!ipmi_si_add_smi(info)) { @@ -2043,49 +2041,43 @@ static int acpi_failure; static u32 ipmi_acpi_gpe(acpi_handle gpe_device, u32 gpe_number, void *context) { - struct smi_info *smi_info = context; - unsigned long flags; - - spin_lock_irqsave(&(smi_info->si_lock), flags); - - smi_inc_stat(smi_info, interrupts); - - debug_timestamp("ACPI_GPE"); - - smi_event_handler(smi_info, 0); - spin_unlock_irqrestore(&(smi_info->si_lock), flags); + struct si_sm_io *io = context; + ipmi_si_irq_handler(io->irq, io->irq_handler_data); return ACPI_INTERRUPT_HANDLED; } -static void acpi_gpe_irq_cleanup(struct smi_info *info) +static void acpi_gpe_irq_cleanup(struct si_sm_io *io) { - if (!info->io.irq) + if (!io->irq) return; - acpi_remove_gpe_handler(NULL, info->io.irq, &ipmi_acpi_gpe); + ipmi_irq_start_cleanup(io); + acpi_remove_gpe_handler(NULL, io->irq, &ipmi_acpi_gpe); } -static int acpi_gpe_irq_setup(struct smi_info *info) +static int acpi_gpe_irq_setup(struct si_sm_io *io) { acpi_status status; - if (!info->io.irq) + if (!io->irq) return 0; status = acpi_install_gpe_handler(NULL, - info->io.irq, + io->irq, ACPI_GPE_LEVEL_TRIGGERED, &ipmi_acpi_gpe, - info); + io); if (status != AE_OK) { - dev_warn(info->io.dev, "%s unable to claim ACPI GPE %d," - " running polled\n", DEVICE_NAME, info->io.irq); - info->io.irq = 0; + dev_warn(io->dev, + "Unable to claim ACPI GPE %d, running polled\n", + io->irq); + io->irq = 0; return -EINVAL; } else { - info->irq_cleanup = acpi_gpe_irq_cleanup; - dev_info(info->io.dev, "Using ACPI GPE %d\n", info->io.irq); + io->irq_cleanup = acpi_gpe_irq_cleanup; + ipmi_irq_finish_setup(io); + dev_info(io->dev, "Using ACPI GPE %d\n", io->irq); return 0; } } @@ -2179,15 +2171,15 @@ static int try_init_spmi(struct SPMITable *spmi) if (spmi->InterruptType & 1) { /* We've got a GPE interrupt. */ info->io.irq = spmi->GPE; - info->irq_setup = acpi_gpe_irq_setup; + info->io.irq_setup = acpi_gpe_irq_setup; } else if (spmi->InterruptType & 2) { /* We've got an APIC/SAPIC interrupt. */ info->io.irq = spmi->GlobalSystemInterrupt; - info->irq_setup = std_irq_setup; + info->io.irq_setup = ipmi_std_irq_setup; } else { /* Use the default interrupt setting. */ info->io.irq = 0; - info->irq_setup = NULL; + info->io.irq_setup = NULL; } if (spmi->addr.bit_width) { @@ -2342,7 +2334,7 @@ static int dmi_ipmi_probe(struct platform_device *pdev) info->io.irq = platform_get_irq(pdev, 0); if (info->io.irq > 0) - info->irq_setup = std_irq_setup; + info->io.irq_setup = ipmi_std_irq_setup; else info->io.irq = 0; @@ -2479,7 +2471,7 @@ static int ipmi_pci_probe(struct pci_dev *pdev, info->io.irq = pdev->irq; if (info->io.irq) - info->irq_setup = std_irq_setup; + info->io.irq_setup = ipmi_std_irq_setup; info->io.dev = &pdev->dev; pci_set_drvdata(pdev, info); @@ -2583,7 +2575,7 @@ static int of_ipmi_probe(struct platform_device *pdev) info->io.si_type = (enum si_type) match->data; info->io.addr_source = SI_DEVICETREE; - info->io.irq_setup = std_irq_setup; + info->io.irq_setup = ipmi_std_irq_setup; if (resource.flags & IORESOURCE_IO) { info->io_setup = port_setup; @@ -2715,13 +2707,13 @@ static int acpi_ipmi_probe(struct platform_device *pdev) status = acpi_evaluate_integer(handle, "_GPE", NULL, &tmp); if (ACPI_SUCCESS(status)) { info->io.irq = tmp; - info->irq_setup = acpi_gpe_irq_setup; + info->io.irq_setup = acpi_gpe_irq_setup; } else { int irq = platform_get_irq(pdev, 0); if (irq > 0) { info->io.irq = irq; - info->irq_setup = std_irq_setup; + info->io.irq_setup = ipmi_std_irq_setup; } } @@ -2809,7 +2801,7 @@ static int __init ipmi_parisc_probe(struct parisc_device *dev) info->io.regspacing = 1; info->io.regshift = 0; info->io.irq = 0; /* no interrupt */ - info->irq_setup = NULL; + info->io.irq_setup = NULL; info->io.dev = &dev->dev; dev_dbg(&dev->dev, "addr 0x%lx\n", info->io.addr_data); @@ -3665,9 +3657,9 @@ out_err: ipmi_unregister_smi(intf); } - if (new_smi->irq_cleanup) { - new_smi->irq_cleanup(new_smi); - new_smi->irq_cleanup = NULL; + if (new_smi->io.irq_cleanup) { + new_smi->io.irq_cleanup(&new_smi->io); + new_smi->io.irq_cleanup = NULL; } /* @@ -3842,8 +3834,8 @@ static void cleanup_one_si(struct smi_info *to_clean) * Make sure that interrupts, the timer and the thread are * stopped and will not run again. */ - if (to_clean->irq_cleanup) - to_clean->irq_cleanup(to_clean); + if (to_clean->io.irq_cleanup) + to_clean->io.irq_cleanup(&to_clean->io); wait_for_timer_and_thread(to_clean); /* diff --git a/drivers/char/ipmi/ipmi_si_sm.h b/drivers/char/ipmi/ipmi_si_sm.h index ffbf67f630a9..bf3f50cede44 100644 --- a/drivers/char/ipmi/ipmi_si_sm.h +++ b/drivers/char/ipmi/ipmi_si_sm.h @@ -72,6 +72,10 @@ struct si_sm_io { void *addr_source_data; int irq; + int (*irq_setup)(struct si_sm_io *io); + void *irq_handler_data; + void (*irq_cleanup)(struct si_sm_io *io); + u8 slave_addr; enum si_type si_type; struct device *dev; From e1eeb7f8620733fe9f6640eef48d449b925b3c23 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Tue, 12 Sep 2017 15:40:53 -0500 Subject: [PATCH 30/48] ipmi_si: Move io setup into io structure Where it belongs, and getting ready for pulling the platform handling into its own file. Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_si_intf.c | 173 +++++++++++++++---------------- drivers/char/ipmi/ipmi_si_sm.h | 4 + 2 files changed, 85 insertions(+), 92 deletions(-) diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 4b832b96d02b..d0a0a5d9e5ff 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -173,9 +173,6 @@ struct smi_info { * IPMI */ struct si_sm_io io; - int (*io_setup)(struct smi_info *info); - void (*io_cleanup)(struct smi_info *info); - unsigned int io_size; /* * Per-OEM handler, called from handle_flags(). Returns 1 @@ -1488,48 +1485,48 @@ static void port_outl(const struct si_sm_io *io, unsigned int offset, outl(b << io->regshift, addr+(offset * io->regspacing)); } -static void port_cleanup(struct smi_info *info) +static void port_cleanup(struct si_sm_io *io) { - unsigned int addr = info->io.addr_data; + unsigned int addr = io->addr_data; int idx; if (addr) { - for (idx = 0; idx < info->io_size; idx++) - release_region(addr + idx * info->io.regspacing, - info->io.regsize); + for (idx = 0; idx < io->io_size; idx++) + release_region(addr + idx * io->regspacing, + io->regsize); } } -static int port_setup(struct smi_info *info) +static int port_setup(struct si_sm_io *io) { - unsigned int addr = info->io.addr_data; + unsigned int addr = io->addr_data; int idx; if (!addr) return -ENODEV; - info->io_cleanup = port_cleanup; + io->io_cleanup = port_cleanup; /* * Figure out the actual inb/inw/inl/etc routine to use based * upon the register size. */ - switch (info->io.regsize) { + switch (io->regsize) { case 1: - info->io.inputb = port_inb; - info->io.outputb = port_outb; + io->inputb = port_inb; + io->outputb = port_outb; break; case 2: - info->io.inputb = port_inw; - info->io.outputb = port_outw; + io->inputb = port_inw; + io->outputb = port_outw; break; case 4: - info->io.inputb = port_inl; - info->io.outputb = port_outl; + io->inputb = port_inl; + io->outputb = port_outl; break; default: - dev_warn(info->io.dev, "Invalid register size: %d\n", - info->io.regsize); + dev_warn(io->dev, "Invalid register size: %d\n", + io->regsize); return -EINVAL; } @@ -1539,13 +1536,13 @@ static int port_setup(struct smi_info *info) * entire I/O region. Therefore we must register each I/O * port separately. */ - for (idx = 0; idx < info->io_size; idx++) { - if (request_region(addr + idx * info->io.regspacing, - info->io.regsize, DEVICE_NAME) == NULL) { + for (idx = 0; idx < io->io_size; idx++) { + if (request_region(addr + idx * io->regspacing, + io->regsize, DEVICE_NAME) == NULL) { /* Undo allocations */ while (idx--) - release_region(addr + idx * info->io.regspacing, - info->io.regsize); + release_region(addr + idx * io->regspacing, + io->regsize); return -EIO; } } @@ -1604,60 +1601,60 @@ static void mem_outq(const struct si_sm_io *io, unsigned int offset, } #endif -static void mem_region_cleanup(struct smi_info *info, int num) +static void mem_region_cleanup(struct si_sm_io *io, int num) { - unsigned long addr = info->io.addr_data; + unsigned long addr = io->addr_data; int idx; for (idx = 0; idx < num; idx++) - release_mem_region(addr + idx * info->io.regspacing, - info->io.regsize); + release_mem_region(addr + idx * io->regspacing, + io->regsize); } -static void mem_cleanup(struct smi_info *info) +static void mem_cleanup(struct si_sm_io *io) { - if (info->io.addr) { - iounmap(info->io.addr); - mem_region_cleanup(info, info->io_size); + if (io->addr) { + iounmap(io->addr); + mem_region_cleanup(io, io->io_size); } } -static int mem_setup(struct smi_info *info) +static int mem_setup(struct si_sm_io *io) { - unsigned long addr = info->io.addr_data; + unsigned long addr = io->addr_data; int mapsize, idx; if (!addr) return -ENODEV; - info->io_cleanup = mem_cleanup; + io->io_cleanup = mem_cleanup; /* * Figure out the actual readb/readw/readl/etc routine to use based * upon the register size. */ - switch (info->io.regsize) { + switch (io->regsize) { case 1: - info->io.inputb = intf_mem_inb; - info->io.outputb = intf_mem_outb; + io->inputb = intf_mem_inb; + io->outputb = intf_mem_outb; break; case 2: - info->io.inputb = intf_mem_inw; - info->io.outputb = intf_mem_outw; + io->inputb = intf_mem_inw; + io->outputb = intf_mem_outw; break; case 4: - info->io.inputb = intf_mem_inl; - info->io.outputb = intf_mem_outl; + io->inputb = intf_mem_inl; + io->outputb = intf_mem_outl; break; #ifdef readq case 8: - info->io.inputb = mem_inq; - info->io.outputb = mem_outq; + io->inputb = mem_inq; + io->outputb = mem_outq; break; #endif default: - dev_warn(info->io.dev, "Invalid register size: %d\n", - info->io.regsize); + dev_warn(io->dev, "Invalid register size: %d\n", + io->regsize); return -EINVAL; } @@ -1667,11 +1664,11 @@ static int mem_setup(struct smi_info *info) * entire region. Therefore we must request each register * separately. */ - for (idx = 0; idx < info->io_size; idx++) { - if (request_mem_region(addr + idx * info->io.regspacing, - info->io.regsize, DEVICE_NAME) == NULL) { + for (idx = 0; idx < io->io_size; idx++) { + if (request_mem_region(addr + idx * io->regspacing, + io->regsize, DEVICE_NAME) == NULL) { /* Undo allocations */ - mem_region_cleanup(info, idx); + mem_region_cleanup(io, idx); return -EIO; } } @@ -1683,11 +1680,11 @@ static int mem_setup(struct smi_info *info) * between the first address to the end of the last full * register. */ - mapsize = ((info->io_size * info->io.regspacing) - - (info->io.regspacing - info->io.regsize)); - info->io.addr = ioremap(addr, mapsize); - if (info->io.addr == NULL) { - mem_region_cleanup(info, info->io_size); + mapsize = ((io->io_size * io->regspacing) + - (io->regspacing - io->regsize)); + io->addr = ioremap(addr, mapsize); + if (io->addr == NULL) { + mem_region_cleanup(io, io->io_size); return -EIO; } return 0; @@ -1903,10 +1900,6 @@ static int hotmod_handler(const char *val, struct kernel_param *kp) info->io.si_type = si_type; info->io.addr_data = addr; info->io.addr_type = addr_space; - if (addr_space == IPMI_MEM_ADDR_SPACE) - info->io_setup = mem_setup; - else - info->io_setup = port_setup; info->io.addr = NULL; info->io.regspacing = regspacing; @@ -1987,12 +1980,10 @@ static int hardcode_find_bmc(void) if (ports[i]) { /* An I/O port */ - info->io_setup = port_setup; info->io.addr_data = ports[i]; info->io.addr_type = IPMI_IO_ADDR_SPACE; } else if (addrs[i]) { /* A memory port */ - info->io_setup = mem_setup; info->io.addr_data = addrs[i]; info->io.addr_type = IPMI_MEM_ADDR_SPACE; } else { @@ -2192,10 +2183,8 @@ static int try_init_spmi(struct SPMITable *spmi) info->io.regshift = spmi->addr.bit_offset; if (spmi->addr.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { - info->io_setup = mem_setup; info->io.addr_type = IPMI_MEM_ADDR_SPACE; } else if (spmi->addr.space_id == ACPI_ADR_SPACE_SYSTEM_IO) { - info->io_setup = port_setup; info->io.addr_type = IPMI_IO_ADDR_SPACE; } else { kfree(info); @@ -2248,14 +2237,11 @@ ipmi_get_info_from_resources(struct platform_device *pdev, res = platform_get_resource(pdev, IORESOURCE_IO, 0); if (res) { - info->io_setup = port_setup; info->io.addr_type = IPMI_IO_ADDR_SPACE; } else { res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res) { - info->io_setup = mem_setup; + if (res) info->io.addr_type = IPMI_MEM_ADDR_SPACE; - } } if (!res) { dev_err(&pdev->dev, "no I/O or memory address\n"); @@ -2389,13 +2375,13 @@ static int ipmi_pci_probe_regspacing(struct smi_info *info) info->io.regsize = DEFAULT_REGSIZE; info->io.regshift = 0; - info->io_size = 2; + info->io.io_size = 2; info->handlers = &kcs_smi_handlers; /* detect 1, 4, 16byte spacing */ for (regspacing = DEFAULT_REGSPACING; regspacing <= 16;) { info->io.regspacing = regspacing; - if (info->io_setup(info)) { + if (info->io.io_setup(&info->io)) { dev_err(info->io.dev, "Could not setup I/O space\n"); return DEFAULT_REGSPACING; @@ -2404,7 +2390,7 @@ static int ipmi_pci_probe_regspacing(struct smi_info *info) info->io.outputb(&info->io, 1, 0x10); /* read status back */ status = info->io.inputb(&info->io, 1); - info->io_cleanup(info); + info->io.io_cleanup(&info->io); if (status) return regspacing; regspacing *= 4; @@ -2456,13 +2442,10 @@ static int ipmi_pci_probe(struct pci_dev *pdev, info->io.addr_source_cleanup = ipmi_pci_cleanup; info->io.addr_source_data = pdev; - if (pci_resource_flags(pdev, 0) & IORESOURCE_IO) { - info->io_setup = port_setup; + if (pci_resource_flags(pdev, 0) & IORESOURCE_IO) info->io.addr_type = IPMI_IO_ADDR_SPACE; - } else { - info->io_setup = mem_setup; + else info->io.addr_type = IPMI_MEM_ADDR_SPACE; - } info->io.addr_data = pci_resource_start(pdev, 0); info->io.regspacing = ipmi_pci_probe_regspacing(info); @@ -2577,13 +2560,10 @@ static int of_ipmi_probe(struct platform_device *pdev) info->io.addr_source = SI_DEVICETREE; info->io.irq_setup = ipmi_std_irq_setup; - if (resource.flags & IORESOURCE_IO) { - info->io_setup = port_setup; - info->io.addr_type = IPMI_IO_ADDR_SPACE; - } else { - info->io_setup = mem_setup; - info->io.addr_type = IPMI_MEM_ADDR_SPACE; - } + if (resource.flags & IORESOURCE_IO) + info->io.addr_type = IPMI_IO_ADDR_SPACE; + else + info->io.addr_type = IPMI_MEM_ADDR_SPACE; info->io.addr_data = resource.start; @@ -2794,7 +2774,6 @@ static int __init ipmi_parisc_probe(struct parisc_device *dev) info->io.si_type = SI_KCS; info->io.addr_source = SI_DEVICETREE; - info->io_setup = mem_setup; info->io.addr_type = IPMI_MEM_ADDR_SPACE; info->io.addr_data = dev->hpa.start; info->io.regsize = 1; @@ -3419,6 +3398,16 @@ int ipmi_si_add_smi(struct smi_info *new_smi) int rv = 0; struct smi_info *dup; + if (!new_smi->io.io_setup) { + if (new_smi->io.addr_type == IPMI_IO_ADDR_SPACE) { + new_smi->io.io_setup = port_setup; + } else if (new_smi->io.addr_type == IPMI_MEM_ADDR_SPACE) { + new_smi->io.io_setup = mem_setup; + } else { + return -EINVAL; + } + } + mutex_lock(&smi_infos_lock); dup = find_dup_si(new_smi); if (dup) { @@ -3522,11 +3511,11 @@ static int try_smi_init(struct smi_info *new_smi) rv = -ENOMEM; goto out_err; } - new_smi->io_size = new_smi->handlers->init_data(new_smi->si_sm, - &new_smi->io); + new_smi->io.io_size = new_smi->handlers->init_data(new_smi->si_sm, + &new_smi->io); /* Now that we know the I/O size, we can set up the I/O. */ - rv = new_smi->io_setup(new_smi); + rv = new_smi->io.io_setup(&new_smi->io); if (rv) { dev_err(new_smi->io.dev, "Could not set up I/O space\n"); goto out_err; @@ -3679,9 +3668,9 @@ out_err: new_smi->io.addr_source_cleanup(&new_smi->io); new_smi->io.addr_source_cleanup = NULL; } - if (new_smi->io_cleanup) { - new_smi->io_cleanup(new_smi); - new_smi->io_cleanup = NULL; + if (new_smi->io.io_cleanup) { + new_smi->io.io_cleanup(&new_smi->io); + new_smi->io.io_cleanup = NULL; } if (new_smi->pdev) { @@ -3861,8 +3850,8 @@ static void cleanup_one_si(struct smi_info *to_clean) if (to_clean->io.addr_source_cleanup) to_clean->io.addr_source_cleanup(&to_clean->io); - if (to_clean->io_cleanup) - to_clean->io_cleanup(to_clean); + if (to_clean->io.io_cleanup) + to_clean->io.io_cleanup(&to_clean->io); if (to_clean->pdev) platform_device_unregister(to_clean->pdev); diff --git a/drivers/char/ipmi/ipmi_si_sm.h b/drivers/char/ipmi/ipmi_si_sm.h index bf3f50cede44..9df77c664908 100644 --- a/drivers/char/ipmi/ipmi_si_sm.h +++ b/drivers/char/ipmi/ipmi_si_sm.h @@ -71,6 +71,10 @@ struct si_sm_io { void (*addr_source_cleanup)(struct si_sm_io *io); void *addr_source_data; + int (*io_setup)(struct si_sm_io *info); + void (*io_cleanup)(struct si_sm_io *info); + unsigned int io_size; + int irq; int (*irq_setup)(struct si_sm_io *io); void *irq_handler_data; From bb398a4cb09a0ed96cf0fc2e90012cf6bf13a824 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Tue, 12 Sep 2017 21:37:02 -0500 Subject: [PATCH 31/48] ipmi_si: Change ipmi_si_add_smi() to take just I/O info Instead of allocating the smi_info structure, filling in the I/O info, and passing it to ipmi_si_add_smi(), just pass the I/O info in the io structure and let ipmi_si_add_smi() allocate the smi_info structure. This required redoing the way the remove functions for some device interfaces worked, a new function named ipmi_si_remove_by_dev() allows the device to be passed in and detected instead of using driver data, which couldn't be filled out easily othersize. After this the platform handling should be decoupled from the smi_info structure and that handling can be pulled out to its own files. Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_si.h | 5 +- drivers/char/ipmi/ipmi_si_intf.c | 524 +++++++++++++------------------ drivers/char/ipmi/ipmi_si_sm.h | 1 + 3 files changed, 225 insertions(+), 305 deletions(-) diff --git a/drivers/char/ipmi/ipmi_si.h b/drivers/char/ipmi/ipmi_si.h index e84651acd772..9573b35d73af 100644 --- a/drivers/char/ipmi/ipmi_si.h +++ b/drivers/char/ipmi/ipmi_si.h @@ -14,10 +14,9 @@ #define DEFAULT_REGSPACING 1 #define DEFAULT_REGSIZE 1 -struct smi_info; - -int ipmi_si_add_smi(struct smi_info *info); +int ipmi_si_add_smi(struct si_sm_io *io); irqreturn_t ipmi_si_irq_handler(int irq, void *data); void ipmi_irq_start_cleanup(struct si_sm_io *io); int ipmi_std_irq_setup(struct si_sm_io *io); void ipmi_irq_finish_setup(struct si_sm_io *io); +int ipmi_si_remove_by_dev(struct device *dev); diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index d0a0a5d9e5ff..6c2e14af8321 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -110,6 +110,8 @@ static const char * const si_to_str[] = { "kcs", "smic", "bt" }; static struct platform_driver ipmi_driver; +static int initialized; + /* * Indexes into stats[] in smi_info below. */ @@ -282,7 +284,6 @@ struct smi_info { struct task_struct *thread; struct list_head link; - union ipmi_smi_info_union addr_info; }; #define smi_inc_stat(smi, stat) \ @@ -1126,8 +1127,6 @@ static void set_need_watch(void *send_info, bool enable) spin_unlock_irqrestore(&smi_info->si_lock, flags); } -static int initialized; - static void smi_timeout(unsigned long data) { struct smi_info *smi_info = (struct smi_info *) data; @@ -1245,7 +1244,7 @@ static int get_smi_info(void *send_info, struct ipmi_smi_info *data) data->addr_src = smi->io.addr_source; data->dev = smi->io.dev; - data->addr_info = smi->addr_info; + data->addr_info = smi->io.addr_info; get_device(smi->io.dev); return 0; @@ -1795,7 +1794,6 @@ static int hotmod_handler(const char *val, struct kernel_param *kp) int ipmb; int ival; int len; - struct smi_info *info; if (!str) return -ENOMEM; @@ -1890,42 +1888,30 @@ static int hotmod_handler(const char *val, struct kernel_param *kp) } if (op == HM_ADD) { - info = smi_info_alloc(); - if (!info) { - rv = -ENOMEM; - goto out; - } + struct si_sm_io io; - info->io.addr_source = SI_HOTMOD; - info->io.si_type = si_type; - info->io.addr_data = addr; - info->io.addr_type = addr_space; + memset(&io, 0, sizeof(io)); + io.addr_source = SI_HOTMOD; + io.si_type = si_type; + io.addr_data = addr; + io.addr_type = addr_space; - info->io.addr = NULL; - info->io.regspacing = regspacing; - if (!info->io.regspacing) - info->io.regspacing = DEFAULT_REGSPACING; - info->io.regsize = regsize; - if (!info->io.regsize) - info->io.regsize = DEFAULT_REGSIZE; - info->io.regshift = regshift; - info->io.irq = irq; - if (info->io.irq) - info->io.irq_setup = ipmi_std_irq_setup; - info->io.slave_addr = ipmb; + io.addr = NULL; + io.regspacing = regspacing; + if (!io.regspacing) + io.regspacing = DEFAULT_REGSPACING; + io.regsize = regsize; + if (!io.regsize) + io.regsize = DEFAULT_REGSIZE; + io.regshift = regshift; + io.irq = irq; + if (io.irq) + io.irq_setup = ipmi_std_irq_setup; + io.slave_addr = ipmb; - rv = ipmi_si_add_smi(info); - if (rv) { - kfree(info); + rv = ipmi_si_add_smi(&io); + if (rv) goto out; - } - mutex_lock(&smi_infos_lock); - rv = try_smi_init(info); - mutex_unlock(&smi_infos_lock); - if (rv) { - cleanup_one_si(info); - goto out; - } } else { /* remove */ struct smi_info *e, *tmp_e; @@ -1952,69 +1938,56 @@ static int hardcode_find_bmc(void) { int ret = -ENODEV; int i; - struct smi_info *info; + struct si_sm_io io; + memset(&io, 0, sizeof(io)); for (i = 0; i < SI_MAX_PARMS; i++) { if (!ports[i] && !addrs[i]) continue; - info = smi_info_alloc(); - if (!info) - return -ENOMEM; - - info->io.addr_source = SI_HARDCODED; + io.addr_source = SI_HARDCODED; pr_info(PFX "probing via hardcoded address\n"); if (!si_type[i] || strcmp(si_type[i], "kcs") == 0) { - info->io.si_type = SI_KCS; + io.si_type = SI_KCS; } else if (strcmp(si_type[i], "smic") == 0) { - info->io.si_type = SI_SMIC; + io.si_type = SI_SMIC; } else if (strcmp(si_type[i], "bt") == 0) { - info->io.si_type = SI_BT; + io.si_type = SI_BT; } else { pr_warn(PFX "Interface type specified for interface %d, was invalid: %s\n", i, si_type[i]); - kfree(info); continue; } if (ports[i]) { /* An I/O port */ - info->io.addr_data = ports[i]; - info->io.addr_type = IPMI_IO_ADDR_SPACE; + io.addr_data = ports[i]; + io.addr_type = IPMI_IO_ADDR_SPACE; } else if (addrs[i]) { /* A memory port */ - info->io.addr_data = addrs[i]; - info->io.addr_type = IPMI_MEM_ADDR_SPACE; + io.addr_data = addrs[i]; + io.addr_type = IPMI_MEM_ADDR_SPACE; } else { pr_warn(PFX "Interface type specified for interface %d, but port and address were not set or set to zero.\n", i); - kfree(info); continue; } - info->io.addr = NULL; - info->io.regspacing = regspacings[i]; - if (!info->io.regspacing) - info->io.regspacing = DEFAULT_REGSPACING; - info->io.regsize = regsizes[i]; - if (!info->io.regsize) - info->io.regsize = DEFAULT_REGSIZE; - info->io.regshift = regshifts[i]; - info->io.irq = irqs[i]; - if (info->io.irq) - info->io.irq_setup = ipmi_std_irq_setup; - info->io.slave_addr = slave_addrs[i]; + io.addr = NULL; + io.regspacing = regspacings[i]; + if (!io.regspacing) + io.regspacing = DEFAULT_REGSPACING; + io.regsize = regsizes[i]; + if (!io.regsize) + io.regsize = DEFAULT_REGSIZE; + io.regshift = regshifts[i]; + io.irq = irqs[i]; + if (io.irq) + io.irq_setup = ipmi_std_irq_setup; + io.slave_addr = slave_addrs[i]; - if (!ipmi_si_add_smi(info)) { - mutex_lock(&smi_infos_lock); - if (try_smi_init(info)) - cleanup_one_si(info); - mutex_unlock(&smi_infos_lock); - ret = 0; - } else { - kfree(info); - } + ret = ipmi_si_add_smi(&io); } return ret; } @@ -2121,88 +2094,74 @@ struct SPMITable { static int try_init_spmi(struct SPMITable *spmi) { - struct smi_info *info; - int rv; + struct si_sm_io io; if (spmi->IPMIlegacy != 1) { pr_info(PFX "Bad SPMI legacy %d\n", spmi->IPMIlegacy); return -ENODEV; } - info = smi_info_alloc(); - if (!info) { - pr_err(PFX "Could not allocate SI data (3)\n"); - return -ENOMEM; - } - - info->io.addr_source = SI_SPMI; + memset(&io, 0, sizeof(io)); + io.addr_source = SI_SPMI; pr_info(PFX "probing via SPMI\n"); /* Figure out the interface type. */ switch (spmi->InterfaceType) { case 1: /* KCS */ - info->io.si_type = SI_KCS; + io.si_type = SI_KCS; break; case 2: /* SMIC */ - info->io.si_type = SI_SMIC; + io.si_type = SI_SMIC; break; case 3: /* BT */ - info->io.si_type = SI_BT; + io.si_type = SI_BT; break; case 4: /* SSIF, just ignore */ - kfree(info); return -EIO; default: pr_info(PFX "Unknown ACPI/SPMI SI type %d\n", spmi->InterfaceType); - kfree(info); return -EIO; } if (spmi->InterruptType & 1) { /* We've got a GPE interrupt. */ - info->io.irq = spmi->GPE; - info->io.irq_setup = acpi_gpe_irq_setup; + io.irq = spmi->GPE; + io.irq_setup = acpi_gpe_irq_setup; } else if (spmi->InterruptType & 2) { /* We've got an APIC/SAPIC interrupt. */ - info->io.irq = spmi->GlobalSystemInterrupt; - info->io.irq_setup = ipmi_std_irq_setup; + io.irq = spmi->GlobalSystemInterrupt; + io.irq_setup = ipmi_std_irq_setup; } else { /* Use the default interrupt setting. */ - info->io.irq = 0; - info->io.irq_setup = NULL; + io.irq = 0; + io.irq_setup = NULL; } if (spmi->addr.bit_width) { /* A (hopefully) properly formed register bit width. */ - info->io.regspacing = spmi->addr.bit_width / 8; + io.regspacing = spmi->addr.bit_width / 8; } else { - info->io.regspacing = DEFAULT_REGSPACING; + io.regspacing = DEFAULT_REGSPACING; } - info->io.regsize = info->io.regspacing; - info->io.regshift = spmi->addr.bit_offset; + io.regsize = io.regspacing; + io.regshift = spmi->addr.bit_offset; if (spmi->addr.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { - info->io.addr_type = IPMI_MEM_ADDR_SPACE; + io.addr_type = IPMI_MEM_ADDR_SPACE; } else if (spmi->addr.space_id == ACPI_ADR_SPACE_SYSTEM_IO) { - info->io.addr_type = IPMI_IO_ADDR_SPACE; + io.addr_type = IPMI_IO_ADDR_SPACE; } else { - kfree(info); pr_warn(PFX "Unknown ACPI I/O Address type\n"); return -EIO; } - info->io.addr_data = spmi->addr.address; + io.addr_data = spmi->addr.address; pr_info("ipmi_si: SPMI: %s %#lx regsize %d spacing %d irq %d\n", - (info->io.addr_type == IPMI_IO_ADDR_SPACE) ? "io" : "mem", - info->io.addr_data, info->io.regsize, info->io.regspacing, - info->io.irq); + (io.addr_type == IPMI_IO_ADDR_SPACE) ? "io" : "mem", + io.addr_data, io.regsize, io.regspacing, io.irq); - rv = ipmi_si_add_smi(info); - if (rv) - kfree(info); - - return rv; + return ipmi_si_add_smi(&io); } static void spmi_find_bmc(void) @@ -2231,36 +2190,35 @@ static void spmi_find_bmc(void) #if defined(CONFIG_DMI) || defined(CONFIG_ACPI) static struct resource * ipmi_get_info_from_resources(struct platform_device *pdev, - struct smi_info *info) + struct si_sm_io *io) { struct resource *res, *res_second; res = platform_get_resource(pdev, IORESOURCE_IO, 0); if (res) { - info->io.addr_type = IPMI_IO_ADDR_SPACE; + io->addr_type = IPMI_IO_ADDR_SPACE; } else { res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res) - info->io.addr_type = IPMI_MEM_ADDR_SPACE; + io->addr_type = IPMI_MEM_ADDR_SPACE; } if (!res) { dev_err(&pdev->dev, "no I/O or memory address\n"); return NULL; } - info->io.addr_data = res->start; + io->addr_data = res->start; - info->io.regspacing = DEFAULT_REGSPACING; + io->regspacing = DEFAULT_REGSPACING; res_second = platform_get_resource(pdev, - (info->io.addr_type == IPMI_IO_ADDR_SPACE) ? + (io->addr_type == IPMI_IO_ADDR_SPACE) ? IORESOURCE_IO : IORESOURCE_MEM, 1); if (res_second) { - if (res_second->start > info->io.addr_data) - info->io.regspacing = - res_second->start - info->io.addr_data; + if (res_second->start > io->addr_data) + io->regspacing = res_second->start - io->addr_data; } - info->io.regsize = DEFAULT_REGSIZE; - info->io.regshift = 0; + io->regsize = DEFAULT_REGSIZE; + io->regshift = 0; return res; } @@ -2270,7 +2228,7 @@ ipmi_get_info_from_resources(struct platform_device *pdev, #ifdef CONFIG_DMI static int dmi_ipmi_probe(struct platform_device *pdev) { - struct smi_info *info; + struct si_sm_io io; u8 type, slave_addr; int rv; @@ -2281,31 +2239,25 @@ static int dmi_ipmi_probe(struct platform_device *pdev) if (rv) return -ENODEV; - info = smi_info_alloc(); - if (!info) { - pr_err(PFX "Could not allocate SI data\n"); - return -ENOMEM; - } - - info->io.addr_source = SI_SMBIOS; + memset(&io, 0, sizeof(io)); + io.addr_source = SI_SMBIOS; pr_info(PFX "probing via SMBIOS\n"); switch (type) { case IPMI_DMI_TYPE_KCS: - info->io.si_type = SI_KCS; + io.si_type = SI_KCS; break; case IPMI_DMI_TYPE_SMIC: - info->io.si_type = SI_SMIC; + io.si_type = SI_SMIC; break; case IPMI_DMI_TYPE_BT: - info->io.si_type = SI_BT; + io.si_type = SI_BT; break; default: - kfree(info); return -EINVAL; } - if (!ipmi_get_info_from_resources(pdev, info)) { + if (!ipmi_get_info_from_resources(pdev, &io)) { rv = -EINVAL; goto err_free; } @@ -2313,31 +2265,28 @@ static int dmi_ipmi_probe(struct platform_device *pdev) rv = device_property_read_u8(&pdev->dev, "slave-addr", &slave_addr); if (rv) { dev_warn(&pdev->dev, "device has no slave-addr property"); - info->io.slave_addr = 0x20; + io.slave_addr = 0x20; } else { - info->io.slave_addr = slave_addr; + io.slave_addr = slave_addr; } - info->io.irq = platform_get_irq(pdev, 0); - if (info->io.irq > 0) - info->io.irq_setup = ipmi_std_irq_setup; + io.irq = platform_get_irq(pdev, 0); + if (io.irq > 0) + io.irq_setup = ipmi_std_irq_setup; else - info->io.irq = 0; + io.irq = 0; - info->io.dev = &pdev->dev; + io.dev = &pdev->dev; pr_info("ipmi_si: SMBIOS: %s %#lx regsize %d spacing %d irq %d\n", - (info->io.addr_type == IPMI_IO_ADDR_SPACE) ? "io" : "mem", - info->io.addr_data, info->io.regsize, info->io.regspacing, - info->io.irq); + (io.addr_type == IPMI_IO_ADDR_SPACE) ? "io" : "mem", + io.addr_data, io.regsize, io.regspacing, io.irq); - if (ipmi_si_add_smi(info)) - kfree(info); + ipmi_si_add_smi(&io); return 0; err_free: - kfree(info); return rv; } #else @@ -2367,30 +2316,28 @@ static void ipmi_pci_cleanup(struct si_sm_io *io) pci_disable_device(pdev); } -static int ipmi_pci_probe_regspacing(struct smi_info *info) +static int ipmi_pci_probe_regspacing(struct si_sm_io *io) { - if (info->io.si_type == SI_KCS) { + if (io->si_type == SI_KCS) { unsigned char status; int regspacing; - info->io.regsize = DEFAULT_REGSIZE; - info->io.regshift = 0; - info->io.io_size = 2; - info->handlers = &kcs_smi_handlers; + io->regsize = DEFAULT_REGSIZE; + io->regshift = 0; /* detect 1, 4, 16byte spacing */ for (regspacing = DEFAULT_REGSPACING; regspacing <= 16;) { - info->io.regspacing = regspacing; - if (info->io.io_setup(&info->io)) { - dev_err(info->io.dev, + io->regspacing = regspacing; + if (io->io_setup(io)) { + dev_err(io->dev, "Could not setup I/O space\n"); return DEFAULT_REGSPACING; } /* write invalid cmd */ - info->io.outputb(&info->io, 1, 0x10); + io->outputb(io, 1, 0x10); /* read status back */ - status = info->io.inputb(&info->io, 1); - info->io.io_cleanup(&info->io); + status = io->inputb(io, 1); + io->io_cleanup(io); if (status) return regspacing; regspacing *= 4; @@ -2404,30 +2351,26 @@ static int ipmi_pci_probe(struct pci_dev *pdev, { int rv; int class_type = pdev->class & PCI_ERMC_CLASSCODE_TYPE_MASK; - struct smi_info *info; + struct si_sm_io io; - info = smi_info_alloc(); - if (!info) - return -ENOMEM; - - info->io.addr_source = SI_PCI; + memset(&io, 0, sizeof(io)); + io.addr_source = SI_PCI; dev_info(&pdev->dev, "probing via PCI"); switch (class_type) { case PCI_ERMC_CLASSCODE_TYPE_SMIC: - info->io.si_type = SI_SMIC; + io.si_type = SI_SMIC; break; case PCI_ERMC_CLASSCODE_TYPE_KCS: - info->io.si_type = SI_KCS; + io.si_type = SI_KCS; break; case PCI_ERMC_CLASSCODE_TYPE_BT: - info->io.si_type = SI_BT; + io.si_type = SI_BT; break; default: - kfree(info); dev_info(&pdev->dev, "Unknown IPMI type: %d\n", class_type); return -ENOMEM; } @@ -2435,47 +2378,41 @@ static int ipmi_pci_probe(struct pci_dev *pdev, rv = pci_enable_device(pdev); if (rv) { dev_err(&pdev->dev, "couldn't enable PCI device\n"); - kfree(info); return rv; } - info->io.addr_source_cleanup = ipmi_pci_cleanup; - info->io.addr_source_data = pdev; + io.addr_source_cleanup = ipmi_pci_cleanup; + io.addr_source_data = pdev; if (pci_resource_flags(pdev, 0) & IORESOURCE_IO) - info->io.addr_type = IPMI_IO_ADDR_SPACE; + io.addr_type = IPMI_IO_ADDR_SPACE; else - info->io.addr_type = IPMI_MEM_ADDR_SPACE; - info->io.addr_data = pci_resource_start(pdev, 0); + io.addr_type = IPMI_MEM_ADDR_SPACE; + io.addr_data = pci_resource_start(pdev, 0); - info->io.regspacing = ipmi_pci_probe_regspacing(info); - info->io.regsize = DEFAULT_REGSIZE; - info->io.regshift = 0; + io.regspacing = ipmi_pci_probe_regspacing(&io); + io.regsize = DEFAULT_REGSIZE; + io.regshift = 0; - info->io.irq = pdev->irq; - if (info->io.irq) - info->io.irq_setup = ipmi_std_irq_setup; + io.irq = pdev->irq; + if (io.irq) + io.irq_setup = ipmi_std_irq_setup; - info->io.dev = &pdev->dev; - pci_set_drvdata(pdev, info); + io.dev = &pdev->dev; dev_info(&pdev->dev, "%pR regsize %d spacing %d irq %d\n", - &pdev->resource[0], info->io.regsize, info->io.regspacing, - info->io.irq); + &pdev->resource[0], io.regsize, io.regspacing, io.irq); - rv = ipmi_si_add_smi(info); - if (rv) { - kfree(info); + rv = ipmi_si_add_smi(&io); + if (rv) pci_disable_device(pdev); - } return rv; } static void ipmi_pci_remove(struct pci_dev *pdev) { - struct smi_info *info = pci_get_drvdata(pdev); - cleanup_one_si(info); + ipmi_si_remove_by_dev(&pdev->dev); } static const struct pci_device_id ipmi_pci_devices[] = { @@ -2508,7 +2445,7 @@ MODULE_DEVICE_TABLE(of, of_ipmi_match); static int of_ipmi_probe(struct platform_device *pdev) { const struct of_device_id *match; - struct smi_info *info; + struct si_sm_io io; struct resource resource; const __be32 *regsize, *regspacing, *regshift; struct device_node *np = pdev->dev.of_node; @@ -2548,44 +2485,29 @@ static int of_ipmi_probe(struct platform_device *pdev) return -EINVAL; } - info = smi_info_alloc(); - - if (!info) { - dev_err(&pdev->dev, - "could not allocate memory for OF probe\n"); - return -ENOMEM; - } - - info->io.si_type = (enum si_type) match->data; - info->io.addr_source = SI_DEVICETREE; - info->io.irq_setup = ipmi_std_irq_setup; + memset(&io, 0, sizeof(io)); + io.si_type = (enum si_type) match->data; + io.addr_source = SI_DEVICETREE; + io.irq_setup = ipmi_std_irq_setup; if (resource.flags & IORESOURCE_IO) - info->io.addr_type = IPMI_IO_ADDR_SPACE; + io.addr_type = IPMI_IO_ADDR_SPACE; else - info->io.addr_type = IPMI_MEM_ADDR_SPACE; + io.addr_type = IPMI_MEM_ADDR_SPACE; - info->io.addr_data = resource.start; + io.addr_data = resource.start; - info->io.regsize = regsize ? be32_to_cpup(regsize) : DEFAULT_REGSIZE; - info->io.regspacing = regspacing ? be32_to_cpup(regspacing) : DEFAULT_REGSPACING; - info->io.regshift = regshift ? be32_to_cpup(regshift) : 0; + io.regsize = regsize ? be32_to_cpup(regsize) : DEFAULT_REGSIZE; + io.regspacing = regspacing ? be32_to_cpup(regspacing) : DEFAULT_REGSPACING; + io.regshift = regshift ? be32_to_cpup(regshift) : 0; - info->io.irq = irq_of_parse_and_map(pdev->dev.of_node, 0); - info->io.dev = &pdev->dev; + io.irq = irq_of_parse_and_map(pdev->dev.of_node, 0); + io.dev = &pdev->dev; dev_dbg(&pdev->dev, "addr 0x%lx regsize %d spacing %d irq %d\n", - info->io.addr_data, info->io.regsize, info->io.regspacing, - info->io.irq); + io.addr_data, io.regsize, io.regspacing, io.irq); - dev_set_drvdata(&pdev->dev, info); - - ret = ipmi_si_add_smi(info); - if (ret) { - kfree(info); - return ret; - } - return 0; + return ipmi_si_add_smi(&io); } #else #define of_ipmi_match NULL @@ -2596,14 +2518,14 @@ static int of_ipmi_probe(struct platform_device *dev) #endif #ifdef CONFIG_ACPI -static int find_slave_address(struct smi_info *info, int slave_addr) +static int find_slave_address(struct si_sm_io *io, int slave_addr) { #ifdef CONFIG_IPMI_DMI_DECODE if (!slave_addr) { int type = -1; u32 flags = IORESOURCE_IO; - switch (info->io.si_type) { + switch (io->si_type) { case SI_KCS: type = IPMI_DMI_TYPE_KCS; break; @@ -2615,11 +2537,11 @@ static int find_slave_address(struct smi_info *info, int slave_addr) break; } - if (info->io.addr_type == IPMI_MEM_ADDR_SPACE) + if (io->addr_type == IPMI_MEM_ADDR_SPACE) flags = IORESOURCE_MEM; slave_addr = ipmi_dmi_get_slave_addr(type, flags, - info->io.addr_data); + io->addr_data); } #endif @@ -2628,7 +2550,7 @@ static int find_slave_address(struct smi_info *info, int slave_addr) static int acpi_ipmi_probe(struct platform_device *pdev) { - struct smi_info *info; + struct si_sm_io io; acpi_handle handle; acpi_status status; unsigned long long tmp; @@ -2642,14 +2564,11 @@ static int acpi_ipmi_probe(struct platform_device *pdev) if (!handle) return -ENODEV; - info = smi_info_alloc(); - if (!info) - return -ENOMEM; - - info->io.addr_source = SI_ACPI; + memset(&io, 0, sizeof(io)); + io.addr_source = SI_ACPI; dev_info(&pdev->dev, PFX "probing via ACPI\n"); - info->addr_info.acpi_info.acpi_handle = handle; + io.addr_info.acpi_info.acpi_handle = handle; /* _IFT tells us the interface type: KCS, BT, etc */ status = acpi_evaluate_integer(handle, "_IFT", NULL, &tmp); @@ -2661,13 +2580,13 @@ static int acpi_ipmi_probe(struct platform_device *pdev) switch (tmp) { case 1: - info->io.si_type = SI_KCS; + io.si_type = SI_KCS; break; case 2: - info->io.si_type = SI_SMIC; + io.si_type = SI_SMIC; break; case 3: - info->io.si_type = SI_BT; + io.si_type = SI_BT; break; case 4: /* SSIF, just ignore */ rv = -ENODEV; @@ -2677,7 +2596,7 @@ static int acpi_ipmi_probe(struct platform_device *pdev) goto err_free; } - res = ipmi_get_info_from_resources(pdev, info); + res = ipmi_get_info_from_resources(pdev, &io); if (!res) { rv = -EINVAL; goto err_free; @@ -2686,34 +2605,27 @@ static int acpi_ipmi_probe(struct platform_device *pdev) /* If _GPE exists, use it; otherwise use standard interrupts */ status = acpi_evaluate_integer(handle, "_GPE", NULL, &tmp); if (ACPI_SUCCESS(status)) { - info->io.irq = tmp; - info->io.irq_setup = acpi_gpe_irq_setup; + io.irq = tmp; + io.irq_setup = acpi_gpe_irq_setup; } else { int irq = platform_get_irq(pdev, 0); if (irq > 0) { - info->io.irq = irq; - info->io.irq_setup = ipmi_std_irq_setup; + io.irq = irq; + io.irq_setup = ipmi_std_irq_setup; } } - info->io.slave_addr = find_slave_address(info, info->io.slave_addr); + io.slave_addr = find_slave_address(&io, io.slave_addr); - info->io.dev = &pdev->dev; - platform_set_drvdata(pdev, info); + io.dev = &pdev->dev; - dev_info(info->io.dev, "%pR regsize %d spacing %d irq %d\n", - res, info->io.regsize, info->io.regspacing, - info->io.irq); + dev_info(io.dev, "%pR regsize %d spacing %d irq %d\n", + res, io.regsize, io.regspacing, io.irq); - rv = ipmi_si_add_smi(info); - if (rv) - kfree(info); - - return rv; + return ipmi_si_add_smi(&io); err_free: - kfree(info); return rv; } @@ -2742,10 +2654,7 @@ static int ipmi_probe(struct platform_device *pdev) static int ipmi_remove(struct platform_device *pdev) { - struct smi_info *info = dev_get_drvdata(&pdev->dev); - - cleanup_one_si(info); - return 0; + return ipmi_si_remove_by_dev(&pdev->dev); } static struct platform_driver ipmi_driver = { @@ -2761,45 +2670,27 @@ static struct platform_driver ipmi_driver = { #ifdef CONFIG_PARISC static int __init ipmi_parisc_probe(struct parisc_device *dev) { - struct smi_info *info; - int rv; + struct si_sm_io io; - info = smi_info_alloc(); + io.si_type = SI_KCS; + io.addr_source = SI_DEVICETREE; + io.addr_type = IPMI_MEM_ADDR_SPACE; + io.addr_data = dev->hpa.start; + io.regsize = 1; + io.regspacing = 1; + io.regshift = 0; + io.irq = 0; /* no interrupt */ + io.irq_setup = NULL; + io.dev = &dev->dev; - if (!info) { - dev_err(&dev->dev, - "could not allocate memory for PARISC probe\n"); - return -ENOMEM; - } + dev_dbg(&dev->dev, "addr 0x%lx\n", io.addr_data); - info->io.si_type = SI_KCS; - info->io.addr_source = SI_DEVICETREE; - info->io.addr_type = IPMI_MEM_ADDR_SPACE; - info->io.addr_data = dev->hpa.start; - info->io.regsize = 1; - info->io.regspacing = 1; - info->io.regshift = 0; - info->io.irq = 0; /* no interrupt */ - info->io.irq_setup = NULL; - info->io.dev = &dev->dev; - - dev_dbg(&dev->dev, "addr 0x%lx\n", info->io.addr_data); - - dev_set_drvdata(&dev->dev, info); - - rv = ipmi_si_add_smi(info); - if (rv) { - kfree(info); - return rv; - } - - return 0; + return ipmi_si_add_smi(&io); } static int __exit ipmi_parisc_remove(struct parisc_device *dev) { - cleanup_one_si(dev_get_drvdata(&dev->dev)); - return 0; + return ipmi_si_remove_by_dev(&pdev->dev); } static const struct parisc_device_id ipmi_parisc_tbl[] __initconst = { @@ -3393,21 +3284,27 @@ static struct smi_info *find_dup_si(struct smi_info *info) return NULL; } -int ipmi_si_add_smi(struct smi_info *new_smi) +int ipmi_si_add_smi(struct si_sm_io *io) { int rv = 0; - struct smi_info *dup; + struct smi_info *new_smi, *dup; - if (!new_smi->io.io_setup) { - if (new_smi->io.addr_type == IPMI_IO_ADDR_SPACE) { - new_smi->io.io_setup = port_setup; - } else if (new_smi->io.addr_type == IPMI_MEM_ADDR_SPACE) { - new_smi->io.io_setup = mem_setup; + if (!io->io_setup) { + if (io->addr_type == IPMI_IO_ADDR_SPACE) { + io->io_setup = port_setup; + } else if (io->addr_type == IPMI_MEM_ADDR_SPACE) { + io->io_setup = mem_setup; } else { return -EINVAL; } } + new_smi = smi_info_alloc(); + if (!new_smi) + return -ENOMEM; + + new_smi->io = *io; + mutex_lock(&smi_infos_lock); dup = find_dup_si(new_smi); if (dup) { @@ -3439,6 +3336,14 @@ int ipmi_si_add_smi(struct smi_info *new_smi) list_add_tail(&new_smi->link, &smi_infos); + if (initialized) { + rv = try_smi_init(new_smi); + if (rv) { + mutex_unlock(&smi_infos_lock); + cleanup_one_si(new_smi); + return rv; + } + } out_err: mutex_unlock(&smi_infos_lock); return rv; @@ -3695,7 +3600,6 @@ static int init_ipmi_si(void) if (initialized) return 0; - initialized = 1; if (si_tryplatform) { rv = platform_driver_register(&ipmi_driver); @@ -3764,10 +3668,8 @@ static int init_ipmi_si(void) } /* type will only have been set if we successfully registered an si */ - if (type) { - mutex_unlock(&smi_infos_lock); - return 0; - } + if (type) + goto skip_fallback_noirq; /* Fall back to the preferred device */ @@ -3778,6 +3680,9 @@ static int init_ipmi_si(void) } } } + +skip_fallback_noirq: + initialized = 1; mutex_unlock(&smi_infos_lock); if (type) @@ -3814,9 +3719,6 @@ static void cleanup_one_si(struct smi_info *to_clean) } } - if (to_clean->io.dev) - dev_set_drvdata(to_clean->io.dev, NULL); - list_del(&to_clean->link); /* @@ -3859,6 +3761,24 @@ static void cleanup_one_si(struct smi_info *to_clean) kfree(to_clean); } +int ipmi_si_remove_by_dev(struct device *dev) +{ + struct smi_info *e; + int rv = -ENOENT; + + mutex_lock(&smi_infos_lock); + list_for_each_entry(e, &smi_infos, link) { + if (e->io.dev == dev) { + cleanup_one_si(e); + rv = 0; + break; + } + } + mutex_unlock(&smi_infos_lock); + + return rv; +} + static void cleanup_ipmi_si(void) { struct smi_info *e, *tmp_e; diff --git a/drivers/char/ipmi/ipmi_si_sm.h b/drivers/char/ipmi/ipmi_si_sm.h index 9df77c664908..fbf5bfccde2e 100644 --- a/drivers/char/ipmi/ipmi_si_sm.h +++ b/drivers/char/ipmi/ipmi_si_sm.h @@ -70,6 +70,7 @@ struct si_sm_io { enum ipmi_addr_src addr_source; /* ACPI, PCI, SMBIOS, hardcode, etc. */ void (*addr_source_cleanup)(struct si_sm_io *io); void *addr_source_data; + union ipmi_smi_info_union addr_info; int (*io_setup)(struct si_sm_io *info); void (*io_cleanup)(struct si_sm_io *info); From 44814ec982d2905d50fe4d0cdaf693b76afe7f64 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Tue, 12 Sep 2017 22:28:49 -0500 Subject: [PATCH 32/48] ipmi_si: Move the hotmod handling to another file. Signed-off-by: Corey Minyard --- drivers/char/ipmi/Makefile | 3 +- drivers/char/ipmi/ipmi_si.h | 2 + drivers/char/ipmi/ipmi_si_hotmod.c | 242 ++++++++++++++++++++++++++ drivers/char/ipmi/ipmi_si_intf.c | 261 ++--------------------------- 4 files changed, 264 insertions(+), 244 deletions(-) create mode 100644 drivers/char/ipmi/ipmi_si_hotmod.c diff --git a/drivers/char/ipmi/Makefile b/drivers/char/ipmi/Makefile index eefb0b301e83..61c7d5d32f4a 100644 --- a/drivers/char/ipmi/Makefile +++ b/drivers/char/ipmi/Makefile @@ -2,7 +2,8 @@ # Makefile for the ipmi drivers. # -ipmi_si-y := ipmi_si_intf.o ipmi_kcs_sm.o ipmi_smic_sm.o ipmi_bt_sm.o +ipmi_si-y := ipmi_si_intf.o ipmi_kcs_sm.o ipmi_smic_sm.o ipmi_bt_sm.o \ + ipmi_si_hotmod.o obj-$(CONFIG_IPMI_HANDLER) += ipmi_msghandler.o obj-$(CONFIG_IPMI_DEVICE_INTERFACE) += ipmi_devintf.o diff --git a/drivers/char/ipmi/ipmi_si.h b/drivers/char/ipmi/ipmi_si.h index 9573b35d73af..4ceb5ac3ad98 100644 --- a/drivers/char/ipmi/ipmi_si.h +++ b/drivers/char/ipmi/ipmi_si.h @@ -20,3 +20,5 @@ void ipmi_irq_start_cleanup(struct si_sm_io *io); int ipmi_std_irq_setup(struct si_sm_io *io); void ipmi_irq_finish_setup(struct si_sm_io *io); int ipmi_si_remove_by_dev(struct device *dev); +void ipmi_si_remove_by_data(int addr_space, enum si_type si_type, + unsigned long addr); diff --git a/drivers/char/ipmi/ipmi_si_hotmod.c b/drivers/char/ipmi/ipmi_si_hotmod.c new file mode 100644 index 000000000000..da5716159974 --- /dev/null +++ b/drivers/char/ipmi/ipmi_si_hotmod.c @@ -0,0 +1,242 @@ +/* + * ipmi_si_hotmod.c + * + * Handling for dynamically adding/removing IPMI devices through + * a module parameter (and thus sysfs). + */ +#include +#include +#include "ipmi_si.h" + +#define PFX "ipmi_hotmod: " + +static int hotmod_handler(const char *val, struct kernel_param *kp); + +module_param_call(hotmod, hotmod_handler, NULL, NULL, 0200); +MODULE_PARM_DESC(hotmod, "Add and remove interfaces. See" + " Documentation/IPMI.txt in the kernel sources for the" + " gory details."); + +/* + * Parms come in as [:op2[:op3...]]. ops are: + * add|remove,kcs|bt|smic,mem|i/o,
[,[,[,...]]] + * Options are: + * rsp= + * rsi= + * rsh= + * irq= + * ipmb= + */ +enum hotmod_op { HM_ADD, HM_REMOVE }; +struct hotmod_vals { + const char *name; + const int val; +}; + +static const struct hotmod_vals hotmod_ops[] = { + { "add", HM_ADD }, + { "remove", HM_REMOVE }, + { NULL } +}; + +static const struct hotmod_vals hotmod_si[] = { + { "kcs", SI_KCS }, + { "smic", SI_SMIC }, + { "bt", SI_BT }, + { NULL } +}; + +static const struct hotmod_vals hotmod_as[] = { + { "mem", IPMI_MEM_ADDR_SPACE }, + { "i/o", IPMI_IO_ADDR_SPACE }, + { NULL } +}; + +static int parse_str(const struct hotmod_vals *v, int *val, char *name, + char **curr) +{ + char *s; + int i; + + s = strchr(*curr, ','); + if (!s) { + pr_warn(PFX "No hotmod %s given.\n", name); + return -EINVAL; + } + *s = '\0'; + s++; + for (i = 0; v[i].name; i++) { + if (strcmp(*curr, v[i].name) == 0) { + *val = v[i].val; + *curr = s; + return 0; + } + } + + pr_warn(PFX "Invalid hotmod %s '%s'\n", name, *curr); + return -EINVAL; +} + +static int check_hotmod_int_op(const char *curr, const char *option, + const char *name, int *val) +{ + char *n; + + if (strcmp(curr, name) == 0) { + if (!option) { + pr_warn(PFX "No option given for '%s'\n", curr); + return -EINVAL; + } + *val = simple_strtoul(option, &n, 0); + if ((*n != '\0') || (*option == '\0')) { + pr_warn(PFX "Bad option given for '%s'\n", curr); + return -EINVAL; + } + return 1; + } + return 0; +} + +static int hotmod_handler(const char *val, struct kernel_param *kp) +{ + char *str = kstrdup(val, GFP_KERNEL); + int rv; + char *next, *curr, *s, *n, *o; + enum hotmod_op op; + enum si_type si_type; + int addr_space; + unsigned long addr; + int regspacing; + int regsize; + int regshift; + int irq; + int ipmb; + int ival; + int len; + + if (!str) + return -ENOMEM; + + /* Kill any trailing spaces, as we can get a "\n" from echo. */ + len = strlen(str); + ival = len - 1; + while ((ival >= 0) && isspace(str[ival])) { + str[ival] = '\0'; + ival--; + } + + for (curr = str; curr; curr = next) { + regspacing = 1; + regsize = 1; + regshift = 0; + irq = 0; + ipmb = 0; /* Choose the default if not specified */ + + next = strchr(curr, ':'); + if (next) { + *next = '\0'; + next++; + } + + rv = parse_str(hotmod_ops, &ival, "operation", &curr); + if (rv) + break; + op = ival; + + rv = parse_str(hotmod_si, &ival, "interface type", &curr); + if (rv) + break; + si_type = ival; + + rv = parse_str(hotmod_as, &addr_space, "address space", &curr); + if (rv) + break; + + s = strchr(curr, ','); + if (s) { + *s = '\0'; + s++; + } + addr = simple_strtoul(curr, &n, 0); + if ((*n != '\0') || (*curr == '\0')) { + pr_warn(PFX "Invalid hotmod address '%s'\n", curr); + break; + } + + while (s) { + curr = s; + s = strchr(curr, ','); + if (s) { + *s = '\0'; + s++; + } + o = strchr(curr, '='); + if (o) { + *o = '\0'; + o++; + } + rv = check_hotmod_int_op(curr, o, "rsp", ®spacing); + if (rv < 0) + goto out; + else if (rv) + continue; + rv = check_hotmod_int_op(curr, o, "rsi", ®size); + if (rv < 0) + goto out; + else if (rv) + continue; + rv = check_hotmod_int_op(curr, o, "rsh", ®shift); + if (rv < 0) + goto out; + else if (rv) + continue; + rv = check_hotmod_int_op(curr, o, "irq", &irq); + if (rv < 0) + goto out; + else if (rv) + continue; + rv = check_hotmod_int_op(curr, o, "ipmb", &ipmb); + if (rv < 0) + goto out; + else if (rv) + continue; + + rv = -EINVAL; + pr_warn(PFX "Invalid hotmod option '%s'\n", curr); + goto out; + } + + if (op == HM_ADD) { + struct si_sm_io io; + + memset(&io, 0, sizeof(io)); + io.addr_source = SI_HOTMOD; + io.si_type = si_type; + io.addr_data = addr; + io.addr_type = addr_space; + + io.addr = NULL; + io.regspacing = regspacing; + if (!io.regspacing) + io.regspacing = DEFAULT_REGSPACING; + io.regsize = regsize; + if (!io.regsize) + io.regsize = DEFAULT_REGSIZE; + io.regshift = regshift; + io.irq = irq; + if (io.irq) + io.irq_setup = ipmi_std_irq_setup; + io.slave_addr = ipmb; + + rv = ipmi_si_add_smi(&io); + if (rv) + goto out; + } else { + ipmi_si_remove_by_data(addr_space, si_type, addr); + } + } + rv = len; +out: + kfree(str); + return rv; +} diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 6c2e14af8321..02e263b2152a 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -1310,13 +1310,6 @@ static unsigned int num_slave_addrs; static const char * const addr_space_to_str[] = { "i/o", "mem" }; -static int hotmod_handler(const char *val, struct kernel_param *kp); - -module_param_call(hotmod, hotmod_handler, NULL, NULL, 0200); -MODULE_PARM_DESC(hotmod, "Add and remove interfaces. See" - " Documentation/IPMI.txt in the kernel sources for the" - " gory details."); - #ifdef CONFIG_ACPI module_param_named(tryacpi, si_tryacpi, bool, 0); MODULE_PARM_DESC(tryacpi, "Setting this to zero will disable the" @@ -1689,86 +1682,6 @@ static int mem_setup(struct si_sm_io *io) return 0; } -/* - * Parms come in as [:op2[:op3...]]. ops are: - * add|remove,kcs|bt|smic,mem|i/o,
[,[,[,...]]] - * Options are: - * rsp= - * rsi= - * rsh= - * irq= - * ipmb= - */ -enum hotmod_op { HM_ADD, HM_REMOVE }; -struct hotmod_vals { - const char *name; - const int val; -}; - -static const struct hotmod_vals hotmod_ops[] = { - { "add", HM_ADD }, - { "remove", HM_REMOVE }, - { NULL } -}; - -static const struct hotmod_vals hotmod_si[] = { - { "kcs", SI_KCS }, - { "smic", SI_SMIC }, - { "bt", SI_BT }, - { NULL } -}; - -static const struct hotmod_vals hotmod_as[] = { - { "mem", IPMI_MEM_ADDR_SPACE }, - { "i/o", IPMI_IO_ADDR_SPACE }, - { NULL } -}; - -static int parse_str(const struct hotmod_vals *v, int *val, char *name, - char **curr) -{ - char *s; - int i; - - s = strchr(*curr, ','); - if (!s) { - pr_warn(PFX "No hotmod %s given.\n", name); - return -EINVAL; - } - *s = '\0'; - s++; - for (i = 0; v[i].name; i++) { - if (strcmp(*curr, v[i].name) == 0) { - *val = v[i].val; - *curr = s; - return 0; - } - } - - pr_warn(PFX "Invalid hotmod %s '%s'\n", name, *curr); - return -EINVAL; -} - -static int check_hotmod_int_op(const char *curr, const char *option, - const char *name, int *val) -{ - char *n; - - if (strcmp(curr, name) == 0) { - if (!option) { - pr_warn(PFX "No option given for '%s'\n", curr); - return -EINVAL; - } - *val = simple_strtoul(option, &n, 0); - if ((*n != '\0') || (*option == '\0')) { - pr_warn(PFX "Bad option given for '%s'\n", curr); - return -EINVAL; - } - return 1; - } - return 0; -} - static struct smi_info *smi_info_alloc(void) { struct smi_info *info = kzalloc(sizeof(*info), GFP_KERNEL); @@ -1778,162 +1691,6 @@ static struct smi_info *smi_info_alloc(void) return info; } -static int hotmod_handler(const char *val, struct kernel_param *kp) -{ - char *str = kstrdup(val, GFP_KERNEL); - int rv; - char *next, *curr, *s, *n, *o; - enum hotmod_op op; - enum si_type si_type; - int addr_space; - unsigned long addr; - int regspacing; - int regsize; - int regshift; - int irq; - int ipmb; - int ival; - int len; - - if (!str) - return -ENOMEM; - - /* Kill any trailing spaces, as we can get a "\n" from echo. */ - len = strlen(str); - ival = len - 1; - while ((ival >= 0) && isspace(str[ival])) { - str[ival] = '\0'; - ival--; - } - - for (curr = str; curr; curr = next) { - regspacing = 1; - regsize = 1; - regshift = 0; - irq = 0; - ipmb = 0; /* Choose the default if not specified */ - - next = strchr(curr, ':'); - if (next) { - *next = '\0'; - next++; - } - - rv = parse_str(hotmod_ops, &ival, "operation", &curr); - if (rv) - break; - op = ival; - - rv = parse_str(hotmod_si, &ival, "interface type", &curr); - if (rv) - break; - si_type = ival; - - rv = parse_str(hotmod_as, &addr_space, "address space", &curr); - if (rv) - break; - - s = strchr(curr, ','); - if (s) { - *s = '\0'; - s++; - } - addr = simple_strtoul(curr, &n, 0); - if ((*n != '\0') || (*curr == '\0')) { - pr_warn(PFX "Invalid hotmod address '%s'\n", curr); - break; - } - - while (s) { - curr = s; - s = strchr(curr, ','); - if (s) { - *s = '\0'; - s++; - } - o = strchr(curr, '='); - if (o) { - *o = '\0'; - o++; - } - rv = check_hotmod_int_op(curr, o, "rsp", ®spacing); - if (rv < 0) - goto out; - else if (rv) - continue; - rv = check_hotmod_int_op(curr, o, "rsi", ®size); - if (rv < 0) - goto out; - else if (rv) - continue; - rv = check_hotmod_int_op(curr, o, "rsh", ®shift); - if (rv < 0) - goto out; - else if (rv) - continue; - rv = check_hotmod_int_op(curr, o, "irq", &irq); - if (rv < 0) - goto out; - else if (rv) - continue; - rv = check_hotmod_int_op(curr, o, "ipmb", &ipmb); - if (rv < 0) - goto out; - else if (rv) - continue; - - rv = -EINVAL; - pr_warn(PFX "Invalid hotmod option '%s'\n", curr); - goto out; - } - - if (op == HM_ADD) { - struct si_sm_io io; - - memset(&io, 0, sizeof(io)); - io.addr_source = SI_HOTMOD; - io.si_type = si_type; - io.addr_data = addr; - io.addr_type = addr_space; - - io.addr = NULL; - io.regspacing = regspacing; - if (!io.regspacing) - io.regspacing = DEFAULT_REGSPACING; - io.regsize = regsize; - if (!io.regsize) - io.regsize = DEFAULT_REGSIZE; - io.regshift = regshift; - io.irq = irq; - if (io.irq) - io.irq_setup = ipmi_std_irq_setup; - io.slave_addr = ipmb; - - rv = ipmi_si_add_smi(&io); - if (rv) - goto out; - } else { - /* remove */ - struct smi_info *e, *tmp_e; - - mutex_lock(&smi_infos_lock); - list_for_each_entry_safe(e, tmp_e, &smi_infos, link) { - if (e->io.addr_type != addr_space) - continue; - if (e->io.si_type != si_type) - continue; - if (e->io.addr_data == addr) - cleanup_one_si(e); - } - mutex_unlock(&smi_infos_lock); - } - } - rv = len; -out: - kfree(str); - return rv; -} - static int hardcode_find_bmc(void) { int ret = -ENODEV; @@ -3779,6 +3536,24 @@ int ipmi_si_remove_by_dev(struct device *dev) return rv; } +void ipmi_si_remove_by_data(int addr_space, enum si_type si_type, + unsigned long addr) +{ + /* remove */ + struct smi_info *e, *tmp_e; + + mutex_lock(&smi_infos_lock); + list_for_each_entry_safe(e, tmp_e, &smi_infos, link) { + if (e->io.addr_type != addr_space) + continue; + if (e->io.si_type != si_type) + continue; + if (e->io.addr_data == addr) + cleanup_one_si(e); + } + mutex_unlock(&smi_infos_lock); +} + static void cleanup_ipmi_si(void) { struct smi_info *e, *tmp_e; From 7a4533087ccbf736396bcbf816e0e45266c4313b Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Tue, 12 Sep 2017 22:46:29 -0500 Subject: [PATCH 33/48] ipmi_si: Move hardcode handling to a separate file. Signed-off-by: Corey Minyard --- drivers/char/ipmi/Makefile | 2 +- drivers/char/ipmi/ipmi_si.h | 1 + drivers/char/ipmi/ipmi_si_hardcode.c | 146 +++++++++++++++++++++++++ drivers/char/ipmi/ipmi_si_intf.c | 152 ++------------------------- 4 files changed, 154 insertions(+), 147 deletions(-) create mode 100644 drivers/char/ipmi/ipmi_si_hardcode.c diff --git a/drivers/char/ipmi/Makefile b/drivers/char/ipmi/Makefile index 61c7d5d32f4a..ebd728497b23 100644 --- a/drivers/char/ipmi/Makefile +++ b/drivers/char/ipmi/Makefile @@ -3,7 +3,7 @@ # ipmi_si-y := ipmi_si_intf.o ipmi_kcs_sm.o ipmi_smic_sm.o ipmi_bt_sm.o \ - ipmi_si_hotmod.o + ipmi_si_hotmod.o ipmi_si_hardcode.o obj-$(CONFIG_IPMI_HANDLER) += ipmi_msghandler.o obj-$(CONFIG_IPMI_DEVICE_INTERFACE) += ipmi_devintf.o diff --git a/drivers/char/ipmi/ipmi_si.h b/drivers/char/ipmi/ipmi_si.h index 4ceb5ac3ad98..1dbd58afc2d7 100644 --- a/drivers/char/ipmi/ipmi_si.h +++ b/drivers/char/ipmi/ipmi_si.h @@ -22,3 +22,4 @@ void ipmi_irq_finish_setup(struct si_sm_io *io); int ipmi_si_remove_by_dev(struct device *dev); void ipmi_si_remove_by_data(int addr_space, enum si_type si_type, unsigned long addr); +int ipmi_si_hardcode_find_bmc(void); diff --git a/drivers/char/ipmi/ipmi_si_hardcode.c b/drivers/char/ipmi/ipmi_si_hardcode.c new file mode 100644 index 000000000000..fa9a4780de36 --- /dev/null +++ b/drivers/char/ipmi/ipmi_si_hardcode.c @@ -0,0 +1,146 @@ + +#include +#include "ipmi_si.h" + +#define PFX "ipmi_hardcode: " +/* + * There can be 4 IO ports passed in (with or without IRQs), 4 addresses, + * a default IO port, and 1 ACPI/SPMI address. That sets SI_MAX_DRIVERS. + */ + +#define SI_MAX_PARMS 4 + +static char *si_type[SI_MAX_PARMS]; +#define MAX_SI_TYPE_STR 30 +static char si_type_str[MAX_SI_TYPE_STR]; +static unsigned long addrs[SI_MAX_PARMS]; +static unsigned int num_addrs; +static unsigned int ports[SI_MAX_PARMS]; +static unsigned int num_ports; +static int irqs[SI_MAX_PARMS]; +static unsigned int num_irqs; +static int regspacings[SI_MAX_PARMS]; +static unsigned int num_regspacings; +static int regsizes[SI_MAX_PARMS]; +static unsigned int num_regsizes; +static int regshifts[SI_MAX_PARMS]; +static unsigned int num_regshifts; +static int slave_addrs[SI_MAX_PARMS]; /* Leaving 0 chooses the default value */ +static unsigned int num_slave_addrs; + +module_param_string(type, si_type_str, MAX_SI_TYPE_STR, 0); +MODULE_PARM_DESC(type, "Defines the type of each interface, each" + " interface separated by commas. The types are 'kcs'," + " 'smic', and 'bt'. For example si_type=kcs,bt will set" + " the first interface to kcs and the second to bt"); +module_param_hw_array(addrs, ulong, iomem, &num_addrs, 0); +MODULE_PARM_DESC(addrs, "Sets the memory address of each interface, the" + " addresses separated by commas. Only use if an interface" + " is in memory. Otherwise, set it to zero or leave" + " it blank."); +module_param_hw_array(ports, uint, ioport, &num_ports, 0); +MODULE_PARM_DESC(ports, "Sets the port address of each interface, the" + " addresses separated by commas. Only use if an interface" + " is a port. Otherwise, set it to zero or leave" + " it blank."); +module_param_hw_array(irqs, int, irq, &num_irqs, 0); +MODULE_PARM_DESC(irqs, "Sets the interrupt of each interface, the" + " addresses separated by commas. Only use if an interface" + " has an interrupt. Otherwise, set it to zero or leave" + " it blank."); +module_param_hw_array(regspacings, int, other, &num_regspacings, 0); +MODULE_PARM_DESC(regspacings, "The number of bytes between the start address" + " and each successive register used by the interface. For" + " instance, if the start address is 0xca2 and the spacing" + " is 2, then the second address is at 0xca4. Defaults" + " to 1."); +module_param_hw_array(regsizes, int, other, &num_regsizes, 0); +MODULE_PARM_DESC(regsizes, "The size of the specific IPMI register in bytes." + " This should generally be 1, 2, 4, or 8 for an 8-bit," + " 16-bit, 32-bit, or 64-bit register. Use this if you" + " the 8-bit IPMI register has to be read from a larger" + " register."); +module_param_hw_array(regshifts, int, other, &num_regshifts, 0); +MODULE_PARM_DESC(regshifts, "The amount to shift the data read from the." + " IPMI register, in bits. For instance, if the data" + " is read from a 32-bit word and the IPMI data is in" + " bit 8-15, then the shift would be 8"); +module_param_hw_array(slave_addrs, int, other, &num_slave_addrs, 0); +MODULE_PARM_DESC(slave_addrs, "Set the default IPMB slave address for" + " the controller. Normally this is 0x20, but can be" + " overridden by this parm. This is an array indexed" + " by interface number."); + +int ipmi_si_hardcode_find_bmc(void) +{ + int ret = -ENODEV; + int i; + struct si_sm_io io; + char *str; + + /* Parse out the si_type string into its components. */ + str = si_type_str; + if (*str != '\0') { + for (i = 0; (i < SI_MAX_PARMS) && (*str != '\0'); i++) { + si_type[i] = str; + str = strchr(str, ','); + if (str) { + *str = '\0'; + str++; + } else { + break; + } + } + } + + memset(&io, 0, sizeof(io)); + for (i = 0; i < SI_MAX_PARMS; i++) { + if (!ports[i] && !addrs[i]) + continue; + + io.addr_source = SI_HARDCODED; + pr_info(PFX "probing via hardcoded address\n"); + + if (!si_type[i] || strcmp(si_type[i], "kcs") == 0) { + io.si_type = SI_KCS; + } else if (strcmp(si_type[i], "smic") == 0) { + io.si_type = SI_SMIC; + } else if (strcmp(si_type[i], "bt") == 0) { + io.si_type = SI_BT; + } else { + pr_warn(PFX "Interface type specified for interface %d, was invalid: %s\n", + i, si_type[i]); + continue; + } + + if (ports[i]) { + /* An I/O port */ + io.addr_data = ports[i]; + io.addr_type = IPMI_IO_ADDR_SPACE; + } else if (addrs[i]) { + /* A memory port */ + io.addr_data = addrs[i]; + io.addr_type = IPMI_MEM_ADDR_SPACE; + } else { + pr_warn(PFX "Interface type specified for interface %d, but port and address were not set or set to zero.\n", + i); + continue; + } + + io.addr = NULL; + io.regspacing = regspacings[i]; + if (!io.regspacing) + io.regspacing = DEFAULT_REGSPACING; + io.regsize = regsizes[i]; + if (!io.regsize) + io.regsize = DEFAULT_REGSIZE; + io.regshift = regshifts[i]; + io.irq = irqs[i]; + if (io.irq) + io.irq_setup = ipmi_std_irq_setup; + io.slave_addr = slave_addrs[i]; + + ret = ipmi_si_add_smi(&io); + } + return ret; +} diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 02e263b2152a..58f0ebbcd342 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -291,9 +291,8 @@ struct smi_info { #define smi_get_stat(smi, stat) \ ((unsigned int) atomic_read(&(smi)->stats[SI_STAT_ ## stat])) -#define SI_MAX_PARMS 4 - -static int force_kipmid[SI_MAX_PARMS]; +#define IPMI_MAX_INTFS 4 +static int force_kipmid[IPMI_MAX_INTFS]; static int num_force_kipmid; #ifdef CONFIG_PCI static bool pci_registered; @@ -302,7 +301,7 @@ static bool pci_registered; static bool parisc_registered; #endif -static unsigned int kipmid_max_busy_us[SI_MAX_PARMS]; +static unsigned int kipmid_max_busy_us[IPMI_MAX_INTFS]; static int num_max_busy_us; static bool unload_when_empty = true; @@ -1271,11 +1270,6 @@ static const struct ipmi_smi_handlers handlers = { .poll = poll, }; -/* - * There can be 4 IO ports passed in (with or without IRQs), 4 addresses, - * a default IO port, and 1 ACPI/SPMI address. That sets SI_MAX_DRIVERS. - */ - static LIST_HEAD(smi_infos); static DEFINE_MUTEX(smi_infos_lock); static int smi_num; /* Used to sequence the SMIs */ @@ -1290,23 +1284,6 @@ static bool si_tryplatform = true; #ifdef CONFIG_PCI static bool si_trypci = true; #endif -static char *si_type[SI_MAX_PARMS]; -#define MAX_SI_TYPE_STR 30 -static char si_type_str[MAX_SI_TYPE_STR]; -static unsigned long addrs[SI_MAX_PARMS]; -static unsigned int num_addrs; -static unsigned int ports[SI_MAX_PARMS]; -static unsigned int num_ports; -static int irqs[SI_MAX_PARMS]; -static unsigned int num_irqs; -static int regspacings[SI_MAX_PARMS]; -static unsigned int num_regspacings; -static int regsizes[SI_MAX_PARMS]; -static unsigned int num_regsizes; -static int regshifts[SI_MAX_PARMS]; -static unsigned int num_regshifts; -static int slave_addrs[SI_MAX_PARMS]; /* Leaving 0 chooses the default value */ -static unsigned int num_slave_addrs; static const char * const addr_space_to_str[] = { "i/o", "mem" }; @@ -1329,48 +1306,6 @@ module_param_named(trypci, si_trypci, bool, 0); MODULE_PARM_DESC(trypci, "Setting this to zero will disable the" " default scan of the interfaces identified via pci"); #endif -module_param_string(type, si_type_str, MAX_SI_TYPE_STR, 0); -MODULE_PARM_DESC(type, "Defines the type of each interface, each" - " interface separated by commas. The types are 'kcs'," - " 'smic', and 'bt'. For example si_type=kcs,bt will set" - " the first interface to kcs and the second to bt"); -module_param_hw_array(addrs, ulong, iomem, &num_addrs, 0); -MODULE_PARM_DESC(addrs, "Sets the memory address of each interface, the" - " addresses separated by commas. Only use if an interface" - " is in memory. Otherwise, set it to zero or leave" - " it blank."); -module_param_hw_array(ports, uint, ioport, &num_ports, 0); -MODULE_PARM_DESC(ports, "Sets the port address of each interface, the" - " addresses separated by commas. Only use if an interface" - " is a port. Otherwise, set it to zero or leave" - " it blank."); -module_param_hw_array(irqs, int, irq, &num_irqs, 0); -MODULE_PARM_DESC(irqs, "Sets the interrupt of each interface, the" - " addresses separated by commas. Only use if an interface" - " has an interrupt. Otherwise, set it to zero or leave" - " it blank."); -module_param_hw_array(regspacings, int, other, &num_regspacings, 0); -MODULE_PARM_DESC(regspacings, "The number of bytes between the start address" - " and each successive register used by the interface. For" - " instance, if the start address is 0xca2 and the spacing" - " is 2, then the second address is at 0xca4. Defaults" - " to 1."); -module_param_hw_array(regsizes, int, other, &num_regsizes, 0); -MODULE_PARM_DESC(regsizes, "The size of the specific IPMI register in bytes." - " This should generally be 1, 2, 4, or 8 for an 8-bit," - " 16-bit, 32-bit, or 64-bit register. Use this if you" - " the 8-bit IPMI register has to be read from a larger" - " register."); -module_param_hw_array(regshifts, int, other, &num_regshifts, 0); -MODULE_PARM_DESC(regshifts, "The amount to shift the data read from the." - " IPMI register, in bits. For instance, if the data" - " is read from a 32-bit word and the IPMI data is in" - " bit 8-15, then the shift would be 8"); -module_param_hw_array(slave_addrs, int, other, &num_slave_addrs, 0); -MODULE_PARM_DESC(slave_addrs, "Set the default IPMB slave address for" - " the controller. Normally this is 0x20, but can be" - " overridden by this parm. This is an array indexed" - " by interface number."); module_param_array(force_kipmid, int, &num_force_kipmid, 0); MODULE_PARM_DESC(force_kipmid, "Force the kipmi daemon to be enabled (1) or" " disabled(0). Normally the IPMI driver auto-detects" @@ -1691,64 +1626,6 @@ static struct smi_info *smi_info_alloc(void) return info; } -static int hardcode_find_bmc(void) -{ - int ret = -ENODEV; - int i; - struct si_sm_io io; - - memset(&io, 0, sizeof(io)); - for (i = 0; i < SI_MAX_PARMS; i++) { - if (!ports[i] && !addrs[i]) - continue; - - io.addr_source = SI_HARDCODED; - pr_info(PFX "probing via hardcoded address\n"); - - if (!si_type[i] || strcmp(si_type[i], "kcs") == 0) { - io.si_type = SI_KCS; - } else if (strcmp(si_type[i], "smic") == 0) { - io.si_type = SI_SMIC; - } else if (strcmp(si_type[i], "bt") == 0) { - io.si_type = SI_BT; - } else { - pr_warn(PFX "Interface type specified for interface %d, was invalid: %s\n", - i, si_type[i]); - continue; - } - - if (ports[i]) { - /* An I/O port */ - io.addr_data = ports[i]; - io.addr_type = IPMI_IO_ADDR_SPACE; - } else if (addrs[i]) { - /* A memory port */ - io.addr_data = addrs[i]; - io.addr_type = IPMI_MEM_ADDR_SPACE; - } else { - pr_warn(PFX "Interface type specified for interface %d, but port and address were not set or set to zero.\n", - i); - continue; - } - - io.addr = NULL; - io.regspacing = regspacings[i]; - if (!io.regspacing) - io.regspacing = DEFAULT_REGSPACING; - io.regsize = regsizes[i]; - if (!io.regsize) - io.regsize = DEFAULT_REGSIZE; - io.regshift = regshifts[i]; - io.irq = irqs[i]; - if (io.irq) - io.irq_setup = ipmi_std_irq_setup; - io.slave_addr = slave_addrs[i]; - - ret = ipmi_si_add_smi(&io); - } - return ret; -} - #ifdef CONFIG_ACPI /* @@ -3349,8 +3226,6 @@ out_err: static int init_ipmi_si(void) { - int i; - char *str; int rv; struct smi_info *e; enum ipmi_addr_src type = SI_INVALID; @@ -3366,26 +3241,11 @@ static int init_ipmi_si(void) } } - /* Parse out the si_type string into its components. */ - str = si_type_str; - if (*str != '\0') { - for (i = 0; (i < SI_MAX_PARMS) && (*str != '\0'); i++) { - si_type[i] = str; - str = strchr(str, ','); - if (str) { - *str = '\0'; - str++; - } else { - break; - } - } - } - pr_info("IPMI System Interface driver.\n"); /* If the user gave us a device, they presumably want us to use it */ - if (!hardcode_find_bmc()) - return 0; + if (!ipmi_si_hardcode_find_bmc()) + goto do_scan; #ifdef CONFIG_PCI if (si_trypci) { @@ -3411,7 +3271,7 @@ static int init_ipmi_si(void) with multiple BMCs we assume that there will be several instances of a given type so if we succeed in registering a type then also try to register everything else of the same type */ - +do_scan: mutex_lock(&smi_infos_lock); list_for_each_entry(e, &smi_infos, link) { /* Try to register a device if it has an IRQ and we either From 9d70029edbbf23474e022ac77700269807d64b0d Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Tue, 12 Sep 2017 22:55:57 -0500 Subject: [PATCH 34/48] ipmi_si: Move platform device handling to another file Signed-off-by: Corey Minyard Stephen Rothwell fixed an issue with the include files --- drivers/char/ipmi/Makefile | 2 +- drivers/char/ipmi/ipmi_si.h | 6 + drivers/char/ipmi/ipmi_si_intf.c | 592 +------------------------- drivers/char/ipmi/ipmi_si_platform.c | 602 +++++++++++++++++++++++++++ 4 files changed, 613 insertions(+), 589 deletions(-) create mode 100644 drivers/char/ipmi/ipmi_si_platform.c diff --git a/drivers/char/ipmi/Makefile b/drivers/char/ipmi/Makefile index ebd728497b23..fa3858f472ac 100644 --- a/drivers/char/ipmi/Makefile +++ b/drivers/char/ipmi/Makefile @@ -3,7 +3,7 @@ # ipmi_si-y := ipmi_si_intf.o ipmi_kcs_sm.o ipmi_smic_sm.o ipmi_bt_sm.o \ - ipmi_si_hotmod.o ipmi_si_hardcode.o + ipmi_si_hotmod.o ipmi_si_hardcode.o ipmi_si_platform.o obj-$(CONFIG_IPMI_HANDLER) += ipmi_msghandler.o obj-$(CONFIG_IPMI_DEVICE_INTERFACE) += ipmi_devintf.o diff --git a/drivers/char/ipmi/ipmi_si.h b/drivers/char/ipmi/ipmi_si.h index 1dbd58afc2d7..ff9a30a1ead5 100644 --- a/drivers/char/ipmi/ipmi_si.h +++ b/drivers/char/ipmi/ipmi_si.h @@ -14,6 +14,8 @@ #define DEFAULT_REGSPACING 1 #define DEFAULT_REGSIZE 1 +#define DEVICE_NAME "ipmi_si" + int ipmi_si_add_smi(struct si_sm_io *io); irqreturn_t ipmi_si_irq_handler(int irq, void *data); void ipmi_irq_start_cleanup(struct si_sm_io *io); @@ -23,3 +25,7 @@ int ipmi_si_remove_by_dev(struct device *dev); void ipmi_si_remove_by_data(int addr_space, enum si_type si_type, unsigned long addr); int ipmi_si_hardcode_find_bmc(void); +void ipmi_si_platform_init(void); +void ipmi_si_platform_shutdown(void); + +extern struct platform_driver ipmi_platform_driver; diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 58f0ebbcd342..bfc052bdbdd7 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -61,15 +61,8 @@ #include #include #include "ipmi_si.h" -#include "ipmi_dmi.h" -#include #include #include -#include -#include -#include -#include -#include #ifdef CONFIG_PARISC #include /* for register_parisc_driver() stuff */ @@ -106,10 +99,6 @@ enum si_intf_state { static const char * const si_to_str[] = { "kcs", "smic", "bt" }; -#define DEVICE_NAME "ipmi_si" - -static struct platform_driver ipmi_driver; - static int initialized; /* @@ -1274,33 +1263,12 @@ static LIST_HEAD(smi_infos); static DEFINE_MUTEX(smi_infos_lock); static int smi_num; /* Used to sequence the SMIs */ -#ifdef CONFIG_ACPI -static bool si_tryacpi = true; -#endif -#ifdef CONFIG_DMI -static bool si_trydmi = true; -#endif -static bool si_tryplatform = true; #ifdef CONFIG_PCI static bool si_trypci = true; #endif static const char * const addr_space_to_str[] = { "i/o", "mem" }; -#ifdef CONFIG_ACPI -module_param_named(tryacpi, si_tryacpi, bool, 0); -MODULE_PARM_DESC(tryacpi, "Setting this to zero will disable the" - " default scan of the interfaces identified via ACPI"); -#endif -#ifdef CONFIG_DMI -module_param_named(trydmi, si_trydmi, bool, 0); -MODULE_PARM_DESC(trydmi, "Setting this to zero will disable the" - " default scan of the interfaces identified via DMI"); -#endif -module_param_named(tryplatform, si_tryplatform, bool, 0); -MODULE_PARM_DESC(tryplatform, "Setting this to zero will disable the" - " default scan of the interfaces identified via platform" - " interfaces like openfirmware"); #ifdef CONFIG_PCI module_param_named(trypci, si_trypci, bool, 0); MODULE_PARM_DESC(trypci, "Setting this to zero will disable the" @@ -1626,310 +1594,6 @@ static struct smi_info *smi_info_alloc(void) return info; } -#ifdef CONFIG_ACPI - -/* - * Once we get an ACPI failure, we don't try any more, because we go - * through the tables sequentially. Once we don't find a table, there - * are no more. - */ -static int acpi_failure; - -/* For GPE-type interrupts. */ -static u32 ipmi_acpi_gpe(acpi_handle gpe_device, - u32 gpe_number, void *context) -{ - struct si_sm_io *io = context; - - ipmi_si_irq_handler(io->irq, io->irq_handler_data); - return ACPI_INTERRUPT_HANDLED; -} - -static void acpi_gpe_irq_cleanup(struct si_sm_io *io) -{ - if (!io->irq) - return; - - ipmi_irq_start_cleanup(io); - acpi_remove_gpe_handler(NULL, io->irq, &ipmi_acpi_gpe); -} - -static int acpi_gpe_irq_setup(struct si_sm_io *io) -{ - acpi_status status; - - if (!io->irq) - return 0; - - status = acpi_install_gpe_handler(NULL, - io->irq, - ACPI_GPE_LEVEL_TRIGGERED, - &ipmi_acpi_gpe, - io); - if (status != AE_OK) { - dev_warn(io->dev, - "Unable to claim ACPI GPE %d, running polled\n", - io->irq); - io->irq = 0; - return -EINVAL; - } else { - io->irq_cleanup = acpi_gpe_irq_cleanup; - ipmi_irq_finish_setup(io); - dev_info(io->dev, "Using ACPI GPE %d\n", io->irq); - return 0; - } -} - -/* - * Defined at - * http://h21007.www2.hp.com/portal/download/files/unprot/hpspmi.pdf - */ -struct SPMITable { - s8 Signature[4]; - u32 Length; - u8 Revision; - u8 Checksum; - s8 OEMID[6]; - s8 OEMTableID[8]; - s8 OEMRevision[4]; - s8 CreatorID[4]; - s8 CreatorRevision[4]; - u8 InterfaceType; - u8 IPMIlegacy; - s16 SpecificationRevision; - - /* - * Bit 0 - SCI interrupt supported - * Bit 1 - I/O APIC/SAPIC - */ - u8 InterruptType; - - /* - * If bit 0 of InterruptType is set, then this is the SCI - * interrupt in the GPEx_STS register. - */ - u8 GPE; - - s16 Reserved; - - /* - * If bit 1 of InterruptType is set, then this is the I/O - * APIC/SAPIC interrupt. - */ - u32 GlobalSystemInterrupt; - - /* The actual register address. */ - struct acpi_generic_address addr; - - u8 UID[4]; - - s8 spmi_id[1]; /* A '\0' terminated array starts here. */ -}; - -static int try_init_spmi(struct SPMITable *spmi) -{ - struct si_sm_io io; - - if (spmi->IPMIlegacy != 1) { - pr_info(PFX "Bad SPMI legacy %d\n", spmi->IPMIlegacy); - return -ENODEV; - } - - memset(&io, 0, sizeof(io)); - io.addr_source = SI_SPMI; - pr_info(PFX "probing via SPMI\n"); - - /* Figure out the interface type. */ - switch (spmi->InterfaceType) { - case 1: /* KCS */ - io.si_type = SI_KCS; - break; - case 2: /* SMIC */ - io.si_type = SI_SMIC; - break; - case 3: /* BT */ - io.si_type = SI_BT; - break; - case 4: /* SSIF, just ignore */ - return -EIO; - default: - pr_info(PFX "Unknown ACPI/SPMI SI type %d\n", - spmi->InterfaceType); - return -EIO; - } - - if (spmi->InterruptType & 1) { - /* We've got a GPE interrupt. */ - io.irq = spmi->GPE; - io.irq_setup = acpi_gpe_irq_setup; - } else if (spmi->InterruptType & 2) { - /* We've got an APIC/SAPIC interrupt. */ - io.irq = spmi->GlobalSystemInterrupt; - io.irq_setup = ipmi_std_irq_setup; - } else { - /* Use the default interrupt setting. */ - io.irq = 0; - io.irq_setup = NULL; - } - - if (spmi->addr.bit_width) { - /* A (hopefully) properly formed register bit width. */ - io.regspacing = spmi->addr.bit_width / 8; - } else { - io.regspacing = DEFAULT_REGSPACING; - } - io.regsize = io.regspacing; - io.regshift = spmi->addr.bit_offset; - - if (spmi->addr.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { - io.addr_type = IPMI_MEM_ADDR_SPACE; - } else if (spmi->addr.space_id == ACPI_ADR_SPACE_SYSTEM_IO) { - io.addr_type = IPMI_IO_ADDR_SPACE; - } else { - pr_warn(PFX "Unknown ACPI I/O Address type\n"); - return -EIO; - } - io.addr_data = spmi->addr.address; - - pr_info("ipmi_si: SPMI: %s %#lx regsize %d spacing %d irq %d\n", - (io.addr_type == IPMI_IO_ADDR_SPACE) ? "io" : "mem", - io.addr_data, io.regsize, io.regspacing, io.irq); - - return ipmi_si_add_smi(&io); -} - -static void spmi_find_bmc(void) -{ - acpi_status status; - struct SPMITable *spmi; - int i; - - if (acpi_disabled) - return; - - if (acpi_failure) - return; - - for (i = 0; ; i++) { - status = acpi_get_table(ACPI_SIG_SPMI, i+1, - (struct acpi_table_header **)&spmi); - if (status != AE_OK) - return; - - try_init_spmi(spmi); - } -} -#endif - -#if defined(CONFIG_DMI) || defined(CONFIG_ACPI) -static struct resource * -ipmi_get_info_from_resources(struct platform_device *pdev, - struct si_sm_io *io) -{ - struct resource *res, *res_second; - - res = platform_get_resource(pdev, IORESOURCE_IO, 0); - if (res) { - io->addr_type = IPMI_IO_ADDR_SPACE; - } else { - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res) - io->addr_type = IPMI_MEM_ADDR_SPACE; - } - if (!res) { - dev_err(&pdev->dev, "no I/O or memory address\n"); - return NULL; - } - io->addr_data = res->start; - - io->regspacing = DEFAULT_REGSPACING; - res_second = platform_get_resource(pdev, - (io->addr_type == IPMI_IO_ADDR_SPACE) ? - IORESOURCE_IO : IORESOURCE_MEM, - 1); - if (res_second) { - if (res_second->start > io->addr_data) - io->regspacing = res_second->start - io->addr_data; - } - io->regsize = DEFAULT_REGSIZE; - io->regshift = 0; - - return res; -} - -#endif - -#ifdef CONFIG_DMI -static int dmi_ipmi_probe(struct platform_device *pdev) -{ - struct si_sm_io io; - u8 type, slave_addr; - int rv; - - if (!si_trydmi) - return -ENODEV; - - rv = device_property_read_u8(&pdev->dev, "ipmi-type", &type); - if (rv) - return -ENODEV; - - memset(&io, 0, sizeof(io)); - io.addr_source = SI_SMBIOS; - pr_info(PFX "probing via SMBIOS\n"); - - switch (type) { - case IPMI_DMI_TYPE_KCS: - io.si_type = SI_KCS; - break; - case IPMI_DMI_TYPE_SMIC: - io.si_type = SI_SMIC; - break; - case IPMI_DMI_TYPE_BT: - io.si_type = SI_BT; - break; - default: - return -EINVAL; - } - - if (!ipmi_get_info_from_resources(pdev, &io)) { - rv = -EINVAL; - goto err_free; - } - - rv = device_property_read_u8(&pdev->dev, "slave-addr", &slave_addr); - if (rv) { - dev_warn(&pdev->dev, "device has no slave-addr property"); - io.slave_addr = 0x20; - } else { - io.slave_addr = slave_addr; - } - - io.irq = platform_get_irq(pdev, 0); - if (io.irq > 0) - io.irq_setup = ipmi_std_irq_setup; - else - io.irq = 0; - - io.dev = &pdev->dev; - - pr_info("ipmi_si: SMBIOS: %s %#lx regsize %d spacing %d irq %d\n", - (io.addr_type == IPMI_IO_ADDR_SPACE) ? "io" : "mem", - io.addr_data, io.regsize, io.regspacing, io.irq); - - ipmi_si_add_smi(&io); - - return 0; - -err_free: - return rv; -} -#else -static int dmi_ipmi_probe(struct platform_device *pdev) -{ - return -ENODEV; -} -#endif /* CONFIG_DMI */ - #ifdef CONFIG_PCI #define PCI_ERMC_CLASSCODE 0x0C0700 @@ -2064,243 +1728,6 @@ static struct pci_driver ipmi_pci_driver = { }; #endif /* CONFIG_PCI */ -#ifdef CONFIG_OF -static const struct of_device_id of_ipmi_match[] = { - { .type = "ipmi", .compatible = "ipmi-kcs", - .data = (void *)(unsigned long) SI_KCS }, - { .type = "ipmi", .compatible = "ipmi-smic", - .data = (void *)(unsigned long) SI_SMIC }, - { .type = "ipmi", .compatible = "ipmi-bt", - .data = (void *)(unsigned long) SI_BT }, - {}, -}; -MODULE_DEVICE_TABLE(of, of_ipmi_match); - -static int of_ipmi_probe(struct platform_device *pdev) -{ - const struct of_device_id *match; - struct si_sm_io io; - struct resource resource; - const __be32 *regsize, *regspacing, *regshift; - struct device_node *np = pdev->dev.of_node; - int ret; - int proplen; - - dev_info(&pdev->dev, "probing via device tree\n"); - - match = of_match_device(of_ipmi_match, &pdev->dev); - if (!match) - return -ENODEV; - - if (!of_device_is_available(np)) - return -EINVAL; - - ret = of_address_to_resource(np, 0, &resource); - if (ret) { - dev_warn(&pdev->dev, PFX "invalid address from OF\n"); - return ret; - } - - regsize = of_get_property(np, "reg-size", &proplen); - if (regsize && proplen != 4) { - dev_warn(&pdev->dev, PFX "invalid regsize from OF\n"); - return -EINVAL; - } - - regspacing = of_get_property(np, "reg-spacing", &proplen); - if (regspacing && proplen != 4) { - dev_warn(&pdev->dev, PFX "invalid regspacing from OF\n"); - return -EINVAL; - } - - regshift = of_get_property(np, "reg-shift", &proplen); - if (regshift && proplen != 4) { - dev_warn(&pdev->dev, PFX "invalid regshift from OF\n"); - return -EINVAL; - } - - memset(&io, 0, sizeof(io)); - io.si_type = (enum si_type) match->data; - io.addr_source = SI_DEVICETREE; - io.irq_setup = ipmi_std_irq_setup; - - if (resource.flags & IORESOURCE_IO) - io.addr_type = IPMI_IO_ADDR_SPACE; - else - io.addr_type = IPMI_MEM_ADDR_SPACE; - - io.addr_data = resource.start; - - io.regsize = regsize ? be32_to_cpup(regsize) : DEFAULT_REGSIZE; - io.regspacing = regspacing ? be32_to_cpup(regspacing) : DEFAULT_REGSPACING; - io.regshift = regshift ? be32_to_cpup(regshift) : 0; - - io.irq = irq_of_parse_and_map(pdev->dev.of_node, 0); - io.dev = &pdev->dev; - - dev_dbg(&pdev->dev, "addr 0x%lx regsize %d spacing %d irq %d\n", - io.addr_data, io.regsize, io.regspacing, io.irq); - - return ipmi_si_add_smi(&io); -} -#else -#define of_ipmi_match NULL -static int of_ipmi_probe(struct platform_device *dev) -{ - return -ENODEV; -} -#endif - -#ifdef CONFIG_ACPI -static int find_slave_address(struct si_sm_io *io, int slave_addr) -{ -#ifdef CONFIG_IPMI_DMI_DECODE - if (!slave_addr) { - int type = -1; - u32 flags = IORESOURCE_IO; - - switch (io->si_type) { - case SI_KCS: - type = IPMI_DMI_TYPE_KCS; - break; - case SI_BT: - type = IPMI_DMI_TYPE_BT; - break; - case SI_SMIC: - type = IPMI_DMI_TYPE_SMIC; - break; - } - - if (io->addr_type == IPMI_MEM_ADDR_SPACE) - flags = IORESOURCE_MEM; - - slave_addr = ipmi_dmi_get_slave_addr(type, flags, - io->addr_data); - } -#endif - - return slave_addr; -} - -static int acpi_ipmi_probe(struct platform_device *pdev) -{ - struct si_sm_io io; - acpi_handle handle; - acpi_status status; - unsigned long long tmp; - struct resource *res; - int rv = -EINVAL; - - if (!si_tryacpi) - return -ENODEV; - - handle = ACPI_HANDLE(&pdev->dev); - if (!handle) - return -ENODEV; - - memset(&io, 0, sizeof(io)); - io.addr_source = SI_ACPI; - dev_info(&pdev->dev, PFX "probing via ACPI\n"); - - io.addr_info.acpi_info.acpi_handle = handle; - - /* _IFT tells us the interface type: KCS, BT, etc */ - status = acpi_evaluate_integer(handle, "_IFT", NULL, &tmp); - if (ACPI_FAILURE(status)) { - dev_err(&pdev->dev, - "Could not find ACPI IPMI interface type\n"); - goto err_free; - } - - switch (tmp) { - case 1: - io.si_type = SI_KCS; - break; - case 2: - io.si_type = SI_SMIC; - break; - case 3: - io.si_type = SI_BT; - break; - case 4: /* SSIF, just ignore */ - rv = -ENODEV; - goto err_free; - default: - dev_info(&pdev->dev, "unknown IPMI type %lld\n", tmp); - goto err_free; - } - - res = ipmi_get_info_from_resources(pdev, &io); - if (!res) { - rv = -EINVAL; - goto err_free; - } - - /* If _GPE exists, use it; otherwise use standard interrupts */ - status = acpi_evaluate_integer(handle, "_GPE", NULL, &tmp); - if (ACPI_SUCCESS(status)) { - io.irq = tmp; - io.irq_setup = acpi_gpe_irq_setup; - } else { - int irq = platform_get_irq(pdev, 0); - - if (irq > 0) { - io.irq = irq; - io.irq_setup = ipmi_std_irq_setup; - } - } - - io.slave_addr = find_slave_address(&io, io.slave_addr); - - io.dev = &pdev->dev; - - dev_info(io.dev, "%pR regsize %d spacing %d irq %d\n", - res, io.regsize, io.regspacing, io.irq); - - return ipmi_si_add_smi(&io); - -err_free: - return rv; -} - -static const struct acpi_device_id acpi_ipmi_match[] = { - { "IPI0001", 0 }, - { }, -}; -MODULE_DEVICE_TABLE(acpi, acpi_ipmi_match); -#else -static int acpi_ipmi_probe(struct platform_device *dev) -{ - return -ENODEV; -} -#endif - -static int ipmi_probe(struct platform_device *pdev) -{ - if (pdev->dev.of_node && of_ipmi_probe(pdev) == 0) - return 0; - - if (acpi_ipmi_probe(pdev) == 0) - return 0; - - return dmi_ipmi_probe(pdev); -} - -static int ipmi_remove(struct platform_device *pdev) -{ - return ipmi_si_remove_by_dev(&pdev->dev); -} - -static struct platform_driver ipmi_driver = { - .driver = { - .name = DEVICE_NAME, - .of_match_table = of_ipmi_match, - .acpi_match_table = ACPI_PTR(acpi_ipmi_match), - }, - .probe = ipmi_probe, - .remove = ipmi_remove, -}; - #ifdef CONFIG_PARISC static int __init ipmi_parisc_probe(struct parisc_device *dev) { @@ -3038,7 +2465,7 @@ static int try_smi_init(struct smi_info *new_smi) goto out_err; } new_smi->io.dev = &new_smi->pdev->dev; - new_smi->io.dev->driver = &ipmi_driver.driver; + new_smi->io.dev->driver = &ipmi_platform_driver.driver; /* Nulled by device_add() */ new_smi->io.dev->init_name = init_name; } @@ -3233,20 +2660,14 @@ static int init_ipmi_si(void) if (initialized) return 0; - if (si_tryplatform) { - rv = platform_driver_register(&ipmi_driver); - if (rv) { - pr_err(PFX "Unable to register driver: %d\n", rv); - return rv; - } - } - pr_info("IPMI System Interface driver.\n"); /* If the user gave us a device, they presumably want us to use it */ if (!ipmi_si_hardcode_find_bmc()) goto do_scan; + ipmi_si_platform_init(); + #ifdef CONFIG_PCI if (si_trypci) { rv = pci_register_driver(&ipmi_pci_driver); @@ -3257,11 +2678,6 @@ static int init_ipmi_si(void) } #endif -#ifdef CONFIG_ACPI - if (si_tryacpi) - spmi_find_bmc(); -#endif - #ifdef CONFIG_PARISC register_parisc_driver(&ipmi_parisc_driver); parisc_registered = true; @@ -3430,7 +2846,7 @@ static void cleanup_ipmi_si(void) unregister_parisc_driver(&ipmi_parisc_driver); #endif - platform_driver_unregister(&ipmi_driver); + ipmi_si_platform_shutdown(); mutex_lock(&smi_infos_lock); list_for_each_entry_safe(e, tmp_e, &smi_infos, link) diff --git a/drivers/char/ipmi/ipmi_si_platform.c b/drivers/char/ipmi/ipmi_si_platform.c new file mode 100644 index 000000000000..cf5c3e5e72e2 --- /dev/null +++ b/drivers/char/ipmi/ipmi_si_platform.c @@ -0,0 +1,602 @@ +/* + * ipmi_si_platform.c + * + * Handling for platform devices in IPMI (ACPI, OF, and things + * coming from the platform. + */ +#include +#include +#include "ipmi_dmi.h" +#include +#include +#include +#include +#include +#include +#include "ipmi_si.h" + +#define PFX "ipmi_platform: " + +static bool si_tryplatform = true; +#ifdef CONFIG_ACPI +static bool si_tryacpi = true; +#endif +#ifdef CONFIG_DMI +static bool si_trydmi = true; +#endif + +module_param_named(tryplatform, si_tryplatform, bool, 0); +MODULE_PARM_DESC(tryplatform, "Setting this to zero will disable the" + " default scan of the interfaces identified via platform" + " interfaces like openfirmware"); +#ifdef CONFIG_ACPI +module_param_named(tryacpi, si_tryacpi, bool, 0); +MODULE_PARM_DESC(tryacpi, "Setting this to zero will disable the" + " default scan of the interfaces identified via ACPI"); +#endif +#ifdef CONFIG_DMI +module_param_named(trydmi, si_trydmi, bool, 0); +MODULE_PARM_DESC(trydmi, "Setting this to zero will disable the" + " default scan of the interfaces identified via DMI"); +#endif + +#ifdef CONFIG_ACPI + +/* + * Once we get an ACPI failure, we don't try any more, because we go + * through the tables sequentially. Once we don't find a table, there + * are no more. + */ +static int acpi_failure; + +/* For GPE-type interrupts. */ +static u32 ipmi_acpi_gpe(acpi_handle gpe_device, + u32 gpe_number, void *context) +{ + struct si_sm_io *io = context; + + ipmi_si_irq_handler(io->irq, io->irq_handler_data); + return ACPI_INTERRUPT_HANDLED; +} + +static void acpi_gpe_irq_cleanup(struct si_sm_io *io) +{ + if (!io->irq) + return; + + ipmi_irq_start_cleanup(io); + acpi_remove_gpe_handler(NULL, io->irq, &ipmi_acpi_gpe); +} + +static int acpi_gpe_irq_setup(struct si_sm_io *io) +{ + acpi_status status; + + if (!io->irq) + return 0; + + status = acpi_install_gpe_handler(NULL, + io->irq, + ACPI_GPE_LEVEL_TRIGGERED, + &ipmi_acpi_gpe, + io); + if (status != AE_OK) { + dev_warn(io->dev, + "Unable to claim ACPI GPE %d, running polled\n", + io->irq); + io->irq = 0; + return -EINVAL; + } else { + io->irq_cleanup = acpi_gpe_irq_cleanup; + ipmi_irq_finish_setup(io); + dev_info(io->dev, "Using ACPI GPE %d\n", io->irq); + return 0; + } +} + +/* + * Defined at + * http://h21007.www2.hp.com/portal/download/files/unprot/hpspmi.pdf + */ +struct SPMITable { + s8 Signature[4]; + u32 Length; + u8 Revision; + u8 Checksum; + s8 OEMID[6]; + s8 OEMTableID[8]; + s8 OEMRevision[4]; + s8 CreatorID[4]; + s8 CreatorRevision[4]; + u8 InterfaceType; + u8 IPMIlegacy; + s16 SpecificationRevision; + + /* + * Bit 0 - SCI interrupt supported + * Bit 1 - I/O APIC/SAPIC + */ + u8 InterruptType; + + /* + * If bit 0 of InterruptType is set, then this is the SCI + * interrupt in the GPEx_STS register. + */ + u8 GPE; + + s16 Reserved; + + /* + * If bit 1 of InterruptType is set, then this is the I/O + * APIC/SAPIC interrupt. + */ + u32 GlobalSystemInterrupt; + + /* The actual register address. */ + struct acpi_generic_address addr; + + u8 UID[4]; + + s8 spmi_id[1]; /* A '\0' terminated array starts here. */ +}; + +static int try_init_spmi(struct SPMITable *spmi) +{ + struct si_sm_io io; + + if (spmi->IPMIlegacy != 1) { + pr_info(PFX "Bad SPMI legacy %d\n", spmi->IPMIlegacy); + return -ENODEV; + } + + memset(&io, 0, sizeof(io)); + io.addr_source = SI_SPMI; + pr_info(PFX "probing via SPMI\n"); + + /* Figure out the interface type. */ + switch (spmi->InterfaceType) { + case 1: /* KCS */ + io.si_type = SI_KCS; + break; + case 2: /* SMIC */ + io.si_type = SI_SMIC; + break; + case 3: /* BT */ + io.si_type = SI_BT; + break; + case 4: /* SSIF, just ignore */ + return -EIO; + default: + pr_info(PFX "Unknown ACPI/SPMI SI type %d\n", + spmi->InterfaceType); + return -EIO; + } + + if (spmi->InterruptType & 1) { + /* We've got a GPE interrupt. */ + io.irq = spmi->GPE; + io.irq_setup = acpi_gpe_irq_setup; + } else if (spmi->InterruptType & 2) { + /* We've got an APIC/SAPIC interrupt. */ + io.irq = spmi->GlobalSystemInterrupt; + io.irq_setup = ipmi_std_irq_setup; + } else { + /* Use the default interrupt setting. */ + io.irq = 0; + io.irq_setup = NULL; + } + + if (spmi->addr.bit_width) { + /* A (hopefully) properly formed register bit width. */ + io.regspacing = spmi->addr.bit_width / 8; + } else { + io.regspacing = DEFAULT_REGSPACING; + } + io.regsize = io.regspacing; + io.regshift = spmi->addr.bit_offset; + + if (spmi->addr.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { + io.addr_type = IPMI_MEM_ADDR_SPACE; + } else if (spmi->addr.space_id == ACPI_ADR_SPACE_SYSTEM_IO) { + io.addr_type = IPMI_IO_ADDR_SPACE; + } else { + pr_warn(PFX "Unknown ACPI I/O Address type\n"); + return -EIO; + } + io.addr_data = spmi->addr.address; + + pr_info("ipmi_si: SPMI: %s %#lx regsize %d spacing %d irq %d\n", + (io.addr_type == IPMI_IO_ADDR_SPACE) ? "io" : "mem", + io.addr_data, io.regsize, io.regspacing, io.irq); + + return ipmi_si_add_smi(&io); +} + +static void spmi_find_bmc(void) +{ + acpi_status status; + struct SPMITable *spmi; + int i; + + if (acpi_disabled) + return; + + if (acpi_failure) + return; + + for (i = 0; ; i++) { + status = acpi_get_table(ACPI_SIG_SPMI, i+1, + (struct acpi_table_header **)&spmi); + if (status != AE_OK) + return; + + try_init_spmi(spmi); + } +} +#endif + +#if defined(CONFIG_DMI) || defined(CONFIG_ACPI) +static struct resource * +ipmi_get_info_from_resources(struct platform_device *pdev, + struct si_sm_io *io) +{ + struct resource *res, *res_second; + + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (res) { + io->addr_type = IPMI_IO_ADDR_SPACE; + } else { + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res) + io->addr_type = IPMI_MEM_ADDR_SPACE; + } + if (!res) { + dev_err(&pdev->dev, "no I/O or memory address\n"); + return NULL; + } + io->addr_data = res->start; + + io->regspacing = DEFAULT_REGSPACING; + res_second = platform_get_resource(pdev, + (io->addr_type == IPMI_IO_ADDR_SPACE) ? + IORESOURCE_IO : IORESOURCE_MEM, + 1); + if (res_second) { + if (res_second->start > io->addr_data) + io->regspacing = res_second->start - io->addr_data; + } + io->regsize = DEFAULT_REGSIZE; + io->regshift = 0; + + return res; +} + +#endif + +#ifdef CONFIG_DMI +static int dmi_ipmi_probe(struct platform_device *pdev) +{ + struct si_sm_io io; + u8 type, slave_addr; + int rv; + + if (!si_trydmi) + return -ENODEV; + + rv = device_property_read_u8(&pdev->dev, "ipmi-type", &type); + if (rv) + return -ENODEV; + + memset(&io, 0, sizeof(io)); + io.addr_source = SI_SMBIOS; + pr_info(PFX "probing via SMBIOS\n"); + + switch (type) { + case IPMI_DMI_TYPE_KCS: + io.si_type = SI_KCS; + break; + case IPMI_DMI_TYPE_SMIC: + io.si_type = SI_SMIC; + break; + case IPMI_DMI_TYPE_BT: + io.si_type = SI_BT; + break; + default: + return -EINVAL; + } + + if (!ipmi_get_info_from_resources(pdev, &io)) { + rv = -EINVAL; + goto err_free; + } + + rv = device_property_read_u8(&pdev->dev, "slave-addr", &slave_addr); + if (rv) { + dev_warn(&pdev->dev, "device has no slave-addr property"); + io.slave_addr = 0x20; + } else { + io.slave_addr = slave_addr; + } + + io.irq = platform_get_irq(pdev, 0); + if (io.irq > 0) + io.irq_setup = ipmi_std_irq_setup; + else + io.irq = 0; + + io.dev = &pdev->dev; + + pr_info("ipmi_si: SMBIOS: %s %#lx regsize %d spacing %d irq %d\n", + (io.addr_type == IPMI_IO_ADDR_SPACE) ? "io" : "mem", + io.addr_data, io.regsize, io.regspacing, io.irq); + + ipmi_si_add_smi(&io); + + return 0; + +err_free: + return rv; +} +#else +static int dmi_ipmi_probe(struct platform_device *pdev) +{ + return -ENODEV; +} +#endif /* CONFIG_DMI */ + +#ifdef CONFIG_OF +static const struct of_device_id of_ipmi_match[] = { + { .type = "ipmi", .compatible = "ipmi-kcs", + .data = (void *)(unsigned long) SI_KCS }, + { .type = "ipmi", .compatible = "ipmi-smic", + .data = (void *)(unsigned long) SI_SMIC }, + { .type = "ipmi", .compatible = "ipmi-bt", + .data = (void *)(unsigned long) SI_BT }, + {}, +}; +MODULE_DEVICE_TABLE(of, of_ipmi_match); + +static int of_ipmi_probe(struct platform_device *pdev) +{ + const struct of_device_id *match; + struct si_sm_io io; + struct resource resource; + const __be32 *regsize, *regspacing, *regshift; + struct device_node *np = pdev->dev.of_node; + int ret; + int proplen; + + dev_info(&pdev->dev, "probing via device tree\n"); + + match = of_match_device(of_ipmi_match, &pdev->dev); + if (!match) + return -ENODEV; + + if (!of_device_is_available(np)) + return -EINVAL; + + ret = of_address_to_resource(np, 0, &resource); + if (ret) { + dev_warn(&pdev->dev, PFX "invalid address from OF\n"); + return ret; + } + + regsize = of_get_property(np, "reg-size", &proplen); + if (regsize && proplen != 4) { + dev_warn(&pdev->dev, PFX "invalid regsize from OF\n"); + return -EINVAL; + } + + regspacing = of_get_property(np, "reg-spacing", &proplen); + if (regspacing && proplen != 4) { + dev_warn(&pdev->dev, PFX "invalid regspacing from OF\n"); + return -EINVAL; + } + + regshift = of_get_property(np, "reg-shift", &proplen); + if (regshift && proplen != 4) { + dev_warn(&pdev->dev, PFX "invalid regshift from OF\n"); + return -EINVAL; + } + + memset(&io, 0, sizeof(io)); + io.si_type = (enum si_type) match->data; + io.addr_source = SI_DEVICETREE; + io.irq_setup = ipmi_std_irq_setup; + + if (resource.flags & IORESOURCE_IO) + io.addr_type = IPMI_IO_ADDR_SPACE; + else + io.addr_type = IPMI_MEM_ADDR_SPACE; + + io.addr_data = resource.start; + + io.regsize = regsize ? be32_to_cpup(regsize) : DEFAULT_REGSIZE; + io.regspacing = regspacing ? be32_to_cpup(regspacing) : DEFAULT_REGSPACING; + io.regshift = regshift ? be32_to_cpup(regshift) : 0; + + io.irq = irq_of_parse_and_map(pdev->dev.of_node, 0); + io.dev = &pdev->dev; + + dev_dbg(&pdev->dev, "addr 0x%lx regsize %d spacing %d irq %d\n", + io.addr_data, io.regsize, io.regspacing, io.irq); + + return ipmi_si_add_smi(&io); +} +#else +#define of_ipmi_match NULL +static int of_ipmi_probe(struct platform_device *dev) +{ + return -ENODEV; +} +#endif + +#ifdef CONFIG_ACPI +static int find_slave_address(struct si_sm_io *io, int slave_addr) +{ +#ifdef CONFIG_IPMI_DMI_DECODE + if (!slave_addr) { + int type = -1; + u32 flags = IORESOURCE_IO; + + switch (io->si_type) { + case SI_KCS: + type = IPMI_DMI_TYPE_KCS; + break; + case SI_BT: + type = IPMI_DMI_TYPE_BT; + break; + case SI_SMIC: + type = IPMI_DMI_TYPE_SMIC; + break; + } + + if (io->addr_type == IPMI_MEM_ADDR_SPACE) + flags = IORESOURCE_MEM; + + slave_addr = ipmi_dmi_get_slave_addr(type, flags, + io->addr_data); + } +#endif + + return slave_addr; +} + +static int acpi_ipmi_probe(struct platform_device *pdev) +{ + struct si_sm_io io; + acpi_handle handle; + acpi_status status; + unsigned long long tmp; + struct resource *res; + int rv = -EINVAL; + + if (!si_tryacpi) + return -ENODEV; + + handle = ACPI_HANDLE(&pdev->dev); + if (!handle) + return -ENODEV; + + memset(&io, 0, sizeof(io)); + io.addr_source = SI_ACPI; + dev_info(&pdev->dev, PFX "probing via ACPI\n"); + + io.addr_info.acpi_info.acpi_handle = handle; + + /* _IFT tells us the interface type: KCS, BT, etc */ + status = acpi_evaluate_integer(handle, "_IFT", NULL, &tmp); + if (ACPI_FAILURE(status)) { + dev_err(&pdev->dev, + "Could not find ACPI IPMI interface type\n"); + goto err_free; + } + + switch (tmp) { + case 1: + io.si_type = SI_KCS; + break; + case 2: + io.si_type = SI_SMIC; + break; + case 3: + io.si_type = SI_BT; + break; + case 4: /* SSIF, just ignore */ + rv = -ENODEV; + goto err_free; + default: + dev_info(&pdev->dev, "unknown IPMI type %lld\n", tmp); + goto err_free; + } + + res = ipmi_get_info_from_resources(pdev, &io); + if (!res) { + rv = -EINVAL; + goto err_free; + } + + /* If _GPE exists, use it; otherwise use standard interrupts */ + status = acpi_evaluate_integer(handle, "_GPE", NULL, &tmp); + if (ACPI_SUCCESS(status)) { + io.irq = tmp; + io.irq_setup = acpi_gpe_irq_setup; + } else { + int irq = platform_get_irq(pdev, 0); + + if (irq > 0) { + io.irq = irq; + io.irq_setup = ipmi_std_irq_setup; + } + } + + io.slave_addr = find_slave_address(&io, io.slave_addr); + + io.dev = &pdev->dev; + + dev_info(io.dev, "%pR regsize %d spacing %d irq %d\n", + res, io.regsize, io.regspacing, io.irq); + + return ipmi_si_add_smi(&io); + +err_free: + return rv; +} + +static const struct acpi_device_id acpi_ipmi_match[] = { + { "IPI0001", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(acpi, acpi_ipmi_match); +#else +static int acpi_ipmi_probe(struct platform_device *dev) +{ + return -ENODEV; +} +#endif + +static int ipmi_probe(struct platform_device *pdev) +{ + if (pdev->dev.of_node && of_ipmi_probe(pdev) == 0) + return 0; + + if (acpi_ipmi_probe(pdev) == 0) + return 0; + + return dmi_ipmi_probe(pdev); +} + +static int ipmi_remove(struct platform_device *pdev) +{ + return ipmi_si_remove_by_dev(&pdev->dev); +} + +struct platform_driver ipmi_platform_driver = { + .driver = { + .name = DEVICE_NAME, + .of_match_table = of_ipmi_match, + .acpi_match_table = ACPI_PTR(acpi_ipmi_match), + }, + .probe = ipmi_probe, + .remove = ipmi_remove, +}; + +void ipmi_si_platform_init(void) +{ + if (si_tryplatform) { + int rv = platform_driver_register(&ipmi_platform_driver); + if (rv) + pr_err(PFX "Unable to register driver: %d\n", rv); + } + +#ifdef CONFIG_ACPI + if (si_tryacpi) + spmi_find_bmc(); +#endif + +} + +void ipmi_si_platform_shutdown(void) +{ + platform_driver_unregister(&ipmi_platform_driver); +} From 13d0b35c5c201e8e6ee520b223c88f58d022a37f Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Tue, 12 Sep 2017 23:04:35 -0500 Subject: [PATCH 35/48] ipmi_si: Move PCI setup to another file Signed-off-by: Corey Minyard Stephen Rothwell fixed an issue with the include files --- drivers/char/ipmi/Makefile | 3 + drivers/char/ipmi/ipmi_si.h | 8 ++ drivers/char/ipmi/ipmi_si_intf.c | 163 +----------------------------- drivers/char/ipmi/ipmi_si_pci.c | 166 +++++++++++++++++++++++++++++++ 4 files changed, 179 insertions(+), 161 deletions(-) create mode 100644 drivers/char/ipmi/ipmi_si_pci.c diff --git a/drivers/char/ipmi/Makefile b/drivers/char/ipmi/Makefile index fa3858f472ac..55ec4a3d7d07 100644 --- a/drivers/char/ipmi/Makefile +++ b/drivers/char/ipmi/Makefile @@ -4,6 +4,9 @@ ipmi_si-y := ipmi_si_intf.o ipmi_kcs_sm.o ipmi_smic_sm.o ipmi_bt_sm.o \ ipmi_si_hotmod.o ipmi_si_hardcode.o ipmi_si_platform.o +ifdef CONFIG_PCI +ipmi_si-y += ipmi_si_pci.o +endif obj-$(CONFIG_IPMI_HANDLER) += ipmi_msghandler.o obj-$(CONFIG_IPMI_DEVICE_INTERFACE) += ipmi_devintf.o diff --git a/drivers/char/ipmi/ipmi_si.h b/drivers/char/ipmi/ipmi_si.h index ff9a30a1ead5..7627e9ada017 100644 --- a/drivers/char/ipmi/ipmi_si.h +++ b/drivers/char/ipmi/ipmi_si.h @@ -29,3 +29,11 @@ void ipmi_si_platform_init(void); void ipmi_si_platform_shutdown(void); extern struct platform_driver ipmi_platform_driver; + +#ifdef CONFIG_PCI +void ipmi_si_pci_init(void); +void ipmi_si_pci_shutdown(void); +#else +static inline void ipmi_si_pci_init(void) { } +static inline void ipmi_si_pci_shutdown(void) { } +#endif diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index bfc052bdbdd7..a2be633697e8 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -49,7 +49,6 @@ #include #include #include -#include #include #include #include @@ -283,9 +282,6 @@ struct smi_info { #define IPMI_MAX_INTFS 4 static int force_kipmid[IPMI_MAX_INTFS]; static int num_force_kipmid; -#ifdef CONFIG_PCI -static bool pci_registered; -#endif #ifdef CONFIG_PARISC static bool parisc_registered; #endif @@ -1263,17 +1259,8 @@ static LIST_HEAD(smi_infos); static DEFINE_MUTEX(smi_infos_lock); static int smi_num; /* Used to sequence the SMIs */ -#ifdef CONFIG_PCI -static bool si_trypci = true; -#endif - static const char * const addr_space_to_str[] = { "i/o", "mem" }; -#ifdef CONFIG_PCI -module_param_named(trypci, si_trypci, bool, 0); -MODULE_PARM_DESC(trypci, "Setting this to zero will disable the" - " default scan of the interfaces identified via pci"); -#endif module_param_array(force_kipmid, int, &num_force_kipmid, 0); MODULE_PARM_DESC(force_kipmid, "Force the kipmi daemon to be enabled (1) or" " disabled(0). Normally the IPMI driver auto-detects" @@ -1594,140 +1581,6 @@ static struct smi_info *smi_info_alloc(void) return info; } -#ifdef CONFIG_PCI - -#define PCI_ERMC_CLASSCODE 0x0C0700 -#define PCI_ERMC_CLASSCODE_MASK 0xffffff00 -#define PCI_ERMC_CLASSCODE_TYPE_MASK 0xff -#define PCI_ERMC_CLASSCODE_TYPE_SMIC 0x00 -#define PCI_ERMC_CLASSCODE_TYPE_KCS 0x01 -#define PCI_ERMC_CLASSCODE_TYPE_BT 0x02 - -#define PCI_HP_VENDOR_ID 0x103C -#define PCI_MMC_DEVICE_ID 0x121A -#define PCI_MMC_ADDR_CW 0x10 - -static void ipmi_pci_cleanup(struct si_sm_io *io) -{ - struct pci_dev *pdev = io->addr_source_data; - - pci_disable_device(pdev); -} - -static int ipmi_pci_probe_regspacing(struct si_sm_io *io) -{ - if (io->si_type == SI_KCS) { - unsigned char status; - int regspacing; - - io->regsize = DEFAULT_REGSIZE; - io->regshift = 0; - - /* detect 1, 4, 16byte spacing */ - for (regspacing = DEFAULT_REGSPACING; regspacing <= 16;) { - io->regspacing = regspacing; - if (io->io_setup(io)) { - dev_err(io->dev, - "Could not setup I/O space\n"); - return DEFAULT_REGSPACING; - } - /* write invalid cmd */ - io->outputb(io, 1, 0x10); - /* read status back */ - status = io->inputb(io, 1); - io->io_cleanup(io); - if (status) - return regspacing; - regspacing *= 4; - } - } - return DEFAULT_REGSPACING; -} - -static int ipmi_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - int rv; - int class_type = pdev->class & PCI_ERMC_CLASSCODE_TYPE_MASK; - struct si_sm_io io; - - memset(&io, 0, sizeof(io)); - io.addr_source = SI_PCI; - dev_info(&pdev->dev, "probing via PCI"); - - switch (class_type) { - case PCI_ERMC_CLASSCODE_TYPE_SMIC: - io.si_type = SI_SMIC; - break; - - case PCI_ERMC_CLASSCODE_TYPE_KCS: - io.si_type = SI_KCS; - break; - - case PCI_ERMC_CLASSCODE_TYPE_BT: - io.si_type = SI_BT; - break; - - default: - dev_info(&pdev->dev, "Unknown IPMI type: %d\n", class_type); - return -ENOMEM; - } - - rv = pci_enable_device(pdev); - if (rv) { - dev_err(&pdev->dev, "couldn't enable PCI device\n"); - return rv; - } - - io.addr_source_cleanup = ipmi_pci_cleanup; - io.addr_source_data = pdev; - - if (pci_resource_flags(pdev, 0) & IORESOURCE_IO) - io.addr_type = IPMI_IO_ADDR_SPACE; - else - io.addr_type = IPMI_MEM_ADDR_SPACE; - io.addr_data = pci_resource_start(pdev, 0); - - io.regspacing = ipmi_pci_probe_regspacing(&io); - io.regsize = DEFAULT_REGSIZE; - io.regshift = 0; - - io.irq = pdev->irq; - if (io.irq) - io.irq_setup = ipmi_std_irq_setup; - - io.dev = &pdev->dev; - - dev_info(&pdev->dev, "%pR regsize %d spacing %d irq %d\n", - &pdev->resource[0], io.regsize, io.regspacing, io.irq); - - rv = ipmi_si_add_smi(&io); - if (rv) - pci_disable_device(pdev); - - return rv; -} - -static void ipmi_pci_remove(struct pci_dev *pdev) -{ - ipmi_si_remove_by_dev(&pdev->dev); -} - -static const struct pci_device_id ipmi_pci_devices[] = { - { PCI_DEVICE(PCI_HP_VENDOR_ID, PCI_MMC_DEVICE_ID) }, - { PCI_DEVICE_CLASS(PCI_ERMC_CLASSCODE, PCI_ERMC_CLASSCODE_MASK) }, - { 0, } -}; -MODULE_DEVICE_TABLE(pci, ipmi_pci_devices); - -static struct pci_driver ipmi_pci_driver = { - .name = DEVICE_NAME, - .id_table = ipmi_pci_devices, - .probe = ipmi_pci_probe, - .remove = ipmi_pci_remove, -}; -#endif /* CONFIG_PCI */ - #ifdef CONFIG_PARISC static int __init ipmi_parisc_probe(struct parisc_device *dev) { @@ -2653,7 +2506,6 @@ out_err: static int init_ipmi_si(void) { - int rv; struct smi_info *e; enum ipmi_addr_src type = SI_INVALID; @@ -2668,15 +2520,7 @@ static int init_ipmi_si(void) ipmi_si_platform_init(); -#ifdef CONFIG_PCI - if (si_trypci) { - rv = pci_register_driver(&ipmi_pci_driver); - if (rv) - pr_err(PFX "Unable to register PCI driver: %d\n", rv); - else - pci_registered = true; - } -#endif + ipmi_si_pci_init(); #ifdef CONFIG_PARISC register_parisc_driver(&ipmi_parisc_driver); @@ -2837,10 +2681,7 @@ static void cleanup_ipmi_si(void) if (!initialized) return; -#ifdef CONFIG_PCI - if (pci_registered) - pci_unregister_driver(&ipmi_pci_driver); -#endif + ipmi_si_pci_shutdown(); #ifdef CONFIG_PARISC if (parisc_registered) unregister_parisc_driver(&ipmi_parisc_driver); diff --git a/drivers/char/ipmi/ipmi_si_pci.c b/drivers/char/ipmi/ipmi_si_pci.c new file mode 100644 index 000000000000..99771f5cad07 --- /dev/null +++ b/drivers/char/ipmi/ipmi_si_pci.c @@ -0,0 +1,166 @@ +/* + * ipmi_si_pci.c + * + * Handling for IPMI devices on the PCI bus. + */ +#include +#include +#include "ipmi_si.h" + +#define PFX "ipmi_pci: " + +static bool pci_registered; + +static bool si_trypci = true; + +module_param_named(trypci, si_trypci, bool, 0); +MODULE_PARM_DESC(trypci, "Setting this to zero will disable the" + " default scan of the interfaces identified via pci"); + +#define PCI_ERMC_CLASSCODE 0x0C0700 +#define PCI_ERMC_CLASSCODE_MASK 0xffffff00 +#define PCI_ERMC_CLASSCODE_TYPE_MASK 0xff +#define PCI_ERMC_CLASSCODE_TYPE_SMIC 0x00 +#define PCI_ERMC_CLASSCODE_TYPE_KCS 0x01 +#define PCI_ERMC_CLASSCODE_TYPE_BT 0x02 + +#define PCI_HP_VENDOR_ID 0x103C +#define PCI_MMC_DEVICE_ID 0x121A +#define PCI_MMC_ADDR_CW 0x10 + +static void ipmi_pci_cleanup(struct si_sm_io *io) +{ + struct pci_dev *pdev = io->addr_source_data; + + pci_disable_device(pdev); +} + +static int ipmi_pci_probe_regspacing(struct si_sm_io *io) +{ + if (io->si_type == SI_KCS) { + unsigned char status; + int regspacing; + + io->regsize = DEFAULT_REGSIZE; + io->regshift = 0; + + /* detect 1, 4, 16byte spacing */ + for (regspacing = DEFAULT_REGSPACING; regspacing <= 16;) { + io->regspacing = regspacing; + if (io->io_setup(io)) { + dev_err(io->dev, + "Could not setup I/O space\n"); + return DEFAULT_REGSPACING; + } + /* write invalid cmd */ + io->outputb(io, 1, 0x10); + /* read status back */ + status = io->inputb(io, 1); + io->io_cleanup(io); + if (status) + return regspacing; + regspacing *= 4; + } + } + return DEFAULT_REGSPACING; +} + +static int ipmi_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + int rv; + int class_type = pdev->class & PCI_ERMC_CLASSCODE_TYPE_MASK; + struct si_sm_io io; + + memset(&io, 0, sizeof(io)); + io.addr_source = SI_PCI; + dev_info(&pdev->dev, "probing via PCI"); + + switch (class_type) { + case PCI_ERMC_CLASSCODE_TYPE_SMIC: + io.si_type = SI_SMIC; + break; + + case PCI_ERMC_CLASSCODE_TYPE_KCS: + io.si_type = SI_KCS; + break; + + case PCI_ERMC_CLASSCODE_TYPE_BT: + io.si_type = SI_BT; + break; + + default: + dev_info(&pdev->dev, "Unknown IPMI type: %d\n", class_type); + return -ENOMEM; + } + + rv = pci_enable_device(pdev); + if (rv) { + dev_err(&pdev->dev, "couldn't enable PCI device\n"); + return rv; + } + + io.addr_source_cleanup = ipmi_pci_cleanup; + io.addr_source_data = pdev; + + if (pci_resource_flags(pdev, 0) & IORESOURCE_IO) + io.addr_type = IPMI_IO_ADDR_SPACE; + else + io.addr_type = IPMI_MEM_ADDR_SPACE; + io.addr_data = pci_resource_start(pdev, 0); + + io.regspacing = ipmi_pci_probe_regspacing(&io); + io.regsize = DEFAULT_REGSIZE; + io.regshift = 0; + + io.irq = pdev->irq; + if (io.irq) + io.irq_setup = ipmi_std_irq_setup; + + io.dev = &pdev->dev; + + dev_info(&pdev->dev, "%pR regsize %d spacing %d irq %d\n", + &pdev->resource[0], io.regsize, io.regspacing, io.irq); + + rv = ipmi_si_add_smi(&io); + if (rv) + pci_disable_device(pdev); + + return rv; +} + +static void ipmi_pci_remove(struct pci_dev *pdev) +{ + ipmi_si_remove_by_dev(&pdev->dev); +} + +static const struct pci_device_id ipmi_pci_devices[] = { + { PCI_DEVICE(PCI_HP_VENDOR_ID, PCI_MMC_DEVICE_ID) }, + { PCI_DEVICE_CLASS(PCI_ERMC_CLASSCODE, PCI_ERMC_CLASSCODE_MASK) }, + { 0, } +}; +MODULE_DEVICE_TABLE(pci, ipmi_pci_devices); + +static struct pci_driver ipmi_pci_driver = { + .name = DEVICE_NAME, + .id_table = ipmi_pci_devices, + .probe = ipmi_pci_probe, + .remove = ipmi_pci_remove, +}; + +void ipmi_si_pci_init(void) +{ + if (si_trypci) { + int rv = pci_register_driver(&ipmi_pci_driver); + if (rv) + pr_err(PFX "Unable to register PCI driver: %d\n", rv); + else + pci_registered = true; + } +} + +void ipmi_si_pci_shutdown(void) +{ + if (pci_registered) + pci_unregister_driver(&ipmi_pci_driver); +} From c6f85a753df858018b063f5ab89b277179c3387f Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Tue, 12 Sep 2017 23:10:18 -0500 Subject: [PATCH 36/48] ipmi_si: Move PARISC handling to another file Signed-off-by: Corey Minyard --- drivers/char/ipmi/Makefile | 3 ++ drivers/char/ipmi/ipmi_si.h | 7 ++++ drivers/char/ipmi/ipmi_si_intf.c | 60 ++---------------------------- drivers/char/ipmi/ipmi_si_parisc.c | 58 +++++++++++++++++++++++++++++ 4 files changed, 71 insertions(+), 57 deletions(-) create mode 100644 drivers/char/ipmi/ipmi_si_parisc.c diff --git a/drivers/char/ipmi/Makefile b/drivers/char/ipmi/Makefile index 55ec4a3d7d07..3c01149e7d36 100644 --- a/drivers/char/ipmi/Makefile +++ b/drivers/char/ipmi/Makefile @@ -7,6 +7,9 @@ ipmi_si-y := ipmi_si_intf.o ipmi_kcs_sm.o ipmi_smic_sm.o ipmi_bt_sm.o \ ifdef CONFIG_PCI ipmi_si-y += ipmi_si_pci.o endif +ifdef CONFIG_PARISC +ipmi_si-y += ipmi_si_parisc.o +endif obj-$(CONFIG_IPMI_HANDLER) += ipmi_msghandler.o obj-$(CONFIG_IPMI_DEVICE_INTERFACE) += ipmi_devintf.o diff --git a/drivers/char/ipmi/ipmi_si.h b/drivers/char/ipmi/ipmi_si.h index 7627e9ada017..f3530d60db05 100644 --- a/drivers/char/ipmi/ipmi_si.h +++ b/drivers/char/ipmi/ipmi_si.h @@ -37,3 +37,10 @@ void ipmi_si_pci_shutdown(void); static inline void ipmi_si_pci_init(void) { } static inline void ipmi_si_pci_shutdown(void) { } #endif +#ifdef CONFIG_PARISC +void ipmi_si_parisc_init(void); +void ipmi_si_parisc_shutdown(void); +#else +static inline void ipmi_si_parisc_init(void) { } +static inline void ipmi_si_parisc_shutdown(void) { } +#endif diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index a2be633697e8..2d538840fbf4 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -63,11 +63,6 @@ #include #include -#ifdef CONFIG_PARISC -#include /* for register_parisc_driver() stuff */ -#include -#endif - #define PFX "ipmi_si: " /* Measure times between events in the driver. */ @@ -282,9 +277,6 @@ struct smi_info { #define IPMI_MAX_INTFS 4 static int force_kipmid[IPMI_MAX_INTFS]; static int num_force_kipmid; -#ifdef CONFIG_PARISC -static bool parisc_registered; -#endif static unsigned int kipmid_max_busy_us[IPMI_MAX_INTFS]; static int num_max_busy_us; @@ -1581,47 +1573,6 @@ static struct smi_info *smi_info_alloc(void) return info; } -#ifdef CONFIG_PARISC -static int __init ipmi_parisc_probe(struct parisc_device *dev) -{ - struct si_sm_io io; - - io.si_type = SI_KCS; - io.addr_source = SI_DEVICETREE; - io.addr_type = IPMI_MEM_ADDR_SPACE; - io.addr_data = dev->hpa.start; - io.regsize = 1; - io.regspacing = 1; - io.regshift = 0; - io.irq = 0; /* no interrupt */ - io.irq_setup = NULL; - io.dev = &dev->dev; - - dev_dbg(&dev->dev, "addr 0x%lx\n", io.addr_data); - - return ipmi_si_add_smi(&io); -} - -static int __exit ipmi_parisc_remove(struct parisc_device *dev) -{ - return ipmi_si_remove_by_dev(&pdev->dev); -} - -static const struct parisc_device_id ipmi_parisc_tbl[] __initconst = { - { HPHW_MC, HVERSION_REV_ANY_ID, 0x004, 0xC0 }, - { 0, } -}; - -MODULE_DEVICE_TABLE(parisc, ipmi_parisc_tbl); - -static struct parisc_driver ipmi_parisc_driver __refdata = { - .name = "ipmi", - .id_table = ipmi_parisc_tbl, - .probe = ipmi_parisc_probe, - .remove = __exit_p(ipmi_parisc_remove), -}; -#endif /* CONFIG_PARISC */ - static int wait_for_msg_done(struct smi_info *smi_info) { enum si_sm_result smi_result; @@ -2522,10 +2473,7 @@ static int init_ipmi_si(void) ipmi_si_pci_init(); -#ifdef CONFIG_PARISC - register_parisc_driver(&ipmi_parisc_driver); - parisc_registered = true; -#endif + ipmi_si_parisc_init(); /* We prefer devices with interrupts, but in the case of a machine with multiple BMCs we assume that there will be several instances @@ -2682,10 +2630,8 @@ static void cleanup_ipmi_si(void) return; ipmi_si_pci_shutdown(); -#ifdef CONFIG_PARISC - if (parisc_registered) - unregister_parisc_driver(&ipmi_parisc_driver); -#endif + + ipmi_si_parisc_shutdown(); ipmi_si_platform_shutdown(); diff --git a/drivers/char/ipmi/ipmi_si_parisc.c b/drivers/char/ipmi/ipmi_si_parisc.c new file mode 100644 index 000000000000..090b073ab441 --- /dev/null +++ b/drivers/char/ipmi/ipmi_si_parisc.c @@ -0,0 +1,58 @@ + +#include +#include /* for register_parisc_driver() stuff */ +#include +#include "ipmi_si.h" + +static bool parisc_registered; + +static int __init ipmi_parisc_probe(struct parisc_device *dev) +{ + struct si_sm_io io; + + io.si_type = SI_KCS; + io.addr_source = SI_DEVICETREE; + io.addr_type = IPMI_MEM_ADDR_SPACE; + io.addr_data = dev->hpa.start; + io.regsize = 1; + io.regspacing = 1; + io.regshift = 0; + io.irq = 0; /* no interrupt */ + io.irq_setup = NULL; + io.dev = &dev->dev; + + dev_dbg(&dev->dev, "addr 0x%lx\n", io.addr_data); + + return ipmi_si_add_smi(&io); +} + +static int __exit ipmi_parisc_remove(struct parisc_device *dev) +{ + return ipmi_si_remove_by_dev(&dev->dev); +} + +static const struct parisc_device_id ipmi_parisc_tbl[] __initconst = { + { HPHW_MC, HVERSION_REV_ANY_ID, 0x004, 0xC0 }, + { 0, } +}; + +MODULE_DEVICE_TABLE(parisc, ipmi_parisc_tbl); + +static struct parisc_driver ipmi_parisc_driver __refdata = { + .name = "ipmi", + .id_table = ipmi_parisc_tbl, + .probe = ipmi_parisc_probe, + .remove = __exit_p(ipmi_parisc_remove), +}; + +void ipmi_si_parisc_init(void) +{ + register_parisc_driver(&ipmi_parisc_driver); + parisc_registered = true; +} + +void ipmi_si_parisc_shutdown(void) +{ + if (parisc_registered) + unregister_parisc_driver(&ipmi_parisc_driver); +} From d1a6791323b810ce9136a58d95c6e0e455313388 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Tue, 12 Sep 2017 23:14:25 -0500 Subject: [PATCH 37/48] ipmi_si: Get rid of unused spacing and port fields Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_si_intf.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 2d538840fbf4..801ca241b34c 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -198,16 +198,6 @@ struct smi_info { */ bool run_to_completion; - /* The I/O port of an SI interface. */ - int port; - - /* - * The space between start addresses of the two ports. For - * instance, if the first port is 0xca2 and the spacing is 4, then - * the second port is 0xca6. - */ - unsigned int spacing; - /* The timer for this si. */ struct timer_list si_timer; From 58e2763553cb837b879d4a2934094e152e7daf27 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Tue, 12 Sep 2017 23:24:30 -0500 Subject: [PATCH 38/48] ipmi_si: Move port and mem I/O handling to their own files Signed-off-by: Corey Minyard --- drivers/char/ipmi/Makefile | 3 +- drivers/char/ipmi/ipmi_si.h | 3 + drivers/char/ipmi/ipmi_si_intf.c | 256 +--------------------------- drivers/char/ipmi/ipmi_si_mem_io.c | 144 ++++++++++++++++ drivers/char/ipmi/ipmi_si_port_io.c | 112 ++++++++++++ 5 files changed, 263 insertions(+), 255 deletions(-) create mode 100644 drivers/char/ipmi/ipmi_si_mem_io.c create mode 100644 drivers/char/ipmi/ipmi_si_port_io.c diff --git a/drivers/char/ipmi/Makefile b/drivers/char/ipmi/Makefile index 3c01149e7d36..312396c1a8e5 100644 --- a/drivers/char/ipmi/Makefile +++ b/drivers/char/ipmi/Makefile @@ -3,7 +3,8 @@ # ipmi_si-y := ipmi_si_intf.o ipmi_kcs_sm.o ipmi_smic_sm.o ipmi_bt_sm.o \ - ipmi_si_hotmod.o ipmi_si_hardcode.o ipmi_si_platform.o + ipmi_si_hotmod.o ipmi_si_hardcode.o ipmi_si_platform.o \ + ipmi_si_port_io.o ipmi_si_mem_io.o ifdef CONFIG_PCI ipmi_si-y += ipmi_si_pci.o endif diff --git a/drivers/char/ipmi/ipmi_si.h b/drivers/char/ipmi/ipmi_si.h index f3530d60db05..17ce5f7b89ab 100644 --- a/drivers/char/ipmi/ipmi_si.h +++ b/drivers/char/ipmi/ipmi_si.h @@ -44,3 +44,6 @@ void ipmi_si_parisc_shutdown(void); static inline void ipmi_si_parisc_init(void) { } static inline void ipmi_si_parisc_shutdown(void) { } #endif + +int ipmi_si_port_setup(struct si_sm_io *io); +int ipmi_si_mem_setup(struct si_sm_io *io); diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 801ca241b34c..d24cd5de09d0 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -49,7 +49,6 @@ #include #include #include -#include #include #include #include @@ -58,7 +57,6 @@ #include #include #include -#include #include "ipmi_si.h" #include #include @@ -1304,256 +1302,6 @@ int ipmi_std_irq_setup(struct si_sm_io *io) return rv; } -static unsigned char port_inb(const struct si_sm_io *io, unsigned int offset) -{ - unsigned int addr = io->addr_data; - - return inb(addr + (offset * io->regspacing)); -} - -static void port_outb(const struct si_sm_io *io, unsigned int offset, - unsigned char b) -{ - unsigned int addr = io->addr_data; - - outb(b, addr + (offset * io->regspacing)); -} - -static unsigned char port_inw(const struct si_sm_io *io, unsigned int offset) -{ - unsigned int addr = io->addr_data; - - return (inw(addr + (offset * io->regspacing)) >> io->regshift) & 0xff; -} - -static void port_outw(const struct si_sm_io *io, unsigned int offset, - unsigned char b) -{ - unsigned int addr = io->addr_data; - - outw(b << io->regshift, addr + (offset * io->regspacing)); -} - -static unsigned char port_inl(const struct si_sm_io *io, unsigned int offset) -{ - unsigned int addr = io->addr_data; - - return (inl(addr + (offset * io->regspacing)) >> io->regshift) & 0xff; -} - -static void port_outl(const struct si_sm_io *io, unsigned int offset, - unsigned char b) -{ - unsigned int addr = io->addr_data; - - outl(b << io->regshift, addr+(offset * io->regspacing)); -} - -static void port_cleanup(struct si_sm_io *io) -{ - unsigned int addr = io->addr_data; - int idx; - - if (addr) { - for (idx = 0; idx < io->io_size; idx++) - release_region(addr + idx * io->regspacing, - io->regsize); - } -} - -static int port_setup(struct si_sm_io *io) -{ - unsigned int addr = io->addr_data; - int idx; - - if (!addr) - return -ENODEV; - - io->io_cleanup = port_cleanup; - - /* - * Figure out the actual inb/inw/inl/etc routine to use based - * upon the register size. - */ - switch (io->regsize) { - case 1: - io->inputb = port_inb; - io->outputb = port_outb; - break; - case 2: - io->inputb = port_inw; - io->outputb = port_outw; - break; - case 4: - io->inputb = port_inl; - io->outputb = port_outl; - break; - default: - dev_warn(io->dev, "Invalid register size: %d\n", - io->regsize); - return -EINVAL; - } - - /* - * Some BIOSes reserve disjoint I/O regions in their ACPI - * tables. This causes problems when trying to register the - * entire I/O region. Therefore we must register each I/O - * port separately. - */ - for (idx = 0; idx < io->io_size; idx++) { - if (request_region(addr + idx * io->regspacing, - io->regsize, DEVICE_NAME) == NULL) { - /* Undo allocations */ - while (idx--) - release_region(addr + idx * io->regspacing, - io->regsize); - return -EIO; - } - } - return 0; -} - -static unsigned char intf_mem_inb(const struct si_sm_io *io, - unsigned int offset) -{ - return readb((io->addr)+(offset * io->regspacing)); -} - -static void intf_mem_outb(const struct si_sm_io *io, unsigned int offset, - unsigned char b) -{ - writeb(b, (io->addr)+(offset * io->regspacing)); -} - -static unsigned char intf_mem_inw(const struct si_sm_io *io, - unsigned int offset) -{ - return (readw((io->addr)+(offset * io->regspacing)) >> io->regshift) - & 0xff; -} - -static void intf_mem_outw(const struct si_sm_io *io, unsigned int offset, - unsigned char b) -{ - writeb(b << io->regshift, (io->addr)+(offset * io->regspacing)); -} - -static unsigned char intf_mem_inl(const struct si_sm_io *io, - unsigned int offset) -{ - return (readl((io->addr)+(offset * io->regspacing)) >> io->regshift) - & 0xff; -} - -static void intf_mem_outl(const struct si_sm_io *io, unsigned int offset, - unsigned char b) -{ - writel(b << io->regshift, (io->addr)+(offset * io->regspacing)); -} - -#ifdef readq -static unsigned char mem_inq(const struct si_sm_io *io, unsigned int offset) -{ - return (readq((io->addr)+(offset * io->regspacing)) >> io->regshift) - & 0xff; -} - -static void mem_outq(const struct si_sm_io *io, unsigned int offset, - unsigned char b) -{ - writeq(b << io->regshift, (io->addr)+(offset * io->regspacing)); -} -#endif - -static void mem_region_cleanup(struct si_sm_io *io, int num) -{ - unsigned long addr = io->addr_data; - int idx; - - for (idx = 0; idx < num; idx++) - release_mem_region(addr + idx * io->regspacing, - io->regsize); -} - -static void mem_cleanup(struct si_sm_io *io) -{ - if (io->addr) { - iounmap(io->addr); - mem_region_cleanup(io, io->io_size); - } -} - -static int mem_setup(struct si_sm_io *io) -{ - unsigned long addr = io->addr_data; - int mapsize, idx; - - if (!addr) - return -ENODEV; - - io->io_cleanup = mem_cleanup; - - /* - * Figure out the actual readb/readw/readl/etc routine to use based - * upon the register size. - */ - switch (io->regsize) { - case 1: - io->inputb = intf_mem_inb; - io->outputb = intf_mem_outb; - break; - case 2: - io->inputb = intf_mem_inw; - io->outputb = intf_mem_outw; - break; - case 4: - io->inputb = intf_mem_inl; - io->outputb = intf_mem_outl; - break; -#ifdef readq - case 8: - io->inputb = mem_inq; - io->outputb = mem_outq; - break; -#endif - default: - dev_warn(io->dev, "Invalid register size: %d\n", - io->regsize); - return -EINVAL; - } - - /* - * Some BIOSes reserve disjoint memory regions in their ACPI - * tables. This causes problems when trying to request the - * entire region. Therefore we must request each register - * separately. - */ - for (idx = 0; idx < io->io_size; idx++) { - if (request_mem_region(addr + idx * io->regspacing, - io->regsize, DEVICE_NAME) == NULL) { - /* Undo allocations */ - mem_region_cleanup(io, idx); - return -EIO; - } - } - - /* - * Calculate the total amount of memory to claim. This is an - * unusual looking calculation, but it avoids claiming any - * more memory than it has to. It will claim everything - * between the first address to the end of the last full - * register. - */ - mapsize = ((io->io_size * io->regspacing) - - (io->regspacing - io->regsize)); - io->addr = ioremap(addr, mapsize); - if (io->addr == NULL) { - mem_region_cleanup(io, io->io_size); - return -EIO; - } - return 0; -} - static struct smi_info *smi_info_alloc(void) { struct smi_info *info = kzalloc(sizeof(*info), GFP_KERNEL); @@ -2146,9 +1894,9 @@ int ipmi_si_add_smi(struct si_sm_io *io) if (!io->io_setup) { if (io->addr_type == IPMI_IO_ADDR_SPACE) { - io->io_setup = port_setup; + io->io_setup = ipmi_si_port_setup; } else if (io->addr_type == IPMI_MEM_ADDR_SPACE) { - io->io_setup = mem_setup; + io->io_setup = ipmi_si_mem_setup; } else { return -EINVAL; } diff --git a/drivers/char/ipmi/ipmi_si_mem_io.c b/drivers/char/ipmi/ipmi_si_mem_io.c new file mode 100644 index 000000000000..8796396ecd0f --- /dev/null +++ b/drivers/char/ipmi/ipmi_si_mem_io.c @@ -0,0 +1,144 @@ + +#include +#include "ipmi_si.h" + +static unsigned char intf_mem_inb(const struct si_sm_io *io, + unsigned int offset) +{ + return readb((io->addr)+(offset * io->regspacing)); +} + +static void intf_mem_outb(const struct si_sm_io *io, unsigned int offset, + unsigned char b) +{ + writeb(b, (io->addr)+(offset * io->regspacing)); +} + +static unsigned char intf_mem_inw(const struct si_sm_io *io, + unsigned int offset) +{ + return (readw((io->addr)+(offset * io->regspacing)) >> io->regshift) + & 0xff; +} + +static void intf_mem_outw(const struct si_sm_io *io, unsigned int offset, + unsigned char b) +{ + writeb(b << io->regshift, (io->addr)+(offset * io->regspacing)); +} + +static unsigned char intf_mem_inl(const struct si_sm_io *io, + unsigned int offset) +{ + return (readl((io->addr)+(offset * io->regspacing)) >> io->regshift) + & 0xff; +} + +static void intf_mem_outl(const struct si_sm_io *io, unsigned int offset, + unsigned char b) +{ + writel(b << io->regshift, (io->addr)+(offset * io->regspacing)); +} + +#ifdef readq +static unsigned char mem_inq(const struct si_sm_io *io, unsigned int offset) +{ + return (readq((io->addr)+(offset * io->regspacing)) >> io->regshift) + & 0xff; +} + +static void mem_outq(const struct si_sm_io *io, unsigned int offset, + unsigned char b) +{ + writeq(b << io->regshift, (io->addr)+(offset * io->regspacing)); +} +#endif + +static void mem_region_cleanup(struct si_sm_io *io, int num) +{ + unsigned long addr = io->addr_data; + int idx; + + for (idx = 0; idx < num; idx++) + release_mem_region(addr + idx * io->regspacing, + io->regsize); +} + +static void mem_cleanup(struct si_sm_io *io) +{ + if (io->addr) { + iounmap(io->addr); + mem_region_cleanup(io, io->io_size); + } +} + +int ipmi_si_mem_setup(struct si_sm_io *io) +{ + unsigned long addr = io->addr_data; + int mapsize, idx; + + if (!addr) + return -ENODEV; + + io->io_cleanup = mem_cleanup; + + /* + * Figure out the actual readb/readw/readl/etc routine to use based + * upon the register size. + */ + switch (io->regsize) { + case 1: + io->inputb = intf_mem_inb; + io->outputb = intf_mem_outb; + break; + case 2: + io->inputb = intf_mem_inw; + io->outputb = intf_mem_outw; + break; + case 4: + io->inputb = intf_mem_inl; + io->outputb = intf_mem_outl; + break; +#ifdef readq + case 8: + io->inputb = mem_inq; + io->outputb = mem_outq; + break; +#endif + default: + dev_warn(io->dev, "Invalid register size: %d\n", + io->regsize); + return -EINVAL; + } + + /* + * Some BIOSes reserve disjoint memory regions in their ACPI + * tables. This causes problems when trying to request the + * entire region. Therefore we must request each register + * separately. + */ + for (idx = 0; idx < io->io_size; idx++) { + if (request_mem_region(addr + idx * io->regspacing, + io->regsize, DEVICE_NAME) == NULL) { + /* Undo allocations */ + mem_region_cleanup(io, idx); + return -EIO; + } + } + + /* + * Calculate the total amount of memory to claim. This is an + * unusual looking calculation, but it avoids claiming any + * more memory than it has to. It will claim everything + * between the first address to the end of the last full + * register. + */ + mapsize = ((io->io_size * io->regspacing) + - (io->regspacing - io->regsize)); + io->addr = ioremap(addr, mapsize); + if (io->addr == NULL) { + mem_region_cleanup(io, io->io_size); + return -EIO; + } + return 0; +} diff --git a/drivers/char/ipmi/ipmi_si_port_io.c b/drivers/char/ipmi/ipmi_si_port_io.c new file mode 100644 index 000000000000..e5ce174fbeeb --- /dev/null +++ b/drivers/char/ipmi/ipmi_si_port_io.c @@ -0,0 +1,112 @@ + +#include +#include "ipmi_si.h" + +static unsigned char port_inb(const struct si_sm_io *io, unsigned int offset) +{ + unsigned int addr = io->addr_data; + + return inb(addr + (offset * io->regspacing)); +} + +static void port_outb(const struct si_sm_io *io, unsigned int offset, + unsigned char b) +{ + unsigned int addr = io->addr_data; + + outb(b, addr + (offset * io->regspacing)); +} + +static unsigned char port_inw(const struct si_sm_io *io, unsigned int offset) +{ + unsigned int addr = io->addr_data; + + return (inw(addr + (offset * io->regspacing)) >> io->regshift) & 0xff; +} + +static void port_outw(const struct si_sm_io *io, unsigned int offset, + unsigned char b) +{ + unsigned int addr = io->addr_data; + + outw(b << io->regshift, addr + (offset * io->regspacing)); +} + +static unsigned char port_inl(const struct si_sm_io *io, unsigned int offset) +{ + unsigned int addr = io->addr_data; + + return (inl(addr + (offset * io->regspacing)) >> io->regshift) & 0xff; +} + +static void port_outl(const struct si_sm_io *io, unsigned int offset, + unsigned char b) +{ + unsigned int addr = io->addr_data; + + outl(b << io->regshift, addr+(offset * io->regspacing)); +} + +static void port_cleanup(struct si_sm_io *io) +{ + unsigned int addr = io->addr_data; + int idx; + + if (addr) { + for (idx = 0; idx < io->io_size; idx++) + release_region(addr + idx * io->regspacing, + io->regsize); + } +} + +int ipmi_si_port_setup(struct si_sm_io *io) +{ + unsigned int addr = io->addr_data; + int idx; + + if (!addr) + return -ENODEV; + + io->io_cleanup = port_cleanup; + + /* + * Figure out the actual inb/inw/inl/etc routine to use based + * upon the register size. + */ + switch (io->regsize) { + case 1: + io->inputb = port_inb; + io->outputb = port_outb; + break; + case 2: + io->inputb = port_inw; + io->outputb = port_outw; + break; + case 4: + io->inputb = port_inl; + io->outputb = port_outl; + break; + default: + dev_warn(io->dev, "Invalid register size: %d\n", + io->regsize); + return -EINVAL; + } + + /* + * Some BIOSes reserve disjoint I/O regions in their ACPI + * tables. This causes problems when trying to register the + * entire I/O region. Therefore we must register each I/O + * port separately. + */ + for (idx = 0; idx < io->io_size; idx++) { + if (request_region(addr + idx * io->regspacing, + io->regsize, DEVICE_NAME) == NULL) { + /* Undo allocations */ + while (idx--) + release_region(addr + idx * io->regspacing, + io->regsize); + return -EIO; + } + } + return 0; +} From 67f4fb025d8e2189f91f6ccfc8f62f76f56f889d Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Tue, 12 Sep 2017 23:35:39 -0500 Subject: [PATCH 39/48] ipmi_si: remove ipmi_smi_alloc() function It's only used in one place now, so it's overkill. Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_si_intf.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index d24cd5de09d0..3758560a6ab2 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -1302,15 +1302,6 @@ int ipmi_std_irq_setup(struct si_sm_io *io) return rv; } -static struct smi_info *smi_info_alloc(void) -{ - struct smi_info *info = kzalloc(sizeof(*info), GFP_KERNEL); - - if (info) - spin_lock_init(&info->si_lock); - return info; -} - static int wait_for_msg_done(struct smi_info *smi_info) { enum si_sm_result smi_result; @@ -1902,9 +1893,10 @@ int ipmi_si_add_smi(struct si_sm_io *io) } } - new_smi = smi_info_alloc(); + new_smi = kzalloc(sizeof(*new_smi), GFP_KERNEL); if (!new_smi) return -ENOMEM; + spin_lock_init(&new_smi->si_lock); new_smi->io = *io; From 3dd377b5b07707c1a37e9129b36eaa1a86ccf9cf Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Sat, 16 Sep 2017 14:53:12 -0500 Subject: [PATCH 40/48] ipmi_si: Add device attrs for the things in proc Create a device attribute for everything we show in proc, getting ready for removing the proc stuff. Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_si_intf.c | 104 ++++++++++++++++++++++++++++++- 1 file changed, 103 insertions(+), 1 deletion(-) diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 3758560a6ab2..6ce5b7c8cf93 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -1699,6 +1699,92 @@ static const struct file_operations smi_params_proc_ops = { .release = single_release, }; +#define IPMI_SI_ATTR(name) \ +static ssize_t ipmi_##name##_show(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ + struct smi_info *smi_info = dev_get_drvdata(dev); \ + \ + return snprintf(buf, 10, "%u\n", smi_get_stat(smi_info, name)); \ +} \ +static DEVICE_ATTR(name, S_IRUGO, ipmi_##name##_show, NULL) + +static ssize_t ipmi_type_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct smi_info *smi_info = dev_get_drvdata(dev); + + return snprintf(buf, 10, "%s\n", si_to_str[smi_info->io.si_type]); +} +static DEVICE_ATTR(type, S_IRUGO, ipmi_type_show, NULL); + +static ssize_t ipmi_interrupts_enabled_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct smi_info *smi_info = dev_get_drvdata(dev); + int enabled = smi_info->io.irq && !smi_info->interrupt_disabled; + + return snprintf(buf, 10, "%d\n", enabled); +} +static DEVICE_ATTR(interrupts_enabled, S_IRUGO, + ipmi_interrupts_enabled_show, NULL); + +IPMI_SI_ATTR(short_timeouts); +IPMI_SI_ATTR(long_timeouts); +IPMI_SI_ATTR(idles); +IPMI_SI_ATTR(interrupts); +IPMI_SI_ATTR(attentions); +IPMI_SI_ATTR(flag_fetches); +IPMI_SI_ATTR(hosed_count); +IPMI_SI_ATTR(complete_transactions); +IPMI_SI_ATTR(events); +IPMI_SI_ATTR(watchdog_pretimeouts); +IPMI_SI_ATTR(incoming_messages); + +static ssize_t ipmi_params_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct smi_info *smi_info = dev_get_drvdata(dev); + + return snprintf(buf, 200, + "%s,%s,0x%lx,rsp=%d,rsi=%d,rsh=%d,irq=%d,ipmb=%d\n", + si_to_str[smi_info->io.si_type], + addr_space_to_str[smi_info->io.addr_type], + smi_info->io.addr_data, + smi_info->io.regspacing, + smi_info->io.regsize, + smi_info->io.regshift, + smi_info->io.irq, + smi_info->io.slave_addr); +} +static DEVICE_ATTR(params, S_IRUGO, ipmi_params_show, NULL); + +static struct attribute *ipmi_si_dev_attrs[] = { + &dev_attr_type.attr, + &dev_attr_interrupts_enabled.attr, + &dev_attr_short_timeouts.attr, + &dev_attr_long_timeouts.attr, + &dev_attr_idles.attr, + &dev_attr_interrupts.attr, + &dev_attr_attentions.attr, + &dev_attr_flag_fetches.attr, + &dev_attr_hosed_count.attr, + &dev_attr_complete_transactions.attr, + &dev_attr_events.attr, + &dev_attr_watchdog_pretimeouts.attr, + &dev_attr_incoming_messages.attr, + &dev_attr_params.attr, + NULL +}; + +static const struct attribute_group ipmi_si_dev_attr_group = { + .attrs = ipmi_si_dev_attrs, +}; + /* * oem_data_avail_to_receive_msg_avail * @info - smi_info structure with msg_flags set @@ -2085,6 +2171,15 @@ static int try_smi_init(struct smi_info *new_smi) } } + dev_set_drvdata(new_smi->io.dev, new_smi); + rv = device_add_group(new_smi->io.dev, &ipmi_si_dev_attr_group); + if (rv) { + dev_err(new_smi->io.dev, + "Unable to add device attributes: error %d\n", + rv); + goto out_err_stop_timer; + } + rv = ipmi_register_smi(&handlers, new_smi, new_smi->io.dev, @@ -2093,7 +2188,7 @@ static int try_smi_init(struct smi_info *new_smi) dev_err(new_smi->io.dev, "Unable to register device: error %d\n", rv); - goto out_err_stop_timer; + goto out_err_remove_attrs; } rv = ipmi_smi_add_proc_entry(new_smi->intf, "type", @@ -2134,6 +2229,10 @@ static int try_smi_init(struct smi_info *new_smi) return 0; +out_err_remove_attrs: + device_remove_group(new_smi->io.dev, &ipmi_si_dev_attr_group); + dev_set_drvdata(new_smi->io.dev, NULL); + out_err_stop_timer: wait_for_timer_and_thread(new_smi); @@ -2274,6 +2373,9 @@ static void cleanup_one_si(struct smi_info *to_clean) } } + device_remove_group(to_clean->io.dev, &ipmi_si_dev_attr_group); + dev_set_drvdata(to_clean->io.dev, NULL); + list_del(&to_clean->link); /* From ac2673d56be609168c3f0792588c1f9ef5824041 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Sat, 16 Sep 2017 15:11:48 -0500 Subject: [PATCH 41/48] ipmi_ssif: Add device attrs for the things in proc Create a device attribute for everything we show in proc, getting ready for removing the proc stuff. Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_ssif.c | 76 ++++++++++++++++++++++++++++++++++- 1 file changed, 74 insertions(+), 2 deletions(-) diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c index dd716d06ce73..7b2d4000b11e 100644 --- a/drivers/char/ipmi/ipmi_ssif.c +++ b/drivers/char/ipmi/ipmi_ssif.c @@ -1173,6 +1173,61 @@ MODULE_PARM_DESC(trydmi, "Setting this to zero will disable the default scan of static DEFINE_MUTEX(ssif_infos_mutex); static LIST_HEAD(ssif_infos); +#define IPMI_SSIF_ATTR(name) \ +static ssize_t ipmi_##name##_show(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ + struct ssif_info *ssif_info = dev_get_drvdata(dev); \ + \ + return snprintf(buf, 10, "%u\n", ssif_get_stat(ssif_info, name));\ +} \ +static DEVICE_ATTR(name, S_IRUGO, ipmi_##name##_show, NULL) + +static ssize_t ipmi_type_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return snprintf(buf, 10, "ssif\n"); +} +static DEVICE_ATTR(type, S_IRUGO, ipmi_type_show, NULL); + +IPMI_SSIF_ATTR(sent_messages); +IPMI_SSIF_ATTR(sent_messages_parts); +IPMI_SSIF_ATTR(send_retries); +IPMI_SSIF_ATTR(send_errors); +IPMI_SSIF_ATTR(received_messages); +IPMI_SSIF_ATTR(received_message_parts); +IPMI_SSIF_ATTR(receive_retries); +IPMI_SSIF_ATTR(receive_errors); +IPMI_SSIF_ATTR(flag_fetches); +IPMI_SSIF_ATTR(hosed); +IPMI_SSIF_ATTR(events); +IPMI_SSIF_ATTR(watchdog_pretimeouts); +IPMI_SSIF_ATTR(alerts); + +static struct attribute *ipmi_ssif_dev_attrs[] = { + &dev_attr_type.attr, + &dev_attr_sent_messages.attr, + &dev_attr_sent_messages_parts.attr, + &dev_attr_send_retries.attr, + &dev_attr_send_errors.attr, + &dev_attr_received_messages.attr, + &dev_attr_received_message_parts.attr, + &dev_attr_receive_retries.attr, + &dev_attr_receive_errors.attr, + &dev_attr_flag_fetches.attr, + &dev_attr_hosed.attr, + &dev_attr_events.attr, + &dev_attr_watchdog_pretimeouts.attr, + &dev_attr_alerts.attr, + NULL +}; + +static const struct attribute_group ipmi_ssif_dev_attr_group = { + .attrs = ipmi_ssif_dev_attrs, +}; + static int ssif_remove(struct i2c_client *client) { struct ssif_info *ssif_info = i2c_get_clientdata(client); @@ -1193,6 +1248,9 @@ static int ssif_remove(struct i2c_client *client) } ssif_info->intf = NULL; + device_remove_group(&ssif_info->client->dev, &ipmi_ssif_dev_attr_group); + dev_set_drvdata(&ssif_info->client->dev, NULL); + /* make sure the driver is not looking for flags any more. */ while (ssif_info->ssif_state != SSIF_NORMAL) schedule_timeout(1); @@ -1665,13 +1723,23 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id) } } + dev_set_drvdata(&ssif_info->client->dev, ssif_info); + rv = device_add_group(&ssif_info->client->dev, + &ipmi_ssif_dev_attr_group); + if (rv) { + dev_err(&ssif_info->client->dev, + "Unable to add device attributes: error %d\n", + rv); + goto out; + } + rv = ipmi_register_smi(&ssif_info->handlers, ssif_info, &ssif_info->client->dev, slave_addr); if (rv) { pr_err(PFX "Unable to register device: error %d\n", rv); - goto out; + goto out_remove_attr; } rv = ipmi_smi_add_proc_entry(ssif_info->intf, "type", @@ -1707,8 +1775,12 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id) kfree(resp); return rv; - out_err_unreg: +out_err_unreg: ipmi_unregister_smi(ssif_info->intf); + +out_remove_attr: + device_remove_group(&ssif_info->client->dev, &ipmi_ssif_dev_attr_group); + dev_set_drvdata(&ssif_info->client->dev, NULL); goto out; } From 55f91cb6f1dfc873359674f35a8ffb1e78429d22 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Sat, 16 Sep 2017 15:51:25 -0500 Subject: [PATCH 42/48] ipmi: Make the IPMI proc interface configurable So we can remove it later. Signed-off-by: Corey Minyard --- drivers/char/ipmi/Kconfig | 8 ++++++ drivers/char/ipmi/ipmi_msghandler.c | 43 +++++++++++++++-------------- drivers/char/ipmi/ipmi_si_intf.c | 4 +++ drivers/char/ipmi/ipmi_ssif.c | 6 ++++ include/linux/ipmi_smi.h | 2 ++ 5 files changed, 42 insertions(+), 21 deletions(-) diff --git a/drivers/char/ipmi/Kconfig b/drivers/char/ipmi/Kconfig index 152ccefdaecb..3544abc0f9f9 100644 --- a/drivers/char/ipmi/Kconfig +++ b/drivers/char/ipmi/Kconfig @@ -22,6 +22,14 @@ config IPMI_DMI_DECODE if IPMI_HANDLER +config IPMI_PROC_INTERFACE + bool 'Provide an interface for IPMI stats in /proc (deprecated)' + depends on PROC_FS + default y + help + Do not use this any more, use sysfs for this info. It will be + removed in future kernel versions. + config IPMI_PANIC_EVENT bool 'Generate a panic event to all BMCs on a panic' help diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 1c8bef2e1dc1..fd3ac6b50412 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -132,9 +132,9 @@ module_param_cb(panic_op, &panic_op_ops, NULL, 0600); MODULE_PARM_DESC(panic_op, "Sets if the IPMI driver will attempt to store panic information in the event log in the event of a panic. Set to 'none' for no, 'event' for a single event, or 'string' for a generic event and the panic string in IPMI OEM events."); -#ifdef CONFIG_PROC_FS +#ifdef CONFIG_IPMI_PROC_INTERFACE static struct proc_dir_entry *proc_ipmi_root; -#endif /* CONFIG_PROC_FS */ +#endif /* CONFIG_IPMI_PROC_INTERFACE */ /* Remain in auto-maintenance mode for this amount of time (in ms). */ #define IPMI_MAINTENANCE_MODE_TIMEOUT 30000 @@ -267,7 +267,7 @@ struct ipmi_my_addrinfo { unsigned char lun; }; -#ifdef CONFIG_PROC_FS +#ifdef CONFIG_IPMI_PROC_INTERFACE struct ipmi_proc_entry { char *name; struct ipmi_proc_entry *next; @@ -449,10 +449,13 @@ struct ipmi_smi { const struct ipmi_smi_handlers *handlers; void *send_info; -#ifdef CONFIG_PROC_FS +#ifdef CONFIG_IPMI_PROC_INTERFACE /* A list of proc entries for this interface. */ struct mutex proc_entry_lock; struct ipmi_proc_entry *proc_entries; + + struct proc_dir_entry *proc_dir; + char proc_dir_name[10]; #endif /* Driver-model device for the system interface. */ @@ -542,10 +545,6 @@ struct ipmi_smi { struct ipmi_my_addrinfo addrinfo[IPMI_MAX_CHANNELS]; bool channels_ready; - /* Proc FS stuff. */ - struct proc_dir_entry *proc_dir; - char proc_dir_name[10]; - atomic_t stats[IPMI_NUM_STATS]; /* @@ -2363,7 +2362,7 @@ static int bmc_get_device_id(ipmi_smi_t intf, struct bmc_device *bmc, return __bmc_get_device_id(intf, bmc, id, guid_set, guid, -1); } -#ifdef CONFIG_PROC_FS +#ifdef CONFIG_IPMI_PROC_INTERFACE static int smi_ipmb_proc_show(struct seq_file *m, void *v) { ipmi_smi_t intf = m->private; @@ -2492,14 +2491,12 @@ static const struct file_operations smi_stats_proc_ops = { .llseek = seq_lseek, .release = single_release, }; -#endif /* CONFIG_PROC_FS */ int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name, const struct file_operations *proc_ops, void *data) { int rv = 0; -#ifdef CONFIG_PROC_FS struct proc_dir_entry *file; struct ipmi_proc_entry *entry; @@ -2525,7 +2522,6 @@ int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name, smi->proc_entries = entry; mutex_unlock(&smi->proc_entry_lock); } -#endif /* CONFIG_PROC_FS */ return rv; } @@ -2535,7 +2531,6 @@ static int add_proc_entries(ipmi_smi_t smi, int num) { int rv = 0; -#ifdef CONFIG_PROC_FS sprintf(smi->proc_dir_name, "%d", num); smi->proc_dir = proc_mkdir(smi->proc_dir_name, proc_ipmi_root); if (!smi->proc_dir) @@ -2555,14 +2550,12 @@ static int add_proc_entries(ipmi_smi_t smi, int num) rv = ipmi_smi_add_proc_entry(smi, "version", &smi_version_proc_ops, smi); -#endif /* CONFIG_PROC_FS */ return rv; } static void remove_proc_entries(ipmi_smi_t smi) { -#ifdef CONFIG_PROC_FS struct ipmi_proc_entry *entry; mutex_lock(&smi->proc_entry_lock); @@ -2576,8 +2569,8 @@ static void remove_proc_entries(ipmi_smi_t smi) } mutex_unlock(&smi->proc_entry_lock); remove_proc_entry(smi->proc_dir_name, proc_ipmi_root); -#endif /* CONFIG_PROC_FS */ } +#endif /* CONFIG_IPMI_PROC_INTERFACE */ static ssize_t device_id_show(struct device *dev, struct device_attribute *attr, @@ -3419,7 +3412,7 @@ int ipmi_register_smi(const struct ipmi_smi_handlers *handlers, intf->seq_table[j].seqid = 0; } intf->curr_seq = 0; -#ifdef CONFIG_PROC_FS +#ifdef CONFIG_IPMI_PROC_INTERFACE mutex_init(&intf->proc_entry_lock); #endif spin_lock_init(&intf->waiting_rcv_msgs_lock); @@ -3443,7 +3436,9 @@ int ipmi_register_smi(const struct ipmi_smi_handlers *handlers, for (i = 0; i < IPMI_NUM_STATS; i++) atomic_set(&intf->stats[i], 0); +#ifdef CONFIG_IPMI_PROC_INTERFACE intf->proc_dir = NULL; +#endif mutex_lock(&smi_watchers_mutex); mutex_lock(&ipmi_interfaces_mutex); @@ -3479,13 +3474,17 @@ int ipmi_register_smi(const struct ipmi_smi_handlers *handlers, if (rv) goto out; +#ifdef CONFIG_IPMI_PROC_INTERFACE rv = add_proc_entries(intf, i); +#endif out: if (rv) { ipmi_bmc_unregister(intf); +#ifdef CONFIG_IPMI_PROC_INTERFACE if (intf->proc_dir) remove_proc_entries(intf); +#endif intf->handlers = NULL; list_del_rcu(&intf->link); mutex_unlock(&ipmi_interfaces_mutex); @@ -3590,7 +3589,9 @@ int ipmi_unregister_smi(ipmi_smi_t intf) intf->handlers = NULL; mutex_unlock(&ipmi_interfaces_mutex); +#ifdef CONFIG_IPMI_PROC_INTERFACE remove_proc_entries(intf); +#endif ipmi_bmc_unregister(intf); /* @@ -5170,7 +5171,7 @@ static int ipmi_init_msghandler(void) printk(KERN_INFO "ipmi message handler version " IPMI_DRIVER_VERSION "\n"); -#ifdef CONFIG_PROC_FS +#ifdef CONFIG_IPMI_PROC_INTERFACE proc_ipmi_root = proc_mkdir("ipmi", NULL); if (!proc_ipmi_root) { printk(KERN_ERR PFX "Unable to create IPMI proc dir"); @@ -5178,7 +5179,7 @@ static int ipmi_init_msghandler(void) return -ENOMEM; } -#endif /* CONFIG_PROC_FS */ +#endif /* CONFIG_IPMI_PROC_INTERFACE */ setup_timer(&ipmi_timer, ipmi_timeout, 0); mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES); @@ -5218,9 +5219,9 @@ static void __exit cleanup_ipmi(void) atomic_inc(&stop_operation); del_timer_sync(&ipmi_timer); -#ifdef CONFIG_PROC_FS +#ifdef CONFIG_IPMI_PROC_INTERFACE proc_remove(proc_ipmi_root); -#endif /* CONFIG_PROC_FS */ +#endif /* CONFIG_IPMI_PROC_INTERFACE */ driver_unregister(&ipmidriver.driver); diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 6ce5b7c8cf93..efc8ee9b5071 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -1605,6 +1605,7 @@ out: return rv; } +#ifdef CONFIG_IPMI_PROC_INTERFACE static int smi_type_proc_show(struct seq_file *m, void *v) { struct smi_info *smi = m->private; @@ -1698,6 +1699,7 @@ static const struct file_operations smi_params_proc_ops = { .llseek = seq_lseek, .release = single_release, }; +#endif #define IPMI_SI_ATTR(name) \ static ssize_t ipmi_##name##_show(struct device *dev, \ @@ -2191,6 +2193,7 @@ static int try_smi_init(struct smi_info *new_smi) goto out_err_remove_attrs; } +#ifdef CONFIG_IPMI_PROC_INTERFACE rv = ipmi_smi_add_proc_entry(new_smi->intf, "type", &smi_type_proc_ops, new_smi); @@ -2217,6 +2220,7 @@ static int try_smi_init(struct smi_info *new_smi) "Unable to create proc entry: %d\n", rv); goto out_err_stop_timer; } +#endif /* Don't increment till we know we have succeeded. */ smi_num++; diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c index 7b2d4000b11e..aadec879d052 100644 --- a/drivers/char/ipmi/ipmi_ssif.c +++ b/drivers/char/ipmi/ipmi_ssif.c @@ -1344,6 +1344,7 @@ static int ssif_detect(struct i2c_client *client, struct i2c_board_info *info) return rv; } +#ifdef CONFIG_IPMI_PROC_INTERFACE static int smi_type_proc_show(struct seq_file *m, void *v) { seq_puts(m, "ssif\n"); @@ -1407,6 +1408,7 @@ static const struct file_operations smi_stats_proc_ops = { .llseek = seq_lseek, .release = single_release, }; +#endif static int strcmp_nospace(char *s1, char *s2) { @@ -1742,6 +1744,7 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id) goto out_remove_attr; } +#ifdef CONFIG_IPMI_PROC_INTERFACE rv = ipmi_smi_add_proc_entry(ssif_info->intf, "type", &smi_type_proc_ops, ssif_info); @@ -1757,6 +1760,7 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id) pr_err(PFX "Unable to create proc entry: %d\n", rv); goto out_err_unreg; } +#endif out: if (rv) { @@ -1775,8 +1779,10 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id) kfree(resp); return rv; +#ifdef CONFIG_IPMI_PROC_INTERFACE out_err_unreg: ipmi_unregister_smi(ssif_info->intf); +#endif out_remove_attr: device_remove_group(&ssif_info->client->dev, &ipmi_ssif_dev_attr_group); diff --git a/include/linux/ipmi_smi.h b/include/linux/ipmi_smi.h index 97771e36b7f0..5be51281e14d 100644 --- a/include/linux/ipmi_smi.h +++ b/include/linux/ipmi_smi.h @@ -241,11 +241,13 @@ static inline void ipmi_free_smi_msg(struct ipmi_smi_msg *msg) msg->done(msg); } +#ifdef CONFIG_IPMI_PROC_INTERFACE /* Allow the lower layer to add things to the proc filesystem directory for this interface. Note that the entry will automatically be dstroyed when the interface is destroyed. */ int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name, const struct file_operations *proc_ops, void *data); +#endif #endif /* __LINUX_IPMI_SMI_H */ From 95e300c052fd9dbb05f289a912c138ed03320ec5 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Mon, 18 Sep 2017 12:38:17 -0500 Subject: [PATCH 43/48] ipmi: Make the DMI probe into a generic platform probe Rework the DMI probe function to be a generic platform probe, and then rework the DMI code (and a few other things) to use the more generic information. This is so other things can declare platform IPMI devices. Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_dmi.c | 70 +++++++++++++------ drivers/char/ipmi/ipmi_dmi.h | 8 +-- drivers/char/ipmi/ipmi_msghandler.c | 2 +- drivers/char/ipmi/ipmi_si_intf.c | 2 +- drivers/char/ipmi/ipmi_si_platform.c | 101 ++++++++++++--------------- drivers/char/ipmi/ipmi_si_sm.h | 2 +- drivers/char/ipmi/ipmi_ssif.c | 12 +--- include/linux/ipmi.h | 2 +- 8 files changed, 104 insertions(+), 95 deletions(-) diff --git a/drivers/char/ipmi/ipmi_dmi.c b/drivers/char/ipmi/ipmi_dmi.c index 2a84401dea05..d08d41903b0f 100644 --- a/drivers/char/ipmi/ipmi_dmi.c +++ b/drivers/char/ipmi/ipmi_dmi.c @@ -8,10 +8,16 @@ #include #include #include +#include "ipmi_si_sm.h" #include "ipmi_dmi.h" +#define IPMI_DMI_TYPE_KCS 0x01 +#define IPMI_DMI_TYPE_SMIC 0x02 +#define IPMI_DMI_TYPE_BT 0x03 +#define IPMI_DMI_TYPE_SSIF 0x04 + struct ipmi_dmi_info { - int type; + enum si_type si_type; u32 flags; unsigned long addr; u8 slave_addr; @@ -22,6 +28,15 @@ static struct ipmi_dmi_info *ipmi_dmi_infos; static int ipmi_dmi_nr __initdata; +#define set_prop_entry(_p_, _name_, type, val) \ +do { \ + struct property_entry *_p = &_p_; \ + _p->name = _name_; \ + _p->length = sizeof(type); \ + _p->is_string = false; \ + _p->value.type##_data = val; \ +} while(0) + static void __init dmi_add_platform_ipmi(unsigned long base_addr, u32 flags, u8 slave_addr, @@ -32,27 +47,14 @@ static void __init dmi_add_platform_ipmi(unsigned long base_addr, struct platform_device *pdev; struct resource r[4]; unsigned int num_r = 1, size; - struct property_entry p[4] = { - PROPERTY_ENTRY_U8("slave-addr", slave_addr), - PROPERTY_ENTRY_U8("ipmi-type", type), - PROPERTY_ENTRY_U16("i2c-addr", base_addr), - { } - }; + struct property_entry p[5]; + unsigned int pidx = 0; char *name, *override; int rv; + enum si_type si_type; struct ipmi_dmi_info *info; - info = kmalloc(sizeof(*info), GFP_KERNEL); - if (!info) { - pr_warn("ipmi:dmi: Could not allocate dmi info\n"); - } else { - info->type = type; - info->flags = flags; - info->addr = base_addr; - info->slave_addr = slave_addr; - info->next = ipmi_dmi_infos; - ipmi_dmi_infos = info; - } + memset(p, 0, sizeof(p)); name = "dmi-ipmi-si"; override = "ipmi_si"; @@ -62,19 +64,42 @@ static void __init dmi_add_platform_ipmi(unsigned long base_addr, override = "ipmi_ssif"; offset = 1; size = 1; + si_type = SI_TYPE_INVALID; break; case IPMI_DMI_TYPE_BT: size = 3; + si_type = SI_BT; break; case IPMI_DMI_TYPE_KCS: + size = 2; + si_type = SI_KCS; + break; case IPMI_DMI_TYPE_SMIC: size = 2; + si_type = SI_SMIC; break; default: pr_err("ipmi:dmi: Invalid IPMI type: %d", type); return; } + if (si_type != SI_TYPE_INVALID) + set_prop_entry(p[pidx++], "ipmi-type", u8, si_type); + set_prop_entry(p[pidx++], "slave-addr", u8, slave_addr); + set_prop_entry(p[pidx++], "addr-source", u8, SI_SMBIOS); + + info = kmalloc(sizeof(*info), GFP_KERNEL); + if (!info) { + pr_warn("ipmi:dmi: Could not allocate dmi info\n"); + } else { + info->si_type = si_type; + info->flags = flags; + info->addr = base_addr; + info->slave_addr = slave_addr; + info->next = ipmi_dmi_infos; + ipmi_dmi_infos = info; + } + pdev = platform_device_alloc(name, ipmi_dmi_nr); if (!pdev) { pr_err("ipmi:dmi: Error allocation IPMI platform device"); @@ -82,8 +107,10 @@ static void __init dmi_add_platform_ipmi(unsigned long base_addr, } pdev->driver_override = override; - if (type == IPMI_DMI_TYPE_SSIF) + if (type == IPMI_DMI_TYPE_SSIF) { + set_prop_entry(p[pidx++], "i2c-addr", u16, base_addr); goto add_properties; + } memset(r, 0, sizeof(r)); @@ -151,12 +178,13 @@ err: * This function allows an ACPI-specified IPMI device to look up the * slave address from the DMI table. */ -int ipmi_dmi_get_slave_addr(int type, u32 flags, unsigned long base_addr) +int ipmi_dmi_get_slave_addr(enum si_type si_type, u32 flags, + unsigned long base_addr) { struct ipmi_dmi_info *info = ipmi_dmi_infos; while (info) { - if (info->type == type && + if (info->si_type == si_type && info->flags == flags && info->addr == base_addr) return info->slave_addr; diff --git a/drivers/char/ipmi/ipmi_dmi.h b/drivers/char/ipmi/ipmi_dmi.h index 0a1afe5ceb1e..062015b8f520 100644 --- a/drivers/char/ipmi/ipmi_dmi.h +++ b/drivers/char/ipmi/ipmi_dmi.h @@ -2,11 +2,7 @@ * DMI defines for use by IPMI */ -#define IPMI_DMI_TYPE_KCS 0x01 -#define IPMI_DMI_TYPE_SMIC 0x02 -#define IPMI_DMI_TYPE_BT 0x03 -#define IPMI_DMI_TYPE_SSIF 0x04 - #ifdef CONFIG_IPMI_DMI_DECODE -int ipmi_dmi_get_slave_addr(int type, u32 flags, unsigned long base_addr); +int ipmi_dmi_get_slave_addr(enum si_type si_type, u32 flags, + unsigned long base_addr); #endif diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index fd3ac6b50412..9d1eaf70f406 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -594,7 +594,7 @@ static DEFINE_MUTEX(smi_watchers_mutex); static const char * const addr_src_to_str[] = { "invalid", "hotmod", "hardcoded", "SPMI", "ACPI", "SMBIOS", "PCI", - "device-tree" + "device-tree", "platform" }; const char *ipmi_addr_src_to_str(enum ipmi_addr_src src) diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index efc8ee9b5071..55e0c42bee4d 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -89,7 +89,7 @@ enum si_intf_state { #define IPMI_BT_INTMASK_CLEAR_IRQ_BIT 2 #define IPMI_BT_INTMASK_ENABLE_IRQ_BIT 1 -static const char * const si_to_str[] = { "kcs", "smic", "bt" }; +static const char * const si_to_str[] = { "invalid", "kcs", "smic", "bt" }; static int initialized; diff --git a/drivers/char/ipmi/ipmi_si_platform.c b/drivers/char/ipmi/ipmi_si_platform.c index cf5c3e5e72e2..9573f1116450 100644 --- a/drivers/char/ipmi/ipmi_si_platform.c +++ b/drivers/char/ipmi/ipmi_si_platform.c @@ -6,14 +6,13 @@ */ #include #include -#include "ipmi_dmi.h" -#include #include #include #include #include #include #include "ipmi_si.h" +#include "ipmi_dmi.h" #define PFX "ipmi_platform: " @@ -21,19 +20,29 @@ static bool si_tryplatform = true; #ifdef CONFIG_ACPI static bool si_tryacpi = true; #endif +#ifdef CONFIG_OF +static bool si_tryopenfirmware = true; +#endif #ifdef CONFIG_DMI static bool si_trydmi = true; +#else +static bool si_trydmi = false; #endif module_param_named(tryplatform, si_tryplatform, bool, 0); MODULE_PARM_DESC(tryplatform, "Setting this to zero will disable the" " default scan of the interfaces identified via platform" - " interfaces like openfirmware"); + " interfaces besides ACPI, OpenFirmware, and DMI"); #ifdef CONFIG_ACPI module_param_named(tryacpi, si_tryacpi, bool, 0); MODULE_PARM_DESC(tryacpi, "Setting this to zero will disable the" " default scan of the interfaces identified via ACPI"); #endif +#ifdef CONFIG_OF +module_param_named(tryopenfirmware, si_tryopenfirmware, bool, 0); +MODULE_PARM_DESC(tryacpi, "Setting this to zero will disable the" + " default scan of the interfaces identified via OpenFirmware"); +#endif #ifdef CONFIG_DMI module_param_named(trydmi, si_trydmi, bool, 0); MODULE_PARM_DESC(trydmi, "Setting this to zero will disable the" @@ -235,7 +244,6 @@ static void spmi_find_bmc(void) } #endif -#if defined(CONFIG_DMI) || defined(CONFIG_ACPI) static struct resource * ipmi_get_info_from_resources(struct platform_device *pdev, struct si_sm_io *io) @@ -271,48 +279,52 @@ ipmi_get_info_from_resources(struct platform_device *pdev, return res; } -#endif - -#ifdef CONFIG_DMI -static int dmi_ipmi_probe(struct platform_device *pdev) +static int platform_ipmi_probe(struct platform_device *pdev) { struct si_sm_io io; - u8 type, slave_addr; + u8 type, slave_addr, addr_source; int rv; - if (!si_trydmi) - return -ENODEV; + rv = device_property_read_u8(&pdev->dev, "addr-source", &addr_source); + if (rv) + addr_source = SI_PLATFORM; + if (addr_source >= SI_LAST) + return -EINVAL; + + if (addr_source == SI_SMBIOS) { + if (!si_trydmi) + return -ENODEV; + } else { + if (!si_tryplatform) + return -ENODEV; + } rv = device_property_read_u8(&pdev->dev, "ipmi-type", &type); if (rv) return -ENODEV; memset(&io, 0, sizeof(io)); - io.addr_source = SI_SMBIOS; - pr_info(PFX "probing via SMBIOS\n"); + io.addr_source = addr_source; + dev_info(&pdev->dev, PFX "probing via %s\n", + ipmi_addr_src_to_str(addr_source)); switch (type) { - case IPMI_DMI_TYPE_KCS: - io.si_type = SI_KCS; - break; - case IPMI_DMI_TYPE_SMIC: - io.si_type = SI_SMIC; - break; - case IPMI_DMI_TYPE_BT: - io.si_type = SI_BT; + case SI_KCS: + case SI_SMIC: + case SI_BT: + io.si_type = type; break; default: + dev_err(&pdev->dev, "ipmi-type property is invalid\n"); return -EINVAL; } - if (!ipmi_get_info_from_resources(pdev, &io)) { - rv = -EINVAL; - goto err_free; - } + if (!ipmi_get_info_from_resources(pdev, &io)) + return -EINVAL; rv = device_property_read_u8(&pdev->dev, "slave-addr", &slave_addr); if (rv) { - dev_warn(&pdev->dev, "device has no slave-addr property"); + dev_warn(&pdev->dev, "device has no slave-addr property\n"); io.slave_addr = 0x20; } else { io.slave_addr = slave_addr; @@ -333,16 +345,7 @@ static int dmi_ipmi_probe(struct platform_device *pdev) ipmi_si_add_smi(&io); return 0; - -err_free: - return rv; } -#else -static int dmi_ipmi_probe(struct platform_device *pdev) -{ - return -ENODEV; -} -#endif /* CONFIG_DMI */ #ifdef CONFIG_OF static const struct of_device_id of_ipmi_match[] = { @@ -366,6 +369,9 @@ static int of_ipmi_probe(struct platform_device *pdev) int ret; int proplen; + if (!si_tryopenfirmware) + return -ENODEV; + dev_info(&pdev->dev, "probing via device tree\n"); match = of_match_device(of_ipmi_match, &pdev->dev); @@ -436,25 +442,12 @@ static int find_slave_address(struct si_sm_io *io, int slave_addr) { #ifdef CONFIG_IPMI_DMI_DECODE if (!slave_addr) { - int type = -1; u32 flags = IORESOURCE_IO; - switch (io->si_type) { - case SI_KCS: - type = IPMI_DMI_TYPE_KCS; - break; - case SI_BT: - type = IPMI_DMI_TYPE_BT; - break; - case SI_SMIC: - type = IPMI_DMI_TYPE_SMIC; - break; - } - if (io->addr_type == IPMI_MEM_ADDR_SPACE) flags = IORESOURCE_MEM; - slave_addr = ipmi_dmi_get_slave_addr(type, flags, + slave_addr = ipmi_dmi_get_slave_addr(io->si_type, flags, io->addr_data); } #endif @@ -563,7 +556,7 @@ static int ipmi_probe(struct platform_device *pdev) if (acpi_ipmi_probe(pdev) == 0) return 0; - return dmi_ipmi_probe(pdev); + return platform_ipmi_probe(pdev); } static int ipmi_remove(struct platform_device *pdev) @@ -583,11 +576,9 @@ struct platform_driver ipmi_platform_driver = { void ipmi_si_platform_init(void) { - if (si_tryplatform) { - int rv = platform_driver_register(&ipmi_platform_driver); - if (rv) - pr_err(PFX "Unable to register driver: %d\n", rv); - } + int rv = platform_driver_register(&ipmi_platform_driver); + if (rv) + pr_err(PFX "Unable to register driver: %d\n", rv); #ifdef CONFIG_ACPI if (si_tryacpi) diff --git a/drivers/char/ipmi/ipmi_si_sm.h b/drivers/char/ipmi/ipmi_si_sm.h index fbf5bfccde2e..aa8d88ab4433 100644 --- a/drivers/char/ipmi/ipmi_si_sm.h +++ b/drivers/char/ipmi/ipmi_si_sm.h @@ -43,7 +43,7 @@ struct si_sm_data; enum si_type { - SI_KCS, SI_SMIC, SI_BT + SI_TYPE_INVALID, SI_KCS, SI_SMIC, SI_BT }; /* diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c index aadec879d052..466b3a1c0adf 100644 --- a/drivers/char/ipmi/ipmi_ssif.c +++ b/drivers/char/ipmi/ipmi_ssif.c @@ -53,6 +53,7 @@ #include #include #include +#include "ipmi_si_sm.h" #include "ipmi_dmi.h" #define PFX "ipmi_ssif: " @@ -1482,7 +1483,7 @@ static int find_slave_address(struct i2c_client *client, int slave_addr) #ifdef CONFIG_IPMI_DMI_DECODE if (!slave_addr) slave_addr = ipmi_dmi_get_slave_addr( - IPMI_DMI_TYPE_SSIF, + SI_TYPE_INVALID, i2c_adapter_id(client->adapter), client->addr); #endif @@ -2013,20 +2014,13 @@ static void spmi_find_bmc(void) { } #ifdef CONFIG_DMI static int dmi_ipmi_probe(struct platform_device *pdev) { - u8 type, slave_addr = 0; + u8 slave_addr = 0; u16 i2c_addr; int rv; if (!ssif_trydmi) return -ENODEV; - rv = device_property_read_u8(&pdev->dev, "ipmi-type", &type); - if (rv) - return -ENODEV; - - if (type != IPMI_DMI_TYPE_SSIF) - return -ENODEV; - rv = device_property_read_u16(&pdev->dev, "i2c-addr", &i2c_addr); if (rv) { dev_warn(&pdev->dev, PFX "No i2c-addr property\n"); diff --git a/include/linux/ipmi.h b/include/linux/ipmi.h index 80fc3f798984..f4ffacf4fe9d 100644 --- a/include/linux/ipmi.h +++ b/include/linux/ipmi.h @@ -277,7 +277,7 @@ int ipmi_validate_addr(struct ipmi_addr *addr, int len); */ enum ipmi_addr_src { SI_INVALID = 0, SI_HOTMOD, SI_HARDCODED, SI_SPMI, SI_ACPI, SI_SMBIOS, - SI_PCI, SI_DEVICETREE, SI_LAST + SI_PCI, SI_DEVICETREE, SI_PLATFORM, SI_LAST }; const char *ipmi_addr_src_to_str(enum ipmi_addr_src src); From 106a846102b86a55359afaeec9b424928db7259c Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Mon, 18 Sep 2017 13:26:33 -0500 Subject: [PATCH 44/48] ipmi: Clean up some print operations Get rid of all printfs, using dev_xxx() if a device is available, pr_xxx() otherwise, and format long strings properly. Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_msghandler.c | 101 +++++++++++++--------------- 1 file changed, 45 insertions(+), 56 deletions(-) diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 9d1eaf70f406..c29d46bef6b3 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -1392,8 +1392,8 @@ int ipmi_set_gets_events(ipmi_user_t user, bool val) list_move_tail(&msg->link, &msgs); intf->waiting_events_count = 0; if (intf->event_msg_printed) { - printk(KERN_WARNING PFX "Event queue no longer" - " full\n"); + dev_warn(intf->si_dev, + PFX "Event queue no longer full\n"); intf->event_msg_printed = 0; } @@ -2137,7 +2137,8 @@ static void bmc_device_id_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg) if ((msg->addr.addr_type != IPMI_SYSTEM_INTERFACE_ADDR_TYPE) || (msg->msg.netfn != IPMI_NETFN_APP_RESPONSE) || (msg->msg.cmd != IPMI_GET_DEVICE_ID_CMD)) { - pr_warn(PFX "invalid device_id msg: addr_type=%d netfn=%x cmd=%x\n", + dev_warn(intf->si_dev, + PFX "invalid device_id msg: addr_type=%d netfn=%x cmd=%x\n", msg->addr.addr_type, msg->msg.netfn, msg->msg.cmd); return; } @@ -2145,7 +2146,8 @@ static void bmc_device_id_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg) rv = ipmi_demangle_device_id(msg->msg.netfn, msg->msg.cmd, msg->msg.data, msg->msg.data_len, &intf->bmc->fetch_id); if (rv) { - pr_warn(PFX "device id demangle failed: %d\n", rv); + dev_warn(intf->si_dev, + PFX "device id demangle failed: %d\n", rv); intf->bmc->dyn_id_set = 0; } else { /* @@ -2978,12 +2980,12 @@ static int __ipmi_bmc_register(ipmi_smi_t intf, list_add_tail(&intf->bmc_link, &bmc->intfs); mutex_unlock(&bmc->dyn_mutex); - printk(KERN_INFO - "ipmi: interfacing existing BMC (man_id: 0x%6.6x," - " prod_id: 0x%4.4x, dev_id: 0x%2.2x)\n", - bmc->id.manufacturer_id, - bmc->id.product_id, - bmc->id.device_id); + dev_info(intf->si_dev, + "ipmi: interfacing existing BMC (man_id: 0x%6.6x," + " prod_id: 0x%4.4x, dev_id: 0x%2.2x)\n", + bmc->id.manufacturer_id, + bmc->id.product_id, + bmc->id.device_id); } else { bmc = kzalloc(sizeof(*bmc), GFP_KERNEL); if (!bmc) { @@ -3018,15 +3020,14 @@ static int __ipmi_bmc_register(ipmi_smi_t intf, rv = platform_device_register(&bmc->pdev); if (rv) { - printk(KERN_ERR - "ipmi_msghandler:" - " Unable to register bmc device: %d\n", - rv); + dev_err(intf->si_dev, + PFX " Unable to register bmc device: %d\n", + rv); goto out_list_del; } - dev_info(intf->si_dev, "Found new BMC (man_id: 0x%6.6x, " - "prod_id: 0x%4.4x, dev_id: 0x%2.2x)\n", + dev_info(intf->si_dev, + "Found new BMC (man_id: 0x%6.6x, prod_id: 0x%4.4x, dev_id: 0x%2.2x)\n", bmc->id.manufacturer_id, bmc->id.product_id, bmc->id.device_id); @@ -3038,9 +3039,8 @@ static int __ipmi_bmc_register(ipmi_smi_t intf, */ rv = sysfs_create_link(&intf->si_dev->kobj, &bmc->pdev.dev.kobj, "bmc"); if (rv) { - printk(KERN_ERR - "ipmi_msghandler: Unable to create bmc symlink: %d\n", - rv); + dev_err(intf->si_dev, + PFX "Unable to create bmc symlink: %d\n", rv); goto out_put_bmc; } @@ -3049,9 +3049,8 @@ static int __ipmi_bmc_register(ipmi_smi_t intf, intf->my_dev_name = kasprintf(GFP_KERNEL, "ipmi%d", intf_num); if (!intf->my_dev_name) { rv = -ENOMEM; - printk(KERN_ERR - "ipmi_msghandler: allocate link from BMC: %d\n", - rv); + dev_err(intf->si_dev, + PFX "Unable to allocate link from BMC: %d\n", rv); goto out_unlink1; } @@ -3060,10 +3059,8 @@ static int __ipmi_bmc_register(ipmi_smi_t intf, if (rv) { kfree(intf->my_dev_name); intf->my_dev_name = NULL; - printk(KERN_ERR - "ipmi_msghandler:" - " Unable to create symlink to bmc: %d\n", - rv); + dev_err(intf->si_dev, + PFX "Unable to create symlink to bmc: %d\n", rv); goto out_free_my_dev_name; } @@ -3146,11 +3143,9 @@ static void guid_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg) if (msg->msg.data_len < 17) { bmc->dyn_guid_set = 0; - printk(KERN_WARNING PFX - "guid_handler: The GUID response from the BMC was too" - " short, it was %d but should have been 17. Assuming" - " GUID is not available.\n", - msg->msg.data_len); + dev_warn(intf->si_dev, + PFX "The GUID response from the BMC was too short, it was %d but should have been 17. Assuming GUID is not available.\n", + msg->msg.data_len); goto out; } @@ -3272,9 +3267,9 @@ channel_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg) if (rv) { /* Got an error somehow, just give up. */ - printk(KERN_WARNING PFX - "Error sending channel information for channel" - " %d: %d\n", intf->curr_channel, rv); + dev_warn(intf->si_dev, + PFX "Error sending channel information for channel %d: %d\n", + intf->curr_channel, rv); intf->channel_list = intf->wchannels + set; intf->channels_ready = true; @@ -4170,8 +4165,8 @@ static int handle_read_event_rsp(ipmi_smi_t intf, * There's too many things in the queue, discard this * message. */ - printk(KERN_WARNING PFX "Event queue full, discarding" - " incoming events\n"); + dev_warn(intf->si_dev, + PFX "Event queue full, discarding incoming events\n"); intf->event_msg_printed = 1; } @@ -4189,11 +4184,8 @@ static int handle_bmc_rsp(ipmi_smi_t intf, recv_msg = (struct ipmi_recv_msg *) msg->user_data; if (recv_msg == NULL) { - printk(KERN_WARNING - "IPMI message received with no owner. This\n" - "could be because of a malformed message, or\n" - "because of a hardware error. Contact your\n" - "hardware vender for assistance\n"); + dev_warn(intf->si_dev, + "IPMI message received with no owner. This could be because of a malformed message, or because of a hardware error. Contact your hardware vender for assistance\n"); return 0; } @@ -4247,9 +4239,9 @@ static int handle_one_recv_msg(ipmi_smi_t intf, #endif if (msg->rsp_size < 2) { /* Message is too small to be correct. */ - printk(KERN_WARNING PFX "BMC returned to small a message" - " for netfn %x cmd %x, got %d bytes\n", - (msg->data[0] >> 2) | 1, msg->data[1], msg->rsp_size); + dev_warn(intf->si_dev, + PFX "BMC returned to small a message for netfn %x cmd %x, got %d bytes\n", + (msg->data[0] >> 2) | 1, msg->data[1], msg->rsp_size); /* Generate an error response for the message. */ msg->rsp[0] = msg->data[0] | (1 << 2); @@ -4262,10 +4254,10 @@ static int handle_one_recv_msg(ipmi_smi_t intf, * The NetFN and Command in the response is not even * marginally correct. */ - printk(KERN_WARNING PFX "BMC returned incorrect response," - " expected netfn %x cmd %x, got netfn %x cmd %x\n", - (msg->data[0] >> 2) | 1, msg->data[1], - msg->rsp[0] >> 2, msg->rsp[1]); + dev_warn(intf->si_dev, + PFX "BMC returned incorrect response, expected netfn %x cmd %x, got netfn %x cmd %x\n", + (msg->data[0] >> 2) | 1, msg->data[1], + msg->rsp[0] >> 2, msg->rsp[1]); /* Generate an error response for the message. */ msg->rsp[0] = msg->data[0] | (1 << 2); @@ -5164,17 +5156,16 @@ static int ipmi_init_msghandler(void) rv = driver_register(&ipmidriver.driver); if (rv) { - printk(KERN_ERR PFX "Could not register IPMI driver\n"); + pr_err(PFX "Could not register IPMI driver\n"); return rv; } - printk(KERN_INFO "ipmi message handler version " - IPMI_DRIVER_VERSION "\n"); + pr_info("ipmi message handler version " IPMI_DRIVER_VERSION "\n"); #ifdef CONFIG_IPMI_PROC_INTERFACE proc_ipmi_root = proc_mkdir("ipmi", NULL); if (!proc_ipmi_root) { - printk(KERN_ERR PFX "Unable to create IPMI proc dir"); + pr_err(PFX "Unable to create IPMI proc dir"); driver_unregister(&ipmidriver.driver); return -ENOMEM; } @@ -5230,12 +5221,10 @@ static void __exit cleanup_ipmi(void) /* Check for buffer leaks. */ count = atomic_read(&smi_msg_inuse_count); if (count != 0) - printk(KERN_WARNING PFX "SMI message count %d at exit\n", - count); + pr_warn(PFX "SMI message count %d at exit\n", count); count = atomic_read(&recv_msg_inuse_count); if (count != 0) - printk(KERN_WARNING PFX "recv message count %d at exit\n", - count); + pr_warn(PFX "recv message count %d at exit\n", count); } module_exit(cleanup_ipmi); From daf9a4ebb742e1229d48bdddff8b91f73202d547 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Mon, 25 Sep 2017 13:19:57 +0530 Subject: [PATCH 45/48] ipmi: pr_err() strings should end with newlines pr_err() messages should terminated with a new-line to avoid other messages being concatenated onto the end. Signed-off-by: Arvind Yadav Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_dmi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/char/ipmi/ipmi_dmi.c b/drivers/char/ipmi/ipmi_dmi.c index d08d41903b0f..bb984176047b 100644 --- a/drivers/char/ipmi/ipmi_dmi.c +++ b/drivers/char/ipmi/ipmi_dmi.c @@ -79,7 +79,7 @@ static void __init dmi_add_platform_ipmi(unsigned long base_addr, si_type = SI_SMIC; break; default: - pr_err("ipmi:dmi: Invalid IPMI type: %d", type); + pr_err("ipmi:dmi: Invalid IPMI type: %d\n", type); return; } @@ -102,7 +102,7 @@ static void __init dmi_add_platform_ipmi(unsigned long base_addr, pdev = platform_device_alloc(name, ipmi_dmi_nr); if (!pdev) { - pr_err("ipmi:dmi: Error allocation IPMI platform device"); + pr_err("ipmi:dmi: Error allocation IPMI platform device\n"); return; } pdev->driver_override = override; @@ -267,7 +267,7 @@ static void __init dmi_decode_ipmi(const struct dmi_header *dm) offset = 16; break; default: - pr_err("ipmi:dmi: Invalid offset: 0"); + pr_err("ipmi:dmi: Invalid offset: 0\n"); return; } } From b79bba15b3f2cf3d7828d45de2d2f2d08fcbb523 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 28 Sep 2017 14:22:54 +0100 Subject: [PATCH 46/48] ipmi: remove redundant initialization of bmc The pointer bmc is being initialized and this initialized value is never being read, so this is assignment redundant and can be removed. Cleans up clang warning: warning: Value stored to 'bmc' during its initialization is never read Signed-off-by: Colin Ian King Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_msghandler.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index c29d46bef6b3..9de189db2cc3 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -2941,7 +2941,7 @@ static int __ipmi_bmc_register(ipmi_smi_t intf, bool guid_set, guid_t *guid, int intf_num) { int rv; - struct bmc_device *bmc = intf->bmc; + struct bmc_device *bmc; struct bmc_device *old_bmc; /* From c0a32fe13cd323ca9420500b16fd69589c9ba91e Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 17 Oct 2017 16:54:52 +0100 Subject: [PATCH 47/48] ipmi_si: fix memory leak on new_smi The error exit path omits kfree'ing the allocated new_smi, causing a memory leak. Fix this by kfree'ing new_smi. Detected by CoverityScan, CID#14582571 ("Resource Leak") Fixes: 7e030d6dff71 ("ipmi: Prefer ACPI system interfaces over SMBIOS ones") Signed-off-by: Colin Ian King Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_si_intf.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 55e0c42bee4d..4c16af64f73a 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -2004,6 +2004,7 @@ int ipmi_si_add_smi(struct si_sm_io *io) ipmi_addr_src_to_str(new_smi->io.addr_source), si_to_str[new_smi->io.si_type]); rv = -EBUSY; + kfree(new_smi); goto out_err; } } From d7e17fe4f7a7d961cc4375c7d868bd353a039bc7 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sun, 15 Oct 2017 22:30:11 +0200 Subject: [PATCH 48/48] ipmi_si: Delete an error message for a failed memory allocation in try_smi_init() Omit an extra message for a memory allocation failure in this function. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_si_intf.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 4c16af64f73a..71d33a1807e4 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -2096,7 +2096,6 @@ static int try_smi_init(struct smi_info *new_smi) /* Allocate the state machine's data and initialize it. */ new_smi->si_sm = kmalloc(new_smi->handlers->size(), GFP_KERNEL); if (!new_smi->si_sm) { - pr_err(PFX "Could not allocate state machine memory\n"); rv = -ENOMEM; goto out_err; }