It turned out that some BMCs - like Renesas H8S/2168 based ones - don't allow
reading back the value of the H_BUSY bit in BT_CTRL register (though the IPMI 
specs
require this bit to be readable by the host).

The patch below adds a workaround for BMCs that don't allow reading the H_BUSY
bit in the BT_CTRL register.

There are three main parts in this patch.

1. Introduce a copy of the H_BUSY bit and redefine the BT_STATUS and the
   BT_CONTROL(x) macros to use and to update this copy if reading H_BUSY
   is not supported in the hardware.

2. Introduce check_if_H_BUSY_readable() function to detect if H_BUSY is
   readable or not. So the driver activates the workaround automatically
   when needed. To perform the autodetection the driver toggles H_BUSY
   twice and sees if the H_BUSY value read back toggles as well. This is
   done right before the very first BT transaction is started, so toggling
   the H_BUSY at this phase would not confuse the BMC.

3. There is a chance that the H_BUSY copy and the real value of this bit
   could go out of sync. In particular, this patch assumes the H_BUSY bit to be
   cleared when the driver starts. If the H_BUSY bit value and its copy in the
   driver becomes different, the communication between the host and the BMC
   would break, and the driver would get to BT_STATE_RESET1 at some point.
   Here (only if H_BUSY is not readable) H_BUSY bit is inverted to give the
   driver a chance to restore the syncronization. The side effect is that
   in case of getting into the RESET1 state for some other reason (not related
   to H_BUSY being different from the copy of this bit in the driver) this
   H_BUSY bit inversion would make the copy to be out of sync with the H_BUSY
   bit. But this synchronization would be restored in the next RESET1.

I tried inverting H_BUSY early in the driver initialization to model the
situation of H_BUSY real value and the driver's local copy of this bit to get
out of sync. The driver survived that (though it took quite some time to go 
through
the BMC reset).

Signed-off-by: Andrei Konovalov <[EMAIL PROTECTED]>

diff --git a/drivers/char/ipmi/ipmi_bt_sm.c b/drivers/char/ipmi/ipmi_bt_sm.c
index 7b98c06..8480dcc 100644
--- a/drivers/char/ipmi/ipmi_bt_sm.c
+++ b/drivers/char/ipmi/ipmi_bt_sm.c
@@ -107,6 +107,10 @@ struct si_sm_data {
        int             BT_CAP_outreqs;
        long            BT_CAP_req2rsp;
        int             BT_CAP_retries; /* Recommended retries */
+
+       /* Some BMCs (e.g. H8S/2168 based) don't allow reading the H_BUSY bit */
+       int             BT_H_BUSY_is_readable; /* initialization isn't needed */
+       unsigned char   BT_H_BUSY_copy; /* should be initialized to 0 */
  };

  #define BT_CLR_WR_PTR 0x01    /* See IPMI 1.5 table 11.6.4 */
@@ -126,8 +130,38 @@ struct si_sm_data {
   * variable "bt" is hardcoded into these macros.
   */

-#define BT_STATUS      bt->io->inputb(bt->io, 0)
-#define BT_CONTROL(x)  bt->io->outputb(bt->io, 0, x)
+#define BT_STATUS ( \
+       (bt->BT_H_BUSY_is_readable) ? \
+       bt->io->inputb(bt->io, 0) : \
+       ((bt->io->inputb(bt->io, 0) & ~BT_H_BUSY) | bt->BT_H_BUSY_copy ) \
+       )
+#define BT_CONTROL(x) { \
+       bt->io->outputb(bt->io, 0, x); \
+       if (!bt->BT_H_BUSY_is_readable) bt->BT_H_BUSY_copy ^= (x & BT_H_BUSY); \
+       }
+#define BT_CTRL_H_BUSY_TRY_SYNC { \
+       if (!bt->BT_H_BUSY_is_readable) bt->io->outputb(bt->io, 0, BT_H_BUSY); \
+       }
+
+static void check_if_H_BUSY_readable(struct si_sm_data *bt)
+{
+       static int once = 1;
+
+       if (once) {
+               once = 0;
+
+               bt->BT_H_BUSY_is_readable =
+                       bt->io->inputb(bt->io, 0) & BT_H_BUSY;
+               bt->io->outputb(bt->io, 0, BT_H_BUSY);
+               bt->BT_H_BUSY_is_readable ^=
+                       bt->io->inputb(bt->io, 0) & BT_H_BUSY;
+               bt->io->outputb(bt->io, 0, BT_H_BUSY);
+
+               if (bt_debug)
+                       printk(KERN_WARNING "BT: H_BUSY is %sreadable\n",
+                              (bt->BT_H_BUSY_is_readable) ? "" : "not ");
+       }
+}

  #define BMC2HOST      bt->io->inputb(bt->io, 1)
  #define HOST2BMC(x)   bt->io->outputb(bt->io, 1, x)
@@ -238,6 +272,8 @@ static int bt_start_transaction(struct si_sm_data *bt,
        if (bt->state != BT_STATE_IDLE)
                return IPMI_NOT_IN_MY_STATE_ERR;

+       check_if_H_BUSY_readable(bt);
+
        if (bt_debug & BT_DEBUG_MSG) {
                printk(KERN_WARNING "BT: +++++++++++++++++ New command\n");
                printk(KERN_WARNING "BT: NetFn/LUN CMD [%d data]:", size - 2);
@@ -601,6 +637,10 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, 
long time)
                return SI_SM_CALL_WITH_DELAY;   /* No repeat printing */

        case BT_STATE_RESET1:
+               /* In case the H_BUSY bit is write only and the local copy
+                is out of sync with the H_BUSY bit toggle the H_BUSY */
+               BT_CTRL_H_BUSY_TRY_SYNC;
+
                reset_flags(bt);
                drain_BMC2HOST(bt);
                BT_STATE_CHANGE(BT_STATE_RESET2,

-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________
Openipmi-developer mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/openipmi-developer

Reply via email to