Exemplo n.º 1
0
u32 ar9003_mci_get_next_gpm_offset(struct ath_hw *ah, bool first, u32 *more)
{
	struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
	u32 offset, more_gpm = 0, gpm_ptr;

	if (first) {
		gpm_ptr = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR);
		mci->gpm_idx = gpm_ptr;
		return gpm_ptr;
	}

	/*
	 * This could be useful to avoid new GPM message interrupt which
	 * may lead to spurious interrupt after power sleep, or multiple
	 * entry of ath_mci_intr().
	 * Adding empty GPM check by returning HAL_MCI_GPM_INVALID can
	 * alleviate this effect, but clearing GPM RX interrupt bit is
	 * safe, because whether this is called from hw or driver code
	 * there must be an interrupt bit set/triggered initially
	 */
	REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
			AR_MCI_INTERRUPT_RX_MSG_GPM);

	gpm_ptr = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR);
	offset = gpm_ptr;

	if (!offset)
		offset = mci->gpm_len - 1;
	else if (offset >= mci->gpm_len) {
		if (offset != 0xFFFF)
			offset = 0;
	} else {
		offset--;
	}

	if ((offset == 0xFFFF) || (gpm_ptr == mci->gpm_idx)) {
		offset = MCI_GPM_INVALID;
		more_gpm = MCI_GPM_NOMORE;
		goto out;
	}
	for (;;) {
		u32 temp_index;

		/* skip reserved GPM if any */

		if (offset != mci->gpm_idx)
			more_gpm = MCI_GPM_MORE;
		else
			more_gpm = MCI_GPM_NOMORE;

		temp_index = mci->gpm_idx;
		mci->gpm_idx++;

		if (mci->gpm_idx >= mci->gpm_len)
			mci->gpm_idx = 0;

		if (ar9003_mci_is_gpm_valid(ah, temp_index)) {
			offset = temp_index;
			break;
		}

		if (more_gpm == MCI_GPM_NOMORE) {
			offset = MCI_GPM_INVALID;
			break;
		}
	}

	if (offset != MCI_GPM_INVALID)
		offset <<= 4;
