Skip to content

Commit 9162052

Browse files
committed
ipmi: Add alert handling to SSIF
The SSIF interface can optionally have an SMBus alert come in when data is ready. Unfortunately, the IPMI spec gives wiggle room to the implementer to allow them to always have the alert enabled, even if the driver doesn't enable it. So implement alerts. If you don't in this situation, the SMBus alert handling will constantly complain. Signed-off-by: Corey Minyard <cminyard@mvista.com>
1 parent 9f81270 commit 9162052

File tree

1 file changed

+116
-16
lines changed

1 file changed

+116
-16
lines changed

drivers/char/ipmi/ipmi_ssif.c

Lines changed: 116 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,9 @@ enum ssif_stat_indexes {
165165
/* Number of watchdog pretimeouts. */
166166
SSIF_STAT_watchdog_pretimeouts,
167167

168+
/* Number of alers received. */
169+
SSIF_STAT_alerts,
170+
168171
/* Always add statistics before this value, it must be last. */
169172
SSIF_NUM_STATS
170173
};
@@ -213,7 +216,16 @@ struct ssif_info {
213216
#define WDT_PRE_TIMEOUT_INT 0x08
214217
unsigned char msg_flags;
215218

219+
u8 global_enables;
216220
bool has_event_buffer;
221+
bool supports_alert;
222+
223+
/*
224+
* Used to tell what we should do with alerts. If we are
225+
* waiting on a response, read the data immediately.
226+
*/
227+
bool got_alert;
228+
bool waiting_alert;
217229

218230
/*
219231
* If set to true, this will request events the next time the
@@ -517,14 +529,10 @@ static int ssif_i2c_send(struct ssif_info *ssif_info,
517529
static void msg_done_handler(struct ssif_info *ssif_info, int result,
518530
unsigned char *data, unsigned int len);
519531

520-
static void retry_timeout(unsigned long data)
532+
static void start_get(struct ssif_info *ssif_info)
521533
{
522-
struct ssif_info *ssif_info = (void *) data;
523534
int rv;
524535

525-
if (ssif_info->stopping)
526-
return;
527-
528536
ssif_info->rtc_us_timer = 0;
529537

530538
rv = ssif_i2c_send(ssif_info, msg_done_handler, I2C_SMBUS_READ,
@@ -539,6 +547,46 @@ static void retry_timeout(unsigned long data)
539547
}
540548
}
541549

550+
static void retry_timeout(unsigned long data)
551+
{
552+
struct ssif_info *ssif_info = (void *) data;
553+
unsigned long oflags, *flags;
554+
bool waiting;
555+
556+
if (ssif_info->stopping)
557+
return;
558+
559+
flags = ipmi_ssif_lock_cond(ssif_info, &oflags);
560+
waiting = ssif_info->waiting_alert;
561+
ssif_info->waiting_alert = false;
562+
ipmi_ssif_unlock_cond(ssif_info, flags);
563+
564+
if (waiting)
565+
start_get(ssif_info);
566+
}
567+
568+
569+
static void ssif_alert(struct i2c_client *client, unsigned int data)
570+
{
571+
struct ssif_info *ssif_info = i2c_get_clientdata(client);
572+
unsigned long oflags, *flags;
573+
bool do_get = false;
574+
575+
ssif_inc_stat(ssif_info, alerts);
576+
577+
flags = ipmi_ssif_lock_cond(ssif_info, &oflags);
578+
if (ssif_info->waiting_alert) {
579+
ssif_info->waiting_alert = false;
580+
del_timer(&ssif_info->retry_timer);
581+
do_get = true;
582+
} else if (ssif_info->curr_msg) {
583+
ssif_info->got_alert = true;
584+
}
585+
ipmi_ssif_unlock_cond(ssif_info, flags);
586+
if (do_get)
587+
start_get(ssif_info);
588+
}
589+
542590
static int start_resend(struct ssif_info *ssif_info);
543591

544592
static void msg_done_handler(struct ssif_info *ssif_info, int result,
@@ -558,9 +606,12 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
558606
if (ssif_info->retries_left > 0) {
559607
ssif_inc_stat(ssif_info, receive_retries);
560608

609+
flags = ipmi_ssif_lock_cond(ssif_info, &oflags);
610+
ssif_info->waiting_alert = true;
611+
ssif_info->rtc_us_timer = SSIF_MSG_USEC;
561612
mod_timer(&ssif_info->retry_timer,
562613
jiffies + SSIF_MSG_JIFFIES);
563-
ssif_info->rtc_us_timer = SSIF_MSG_USEC;
614+
ipmi_ssif_unlock_cond(ssif_info, flags);
564615
return;
565616
}
566617

@@ -649,7 +700,7 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
649700
if (rv < 0) {
650701
if (ssif_info->ssif_debug & SSIF_DEBUG_MSG)
651702
pr_info(PFX
652-
"Error from i2c_non_blocking_op(2)\n");
703+
"Error from ssif_i2c_send\n");
653704

654705
result = -EIO;
655706
} else
@@ -863,15 +914,32 @@ static void msg_written_handler(struct ssif_info *ssif_info, int result,
863914
msg_done_handler(ssif_info, -EIO, NULL, 0);
864915
}
865916
} else {
917+
unsigned long oflags, *flags;
918+
bool got_alert;
919+
866920
ssif_inc_stat(ssif_info, sent_messages);
867921
ssif_inc_stat(ssif_info, sent_messages_parts);
868922

869-
/* Wait a jiffie then request the next message */
870-
ssif_info->retries_left = SSIF_RECV_RETRIES;
871-
ssif_info->rtc_us_timer = SSIF_MSG_PART_USEC;
872-
mod_timer(&ssif_info->retry_timer,
873-
jiffies + SSIF_MSG_PART_JIFFIES);
874-
return;
923+
flags = ipmi_ssif_lock_cond(ssif_info, &oflags);
924+
got_alert = ssif_info->got_alert;
925+
if (got_alert) {
926+
ssif_info->got_alert = false;
927+
ssif_info->waiting_alert = false;
928+
}
929+
930+
if (got_alert) {
931+
ipmi_ssif_unlock_cond(ssif_info, flags);
932+
/* The alert already happened, try now. */
933+
retry_timeout((unsigned long) ssif_info);
934+
} else {
935+
/* Wait a jiffie then request the next message */
936+
ssif_info->waiting_alert = true;
937+
ssif_info->retries_left = SSIF_RECV_RETRIES;
938+
ssif_info->rtc_us_timer = SSIF_MSG_PART_USEC;
939+
mod_timer(&ssif_info->retry_timer,
940+
jiffies + SSIF_MSG_PART_JIFFIES);
941+
ipmi_ssif_unlock_cond(ssif_info, flags);
942+
}
875943
}
876944
}
877945

