From 6de65fcfdb51835789b245203d1bfc8d14cb1e06 Mon Sep 17 00:00:00 2001 From: Joeseph Chang Date: Mon, 27 Mar 2017 20:22:09 -0600 Subject: ipmi: Fix kernel panic at ipmi_ssif_thread() msg_written_handler() may set ssif_info->multi_data to NULL when using ipmitool to write fru. Before setting ssif_info->multi_data to NULL, add new local pointer "data_to_send" and store correct i2c data pointer to it to fix NULL pointer kernel panic and incorrect ssif_info->multi_pos. Signed-off-by: Joeseph Chang Signed-off-by: Corey Minyard Cc: stable@vger.kernel.org # 3.19- --- drivers/char/ipmi/ipmi_ssif.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c index cca6e5bc1cea..51ba67de862e 100644 --- a/drivers/char/ipmi/ipmi_ssif.c +++ b/drivers/char/ipmi/ipmi_ssif.c @@ -891,6 +891,7 @@ static void msg_written_handler(struct ssif_info *ssif_info, int result, * for details on the intricacies of this. */ int left; + unsigned char *data_to_send; ssif_inc_stat(ssif_info, sent_messages_parts); @@ -899,6 +900,7 @@ static void msg_written_handler(struct ssif_info *ssif_info, int result, left = 32; /* Length byte. */ ssif_info->multi_data[ssif_info->multi_pos] = left; + data_to_send = ssif_info->multi_data + ssif_info->multi_pos; ssif_info->multi_pos += left; if (left < 32) /* @@ -912,7 +914,7 @@ static void msg_written_handler(struct ssif_info *ssif_info, int result, rv = ssif_i2c_send(ssif_info, msg_written_handler, I2C_SMBUS_WRITE, SSIF_IPMI_MULTI_PART_REQUEST_MIDDLE, - ssif_info->multi_data + ssif_info->multi_pos, + data_to_send, I2C_SMBUS_BLOCK_DATA); if (rv < 0) { /* request failed, just return the error. */ -- cgit From 36cb82dabb09b29cce5850ee701bedaf5c1aa89d Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Fri, 24 Mar 2017 22:15:12 +0800 Subject: ipmi_ssif: use setup_timer Use setup_timer() instead of init_timer() to simplify the code. Signed-off-by: Geliang Tang Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_ssif.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c index 51ba67de862e..0b22a9be5029 100644 --- a/drivers/char/ipmi/ipmi_ssif.c +++ b/drivers/char/ipmi/ipmi_ssif.c @@ -1644,9 +1644,8 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id) spin_lock_init(&ssif_info->lock); ssif_info->ssif_state = SSIF_NORMAL; - init_timer(&ssif_info->retry_timer); - ssif_info->retry_timer.data = (unsigned long) ssif_info; - ssif_info->retry_timer.function = retry_timeout; + setup_timer(&ssif_info->retry_timer, retry_timeout, + (unsigned long)ssif_info); for (i = 0; i < SSIF_NUM_STATS; i++) atomic_set(&ssif_info->stats[i], 0); -- cgit From 7ecaff7733b50da8e02d22be6719069892633c53 Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Thu, 23 Mar 2017 00:31:12 +1030 Subject: ipmi: bt-bmc: Add ast2500 compatible string MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ast2500 SoCs contain the same IPMI BT device. Signed-off-by: Joel Stanley Reviewed-by: Cédric Le Goater Acked-by: Rob Herring Signed-off-by: Corey Minyard --- drivers/char/ipmi/bt-bmc.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/char') diff --git a/drivers/char/ipmi/bt-bmc.c b/drivers/char/ipmi/bt-bmc.c index d6f5d9eb102d..70d434bc1cbf 100644 --- a/drivers/char/ipmi/bt-bmc.c +++ b/drivers/char/ipmi/bt-bmc.c @@ -523,6 +523,7 @@ static int bt_bmc_remove(struct platform_device *pdev) static const struct of_device_id bt_bmc_match[] = { { .compatible = "aspeed,ast2400-ibt-bmc" }, + { .compatible = "aspeed,ast2500-ibt-bmc" }, { }, }; -- cgit From 3f724c408a7bcf25609f6a0102b835d5970cadd3 Mon Sep 17 00:00:00 2001 From: Tony Camuso Date: Mon, 10 Apr 2017 12:22:13 -0400 Subject: ipmi_si: use smi_num for init_name Commit 1abf71e moved the creation of new_smi->dev to earlier in the init sequence in order to provide infrastructure for log printing. However, the init_name was created with a hard-coded value of zero. This presents a problem in systems with more than one interface, producing a call trace in dmesg. To correct the problem, simply use smi_num instead of the hard-coded value of zero. Tested on a lenovo x3950. Signed-off-by: Tony Camuso There was actually a more general problem, the platform device wasn't being set correctly, either, and there was a possible (though extremely unlikely) race on smi_num. Add locks to clean up the race and use the proper value for the platform device, too. Tested on qemu in various configurations. Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_si_intf.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 2a7c425ddfa7..b2b618f066e0 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -1954,7 +1954,9 @@ static int hotmod_handler(const char *val, struct kernel_param *kp) kfree(info); 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; @@ -2042,8 +2044,10 @@ static int hardcode_find_bmc(void) info->slave_addr = slave_addrs[i]; if (!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); @@ -3492,6 +3496,11 @@ out_err: return rv; } +/* + * Try to start up an interface. Must be called with smi_infos_lock + * held, primarily to keep smi_num consistent, we only one to do these + * one at a time. + */ static int try_smi_init(struct smi_info *new_smi) { int rv = 0; @@ -3524,9 +3533,12 @@ static int try_smi_init(struct smi_info *new_smi) goto out_err; } + new_smi->intf_num = smi_num; + /* Do this early so it's available for logs. */ if (!new_smi->dev) { - init_name = kasprintf(GFP_KERNEL, "ipmi_si.%d", 0); + init_name = kasprintf(GFP_KERNEL, "ipmi_si.%d", + new_smi->intf_num); /* * If we don't already have a device from something @@ -3593,8 +3605,6 @@ static int try_smi_init(struct smi_info *new_smi) new_smi->interrupt_disabled = true; atomic_set(&new_smi->need_watch, 0); - new_smi->intf_num = smi_num; - smi_num++; rv = try_enable_event_buffer(new_smi); if (rv == 0) @@ -3661,6 +3671,9 @@ static int try_smi_init(struct smi_info *new_smi) 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]); -- cgit From 2c1175c2e8e5487233cabde358a19577562ac83e Mon Sep 17 00:00:00 2001 From: Robert Lippert Date: Thu, 20 Apr 2017 16:49:47 -0700 Subject: ipmi/watchdog: fix wdog hang on panic waiting for ipmi response Commit c49c097610fe ("ipmi: Don't call receive handler in the panic context") means that the panic_recv_free is not called during a panic and the atomic count does not drop to 0. Fix this by only expecting one decrement of the atomic variable which comes from panic_smi_free. Signed-off-by: Robert Lippert Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_watchdog.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c index 5ca24d9b101b..d165af8abe36 100644 --- a/drivers/char/ipmi/ipmi_watchdog.c +++ b/drivers/char/ipmi/ipmi_watchdog.c @@ -516,7 +516,7 @@ static void panic_halt_ipmi_heartbeat(void) msg.cmd = IPMI_WDOG_RESET_TIMER; msg.data = NULL; msg.data_len = 0; - atomic_add(2, &panic_done_count); + atomic_add(1, &panic_done_count); rv = ipmi_request_supply_msgs(watchdog_user, (struct ipmi_addr *) &addr, 0, @@ -526,7 +526,7 @@ static void panic_halt_ipmi_heartbeat(void) &panic_halt_heartbeat_recv_msg, 1); if (rv) - atomic_sub(2, &panic_done_count); + atomic_sub(1, &panic_done_count); } static struct ipmi_smi_msg panic_halt_smi_msg = { @@ -550,12 +550,12 @@ static void panic_halt_ipmi_set_timeout(void) /* Wait for the messages to be free. */ while (atomic_read(&panic_done_count) != 0) ipmi_poll_interface(watchdog_user); - atomic_add(2, &panic_done_count); + atomic_add(1, &panic_done_count); rv = i_ipmi_set_timeout(&panic_halt_smi_msg, &panic_halt_recv_msg, &send_heartbeat_now); if (rv) { - atomic_sub(2, &panic_done_count); + atomic_sub(1, &panic_done_count); printk(KERN_WARNING PFX "Unable to extend the watchdog timeout."); } else { -- cgit