ipmi:ssif: Add a timer between request retries

[ Upstream commit 00bb7e763ec9f384cb382455cb6ba5588b5375cf ]

The IPMI spec has a time (T6) specified between request retries.  Add
the handling for that.

Reported by: Tony Camuso <tcamuso@redhat.com>
Cc: stable@vger.kernel.org
Signed-off-by: Corey Minyard <cminyard@mvista.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
Corey Minyard 2023-01-25 10:34:47 -06:00 committed by Greg Kroah-Hartman
parent e8ba1b693a
commit 36c5682cbb

View File

@ -79,7 +79,8 @@
/* /*
* Timer values * Timer values
*/ */
#define SSIF_MSG_USEC 60000 /* 60ms between message tries. */ #define SSIF_MSG_USEC 60000 /* 60ms between message tries (T3). */
#define SSIF_REQ_RETRY_USEC 60000 /* 60ms between send retries (T6). */
#define SSIF_MSG_PART_USEC 5000 /* 5ms for a message part */ #define SSIF_MSG_PART_USEC 5000 /* 5ms for a message part */
/* How many times to we retry sending/receiving the message. */ /* How many times to we retry sending/receiving the message. */
@ -87,7 +88,9 @@
#define SSIF_RECV_RETRIES 250 #define SSIF_RECV_RETRIES 250
#define SSIF_MSG_MSEC (SSIF_MSG_USEC / 1000) #define SSIF_MSG_MSEC (SSIF_MSG_USEC / 1000)
#define SSIF_REQ_RETRY_MSEC (SSIF_REQ_RETRY_USEC / 1000)
#define SSIF_MSG_JIFFIES ((SSIF_MSG_USEC * 1000) / TICK_NSEC) #define SSIF_MSG_JIFFIES ((SSIF_MSG_USEC * 1000) / TICK_NSEC)
#define SSIF_REQ_RETRY_JIFFIES ((SSIF_REQ_RETRY_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)
/* /*
@ -236,6 +239,9 @@ struct ssif_info {
bool got_alert; bool got_alert;
bool waiting_alert; bool waiting_alert;
/* Used to inform the timeout that it should do a resend. */
bool do_resend;
/* /*
* If set to true, this will request events the next time the * If set to true, this will request events the next time the
* state machine is idle. * state machine is idle.
@ -536,22 +542,28 @@ static void start_get(struct ssif_info *ssif_info)
ssif_info->recv, I2C_SMBUS_BLOCK_DATA); ssif_info->recv, I2C_SMBUS_BLOCK_DATA);
} }
static void start_resend(struct ssif_info *ssif_info);
static void retry_timeout(struct timer_list *t) static void retry_timeout(struct timer_list *t)
{ {
struct ssif_info *ssif_info = from_timer(ssif_info, t, retry_timer); struct ssif_info *ssif_info = from_timer(ssif_info, t, retry_timer);
unsigned long oflags, *flags; unsigned long oflags, *flags;
bool waiting; bool waiting, resend;
if (ssif_info->stopping) if (ssif_info->stopping)
return; return;
flags = ipmi_ssif_lock_cond(ssif_info, &oflags); flags = ipmi_ssif_lock_cond(ssif_info, &oflags);
resend = ssif_info->do_resend;
ssif_info->do_resend = false;
waiting = ssif_info->waiting_alert; waiting = ssif_info->waiting_alert;
ssif_info->waiting_alert = false; ssif_info->waiting_alert = false;
ipmi_ssif_unlock_cond(ssif_info, flags); ipmi_ssif_unlock_cond(ssif_info, flags);
if (waiting) if (waiting)
start_get(ssif_info); start_get(ssif_info);
if (resend)
start_resend(ssif_info);
} }
static void watch_timeout(struct timer_list *t) static void watch_timeout(struct timer_list *t)
@ -600,8 +612,6 @@ static void ssif_alert(struct i2c_client *client, enum i2c_alert_protocol type,
start_get(ssif_info); start_get(ssif_info);
} }
static void start_resend(struct ssif_info *ssif_info);
static void msg_done_handler(struct ssif_info *ssif_info, int result, static void msg_done_handler(struct ssif_info *ssif_info, int result,
unsigned char *data, unsigned int len) unsigned char *data, unsigned int len)
{ {
@ -906,7 +916,13 @@ static void msg_written_handler(struct ssif_info *ssif_info, int result,
if (result < 0) { if (result < 0) {
ssif_info->retries_left--; ssif_info->retries_left--;
if (ssif_info->retries_left > 0) { if (ssif_info->retries_left > 0) {
start_resend(ssif_info); /*
* Wait the retry timeout time per the spec,
* then redo the send.
*/
ssif_info->do_resend = true;
mod_timer(&ssif_info->retry_timer,
jiffies + SSIF_REQ_RETRY_JIFFIES);
return; return;
} }
@ -1318,8 +1334,10 @@ static int do_cmd(struct i2c_client *client, int len, unsigned char *msg,
ret = i2c_smbus_write_block_data(client, SSIF_IPMI_REQUEST, len, msg); ret = i2c_smbus_write_block_data(client, SSIF_IPMI_REQUEST, len, msg);
if (ret) { if (ret) {
retry_cnt--; retry_cnt--;
if (retry_cnt > 0) if (retry_cnt > 0) {
msleep(SSIF_REQ_RETRY_MSEC);
goto retry1; goto retry1;
}
return -ENODEV; return -ENODEV;
} }
@ -1459,8 +1477,10 @@ retry_write:
32, msg); 32, msg);
if (ret) { if (ret) {
retry_cnt--; retry_cnt--;
if (retry_cnt > 0) if (retry_cnt > 0) {
msleep(SSIF_REQ_RETRY_MSEC);
goto retry_write; goto retry_write;
}
dev_err(&client->dev, "Could not write multi-part start, though the BMC said it could handle it. Just limit sends to one part.\n"); dev_err(&client->dev, "Could not write multi-part start, though the BMC said it could handle it. Just limit sends to one part.\n");
return ret; return ret;
} }