out:
	if (more)
		*more = more_gpm;

	return offset;
}
u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data)
{
	struct ath_common *common = ath9k_hw_common(ah);
	struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
	u32 value = 0, more_gpm = 0, gpm_ptr;
	u8 query_type;

	switch (state_type) {
	case MCI_STATE_ENABLE:
		if (mci->ready) {
			value = REG_READ(ah, AR_BTCOEX_CTRL);

			if ((value == 0xdeadbeef) || (value == 0xffffffff))
				value = 0;
		}
		value &= AR_BTCOEX_CTRL_MCI_MODE_EN;
		break;
	case MCI_STATE_INIT_GPM_OFFSET:
		value = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR);
		mci->gpm_idx = value;
		break;
	case MCI_STATE_NEXT_GPM_OFFSET:
	case MCI_STATE_LAST_GPM_OFFSET:
		REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
			  AR_MCI_INTERRUPT_RX_MSG_GPM);

		gpm_ptr = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR);
		value = gpm_ptr;

		if (value == 0)
			value = mci->gpm_len - 1;
		else if (value >= mci->gpm_len) {
			if (value != 0xFFFF)
				value = 0;
		} else {
			value--;
		}

		if (value == 0xFFFF) {
			value = MCI_GPM_INVALID;
			more_gpm = MCI_GPM_NOMORE;
		} else if (state_type == MCI_STATE_NEXT_GPM_OFFSET) {
			if (gpm_ptr == mci->gpm_idx) {
				value = MCI_GPM_INVALID;
				more_gpm = MCI_GPM_NOMORE;
			} else {
				for (;;) {
					u32 temp_index;

					

					if (value != mci->gpm_idx)
						more_gpm = MCI_GPM_MORE;
					else
						more_gpm = MCI_GPM_NOMORE;

					temp_index = mci->gpm_idx;
					mci->gpm_idx++;

					if (mci->gpm_idx >=
					    mci->gpm_len)
						mci->gpm_idx = 0;

					if (ar9003_mci_is_gpm_valid(ah,
								    temp_index)) {
						value = temp_index;
						break;
					}

					if (more_gpm == MCI_GPM_NOMORE) {
						value = MCI_GPM_INVALID;
						break;
					}
				}
			}
			if (p_data)
				*p_data = more_gpm;
			}

			if (value != MCI_GPM_INVALID)
				value <<= 4;

			break;
	case MCI_STATE_LAST_SCHD_MSG_OFFSET:
		value = MS(REG_READ(ah, AR_MCI_RX_STATUS),
				    AR_MCI_RX_LAST_SCHD_MSG_INDEX);
		
		value <<= 4;
		break;
	case MCI_STATE_REMOTE_SLEEP:
		value = MS(REG_READ(ah, AR_MCI_RX_STATUS),
			   AR_MCI_RX_REMOTE_SLEEP) ?
			MCI_BT_SLEEP : MCI_BT_AWAKE;
		break;
	case MCI_STATE_CONT_RSSI_POWER:
		value = MS(mci->cont_status, AR_MCI_CONT_RSSI_POWER);
		break;
	case MCI_STATE_CONT_PRIORITY:
		value = MS(mci->cont_status, AR_MCI_CONT_RRIORITY);
		break;
	case MCI_STATE_CONT_TXRX:
		value = MS(mci->cont_status, AR_MCI_CONT_TXRX);
		break;
	case MCI_STATE_BT:
		value = mci->bt_state;
		break;
	case MCI_STATE_SET_BT_SLEEP:
		mci->bt_state = MCI_BT_SLEEP;
		break;
	case MCI_STATE_SET_BT_AWAKE:
		mci->bt_state = MCI_BT_AWAKE;
		ar9003_mci_send_coex_version_query(ah, true);
		ar9003_mci_send_coex_wlan_channels(ah, true);

		if (mci->unhalt_bt_gpm)
			ar9003_mci_send_coex_halt_bt_gpm(ah, false, true);

		ar9003_mci_2g5g_switch(ah, true);
		break;
	case MCI_STATE_SET_BT_CAL_START:
		mci->bt_state = MCI_BT_CAL_START;
		break;
	case MCI_STATE_SET_BT_CAL:
		mci->bt_state = MCI_BT_CAL;
		break;
	case MCI_STATE_RESET_REQ_WAKE:
		ar9003_mci_reset_req_wakeup(ah);
		mci->update_2g5g = true;

		if (mci->config & ATH_MCI_CONFIG_MCI_OBS_MASK) {
			
			if ((REG_READ(ah, AR_GLB_GPIO_CONTROL) &
			     ATH_MCI_CONFIG_MCI_OBS_GPIO) !=
			    ATH_MCI_CONFIG_MCI_OBS_GPIO) {
				ar9003_mci_observation_set_up(ah);
			}
		}
		break;
	case MCI_STATE_SEND_WLAN_COEX_VERSION:
		ar9003_mci_send_coex_version_response(ah, true);
		break;
	case MCI_STATE_SET_BT_COEX_VERSION:
		if (!p_data)
			ath_dbg(common, MCI,
				"MCI Set BT Coex version with NULL data!!\n");
		else {
			mci->bt_ver_major = (*p_data >> 8) & 0xff;
			mci->bt_ver_minor = (*p_data) & 0xff;
			mci->bt_version_known = true;
			ath_dbg(common, MCI, "MCI BT version set: %d.%d\n",
				mci->bt_ver_major, mci->bt_ver_minor);
		}
		break;
	case MCI_STATE_SEND_WLAN_CHANNELS:
		if (p_data) {
			if (((mci->wlan_channels[1] & 0xffff0000) ==
			     (*(p_data + 1) & 0xffff0000)) &&
			    (mci->wlan_channels[2] == *(p_data + 2)) &&
			    (mci->wlan_channels[3] == *(p_data + 3)))
				break;

			mci->wlan_channels[0] = *p_data++;
			mci->wlan_channels[1] = *p_data++;
			mci->wlan_channels[2] = *p_data++;
			mci->wlan_channels[3] = *p_data++;
		}
		mci->wlan_channels_update = true;
		ar9003_mci_send_coex_wlan_channels(ah, true);
		break;
	case MCI_STATE_SEND_VERSION_QUERY:
		ar9003_mci_send_coex_version_query(ah, true);
		break;
	case MCI_STATE_SEND_STATUS_QUERY:
		query_type = MCI_GPM_COEX_QUERY_BT_TOPOLOGY;
		ar9003_mci_send_coex_bt_status_query(ah, true, query_type);
		break;
	case MCI_STATE_NEED_FLUSH_BT_INFO:
			value = (!mci->unhalt_bt_gpm &&
				 mci->need_flush_btinfo) ? 1 : 0;
			if (p_data)
				mci->need_flush_btinfo =
					(*p_data != 0) ? true : false;
			break;
	case MCI_STATE_RECOVER_RX:
		ar9003_mci_prep_interface(ah);
		mci->query_bt = true;
		mci->need_flush_btinfo = true;
		ar9003_mci_send_coex_wlan_channels(ah, true);
		ar9003_mci_2g5g_switch(ah, true);
		break;
	case MCI_STATE_NEED_FTP_STOMP:
		value = !(mci->config & ATH_MCI_CONFIG_DISABLE_FTP_STOMP);
		break;
	case MCI_STATE_NEED_TUNING:
		value = !(mci->config & ATH_MCI_CONFIG_DISABLE_TUNING);
		break;
	default:
		break;
	}

	return value;
}