aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char
diff options
context:
space:
mode:
authorCorey Minyard <cminyard@mvista.com>2015-04-24 08:46:06 -0400
committerCorey Minyard <cminyard@mvista.com>2015-05-05 20:36:38 -0400
commit9162052173d2381e2bbabc224c3c1457acb4c54c (patch)
treefac1fbe196644fc3d1cbbc91bc77160c896bc0b0 /drivers/char
parent9f8127048ab8b47b43f8aeaaec9fec2da44be9a1 (diff)
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>
Diffstat (limited to 'drivers/char')
-rw-r--r--drivers/char/ipmi/ipmi_ssif.c132
1 files changed, 116 insertions, 16 deletions
diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c
index f6ea4fa444b3..5b82d9947ec5 100644
--- a/drivers/char/ipmi/ipmi_ssif.c
+++ b/drivers/char/ipmi/ipmi_ssif.c
@@ -165,6 +165,9 @@ enum ssif_stat_indexes {
165 /* Number of watchdog pretimeouts. */ 165 /* Number of watchdog pretimeouts. */
166 SSIF_STAT_watchdog_pretimeouts, 166 SSIF_STAT_watchdog_pretimeouts,
167 167
168 /* Number of alers received. */
169 SSIF_STAT_alerts,
170
168 /* Always add statistics before this value, it must be last. */ 171 /* Always add statistics before this value, it must be last. */
169 SSIF_NUM_STATS 172 SSIF_NUM_STATS
170}; 173};
@@ -213,7 +216,16 @@ struct ssif_info {
213#define WDT_PRE_TIMEOUT_INT 0x08 216#define WDT_PRE_TIMEOUT_INT 0x08
214 unsigned char msg_flags; 217 unsigned char msg_flags;
215 218
219 u8 global_enables;
216 bool has_event_buffer; 220 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;
217 229
218 /* 230 /*
219 * If set to true, this will request events the next time the 231 * 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,
517static void msg_done_handler(struct ssif_info *ssif_info, int result, 529static void msg_done_handler(struct ssif_info *ssif_info, int result,
518 unsigned char *data, unsigned int len); 530 unsigned char *data, unsigned int len);
519 531
520static void retry_timeout(unsigned long data) 532static void start_get(struct ssif_info *ssif_info)
521{ 533{
522 struct ssif_info *ssif_info = (void *) data;
523 int rv; 534 int rv;
524 535
525 if (ssif_info->stopping)
526 return;
527
528 ssif_info->rtc_us_timer = 0; 536 ssif_info->rtc_us_timer = 0;
529 537
530 rv = ssif_i2c_send(ssif_info, msg_done_handler, I2C_SMBUS_READ, 538 rv = ssif_i2c_send(ssif_info, msg_done_handler, I2C_SMBUS_READ,
@@ -539,6 +547,46 @@ static void retry_timeout(unsigned long data)
539 } 547 }
540} 548}
541 549
550static 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
569static 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
542static int start_resend(struct ssif_info *ssif_info); 590static int start_resend(struct ssif_info *ssif_info);
543 591
544static void msg_done_handler(struct ssif_info *ssif_info, int result, 592static 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 if (ssif_info->retries_left > 0) { 606 if (ssif_info->retries_left > 0) {
559 ssif_inc_stat(ssif_info, receive_retries); 607 ssif_inc_stat(ssif_info, receive_retries);
560 608
609 flags = ipmi_ssif_lock_cond(ssif_info, &oflags);
610 ssif_info->waiting_alert = true;
611 ssif_info->rtc_us_timer = SSIF_MSG_USEC;
561 mod_timer(&ssif_info->retry_timer, 612 mod_timer(&ssif_info->retry_timer,
562 jiffies + SSIF_MSG_JIFFIES); 613 jiffies + SSIF_MSG_JIFFIES);
563 ssif_info->rtc_us_timer = SSIF_MSG_USEC; 614 ipmi_ssif_unlock_cond(ssif_info, flags);
564 return; 615 return;
565 } 616 }
566 617
@@ -649,7 +700,7 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
649 if (rv < 0) { 700 if (rv < 0) {
650 if (ssif_info->ssif_debug & SSIF_DEBUG_MSG) 701 if (ssif_info->ssif_debug & SSIF_DEBUG_MSG)
651 pr_info(PFX 702 pr_info(PFX
652 "Error from i2c_non_blocking_op(2)\n"); 703 "Error from ssif_i2c_send\n");
653 704
654 result = -EIO; 705 result = -EIO;
655 } else 706 } else
@@ -863,15 +914,32 @@ static void msg_written_handler(struct ssif_info *ssif_info, int result,
863 msg_done_handler(ssif_info, -EIO, NULL, 0); 914 msg_done_handler(ssif_info, -EIO, NULL, 0);
864 } 915 }
865 } else { 916 } else {
917 unsigned long oflags, *flags;
918 bool got_alert;
919
866 ssif_inc_stat(ssif_info, sent_messages); 920 ssif_inc_stat(ssif_info, sent_messages);
867 ssif_inc_stat(ssif_info, sent_messages_parts); 921 ssif_inc_stat(ssif_info, sent_messages_parts);
868 922
869 /* Wait a jiffie then request the next message */ 923 flags = ipmi_ssif_lock_cond(ssif_info, &oflags);
870 ssif_info->retries_left = SSIF_RECV_RETRIES; 924 got_alert = ssif_info->got_alert;
871 ssif_info->rtc_us_timer = SSIF_MSG_PART_USEC; 925 if (got_alert) {
872 mod_timer(&ssif_info->retry_timer, 926 ssif_info->got_alert = false;
873 jiffies + SSIF_MSG_PART_JIFFIES); 927 ssif_info->waiting_alert = false;
874 return; 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 }
875 } 943 }
876} 944}
877 945
@@ -880,6 +948,8 @@ static int start_resend(struct ssif_info *ssif_info)
880 int rv; 948 int rv;
881 int command; 949 int command;
882 950
951 ssif_info->got_alert = false;
952
883 if (ssif_info->data_len > 32) { 953 if (ssif_info->data_len > 32) {
884 command = SSIF_IPMI_MULTI_PART_REQUEST_START; 954 command = SSIF_IPMI_MULTI_PART_REQUEST_START;
885 ssif_info->multi_data = ssif_info->data; 955 ssif_info->multi_data = ssif_info->data;
@@ -1242,6 +1312,8 @@ static int smi_stats_proc_show(struct seq_file *m, void *v)
1242 ssif_get_stat(ssif_info, events)); 1312 ssif_get_stat(ssif_info, events));
1243 seq_printf(m, "watchdog_pretimeouts: %u\n", 1313 seq_printf(m, "watchdog_pretimeouts: %u\n",
1244 ssif_get_stat(ssif_info, watchdog_pretimeouts)); 1314 ssif_get_stat(ssif_info, watchdog_pretimeouts));
1315 seq_printf(m, "alerts: %u\n",
1316 ssif_get_stat(ssif_info, alerts));
1245 return 0; 1317 return 0;
1246} 1318}
1247 1319
@@ -1324,6 +1396,12 @@ static bool check_acpi(struct ssif_info *ssif_info, struct device *dev)
1324 return false; 1396 return false;
1325} 1397}
1326 1398
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
1327static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id) 1405static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
1328{ 1406{
1329 unsigned char msg[3]; 1407 unsigned char msg[3];
@@ -1454,6 +1532,8 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
1454 goto found; 1532 goto found;
1455 } 1533 }
1456 1534
1535 ssif_info->global_enables = resp[3];
1536
1457 if (resp[3] & IPMI_BMC_EVT_MSG_BUFF) { 1537 if (resp[3] & IPMI_BMC_EVT_MSG_BUFF) {
1458 ssif_info->has_event_buffer = true; 1538 ssif_info->has_event_buffer = true;
1459 /* buffer is already enabled, nothing to do. */ 1539 /* 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 1542
1463 msg[0] = IPMI_NETFN_APP_REQUEST << 2; 1543 msg[0] = IPMI_NETFN_APP_REQUEST << 2;
1464 msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD; 1544 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;
1466 rv = do_cmd(client, 3, msg, &len, resp); 1546 rv = do_cmd(client, 3, msg, &len, resp);
1467 if (rv || (len < 2)) { 1547 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",
1469 rv, len, resp[2]); 1549 rv, len, resp[2]);
1470 rv = 0; /* Not fatal */ 1550 rv = 0; /* Not fatal */
1471 goto found; 1551 goto found;
1472 } 1552 }
1473 1553
1474 if (resp[2] == 0) 1554 if (resp[2] == 0) {
1475 /* A successful return means the event buffer is supported. */ 1555 /* A successful return means the event buffer is supported. */
1476 ssif_info->has_event_buffer = true; 1556 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 }
1477 1576
1478 found: 1577 found:
1479 ssif_info->intf_num = atomic_inc_return(&next_intf); 1578 ssif_info->intf_num = atomic_inc_return(&next_intf);
@@ -1831,6 +1930,7 @@ static struct i2c_driver ssif_i2c_driver = {
1831 }, 1930 },
1832 .probe = ssif_probe, 1931 .probe = ssif_probe,
1833 .remove = ssif_remove, 1932 .remove = ssif_remove,
1933 .alert = ssif_alert,
1834 .id_table = ssif_id, 1934 .id_table = ssif_id,
1835 .detect = ssif_detect 1935 .detect = ssif_detect
1836}; 1936};