aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c109
1 files changed, 102 insertions, 7 deletions
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index f6646ed3047e..518585c1ce94 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -263,6 +263,11 @@ struct smi_info {
263 bool supports_event_msg_buff; 263 bool supports_event_msg_buff;
264 264
265 /* 265 /*
266 * Can we clear the global enables receive irq bit?
267 */
268 bool cannot_clear_recv_irq_bit;
269
270 /*
266 * Did we get an attention that we did not handle? 271 * Did we get an attention that we did not handle?
267 */ 272 */
268 bool got_attn; 273 bool got_attn;
@@ -461,6 +466,9 @@ static void smi_mod_timer(struct smi_info *smi_info, unsigned long new_val)
461 * allocate messages, we just leave them in the BMC and run the system 466 * allocate messages, we just leave them in the BMC and run the system
462 * polled until we can allocate some memory. Once we have some 467 * polled until we can allocate some memory. Once we have some
463 * memory, we will re-enable the interrupt. 468 * memory, we will re-enable the interrupt.
469 *
470 * Note that we cannot just use disable_irq(), since the interrupt may
471 * be shared.
464 */ 472 */
465static inline bool disable_si_irq(struct smi_info *smi_info) 473static inline bool disable_si_irq(struct smi_info *smi_info)
466{ 474{
@@ -549,20 +557,15 @@ static u8 current_global_enables(struct smi_info *smi_info, u8 base,
549 557
550 if (smi_info->supports_event_msg_buff) 558 if (smi_info->supports_event_msg_buff)
551 enables |= IPMI_BMC_EVT_MSG_BUFF; 559 enables |= IPMI_BMC_EVT_MSG_BUFF;
552 else
553 enables &= ~IPMI_BMC_EVT_MSG_BUFF;
554 560
555 if (smi_info->irq && !smi_info->interrupt_disabled) 561 if ((smi_info->irq && !smi_info->interrupt_disabled) ||
562 smi_info->cannot_clear_recv_irq_bit)
556 enables |= IPMI_BMC_RCV_MSG_INTR; 563 enables |= IPMI_BMC_RCV_MSG_INTR;
557 else
558 enables &= ~IPMI_BMC_RCV_MSG_INTR;
559 564
560 if (smi_info->supports_event_msg_buff && 565 if (smi_info->supports_event_msg_buff &&
561 smi_info->irq && !smi_info->interrupt_disabled) 566 smi_info->irq && !smi_info->interrupt_disabled)
562 567
563 enables |= IPMI_BMC_EVT_MSG_INTR; 568 enables |= IPMI_BMC_EVT_MSG_INTR;
564 else
565 enables &= ~IPMI_BMC_EVT_MSG_INTR;
566 569
567 *irq_on = enables & (IPMI_BMC_EVT_MSG_INTR | IPMI_BMC_RCV_MSG_INTR); 570 *irq_on = enables & (IPMI_BMC_EVT_MSG_INTR | IPMI_BMC_RCV_MSG_INTR);
568 571
@@ -2900,6 +2903,96 @@ static int try_get_dev_id(struct smi_info *smi_info)
2900 return rv; 2903 return rv;
2901} 2904}
2902 2905
2906/*
2907 * Some BMCs do not support clearing the receive irq bit in the global
2908 * enables (even if they don't support interrupts on the BMC). Check
2909 * for this and handle it properly.
2910 */
2911static void check_clr_rcv_irq(struct smi_info *smi_info)
2912{
2913 unsigned char msg[3];
2914 unsigned char *resp;
2915 unsigned long resp_len;
2916 int rv;
2917
2918 resp = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL);
2919 if (!resp) {
2920 printk(KERN_WARNING PFX "Out of memory allocating response for"
2921 " global enables command, cannot check recv irq bit"
2922 " handling.\n");
2923 return;
2924 }
2925
2926 msg[0] = IPMI_NETFN_APP_REQUEST << 2;
2927 msg[1] = IPMI_GET_BMC_GLOBAL_ENABLES_CMD;
2928 smi_info->handlers->start_transaction(smi_info->si_sm, msg, 2);
2929
2930 rv = wait_for_msg_done(smi_info);
2931 if (rv) {
2932 printk(KERN_WARNING PFX "Error getting response from get"
2933 " global enables command, cannot check recv irq bit"
2934 " handling.\n");
2935 goto out;
2936 }
2937
2938 resp_len = smi_info->handlers->get_result(smi_info->si_sm,
2939 resp, IPMI_MAX_MSG_LENGTH);
2940
2941 if (resp_len < 4 ||
2942 resp[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2 ||
2943 resp[1] != IPMI_GET_BMC_GLOBAL_ENABLES_CMD ||
2944 resp[2] != 0) {
2945 printk(KERN_WARNING PFX "Invalid return from get global"
2946 " enables command, cannot check recv irq bit"
2947 " handling.\n");
2948 rv = -EINVAL;
2949 goto out;
2950 }
2951
2952 if ((resp[3] & IPMI_BMC_RCV_MSG_INTR) == 0)
2953 /* Already clear, should work ok. */
2954 goto out;
2955
2956 msg[0] = IPMI_NETFN_APP_REQUEST << 2;
2957 msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD;
2958 msg[2] = resp[3] & ~IPMI_BMC_RCV_MSG_INTR;
2959 smi_info->handlers->start_transaction(smi_info->si_sm, msg, 3);
2960
2961 rv = wait_for_msg_done(smi_info);
2962 if (rv) {
2963 printk(KERN_WARNING PFX "Error getting response from set"
2964 " global enables command, cannot check recv irq bit"
2965 " handling.\n");
2966 goto out;
2967 }
2968
2969 resp_len = smi_info->handlers->get_result(smi_info->si_sm,
2970 resp, IPMI_MAX_MSG_LENGTH);
2971
2972 if (resp_len < 3 ||
2973 resp[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2 ||
2974 resp[1] != IPMI_SET_BMC_GLOBAL_ENABLES_CMD) {
2975 printk(KERN_WARNING PFX "Invalid return from get global"
2976 " enables command, cannot check recv irq bit"
2977 " handling.\n");
2978 rv = -EINVAL;
2979 goto out;
2980 }
2981
2982 if (resp[2] != 0) {
2983 /*
2984 * An error when setting the event buffer bit means
2985 * clearing the bit is not supported.
2986 */
2987 printk(KERN_WARNING PFX "The BMC does not support clearing"
2988 " the recv irq bit, compensating, but the BMC needs to"
2989 " be fixed.\n");
2990 smi_info->cannot_clear_recv_irq_bit = true;
2991 }
2992 out:
2993 kfree(resp);
2994}
2995
2903static int try_enable_event_buffer(struct smi_info *smi_info) 2996static int try_enable_event_buffer(struct smi_info *smi_info)
2904{ 2997{
2905 unsigned char msg[3]; 2998 unsigned char msg[3];
@@ -3395,6 +3488,8 @@ static int try_smi_init(struct smi_info *new_smi)
3395 goto out_err; 3488 goto out_err;
3396 } 3489 }
3397 3490
3491 check_clr_rcv_irq(new_smi);
3492
3398 setup_oem_data_handler(new_smi); 3493 setup_oem_data_handler(new_smi);
3399 setup_xaction_handlers(new_smi); 3494 setup_xaction_handlers(new_smi);
3400 3495