diff options
-rw-r--r-- | drivers/char/ipmi/ipmi_si_intf.c | 109 |
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 | */ |
465 | static inline bool disable_si_irq(struct smi_info *smi_info) | 473 | static 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 | */ | ||
2911 | static 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 | |||
2903 | static int try_enable_event_buffer(struct smi_info *smi_info) | 2996 | static 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 | ||