@@ -880,6 +948,8 @@ static int start_resend(struct ssif_info *ssif_info)
880948
int rv;
881949
int command;
882950

951+
ssif_info->got_alert = false;
952+
883953
if (ssif_info->data_len > 32) {
884954
command = SSIF_IPMI_MULTI_PART_REQUEST_START;
885955
ssif_info->multi_data = ssif_info->data;
@@ -1242,6 +1312,8 @@ static int smi_stats_proc_show(struct seq_file *m, void *v)
12421312
ssif_get_stat(ssif_info, events));
12431313
seq_printf(m, "watchdog_pretimeouts: %u\n",
12441314
ssif_get_stat(ssif_info, watchdog_pretimeouts));
1315+
seq_printf(m, "alerts: %u\n",
1316+
ssif_get_stat(ssif_info, alerts));
12451317
return 0;
12461318
}
12471319

@@ -1324,6 +1396,12 @@ static bool check_acpi(struct ssif_info *ssif_info, struct device *dev)
13241396
return false;
13251397
}
13261398

1399+
/*
1400+
* Global enables we care about.
1401+
*/
1402+
#define GLOBAL_ENABLES_MASK (IPMI_BMC_EVT_MSG_BUFF | IPMI_BMC_RCV_MSG_INTR | \
1403+
IPMI_BMC_EVT_MSG_INTR)
1404+
13271405
static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
13281406
{
13291407
unsigned char msg[3];
@@ -1454,6 +1532,8 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
14541532
goto found;
14551533
}
14561534

1535+
ssif_info->global_enables = resp[3];
1536+
14571537
if (resp[3] & IPMI_BMC_EVT_MSG_BUFF) {
14581538
ssif_info->has_event_buffer = true;
14591539
/* buffer is already enabled, nothing to do. */
@@ -1462,18 +1542,37 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
14621542

14631543
msg[0] = IPMI_NETFN_APP_REQUEST << 2;
14641544
msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD;
1465-
msg[2] = resp[3] | IPMI_BMC_EVT_MSG_BUFF;
1545+
msg[2] = ssif_info->global_enables | IPMI_BMC_EVT_MSG_BUFF;
14661546
rv = do_cmd(client, 3, msg, &len, resp);
14671547
if (rv || (len < 2)) {
1468-
pr_warn(PFX "Error getting global enables: %d %d %2.2x\n",
1548+
pr_warn(PFX "Error setting global enables: %d %d %2.2x\n",
14691549
rv, len, resp[2]);
14701550
rv = 0; /* Not fatal */
14711551
goto found;
14721552
}
14731553

1474-
if (resp[2] == 0)
1554+
if (resp[2] == 0) {
14751555
/* A successful return means the event buffer is supported. */
14761556
ssif_info->has_event_buffer = true;
1557+
ssif_info->global_enables |= IPMI_BMC_EVT_MSG_BUFF;
1558+
}
1559+
1560+
msg[0] = IPMI_NETFN_APP_REQUEST << 2;
1561+
msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD;
1562+
msg[2] = ssif_info->global_enables | IPMI_BMC_RCV_MSG_INTR;
1563+
rv = do_cmd(client, 3, msg, &len, resp);
1564+
if (rv || (len < 2)) {
1565+
pr_warn(PFX "Error setting global enables: %d %d %2.2x\n",
1566+
rv, len, resp[2]);
1567+
rv = 0; /* Not fatal */
1568+
goto found;
1569+
}
1570+
1571+
if (resp[2] == 0) {
1572+
/* A successful return means the alert is supported. */
1573+
ssif_info->supports_alert = true;
1574+
ssif_info->global_enables |= IPMI_BMC_RCV_MSG_INTR;
1575+
}
14771576

14781577
found:
14791578
ssif_info->intf_num = atomic_inc_return(&next_intf);
@@ -1831,6 +1930,7 @@ static struct i2c_driver ssif_i2c_driver = {
18311930
},
18321931
.probe = ssif_probe,
18331932
.remove = ssif_remove,
1933+
.alert = ssif_alert,
18341934
.id_table = ssif_id,
18351935
.detect = ssif_detect
18361936
};

0 commit comments

Comments
 (0)