aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCorey Minyard <cminyard@mvista.com>2015-08-18 15:29:10 -0400
committerCorey Minyard <cminyard@mvista.com>2015-09-03 16:02:30 -0400
commitd08828973d96eb26e48fb7ca8fb8a8d49adbe53a (patch)
tree10eb205c71c4f97388c4eb50ba5eab54926f76ad
parentc49c097610fe1aabf86111297280a718abb5dcc2 (diff)
ipmi: Compensate for BMCs that wont set the irq enable bit
It appears that some BMCs support interrupts but don't support setting the irq enable bits. The interrupts are just always on. Sigh. Add code to compensate. The new code was very similar to another functions, so this also factors out the common code into other functions. Signed-off-by: Corey Minyard <cminyard@mvista.com> Tested-by: Henrik Korkuc <henrik@kirneh.eu>
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c180
1 files changed, 137 insertions, 43 deletions
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index 2f4cf6e78f72..21bddc10e321 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -262,9 +262,21 @@ struct smi_info {
262 bool supports_event_msg_buff; 262 bool supports_event_msg_buff;
263 263
264 /* 264 /*
265 * Can we clear the global enables receive irq bit? 265 * Can we disable interrupts the global enables receive irq
266 * bit? There are currently two forms of brokenness, some
267 * systems cannot disable the bit (which is technically within
268 * the spec but a bad idea) and some systems have the bit
269 * forced to zero even though interrupts work (which is
270 * clearly outside the spec). The next bool tells which form
271 * of brokenness is present.
266 */ 272 */
267 bool cannot_clear_recv_irq_bit; 273 bool cannot_disable_irq;
274
275 /*
276 * Some systems are broken and cannot set the irq enable
277 * bit, even if they support interrupts.
278 */
279 bool irq_enable_broken;
268 280
269 /* 281 /*
270 * Did we get an attention that we did not handle? 282 * Did we get an attention that we did not handle?
@@ -554,13 +566,14 @@ static u8 current_global_enables(struct smi_info *smi_info, u8 base,
554 if (smi_info->supports_event_msg_buff) 566 if (smi_info->supports_event_msg_buff)
555 enables |= IPMI_BMC_EVT_MSG_BUFF; 567 enables |= IPMI_BMC_EVT_MSG_BUFF;
556 568
557 if ((smi_info->irq && !smi_info->interrupt_disabled) || 569 if (((smi_info->irq && !smi_info->interrupt_disabled) ||
558 smi_info->cannot_clear_recv_irq_bit) 570 smi_info->cannot_disable_irq) &&
571 !smi_info->irq_enable_broken)
559 enables |= IPMI_BMC_RCV_MSG_INTR; 572 enables |= IPMI_BMC_RCV_MSG_INTR;
560 573
561 if (smi_info->supports_event_msg_buff && 574 if (smi_info->supports_event_msg_buff &&
562 smi_info->irq && !smi_info->interrupt_disabled) 575 smi_info->irq && !smi_info->interrupt_disabled &&
563 576 !smi_info->irq_enable_broken)
564 enables |= IPMI_BMC_EVT_MSG_INTR; 577 enables |= IPMI_BMC_EVT_MSG_INTR;
565 578
566 *irq_on = enables & (IPMI_BMC_EVT_MSG_INTR | IPMI_BMC_RCV_MSG_INTR); 579 *irq_on = enables & (IPMI_BMC_EVT_MSG_INTR | IPMI_BMC_RCV_MSG_INTR);
@@ -2908,12 +2921,7 @@ static int try_get_dev_id(struct smi_info *smi_info)
2908 return rv; 2921 return rv;
2909} 2922}
2910 2923
2911/* 2924static int get_global_enables(struct smi_info *smi_info, u8 *enables)
2912 * Some BMCs do not support clearing the receive irq bit in the global
2913 * enables (even if they don't support interrupts on the BMC). Check
2914 * for this and handle it properly.
2915 */
2916static void check_clr_rcv_irq(struct smi_info *smi_info)
2917{ 2925{
2918 unsigned char msg[3]; 2926 unsigned char msg[3];
2919 unsigned char *resp; 2927 unsigned char *resp;
@@ -2921,12 +2929,8 @@ static void check_clr_rcv_irq(struct smi_info *smi_info)
2921 int rv; 2929 int rv;
2922 2930
2923 resp = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL); 2931 resp = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL);
2924 if (!resp) { 2932 if (!resp)
2925 printk(KERN_WARNING PFX "Out of memory allocating response for" 2933 return -ENOMEM;
2926 " global enables command, cannot check recv irq bit"
2927 " handling.\n");
2928 return;
2929 }
2930 2934
2931 msg[0] = IPMI_NETFN_APP_REQUEST << 2; 2935 msg[0] = IPMI_NETFN_APP_REQUEST << 2;
2932 msg[1] = IPMI_GET_BMC_GLOBAL_ENABLES_CMD; 2936 msg[1] = IPMI_GET_BMC_GLOBAL_ENABLES_CMD;
@@ -2934,9 +2938,9 @@ static void check_clr_rcv_irq(struct smi_info *smi_info)
2934 2938
2935 rv = wait_for_msg_done(smi_info); 2939 rv = wait_for_msg_done(smi_info);
2936 if (rv) { 2940 if (rv) {
2937 printk(KERN_WARNING PFX "Error getting response from get" 2941 dev_warn(smi_info->dev,
2938 " global enables command, cannot check recv irq bit" 2942 "Error getting response from get global enables command: %d\n",
2939 " handling.\n"); 2943 rv);
2940 goto out; 2944 goto out;
2941 } 2945 }
2942 2946
@@ -2947,27 +2951,44 @@ static void check_clr_rcv_irq(struct smi_info *smi_info)
2947 resp[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2 || 2951 resp[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2 ||
2948 resp[1] != IPMI_GET_BMC_GLOBAL_ENABLES_CMD || 2952 resp[1] != IPMI_GET_BMC_GLOBAL_ENABLES_CMD ||
2949 resp[2] != 0) { 2953 resp[2] != 0) {
2950 printk(KERN_WARNING PFX "Invalid return from get global" 2954 dev_warn(smi_info->dev,
2951 " enables command, cannot check recv irq bit" 2955 "Invalid return from get global enables command: %ld %x %x %x\n",
2952 " handling.\n"); 2956 resp_len, resp[0], resp[1], resp[2]);
2953 rv = -EINVAL; 2957 rv = -EINVAL;
2954 goto out; 2958 goto out;
2959 } else {
2960 *enables = resp[3];
2955 } 2961 }
2956 2962
2957 if ((resp[3] & IPMI_BMC_RCV_MSG_INTR) == 0) 2963out:
2958 /* Already clear, should work ok. */ 2964 kfree(resp);
2959 goto out; 2965 return rv;
2966}
2967
2968/*
2969 * Returns 1 if it gets an error from the command.
2970 */
2971static int set_global_enables(struct smi_info *smi_info, u8 enables)
2972{
2973 unsigned char msg[3];
2974 unsigned char *resp;
2975 unsigned long resp_len;
2976 int rv;
2977
2978 resp = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL);
2979 if (!resp)
2980 return -ENOMEM;
2960 2981
2961 msg[0] = IPMI_NETFN_APP_REQUEST << 2; 2982 msg[0] = IPMI_NETFN_APP_REQUEST << 2;
2962 msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD; 2983 msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD;
2963 msg[2] = resp[3] & ~IPMI_BMC_RCV_MSG_INTR; 2984 msg[2] = enables;
2964 smi_info->handlers->start_transaction(smi_info->si_sm, msg, 3); 2985 smi_info->handlers->start_transaction(smi_info->si_sm, msg, 3);
2965 2986
2966 rv = wait_for_msg_done(smi_info); 2987 rv = wait_for_msg_done(smi_info);
2967 if (rv) { 2988 if (rv) {
2968 printk(KERN_WARNING PFX "Error getting response from set" 2989 dev_warn(smi_info->dev,
2969 " global enables command, cannot check recv irq bit" 2990 "Error getting response from set global enables command: %d\n",
2970 " handling.\n"); 2991 rv);
2971 goto out; 2992 goto out;
2972 } 2993 }
2973 2994
@@ -2977,25 +2998,93 @@ static void check_clr_rcv_irq(struct smi_info *smi_info)
2977 if (resp_len < 3 || 2998 if (resp_len < 3 ||
2978 resp[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2 || 2999 resp[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2 ||
2979 resp[1] != IPMI_SET_BMC_GLOBAL_ENABLES_CMD) { 3000 resp[1] != IPMI_SET_BMC_GLOBAL_ENABLES_CMD) {
2980 printk(KERN_WARNING PFX "Invalid return from get global" 3001 dev_warn(smi_info->dev,
2981 " enables command, cannot check recv irq bit" 3002 "Invalid return from set global enables command: %ld %x %x\n",
2982 " handling.\n"); 3003 resp_len, resp[0], resp[1]);
2983 rv = -EINVAL; 3004 rv = -EINVAL;
2984 goto out; 3005 goto out;
2985 } 3006 }
2986 3007
2987 if (resp[2] != 0) { 3008 if (resp[2] != 0)
3009 rv = 1;
3010
3011out:
3012 kfree(resp);
3013 return rv;
3014}
3015
3016/*
3017 * Some BMCs do not support clearing the receive irq bit in the global
3018 * enables (even if they don't support interrupts on the BMC). Check
3019 * for this and handle it properly.
3020 */
3021static void check_clr_rcv_irq(struct smi_info *smi_info)
3022{
3023 u8 enables = 0;
3024 int rv;
3025
3026 rv = get_global_enables(smi_info, &enables);
3027 if (!rv) {
3028 if ((enables & IPMI_BMC_RCV_MSG_INTR) == 0)
3029 /* Already clear, should work ok. */
3030 return;
3031
3032 enables &= ~IPMI_BMC_RCV_MSG_INTR;
3033 rv = set_global_enables(smi_info, enables);
3034 }
3035
3036 if (rv < 0) {
3037 dev_err(smi_info->dev,
3038 "Cannot check clearing the rcv irq: %d\n", rv);
3039 return;
3040 }
3041
3042 if (rv) {
2988 /* 3043 /*
2989 * An error when setting the event buffer bit means 3044 * An error when setting the event buffer bit means
2990 * clearing the bit is not supported. 3045 * clearing the bit is not supported.
2991 */ 3046 */
2992 printk(KERN_WARNING PFX "The BMC does not support clearing" 3047 dev_warn(smi_info->dev,
2993 " the recv irq bit, compensating, but the BMC needs to" 3048 "The BMC does not support clearing the recv irq bit, compensating, but the BMC needs to be fixed.\n");
2994 " be fixed.\n"); 3049 smi_info->cannot_disable_irq = true;
2995 smi_info->cannot_clear_recv_irq_bit = true; 3050 }
3051}
3052
3053/*
3054 * Some BMCs do not support setting the interrupt bits in the global
3055 * enables even if they support interrupts. Clearly bad, but we can
3056 * compensate.
3057 */
3058static void check_set_rcv_irq(struct smi_info *smi_info)
3059{
3060 u8 enables = 0;
3061 int rv;
3062
3063 if (!smi_info->irq)
3064 return;
3065
3066 rv = get_global_enables(smi_info, &enables);
3067 if (!rv) {
3068 enables |= IPMI_BMC_RCV_MSG_INTR;
3069 rv = set_global_enables(smi_info, enables);
3070 }
3071
3072 if (rv < 0) {
3073 dev_err(smi_info->dev,
3074 "Cannot check setting the rcv irq: %d\n", rv);
3075 return;
3076 }
3077
3078 if (rv) {
3079 /*
3080 * An error when setting the event buffer bit means
3081 * setting the bit is not supported.
3082 */
3083 dev_warn(smi_info->dev,
3084 "The BMC does not support setting the recv irq bit, compensating, but the BMC needs to be fixed.\n");
3085 smi_info->cannot_disable_irq = true;
3086 smi_info->irq_enable_broken = true;
2996 } 3087 }
2997 out:
2998 kfree(resp);
2999} 3088}
3000 3089
3001static int try_enable_event_buffer(struct smi_info *smi_info) 3090static int try_enable_event_buffer(struct smi_info *smi_info)
@@ -3316,6 +3405,12 @@ static void setup_xaction_handlers(struct smi_info *smi_info)
3316 setup_dell_poweredge_bt_xaction_handler(smi_info); 3405 setup_dell_poweredge_bt_xaction_handler(smi_info);
3317} 3406}
3318 3407
3408static void check_for_broken_irqs(struct smi_info *smi_info)
3409{
3410 check_clr_rcv_irq(smi_info);
3411 check_set_rcv_irq(smi_info);
3412}
3413
3319static inline void wait_for_timer_and_thread(struct smi_info *smi_info) 3414static inline void wait_for_timer_and_thread(struct smi_info *smi_info)
3320{ 3415{
3321 if (smi_info->thread != NULL) 3416 if (smi_info->thread != NULL)
@@ -3493,10 +3588,9 @@ static int try_smi_init(struct smi_info *new_smi)
3493 goto out_err; 3588 goto out_err;
3494 } 3589 }
3495 3590
3496 check_clr_rcv_irq(new_smi);
3497
3498 setup_oem_data_handler(new_smi); 3591 setup_oem_data_handler(new_smi);
3499 setup_xaction_handlers(new_smi); 3592 setup_xaction_handlers(new_smi);
3593 check_for_broken_irqs(new_smi);
3500 3594
3501 new_smi->waiting_msg = NULL; 3595 new_smi->waiting_msg = NULL;
3502 new_smi->curr_msg = NULL; 3596 new_smi->curr_msg = NULL;