aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/ipmi/ipmi_si_intf.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char/ipmi/ipmi_si_intf.c')
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c150
1 files changed, 120 insertions, 30 deletions
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index e58ea4cd55ce..259644646b82 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -82,12 +82,6 @@
82#define SI_SHORT_TIMEOUT_USEC 250 /* .25ms when the SM request a 82#define SI_SHORT_TIMEOUT_USEC 250 /* .25ms when the SM request a
83 short timeout */ 83 short timeout */
84 84
85/* Bit for BMC global enables. */
86#define IPMI_BMC_RCV_MSG_INTR 0x01
87#define IPMI_BMC_EVT_MSG_INTR 0x02
88#define IPMI_BMC_EVT_MSG_BUFF 0x04
89#define IPMI_BMC_SYS_LOG 0x08
90
91enum si_intf_state { 85enum si_intf_state {
92 SI_NORMAL, 86 SI_NORMAL,
93 SI_GETTING_FLAGS, 87 SI_GETTING_FLAGS,
@@ -220,6 +214,9 @@ struct smi_info {
220 OEM2_DATA_AVAIL) 214 OEM2_DATA_AVAIL)
221 unsigned char msg_flags; 215 unsigned char msg_flags;
222 216
217 /* Does the BMC have an event buffer? */
218 char has_event_buffer;
219
223 /* 220 /*
224 * If set to true, this will request events the next time the 221 * If set to true, this will request events the next time the
225 * state machine is idle. 222 * state machine is idle.
@@ -968,7 +965,8 @@ static void request_events(void *send_info)
968{ 965{
969 struct smi_info *smi_info = send_info; 966 struct smi_info *smi_info = send_info;
970 967
971 if (atomic_read(&smi_info->stop_operation)) 968 if (atomic_read(&smi_info->stop_operation) ||
969 !smi_info->has_event_buffer)
972 return; 970 return;
973 971
974 atomic_set(&smi_info->req_events, 1); 972 atomic_set(&smi_info->req_events, 1);
@@ -2407,26 +2405,9 @@ static struct of_platform_driver ipmi_of_platform_driver = {
2407}; 2405};
2408#endif /* CONFIG_PPC_OF */ 2406#endif /* CONFIG_PPC_OF */
2409 2407
2410 2408static int wait_for_msg_done(struct smi_info *smi_info)
2411static int try_get_dev_id(struct smi_info *smi_info)
2412{ 2409{
2413 unsigned char msg[2];
2414 unsigned char *resp;
2415 unsigned long resp_len;
2416 enum si_sm_result smi_result; 2410 enum si_sm_result smi_result;
2417 int rv = 0;
2418
2419 resp = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL);
2420 if (!resp)
2421 return -ENOMEM;
2422
2423 /*
2424 * Do a Get Device ID command, since it comes back with some
2425 * useful info.
2426 */
2427 msg[0] = IPMI_NETFN_APP_REQUEST << 2;
2428 msg[1] = IPMI_GET_DEVICE_ID_CMD;
2429 smi_info->handlers->start_transaction(smi_info->si_sm, msg, 2);
2430 2411
2431 smi_result = smi_info->handlers->event(smi_info->si_sm, 0); 2412 smi_result = smi_info->handlers->event(smi_info->si_sm, 0);
2432 for (;;) { 2413 for (;;) {
@@ -2441,16 +2422,39 @@ static int try_get_dev_id(struct smi_info *smi_info)
2441 } else 2422 } else
2442 break; 2423 break;
2443 } 2424 }
2444 if (smi_result == SI_SM_HOSED) { 2425 if (smi_result == SI_SM_HOSED)
2445 /* 2426 /*
2446 * We couldn't get the state machine to run, so whatever's at 2427 * We couldn't get the state machine to run, so whatever's at
2447 * the port is probably not an IPMI SMI interface. 2428 * the port is probably not an IPMI SMI interface.
2448 */ 2429 */
2449 rv = -ENODEV; 2430 return -ENODEV;
2431
2432 return 0;
2433}
2434
2435static int try_get_dev_id(struct smi_info *smi_info)
2436{
2437 unsigned char msg[2];
2438 unsigned char *resp;
2439 unsigned long resp_len;
2440 int rv = 0;
2441
2442 resp = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL);
2443 if (!resp)
2444 return -ENOMEM;
2445
2446 /*
2447 * Do a Get Device ID command, since it comes back with some
2448 * useful info.
2449 */
2450 msg[0] = IPMI_NETFN_APP_REQUEST << 2;
2451 msg[1] = IPMI_GET_DEVICE_ID_CMD;
2452 smi_info->handlers->start_transaction(smi_info->si_sm, msg, 2);
2453
2454 rv = wait_for_msg_done(smi_info);
2455 if (rv)
2450 goto out; 2456 goto out;
2451 }
2452 2457
2453 /* Otherwise, we got some data. */
2454 resp_len = smi_info->handlers->get_result(smi_info->si_sm, 2458 resp_len = smi_info->handlers->get_result(smi_info->si_sm,
2455 resp, IPMI_MAX_MSG_LENGTH); 2459 resp, IPMI_MAX_MSG_LENGTH);
2456 2460
@@ -2462,6 +2466,88 @@ static int try_get_dev_id(struct smi_info *smi_info)
2462 return rv; 2466 return rv;
2463} 2467}
2464 2468
2469static int try_enable_event_buffer(struct smi_info *smi_info)
2470{
2471 unsigned char msg[3];
2472 unsigned char *resp;
2473 unsigned long resp_len;
2474 int rv = 0;
2475
2476 resp = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL);
2477 if (!resp)
2478 return -ENOMEM;
2479
2480 msg[0] = IPMI_NETFN_APP_REQUEST << 2;
2481 msg[1] = IPMI_GET_BMC_GLOBAL_ENABLES_CMD;
2482 smi_info->handlers->start_transaction(smi_info->si_sm, msg, 2);
2483
2484 rv = wait_for_msg_done(smi_info);
2485 if (rv) {
2486 printk(KERN_WARNING
2487 "ipmi_si: Error getting response from get global,"
2488 " enables command, the event buffer is not"
2489 " enabled.\n");
2490 goto out;
2491 }
2492
2493 resp_len = smi_info->handlers->get_result(smi_info->si_sm,
2494 resp, IPMI_MAX_MSG_LENGTH);
2495
2496 if (resp_len < 4 ||
2497 resp[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2 ||
2498 resp[1] != IPMI_GET_BMC_GLOBAL_ENABLES_CMD ||
2499 resp[2] != 0) {
2500 printk(KERN_WARNING
2501 "ipmi_si: Invalid return from get global"
2502 " enables command, cannot enable the event"
2503 " buffer.\n");
2504 rv = -EINVAL;
2505 goto out;
2506 }
2507
2508 if (resp[3] & IPMI_BMC_EVT_MSG_BUFF)
2509 /* buffer is already enabled, nothing to do. */
2510 goto out;
2511
2512 msg[0] = IPMI_NETFN_APP_REQUEST << 2;
2513 msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD;
2514 msg[2] = resp[3] | IPMI_BMC_EVT_MSG_BUFF;
2515 smi_info->handlers->start_transaction(smi_info->si_sm, msg, 3);
2516
2517 rv = wait_for_msg_done(smi_info);
2518 if (rv) {
2519 printk(KERN_WARNING
2520 "ipmi_si: Error getting response from set global,"
2521 " enables command, the event buffer is not"
2522 " enabled.\n");
2523 goto out;
2524 }
2525
2526 resp_len = smi_info->handlers->get_result(smi_info->si_sm,
2527 resp, IPMI_MAX_MSG_LENGTH);
2528
2529 if (resp_len < 3 ||
2530 resp[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2 ||
2531 resp[1] != IPMI_SET_BMC_GLOBAL_ENABLES_CMD) {
2532 printk(KERN_WARNING
2533 "ipmi_si: Invalid return from get global,"
2534 "enables command, not enable the event"
2535 " buffer.\n");
2536 rv = -EINVAL;
2537 goto out;
2538 }
2539
2540 if (resp[2] != 0)
2541 /*
2542 * An error when setting the event buffer bit means
2543 * that the event buffer is not supported.
2544 */
2545 rv = -ENOENT;
2546 out:
2547 kfree(resp);
2548 return rv;
2549}
2550
2465static int type_file_read_proc(char *page, char **start, off_t off, 2551static int type_file_read_proc(char *page, char **start, off_t off,
2466 int count, int *eof, void *data) 2552 int count, int *eof, void *data)
2467{ 2553{
@@ -2847,6 +2933,10 @@ static int try_smi_init(struct smi_info *new_smi)
2847 new_smi->intf_num = smi_num; 2933 new_smi->intf_num = smi_num;
2848 smi_num++; 2934 smi_num++;
2849 2935
2936 rv = try_enable_event_buffer(new_smi);
2937 if (rv == 0)
2938 new_smi->has_event_buffer = 1;
2939
2850 /* 2940 /*
2851 * Start clearing the flags before we enable interrupts or the 2941 * Start clearing the flags before we enable interrupts or the
2852 * timer to avoid racing with the timer. 2942 * timer to avoid racing with the timer.
@@ -2863,7 +2953,7 @@ static int try_smi_init(struct smi_info *new_smi)
2863 */ 2953 */
2864 new_smi->pdev = platform_device_alloc("ipmi_si", 2954 new_smi->pdev = platform_device_alloc("ipmi_si",
2865 new_smi->intf_num); 2955 new_smi->intf_num);
2866 if (rv) { 2956 if (!new_smi->pdev) {
2867 printk(KERN_ERR 2957 printk(KERN_ERR
2868 "ipmi_si_intf:" 2958 "ipmi_si_intf:"
2869 " Unable to allocate platform device\n"); 2959 " Unable to allocate platform device\n");