summaryrefslogtreecommitdiff
path: root/drivers/char/ipmi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char/ipmi')
-rw-r--r--drivers/char/ipmi/Kconfig9
-rw-r--r--drivers/char/ipmi/ipmb_dev_int.c13
-rw-r--r--drivers/char/ipmi/ipmi_ipmb.c4
-rw-r--r--drivers/char/ipmi/ipmi_kcs_sm.c2
-rw-r--r--drivers/char/ipmi/ipmi_msghandler.c29
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c149
-rw-r--r--drivers/char/ipmi/ipmi_si_platform.c15
-rw-r--r--drivers/char/ipmi/ipmi_ssif.c32
-rw-r--r--drivers/char/ipmi/ssif_bmc.c2
9 files changed, 191 insertions, 64 deletions
diff --git a/drivers/char/ipmi/Kconfig b/drivers/char/ipmi/Kconfig
index 669f76000197..538a7d3c65bf 100644
--- a/drivers/char/ipmi/Kconfig
+++ b/drivers/char/ipmi/Kconfig
@@ -67,6 +67,15 @@ config IPMI_SI
Currently, only KCS and SMIC are supported. If
you are using IPMI, you should probably say "y" here.
+config IPMI_SI_ASYNC_INIT
+ bool 'Asynchronous initialization of IPMI System Interface'
+ depends on IPMI_SI
+ default n
+ help
+ Offloads individual SMI inits. It speeds up the boot time.
+ It also introduces a very small risk that something else might fail
+ if it depends on synchronous IPMI init.
+
config IPMI_SSIF
tristate 'IPMI SMBus handler (SSIF)'
depends on I2C
diff --git a/drivers/char/ipmi/ipmb_dev_int.c b/drivers/char/ipmi/ipmb_dev_int.c
index 2fe1d205ce4e..eae31ec92382 100644
--- a/drivers/char/ipmi/ipmb_dev_int.c
+++ b/drivers/char/ipmi/ipmb_dev_int.c
@@ -141,13 +141,14 @@ static ssize_t ipmb_write(struct file *file, const char __user *buf,
u8 msg[MAX_MSG_LEN];
ssize_t ret;
- if (count > sizeof(msg))
+ if (!count || count > sizeof(msg))
return -EINVAL;
if (copy_from_user(&msg, buf, count))
return -EFAULT;
- if (count < msg[0])
+ if (msg[IPMB_MSG_LEN_IDX] < IPMB_REQUEST_LEN_MIN ||
+ count < (size_t)msg[IPMB_MSG_LEN_IDX] + 1)
return -EINVAL;
rq_sa = GET_7BIT_ADDR(msg[RQ_SA_8BIT_IDX]);
@@ -353,15 +354,15 @@ static void ipmb_remove(struct i2c_client *client)
}
static const struct i2c_device_id ipmb_id[] = {
- { "ipmb-dev" },
- {}
+ { .name = "ipmb-dev" },
+ { }
};
MODULE_DEVICE_TABLE(i2c, ipmb_id);
#ifdef CONFIG_ACPI
static const struct acpi_device_id acpi_ipmb_id[] = {
- { "IPMB0001", 0 },
- {},
+ { .id = "IPMB0001" },
+ { }
};
MODULE_DEVICE_TABLE(acpi, acpi_ipmb_id);
#endif
diff --git a/drivers/char/ipmi/ipmi_ipmb.c b/drivers/char/ipmi/ipmi_ipmb.c
index 28818952a7a4..1f1e5718f082 100644
--- a/drivers/char/ipmi/ipmi_ipmb.c
+++ b/drivers/char/ipmi/ipmi_ipmb.c
@@ -566,8 +566,8 @@ MODULE_DEVICE_TABLE(of, of_ipmi_ipmb_match);
#endif
static const struct i2c_device_id ipmi_ipmb_id[] = {
- { DEVICE_NAME },
- {}
+ { .name = DEVICE_NAME },
+ { }
};
MODULE_DEVICE_TABLE(i2c, ipmi_ipmb_id);
diff --git a/drivers/char/ipmi/ipmi_kcs_sm.c b/drivers/char/ipmi/ipmi_kcs_sm.c
index efda90dcf5b3..c89055db39e5 100644
--- a/drivers/char/ipmi/ipmi_kcs_sm.c
+++ b/drivers/char/ipmi/ipmi_kcs_sm.c
@@ -102,7 +102,7 @@ enum kcs_states {
/* Timeouts in microseconds. */
#define IBF_RETRY_TIMEOUT (5*USEC_PER_SEC)
#define OBF_RETRY_TIMEOUT (5*USEC_PER_SEC)
-#define MAX_ERROR_RETRIES 10
+#define MAX_ERROR_RETRIES 2
#define ERROR0_OBF_WAIT_JIFFIES (2*HZ)
struct si_sm_data {
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index 869ac87a4b6a..152dd6b5bb27 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -1391,6 +1391,7 @@ static void _ipmi_destroy_user(struct ipmi_user *user)
}
}
mutex_unlock(&intf->cmd_rcvrs_mutex);
+ synchronize_rcu();
while (rcvrs) {
rcvr = rcvrs;
rcvrs = rcvr->next;
@@ -1610,14 +1611,12 @@ int ipmi_set_gets_events(struct ipmi_user *user, bool val)
{
struct ipmi_smi *intf = user->intf;
struct ipmi_recv_msg *msg, *msg2;
- struct list_head msgs;
+ LIST_HEAD(msgs);
user = acquire_ipmi_user(user);
if (!user)
return -ENODEV;
- INIT_LIST_HEAD(&msgs);
-
mutex_lock(&intf->events_mutex);
if (user->gets_events == val)
goto out;
@@ -2347,6 +2346,10 @@ static int i_ipmi_request(struct ipmi_user *user,
if (smi_msg == NULL) {
if (!supplied_recv)
ipmi_free_recv_msg(recv_msg);
+ else if (recv_msg->user) {
+ atomic_dec(&recv_msg->user->nr_msgs);
+ kref_put(&recv_msg->user->refcount, free_ipmi_user);
+ }
return -ENOMEM;
}
}
@@ -2420,6 +2423,10 @@ out_err:
ipmi_free_smi_msg(smi_msg);
if (!supplied_recv)
ipmi_free_recv_msg(recv_msg);
+ else if (recv_msg->user) {
+ atomic_dec(&recv_msg->user->nr_msgs);
+ kref_put(&recv_msg->user->refcount, free_ipmi_user);
+ }
}
return rv;
}
@@ -3295,6 +3302,7 @@ out_list_del:
list_del(&intf->bmc_link);
mutex_unlock(&bmc->dyn_mutex);
intf->bmc = &intf->tmp_bmc;
+ ida_free(&ipmi_bmc_ida, bmc->pdev.id);
put_device(&bmc->pdev.dev);
goto out;
}
@@ -3734,6 +3742,7 @@ int ipmi_add_smi(struct module *owner,
sysfs_attr_init(&intf->maintenance_mode_devattr.attr);
rv = device_create_file(intf->si_dev, &intf->maintenance_mode_devattr);
if (rv) {
+ device_remove_file(intf->si_dev, &intf->nr_msgs_devattr);
device_remove_file(intf->si_dev, &intf->nr_users_devattr);
goto out_err_bmc_reg;
}
@@ -3751,12 +3760,14 @@ int ipmi_add_smi(struct module *owner,
out_err_bmc_reg:
ipmi_bmc_unregister(intf);
out_err_started:
+ intf->in_shutdown = true;
if (intf->handlers->shutdown)
intf->handlers->shutdown(intf->send_info);
out_err:
list_del(&intf->link);
mutex_unlock(&ipmi_interfaces_mutex);
mutex_unlock(&smi_watchers_mutex);
+ cancel_work_sync(&intf->smi_work);
kref_put(&intf->refcount, intf_free);
return rv;
@@ -3785,10 +3796,9 @@ static void cleanup_smi_msgs(struct ipmi_smi *intf)
struct seq_table *ent;
struct ipmi_smi_msg *msg;
struct list_head *entry;
- struct list_head tmplist;
+ LIST_HEAD(tmplist);
/* Clear out our transmit queues and hold the messages. */
- INIT_LIST_HEAD(&tmplist);
list_splice_tail(&intf->hp_xmit_msgs, &tmplist);
list_splice_tail(&intf->xmit_msgs, &tmplist);
@@ -4442,7 +4452,7 @@ static int handle_read_event_rsp(struct ipmi_smi *intf,
struct ipmi_smi_msg *msg)
{
struct ipmi_recv_msg *recv_msg, *recv_msg2;
- struct list_head msgs;
+ LIST_HEAD(msgs);
struct ipmi_user *user;
int rv = 0, deliver_count = 0;
@@ -4457,8 +4467,6 @@ static int handle_read_event_rsp(struct ipmi_smi *intf,
return 0;
}
- INIT_LIST_HEAD(&msgs);
-
mutex_lock(&intf->events_mutex);
ipmi_inc_stat(intf, events);
@@ -4477,10 +4485,8 @@ static int handle_read_event_rsp(struct ipmi_smi *intf,
mutex_unlock(&intf->users_mutex);
list_for_each_entry_safe(recv_msg, recv_msg2, &msgs,
link) {
- user = recv_msg->user;
list_del(&recv_msg->link);
ipmi_free_recv_msg(recv_msg);
- kref_put(&user->refcount, free_ipmi_user);
}
/*
* We couldn't allocate memory for the
@@ -5101,7 +5107,7 @@ static void check_msg_timeout(struct ipmi_smi *intf, struct seq_table *ent,
static bool ipmi_timeout_handler(struct ipmi_smi *intf,
unsigned long timeout_period)
{
- struct list_head timeouts;
+ LIST_HEAD(timeouts);
struct ipmi_recv_msg *msg, *msg2;
unsigned long flags;
int i;
@@ -5120,7 +5126,6 @@ static bool ipmi_timeout_handler(struct ipmi_smi *intf,
* have timed out, putting them in the timeouts
* list.
*/
- INIT_LIST_HEAD(&timeouts);
mutex_lock(&intf->seq_lock);
if (intf->ipmb_maintenance_mode_timeout) {
if (intf->ipmb_maintenance_mode_timeout <= timeout_period)
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index 4a9e9de4d684..6b95a7581328 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -39,6 +39,7 @@
#include <linux/rcupdate.h>
#include <linux/ipmi.h>
#include <linux/ipmi_smi.h>
+#include <linux/workqueue.h>
#include "ipmi_si.h"
#include "ipmi_si_sm.h"
#include <linux/string.h>
@@ -168,6 +169,10 @@ struct smi_info {
OEM2_DATA_AVAIL)
unsigned char msg_flags;
+ /* When requesting events and messages, don't do it forever. */
+ unsigned int num_requests_in_a_row;
+ bool last_was_flag_fetch;
+
/* Does the BMC have an event buffer? */
bool has_event_buffer;
@@ -248,6 +253,8 @@ struct smi_info {
struct task_struct *thread;
+ struct work_struct init_work;
+
struct list_head link;
};
@@ -268,6 +275,7 @@ static bool unload_when_empty = true;
static int try_smi_init(struct smi_info *smi);
static void cleanup_one_si(struct smi_info *smi_info);
static void cleanup_ipmi_si(void);
+static void smi_init_work_fn(struct work_struct *work);
#ifdef DEBUG_TIMING
void debug_timestamp(struct smi_info *smi_info, char *msg)
@@ -410,7 +418,10 @@ static void start_getting_msg_queue(struct smi_info *smi_info)
start_new_msg(smi_info, smi_info->curr_msg->data,
smi_info->curr_msg->data_size);
- smi_info->si_state = SI_GETTING_MESSAGES;
+ if (smi_info->si_state != SI_GETTING_MESSAGES) {
+ smi_info->num_requests_in_a_row = 0;
+ smi_info->si_state = SI_GETTING_MESSAGES;
+ }
}
static void start_getting_events(struct smi_info *smi_info)
@@ -421,7 +432,10 @@ static void start_getting_events(struct smi_info *smi_info)
start_new_msg(smi_info, smi_info->curr_msg->data,
smi_info->curr_msg->data_size);
- smi_info->si_state = SI_GETTING_EVENTS;
+ if (smi_info->si_state != SI_GETTING_EVENTS) {
+ smi_info->num_requests_in_a_row = 0;
+ smi_info->si_state = SI_GETTING_EVENTS;
+ }
}
/*
@@ -487,15 +501,19 @@ retry:
} else if (smi_info->msg_flags & RECEIVE_MSG_AVAIL) {
/* Messages available. */
smi_info->curr_msg = alloc_msg_handle_irq(smi_info);
- if (!smi_info->curr_msg)
+ if (!smi_info->curr_msg) {
+ smi_info->si_state = SI_NORMAL;
return;
+ }
start_getting_msg_queue(smi_info);
} else if (smi_info->msg_flags & EVENT_MSG_BUFFER_FULL) {
/* Events available. */
smi_info->curr_msg = alloc_msg_handle_irq(smi_info);
- if (!smi_info->curr_msg)
+ if (!smi_info->curr_msg) {
+ smi_info->si_state = SI_NORMAL;
return;
+ }
start_getting_events(smi_info);
} else if (smi_info->msg_flags & OEM_DATA_AVAIL &&
@@ -595,6 +613,7 @@ static void handle_transaction_done(struct smi_info *smi_info)
smi_info->si_state = SI_NORMAL;
} else {
smi_info->msg_flags = msg[3];
+ smi_info->last_was_flag_fetch = true;
handle_flags(smi_info);
}
break;
@@ -630,7 +649,13 @@ static void handle_transaction_done(struct smi_info *smi_info)
*/
msg = smi_info->curr_msg;
smi_info->curr_msg = NULL;
- if (msg->rsp[2] != 0) {
+ /*
+ * It appears some BMCs, with no event data, return no
+ * data in the message and not a 0x80 error as the
+ * spec says they should. Shut down processing if
+ * the data is not the right length.
+ */
+ if (msg->rsp[2] != 0 || msg->rsp_size != 19) {
/* Error getting event, probably done. */
msg->done(msg);
@@ -640,6 +665,11 @@ static void handle_transaction_done(struct smi_info *smi_info)
} else {
smi_inc_stat(smi_info, events);
+ smi_info->num_requests_in_a_row++;
+ if (smi_info->num_requests_in_a_row > 10)
+ /* Stop if we do this too many times. */
+ smi_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
+
/*
* Do this before we deliver the message
* because delivering the message releases the
@@ -678,6 +708,11 @@ static void handle_transaction_done(struct smi_info *smi_info)
} else {
smi_inc_stat(smi_info, incoming_messages);
+ smi_info->num_requests_in_a_row++;
+ if (smi_info->num_requests_in_a_row > 10)
+ /* Stop if we do this too many times. */
+ smi_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
+
/*
* Do this before we deliver the message
* because delivering the message releases the
@@ -820,6 +855,26 @@ restart:
}
/*
+ * If we are currently idle, or if the last thing that was
+ * done was a flag fetch and there is a message pending, try
+ * to start the next message.
+ *
+ * We do the waiting message check to avoid a stuck flag
+ * completely wedging the driver. Let a message through
+ * in between flag operations if that happens.
+ */
+ if (si_sm_result == SI_SM_IDLE ||
+ (si_sm_result == SI_SM_ATTN && smi_info->waiting_msg &&
+ smi_info->last_was_flag_fetch)) {
+ smi_info->last_was_flag_fetch = false;
+ smi_inc_stat(smi_info, idles);
+
+ si_sm_result = start_next_msg(smi_info);
+ if (si_sm_result != SI_SM_IDLE)
+ goto restart;
+ }
+
+ /*
* We prefer handling attn over new messages. But don't do
* this if there is not yet an upper layer to handle anything.
*/
@@ -846,15 +901,6 @@ restart:
}
}
- /* If we are currently idle, try to start the next message. */
- if (si_sm_result == SI_SM_IDLE) {
- smi_inc_stat(smi_info, idles);
-
- si_sm_result = start_next_msg(smi_info);
- if (si_sm_result != SI_SM_IDLE)
- goto restart;
- }
-
if ((si_sm_result == SI_SM_IDLE)
&& (atomic_read(&smi_info->req_events))) {
/*
@@ -1928,6 +1974,7 @@ int ipmi_si_add_smi(struct si_sm_io *io)
if (!new_smi)
return -ENOMEM;
spin_lock_init(&new_smi->si_lock);
+ INIT_WORK(&new_smi->init_work, smi_init_work_fn);
new_smi->io = *io;
@@ -1940,7 +1987,12 @@ int ipmi_si_add_smi(struct si_sm_io *io)
dev_info(dup->io.dev,
"Removing SMBIOS-specified %s state machine in favor of ACPI\n",
si_to_str[new_smi->io.si_info->type]);
+ list_del(&dup->link);
+ mutex_unlock(&smi_infos_lock);
+
cleanup_one_si(dup);
+
+ mutex_lock(&smi_infos_lock);
} else {
dev_info(new_smi->io.dev,
"%s-specified %s state machine: duplicate\n",
@@ -1958,8 +2010,12 @@ int ipmi_si_add_smi(struct si_sm_io *io)
list_add_tail(&new_smi->link, &smi_infos);
- if (initialized)
- rv = try_smi_init(new_smi);
+ if (initialized) {
+ if (IS_ENABLED(CONFIG_IPMI_SI_ASYNC_INIT))
+ queue_work(system_dfl_wq, &new_smi->init_work);
+ else
+ rv = try_smi_init(new_smi);
+ }
out_err:
mutex_unlock(&smi_infos_lock);
return rv;
@@ -2132,6 +2188,15 @@ static bool __init ipmi_smi_info_same(struct smi_info *e1, struct smi_info *e2)
e1->io.addr_data == e2->io.addr_data);
}
+static void smi_init_work_fn(struct work_struct *work)
+{
+ struct smi_info *smi = container_of(work, struct smi_info, init_work);
+
+ mutex_lock(&smi_infos_lock);
+ try_smi_init(smi);
+ mutex_unlock(&smi_infos_lock);
+}
+
static int __init init_ipmi_si(void)
{
struct smi_info *e, *e2;
@@ -2177,8 +2242,12 @@ static int __init init_ipmi_si(void)
break;
}
}
- if (!dup)
- try_smi_init(e);
+ if (!dup) {
+ if (IS_ENABLED(CONFIG_IPMI_SI_ASYNC_INIT))
+ queue_work(system_unbound_wq, &e->init_work);
+ else
+ try_smi_init(e);
+ }
}
/*
@@ -2211,8 +2280,12 @@ static int __init init_ipmi_si(void)
break;
}
}
- if (!dup)
- try_smi_init(e);
+ if (!dup) {
+ if (IS_ENABLED(CONFIG_IPMI_SI_ASYNC_INIT))
+ queue_work(system_unbound_wq, &e->init_work);
+ else
+ try_smi_init(e);
+ }
}
initialized = true;
@@ -2302,31 +2375,36 @@ static void shutdown_smi(void *send_info)
}
/*
- * Must be called with smi_infos_lock held, to serialize the
- * smi_info->intf check.
+ * Must be called with smi_info unlinked from smi_infos and smi_infos_lock released.
*/
static void cleanup_one_si(struct smi_info *smi_info)
{
if (!smi_info)
return;
- list_del(&smi_info->link);
+ if (IS_ENABLED(CONFIG_IPMI_SI_ASYNC_INIT))
+ cancel_work_sync(&smi_info->init_work);
+
ipmi_unregister_smi(smi_info->intf);
kfree(smi_info);
}
void ipmi_si_remove_by_dev(struct device *dev)
{
- struct smi_info *e;
+ struct smi_info *e = NULL, *tmp;
mutex_lock(&smi_infos_lock);
- list_for_each_entry(e, &smi_infos, link) {
- if (e->io.dev == dev) {
- cleanup_one_si(e);
+ list_for_each_entry(tmp, &smi_infos, link) {
+ if (tmp->io.dev == dev) {
+ e = tmp;
+ list_del(&e->link);
break;
}
}
mutex_unlock(&smi_infos_lock);
+
+ if (e)
+ cleanup_one_si(e);
}
struct device *ipmi_si_remove_by_data(int addr_space, enum si_type si_type,
@@ -2335,6 +2413,7 @@ struct device *ipmi_si_remove_by_data(int addr_space, enum si_type si_type,
/* remove */
struct smi_info *e, *tmp_e;
struct device *dev = NULL;
+ LIST_HEAD(to_clean);
mutex_lock(&smi_infos_lock);
list_for_each_entry_safe(e, tmp_e, &smi_infos, link) {
@@ -2344,17 +2423,23 @@ struct device *ipmi_si_remove_by_data(int addr_space, enum si_type si_type,
continue;
if (e->io.addr_data == addr) {
dev = get_device(e->io.dev);
- cleanup_one_si(e);
+ list_move_tail(&e->link, &to_clean);
}
}
mutex_unlock(&smi_infos_lock);
+ list_for_each_entry_safe(e, tmp_e, &to_clean, link) {
+ list_del(&e->link);
+ cleanup_one_si(e);
+ }
+
return dev;
}
static void cleanup_ipmi_si(void)
{
struct smi_info *e, *tmp_e;
+ LIST_HEAD(to_clean);
if (!initialized)
return;
@@ -2368,10 +2453,14 @@ static void cleanup_ipmi_si(void)
ipmi_si_platform_shutdown();
mutex_lock(&smi_infos_lock);
- list_for_each_entry_safe(e, tmp_e, &smi_infos, link)
- cleanup_one_si(e);
+ list_splice_init(&smi_infos, &to_clean);
mutex_unlock(&smi_infos_lock);
+ list_for_each_entry_safe(e, tmp_e, &to_clean, link) {
+ list_del(&e->link);
+ cleanup_one_si(e);
+ }
+
ipmi_si_hardcode_exit();
ipmi_si_hotmod_exit();
}
diff --git a/drivers/char/ipmi/ipmi_si_platform.c b/drivers/char/ipmi/ipmi_si_platform.c
index fb6e359ae494..fa221cbb4b3b 100644
--- a/drivers/char/ipmi/ipmi_si_platform.c
+++ b/drivers/char/ipmi/ipmi_si_platform.c
@@ -276,7 +276,10 @@ static int of_ipmi_probe(struct platform_device *pdev)
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.irq = platform_get_irq_optional(pdev, 0);
+ if (io.irq < 0)
+ io.irq = 0;
+
io.dev = &pdev->dev;
dev_dbg(&pdev->dev, "addr 0x%lx regsize %d spacing %d irq %d\n",
@@ -384,8 +387,8 @@ static int acpi_ipmi_probe(struct platform_device *pdev)
}
static const struct acpi_device_id acpi_ipmi_match[] = {
- { "IPI0001", 0 },
- { },
+ { .id = "IPI0001" },
+ { }
};
MODULE_DEVICE_TABLE(acpi, acpi_ipmi_match);
#else
@@ -433,9 +436,9 @@ void ipmi_remove_platform_device_by_name(char *name)
}
static const struct platform_device_id si_plat_ids[] = {
- { "dmi-ipmi-si", 0 },
- { "hardcode-ipmi-si", 0 },
- { "hotmod-ipmi-si", 0 },
+ { .name = "dmi-ipmi-si" },
+ { .name = "hardcode-ipmi-si" },
+ { .name = "hotmod-ipmi-si" },
{ }
};
diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c
index b49500a1bd36..2361103c5edc 100644
--- a/drivers/char/ipmi/ipmi_ssif.c
+++ b/drivers/char/ipmi/ipmi_ssif.c
@@ -225,6 +225,9 @@ struct ssif_info {
bool has_event_buffer;
bool supports_alert;
+ /* When requesting events and messages, don't do it forever. */
+ unsigned int num_requests_in_a_row;
+
/*
* Used to tell what we should do with alerts. If we are
* waiting on a response, read the data immediately.
@@ -413,7 +416,10 @@ static void start_event_fetch(struct ssif_info *ssif_info, unsigned long *flags)
}
ssif_info->curr_msg = msg;
- ssif_info->ssif_state = SSIF_GETTING_EVENTS;
+ if (ssif_info->ssif_state != SSIF_GETTING_EVENTS) {
+ ssif_info->num_requests_in_a_row = 0;
+ ssif_info->ssif_state = SSIF_GETTING_EVENTS;
+ }
ipmi_ssif_unlock_cond(ssif_info, flags);
msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
@@ -436,7 +442,10 @@ static void start_recv_msg_fetch(struct ssif_info *ssif_info,
}
ssif_info->curr_msg = msg;
- ssif_info->ssif_state = SSIF_GETTING_MESSAGES;
+ if (ssif_info->ssif_state != SSIF_GETTING_MESSAGES) {
+ ssif_info->num_requests_in_a_row = 0;
+ ssif_info->ssif_state = SSIF_GETTING_MESSAGES;
+ }
ipmi_ssif_unlock_cond(ssif_info, flags);
msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
@@ -843,6 +852,11 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
ssif_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
handle_flags(ssif_info, flags);
} else {
+ ssif_info->num_requests_in_a_row++;
+ if (ssif_info->num_requests_in_a_row > 10)
+ /* Stop if we do this too many times. */
+ ssif_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
+
handle_flags(ssif_info, flags);
ssif_inc_stat(ssif_info, events);
deliver_recv_msg(ssif_info, msg);
@@ -876,6 +890,11 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
ssif_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
handle_flags(ssif_info, flags);
} else {
+ ssif_info->num_requests_in_a_row++;
+ if (ssif_info->num_requests_in_a_row > 10)
+ /* Stop if we do this too many times. */
+ ssif_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
+
ssif_inc_stat(ssif_info, incoming_messages);
handle_flags(ssif_info, flags);
deliver_recv_msg(ssif_info, msg);
@@ -1886,6 +1905,7 @@ static int ssif_probe(struct i2c_client *client)
"kssif%4.4x", thread_num);
if (IS_ERR(ssif_info->thread)) {
rv = PTR_ERR(ssif_info->thread);
+ ssif_info->thread = NULL;
dev_notice(&ssif_info->client->dev,
"Could not start kernel thread: error %d\n",
rv);
@@ -2037,8 +2057,8 @@ static unsigned short *ssif_address_list(void)
#ifdef CONFIG_ACPI
static const struct acpi_device_id ssif_acpi_match[] = {
- { "IPI0001", 0 },
- { },
+ { .id = "IPI0001" },
+ { }
};
MODULE_DEVICE_TABLE(acpi, ssif_acpi_match);
#endif
@@ -2074,7 +2094,7 @@ static int dmi_ipmi_probe(struct platform_device *pdev)
#endif
static const struct i2c_device_id ssif_id[] = {
- { DEVICE_NAME },
+ { .name = DEVICE_NAME },
{ }
};
MODULE_DEVICE_TABLE(i2c, ssif_id);
@@ -2107,7 +2127,7 @@ static void ssif_platform_remove(struct platform_device *dev)
}
static const struct platform_device_id ssif_plat_ids[] = {
- { "dmi-ipmi-ssif", 0 },
+ { .name = "dmi-ipmi-ssif" },
{ }
};
MODULE_DEVICE_TABLE(platform, ssif_plat_ids);
diff --git a/drivers/char/ipmi/ssif_bmc.c b/drivers/char/ipmi/ssif_bmc.c
index 1df0e9284ad9..6036897725f3 100644
--- a/drivers/char/ipmi/ssif_bmc.c
+++ b/drivers/char/ipmi/ssif_bmc.c
@@ -874,7 +874,7 @@ static const struct of_device_id ssif_bmc_match[] = {
MODULE_DEVICE_TABLE(of, ssif_bmc_match);
static const struct i2c_device_id ssif_bmc_id[] = {
- { DEVICE_NAME },
+ { .name = DEVICE_NAME },
{ }
};
MODULE_DEVICE_TABLE(i2c, ssif_bmc_id);