Commit 91620521 authored by Corey Minyard's avatar Corey Minyard

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: default avatarCorey Minyard <cminyard@mvista.com>
parent 9f812704
...@@ -165,6 +165,9 @@ enum ssif_stat_indexes { ...@@ -165,6 +165,9 @@ enum ssif_stat_indexes {
/* Number of watchdog pretimeouts. */ /* Number of watchdog pretimeouts. */
SSIF_STAT_watchdog_pretimeouts, SSIF_STAT_watchdog_pretimeouts,
/* Number of alers received. */
SSIF_STAT_alerts,
/* Always add statistics before this value, it must be last. */ /* Always add statistics before this value, it must be last. */
SSIF_NUM_STATS SSIF_NUM_STATS
}; };
...@@ -213,7 +216,16 @@ struct ssif_info { ...@@ -213,7 +216,16 @@ struct ssif_info {
#define WDT_PRE_TIMEOUT_INT 0x08 #define WDT_PRE_TIMEOUT_INT 0x08
unsigned char msg_flags; unsigned char msg_flags;
u8 global_enables;
bool has_event_buffer; bool has_event_buffer;
bool supports_alert;
/*
* Used to tell what we should do with alerts. If we are
* waiting on a response, read the data immediately.
*/
bool got_alert;
bool waiting_alert;
/* /*
* If set to true, this will request events the next time the * 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, ...@@ -517,14 +529,10 @@ static int ssif_i2c_send(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);
static void retry_timeout(unsigned long data) static void start_get(struct ssif_info *ssif_info)
{ {
struct ssif_info *ssif_info = (void *) data;
int rv; int rv;
if (ssif_info->stopping)
return;
ssif_info->rtc_us_timer = 0; ssif_info->rtc_us_timer = 0;
rv = ssif_i2c_send(ssif_info, msg_done_handler, I2C_SMBUS_READ, rv = ssif_i2c_send(ssif_info, msg_done_handler, I2C_SMBUS_READ,
...@@ -539,6 +547,46 @@ static void retry_timeout(unsigned long data) ...@@ -539,6 +547,46 @@ static void retry_timeout(unsigned long data)
} }
} }
static void retry_timeout(unsigned long data)
{
struct ssif_info *ssif_info = (void *) data;
unsigned long oflags, *flags;
bool waiting;
if (ssif_info->stopping)
return;
flags = ipmi_ssif_lock_cond(ssif_info, &oflags);
waiting = ssif_info->waiting_alert;
ssif_info->waiting_alert = false;
ipmi_ssif_unlock_cond(ssif_info, flags);
if (waiting)
start_get(ssif_info);
}
static void ssif_alert(struct i2c_client *client, unsigned int data)
{
struct ssif_info *ssif_info = i2c_get_clientdata(client);
unsigned long oflags, *flags;
bool do_get = false;
ssif_inc_stat(ssif_info, alerts);
flags = ipmi_ssif_lock_cond(ssif_info, &oflags);
if (ssif_info->waiting_alert) {
ssif_info->waiting_alert = false;
del_timer(&ssif_info->retry_timer);
do_get = true;
} else if (ssif_info->curr_msg) {
ssif_info->got_alert = true;
}
ipmi_ssif_unlock_cond(ssif_info, flags);
if (do_get)
start_get(ssif_info);
}
static int start_resend(struct ssif_info *ssif_info); static int 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,
...@@ -558,9 +606,12 @@ 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,
if (ssif_info->retries_left > 0) { if (ssif_info->retries_left > 0) {
ssif_inc_stat(ssif_info, receive_retries); ssif_inc_stat(ssif_info, receive_retries);
flags = ipmi_ssif_lock_cond(ssif_info, &oflags);
ssif_info->waiting_alert = true;
ssif_info->rtc_us_timer = SSIF_MSG_USEC;
mod_timer(&ssif_info->retry_timer, mod_timer(&ssif_info->retry_timer,
jiffies + SSIF_MSG_JIFFIES); jiffies + SSIF_MSG_JIFFIES);
ssif_info->rtc_us_timer = SSIF_MSG_USEC; ipmi_ssif_unlock_cond(ssif_info, flags);
return; return;
} }
...@@ -649,7 +700,7 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result, ...@@ -649,7 +700,7 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
if (rv < 0) { if (rv < 0) {
if (ssif_info->ssif_debug & SSIF_DEBUG_MSG) if (ssif_info->ssif_debug & SSIF_DEBUG_MSG)
pr_info(PFX pr_info(PFX
"Error from i2c_non_blocking_op(2)\n"); "Error from ssif_i2c_send\n");
result = -EIO; result = -EIO;
} else } else
...@@ -863,15 +914,32 @@ static void msg_written_handler(struct ssif_info *ssif_info, int result, ...@@ -863,15 +914,32 @@ static void msg_written_handler(struct ssif_info *ssif_info, int result,
msg_done_handler(ssif_info, -EIO, NULL, 0); msg_done_handler(ssif_info, -EIO, NULL, 0);
} }
} else { } else {
unsigned long oflags, *flags;
bool got_alert;
ssif_inc_stat(ssif_info, sent_messages); ssif_inc_stat(ssif_info, sent_messages);
ssif_inc_stat(ssif_info, sent_messages_parts); ssif_inc_stat(ssif_info, sent_messages_parts);
/* Wait a jiffie then request the next message */ flags = ipmi_ssif_lock_cond(ssif_info, &oflags);
ssif_info->retries_left = SSIF_RECV_RETRIES; got_alert = ssif_info->got_alert;
ssif_info->rtc_us_timer = SSIF_MSG_PART_USEC; if (got_alert) {
mod_timer(&ssif_info->retry_timer, ssif_info->got_alert = false;
jiffies + SSIF_MSG_PART_JIFFIES); ssif_info->waiting_alert = false;
return; }
if (got_alert) {
ipmi_ssif_unlock_cond(ssif_info, flags);
/* The alert already happened, try now. */
retry_timeout((unsigned long) ssif_info);
} else {
/* Wait a jiffie then request the next message */
ssif_info->waiting_alert = true;
ssif_info->retries_left = SSIF_RECV_RETRIES;
ssif_info->rtc_us_timer = SSIF_MSG_PART_USEC;
mod_timer(&ssif_info->retry_timer,
jiffies + SSIF_MSG_PART_JIFFIES);
ipmi_ssif_unlock_cond(ssif_info, flags);
}
} }
} }
...@@ -880,6 +948,8 @@ static int start_resend(struct ssif_info *ssif_info) ...@@ -880,6 +948,8 @@ static int start_resend(struct ssif_info *ssif_info)
int rv; int rv;
int command; int command;
ssif_info->got_alert = false;
if (ssif_info->data_len > 32) { if (ssif_info->data_len > 32) {
command = SSIF_IPMI_MULTI_PART_REQUEST_START; command = SSIF_IPMI_MULTI_PART_REQUEST_START;
ssif_info->multi_data = ssif_info->data; ssif_info->multi_data = ssif_info->data;
...@@ -1242,6 +1312,8 @@ static int smi_stats_proc_show(struct seq_file *m, void *v) ...@@ -1242,6 +1312,8 @@ static int smi_stats_proc_show(struct seq_file *m, void *v)
ssif_get_stat(ssif_info, events)); ssif_get_stat(ssif_info, events));
seq_printf(m, "watchdog_pretimeouts: %u\n", seq_printf(m, "watchdog_pretimeouts: %u\n",
ssif_get_stat(ssif_info, watchdog_pretimeouts)); ssif_get_stat(ssif_info, watchdog_pretimeouts));
seq_printf(m, "alerts: %u\n",
ssif_get_stat(ssif_info, alerts));
return 0; return 0;
} }
...@@ -1324,6 +1396,12 @@ static bool check_acpi(struct ssif_info *ssif_info, struct device *dev) ...@@ -1324,6 +1396,12 @@ static bool check_acpi(struct ssif_info *ssif_info, struct device *dev)
return false; return false;
} }
/*
* Global enables we care about.
*/
#define GLOBAL_ENABLES_MASK (IPMI_BMC_EVT_MSG_BUFF | IPMI_BMC_RCV_MSG_INTR | \
IPMI_BMC_EVT_MSG_INTR)
static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id) static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
{ {
unsigned char msg[3]; unsigned char msg[3];
...@@ -1454,6 +1532,8 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id) ...@@ -1454,6 +1532,8 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
goto found; goto found;
} }
ssif_info->global_enables = resp[3];
if (resp[3] & IPMI_BMC_EVT_MSG_BUFF) { if (resp[3] & IPMI_BMC_EVT_MSG_BUFF) {
ssif_info->has_event_buffer = true; ssif_info->has_event_buffer = true;
/* buffer is already enabled, nothing to do. */ /* 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) ...@@ -1462,18 +1542,37 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
msg[0] = IPMI_NETFN_APP_REQUEST << 2; msg[0] = IPMI_NETFN_APP_REQUEST << 2;
msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD; msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD;
msg[2] = resp[3] | IPMI_BMC_EVT_MSG_BUFF; msg[2] = ssif_info->global_enables | IPMI_BMC_EVT_MSG_BUFF;
rv = do_cmd(client, 3, msg, &len, resp); rv = do_cmd(client, 3, msg, &len, resp);
if (rv || (len < 2)) { if (rv || (len < 2)) {
pr_warn(PFX "Error getting global enables: %d %d %2.2x\n", pr_warn(PFX "Error setting global enables: %d %d %2.2x\n",
rv, len, resp[2]); rv, len, resp[2]);
rv = 0; /* Not fatal */ rv = 0; /* Not fatal */
goto found; goto found;
} }
if (resp[2] == 0) if (resp[2] == 0) {
/* A successful return means the event buffer is supported. */ /* A successful return means the event buffer is supported. */
ssif_info->has_event_buffer = true; ssif_info->has_event_buffer = true;
ssif_info->global_enables |= IPMI_BMC_EVT_MSG_BUFF;
}
msg[0] = IPMI_NETFN_APP_REQUEST << 2;
msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD;
msg[2] = ssif_info->global_enables | IPMI_BMC_RCV_MSG_INTR;
rv = do_cmd(client, 3, msg, &len, resp);
if (rv || (len < 2)) {
pr_warn(PFX "Error setting global enables: %d %d %2.2x\n",
rv, len, resp[2]);
rv = 0; /* Not fatal */
goto found;
}
if (resp[2] == 0) {
/* A successful return means the alert is supported. */
ssif_info->supports_alert = true;
ssif_info->global_enables |= IPMI_BMC_RCV_MSG_INTR;
}
found: found:
ssif_info->intf_num = atomic_inc_return(&next_intf); ssif_info->intf_num = atomic_inc_return(&next_intf);
...@@ -1831,6 +1930,7 @@ static struct i2c_driver ssif_i2c_driver = { ...@@ -1831,6 +1930,7 @@ static struct i2c_driver ssif_i2c_driver = {
}, },
.probe = ssif_probe, .probe = ssif_probe,
.remove = ssif_remove, .remove = ssif_remove,
.alert = ssif_alert,
.id_table = ssif_id, .id_table = ssif_id,
.detect = ssif_detect .detect = ssif_detect
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment