ipmi: Fix SSIF flag requests

Commit 89986496de ("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>
This commit is contained in:
Corey Minyard 2018-10-22 15:30:57 -05:00
parent 401e7e88d4
commit a1466ec5b6
1 changed files with 52 additions and 12 deletions

View File

@ -90,6 +90,12 @@
#define SSIF_MSG_JIFFIES ((SSIF_MSG_USEC * 1000) / TICK_NSEC) #define SSIF_MSG_JIFFIES ((SSIF_MSG_USEC * 1000) / TICK_NSEC)
#define SSIF_MSG_PART_JIFFIES ((SSIF_MSG_PART_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 { enum ssif_intf_state {
SSIF_NORMAL, SSIF_NORMAL,
SSIF_GETTING_FLAGS, SSIF_GETTING_FLAGS,
@ -270,6 +276,9 @@ struct ssif_info {
struct timer_list retry_timer; struct timer_list retry_timer;
int retries_left; int retries_left;
bool need_watch; /* Need to look for flags? */
struct timer_list watch_timer; /* Flag fetch timer. */
/* Info from SSIF cmd */ /* Info from SSIF cmd */
unsigned char max_xmit_msg_size; unsigned char max_xmit_msg_size;
unsigned char max_recv_msg_size; unsigned char max_recv_msg_size;
@ -560,6 +569,26 @@ static void retry_timeout(struct timer_list *t)
start_get(ssif_info); 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, static void ssif_alert(struct i2c_client *client, enum i2c_alert_protocol type,
unsigned int data) 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 * Upper layer wants us to request events.
* flags, we let the message handler drive us.
*/ */
static void request_events(void *send_info) static void request_events(void *send_info)
{ {
@ -1085,18 +1113,27 @@ static void request_events(void *send_info)
return; return;
flags = ipmi_ssif_lock_cond(ssif_info, &oflags); 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; ssif_info->req_events = true;
if (SSIF_IDLE(ssif_info)) ipmi_ssif_unlock_cond(ssif_info, flags);
start_flag_fetch(ssif_info, flags); }
else {
ssif_info->req_flags = true; /*
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, static int ssif_start_processing(void *send_info,
@ -1223,6 +1260,7 @@ static void shutdown_ssif(void *send_info)
schedule_timeout(1); schedule_timeout(1);
ssif_info->stopping = true; ssif_info->stopping = true;
del_timer_sync(&ssif_info->watch_timer);
del_timer_sync(&ssif_info->retry_timer); del_timer_sync(&ssif_info->retry_timer);
if (ssif_info->thread) { if (ssif_info->thread) {
complete(&ssif_info->wake_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); spin_lock_init(&ssif_info->lock);
ssif_info->ssif_state = SSIF_NORMAL; ssif_info->ssif_state = SSIF_NORMAL;
timer_setup(&ssif_info->retry_timer, retry_timeout, 0); 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++) for (i = 0; i < SSIF_NUM_STATS; i++)
atomic_set(&ssif_info->stats[i], 0); 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.get_smi_info = get_smi_info;
ssif_info->handlers.sender = sender; ssif_info->handlers.sender = sender;
ssif_info->handlers.request_events = request_events; ssif_info->handlers.request_events = request_events;
ssif_info->handlers.set_need_watch = ssif_set_need_watch;
{ {
unsigned int thread_num; unsigned int thread_num;