|
@@ -165,6 +165,9 @@ enum ssif_stat_indexes {
|
|
|
/* Number of watchdog pretimeouts. */
|
|
|
SSIF_STAT_watchdog_pretimeouts,
|
|
|
|
|
|
+ /* Number of alers received. */
|
|
|
+ SSIF_STAT_alerts,
|
|
|
+
|
|
|
/* Always add statistics before this value, it must be last. */
|
|
|
SSIF_NUM_STATS
|
|
|
};
|
|
@@ -213,7 +216,16 @@ struct ssif_info {
|
|
|
#define WDT_PRE_TIMEOUT_INT 0x08
|
|
|
unsigned char msg_flags;
|
|
|
|
|
|
+ u8 global_enables;
|
|
|
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
|
|
@@ -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,
|
|
|
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;
|
|
|
|
|
|
- if (ssif_info->stopping)
|
|
|
- return;
|
|
|
-
|
|
|
ssif_info->rtc_us_timer = 0;
|
|
|
|
|
|
rv = ssif_i2c_send(ssif_info, msg_done_handler, I2C_SMBUS_READ,
|
|
@@ -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 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) {
|
|
|
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,
|
|
|
jiffies + SSIF_MSG_JIFFIES);
|
|
|
- ssif_info->rtc_us_timer = SSIF_MSG_USEC;
|
|
|
+ ipmi_ssif_unlock_cond(ssif_info, flags);
|
|
|
return;
|
|
|
}
|
|
|
|
|
@@ -649,7 +700,7 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
|
|
|
if (rv < 0) {
|
|
|
if (ssif_info->ssif_debug & SSIF_DEBUG_MSG)
|
|
|
pr_info(PFX
|
|
|
- "Error from i2c_non_blocking_op(2)\n");
|
|
|
+ "Error from ssif_i2c_send\n");
|
|
|
|
|
|
result = -EIO;
|
|
|
} else
|
|
@@ -863,15 +914,32 @@ static void msg_written_handler(struct ssif_info *ssif_info, int result,
|
|
|
msg_done_handler(ssif_info, -EIO, NULL, 0);
|
|
|
}
|
|
|
} else {
|
|
|
+ unsigned long oflags, *flags;
|
|
|
+ bool got_alert;
|
|
|
+
|
|
|
ssif_inc_stat(ssif_info, sent_messages);
|
|
|
ssif_inc_stat(ssif_info, sent_messages_parts);
|
|
|
|
|
|
- /* Wait a jiffie then request the next message */
|
|
|
- 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);
|
|
|
- return;
|
|
|
+ flags = ipmi_ssif_lock_cond(ssif_info, &oflags);
|
|
|
+ got_alert = ssif_info->got_alert;
|
|
|
+ if (got_alert) {
|
|
|
+ ssif_info->got_alert = false;
|
|
|
+ ssif_info->waiting_alert = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ 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)
|
|
|
int rv;
|
|
|
int command;
|
|
|
|
|
|
+ ssif_info->got_alert = false;
|
|
|
+
|
|
|
if (ssif_info->data_len > 32) {
|
|
|
command = SSIF_IPMI_MULTI_PART_REQUEST_START;
|
|
|
ssif_info->multi_data = ssif_info->data;
|
|
@@ -1242,6 +1312,8 @@ static int smi_stats_proc_show(struct seq_file *m, void *v)
|
|
|
ssif_get_stat(ssif_info, events));
|
|
|
seq_printf(m, "watchdog_pretimeouts: %u\n",
|
|
|
ssif_get_stat(ssif_info, watchdog_pretimeouts));
|
|
|
+ seq_printf(m, "alerts: %u\n",
|
|
|
+ ssif_get_stat(ssif_info, alerts));
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -1324,6 +1396,12 @@ static bool check_acpi(struct ssif_info *ssif_info, struct device *dev)
|
|
|
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)
|
|
|
{
|
|
|
unsigned char msg[3];
|
|
@@ -1454,6 +1532,8 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
|
|
goto found;
|
|
|
}
|
|
|
|
|
|
+ ssif_info->global_enables = resp[3];
|
|
|
+
|
|
|
if (resp[3] & IPMI_BMC_EVT_MSG_BUFF) {
|
|
|
ssif_info->has_event_buffer = true;
|
|
|
/* 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)
|
|
|
|
|
|
msg[0] = IPMI_NETFN_APP_REQUEST << 2;
|
|
|
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);
|
|
|
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 = 0; /* Not fatal */
|
|
|
goto found;
|
|
|
}
|
|
|
|
|
|
- if (resp[2] == 0)
|
|
|
+ if (resp[2] == 0) {
|
|
|
/* A successful return means the event buffer is supported. */
|
|
|
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:
|
|
|
ssif_info->intf_num = atomic_inc_return(&next_intf);
|
|
@@ -1831,6 +1930,7 @@ static struct i2c_driver ssif_i2c_driver = {
|
|
|
},
|
|
|
.probe = ssif_probe,
|
|
|
.remove = ssif_remove,
|
|
|
+ .alert = ssif_alert,
|
|
|
.id_table = ssif_id,
|
|
|
.detect = ssif_detect
|
|
|
};
|