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 | ||
