static void reset_flags(struct si_sm_data *bt) { if (bt_debug) printk(KERN_WARNING "IPMI BT: flag reset %s\n", status2txt(BT_STATUS)); if (BT_STATUS & BT_H_BUSY) BT_CONTROL(BT_H_BUSY); /* force clear */ BT_CONTROL(BT_CLR_WR_PTR); /* always reset */ BT_CONTROL(BT_SMS_ATN); /* always clear */ BT_INTMASK_W(BT_BMC_HWRST); }
static void drain_BMC2HOST(struct si_sm_data *bt) { int i, size; if (!(BT_STATUS & BT_B2H_ATN)) /* Not signalling a response */ return; BT_CONTROL(BT_H_BUSY); /* now set */ BT_CONTROL(BT_B2H_ATN); /* always clear */ BT_STATUS; /* pause */ BT_CONTROL(BT_B2H_ATN); /* some BMCs are stubborn */ BT_CONTROL(BT_CLR_RD_PTR); /* always reset */ if (bt_debug) printk(KERN_WARNING "IPMI BT: stale response %s; ", status2txt(BT_STATUS)); size = BMC2HOST; for (i = 0; i < size ; i++) BMC2HOST; BT_CONTROL(BT_H_BUSY); /* now clear */ if (bt_debug) printk("drained %d bytes\n", size + 1); }
static void reset_flags(struct si_sm_data *bt) { if (BT_STATUS & BT_H_BUSY) BT_CONTROL(BT_H_BUSY); if (BT_STATUS & BT_B_BUSY) BT_CONTROL(BT_B_BUSY); BT_CONTROL(BT_CLR_WR_PTR); BT_CONTROL(BT_SMS_ATN); if (BT_STATUS & BT_B2H_ATN) { int i; BT_CONTROL(BT_H_BUSY); BT_CONTROL(BT_B2H_ATN); BT_CONTROL(BT_CLR_RD_PTR); for (i = 0; i < IPMI_MAX_MSG_LENGTH + 2; i++) BMC2HOST; BT_CONTROL(BT_H_BUSY); } }
static void reset_flags(struct si_sm_data *bt) { if (BT_STATUS & BT_H_BUSY) BT_CONTROL(BT_H_BUSY); if (BT_STATUS & BT_B_BUSY) BT_CONTROL(BT_B_BUSY); BT_CONTROL(BT_CLR_WR_PTR); BT_CONTROL(BT_SMS_ATN); #ifdef DEVELOPMENT_ONLY_NOT_FOR_PRODUCTION if (BT_STATUS & BT_B2H_ATN) { int i; BT_CONTROL(BT_H_BUSY); BT_CONTROL(BT_B2H_ATN); BT_CONTROL(BT_CLR_RD_PTR); for (i = 0; i < IPMI_MAX_MSG_LENGTH + 2; i++) BMC2HOST; BT_CONTROL(BT_H_BUSY); } #endif }
static enum si_sm_result bt_event(struct si_sm_data *bt, long time) { unsigned char status, BT_CAP[8]; static enum bt_states last_printed = BT_STATE_PRINTME; int i; status = BT_STATUS; bt->nonzero_status |= status; if ((bt_debug & BT_DEBUG_STATES) && (bt->state != last_printed)) { printk(KERN_WARNING "BT: %s %s TO=%ld - %ld \n", STATE2TXT, STATUS2TXT, bt->timeout, time); last_printed = bt->state; } /* * Commands that time out may still (eventually) provide a response. * This stale response will get in the way of a new response so remove * it if possible (hopefully during IDLE). Even if it comes up later * it will be rejected by its (now-forgotten) seq number. */ if ((bt->state < BT_STATE_WRITE_BYTES) && (status & BT_B2H_ATN)) { drain_BMC2HOST(bt); BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY); } if ((bt->state != BT_STATE_IDLE) && (bt->state < BT_STATE_PRINTME)) { /* check timeout */ bt->timeout -= time; if ((bt->timeout < 0) && (bt->state < BT_STATE_RESET1)) return error_recovery(bt, status, IPMI_TIMEOUT_ERR); } switch (bt->state) { /* * Idle state first checks for asynchronous messages from another * channel, then does some opportunistic housekeeping. */ case BT_STATE_IDLE: if (status & BT_SMS_ATN) { BT_CONTROL(BT_SMS_ATN); /* clear it */ return SI_SM_ATTN; } if (status & BT_H_BUSY) /* clear a leftover H_BUSY */ BT_CONTROL(BT_H_BUSY); /* Read BT capabilities if it hasn't been done yet */ if (!bt->BT_CAP_outreqs) BT_STATE_CHANGE(BT_STATE_CAPABILITIES_BEGIN, SI_SM_CALL_WITHOUT_DELAY); bt->timeout = bt->BT_CAP_req2rsp; BT_SI_SM_RETURN(SI_SM_IDLE); case BT_STATE_XACTION_START: if (status & (BT_B_BUSY | BT_H2B_ATN)) BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY); if (BT_STATUS & BT_H_BUSY) BT_CONTROL(BT_H_BUSY); /* force clear */ BT_STATE_CHANGE(BT_STATE_WRITE_BYTES, SI_SM_CALL_WITHOUT_DELAY); case BT_STATE_WRITE_BYTES: if (status & BT_H_BUSY) BT_CONTROL(BT_H_BUSY); /* clear */ BT_CONTROL(BT_CLR_WR_PTR); write_all_bytes(bt); BT_CONTROL(BT_H2B_ATN); /* can clear too fast to catch */ BT_STATE_CHANGE(BT_STATE_WRITE_CONSUME, SI_SM_CALL_WITHOUT_DELAY); case BT_STATE_WRITE_CONSUME: if (status & (BT_B_BUSY | BT_H2B_ATN)) BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY); BT_STATE_CHANGE(BT_STATE_READ_WAIT, SI_SM_CALL_WITHOUT_DELAY); /* Spinning hard can suppress B2H_ATN and force a timeout */ case BT_STATE_READ_WAIT: if (!(status & BT_B2H_ATN)) BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY); BT_CONTROL(BT_H_BUSY); /* set */ /* * Uncached, ordered writes should just proceeed serially but * some BMCs don't clear B2H_ATN with one hit. Fast-path a * workaround without too much penalty to the general case. */ BT_CONTROL(BT_B2H_ATN); /* clear it to ACK the BMC */ BT_STATE_CHANGE(BT_STATE_CLEAR_B2H, SI_SM_CALL_WITHOUT_DELAY); case BT_STATE_CLEAR_B2H: if (status & BT_B2H_ATN) { /* keep hitting it */ BT_CONTROL(BT_B2H_ATN); BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY); } BT_STATE_CHANGE(BT_STATE_READ_BYTES, SI_SM_CALL_WITHOUT_DELAY); case BT_STATE_READ_BYTES: if (!(status & BT_H_BUSY)) /* check in case of retry */ BT_CONTROL(BT_H_BUSY); BT_CONTROL(BT_CLR_RD_PTR); /* start of BMC2HOST buffer */ i = read_all_bytes(bt); /* true == packet seq match */ BT_CONTROL(BT_H_BUSY); /* NOW clear */ if (!i) /* Not my message */ BT_STATE_CHANGE(BT_STATE_READ_WAIT, SI_SM_CALL_WITHOUT_DELAY); bt->state = bt->complete; return bt->state == BT_STATE_IDLE ? /* where to next? */ SI_SM_TRANSACTION_COMPLETE : /* normal */ SI_SM_CALL_WITHOUT_DELAY; /* Startup magic */ case BT_STATE_LONG_BUSY: /* For example: after FW update */ if (!(status & BT_B_BUSY)) { reset_flags(bt); /* next state is now IDLE */ bt_init_data(bt, bt->io); } return SI_SM_CALL_WITH_DELAY; /* No repeat printing */ case BT_STATE_RESET1: reset_flags(bt); drain_BMC2HOST(bt); BT_STATE_CHANGE(BT_STATE_RESET2, SI_SM_CALL_WITH_DELAY); case BT_STATE_RESET2: /* Send a soft reset */ BT_CONTROL(BT_CLR_WR_PTR); HOST2BMC(3); /* number of bytes following */ HOST2BMC(0x18); /* NetFn/LUN == Application, LUN 0 */ HOST2BMC(42); /* Sequence number */ HOST2BMC(3); /* Cmd == Soft reset */ BT_CONTROL(BT_H2B_ATN); bt->timeout = BT_RESET_DELAY * 1000000; BT_STATE_CHANGE(BT_STATE_RESET3, SI_SM_CALL_WITH_DELAY); case BT_STATE_RESET3: /* Hold off everything for a bit */ if (bt->timeout > 0) return SI_SM_CALL_WITH_DELAY; drain_BMC2HOST(bt); BT_STATE_CHANGE(BT_STATE_RESTART, SI_SM_CALL_WITH_DELAY); case BT_STATE_RESTART: /* don't reset retries or seq! */ bt->read_count = 0; bt->nonzero_status = 0; bt->timeout = bt->BT_CAP_req2rsp; BT_STATE_CHANGE(BT_STATE_XACTION_START, SI_SM_CALL_WITH_DELAY); /* * Get BT Capabilities, using timing of upper level state machine. * Set outreqs to prevent infinite loop on timeout. */ case BT_STATE_CAPABILITIES_BEGIN: bt->BT_CAP_outreqs = 1; { unsigned char GetBT_CAP[] = { 0x18, 0x36 }; bt->state = BT_STATE_IDLE; bt_start_transaction(bt, GetBT_CAP, sizeof(GetBT_CAP)); } bt->complete = BT_STATE_CAPABILITIES_END; BT_STATE_CHANGE(BT_STATE_XACTION_START, SI_SM_CALL_WITH_DELAY); case BT_STATE_CAPABILITIES_END: i = bt_get_result(bt, BT_CAP, sizeof(BT_CAP)); bt_init_data(bt, bt->io); if ((i == 8) && !BT_CAP[2]) { bt->BT_CAP_outreqs = BT_CAP[3]; bt->BT_CAP_req2rsp = BT_CAP[6] * 1000000; bt->BT_CAP_retries = BT_CAP[7]; } else printk(KERN_WARNING "IPMI BT: using default values\n"); if (!bt->BT_CAP_outreqs) bt->BT_CAP_outreqs = 1; printk(KERN_WARNING "IPMI BT: req2rsp=%ld secs retries=%d\n", bt->BT_CAP_req2rsp / 1000000L, bt->BT_CAP_retries); bt->timeout = bt->BT_CAP_req2rsp; return SI_SM_CALL_WITHOUT_DELAY; default: /* should never occur */ return error_recovery(bt, status, IPMI_ERR_UNSPECIFIED); } return SI_SM_CALL_WITH_DELAY; }
static enum si_sm_result bt_event(struct si_sm_data *bt, long time) { unsigned char status; char buf[40]; /* For getting status */ int i; status = BT_STATUS; bt->nonzero_status |= status; if ((bt_debug & BT_DEBUG_STATES) && (bt->state != bt->last_state)) printk(KERN_WARNING "BT: %s %s TO=%ld - %ld \n", STATE2TXT, STATUS2TXT(buf), bt->timeout, time); bt->last_state = bt->state; if (bt->state == BT_STATE_HOSED) return SI_SM_HOSED; if (bt->state != BT_STATE_IDLE) { /* do timeout test */ /* Certain states, on error conditions, can lock up a CPU because they are effectively in an infinite loop with CALL_WITHOUT_DELAY (right back here with time == 0). Prevent infinite lockup by ALWAYS decrementing timeout. */ /* FIXME: bt_event is sometimes called with time > BT_NORMAL_TIMEOUT (noticed in ipmi_smic_sm.c January 2004) */ if ((time <= 0) || (time >= BT_NORMAL_TIMEOUT)) time = 100; bt->timeout -= time; if ((bt->timeout < 0) && (bt->state < BT_STATE_RESET1)) { error_recovery(bt, "timed out"); return SI_SM_CALL_WITHOUT_DELAY; } } switch (bt->state) { case BT_STATE_IDLE: /* check for asynchronous messages */ if (status & BT_SMS_ATN) { BT_CONTROL(BT_SMS_ATN); /* clear it */ return SI_SM_ATTN; } return SI_SM_IDLE; case BT_STATE_XACTION_START: if (status & BT_H_BUSY) { BT_CONTROL(BT_H_BUSY); break; } if (status & BT_B2H_ATN) break; bt->state = BT_STATE_WRITE_BYTES; return SI_SM_CALL_WITHOUT_DELAY; /* for logging */ case BT_STATE_WRITE_BYTES: if (status & (BT_B_BUSY | BT_H2B_ATN)) break; BT_CONTROL(BT_CLR_WR_PTR); write_all_bytes(bt); BT_CONTROL(BT_H2B_ATN); /* clears too fast to catch? */ bt->state = BT_STATE_WRITE_CONSUME; return SI_SM_CALL_WITHOUT_DELAY; /* it MIGHT sail through */ case BT_STATE_WRITE_CONSUME: /* BMCs usually blow right thru here */ if (status & (BT_H2B_ATN | BT_B_BUSY)) break; bt->state = BT_STATE_B2H_WAIT; /* fall through with status */ /* Stay in BT_STATE_B2H_WAIT until a packet matches. However, spinning hard here, constantly reading status, seems to hold off the generation of B2H_ATN so ALWAYS return CALL_WITH_DELAY. */ case BT_STATE_B2H_WAIT: if (!(status & BT_B2H_ATN)) break; /* Assume ordered, uncached writes: no need to wait */ if (!(status & BT_H_BUSY)) BT_CONTROL(BT_H_BUSY); /* set */ BT_CONTROL(BT_B2H_ATN); /* clear it, ACK to the BMC */ BT_CONTROL(BT_CLR_RD_PTR); /* reset the queue */ i = read_all_bytes(bt); BT_CONTROL(BT_H_BUSY); /* clear */ if (!i) break; /* Try this state again */ bt->state = BT_STATE_READ_END; return SI_SM_CALL_WITHOUT_DELAY; /* for logging */ case BT_STATE_READ_END: /* I could wait on BT_H_BUSY to go clear for a truly clean exit. However, this is already done in XACTION_START and the (possible) extra loop/status/possible wait affects performance. So, as long as it works, just ignore H_BUSY */ #ifdef MAKE_THIS_TRUE_IF_NECESSARY if (status & BT_H_BUSY) break; #endif bt->seq++; bt->state = BT_STATE_IDLE; return SI_SM_TRANSACTION_COMPLETE; case BT_STATE_RESET1: reset_flags(bt); bt->timeout = BT_RESET_DELAY; bt->state = BT_STATE_RESET2; break; case BT_STATE_RESET2: /* Send a soft reset */ BT_CONTROL(BT_CLR_WR_PTR); HOST2BMC(3); /* number of bytes following */ HOST2BMC(0x18); /* NetFn/LUN == Application, LUN 0 */ HOST2BMC(42); /* Sequence number */ HOST2BMC(3); /* Cmd == Soft reset */ BT_CONTROL(BT_H2B_ATN); bt->state = BT_STATE_RESET3; break; case BT_STATE_RESET3: if (bt->timeout > 0) return SI_SM_CALL_WITH_DELAY; bt->state = BT_STATE_RESTART; /* printk in debug modes */ break; case BT_STATE_RESTART: /* don't reset retries! */ bt->write_data[2] = ++bt->seq; bt->read_count = 0; bt->nonzero_status = 0; bt->timeout = BT_NORMAL_TIMEOUT; bt->state = BT_STATE_XACTION_START; break; default: /* HOSED is supposed to be caught much earlier */ error_recovery(bt, "internal logic error"); break; } return SI_SM_CALL_WITH_DELAY; }
/* * Portions Copyright 2011 VMware, Inc. */ static int bt_detect(struct si_sm_data *bt) { /* * It's impossible for the BT status and interrupt registers to be * all 1's, (assuming a properly functioning, self-initialized BMC) * but that's what you get from reading a bogus address, so we * test that first. The calling routine uses negative logic. */ unsigned char bt_status = BT_STATUS; unsigned char bt_intmask = BT_INTMASK_R; if ((bt_status == 0xFF) || (bt_intmask == 0xFF)) { if (bt_debug) { printk(KERN_WARNING "IPMI BT: BT__STATUS or BT_MASK is invalid: %d, %d\n", bt_status, bt_intmask); } return 1; } /* * Test the R/W bits on the BT interface to ascertain if the device is * truly available. These bits the host to device clear read bit and clear write * bit, bit 0 and 1 on the BT_CNTL register and bit 7 the h/w reset bit of the * BT_INTMASK register. The R/W bits should return 0 when read */ if (bt_status & (BT_CLR_WR_PTR | BT_CLR_RD_PTR)) { if (bt_debug) { printk(KERN_WARNING "IPMI BT: BT_CLR_WR_PTR or BT_CLR_RD_PTR are not 0: %d, %d\n", (bt_status & BT_CLR_WR_PTR), (bt_status & BT_CLR_WR_PTR)); } return 1; } if(bt_intmask & BT_BMC_HWRST) { if (bt_debug) { printk(KERN_WARNING "IPMI BT: BT_BMC_HWRST is not 0: %d\n", (bt_intmask & BT_BMC_HWRST)); } return 1; } /* * The H_BUSY (bit 6) of the BT_CNTL register works as a toggle bit, with * the state of the bit toggling if a 1 is written. No change is seen if 0 is * written. This bit is toggled to further verify the presence of the BT interface */ // Toggle bit BT_CONTROL(BT_H_BUSY); if (!((bt_status ^ BT_STATUS) & BT_H_BUSY)) { if (bt_debug) { printk(KERN_WARNING "IPMI BT: Unable to toggle BT_H_BUSY once\n"); } return 1; } //Toggle again BT_CONTROL(BT_H_BUSY); if ((bt_status ^ BT_STATUS) & BT_H_BUSY) { if (bt_debug) { printk(KERN_WARNING "IPMI BT: Unable to toggle BT_H_BUSY twice\n"); } return 1; } reset_flags(bt); return 0; }
static enum si_sm_result bt_event(struct si_sm_data *bt, long time) { unsigned char status, BT_CAP[8]; static enum bt_states last_printed = BT_STATE_PRINTME; int i; status = BT_STATUS; bt->nonzero_status |= status; if ((bt_debug & BT_DEBUG_STATES) && (bt->state != last_printed)) { printk(KERN_WARNING "BT: %s %s TO=%ld - %ld \n", STATE2TXT, STATUS2TXT, bt->timeout, time); last_printed = bt->state; } /* * Commands that time out may still (eventually) provide a response. * This stale response will get in the way of a new response so remove * it if possible (hopefully during IDLE). Even if it comes up later * it will be rejected by its (now-forgotten) seq number. */ if ((bt->state < BT_STATE_WRITE_BYTES) && (status & BT_B2H_ATN)) { drain_BMC2HOST(bt); BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY); } if ((bt->state != BT_STATE_IDLE) && (bt->state < BT_STATE_PRINTME)) { /* check timeout */ bt->timeout -= time; if ((bt->timeout < 0) && (bt->state < BT_STATE_RESET1)) return error_recovery(bt, status, IPMI_TIMEOUT_ERR); } switch (bt->state) { /* * Idle state first checks for asynchronous messages from another * channel, then does some opportunistic housekeeping. */ case BT_STATE_IDLE: if (status & BT_SMS_ATN) { BT_CONTROL(BT_SMS_ATN); /* clear it */ return SI_SM_ATTN; } if (status & BT_H_BUSY) /* clear a leftover H_BUSY */ BT_CONTROL(BT_H_BUSY); /* Read BT capabilities if it hasn't been done yet */ if (!bt->BT_CAP_outreqs) BT_STATE_CHANGE(BT_STATE_CAPABILITIES_BEGIN, SI_SM_CALL_WITHOUT_DELAY); bt->timeout = bt->BT_CAP_req2rsp; BT_SI_SM_RETURN(SI_SM_IDLE); case BT_STATE_XACTION_START: if (status & (BT_B_BUSY | BT_H2B_ATN)) BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY); if (BT_STATUS & BT_H_BUSY) BT_CONTROL(BT_H_BUSY); /* force clear */ BT_STATE_CHANGE(BT_STATE_WRITE_BYTES, SI_SM_CALL_WITHOUT_DELAY); case BT_STATE_WRITE_BYTES: if (status & BT_H_BUSY) BT_CONTROL(BT_H_BUSY); /* clear */ BT_CONTROL(BT_CLR_WR_PTR); write_all_bytes(bt); BT_CONTROL(BT_H2B_ATN); /* can clear too fast to catch */ BT_STATE_CHANGE(BT_STATE_WRITE_CONSUME, SI_SM_CALL_WITHOUT_DELAY); case BT_STATE_WRITE_CONSUME: if (status & (BT_B_BUSY | BT_H2B_ATN)) BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY); BT_STATE_CHANGE(BT_STATE_READ