aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCorey Minyard <minyard@acm.org>2005-11-07 04:00:02 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2005-11-07 10:53:44 -0500
commitc3e7e7916ec61cf58c88af12f4db17f28cffd83a (patch)
tree4d5be7158f79a9a2b1572e60af5c3645afa333c2
parent21dcd300b15f87ce10df8773d029708f27499aa7 (diff)
[PATCH] ipmi: kcs error0 delay
BMCs can get into ERROR0 state while flashing new firmware, particularly while the BMC is erasing the next flash block, which may take a just under 2 seconds on a Dell PowerEdge 2800 (1.75 seconds typical), during which time the single-threaded firmware may not be able to process new commands. In particular, clearing OBF may not take effect immediately. We want it to delay in ERROR0 after clearing OBF a bit waiting for OBF to actually be clear before proceeding. This introduces a new return value from the LLDD's event loop, SI_SM_CALL_WITH_TICK_DELAY. This means the calling thread/timer should schedule_timeout() at least 1 tick, rather than busy-wait. This is a longer delay than SI_SM_CALL_WITH_DELAY, which is typically a 250us busy-wait. Signed-off-by: Matt Domsch <Matt_Domsch@dell.com> Signed-off-by: Corey Minyard <minyard@acm.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--drivers/char/ipmi/ipmi_kcs_sm.c8
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c3
-rw-r--r--drivers/char/ipmi/ipmi_si_sm.h1
3 files changed, 11 insertions, 1 deletions
diff --git a/drivers/char/ipmi/ipmi_kcs_sm.c b/drivers/char/ipmi/ipmi_kcs_sm.c
index dc83365ede4a..da1554194d3d 100644
--- a/drivers/char/ipmi/ipmi_kcs_sm.c
+++ b/drivers/char/ipmi/ipmi_kcs_sm.c
@@ -41,6 +41,7 @@
41#include <linux/module.h> 41#include <linux/module.h>
42#include <linux/moduleparam.h> 42#include <linux/moduleparam.h>
43#include <linux/string.h> 43#include <linux/string.h>
44#include <linux/jiffies.h>
44#include <linux/ipmi_msgdefs.h> /* for completion codes */ 45#include <linux/ipmi_msgdefs.h> /* for completion codes */
45#include "ipmi_si_sm.h" 46#include "ipmi_si_sm.h"
46 47
@@ -99,6 +100,7 @@ enum kcs_states {
99#define IBF_RETRY_TIMEOUT 1000000 100#define IBF_RETRY_TIMEOUT 1000000
100#define OBF_RETRY_TIMEOUT 1000000 101#define OBF_RETRY_TIMEOUT 1000000
101#define MAX_ERROR_RETRIES 10 102#define MAX_ERROR_RETRIES 10
103#define ERROR0_OBF_WAIT_JIFFIES (2*HZ)
102 104
103struct si_sm_data 105struct si_sm_data
104{ 106{
@@ -115,6 +117,7 @@ struct si_sm_data
115 unsigned int error_retries; 117 unsigned int error_retries;
116 long ibf_timeout; 118 long ibf_timeout;
117 long obf_timeout; 119 long obf_timeout;
120 unsigned long error0_timeout;
118}; 121};
119 122
120static unsigned int init_kcs_data(struct si_sm_data *kcs, 123static unsigned int init_kcs_data(struct si_sm_data *kcs,
@@ -187,6 +190,7 @@ static inline void start_error_recovery(struct si_sm_data *kcs, char *reason)
187 printk(KERN_DEBUG "ipmi_kcs_sm: kcs hosed: %s\n", reason); 190 printk(KERN_DEBUG "ipmi_kcs_sm: kcs hosed: %s\n", reason);
188 kcs->state = KCS_HOSED; 191 kcs->state = KCS_HOSED;
189 } else { 192 } else {
193 kcs->error0_timeout = jiffies + ERROR0_OBF_WAIT_JIFFIES;
190 kcs->state = KCS_ERROR0; 194 kcs->state = KCS_ERROR0;
191 } 195 }
192} 196}
@@ -423,6 +427,10 @@ static enum si_sm_result kcs_event(struct si_sm_data *kcs, long time)
423 427
424 case KCS_ERROR0: 428 case KCS_ERROR0:
425 clear_obf(kcs, status); 429 clear_obf(kcs, status);
430 status = read_status(kcs);
431 if (GET_STATUS_OBF(status)) /* controller isn't responding */
432 if (time_before(jiffies, kcs->error0_timeout))
433 return SI_SM_CALL_WITH_TICK_DELAY;
426 write_cmd(kcs, KCS_GET_STATUS_ABORT); 434 write_cmd(kcs, KCS_GET_STATUS_ABORT);
427 kcs->state = KCS_ERROR1; 435 kcs->state = KCS_ERROR1;
428 break; 436 break;
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index 2ace62b1d326..d514df7c7283 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -1932,7 +1932,8 @@ static int try_get_dev_id(struct smi_info *smi_info)
1932 smi_result = smi_info->handlers->event(smi_info->si_sm, 0); 1932 smi_result = smi_info->handlers->event(smi_info->si_sm, 0);
1933 for (;;) 1933 for (;;)
1934 { 1934 {
1935 if (smi_result == SI_SM_CALL_WITH_DELAY) { 1935 if (smi_result == SI_SM_CALL_WITH_DELAY ||
1936 smi_result == SI_SM_CALL_WITH_TICK_DELAY) {
1936 schedule_timeout_uninterruptible(1); 1937 schedule_timeout_uninterruptible(1);
1937 smi_result = smi_info->handlers->event( 1938 smi_result = smi_info->handlers->event(
1938 smi_info->si_sm, 100); 1939 smi_info->si_sm, 100);
diff --git a/drivers/char/ipmi/ipmi_si_sm.h b/drivers/char/ipmi/ipmi_si_sm.h
index 62791dd42985..bf3d4962d6a5 100644
--- a/drivers/char/ipmi/ipmi_si_sm.h
+++ b/drivers/char/ipmi/ipmi_si_sm.h
@@ -62,6 +62,7 @@ enum si_sm_result
62{ 62{
63 SI_SM_CALL_WITHOUT_DELAY, /* Call the driver again immediately */ 63 SI_SM_CALL_WITHOUT_DELAY, /* Call the driver again immediately */
64 SI_SM_CALL_WITH_DELAY, /* Delay some before calling again. */ 64 SI_SM_CALL_WITH_DELAY, /* Delay some before calling again. */
65 SI_SM_CALL_WITH_TICK_DELAY, /* Delay at least 1 tick before calling again. */
65 SI_SM_TRANSACTION_COMPLETE, /* A transaction is finished. */ 66 SI_SM_TRANSACTION_COMPLETE, /* A transaction is finished. */
66 SI_SM_IDLE, /* The SM is in idle state. */ 67 SI_SM_IDLE, /* The SM is in idle state. */
67 SI_SM_HOSED, /* The hardware violated the state machine. */ 68 SI_SM_HOSED, /* The hardware violated the state machine. */