bool ar9003_mci_start_reset(struct ath_hw *ah, struct ath9k_channel *chan) { struct ath_common *common = ath9k_hw_common(ah); struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci; u32 payload[4] = {0, 0, 0, 0}; ar9003_mci_2g5g_changed(ah, IS_CHAN_2GHZ(chan)); if (mci_hw->bt_state != MCI_BT_CAL_START) return false; mci_hw->bt_state = MCI_BT_CAL; ar9003_mci_disable_interrupt(ah); MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_GRANT); ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, true, false); if (ar9003_mci_wait_for_gpm(ah, MCI_GPM_BT_CAL_DONE, 0, 25000)) ath_dbg(common, MCI, "MCI BT_CAL_DONE received\n"); else ath_dbg(common, MCI, "MCI BT_CAL_DONE not received\n"); mci_hw->bt_state = MCI_BT_AWAKE; ar9003_mci_enable_interrupt(ah); return true; }
void ar9003_mci_init_cal_done(struct ath_hw *ah) { struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci; u32 pld[4] = {0, 0, 0, 0}; if ((mci_hw->bt_state != MCI_BT_AWAKE) || (mci_hw->config & ATH_MCI_CONFIG_DISABLE_MCI_CAL)) return; MCI_GPM_SET_CAL_TYPE(pld, MCI_GPM_WLAN_CAL_DONE); pld[MCI_GPM_WLAN_CAL_W_SEQUENCE] = mci_hw->wlan_cal_done++; ar9003_mci_send_message(ah, MCI_GPM, 0, pld, 16, true, false); }
bool ar9003_mci_start_reset(struct ath_hw *ah, struct ath9k_channel *chan) { struct ath_common *common = ath9k_hw_common(ah); struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci; u32 payload[4] = {0, 0, 0, 0}; ar9003_mci_2g5g_changed(ah, IS_CHAN_2GHZ(chan)); if (mci_hw->bt_state != MCI_BT_CAL_START) return false; mci_hw->bt_state = MCI_BT_CAL; /* * MCI FIX: disable mci interrupt here. This is to avoid * SW_MSG_DONE or RX_MSG bits to trigger MCI_INT and * lead to mci_intr reentry. */ ar9003_mci_disable_interrupt(ah); MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_GRANT); ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, true, false); /* Wait BT calibration to be completed for 25ms */ if (ar9003_mci_wait_for_gpm(ah, MCI_GPM_BT_CAL_DONE, 0, 25000)) ath_dbg(common, MCI, "MCI BT_CAL_DONE received\n"); else ath_dbg(common, MCI, "MCI BT_CAL_DONE not received\n"); mci_hw->bt_state = MCI_BT_AWAKE; /* MCI FIX: enable mci interrupt here */ ar9003_mci_enable_interrupt(ah); return true; }
void ar9003_mci_init_cal_req(struct ath_hw *ah, bool *is_reusable) { struct ath_common *common = ath9k_hw_common(ah); struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci; u32 pld[4] = {0, 0, 0, 0}; if ((mci_hw->bt_state != MCI_BT_AWAKE) || (mci_hw->config & ATH_MCI_CONFIG_DISABLE_MCI_CAL)) return; MCI_GPM_SET_CAL_TYPE(pld, MCI_GPM_WLAN_CAL_REQ); pld[MCI_GPM_WLAN_CAL_W_SEQUENCE] = mci_hw->wlan_cal_seq++; ar9003_mci_send_message(ah, MCI_GPM, 0, pld, 16, true, false); if (ar9003_mci_wait_for_gpm(ah, MCI_GPM_BT_CAL_GRANT, 0, 50000)) { ath_dbg(common, MCI, "MCI BT_CAL_GRANT received\n"); } else { *is_reusable = false; ath_dbg(common, MCI, "MCI BT_CAL_GRANT not received\n"); } }
static u32 ar9003_mci_wait_for_gpm(struct ath_hw *ah, u8 gpm_type, u8 gpm_opcode, int time_out) { struct ath_common *common = ath9k_hw_common(ah); struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; u32 *p_gpm = NULL, mismatch = 0, more_data; u32 offset; u8 recv_type = 0, recv_opcode = 0; bool b_is_bt_cal_done = (gpm_type == MCI_GPM_BT_CAL_DONE); more_data = time_out ? MCI_GPM_NOMORE : MCI_GPM_MORE; while (time_out > 0) { if (p_gpm) { MCI_GPM_RECYCLE(p_gpm); p_gpm = NULL; } if (more_data != MCI_GPM_MORE) time_out = ar9003_mci_wait_for_interrupt(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, AR_MCI_INTERRUPT_RX_MSG_GPM, time_out); if (!time_out) break; offset = ar9003_mci_get_next_gpm_offset(ah, false, &more_data); if (offset == MCI_GPM_INVALID) continue; p_gpm = (u32 *) (mci->gpm_buf + offset); recv_type = MCI_GPM_TYPE(p_gpm); recv_opcode = MCI_GPM_OPCODE(p_gpm); if (MCI_GPM_IS_CAL_TYPE(recv_type)) { if (recv_type == gpm_type) { if ((gpm_type == MCI_GPM_BT_CAL_DONE) && !b_is_bt_cal_done) { gpm_type = MCI_GPM_BT_CAL_GRANT; continue; } break; } } else if ((recv_type == gpm_type) && (recv_opcode == gpm_opcode)) break; /* * check if it's cal_grant * * When we're waiting for cal_grant in reset routine, * it's possible that BT sends out cal_request at the * same time. Since BT's calibration doesn't happen * that often, we'll let BT completes calibration then * we continue to wait for cal_grant from BT. * Orginal: Wait BT_CAL_GRANT. * New: Receive BT_CAL_REQ -> send WLAN_CAL_GRANT->wait * BT_CAL_DONE -> Wait BT_CAL_GRANT. */ if ((gpm_type == MCI_GPM_BT_CAL_GRANT) && (recv_type == MCI_GPM_BT_CAL_REQ)) { u32 payload[4] = {0, 0, 0, 0}; gpm_type = MCI_GPM_BT_CAL_DONE; MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_GRANT); ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, false, false); continue; } else { ath_dbg(common, MCI, "MCI GPM subtype not match 0x%x\n", *(p_gpm + 1)); mismatch++; ar9003_mci_process_gpm_extra(ah, recv_type, recv_opcode, p_gpm); } } if (p_gpm) { MCI_GPM_RECYCLE(p_gpm); p_gpm = NULL; } if (time_out <= 0) time_out = 0; while (more_data == MCI_GPM_MORE) { offset = ar9003_mci_get_next_gpm_offset(ah, false, &more_data); if (offset == MCI_GPM_INVALID) break; p_gpm = (u32 *) (mci->gpm_buf + offset); recv_type = MCI_GPM_TYPE(p_gpm); recv_opcode = MCI_GPM_OPCODE(p_gpm); if (!MCI_GPM_IS_CAL_TYPE(recv_type)) ar9003_mci_process_gpm_extra(ah, recv_type, recv_opcode, p_gpm); MCI_GPM_RECYCLE(p_gpm); } return time_out; }
static u32 ar9003_mci_wait_for_gpm(struct ath_hw *ah, u8 gpm_type, u8 gpm_opcode, int time_out) { struct ath_common *common = ath9k_hw_common(ah); struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; u32 *p_gpm = NULL, mismatch = 0, more_data; u32 offset; u8 recv_type = 0, recv_opcode = 0; bool b_is_bt_cal_done = (gpm_type == MCI_GPM_BT_CAL_DONE); more_data = time_out ? MCI_GPM_NOMORE : MCI_GPM_MORE; while (time_out > 0) { if (p_gpm) { MCI_GPM_RECYCLE(p_gpm); p_gpm = NULL; } if (more_data != MCI_GPM_MORE) time_out = ar9003_mci_wait_for_interrupt(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, AR_MCI_INTERRUPT_RX_MSG_GPM, time_out); if (!time_out) break; offset = ar9003_mci_state(ah, MCI_STATE_NEXT_GPM_OFFSET, &more_data); if (offset == MCI_GPM_INVALID) continue; p_gpm = (u32 *) (mci->gpm_buf + offset); recv_type = MCI_GPM_TYPE(p_gpm); recv_opcode = MCI_GPM_OPCODE(p_gpm); if (MCI_GPM_IS_CAL_TYPE(recv_type)) { if (recv_type == gpm_type) { if ((gpm_type == MCI_GPM_BT_CAL_DONE) && !b_is_bt_cal_done) { gpm_type = MCI_GPM_BT_CAL_GRANT; continue; } break; } } else if ((recv_type == gpm_type) && (recv_opcode == gpm_opcode)) { break; } if ((gpm_type == MCI_GPM_BT_CAL_GRANT) && (recv_type == MCI_GPM_BT_CAL_REQ)) { u32 payload[4] = {0, 0, 0, 0}; gpm_type = MCI_GPM_BT_CAL_DONE; MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_GRANT); ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, false, false); continue; } else { ath_dbg(common, MCI, "MCI GPM subtype not match 0x%x\n", *(p_gpm + 1)); mismatch++; ar9003_mci_process_gpm_extra(ah, recv_type, recv_opcode, p_gpm); } } if (p_gpm) { MCI_GPM_RECYCLE(p_gpm); p_gpm = NULL; } if (time_out <= 0) time_out = 0; while (more_data == MCI_GPM_MORE) { offset = ar9003_mci_state(ah, MCI_STATE_NEXT_GPM_OFFSET, &more_data); if (offset == MCI_GPM_INVALID) break; p_gpm = (u32 *) (mci->gpm_buf + offset); recv_type = MCI_GPM_TYPE(p_gpm); recv_opcode = MCI_GPM_OPCODE(p_gpm); if (!MCI_GPM_IS_CAL_TYPE(recv_type)) ar9003_mci_process_gpm_extra(ah, recv_type, recv_opcode, p_gpm); MCI_GPM_RECYCLE(p_gpm); } return time_out; }