diff options
author | Corey Minyard <minyard@acm.org> | 2005-11-07 04:00:02 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-11-07 10:53:44 -0500 |
commit | c3e7e7916ec61cf58c88af12f4db17f28cffd83a (patch) | |
tree | 4d5be7158f79a9a2b1572e60af5c3645afa333c2 /drivers/char | |
parent | 21dcd300b15f87ce10df8773d029708f27499aa7 (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>
Diffstat (limited to 'drivers/char')
-rw-r--r-- | drivers/char/ipmi/ipmi_kcs_sm.c | 8 | ||||
-rw-r--r-- | drivers/char/ipmi/ipmi_si_intf.c | 3 | ||||
-rw-r--r-- | drivers/char/ipmi/ipmi_si_sm.h | 1 |
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 | ||
103 | struct si_sm_data | 105 | struct 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 | ||
120 | static unsigned int init_kcs_data(struct si_sm_data *kcs, | 123 | static 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. */ |