aboutsummaryrefslogtreecommitdiff
path: root/drivers/char/ipmi
diff options
context:
space:
mode:
authorCorey Minyard2018-10-22 15:30:57 -0500
committerCorey Minyard2019-02-09 19:48:41 -0600
commita1466ec5b671651b848df17fc9233ecbb7d35f9f (patch)
treed648d1d16ff077724d08018e66f048910b6b3b42 /drivers/char/ipmi
parent401e7e88d4ef80188ffa07095ac00456f901b8c4 (diff)
ipmi: Fix SSIF flag requests
Commit 89986496de141 ("ipmi: Turn off all activity on an idle ipmi interface") modified the IPMI code to only request events when the driver had somethine waiting for events. The SSIF code, however, was using the event fetch request to also fetch the flags. Add a timer and the proper handling for the upper layer telling whether flags fetches are required. Reported-by: Kamlakant Patel <Kamlakant.Patel@cavium.com> Signed-off-by: Corey Minyard <cminyard@mvista.com> Tested-by: Kamlakant Patel <kamlakant.patel@cavium.com>
Diffstat (limited to 'drivers/char/ipmi')
-rw-r--r--drivers/char/ipmi/ipmi_ssif.c64
1 files changed, 52 insertions, 12 deletions
diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c
index b7a1ae2afaea..1aacc1144d2a 100644
--- a/drivers/char/ipmi/ipmi_ssif.c
+++ b/drivers/char/ipmi/ipmi_ssif.c
@@ -90,6 +90,12 @@
#define SSIF_MSG_JIFFIES ((SSIF_MSG_USEC * 1000) / TICK_NSEC)
#define SSIF_MSG_PART_JIFFIES ((SSIF_MSG_PART_USEC * 1000) / TICK_NSEC)
+/*
+ * Timeout for the watch, only used for get flag timer.
+ */
+#define SSIF_WATCH_TIMEOUT_MSEC 100
+#define SSIF_WATCH_TIMEOUT_JIFFIES msecs_to_jiffies(SSIF_WATCH_TIMEOUT_MSEC)
+
enum ssif_intf_state {
SSIF_NORMAL,
SSIF_GETTING_FLAGS,
@@ -270,6 +276,9 @@ struct ssif_info {
struct timer_list retry_timer;
int retries_left;
+ bool need_watch; /* Need to look for flags? */
+ struct timer_list watch_timer; /* Flag fetch timer. */
+
/* Info from SSIF cmd */
unsigned char max_xmit_msg_size;
unsigned char max_recv_msg_size;
@@ -560,6 +569,26 @@ static void retry_timeout(struct timer_list *t)
start_get(ssif_info);
}
+static void watch_timeout(struct timer_list *t)
+{
+ struct ssif_info *ssif_info = from_timer(ssif_info, t, watch_timer);
+ unsigned long oflags, *flags;
+
+ if (ssif_info->stopping)
+ return;
+
+ flags = ipmi_ssif_lock_cond(ssif_info, &oflags);
+ if (ssif_info->need_watch) {
+ mod_timer(&ssif_info->watch_timer,
+ jiffies + SSIF_WATCH_TIMEOUT_JIFFIES);
+ if (SSIF_IDLE(ssif_info)) {
+ start_flag_fetch(ssif_info, flags); /* Releases lock */
+ return;
+ }
+ ssif_info->req_flags = true;
+ }
+ ipmi_ssif_unlock_cond(ssif_info, flags);
+}
static void ssif_alert(struct i2c_client *client, enum i2c_alert_protocol type,
unsigned int data)
@@ -1073,8 +1102,7 @@ static int get_smi_info(void *send_info, struct ipmi_smi_info *data)
}
/*
- * Instead of having our own timer to periodically check the message
- * flags, we let the message handler drive us.
+ * Upper layer wants us to request events.
*/
static void request_events(void *send_info)
{
@@ -1085,18 +1113,27 @@ static void request_events(void *send_info)
return;
flags = ipmi_ssif_lock_cond(ssif_info, &oflags);
- /*
- * Request flags first, not events, because the lower layer
- * doesn't have a way to send an attention. But make sure
- * event checking still happens.
- */
ssif_info->req_events = true;
- if (SSIF_IDLE(ssif_info))
- start_flag_fetch(ssif_info, flags);
- else {
- ssif_info->req_flags = true;
- ipmi_ssif_unlock_cond(ssif_info, flags);
+ ipmi_ssif_unlock_cond(ssif_info, flags);
+}
+
+/*
+ * Upper layer is changing the flag saying whether we need to request
+ * flags periodically or not.
+ */
+static void ssif_set_need_watch(void *send_info, bool enable)
+{
+ struct ssif_info *ssif_info = (struct ssif_info *) send_info;
+ unsigned long oflags, *flags;
+
+ flags = ipmi_ssif_lock_cond(ssif_info, &oflags);
+ if (enable != ssif_info->need_watch) {
+ ssif_info->need_watch = enable;
+ if (ssif_info->need_watch)
+ mod_timer(&ssif_info->watch_timer,
+ jiffies + SSIF_WATCH_TIMEOUT_JIFFIES);
}
+ ipmi_ssif_unlock_cond(ssif_info, flags);
}
static int ssif_start_processing(void *send_info,
@@ -1223,6 +1260,7 @@ static void shutdown_ssif(void *send_info)
schedule_timeout(1);
ssif_info->stopping = true;
+ del_timer_sync(&ssif_info->watch_timer);
del_timer_sync(&ssif_info->retry_timer);
if (ssif_info->thread) {
complete(&ssif_info->wake_thread);
@@ -1708,6 +1746,7 @@ 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;
timer_setup(&ssif_info->retry_timer, retry_timeout, 0);
+ timer_setup(&ssif_info->watch_timer, watch_timeout, 0);
for (i = 0; i < SSIF_NUM_STATS; i++)
atomic_set(&ssif_info->stats[i], 0);
@@ -1721,6 +1760,7 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
ssif_info->handlers.get_smi_info = get_smi_info;
ssif_info->handlers.sender = sender;
ssif_info->handlers.request_events = request_events;
+ ssif_info->handlers.set_need_watch = ssif_set_need_watch;
{
unsigned int thread_num;