Merge ath-next from git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git
ath.git patches for v5.10. Major changes: ath11k * add support for QCA6390 PCI devices wcn36xx * add support for TX ack ath9k * add support for NL80211_EXT_FEATURE_CAN_REPLACE_PTK0 to improve PTK0 rekeying
This commit is contained in:
		
						commit
						eb77802e0d
					
				| @ -12,17 +12,9 @@ | ||||
| 
 | ||||
| void ath10k_bmi_start(struct ath10k *ar) | ||||
| { | ||||
| 	int ret; | ||||
| 
 | ||||
| 	ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi start\n"); | ||||
| 
 | ||||
| 	ar->bmi.done_sent = false; | ||||
| 
 | ||||
| 	/* Enable hardware clock to speed up firmware download */ | ||||
| 	if (ar->hw_params.hw_ops->enable_pll_clk) { | ||||
| 		ret = ar->hw_params.hw_ops->enable_pll_clk(ar); | ||||
| 		ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi enable pll ret %d\n", ret); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| int ath10k_bmi_done(struct ath10k *ar) | ||||
|  | ||||
| @ -481,6 +481,15 @@ static inline void ath10k_ce_engine_int_status_clear(struct ath10k *ar, | ||||
| 	ath10k_ce_write32(ar, ce_ctrl_addr + wm_regs->addr, mask); | ||||
| } | ||||
| 
 | ||||
| static inline bool ath10k_ce_engine_int_status_check(struct ath10k *ar, | ||||
| 						     u32 ce_ctrl_addr, | ||||
| 						     unsigned int mask) | ||||
| { | ||||
| 	struct ath10k_hw_ce_host_wm_regs *wm_regs = ar->hw_ce_regs->wm_regs; | ||||
| 
 | ||||
| 	return ath10k_ce_read32(ar, ce_ctrl_addr + wm_regs->addr) & mask; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Guts of ath10k_ce_send. | ||||
|  * The caller takes responsibility for any needed locking. | ||||
| @ -1301,19 +1310,22 @@ void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id) | ||||
| 
 | ||||
| 	spin_lock_bh(&ce->ce_lock); | ||||
| 
 | ||||
| 	/* Clear the copy-complete interrupts that will be handled here. */ | ||||
| 	ath10k_ce_engine_int_status_clear(ar, ctrl_addr, | ||||
| 					  wm_regs->cc_mask); | ||||
| 	if (ath10k_ce_engine_int_status_check(ar, ctrl_addr, | ||||
| 					      wm_regs->cc_mask)) { | ||||
| 		/* Clear before handling */ | ||||
| 		ath10k_ce_engine_int_status_clear(ar, ctrl_addr, | ||||
| 						  wm_regs->cc_mask); | ||||
| 
 | ||||
| 	spin_unlock_bh(&ce->ce_lock); | ||||
| 		spin_unlock_bh(&ce->ce_lock); | ||||
| 
 | ||||
| 	if (ce_state->recv_cb) | ||||
| 		ce_state->recv_cb(ce_state); | ||||
| 		if (ce_state->recv_cb) | ||||
| 			ce_state->recv_cb(ce_state); | ||||
| 
 | ||||
| 	if (ce_state->send_cb) | ||||
| 		ce_state->send_cb(ce_state); | ||||
| 		if (ce_state->send_cb) | ||||
| 			ce_state->send_cb(ce_state); | ||||
| 
 | ||||
| 	spin_lock_bh(&ce->ce_lock); | ||||
| 		spin_lock_bh(&ce->ce_lock); | ||||
| 	} | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Misc CE interrupts are not being handled, but still need | ||||
| @ -1555,7 +1567,7 @@ ath10k_ce_alloc_src_ring(struct ath10k *ar, unsigned int ce_id, | ||||
| 		ret = ath10k_ce_alloc_shadow_base(ar, src_ring, nentries); | ||||
| 		if (ret) { | ||||
| 			dma_free_coherent(ar->dev, | ||||
| 					  (nentries * sizeof(struct ce_desc_64) + | ||||
| 					  (nentries * sizeof(struct ce_desc) + | ||||
| 					   CE_DESC_RING_ALIGN), | ||||
| 					  src_ring->base_addr_owner_space_unaligned, | ||||
| 					  base_addr); | ||||
|  | ||||
| @ -334,6 +334,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { | ||||
| 		.hw_filter_reset_required = true, | ||||
| 		.fw_diag_ce_download = true, | ||||
| 		.tx_stats_over_pktlog = false, | ||||
| 		.supports_peer_stats_info = true, | ||||
| 	}, | ||||
| 	{ | ||||
| 		.id = QCA99X0_HW_2_0_DEV_VERSION, | ||||
| @ -2320,7 +2321,7 @@ static void ath10k_core_restart(struct work_struct *work) | ||||
| 		break; | ||||
| 	case ATH10K_STATE_RESTARTED: | ||||
| 		ar->state = ATH10K_STATE_WEDGED; | ||||
| 		/* fall through */ | ||||
| 		fallthrough; | ||||
| 	case ATH10K_STATE_WEDGED: | ||||
| 		ath10k_warn(ar, "device is wedged, will not restart\n"); | ||||
| 		break; | ||||
| @ -2614,6 +2615,13 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode, | ||||
| 		      ar->running_fw->fw_file.fw_features)) { | ||||
| 		ath10k_bmi_start(ar); | ||||
| 
 | ||||
| 		/* Enable hardware clock to speed up firmware download */ | ||||
| 		if (ar->hw_params.hw_ops->enable_pll_clk) { | ||||
| 			status = ar->hw_params.hw_ops->enable_pll_clk(ar); | ||||
| 			ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot enable pll ret %d\n", | ||||
| 				   status); | ||||
| 		} | ||||
| 
 | ||||
| 		if (ath10k_init_configure_target(ar)) { | ||||
| 			status = -EINVAL; | ||||
| 			goto err; | ||||
|  | ||||
| @ -142,6 +142,14 @@ static int __ath10k_htt_rx_ring_fill_n(struct ath10k_htt *htt, int num) | ||||
| 	BUILD_BUG_ON(HTT_RX_RING_FILL_LEVEL >= HTT_RX_RING_SIZE / 2); | ||||
| 
 | ||||
| 	idx = __le32_to_cpu(*htt->rx_ring.alloc_idx.vaddr); | ||||
| 
 | ||||
| 	if (idx < 0 || idx >= htt->rx_ring.size) { | ||||
| 		ath10k_err(htt->ar, "rx ring index is not valid, firmware malfunctioning?\n"); | ||||
| 		idx &= htt->rx_ring.size_mask; | ||||
| 		ret = -ENOMEM; | ||||
| 		goto fail; | ||||
| 	} | ||||
| 
 | ||||
| 	while (num > 0) { | ||||
| 		skb = dev_alloc_skb(HTT_RX_BUF_SIZE + HTT_RX_DESC_ALIGN); | ||||
| 		if (!skb) { | ||||
| @ -941,6 +949,7 @@ static void ath10k_htt_rx_h_rates(struct ath10k *ar, | ||||
| 	u8 preamble = 0; | ||||
| 	u8 group_id; | ||||
| 	u32 info1, info2, info3; | ||||
| 	u32 stbc, nsts_su; | ||||
| 
 | ||||
| 	info1 = __le32_to_cpu(rxd->ppdu_start.info1); | ||||
| 	info2 = __le32_to_cpu(rxd->ppdu_start.info2); | ||||
| @ -985,11 +994,16 @@ static void ath10k_htt_rx_h_rates(struct ath10k *ar, | ||||
| 		 */ | ||||
| 		bw = info2 & 3; | ||||
| 		sgi = info3 & 1; | ||||
| 		stbc = (info2 >> 3) & 1; | ||||
| 		group_id = (info2 >> 4) & 0x3F; | ||||
| 
 | ||||
| 		if (GROUP_ID_IS_SU_MIMO(group_id)) { | ||||
| 			mcs = (info3 >> 4) & 0x0F; | ||||
| 			nss = ((info2 >> 10) & 0x07) + 1; | ||||
| 			nsts_su = ((info2 >> 10) & 0x07); | ||||
| 			if (stbc) | ||||
| 				nss = (nsts_su >> 2) + 1; | ||||
| 			else | ||||
| 				nss = (nsts_su + 1); | ||||
| 		} else { | ||||
| 			/* Hardware doesn't decode VHT-SIG-B into Rx descriptor
 | ||||
| 			 * so it's impossible to decode MCS. Also since | ||||
| @ -3017,7 +3031,7 @@ static int ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb) | ||||
| 			ath10k_htt_rx_h_enqueue(ar, &amsdu, status); | ||||
| 			break; | ||||
| 		case -EAGAIN: | ||||
| 			/* fall through */ | ||||
| 			fallthrough; | ||||
| 		default: | ||||
| 			/* Should not happen. */ | ||||
| 			ath10k_warn(ar, "failed to extract amsdu: %d\n", ret); | ||||
| @ -3575,12 +3589,14 @@ ath10k_update_per_peer_tx_stats(struct ath10k *ar, | ||||
| 	} | ||||
| 
 | ||||
| 	if (ar->htt.disable_tx_comp) { | ||||
| 		arsta->tx_retries += peer_stats->retry_pkts; | ||||
| 		arsta->tx_failed += peer_stats->failed_pkts; | ||||
| 		ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx retries %d tx failed %d\n", | ||||
| 			   arsta->tx_retries, arsta->tx_failed); | ||||
| 		ath10k_dbg(ar, ATH10K_DBG_HTT, "tx failed %d\n", | ||||
| 			   arsta->tx_failed); | ||||
| 	} | ||||
| 
 | ||||
| 	arsta->tx_retries += peer_stats->retry_pkts; | ||||
| 	ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx retries %d", arsta->tx_retries); | ||||
| 
 | ||||
| 	if (ath10k_debug_is_extd_tx_stats_enabled(ar)) | ||||
| 		ath10k_accumulate_per_peer_tx_stats(ar, arsta, peer_stats, | ||||
| 						    rate_idx); | ||||
|  | ||||
| @ -1314,7 +1314,7 @@ static int ath10k_htt_tx_hl(struct ath10k_htt *htt, enum ath10k_hw_txrx_mode txm | ||||
| 	case ATH10K_HW_TXRX_RAW: | ||||
| 	case ATH10K_HW_TXRX_NATIVE_WIFI: | ||||
| 		flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT; | ||||
| 		/* fall through */ | ||||
| 		fallthrough; | ||||
| 	case ATH10K_HW_TXRX_ETHERNET: | ||||
| 		flags0 |= SM(txmode, HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE); | ||||
| 		break; | ||||
| @ -1460,7 +1460,7 @@ static int ath10k_htt_tx_32(struct ath10k_htt *htt, | ||||
| 	case ATH10K_HW_TXRX_RAW: | ||||
| 	case ATH10K_HW_TXRX_NATIVE_WIFI: | ||||
| 		flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT; | ||||
| 		/* fall through */ | ||||
| 		fallthrough; | ||||
| 	case ATH10K_HW_TXRX_ETHERNET: | ||||
| 		if (ar->hw_params.continuous_frag_desc) { | ||||
| 			ext_desc_t = htt->frag_desc.vaddr_desc_32; | ||||
| @ -1662,7 +1662,7 @@ static int ath10k_htt_tx_64(struct ath10k_htt *htt, | ||||
| 	case ATH10K_HW_TXRX_RAW: | ||||
| 	case ATH10K_HW_TXRX_NATIVE_WIFI: | ||||
| 		flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT; | ||||
| 		/* fall through */ | ||||
| 		fallthrough; | ||||
| 	case ATH10K_HW_TXRX_ETHERNET: | ||||
| 		if (ar->hw_params.continuous_frag_desc) { | ||||
| 			ext_desc_t = htt->frag_desc.vaddr_desc_64; | ||||
|  | ||||
| @ -2468,17 +2468,17 @@ ath10k_peer_assoc_h_vht_limit(u16 tx_mcs_set, | ||||
| 			idx_limit = -1; | ||||
| 
 | ||||
| 		switch (idx_limit) { | ||||
| 		case 0: /* fall through */ | ||||
| 		case 1: /* fall through */ | ||||
| 		case 2: /* fall through */ | ||||
| 		case 3: /* fall through */ | ||||
| 		case 4: /* fall through */ | ||||
| 		case 5: /* fall through */ | ||||
| 		case 6: /* fall through */ | ||||
| 		case 0: | ||||
| 		case 1: | ||||
| 		case 2: | ||||
| 		case 3: | ||||
| 		case 4: | ||||
| 		case 5: | ||||
| 		case 6: | ||||
| 		default: | ||||
| 			/* see ath10k_mac_can_set_bitrate_mask() */ | ||||
| 			WARN_ON(1); | ||||
| 			/* fall through */ | ||||
| 			fallthrough; | ||||
| 		case -1: | ||||
| 			mcs = IEEE80211_VHT_MCS_NOT_SUPPORTED; | ||||
| 			break; | ||||
| @ -4238,7 +4238,7 @@ void __ath10k_scan_finish(struct ath10k *ar) | ||||
| 		} else if (ar->scan.roc_notify) { | ||||
| 			ieee80211_remain_on_channel_expired(ar->hw); | ||||
| 		} | ||||
| 		/* fall through */ | ||||
| 		fallthrough; | ||||
| 	case ATH10K_SCAN_STARTING: | ||||
| 		ar->scan.state = ATH10K_SCAN_IDLE; | ||||
| 		ar->scan_channel = NULL; | ||||
| @ -7278,7 +7278,7 @@ ath10k_mac_update_bss_chan_survey(struct ath10k *ar, | ||||
| 				  struct ieee80211_channel *channel) | ||||
| { | ||||
| 	int ret; | ||||
| 	enum wmi_bss_survey_req_type type = WMI_BSS_SURVEY_REQ_TYPE_READ_CLEAR; | ||||
| 	enum wmi_bss_survey_req_type type = WMI_BSS_SURVEY_REQ_TYPE_READ; | ||||
| 
 | ||||
| 	lockdep_assert_held(&ar->conf_mutex); | ||||
| 
 | ||||
| @ -8363,19 +8363,32 @@ static void ath10k_mac_get_rate_flags_ht(struct ath10k *ar, u32 rate, u8 nss, u8 | ||||
| 					 u8 *flags, u8 *bw) | ||||
| { | ||||
| 	struct ath10k_index_ht_data_rate_type *mcs_rate; | ||||
| 	u8 index; | ||||
| 	size_t len_nss1 = ARRAY_SIZE(supported_ht_mcs_rate_nss1); | ||||
| 	size_t len_nss2 = ARRAY_SIZE(supported_ht_mcs_rate_nss2); | ||||
| 
 | ||||
| 	if (mcs >= (len_nss1 + len_nss2)) { | ||||
| 		ath10k_warn(ar, "not supported mcs %d in current rate table", mcs); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	mcs_rate = (struct ath10k_index_ht_data_rate_type *) | ||||
| 		   ((nss == 1) ? &supported_ht_mcs_rate_nss1 : | ||||
| 		   &supported_ht_mcs_rate_nss2); | ||||
| 
 | ||||
| 	if (rate == mcs_rate[mcs].supported_rate[0]) { | ||||
| 	if (mcs >= len_nss1) | ||||
| 		index = mcs - len_nss1; | ||||
| 	else | ||||
| 		index = mcs; | ||||
| 
 | ||||
| 	if (rate == mcs_rate[index].supported_rate[0]) { | ||||
| 		*bw = RATE_INFO_BW_20; | ||||
| 	} else if (rate == mcs_rate[mcs].supported_rate[1]) { | ||||
| 	} else if (rate == mcs_rate[index].supported_rate[1]) { | ||||
| 		*bw |= RATE_INFO_BW_40; | ||||
| 	} else if (rate == mcs_rate[mcs].supported_rate[2]) { | ||||
| 	} else if (rate == mcs_rate[index].supported_rate[2]) { | ||||
| 		*bw |= RATE_INFO_BW_20; | ||||
| 		*flags |= RATE_INFO_FLAGS_SHORT_GI; | ||||
| 	} else if (rate == mcs_rate[mcs].supported_rate[3]) { | ||||
| 	} else if (rate == mcs_rate[index].supported_rate[3]) { | ||||
| 		*bw |= RATE_INFO_BW_40; | ||||
| 		*flags |= RATE_INFO_FLAGS_SHORT_GI; | ||||
| 	} else { | ||||
| @ -8436,6 +8449,9 @@ static void ath10k_mac_parse_bitrate(struct ath10k *ar, u32 rate_code, | ||||
| 	u8 mcs = WMI_TLV_GET_HW_RC_RATE_V1(rate_code); | ||||
| 	u8 flags = 0, bw = 0; | ||||
| 
 | ||||
| 	ath10k_dbg(ar, ATH10K_DBG_MAC, "mac parse rate code 0x%x bitrate %d kbps\n", | ||||
| 		   rate_code, bitrate_kbps); | ||||
| 
 | ||||
| 	if (preamble == WMI_RATE_PREAMBLE_HT) | ||||
| 		mode = ATH10K_PHY_MODE_HT; | ||||
| 	else if (preamble == WMI_RATE_PREAMBLE_VHT) | ||||
| @ -8528,26 +8544,26 @@ static void ath10k_sta_statistics(struct ieee80211_hw *hw, | ||||
| 	sinfo->rx_duration = arsta->rx_duration; | ||||
| 	sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_DURATION); | ||||
| 
 | ||||
| 	if (!arsta->txrate.legacy && !arsta->txrate.nss) | ||||
| 		return; | ||||
| 
 | ||||
| 	if (arsta->txrate.legacy) { | ||||
| 		sinfo->txrate.legacy = arsta->txrate.legacy; | ||||
| 	} else { | ||||
| 		sinfo->txrate.mcs = arsta->txrate.mcs; | ||||
| 		sinfo->txrate.nss = arsta->txrate.nss; | ||||
| 		sinfo->txrate.bw = arsta->txrate.bw; | ||||
| 	if (arsta->txrate.legacy || arsta->txrate.nss) { | ||||
| 		if (arsta->txrate.legacy) { | ||||
| 			sinfo->txrate.legacy = arsta->txrate.legacy; | ||||
| 		} else { | ||||
| 			sinfo->txrate.mcs = arsta->txrate.mcs; | ||||
| 			sinfo->txrate.nss = arsta->txrate.nss; | ||||
| 			sinfo->txrate.bw = arsta->txrate.bw; | ||||
| 		} | ||||
| 		sinfo->txrate.flags = arsta->txrate.flags; | ||||
| 		sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); | ||||
| 	} | ||||
| 	sinfo->txrate.flags = arsta->txrate.flags; | ||||
| 	sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); | ||||
| 
 | ||||
| 	if (ar->htt.disable_tx_comp) { | ||||
| 		sinfo->tx_retries = arsta->tx_retries; | ||||
| 		sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_RETRIES); | ||||
| 		sinfo->tx_failed = arsta->tx_failed; | ||||
| 		sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_FAILED); | ||||
| 	} | ||||
| 
 | ||||
| 	sinfo->tx_retries = arsta->tx_retries; | ||||
| 	sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_RETRIES); | ||||
| 
 | ||||
| 	ath10k_mac_sta_get_peer_stats_info(ar, sta, sinfo); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -2184,7 +2184,7 @@ err_req: | ||||
| 
 | ||||
| 	if (ret == 0 && resp_len) { | ||||
| 		*resp_len = min(*resp_len, xfer.resp_len); | ||||
| 		memcpy(resp, tresp, xfer.resp_len); | ||||
| 		memcpy(resp, tresp, *resp_len); | ||||
| 	} | ||||
| err_dma: | ||||
| 	kfree(treq); | ||||
|  | ||||
| @ -557,6 +557,10 @@ static int ath10k_sdio_mbox_rx_alloc(struct ath10k *ar, | ||||
| 				    le16_to_cpu(htc_hdr->len), | ||||
| 				    ATH10K_HTC_MBOX_MAX_PAYLOAD_LENGTH); | ||||
| 			ret = -ENOMEM; | ||||
| 
 | ||||
| 			queue_work(ar->workqueue, &ar->restart_work); | ||||
| 			ath10k_warn(ar, "exceeds length, start recovery\n"); | ||||
| 
 | ||||
| 			goto err; | ||||
| 		} | ||||
| 
 | ||||
|  | ||||
| @ -1772,9 +1772,18 @@ static int ath10k_snoc_remove(struct platform_device *pdev) | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static void ath10k_snoc_shutdown(struct platform_device *pdev) | ||||
| { | ||||
| 	struct ath10k *ar = platform_get_drvdata(pdev); | ||||
| 
 | ||||
| 	ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc shutdown\n"); | ||||
| 	ath10k_snoc_remove(pdev); | ||||
| } | ||||
| 
 | ||||
| static struct platform_driver ath10k_snoc_driver = { | ||||
| 	.probe  = ath10k_snoc_probe, | ||||
| 	.remove = ath10k_snoc_remove, | ||||
| 	.shutdown =  ath10k_snoc_shutdown, | ||||
| 	.driver = { | ||||
| 		.name   = "ath10k_snoc", | ||||
| 		.of_match_table = ath10k_snoc_dt_match, | ||||
|  | ||||
| @ -1614,6 +1614,8 @@ wmi_tlv_svc_map(const __le32 *in, unsigned long *out, size_t len) | ||||
| 	       WMI_SERVICE_MESH_11S, len); | ||||
| 	SVCMAP(WMI_TLV_SERVICE_SYNC_DELETE_CMDS, | ||||
| 	       WMI_SERVICE_SYNC_DELETE_CMDS, len); | ||||
| 	SVCMAP(WMI_TLV_SERVICE_PEER_STATS_INFO, | ||||
| 	       WMI_SERVICE_PEER_STATS, len); | ||||
| } | ||||
| 
 | ||||
| static inline void | ||||
|  | ||||
| @ -275,7 +275,7 @@ static int ath10k_vif_wow_set_wakeups(struct ath10k_vif *arvif, | ||||
| 	switch (arvif->vdev_type) { | ||||
| 	case WMI_VDEV_TYPE_IBSS: | ||||
| 		__set_bit(WOW_BEACON_EVENT, &wow_mask); | ||||
| 		 /* fall through */ | ||||
| 		fallthrough; | ||||
| 	case WMI_VDEV_TYPE_AP: | ||||
| 		__set_bit(WOW_DEAUTH_RECVD_EVENT, &wow_mask); | ||||
| 		__set_bit(WOW_DISASSOC_RECVD_EVENT, &wow_mask); | ||||
|  | ||||
| @ -2,9 +2,7 @@ | ||||
| config ATH11K | ||||
| 	tristate "Qualcomm Technologies 802.11ax chipset support" | ||||
| 	depends on MAC80211 && HAS_DMA | ||||
| 	depends on REMOTEPROC | ||||
| 	depends on CRYPTO_MICHAEL_MIC | ||||
| 	depends on ARCH_QCOM || COMPILE_TEST | ||||
| 	select ATH_COMMON | ||||
| 	select QCOM_QMI_HELPERS | ||||
| 	help | ||||
| @ -13,6 +11,22 @@ config ATH11K | ||||
| 
 | ||||
| 	  If you choose to build a module, it'll be called ath11k. | ||||
| 
 | ||||
| config ATH11K_AHB | ||||
| 	tristate "Atheros ath11k AHB support" | ||||
| 	depends on ATH11K | ||||
| 	depends on REMOTEPROC | ||||
| 	help | ||||
| 	  This module adds support for AHB bus | ||||
| 
 | ||||
| config ATH11K_PCI | ||||
| 	tristate "Atheros ath11k PCI support" | ||||
| 	depends on ATH11K && PCI | ||||
| 	select MHI_BUS | ||||
| 	select QRTR | ||||
| 	select QRTR_MHI | ||||
| 	help | ||||
| 	  This module adds support for PCIE bus | ||||
| 
 | ||||
| config ATH11K_DEBUG | ||||
| 	bool "QCA ath11k debugging" | ||||
| 	depends on ATH11K | ||||
|  | ||||
| @ -4,7 +4,6 @@ ath11k-y += core.o \ | ||||
| 	    hal.o \
 | ||||
| 	    hal_tx.o \
 | ||||
| 	    hal_rx.o \
 | ||||
| 	    ahb.o \
 | ||||
| 	    wmi.o \
 | ||||
| 	    mac.o \
 | ||||
| 	    reg.o \
 | ||||
| @ -16,7 +15,8 @@ ath11k-y += core.o \ | ||||
| 	    debug.o \
 | ||||
| 	    ce.o \
 | ||||
| 	    peer.o \
 | ||||
| 	    dbring.o | ||||
| 	    dbring.o \
 | ||||
| 	    hw.o | ||||
| 
 | ||||
| ath11k-$(CONFIG_ATH11K_DEBUGFS) += debug_htt_stats.o debugfs_sta.o | ||||
| ath11k-$(CONFIG_NL80211_TESTMODE) += testmode.o | ||||
| @ -24,5 +24,11 @@ ath11k-$(CONFIG_ATH11K_TRACING) += trace.o | ||||
| ath11k-$(CONFIG_THERMAL) += thermal.o | ||||
| ath11k-$(CONFIG_ATH11K_SPECTRAL) += spectral.o | ||||
| 
 | ||||
| obj-$(CONFIG_ATH11K_AHB) += ath11k_ahb.o | ||||
| ath11k_ahb-y += ahb.o | ||||
| 
 | ||||
| obj-$(CONFIG_ATH11K_PCI) += ath11k_pci.o | ||||
| ath11k_pci-y += mhi.o pci.o | ||||
| 
 | ||||
| # for tracing framework to find trace.h
 | ||||
| CFLAGS_trace.o := -I$(src) | ||||
|  | ||||
| @ -25,6 +25,13 @@ static const struct of_device_id ath11k_ahb_of_match[] = { | ||||
| 
 | ||||
| MODULE_DEVICE_TABLE(of, ath11k_ahb_of_match); | ||||
| 
 | ||||
| static const struct ath11k_bus_params ath11k_ahb_bus_params = { | ||||
| 	.mhi_support = false, | ||||
| 	.m3_fw_support = false, | ||||
| 	.fixed_bdf_addr = true, | ||||
| 	.fixed_mem_region = true, | ||||
| }; | ||||
| 
 | ||||
| /* Target firmware's Copy Engine configuration. */ | ||||
| static const struct ce_pipe_config target_ce_config_wlan[] = { | ||||
| 	/* CE0: host->target HTC control and raw streams */ | ||||
| @ -321,78 +328,6 @@ static const char *irq_name[ATH11K_IRQ_NUM_MAX] = { | ||||
| 	"tcl2host-status-ring", | ||||
| }; | ||||
| 
 | ||||
| #define ATH11K_TX_RING_MASK_0 0x1 | ||||
| #define ATH11K_TX_RING_MASK_1 0x2 | ||||
| #define ATH11K_TX_RING_MASK_2 0x4 | ||||
| 
 | ||||
| #define ATH11K_RX_RING_MASK_0 0x1 | ||||
| #define ATH11K_RX_RING_MASK_1 0x2 | ||||
| #define ATH11K_RX_RING_MASK_2 0x4 | ||||
| #define ATH11K_RX_RING_MASK_3 0x8 | ||||
| 
 | ||||
| #define ATH11K_RX_ERR_RING_MASK_0 0x1 | ||||
| 
 | ||||
| #define ATH11K_RX_WBM_REL_RING_MASK_0 0x1 | ||||
| 
 | ||||
| #define ATH11K_REO_STATUS_RING_MASK_0 0x1 | ||||
| 
 | ||||
| #define ATH11K_RXDMA2HOST_RING_MASK_0 0x1 | ||||
| #define ATH11K_RXDMA2HOST_RING_MASK_1 0x2 | ||||
| #define ATH11K_RXDMA2HOST_RING_MASK_2 0x4 | ||||
| 
 | ||||
| #define ATH11K_HOST2RXDMA_RING_MASK_0 0x1 | ||||
| #define ATH11K_HOST2RXDMA_RING_MASK_1 0x2 | ||||
| #define ATH11K_HOST2RXDMA_RING_MASK_2 0x4 | ||||
| 
 | ||||
| #define ATH11K_RX_MON_STATUS_RING_MASK_0 0x1 | ||||
| #define ATH11K_RX_MON_STATUS_RING_MASK_1 0x2 | ||||
| #define ATH11K_RX_MON_STATUS_RING_MASK_2 0x4 | ||||
| 
 | ||||
| const u8 ath11k_tx_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX] = { | ||||
| 	ATH11K_TX_RING_MASK_0, | ||||
| 	ATH11K_TX_RING_MASK_1, | ||||
| 	ATH11K_TX_RING_MASK_2, | ||||
| }; | ||||
| 
 | ||||
| const u8 rx_mon_status_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX] = { | ||||
| 	0, 0, 0, 0, | ||||
| 	ATH11K_RX_MON_STATUS_RING_MASK_0, | ||||
| 	ATH11K_RX_MON_STATUS_RING_MASK_1, | ||||
| 	ATH11K_RX_MON_STATUS_RING_MASK_2, | ||||
| }; | ||||
| 
 | ||||
| const u8 ath11k_rx_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX] = { | ||||
| 	0, 0, 0, 0, 0, 0, 0, | ||||
| 	ATH11K_RX_RING_MASK_0, | ||||
| 	ATH11K_RX_RING_MASK_1, | ||||
| 	ATH11K_RX_RING_MASK_2, | ||||
| 	ATH11K_RX_RING_MASK_3, | ||||
| }; | ||||
| 
 | ||||
| const u8 ath11k_rx_err_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX] = { | ||||
| 	ATH11K_RX_ERR_RING_MASK_0, | ||||
| }; | ||||
| 
 | ||||
| const u8 ath11k_rx_wbm_rel_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX] = { | ||||
| 	ATH11K_RX_WBM_REL_RING_MASK_0, | ||||
| }; | ||||
| 
 | ||||
| const u8 ath11k_reo_status_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX] = { | ||||
| 	ATH11K_REO_STATUS_RING_MASK_0, | ||||
| }; | ||||
| 
 | ||||
| const u8 ath11k_rxdma2host_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX] = { | ||||
| 	ATH11K_RXDMA2HOST_RING_MASK_0, | ||||
| 	ATH11K_RXDMA2HOST_RING_MASK_1, | ||||
| 	ATH11K_RXDMA2HOST_RING_MASK_2, | ||||
| }; | ||||
| 
 | ||||
| const u8 ath11k_host2rxdma_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX] = { | ||||
| 	ATH11K_HOST2RXDMA_RING_MASK_0, | ||||
| 	ATH11K_HOST2RXDMA_RING_MASK_1, | ||||
| 	ATH11K_HOST2RXDMA_RING_MASK_2, | ||||
| }; | ||||
| 
 | ||||
| /* enum ext_irq_num - irq numbers that can be used by external modules
 | ||||
|  * like datapath | ||||
|  */ | ||||
| @ -449,10 +384,10 @@ static void ath11k_ahb_kill_tasklets(struct ath11k_base *ab) | ||||
| { | ||||
| 	int i; | ||||
| 
 | ||||
| 	for (i = 0; i < CE_COUNT; i++) { | ||||
| 	for (i = 0; i < ab->hw_params.ce_count; i++) { | ||||
| 		struct ath11k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i]; | ||||
| 
 | ||||
| 		if (ath11k_ce_get_attr_flags(i) & CE_ATTR_DIS_INTR) | ||||
| 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) | ||||
| 			continue; | ||||
| 
 | ||||
| 		tasklet_kill(&ce_pipe->intr_tq); | ||||
| @ -540,8 +475,8 @@ static void ath11k_ahb_sync_ce_irqs(struct ath11k_base *ab) | ||||
| 	int i; | ||||
| 	int irq_idx; | ||||
| 
 | ||||
| 	for (i = 0; i < CE_COUNT; i++) { | ||||
| 		if (ath11k_ce_get_attr_flags(i) & CE_ATTR_DIS_INTR) | ||||
| 	for (i = 0; i < ab->hw_params.ce_count; i++) { | ||||
| 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) | ||||
| 			continue; | ||||
| 
 | ||||
| 		irq_idx = ATH11K_IRQ_CE0_OFFSET + i; | ||||
| @ -568,8 +503,8 @@ static void ath11k_ahb_ce_irqs_enable(struct ath11k_base *ab) | ||||
| { | ||||
| 	int i; | ||||
| 
 | ||||
| 	for (i = 0; i < CE_COUNT; i++) { | ||||
| 		if (ath11k_ce_get_attr_flags(i) & CE_ATTR_DIS_INTR) | ||||
| 	for (i = 0; i < ab->hw_params.ce_count; i++) { | ||||
| 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) | ||||
| 			continue; | ||||
| 		ath11k_ahb_ce_irq_enable(ab, i); | ||||
| 	} | ||||
| @ -579,8 +514,8 @@ static void ath11k_ahb_ce_irqs_disable(struct ath11k_base *ab) | ||||
| { | ||||
| 	int i; | ||||
| 
 | ||||
| 	for (i = 0; i < CE_COUNT; i++) { | ||||
| 		if (ath11k_ce_get_attr_flags(i) & CE_ATTR_DIS_INTR) | ||||
| 	for (i = 0; i < ab->hw_params.ce_count; i++) { | ||||
| 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) | ||||
| 			continue; | ||||
| 		ath11k_ahb_ce_irq_disable(ab, i); | ||||
| 	} | ||||
| @ -646,6 +581,7 @@ static void ath11k_ahb_init_qmi_ce_config(struct ath11k_base *ab) | ||||
| 	cfg->tgt_ce = target_ce_config_wlan; | ||||
| 	cfg->svc_to_ce_map_len = ARRAY_SIZE(target_service_to_ce_map_wlan); | ||||
| 	cfg->svc_to_ce_map = target_service_to_ce_map_wlan; | ||||
| 	ab->qmi.service_ins_id = ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_IPQ8074; | ||||
| } | ||||
| 
 | ||||
| static void ath11k_ahb_free_ext_irq(struct ath11k_base *ab) | ||||
| @ -665,8 +601,8 @@ static void ath11k_ahb_free_irq(struct ath11k_base *ab) | ||||
| 	int irq_idx; | ||||
| 	int i; | ||||
| 
 | ||||
| 	for (i = 0; i < CE_COUNT; i++) { | ||||
| 		if (ath11k_ce_get_attr_flags(i) & CE_ATTR_DIS_INTR) | ||||
| 	for (i = 0; i < ab->hw_params.ce_count; i++) { | ||||
| 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) | ||||
| 			continue; | ||||
| 		irq_idx = ATH11K_IRQ_CE0_OFFSET + i; | ||||
| 		free_irq(ab->irq_num[irq_idx], &ab->ce.ce_pipe[i]); | ||||
| @ -734,6 +670,7 @@ static irqreturn_t ath11k_ahb_ext_interrupt_handler(int irq, void *arg) | ||||
| 
 | ||||
| static int ath11k_ahb_ext_irq_config(struct ath11k_base *ab) | ||||
| { | ||||
| 	struct ath11k_hw_params *hw = &ab->hw_params; | ||||
| 	int i, j; | ||||
| 	int irq; | ||||
| 	int ret; | ||||
| @ -749,45 +686,45 @@ static int ath11k_ahb_ext_irq_config(struct ath11k_base *ab) | ||||
| 			       ath11k_ahb_ext_grp_napi_poll, NAPI_POLL_WEIGHT); | ||||
| 
 | ||||
| 		for (j = 0; j < ATH11K_EXT_IRQ_NUM_MAX; j++) { | ||||
| 			if (ath11k_tx_ring_mask[i] & BIT(j)) { | ||||
| 			if (ab->hw_params.ring_mask->tx[i] & BIT(j)) { | ||||
| 				irq_grp->irqs[num_irq++] = | ||||
| 					wbm2host_tx_completions_ring1 - j; | ||||
| 			} | ||||
| 
 | ||||
| 			if (ath11k_rx_ring_mask[i] & BIT(j)) { | ||||
| 			if (ab->hw_params.ring_mask->rx[i] & BIT(j)) { | ||||
| 				irq_grp->irqs[num_irq++] = | ||||
| 					reo2host_destination_ring1 - j; | ||||
| 			} | ||||
| 
 | ||||
| 			if (ath11k_rx_err_ring_mask[i] & BIT(j)) | ||||
| 			if (ab->hw_params.ring_mask->rx_err[i] & BIT(j)) | ||||
| 				irq_grp->irqs[num_irq++] = reo2host_exception; | ||||
| 
 | ||||
| 			if (ath11k_rx_wbm_rel_ring_mask[i] & BIT(j)) | ||||
| 			if (ab->hw_params.ring_mask->rx_wbm_rel[i] & BIT(j)) | ||||
| 				irq_grp->irqs[num_irq++] = wbm2host_rx_release; | ||||
| 
 | ||||
| 			if (ath11k_reo_status_ring_mask[i] & BIT(j)) | ||||
| 			if (ab->hw_params.ring_mask->reo_status[i] & BIT(j)) | ||||
| 				irq_grp->irqs[num_irq++] = reo2host_status; | ||||
| 
 | ||||
| 			if (j < MAX_RADIOS) { | ||||
| 				if (ath11k_rxdma2host_ring_mask[i] & BIT(j)) { | ||||
| 			if (j < ab->hw_params.max_radios) { | ||||
| 				if (ab->hw_params.ring_mask->rxdma2host[i] & BIT(j)) { | ||||
| 					irq_grp->irqs[num_irq++] = | ||||
| 						rxdma2host_destination_ring_mac1 | ||||
| 						- ath11k_core_get_hw_mac_id(ab, j); | ||||
| 						rxdma2host_destination_ring_mac1 - | ||||
| 						ath11k_hw_get_mac_from_pdev_id(hw, j); | ||||
| 				} | ||||
| 
 | ||||
| 				if (ath11k_host2rxdma_ring_mask[i] & BIT(j)) { | ||||
| 				if (ab->hw_params.ring_mask->host2rxdma[i] & BIT(j)) { | ||||
| 					irq_grp->irqs[num_irq++] = | ||||
| 						host2rxdma_host_buf_ring_mac1 | ||||
| 						- ath11k_core_get_hw_mac_id(ab, j); | ||||
| 						host2rxdma_host_buf_ring_mac1 - | ||||
| 						ath11k_hw_get_mac_from_pdev_id(hw, j); | ||||
| 				} | ||||
| 
 | ||||
| 				if (rx_mon_status_ring_mask[i] & BIT(j)) { | ||||
| 				if (ab->hw_params.ring_mask->rx_mon_status[i] & BIT(j)) { | ||||
| 					irq_grp->irqs[num_irq++] = | ||||
| 						ppdu_end_interrupts_mac1 - | ||||
| 						ath11k_core_get_hw_mac_id(ab, j); | ||||
| 						ath11k_hw_get_mac_from_pdev_id(hw, j); | ||||
| 					irq_grp->irqs[num_irq++] = | ||||
| 						rxdma2host_monitor_status_ring_mac1 - | ||||
| 						ath11k_core_get_hw_mac_id(ab, j); | ||||
| 						ath11k_hw_get_mac_from_pdev_id(hw, j); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| @ -819,10 +756,10 @@ static int ath11k_ahb_config_irq(struct ath11k_base *ab) | ||||
| 	int ret; | ||||
| 
 | ||||
| 	/* Configure CE irqs */ | ||||
| 	for (i = 0; i < CE_COUNT; i++) { | ||||
| 	for (i = 0; i < ab->hw_params.ce_count; i++) { | ||||
| 		struct ath11k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i]; | ||||
| 
 | ||||
| 		if (ath11k_ce_get_attr_flags(i) & CE_ATTR_DIS_INTR) | ||||
| 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) | ||||
| 			continue; | ||||
| 
 | ||||
| 		irq_idx = ATH11K_IRQ_CE0_OFFSET + i; | ||||
| @ -926,7 +863,7 @@ static int ath11k_ahb_probe(struct platform_device *pdev) | ||||
| 		return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	ab = ath11k_core_alloc(&pdev->dev, 0, ATH11K_BUS_AHB); | ||||
| 	ab = ath11k_core_alloc(&pdev->dev, 0, ATH11K_BUS_AHB, &ath11k_ahb_bus_params); | ||||
| 	if (!ab) { | ||||
| 		dev_err(&pdev->dev, "failed to allocate ath11k base\n"); | ||||
| 		return -ENOMEM; | ||||
| @ -939,6 +876,10 @@ static int ath11k_ahb_probe(struct platform_device *pdev) | ||||
| 	ab->mem_len = resource_size(mem_res); | ||||
| 	platform_set_drvdata(pdev, ab); | ||||
| 
 | ||||
| 	ret = ath11k_core_pre_init(ab); | ||||
| 	if (ret) | ||||
| 		goto err_core_free; | ||||
| 
 | ||||
| 	ret = ath11k_hal_srng_init(ab); | ||||
| 	if (ret) | ||||
| 		goto err_core_free; | ||||
| @ -951,18 +892,18 @@ static int ath11k_ahb_probe(struct platform_device *pdev) | ||||
| 
 | ||||
| 	ath11k_ahb_init_qmi_ce_config(ab); | ||||
| 
 | ||||
| 	ret = ath11k_ahb_config_irq(ab); | ||||
| 	if (ret) { | ||||
| 		ath11k_err(ab, "failed to configure irq: %d\n", ret); | ||||
| 		goto err_ce_free; | ||||
| 	} | ||||
| 
 | ||||
| 	ret = ath11k_core_init(ab); | ||||
| 	if (ret) { | ||||
| 		ath11k_err(ab, "failed to init core: %d\n", ret); | ||||
| 		goto err_ce_free; | ||||
| 	} | ||||
| 
 | ||||
| 	ret = ath11k_ahb_config_irq(ab); | ||||
| 	if (ret) { | ||||
| 		ath11k_err(ab, "failed to configure irq: %d\n", ret); | ||||
| 		goto err_ce_free; | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| 
 | ||||
| err_ce_free: | ||||
| @ -1023,5 +964,5 @@ static void ath11k_ahb_exit(void) | ||||
| } | ||||
| module_exit(ath11k_ahb_exit); | ||||
| 
 | ||||
| MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11ax wireless chip"); | ||||
| MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11ax WLAN AHB devices"); | ||||
| MODULE_LICENSE("Dual BSD/GPL"); | ||||
|  | ||||
| @ -5,8 +5,9 @@ | ||||
| 
 | ||||
| #include "dp_rx.h" | ||||
| #include "debug.h" | ||||
| #include "hif.h" | ||||
| 
 | ||||
| static const struct ce_attr host_ce_config_wlan[] = { | ||||
| const struct ce_attr ath11k_host_ce_config_ipq8074[] = { | ||||
| 	/* CE0: host->target HTC control and raw streams */ | ||||
| 	{ | ||||
| 		.flags = CE_ATTR_FLAGS, | ||||
| @ -108,6 +109,84 @@ static const struct ce_attr host_ce_config_wlan[] = { | ||||
| 	}, | ||||
| }; | ||||
| 
 | ||||
| const struct ce_attr ath11k_host_ce_config_qca6390[] = { | ||||
| 	/* CE0: host->target HTC control and raw streams */ | ||||
| 	{ | ||||
| 		.flags = CE_ATTR_FLAGS, | ||||
| 		.src_nentries = 16, | ||||
| 		.src_sz_max = 2048, | ||||
| 		.dest_nentries = 0, | ||||
| 	}, | ||||
| 
 | ||||
| 	/* CE1: target->host HTT + HTC control */ | ||||
| 	{ | ||||
| 		.flags = CE_ATTR_FLAGS, | ||||
| 		.src_nentries = 0, | ||||
| 		.src_sz_max = 2048, | ||||
| 		.dest_nentries = 512, | ||||
| 		.recv_cb = ath11k_htc_rx_completion_handler, | ||||
| 	}, | ||||
| 
 | ||||
| 	/* CE2: target->host WMI */ | ||||
| 	{ | ||||
| 		.flags = CE_ATTR_FLAGS, | ||||
| 		.src_nentries = 0, | ||||
| 		.src_sz_max = 2048, | ||||
| 		.dest_nentries = 512, | ||||
| 		.recv_cb = ath11k_htc_rx_completion_handler, | ||||
| 	}, | ||||
| 
 | ||||
| 	/* CE3: host->target WMI (mac0) */ | ||||
| 	{ | ||||
| 		.flags = CE_ATTR_FLAGS, | ||||
| 		.src_nentries = 32, | ||||
| 		.src_sz_max = 2048, | ||||
| 		.dest_nentries = 0, | ||||
| 	}, | ||||
| 
 | ||||
| 	/* CE4: host->target HTT */ | ||||
| 	{ | ||||
| 		.flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR, | ||||
| 		.src_nentries = 2048, | ||||
| 		.src_sz_max = 256, | ||||
| 		.dest_nentries = 0, | ||||
| 	}, | ||||
| 
 | ||||
| 	/* CE5: target->host pktlog */ | ||||
| 	{ | ||||
| 		.flags = CE_ATTR_FLAGS, | ||||
| 		.src_nentries = 0, | ||||
| 		.src_sz_max = 2048, | ||||
| 		.dest_nentries = 512, | ||||
| 		.recv_cb = ath11k_dp_htt_htc_t2h_msg_handler, | ||||
| 	}, | ||||
| 
 | ||||
| 	/* CE6: target autonomous hif_memcpy */ | ||||
| 	{ | ||||
| 		.flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR, | ||||
| 		.src_nentries = 0, | ||||
| 		.src_sz_max = 0, | ||||
| 		.dest_nentries = 0, | ||||
| 	}, | ||||
| 
 | ||||
| 	/* CE7: host->target WMI (mac1) */ | ||||
| 	{ | ||||
| 		.flags = CE_ATTR_FLAGS, | ||||
| 		.src_nentries = 32, | ||||
| 		.src_sz_max = 2048, | ||||
| 		.dest_nentries = 0, | ||||
| 	}, | ||||
| 
 | ||||
| 	/* CE8: target autonomous hif_memcpy */ | ||||
| 	{ | ||||
| 		.flags = CE_ATTR_FLAGS, | ||||
| 		.src_nentries = 0, | ||||
| 		.src_sz_max = 0, | ||||
| 		.dest_nentries = 0, | ||||
| 	}, | ||||
| 
 | ||||
| }; | ||||
| 
 | ||||
| static int ath11k_ce_rx_buf_enqueue_pipe(struct ath11k_ce_pipe *pipe, | ||||
| 					 struct sk_buff *skb, dma_addr_t paddr) | ||||
| { | ||||
| @ -352,6 +431,31 @@ static void ath11k_ce_send_done_cb(struct ath11k_ce_pipe *pipe) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void ath11k_ce_srng_msi_ring_params_setup(struct ath11k_base *ab, u32 ce_id, | ||||
| 						 struct hal_srng_params *ring_params) | ||||
| { | ||||
| 	u32 msi_data_start; | ||||
| 	u32 msi_data_count; | ||||
| 	u32 msi_irq_start; | ||||
| 	u32 addr_lo; | ||||
| 	u32 addr_hi; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	ret = ath11k_get_user_msi_vector(ab, "CE", | ||||
| 					 &msi_data_count, &msi_data_start, | ||||
| 					 &msi_irq_start); | ||||
| 
 | ||||
| 	if (ret) | ||||
| 		return; | ||||
| 
 | ||||
| 	ath11k_get_msi_address(ab, &addr_lo, &addr_hi); | ||||
| 
 | ||||
| 	ring_params->msi_addr = addr_lo; | ||||
| 	ring_params->msi_addr |= (dma_addr_t)(((uint64_t)addr_hi) << 32); | ||||
| 	ring_params->msi_data = (ce_id % msi_data_count) + msi_data_start; | ||||
| 	ring_params->flags |= HAL_SRNG_FLAGS_MSI_INTR; | ||||
| } | ||||
| 
 | ||||
| static int ath11k_ce_init_ring(struct ath11k_base *ab, | ||||
| 			       struct ath11k_ce_ring *ce_ring, | ||||
| 			       int ce_id, enum hal_ring_type type) | ||||
| @ -363,21 +467,24 @@ static int ath11k_ce_init_ring(struct ath11k_base *ab, | ||||
| 	params.ring_base_vaddr = ce_ring->base_addr_owner_space; | ||||
| 	params.num_entries = ce_ring->nentries; | ||||
| 
 | ||||
| 	if (!(CE_ATTR_DIS_INTR & ab->hw_params.host_ce_config[ce_id].flags)) | ||||
| 		ath11k_ce_srng_msi_ring_params_setup(ab, ce_id, ¶ms); | ||||
| 
 | ||||
| 	switch (type) { | ||||
| 	case HAL_CE_SRC: | ||||
| 		if (!(CE_ATTR_DIS_INTR & host_ce_config_wlan[ce_id].flags)) | ||||
| 		if (!(CE_ATTR_DIS_INTR & ab->hw_params.host_ce_config[ce_id].flags)) | ||||
| 			params.intr_batch_cntr_thres_entries = 1; | ||||
| 		break; | ||||
| 	case HAL_CE_DST: | ||||
| 		params.max_buffer_len = host_ce_config_wlan[ce_id].src_sz_max; | ||||
| 		if (!(host_ce_config_wlan[ce_id].flags & CE_ATTR_DIS_INTR)) { | ||||
| 		params.max_buffer_len = ab->hw_params.host_ce_config[ce_id].src_sz_max; | ||||
| 		if (!(ab->hw_params.host_ce_config[ce_id].flags & CE_ATTR_DIS_INTR)) { | ||||
| 			params.intr_timer_thres_us = 1024; | ||||
| 			params.flags |= HAL_SRNG_FLAGS_LOW_THRESH_INTR_EN; | ||||
| 			params.low_threshold = ce_ring->nentries - 3; | ||||
| 		} | ||||
| 		break; | ||||
| 	case HAL_CE_DST_STATUS: | ||||
| 		if (!(host_ce_config_wlan[ce_id].flags & CE_ATTR_DIS_INTR)) { | ||||
| 		if (!(ab->hw_params.host_ce_config[ce_id].flags & CE_ATTR_DIS_INTR)) { | ||||
| 			params.intr_batch_cntr_thres_entries = 1; | ||||
| 			params.intr_timer_thres_us = 0x1000; | ||||
| 		} | ||||
| @ -395,6 +502,7 @@ static int ath11k_ce_init_ring(struct ath11k_base *ab, | ||||
| 			    ret, ce_id); | ||||
| 		return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	ce_ring->hal_ring_id = ret; | ||||
| 
 | ||||
| 	return 0; | ||||
| @ -440,7 +548,7 @@ ath11k_ce_alloc_ring(struct ath11k_base *ab, int nentries, int desc_sz) | ||||
| static int ath11k_ce_alloc_pipe(struct ath11k_base *ab, int ce_id) | ||||
| { | ||||
| 	struct ath11k_ce_pipe *pipe = &ab->ce.ce_pipe[ce_id]; | ||||
| 	const struct ce_attr *attr = &host_ce_config_wlan[ce_id]; | ||||
| 	const struct ce_attr *attr = &ab->hw_params.host_ce_config[ce_id]; | ||||
| 	struct ath11k_ce_ring *ring; | ||||
| 	int nentries; | ||||
| 	int desc_sz; | ||||
| @ -494,6 +602,7 @@ void ath11k_ce_poll_send_completed(struct ath11k_base *ab, u8 pipe_id) | ||||
| 	if ((pipe->attr_flags & CE_ATTR_DIS_INTR) && pipe->send_cb) | ||||
| 		pipe->send_cb(pipe); | ||||
| } | ||||
| EXPORT_SYMBOL(ath11k_ce_per_engine_service); | ||||
| 
 | ||||
| int ath11k_ce_send(struct ath11k_base *ab, struct sk_buff *skb, u8 pipe_id, | ||||
| 		   u16 transfer_id) | ||||
| @ -609,7 +718,7 @@ void ath11k_ce_cleanup_pipes(struct ath11k_base *ab) | ||||
| 	struct ath11k_ce_pipe *pipe; | ||||
| 	int pipe_num; | ||||
| 
 | ||||
| 	for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) { | ||||
| 	for (pipe_num = 0; pipe_num < ab->hw_params.ce_count; pipe_num++) { | ||||
| 		pipe = &ab->ce.ce_pipe[pipe_num]; | ||||
| 		ath11k_ce_rx_pipe_cleanup(pipe); | ||||
| 
 | ||||
| @ -619,6 +728,7 @@ void ath11k_ce_cleanup_pipes(struct ath11k_base *ab) | ||||
| 		/* NOTE: Should we also clean up tx buffer in all pipes? */ | ||||
| 	} | ||||
| } | ||||
| EXPORT_SYMBOL(ath11k_ce_cleanup_pipes); | ||||
| 
 | ||||
| void ath11k_ce_rx_post_buf(struct ath11k_base *ab) | ||||
| { | ||||
| @ -626,7 +736,7 @@ void ath11k_ce_rx_post_buf(struct ath11k_base *ab) | ||||
| 	int i; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	for (i = 0; i < CE_COUNT; i++) { | ||||
| 	for (i = 0; i < ab->hw_params.ce_count; i++) { | ||||
| 		pipe = &ab->ce.ce_pipe[i]; | ||||
| 		ret = ath11k_ce_rx_post_pipe(pipe); | ||||
| 		if (ret) { | ||||
| @ -642,6 +752,7 @@ void ath11k_ce_rx_post_buf(struct ath11k_base *ab) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| EXPORT_SYMBOL(ath11k_ce_rx_post_buf); | ||||
| 
 | ||||
| void ath11k_ce_rx_replenish_retry(struct timer_list *t) | ||||
| { | ||||
| @ -656,7 +767,7 @@ int ath11k_ce_init_pipes(struct ath11k_base *ab) | ||||
| 	int i; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	for (i = 0; i < CE_COUNT; i++) { | ||||
| 	for (i = 0; i < ab->hw_params.ce_count; i++) { | ||||
| 		pipe = &ab->ce.ce_pipe[i]; | ||||
| 
 | ||||
| 		if (pipe->src_ring) { | ||||
| @ -714,7 +825,7 @@ void ath11k_ce_free_pipes(struct ath11k_base *ab) | ||||
| 	int desc_sz; | ||||
| 	int i; | ||||
| 
 | ||||
| 	for (i = 0; i < CE_COUNT; i++) { | ||||
| 	for (i = 0; i < ab->hw_params.ce_count; i++) { | ||||
| 		pipe = &ab->ce.ce_pipe[i]; | ||||
| 
 | ||||
| 		if (pipe->src_ring) { | ||||
| @ -752,6 +863,7 @@ void ath11k_ce_free_pipes(struct ath11k_base *ab) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| EXPORT_SYMBOL(ath11k_ce_free_pipes); | ||||
| 
 | ||||
| int ath11k_ce_alloc_pipes(struct ath11k_base *ab) | ||||
| { | ||||
| @ -762,8 +874,8 @@ int ath11k_ce_alloc_pipes(struct ath11k_base *ab) | ||||
| 
 | ||||
| 	spin_lock_init(&ab->ce.ce_lock); | ||||
| 
 | ||||
| 	for (i = 0; i < CE_COUNT; i++) { | ||||
| 		attr = &host_ce_config_wlan[i]; | ||||
| 	for (i = 0; i < ab->hw_params.ce_count; i++) { | ||||
| 		attr = &ab->hw_params.host_ce_config[i]; | ||||
| 		pipe = &ab->ce.ce_pipe[i]; | ||||
| 		pipe->pipe_num = i; | ||||
| 		pipe->ab = ab; | ||||
| @ -779,6 +891,7 @@ int ath11k_ce_alloc_pipes(struct ath11k_base *ab) | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| EXPORT_SYMBOL(ath11k_ce_alloc_pipes); | ||||
| 
 | ||||
| /* For Big Endian Host, Copy Engine byte_swap is enabled
 | ||||
|  * When Copy Engine does byte_swap, need to byte swap again for the | ||||
| @ -799,10 +912,11 @@ void ath11k_ce_byte_swap(void *mem, u32 len) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| int ath11k_ce_get_attr_flags(int ce_id) | ||||
| int ath11k_ce_get_attr_flags(struct ath11k_base *ab, int ce_id) | ||||
| { | ||||
| 	if (ce_id >= CE_COUNT) | ||||
| 	if (ce_id >= ab->hw_params.ce_count) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	return host_ce_config_wlan[ce_id].flags; | ||||
| 	return ab->hw_params.host_ce_config[ce_id].flags; | ||||
| } | ||||
| EXPORT_SYMBOL(ath11k_ce_get_attr_flags); | ||||
|  | ||||
| @ -6,7 +6,7 @@ | ||||
| #ifndef ATH11K_CE_H | ||||
| #define ATH11K_CE_H | ||||
| 
 | ||||
| #define CE_COUNT 12 | ||||
| #define CE_COUNT_MAX 12 | ||||
| 
 | ||||
| /* Byte swap data words */ | ||||
| #define CE_ATTR_BYTE_SWAP_DATA 2 | ||||
| @ -165,11 +165,14 @@ struct ath11k_ce_pipe { | ||||
| }; | ||||
| 
 | ||||
| struct ath11k_ce { | ||||
| 	struct ath11k_ce_pipe ce_pipe[CE_COUNT]; | ||||
| 	struct ath11k_ce_pipe ce_pipe[CE_COUNT_MAX]; | ||||
| 	/* Protects rings of all ce pipes */ | ||||
| 	spinlock_t ce_lock; | ||||
| }; | ||||
| 
 | ||||
| extern const struct ce_attr ath11k_host_ce_config_ipq8074[]; | ||||
| extern const struct ce_attr ath11k_host_ce_config_qca6390[]; | ||||
| 
 | ||||
| void ath11k_ce_cleanup_pipes(struct ath11k_base *ab); | ||||
| void ath11k_ce_rx_replenish_retry(struct timer_list *t); | ||||
| void ath11k_ce_per_engine_service(struct ath11k_base *ab, u16 ce_id); | ||||
| @ -179,6 +182,9 @@ void ath11k_ce_rx_post_buf(struct ath11k_base *ab); | ||||
| int ath11k_ce_init_pipes(struct ath11k_base *ab); | ||||
| int ath11k_ce_alloc_pipes(struct ath11k_base *ab); | ||||
| void ath11k_ce_free_pipes(struct ath11k_base *ab); | ||||
| int ath11k_ce_get_attr_flags(int ce_id); | ||||
| int ath11k_ce_get_attr_flags(struct ath11k_base *ab, int ce_id); | ||||
| void ath11k_ce_poll_send_completed(struct ath11k_base *ab, u8 pipe_id); | ||||
| int ath11k_ce_map_service_to_pipe(struct ath11k_base *ab, u16 service_id, | ||||
| 				  u8 *ul_pipe, u8 *dl_pipe); | ||||
| int ath11k_ce_attr_attach(struct ath11k_base *ab); | ||||
| #endif | ||||
|  | ||||
| @ -14,43 +14,69 @@ | ||||
| #include "hif.h" | ||||
| 
 | ||||
| unsigned int ath11k_debug_mask; | ||||
| EXPORT_SYMBOL(ath11k_debug_mask); | ||||
| module_param_named(debug_mask, ath11k_debug_mask, uint, 0644); | ||||
| MODULE_PARM_DESC(debug_mask, "Debugging mask"); | ||||
| 
 | ||||
| static const struct ath11k_hw_params ath11k_hw_params = { | ||||
| 	.name = "ipq8074", | ||||
| 	.fw = { | ||||
| 		.dir = IPQ8074_FW_DIR, | ||||
| 		.board_size = IPQ8074_MAX_BOARD_DATA_SZ, | ||||
| 		.cal_size =  IPQ8074_MAX_CAL_DATA_SZ, | ||||
| static const struct ath11k_hw_params ath11k_hw_params[] = { | ||||
| 	{ | ||||
| 		.hw_rev = ATH11K_HW_IPQ8074, | ||||
| 		.name = "ipq8074 hw2.0", | ||||
| 		.fw = { | ||||
| 			.dir = "IPQ8074/hw2.0", | ||||
| 			.board_size = 256 * 1024, | ||||
| 			.cal_size = 256 * 1024, | ||||
| 		}, | ||||
| 		.max_radios = 3, | ||||
| 		.bdf_addr = 0x4B0C0000, | ||||
| 		.hw_ops = &ipq8074_ops, | ||||
| 		.ring_mask = &ath11k_hw_ring_mask_ipq8074, | ||||
| 		.internal_sleep_clock = false, | ||||
| 		.regs = &ipq8074_regs, | ||||
| 		.host_ce_config = ath11k_host_ce_config_ipq8074, | ||||
| 		.ce_count = 12, | ||||
| 		.single_pdev_only = false, | ||||
| 		.needs_band_to_mac = true, | ||||
| 		.rxdma1_enable = true, | ||||
| 		.num_rxmda_per_pdev = 1, | ||||
| 		.rx_mac_buf_ring = false, | ||||
| 		.vdev_start_delay = false, | ||||
| 		.htt_peer_map_v2 = true, | ||||
| 		.tcl_0_only = false, | ||||
| 	}, | ||||
| 	{ | ||||
| 		.name = "qca6390 hw2.0", | ||||
| 		.hw_rev = ATH11K_HW_QCA6390_HW20, | ||||
| 		.fw = { | ||||
| 			.dir = "QCA6390/hw2.0", | ||||
| 			.board_size = 256 * 1024, | ||||
| 			.cal_size = 256 * 1024, | ||||
| 		}, | ||||
| 		.max_radios = 3, | ||||
| 		.bdf_addr = 0x4B0C0000, | ||||
| 		.hw_ops = &qca6390_ops, | ||||
| 		.ring_mask = &ath11k_hw_ring_mask_qca6390, | ||||
| 		.internal_sleep_clock = true, | ||||
| 		.regs = &qca6390_regs, | ||||
| 		.host_ce_config = ath11k_host_ce_config_qca6390, | ||||
| 		.ce_count = 9, | ||||
| 		.single_pdev_only = true, | ||||
| 		.needs_band_to_mac = false, | ||||
| 		.rxdma1_enable = false, | ||||
| 		.num_rxmda_per_pdev = 2, | ||||
| 		.rx_mac_buf_ring = true, | ||||
| 		.vdev_start_delay = true, | ||||
| 		.htt_peer_map_v2 = false, | ||||
| 		.tcl_0_only = true, | ||||
| 	}, | ||||
| }; | ||||
| 
 | ||||
| /* Map from pdev index to hw mac index */ | ||||
| u8 ath11k_core_get_hw_mac_id(struct ath11k_base *ab, int pdev_idx) | ||||
| { | ||||
| 	switch (pdev_idx) { | ||||
| 	case 0: | ||||
| 		return 0; | ||||
| 	case 1: | ||||
| 		return 2; | ||||
| 	case 2: | ||||
| 		return 1; | ||||
| 	default: | ||||
| 		ath11k_warn(ab, "Invalid pdev idx %d\n", pdev_idx); | ||||
| 		return ATH11K_INVALID_HW_MAC_ID; | ||||
| 	} | ||||
| } | ||||
| EXPORT_SYMBOL(ath11k_core_get_hw_mac_id); | ||||
| 
 | ||||
| static int ath11k_core_create_board_name(struct ath11k_base *ab, char *name, | ||||
| 					 size_t name_len) | ||||
| { | ||||
| 	/* Note: bus is fixed to ahb. When other bus type supported,
 | ||||
| 	 * make it to dynamic. | ||||
| 	 */ | ||||
| 	scnprintf(name, name_len, | ||||
| 		  "bus=ahb,qmi-chip-id=%d,qmi-board-id=%d", | ||||
| 		  "bus=%s,qmi-chip-id=%d,qmi-board-id=%d", | ||||
| 		  ath11k_bus_str(ab->hif.bus), | ||||
| 		  ab->qmi.target.chip_id, | ||||
| 		  ab->qmi.target.board_id); | ||||
| 
 | ||||
| @ -59,29 +85,24 @@ static int ath11k_core_create_board_name(struct ath11k_base *ab, char *name, | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static const struct firmware *ath11k_fetch_fw_file(struct ath11k_base *ab, | ||||
| 						   const char *dir, | ||||
| 						   const char *file) | ||||
| const struct firmware *ath11k_core_firmware_request(struct ath11k_base *ab, | ||||
| 						    const char *file) | ||||
| { | ||||
| 	char filename[100]; | ||||
| 	const struct firmware *fw; | ||||
| 	char path[100]; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	if (file == NULL) | ||||
| 		return ERR_PTR(-ENOENT); | ||||
| 
 | ||||
| 	if (dir == NULL) | ||||
| 		dir = "."; | ||||
| 
 | ||||
| 	snprintf(filename, sizeof(filename), "%s/%s", dir, file); | ||||
| 	ret = firmware_request_nowarn(&fw, filename, ab->dev); | ||||
| 	ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot fw request '%s': %d\n", | ||||
| 		   filename, ret); | ||||
| 	ath11k_core_create_firmware_path(ab, file, path, sizeof(path)); | ||||
| 
 | ||||
| 	ret = firmware_request_nowarn(&fw, path, ab->dev); | ||||
| 	if (ret) | ||||
| 		return ERR_PTR(ret); | ||||
| 	ath11k_warn(ab, "Downloading BDF: %s, size: %zu\n", | ||||
| 		    filename, fw->size); | ||||
| 
 | ||||
| 	ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot firmware request %s size %zu\n", | ||||
| 		   path, fw->size); | ||||
| 
 | ||||
| 	return fw; | ||||
| } | ||||
| @ -181,26 +202,30 @@ static int ath11k_core_fetch_board_data_api_n(struct ath11k_base *ab, | ||||
| { | ||||
| 	size_t len, magic_len; | ||||
| 	const u8 *data; | ||||
| 	char *filename = ATH11K_BOARD_API2_FILE; | ||||
| 	char *filename, filepath[100]; | ||||
| 	size_t ie_len; | ||||
| 	struct ath11k_fw_ie *hdr; | ||||
| 	int ret, ie_id; | ||||
| 
 | ||||
| 	filename = ATH11K_BOARD_API2_FILE; | ||||
| 
 | ||||
| 	if (!bd->fw) | ||||
| 		bd->fw = ath11k_fetch_fw_file(ab, | ||||
| 					      ab->hw_params.fw.dir, | ||||
| 					      filename); | ||||
| 		bd->fw = ath11k_core_firmware_request(ab, filename); | ||||
| 
 | ||||
| 	if (IS_ERR(bd->fw)) | ||||
| 		return PTR_ERR(bd->fw); | ||||
| 
 | ||||
| 	data = bd->fw->data; | ||||
| 	len = bd->fw->size; | ||||
| 
 | ||||
| 	ath11k_core_create_firmware_path(ab, filename, | ||||
| 					 filepath, sizeof(filepath)); | ||||
| 
 | ||||
| 	/* magic has extra null byte padded */ | ||||
| 	magic_len = strlen(ATH11K_BOARD_MAGIC) + 1; | ||||
| 	if (len < magic_len) { | ||||
| 		ath11k_err(ab, "failed to find magic value in %s/%s, file too short: %zu\n", | ||||
| 			   ab->hw_params.fw.dir, filename, len); | ||||
| 		ath11k_err(ab, "failed to find magic value in %s, file too short: %zu\n", | ||||
| 			   filepath, len); | ||||
| 		ret = -EINVAL; | ||||
| 		goto err; | ||||
| 	} | ||||
| @ -214,8 +239,8 @@ static int ath11k_core_fetch_board_data_api_n(struct ath11k_base *ab, | ||||
| 	/* magic is padded to 4 bytes */ | ||||
| 	magic_len = ALIGN(magic_len, 4); | ||||
| 	if (len < magic_len) { | ||||
| 		ath11k_err(ab, "failed: %s/%s too small to contain board data, len: %zu\n", | ||||
| 			   ab->hw_params.fw.dir, filename, len); | ||||
| 		ath11k_err(ab, "failed: %s too small to contain board data, len: %zu\n", | ||||
| 			   filepath, len); | ||||
| 		ret = -EINVAL; | ||||
| 		goto err; | ||||
| 	} | ||||
| @ -263,8 +288,8 @@ static int ath11k_core_fetch_board_data_api_n(struct ath11k_base *ab, | ||||
| out: | ||||
| 	if (!bd->data || !bd->len) { | ||||
| 		ath11k_err(ab, | ||||
| 			   "failed to fetch board data for %s from %s/%s\n", | ||||
| 			   boardname, ab->hw_params.fw.dir, filename); | ||||
| 			   "failed to fetch board data for %s from %s\n", | ||||
| 			   boardname, filepath); | ||||
| 		ret = -ENODATA; | ||||
| 		goto err; | ||||
| 	} | ||||
| @ -279,9 +304,7 @@ err: | ||||
| static int ath11k_core_fetch_board_data_api_1(struct ath11k_base *ab, | ||||
| 					      struct ath11k_board_data *bd) | ||||
| { | ||||
| 	bd->fw = ath11k_fetch_fw_file(ab, | ||||
| 				      ab->hw_params.fw.dir, | ||||
| 				      ATH11K_DEFAULT_BOARD_FILE); | ||||
| 	bd->fw = ath11k_core_firmware_request(ab, ATH11K_DEFAULT_BOARD_FILE); | ||||
| 	if (IS_ERR(bd->fw)) | ||||
| 		return PTR_ERR(bd->fw); | ||||
| 
 | ||||
| @ -706,7 +729,7 @@ static void ath11k_core_restart(struct work_struct *work) | ||||
| 			break; | ||||
| 		case ATH11K_STATE_RESTARTED: | ||||
| 			ar->state = ATH11K_STATE_WEDGED; | ||||
| 			/* fall through */ | ||||
| 			fallthrough; | ||||
| 		case ATH11K_STATE_WEDGED: | ||||
| 			ath11k_warn(ab, | ||||
| 				    "device is wedged, will not restart radio %d\n", i); | ||||
| @ -717,12 +740,52 @@ static void ath11k_core_restart(struct work_struct *work) | ||||
| 	complete(&ab->driver_recovery); | ||||
| } | ||||
| 
 | ||||
| int ath11k_core_init(struct ath11k_base *ab) | ||||
| static int ath11k_init_hw_params(struct ath11k_base *ab) | ||||
| { | ||||
| 	const struct ath11k_hw_params *hw_params = NULL; | ||||
| 	int i; | ||||
| 
 | ||||
| 	for (i = 0; i < ARRAY_SIZE(ath11k_hw_params); i++) { | ||||
| 		hw_params = &ath11k_hw_params[i]; | ||||
| 
 | ||||
| 		if (hw_params->hw_rev == ab->hw_rev) | ||||
| 			break; | ||||
| 	} | ||||
| 
 | ||||
| 	if (i == ARRAY_SIZE(ath11k_hw_params)) { | ||||
| 		ath11k_err(ab, "Unsupported hardware version: 0x%x\n", ab->hw_rev); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 
 | ||||
| 	ab->hw_params = *hw_params; | ||||
| 
 | ||||
| 	ath11k_dbg(ab, ATH11K_DBG_BOOT, "Hardware name %s\n", ab->hw_params.name); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| int ath11k_core_pre_init(struct ath11k_base *ab) | ||||
| { | ||||
| 	int ret; | ||||
| 
 | ||||
| 	ret = ath11k_init_hw_params(ab); | ||||
| 	if (ret) { | ||||
| 		ath11k_err(ab, "failed to get hw params: %d\n", ret); | ||||
| 		return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| EXPORT_SYMBOL(ath11k_core_pre_init); | ||||
| 
 | ||||
| static int ath11k_core_get_rproc(struct ath11k_base *ab) | ||||
| { | ||||
| 	struct device *dev = ab->dev; | ||||
| 	struct rproc *prproc; | ||||
| 	phandle rproc_phandle; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	if (ab->bus_params.mhi_support) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	if (of_property_read_u32(dev->of_node, "qcom,rproc", &rproc_phandle)) { | ||||
| 		ath11k_err(ab, "failed to get q6_rproc handle\n"); | ||||
| @ -735,7 +798,25 @@ int ath11k_core_init(struct ath11k_base *ab) | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 	ab->tgt_rproc = prproc; | ||||
| 	ab->hw_params = ath11k_hw_params; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| int ath11k_core_init(struct ath11k_base *ab) | ||||
| { | ||||
| 	int ret; | ||||
| 
 | ||||
| 	ret = ath11k_core_get_rproc(ab); | ||||
| 	if (ret) { | ||||
| 		ath11k_err(ab, "failed to get rproc: %d\n", ret); | ||||
| 		return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	ret = ath11k_init_hw_params(ab); | ||||
| 	if (ret) { | ||||
| 		ath11k_err(ab, "failed to get hw params %d\n", ret); | ||||
| 		return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	ret = ath11k_core_soc_create(ab); | ||||
| 	if (ret) { | ||||
| @ -745,6 +826,7 @@ int ath11k_core_init(struct ath11k_base *ab) | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| EXPORT_SYMBOL(ath11k_core_init); | ||||
| 
 | ||||
| void ath11k_core_deinit(struct ath11k_base *ab) | ||||
| { | ||||
| @ -759,14 +841,17 @@ void ath11k_core_deinit(struct ath11k_base *ab) | ||||
| 	ath11k_mac_destroy(ab); | ||||
| 	ath11k_core_soc_destroy(ab); | ||||
| } | ||||
| EXPORT_SYMBOL(ath11k_core_deinit); | ||||
| 
 | ||||
| void ath11k_core_free(struct ath11k_base *ab) | ||||
| { | ||||
| 	kfree(ab); | ||||
| } | ||||
| EXPORT_SYMBOL(ath11k_core_free); | ||||
| 
 | ||||
| struct ath11k_base *ath11k_core_alloc(struct device *dev, size_t priv_size, | ||||
| 				      enum ath11k_bus bus) | ||||
| 				      enum ath11k_bus bus, | ||||
| 				      const struct ath11k_bus_params *bus_params) | ||||
| { | ||||
| 	struct ath11k_base *ab; | ||||
| 
 | ||||
| @ -789,6 +874,8 @@ struct ath11k_base *ath11k_core_alloc(struct device *dev, size_t priv_size, | ||||
| 	INIT_WORK(&ab->restart_work, ath11k_core_restart); | ||||
| 	timer_setup(&ab->rx_replenish_retry, ath11k_ce_rx_replenish_retry, 0); | ||||
| 	ab->dev = dev; | ||||
| 	ab->bus_params = *bus_params; | ||||
| 	ab->hif.bus = bus; | ||||
| 
 | ||||
| 	return ab; | ||||
| 
 | ||||
| @ -796,3 +883,7 @@ err_sc_free: | ||||
| 	kfree(ab); | ||||
| 	return NULL; | ||||
| } | ||||
| EXPORT_SYMBOL(ath11k_core_alloc); | ||||
| 
 | ||||
| MODULE_DESCRIPTION("Core module for Qualcomm Atheros 802.11ax wireless LAN cards."); | ||||
| MODULE_LICENSE("Dual BSD/GPL"); | ||||
|  | ||||
| @ -90,6 +90,7 @@ struct ath11k_skb_rxcb { | ||||
| 
 | ||||
| enum ath11k_hw_rev { | ||||
| 	ATH11K_HW_IPQ8074, | ||||
| 	ATH11K_HW_QCA6390_HW20, | ||||
| }; | ||||
| 
 | ||||
| enum ath11k_firmware_mode { | ||||
| @ -101,18 +102,8 @@ enum ath11k_firmware_mode { | ||||
| }; | ||||
| 
 | ||||
| #define ATH11K_IRQ_NUM_MAX 52 | ||||
| #define ATH11K_EXT_IRQ_GRP_NUM_MAX 11 | ||||
| #define ATH11K_EXT_IRQ_NUM_MAX	16 | ||||
| 
 | ||||
| extern const u8 ath11k_reo_status_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX]; | ||||
| extern const u8 ath11k_tx_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX]; | ||||
| extern const u8 ath11k_rx_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX]; | ||||
| extern const u8 ath11k_rx_err_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX]; | ||||
| extern const u8 ath11k_rx_wbm_rel_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX]; | ||||
| extern const u8 ath11k_rxdma2host_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX]; | ||||
| extern const u8 ath11k_host2rxdma_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX]; | ||||
| extern const u8 rx_mon_status_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX]; | ||||
| 
 | ||||
| struct ath11k_ext_irq_grp { | ||||
| 	struct ath11k_base *ab; | ||||
| 	u32 irqs[ATH11K_EXT_IRQ_NUM_MAX]; | ||||
| @ -226,6 +217,7 @@ struct ath11k_vif { | ||||
| 	int txpower; | ||||
| 	bool rsnie_present; | ||||
| 	bool wpaie_present; | ||||
| 	struct ieee80211_chanctx_conf chanctx; | ||||
| }; | ||||
| 
 | ||||
| struct ath11k_vif_iter { | ||||
| @ -554,6 +546,7 @@ struct ath11k { | ||||
| }; | ||||
| 
 | ||||
| struct ath11k_band_cap { | ||||
| 	u32 phy_id; | ||||
| 	u32 max_bw_supported; | ||||
| 	u32 ht_cap_info; | ||||
| 	u32 he_cap_info[2]; | ||||
| @ -589,6 +582,13 @@ struct ath11k_board_data { | ||||
| 	size_t len; | ||||
| }; | ||||
| 
 | ||||
| struct ath11k_bus_params { | ||||
| 	bool mhi_support; | ||||
| 	bool m3_fw_support; | ||||
| 	bool fixed_bdf_addr; | ||||
| 	bool fixed_mem_region; | ||||
| }; | ||||
| 
 | ||||
| /* IPQ8074 HW channel counters frequency value in hertz */ | ||||
| #define IPQ8074_CC_FREQ_HERTZ 320000 | ||||
| 
 | ||||
| @ -651,6 +651,7 @@ struct ath11k_base { | ||||
| 	unsigned long mem_len; | ||||
| 
 | ||||
| 	struct { | ||||
| 		enum ath11k_bus bus; | ||||
| 		const struct ath11k_hif_ops *ops; | ||||
| 	} hif; | ||||
| 
 | ||||
| @ -677,7 +678,10 @@ struct ath11k_base { | ||||
| 	u32 ext_service_bitmap[WMI_SERVICE_EXT_BM_SIZE]; | ||||
| 	bool pdevs_macaddr_valid; | ||||
| 	int bd_api; | ||||
| 
 | ||||
| 	struct ath11k_hw_params hw_params; | ||||
| 	struct ath11k_bus_params bus_params; | ||||
| 
 | ||||
| 	const struct firmware *cal_file; | ||||
| 
 | ||||
| 	/* Below regd's are protected by ab->data_lock */ | ||||
| @ -850,17 +854,21 @@ struct ath11k_peer *ath11k_peer_find_by_addr(struct ath11k_base *ab, | ||||
| 					     const u8 *addr); | ||||
| struct ath11k_peer *ath11k_peer_find_by_id(struct ath11k_base *ab, int peer_id); | ||||
| int ath11k_core_qmi_firmware_ready(struct ath11k_base *ab); | ||||
| int ath11k_core_pre_init(struct ath11k_base *ab); | ||||
| int ath11k_core_init(struct ath11k_base *ath11k); | ||||
| void ath11k_core_deinit(struct ath11k_base *ath11k); | ||||
| struct ath11k_base *ath11k_core_alloc(struct device *dev, size_t priv_size, | ||||
| 				      enum ath11k_bus bus); | ||||
| 				      enum ath11k_bus bus, | ||||
| 				      const struct ath11k_bus_params *bus_params); | ||||
| void ath11k_core_free(struct ath11k_base *ath11k); | ||||
| int ath11k_core_fetch_bdf(struct ath11k_base *ath11k, | ||||
| 			  struct ath11k_board_data *bd); | ||||
| void ath11k_core_free_bdf(struct ath11k_base *ab, struct ath11k_board_data *bd); | ||||
| 
 | ||||
| void ath11k_core_halt(struct ath11k *ar); | ||||
| u8 ath11k_core_get_hw_mac_id(struct ath11k_base *ab, int pdev_idx); | ||||
| 
 | ||||
| const struct firmware *ath11k_core_firmware_request(struct ath11k_base *ab, | ||||
| 						    const char *filename); | ||||
| 
 | ||||
| static inline const char *ath11k_scan_state_str(enum ath11k_scan_state state) | ||||
| { | ||||
| @ -894,4 +902,30 @@ static inline struct ath11k_vif *ath11k_vif_to_arvif(struct ieee80211_vif *vif) | ||||
| 	return (struct ath11k_vif *)vif->drv_priv; | ||||
| } | ||||
| 
 | ||||
| static inline struct ath11k *ath11k_ab_to_ar(struct ath11k_base *ab, | ||||
| 					     int mac_id) | ||||
| { | ||||
| 	return ab->pdevs[ath11k_hw_mac_id_to_pdev_id(&ab->hw_params, mac_id)].ar; | ||||
| } | ||||
| 
 | ||||
| static inline void ath11k_core_create_firmware_path(struct ath11k_base *ab, | ||||
| 						    const char *filename, | ||||
| 						    void *buf, size_t buf_len) | ||||
| { | ||||
| 	snprintf(buf, buf_len, "%s/%s/%s", ATH11K_FW_DIR, | ||||
| 		 ab->hw_params.fw.dir, filename); | ||||
| } | ||||
| 
 | ||||
| static inline const char *ath11k_bus_str(enum ath11k_bus bus) | ||||
| { | ||||
| 	switch (bus) { | ||||
| 	case ATH11K_BUS_PCI: | ||||
| 		return "pci"; | ||||
| 	case ATH11K_BUS_AHB: | ||||
| 		return "ahb"; | ||||
| 	} | ||||
| 
 | ||||
| 	return "unknown"; | ||||
| } | ||||
| 
 | ||||
| #endif /* _CORE_H_ */ | ||||
|  | ||||
| @ -168,7 +168,7 @@ int ath11k_dbring_buf_setup(struct ath11k *ar, | ||||
| 
 | ||||
| 	srng = &ab->hal.srng_list[ring->refill_srng.ring_id]; | ||||
| 	ring->bufs_max = ring->refill_srng.size / | ||||
| 			 ath11k_hal_srng_get_entrysize(HAL_RXDMA_DIR_BUF); | ||||
| 		ath11k_hal_srng_get_entrysize(ab, HAL_RXDMA_DIR_BUF); | ||||
| 
 | ||||
| 	ring->buf_sz = db_cap->min_buf_sz; | ||||
| 	ring->buf_align = db_cap->min_buf_align; | ||||
|  | ||||
| @ -62,6 +62,7 @@ void ath11k_info(struct ath11k_base *ab, const char *fmt, ...) | ||||
| 	/* TODO: Trace the log */ | ||||
| 	va_end(args); | ||||
| } | ||||
| EXPORT_SYMBOL(ath11k_info); | ||||
| 
 | ||||
| void ath11k_err(struct ath11k_base *ab, const char *fmt, ...) | ||||
| { | ||||
| @ -76,6 +77,7 @@ void ath11k_err(struct ath11k_base *ab, const char *fmt, ...) | ||||
| 	/* TODO: Trace the log */ | ||||
| 	va_end(args); | ||||
| } | ||||
| EXPORT_SYMBOL(ath11k_err); | ||||
| 
 | ||||
| void ath11k_warn(struct ath11k_base *ab, const char *fmt, ...) | ||||
| { | ||||
| @ -90,6 +92,7 @@ void ath11k_warn(struct ath11k_base *ab, const char *fmt, ...) | ||||
| 	/* TODO: Trace the log */ | ||||
| 	va_end(args); | ||||
| } | ||||
| EXPORT_SYMBOL(ath11k_warn); | ||||
| 
 | ||||
| #ifdef CONFIG_ATH11K_DEBUG | ||||
| void __ath11k_dbg(struct ath11k_base *ab, enum ath11k_debug_mask mask, | ||||
| @ -110,6 +113,7 @@ void __ath11k_dbg(struct ath11k_base *ab, enum ath11k_debug_mask mask, | ||||
| 
 | ||||
| 	va_end(args); | ||||
| } | ||||
| EXPORT_SYMBOL(__ath11k_dbg); | ||||
| 
 | ||||
| void ath11k_dbg_dump(struct ath11k_base *ab, | ||||
| 		     enum ath11k_debug_mask mask, | ||||
| @ -138,6 +142,7 @@ void ath11k_dbg_dump(struct ath11k_base *ab, | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| EXPORT_SYMBOL(ath11k_dbg_dump); | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| @ -693,8 +698,10 @@ static ssize_t ath11k_write_extd_rx_stats(struct file *file, | ||||
| 					  size_t count, loff_t *ppos) | ||||
| { | ||||
| 	struct ath11k *ar = file->private_data; | ||||
| 	struct ath11k_base *ab = ar->ab; | ||||
| 	struct htt_rx_ring_tlv_filter tlv_filter = {0}; | ||||
| 	u32 enable, rx_filter = 0, ring_id; | ||||
| 	int i; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	if (kstrtouint_from_user(ubuf, count, 0, &enable)) | ||||
| @ -737,14 +744,16 @@ static ssize_t ath11k_write_extd_rx_stats(struct file *file, | ||||
| 
 | ||||
| 	ar->debug.rx_filter = tlv_filter.rx_filter; | ||||
| 
 | ||||
| 	ring_id = ar->dp.rx_mon_status_refill_ring.refill_buf_ring.ring_id; | ||||
| 	ret = ath11k_dp_tx_htt_rx_filter_setup(ar->ab, ring_id, ar->dp.mac_id, | ||||
| 					       HAL_RXDMA_MONITOR_STATUS, | ||||
| 					       DP_RX_BUFFER_SIZE, &tlv_filter); | ||||
| 	for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { | ||||
| 		ring_id = ar->dp.rx_mon_status_refill_ring[i].refill_buf_ring.ring_id; | ||||
| 		ret = ath11k_dp_tx_htt_rx_filter_setup(ar->ab, ring_id, ar->dp.mac_id, | ||||
| 						       HAL_RXDMA_MONITOR_STATUS, | ||||
| 						       DP_RX_BUFFER_SIZE, &tlv_filter); | ||||
| 
 | ||||
| 	if (ret) { | ||||
| 		ath11k_warn(ar->ab, "failed to set rx filter for monitor status ring\n"); | ||||
| 		goto exit; | ||||
| 		if (ret) { | ||||
| 			ath11k_warn(ar->ab, "failed to set rx filter for monitor status ring\n"); | ||||
| 			goto exit; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	ar->debug.extd_rx_stats = enable; | ||||
| @ -995,10 +1004,11 @@ static ssize_t ath11k_write_pktlog_filter(struct file *file, | ||||
| 					  size_t count, loff_t *ppos) | ||||
| { | ||||
| 	struct ath11k *ar = file->private_data; | ||||
| 	struct ath11k_base *ab = ar->ab; | ||||
| 	struct htt_rx_ring_tlv_filter tlv_filter = {0}; | ||||
| 	u32 rx_filter = 0, ring_id, filter, mode; | ||||
| 	u8 buf[128] = {0}; | ||||
| 	int ret; | ||||
| 	int i, ret; | ||||
| 	ssize_t rc; | ||||
| 
 | ||||
| 	mutex_lock(&ar->conf_mutex); | ||||
| @ -1079,16 +1089,20 @@ static ssize_t ath11k_write_pktlog_filter(struct file *file, | ||||
| 					       HTT_RX_FP_DATA_FILTER_FLASG3; | ||||
| 	} | ||||
| 
 | ||||
| 	ring_id = ar->dp.rx_mon_status_refill_ring.refill_buf_ring.ring_id; | ||||
| 	ret = ath11k_dp_tx_htt_rx_filter_setup(ar->ab, ring_id, ar->dp.mac_id, | ||||
| 					       HAL_RXDMA_MONITOR_STATUS, | ||||
| 					       DP_RX_BUFFER_SIZE, &tlv_filter); | ||||
| 	if (ret) { | ||||
| 		ath11k_warn(ar->ab, "failed to set rx filter for monitor status ring\n"); | ||||
| 		goto out; | ||||
| 	for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { | ||||
| 		ring_id = ar->dp.rx_mon_status_refill_ring[i].refill_buf_ring.ring_id; | ||||
| 		ret = ath11k_dp_tx_htt_rx_filter_setup(ab, ring_id, | ||||
| 						       ar->dp.mac_id + i, | ||||
| 						       HAL_RXDMA_MONITOR_STATUS, | ||||
| 						       DP_RX_BUFFER_SIZE, &tlv_filter); | ||||
| 
 | ||||
| 		if (ret) { | ||||
| 			ath11k_warn(ab, "failed to set rx filter for moniter status ring\n"); | ||||
| 			goto out; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "pktlog filter %d mode %s\n", | ||||
| 	ath11k_dbg(ab, ATH11K_DBG_WMI, "pktlog filter %d mode %s\n", | ||||
| 		   filter, ((mode == ATH11K_PKTLOG_MODE_FULL) ? "full" : "lite")); | ||||
| 
 | ||||
| 	ar->debug.pktlog_filter = filter; | ||||
|  | ||||
| @ -25,6 +25,7 @@ enum ath11k_debug_mask { | ||||
| 	ATH11K_DBG_REG		= 0x00000200, | ||||
| 	ATH11K_DBG_TESTMODE	= 0x00000400, | ||||
| 	ATH11k_DBG_HAL		= 0x00000800, | ||||
| 	ATH11K_DBG_PCI		= 0x00001000, | ||||
| 	ATH11K_DBG_ANY		= 0xffffffff, | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -7,6 +7,7 @@ | ||||
| #include "core.h" | ||||
| #include "dp_tx.h" | ||||
| #include "hal_tx.h" | ||||
| #include "hif.h" | ||||
| #include "debug.h" | ||||
| #include "dp_rx.h" | ||||
| #include "peer.h" | ||||
| @ -106,13 +107,120 @@ void ath11k_dp_srng_cleanup(struct ath11k_base *ab, struct dp_srng *ring) | ||||
| 	ring->vaddr_unaligned = NULL; | ||||
| } | ||||
| 
 | ||||
| static int ath11k_dp_srng_find_ring_in_mask(int ring_num, const u8 *grp_mask) | ||||
| { | ||||
| 	int ext_group_num; | ||||
| 	u8 mask = 1 << ring_num; | ||||
| 
 | ||||
| 	for (ext_group_num = 0; ext_group_num < ATH11K_EXT_IRQ_GRP_NUM_MAX; | ||||
| 	     ext_group_num++) { | ||||
| 		if (mask & grp_mask[ext_group_num]) | ||||
| 			return ext_group_num; | ||||
| 	} | ||||
| 
 | ||||
| 	return -ENOENT; | ||||
| } | ||||
| 
 | ||||
| static int ath11k_dp_srng_calculate_msi_group(struct ath11k_base *ab, | ||||
| 					      enum hal_ring_type type, int ring_num) | ||||
| { | ||||
| 	const u8 *grp_mask; | ||||
| 
 | ||||
| 	switch (type) { | ||||
| 	case HAL_WBM2SW_RELEASE: | ||||
| 		if (ring_num < 3) { | ||||
| 			grp_mask = &ab->hw_params.ring_mask->tx[0]; | ||||
| 		} else if (ring_num == 3) { | ||||
| 			grp_mask = &ab->hw_params.ring_mask->rx_wbm_rel[0]; | ||||
| 			ring_num = 0; | ||||
| 		} else { | ||||
| 			return -ENOENT; | ||||
| 		} | ||||
| 		break; | ||||
| 	case HAL_REO_EXCEPTION: | ||||
| 		grp_mask = &ab->hw_params.ring_mask->rx_err[0]; | ||||
| 		break; | ||||
| 	case HAL_REO_DST: | ||||
| 		grp_mask = &ab->hw_params.ring_mask->rx[0]; | ||||
| 		break; | ||||
| 	case HAL_REO_STATUS: | ||||
| 		grp_mask = &ab->hw_params.ring_mask->reo_status[0]; | ||||
| 		break; | ||||
| 	case HAL_RXDMA_MONITOR_STATUS: | ||||
| 	case HAL_RXDMA_MONITOR_DST: | ||||
| 		grp_mask = &ab->hw_params.ring_mask->rx_mon_status[0]; | ||||
| 		break; | ||||
| 	case HAL_RXDMA_DST: | ||||
| 		grp_mask = &ab->hw_params.ring_mask->rxdma2host[0]; | ||||
| 		break; | ||||
| 	case HAL_RXDMA_BUF: | ||||
| 		grp_mask = &ab->hw_params.ring_mask->host2rxdma[0]; | ||||
| 		break; | ||||
| 	case HAL_RXDMA_MONITOR_BUF: | ||||
| 	case HAL_TCL_DATA: | ||||
| 	case HAL_TCL_CMD: | ||||
| 	case HAL_REO_CMD: | ||||
| 	case HAL_SW2WBM_RELEASE: | ||||
| 	case HAL_WBM_IDLE_LINK: | ||||
| 	case HAL_TCL_STATUS: | ||||
| 	case HAL_REO_REINJECT: | ||||
| 	case HAL_CE_SRC: | ||||
| 	case HAL_CE_DST: | ||||
| 	case HAL_CE_DST_STATUS: | ||||
| 	default: | ||||
| 		return -ENOENT; | ||||
| 	} | ||||
| 
 | ||||
| 	return ath11k_dp_srng_find_ring_in_mask(ring_num, grp_mask); | ||||
| } | ||||
| 
 | ||||
| static void ath11k_dp_srng_msi_setup(struct ath11k_base *ab, | ||||
| 				     struct hal_srng_params *ring_params, | ||||
| 				     enum hal_ring_type type, int ring_num) | ||||
| { | ||||
| 	int msi_group_number, msi_data_count; | ||||
| 	u32 msi_data_start, msi_irq_start, addr_lo, addr_hi; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	ret = ath11k_get_user_msi_vector(ab, "DP", | ||||
| 					 &msi_data_count, &msi_data_start, | ||||
| 					 &msi_irq_start); | ||||
| 	if (ret) | ||||
| 		return; | ||||
| 
 | ||||
| 	msi_group_number = ath11k_dp_srng_calculate_msi_group(ab, type, | ||||
| 							      ring_num); | ||||
| 	if (msi_group_number < 0) { | ||||
| 		ath11k_dbg(ab, ATH11K_DBG_PCI, | ||||
| 			   "ring not part of an ext_group; ring_type: %d,ring_num %d", | ||||
| 			   type, ring_num); | ||||
| 		ring_params->msi_addr = 0; | ||||
| 		ring_params->msi_data = 0; | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	if (msi_group_number > msi_data_count) { | ||||
| 		ath11k_dbg(ab, ATH11K_DBG_PCI, | ||||
| 			   "multiple msi_groups share one msi, msi_group_num %d", | ||||
| 			   msi_group_number); | ||||
| 	} | ||||
| 
 | ||||
| 	ath11k_get_msi_address(ab, &addr_lo, &addr_hi); | ||||
| 
 | ||||
| 	ring_params->msi_addr = addr_lo; | ||||
| 	ring_params->msi_addr |= (dma_addr_t)(((uint64_t)addr_hi) << 32); | ||||
| 	ring_params->msi_data = (msi_group_number % msi_data_count) | ||||
| 		+ msi_data_start; | ||||
| 	ring_params->flags |= HAL_SRNG_FLAGS_MSI_INTR; | ||||
| } | ||||
| 
 | ||||
| int ath11k_dp_srng_setup(struct ath11k_base *ab, struct dp_srng *ring, | ||||
| 			 enum hal_ring_type type, int ring_num, | ||||
| 			 int mac_id, int num_entries) | ||||
| { | ||||
| 	struct hal_srng_params params = { 0 }; | ||||
| 	int entry_sz = ath11k_hal_srng_get_entrysize(type); | ||||
| 	int max_entries = ath11k_hal_srng_get_max_entries(type); | ||||
| 	int entry_sz = ath11k_hal_srng_get_entrysize(ab, type); | ||||
| 	int max_entries = ath11k_hal_srng_get_max_entries(ab, type); | ||||
| 	int ret; | ||||
| 
 | ||||
| 	if (max_entries < 0 || entry_sz < 0) | ||||
| @ -135,6 +243,7 @@ int ath11k_dp_srng_setup(struct ath11k_base *ab, struct dp_srng *ring, | ||||
| 	params.ring_base_vaddr = ring->vaddr; | ||||
| 	params.ring_base_paddr = ring->paddr; | ||||
| 	params.num_entries = num_entries; | ||||
| 	ath11k_dp_srng_msi_setup(ab, ¶ms, type, ring_num + mac_id); | ||||
| 
 | ||||
| 	switch (type) { | ||||
| 	case HAL_REO_DST: | ||||
| @ -159,7 +268,7 @@ int ath11k_dp_srng_setup(struct ath11k_base *ab, struct dp_srng *ring, | ||||
| 			break; | ||||
| 		} | ||||
| 		/* follow through when ring_num >= 3 */ | ||||
| 		/* fall through */ | ||||
| 		fallthrough; | ||||
| 	case HAL_REO_EXCEPTION: | ||||
| 	case HAL_REO_REINJECT: | ||||
| 	case HAL_REO_CMD: | ||||
| @ -367,7 +476,7 @@ static int ath11k_dp_scatter_idle_link_desc_setup(struct ath11k_base *ab, | ||||
| 	u32 end_offset; | ||||
| 
 | ||||
| 	n_entries_per_buf = HAL_WBM_IDLE_SCATTER_BUF_SIZE / | ||||
| 			    ath11k_hal_srng_get_entrysize(HAL_WBM_IDLE_LINK); | ||||
| 		ath11k_hal_srng_get_entrysize(ab, HAL_WBM_IDLE_LINK); | ||||
| 	num_scatter_buf = DIV_ROUND_UP(size, HAL_WBM_IDLE_SCATTER_BUF_SIZE); | ||||
| 
 | ||||
| 	if (num_scatter_buf > DP_IDLE_SCATTER_BUFS_MAX) | ||||
| @ -565,7 +674,7 @@ int ath11k_dp_link_desc_setup(struct ath11k_base *ab, | ||||
| 		return ret; | ||||
| 
 | ||||
| 	/* Setup link desc idle list for HW internal usage */ | ||||
| 	entry_sz = ath11k_hal_srng_get_entrysize(ring_type); | ||||
| 	entry_sz = ath11k_hal_srng_get_entrysize(ab, ring_type); | ||||
| 	tot_mem_sz = entry_sz * n_link_desc; | ||||
| 
 | ||||
| 	/* Setup scatter desc list when the total memory requirement is more */ | ||||
| @ -622,16 +731,16 @@ int ath11k_dp_service_srng(struct ath11k_base *ab, | ||||
| 	struct napi_struct *napi = &irq_grp->napi; | ||||
| 	int grp_id = irq_grp->grp_id; | ||||
| 	int work_done = 0; | ||||
| 	int i = 0; | ||||
| 	int i = 0, j; | ||||
| 	int tot_work_done = 0; | ||||
| 
 | ||||
| 	while (ath11k_tx_ring_mask[grp_id] >> i) { | ||||
| 		if (ath11k_tx_ring_mask[grp_id] & BIT(i)) | ||||
| 	while (ab->hw_params.ring_mask->tx[grp_id] >> i) { | ||||
| 		if (ab->hw_params.ring_mask->tx[grp_id] & BIT(i)) | ||||
| 			ath11k_dp_tx_completion_handler(ab, i); | ||||
| 		i++; | ||||
| 	} | ||||
| 
 | ||||
| 	if (ath11k_rx_err_ring_mask[grp_id]) { | ||||
| 	if (ab->hw_params.ring_mask->rx_err[grp_id]) { | ||||
| 		work_done = ath11k_dp_process_rx_err(ab, napi, budget); | ||||
| 		budget -= work_done; | ||||
| 		tot_work_done += work_done; | ||||
| @ -639,7 +748,7 @@ int ath11k_dp_service_srng(struct ath11k_base *ab, | ||||
| 			goto done; | ||||
| 	} | ||||
| 
 | ||||
| 	if (ath11k_rx_wbm_rel_ring_mask[grp_id]) { | ||||
| 	if (ab->hw_params.ring_mask->rx_wbm_rel[grp_id]) { | ||||
| 		work_done = ath11k_dp_rx_process_wbm_err(ab, | ||||
| 							 napi, | ||||
| 							 budget); | ||||
| @ -650,8 +759,8 @@ int ath11k_dp_service_srng(struct ath11k_base *ab, | ||||
| 			goto done; | ||||
| 	} | ||||
| 
 | ||||
| 	if (ath11k_rx_ring_mask[grp_id]) { | ||||
| 		i =  fls(ath11k_rx_ring_mask[grp_id]) - 1; | ||||
| 	if (ab->hw_params.ring_mask->rx[grp_id]) { | ||||
| 		i =  fls(ab->hw_params.ring_mask->rx[grp_id]) - 1; | ||||
| 		work_done = ath11k_dp_process_rx(ab, i, napi, | ||||
| 						 budget); | ||||
| 		budget -= work_done; | ||||
| @ -660,41 +769,52 @@ int ath11k_dp_service_srng(struct ath11k_base *ab, | ||||
| 			goto done; | ||||
| 	} | ||||
| 
 | ||||
| 	if (rx_mon_status_ring_mask[grp_id]) { | ||||
| 		for (i = 0; i <  ab->num_radios; i++) { | ||||
| 			if (rx_mon_status_ring_mask[grp_id] & BIT(i)) { | ||||
| 				work_done = | ||||
| 				ath11k_dp_rx_process_mon_rings(ab, | ||||
| 							       i, napi, | ||||
| 							       budget); | ||||
| 				budget -= work_done; | ||||
| 				tot_work_done += work_done; | ||||
| 	if (ab->hw_params.ring_mask->rx_mon_status[grp_id]) { | ||||
| 		for (i = 0; i < ab->num_radios; i++) { | ||||
| 			for (j = 0; j < ab->hw_params.num_rxmda_per_pdev; j++) { | ||||
| 				int id = i * ab->hw_params.num_rxmda_per_pdev + j; | ||||
| 
 | ||||
| 				if (ab->hw_params.ring_mask->rx_mon_status[grp_id] & | ||||
| 					BIT(id)) { | ||||
| 					work_done = | ||||
| 					ath11k_dp_rx_process_mon_rings(ab, | ||||
| 								       id, | ||||
| 								       napi, budget); | ||||
| 					budget -= work_done; | ||||
| 					tot_work_done += work_done; | ||||
| 
 | ||||
| 					if (budget <= 0) | ||||
| 						goto done; | ||||
| 				} | ||||
| 			} | ||||
| 			if (budget <= 0) | ||||
| 				goto done; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (ath11k_reo_status_ring_mask[grp_id]) | ||||
| 	if (ab->hw_params.ring_mask->reo_status[grp_id]) | ||||
| 		ath11k_dp_process_reo_status(ab); | ||||
| 
 | ||||
| 	for (i = 0; i < ab->num_radios; i++) { | ||||
| 		if (ath11k_rxdma2host_ring_mask[grp_id] & BIT(i)) { | ||||
| 			work_done = ath11k_dp_process_rxdma_err(ab, i, budget); | ||||
| 			budget -= work_done; | ||||
| 			tot_work_done += work_done; | ||||
| 		} | ||||
| 		for (j = 0; j < ab->hw_params.num_rxmda_per_pdev; j++) { | ||||
| 			int id = i * ab->hw_params.num_rxmda_per_pdev + j; | ||||
| 
 | ||||
| 		if (budget <= 0) | ||||
| 			goto done; | ||||
| 			if (ab->hw_params.ring_mask->rxdma2host[grp_id] & BIT(id)) { | ||||
| 				work_done = ath11k_dp_process_rxdma_err(ab, id, budget); | ||||
| 				budget -= work_done; | ||||
| 				tot_work_done += work_done; | ||||
| 			} | ||||
| 
 | ||||
| 		if (ath11k_host2rxdma_ring_mask[grp_id] & BIT(i)) { | ||||
| 			struct ath11k_pdev_dp *dp = &ab->pdevs[i].ar->dp; | ||||
| 			struct dp_rxdma_ring *rx_ring = &dp->rx_refill_buf_ring; | ||||
| 			if (budget <= 0) | ||||
| 				goto done; | ||||
| 
 | ||||
| 			ath11k_dp_rxbufs_replenish(ab, i, rx_ring, 0, | ||||
| 						   HAL_RX_BUF_RBM_SW3_BM, | ||||
| 						   GFP_ATOMIC); | ||||
| 			if (ab->hw_params.ring_mask->host2rxdma[grp_id] & BIT(id)) { | ||||
| 				struct ath11k *ar = ath11k_ab_to_ar(ab, id); | ||||
| 				struct ath11k_pdev_dp *dp = &ar->dp; | ||||
| 				struct dp_rxdma_ring *rx_ring = &dp->rx_refill_buf_ring; | ||||
| 
 | ||||
| 				ath11k_dp_rxbufs_replenish(ab, id, rx_ring, 0, | ||||
| 							   HAL_RX_BUF_RBM_SW3_BM, | ||||
| 							   GFP_ATOMIC); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	/* TODO: Implement handler for other interrupts */ | ||||
| @ -722,6 +842,7 @@ void ath11k_dp_pdev_pre_alloc(struct ath11k_base *ab) | ||||
| 	struct ath11k *ar; | ||||
| 	struct ath11k_pdev_dp *dp; | ||||
| 	int i; | ||||
| 	int j; | ||||
| 
 | ||||
| 	for (i = 0; i <  ab->num_radios; i++) { | ||||
| 		ar = ab->pdevs[i].ar; | ||||
| @ -731,8 +852,10 @@ void ath11k_dp_pdev_pre_alloc(struct ath11k_base *ab) | ||||
| 		spin_lock_init(&dp->rx_refill_buf_ring.idr_lock); | ||||
| 		atomic_set(&dp->num_tx_pending, 0); | ||||
| 		init_waitqueue_head(&dp->tx_empty_waitq); | ||||
| 		idr_init(&dp->rx_mon_status_refill_ring.bufs_idr); | ||||
| 		spin_lock_init(&dp->rx_mon_status_refill_ring.idr_lock); | ||||
| 		for (j = 0; j < ab->hw_params.num_rxmda_per_pdev; j++) { | ||||
| 			idr_init(&dp->rx_mon_status_refill_ring[j].bufs_idr); | ||||
| 			spin_lock_init(&dp->rx_mon_status_refill_ring[j].idr_lock); | ||||
| 		} | ||||
| 		idr_init(&dp->rxdma_mon_buf_ring.bufs_idr); | ||||
| 		spin_lock_init(&dp->rxdma_mon_buf_ring.idr_lock); | ||||
| 	} | ||||
| @ -797,13 +920,20 @@ int ath11k_dp_htt_connect(struct ath11k_dp *dp) | ||||
| 
 | ||||
| static void ath11k_dp_update_vdev_search(struct ath11k_vif *arvif) | ||||
| { | ||||
| 	 /* For STA mode, enable address search index,
 | ||||
| 	  * tcl uses ast_hash value in the descriptor. | ||||
| 	 /* When v2_map_support is true:for STA mode, enable address
 | ||||
| 	  * search index, tcl uses ast_hash value in the descriptor. | ||||
| 	  * When v2_map_support is false: for STA mode, dont' enable | ||||
| 	  * address search index. | ||||
| 	  */ | ||||
| 	switch (arvif->vdev_type) { | ||||
| 	case WMI_VDEV_TYPE_STA: | ||||
| 		arvif->hal_addr_search_flags = HAL_TX_ADDRX_EN; | ||||
| 		arvif->search_type = HAL_TX_ADDR_SEARCH_INDEX; | ||||
| 		if (arvif->ar->ab->hw_params.htt_peer_map_v2) { | ||||
| 			arvif->hal_addr_search_flags = HAL_TX_ADDRX_EN; | ||||
| 			arvif->search_type = HAL_TX_ADDR_SEARCH_INDEX; | ||||
| 		} else { | ||||
| 			arvif->hal_addr_search_flags = HAL_TX_ADDRY_EN; | ||||
| 			arvif->search_type = HAL_TX_ADDR_SEARCH_DEFAULT; | ||||
| 		} | ||||
| 		break; | ||||
| 	case WMI_VDEV_TYPE_AP: | ||||
| 	case WMI_VDEV_TYPE_IBSS: | ||||
|  | ||||
| @ -8,6 +8,8 @@ | ||||
| 
 | ||||
| #include "hal_rx.h" | ||||
| 
 | ||||
| #define MAX_RXDMA_PER_PDEV     2 | ||||
| 
 | ||||
| struct ath11k_base; | ||||
| struct ath11k_peer; | ||||
| struct ath11k_dp; | ||||
| @ -142,12 +144,13 @@ struct ath11k_pdev_dp { | ||||
| 	atomic_t num_tx_pending; | ||||
| 	wait_queue_head_t tx_empty_waitq; | ||||
| 	struct dp_rxdma_ring rx_refill_buf_ring; | ||||
| 	struct dp_srng rxdma_err_dst_ring; | ||||
| 	struct dp_srng rx_mac_buf_ring[MAX_RXDMA_PER_PDEV]; | ||||
| 	struct dp_srng rxdma_err_dst_ring[MAX_RXDMA_PER_PDEV]; | ||||
| 	struct dp_srng rxdma_mon_dst_ring; | ||||
| 	struct dp_srng rxdma_mon_desc_ring; | ||||
| 
 | ||||
| 	struct dp_rxdma_ring rxdma_mon_buf_ring; | ||||
| 	struct dp_rxdma_ring rx_mon_status_refill_ring; | ||||
| 	struct dp_rxdma_ring rx_mon_status_refill_ring[MAX_RXDMA_PER_PDEV]; | ||||
| 	struct ieee80211_rx_status rx_status; | ||||
| 	struct ath11k_mon_data mon_data; | ||||
| }; | ||||
| @ -936,11 +939,13 @@ struct htt_rx_ring_tlv_filter { | ||||
| 
 | ||||
| enum htt_t2h_msg_type { | ||||
| 	HTT_T2H_MSG_TYPE_VERSION_CONF, | ||||
| 	HTT_T2H_MSG_TYPE_PEER_MAP	= 0x3, | ||||
| 	HTT_T2H_MSG_TYPE_PEER_UNMAP	= 0x4, | ||||
| 	HTT_T2H_MSG_TYPE_RX_ADDBA	= 0x5, | ||||
| 	HTT_T2H_MSG_TYPE_PKTLOG		= 0x8, | ||||
| 	HTT_T2H_MSG_TYPE_SEC_IND	= 0xb, | ||||
| 	HTT_T2H_MSG_TYPE_PEER_MAP	= 0x1e, | ||||
| 	HTT_T2H_MSG_TYPE_PEER_UNMAP	= 0x1f, | ||||
| 	HTT_T2H_MSG_TYPE_PEER_MAP2	= 0x1e, | ||||
| 	HTT_T2H_MSG_TYPE_PEER_UNMAP2	= 0x1f, | ||||
| 	HTT_T2H_MSG_TYPE_PPDU_STATS_IND = 0x1d, | ||||
| 	HTT_T2H_MSG_TYPE_EXT_STATS_CONF = 0x1c, | ||||
| 	HTT_T2H_MSG_TYPE_BKPRESSURE_EVENT_IND = 0x24, | ||||
|  | ||||
| @ -375,7 +375,13 @@ static int ath11k_dp_rxdma_buf_ring_free(struct ath11k *ar, | ||||
| 	idr_destroy(&rx_ring->bufs_idr); | ||||
| 	spin_unlock_bh(&rx_ring->idr_lock); | ||||
| 
 | ||||
| 	rx_ring = &dp->rx_mon_status_refill_ring; | ||||
| 	/* if rxdma1_enable is false, mon_status_refill_ring
 | ||||
| 	 * isn't setup, so don't clean. | ||||
| 	 */ | ||||
| 	if (!ar->ab->hw_params.rxdma1_enable) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	rx_ring = &dp->rx_mon_status_refill_ring[0]; | ||||
| 
 | ||||
| 	spin_lock_bh(&rx_ring->idr_lock); | ||||
| 	idr_for_each_entry(&rx_ring->bufs_idr, skb, buf_id) { | ||||
| @ -390,21 +396,27 @@ static int ath11k_dp_rxdma_buf_ring_free(struct ath11k *ar, | ||||
| 
 | ||||
| 	idr_destroy(&rx_ring->bufs_idr); | ||||
| 	spin_unlock_bh(&rx_ring->idr_lock); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int ath11k_dp_rxdma_pdev_buf_free(struct ath11k *ar) | ||||
| { | ||||
| 	struct ath11k_pdev_dp *dp = &ar->dp; | ||||
| 	struct ath11k_base *ab = ar->ab; | ||||
| 	struct dp_rxdma_ring *rx_ring = &dp->rx_refill_buf_ring; | ||||
| 	int i; | ||||
| 
 | ||||
| 	ath11k_dp_rxdma_buf_ring_free(ar, rx_ring); | ||||
| 
 | ||||
| 	rx_ring = &dp->rxdma_mon_buf_ring; | ||||
| 	ath11k_dp_rxdma_buf_ring_free(ar, rx_ring); | ||||
| 
 | ||||
| 	rx_ring = &dp->rx_mon_status_refill_ring; | ||||
| 	ath11k_dp_rxdma_buf_ring_free(ar, rx_ring); | ||||
| 	for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { | ||||
| 		rx_ring = &dp->rx_mon_status_refill_ring[i]; | ||||
| 		ath11k_dp_rxdma_buf_ring_free(ar, rx_ring); | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| @ -416,7 +428,7 @@ static int ath11k_dp_rxdma_ring_buf_setup(struct ath11k *ar, | ||||
| 	int num_entries; | ||||
| 
 | ||||
| 	num_entries = rx_ring->refill_buf_ring.size / | ||||
| 		      ath11k_hal_srng_get_entrysize(ringtype); | ||||
| 		ath11k_hal_srng_get_entrysize(ar->ab, ringtype); | ||||
| 
 | ||||
| 	rx_ring->bufs_max = num_entries; | ||||
| 	ath11k_dp_rxbufs_replenish(ar->ab, dp->mac_id, rx_ring, num_entries, | ||||
| @ -427,15 +439,21 @@ static int ath11k_dp_rxdma_ring_buf_setup(struct ath11k *ar, | ||||
| static int ath11k_dp_rxdma_pdev_buf_setup(struct ath11k *ar) | ||||
| { | ||||
| 	struct ath11k_pdev_dp *dp = &ar->dp; | ||||
| 	struct ath11k_base *ab = ar->ab; | ||||
| 	struct dp_rxdma_ring *rx_ring = &dp->rx_refill_buf_ring; | ||||
| 	int i; | ||||
| 
 | ||||
| 	ath11k_dp_rxdma_ring_buf_setup(ar, rx_ring, HAL_RXDMA_BUF); | ||||
| 
 | ||||
| 	rx_ring = &dp->rxdma_mon_buf_ring; | ||||
| 	ath11k_dp_rxdma_ring_buf_setup(ar, rx_ring, HAL_RXDMA_MONITOR_BUF); | ||||
| 	if (ar->ab->hw_params.rxdma1_enable) { | ||||
| 		rx_ring = &dp->rxdma_mon_buf_ring; | ||||
| 		ath11k_dp_rxdma_ring_buf_setup(ar, rx_ring, HAL_RXDMA_MONITOR_BUF); | ||||
| 	} | ||||
| 
 | ||||
| 	rx_ring = &dp->rx_mon_status_refill_ring; | ||||
| 	ath11k_dp_rxdma_ring_buf_setup(ar, rx_ring, HAL_RXDMA_MONITOR_STATUS); | ||||
| 	for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { | ||||
| 		rx_ring = &dp->rx_mon_status_refill_ring[i]; | ||||
| 		ath11k_dp_rxdma_ring_buf_setup(ar, rx_ring, HAL_RXDMA_MONITOR_STATUS); | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| @ -443,11 +461,21 @@ static int ath11k_dp_rxdma_pdev_buf_setup(struct ath11k *ar) | ||||
| static void ath11k_dp_rx_pdev_srng_free(struct ath11k *ar) | ||||
| { | ||||
| 	struct ath11k_pdev_dp *dp = &ar->dp; | ||||
| 	struct ath11k_base *ab = ar->ab; | ||||
| 	int i; | ||||
| 
 | ||||
| 	ath11k_dp_srng_cleanup(ar->ab, &dp->rx_refill_buf_ring.refill_buf_ring); | ||||
| 	ath11k_dp_srng_cleanup(ar->ab, &dp->rxdma_err_dst_ring); | ||||
| 	ath11k_dp_srng_cleanup(ar->ab, &dp->rx_mon_status_refill_ring.refill_buf_ring); | ||||
| 	ath11k_dp_srng_cleanup(ar->ab, &dp->rxdma_mon_buf_ring.refill_buf_ring); | ||||
| 	ath11k_dp_srng_cleanup(ab, &dp->rx_refill_buf_ring.refill_buf_ring); | ||||
| 
 | ||||
| 	for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { | ||||
| 		if (ab->hw_params.rx_mac_buf_ring) | ||||
| 			ath11k_dp_srng_cleanup(ab, &dp->rx_mac_buf_ring[i]); | ||||
| 
 | ||||
| 		ath11k_dp_srng_cleanup(ab, &dp->rxdma_err_dst_ring[i]); | ||||
| 		ath11k_dp_srng_cleanup(ab, | ||||
| 				       &dp->rx_mon_status_refill_ring[i].refill_buf_ring); | ||||
| 	} | ||||
| 
 | ||||
| 	ath11k_dp_srng_cleanup(ab, &dp->rxdma_mon_buf_ring.refill_buf_ring); | ||||
| } | ||||
| 
 | ||||
| void ath11k_dp_pdev_reo_cleanup(struct ath11k_base *ab) | ||||
| @ -486,7 +514,9 @@ err_reo_cleanup: | ||||
| static int ath11k_dp_rx_pdev_srng_alloc(struct ath11k *ar) | ||||
| { | ||||
| 	struct ath11k_pdev_dp *dp = &ar->dp; | ||||
| 	struct ath11k_base *ab = ar->ab; | ||||
| 	struct dp_srng *srng = NULL; | ||||
| 	int i; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	ret = ath11k_dp_srng_setup(ar->ab, | ||||
| @ -498,24 +528,50 @@ static int ath11k_dp_rx_pdev_srng_alloc(struct ath11k *ar) | ||||
| 		return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	ret = ath11k_dp_srng_setup(ar->ab, &dp->rxdma_err_dst_ring, | ||||
| 				   HAL_RXDMA_DST, 0, dp->mac_id, | ||||
| 				   DP_RXDMA_ERR_DST_RING_SIZE); | ||||
| 	if (ret) { | ||||
| 		ath11k_warn(ar->ab, "failed to setup rxdma_err_dst_ring\n"); | ||||
| 		return ret; | ||||
| 	if (ar->ab->hw_params.rx_mac_buf_ring) { | ||||
| 		for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { | ||||
| 			ret = ath11k_dp_srng_setup(ar->ab, | ||||
| 						   &dp->rx_mac_buf_ring[i], | ||||
| 						   HAL_RXDMA_BUF, 1, | ||||
| 						   dp->mac_id + i, 1024); | ||||
| 			if (ret) { | ||||
| 				ath11k_warn(ar->ab, "failed to setup rx_mac_buf_ring %d\n", | ||||
| 					    i); | ||||
| 				return ret; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	srng = &dp->rx_mon_status_refill_ring.refill_buf_ring; | ||||
| 	ret = ath11k_dp_srng_setup(ar->ab, | ||||
| 				   srng, | ||||
| 				   HAL_RXDMA_MONITOR_STATUS, 0, dp->mac_id, | ||||
| 				   DP_RXDMA_MON_STATUS_RING_SIZE); | ||||
| 	if (ret) { | ||||
| 		ath11k_warn(ar->ab, | ||||
| 			    "failed to setup rx_mon_status_refill_ring\n"); | ||||
| 		return ret; | ||||
| 	for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { | ||||
| 		ret = ath11k_dp_srng_setup(ar->ab, &dp->rxdma_err_dst_ring[i], | ||||
| 					   HAL_RXDMA_DST, 0, dp->mac_id + i, | ||||
| 					   DP_RXDMA_ERR_DST_RING_SIZE); | ||||
| 		if (ret) { | ||||
| 			ath11k_warn(ar->ab, "failed to setup rxdma_err_dst_ring %d\n", i); | ||||
| 			return ret; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { | ||||
| 		srng = &dp->rx_mon_status_refill_ring[i].refill_buf_ring; | ||||
| 		ret = ath11k_dp_srng_setup(ar->ab, | ||||
| 					   srng, | ||||
| 					   HAL_RXDMA_MONITOR_STATUS, 0, dp->mac_id + i, | ||||
| 					   DP_RXDMA_MON_STATUS_RING_SIZE); | ||||
| 		if (ret) { | ||||
| 			ath11k_warn(ar->ab, | ||||
| 				    "failed to setup rx_mon_status_refill_ring %d\n", i); | ||||
| 			return ret; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/* if rxdma1_enable is false, then it doesn't need
 | ||||
| 	 * to setup rxdam_mon_buf_ring, rxdma_mon_dst_ring | ||||
| 	 * and rxdma_mon_desc_ring. | ||||
| 	 */ | ||||
| 	if (!ar->ab->hw_params.rxdma1_enable) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	ret = ath11k_dp_srng_setup(ar->ab, | ||||
| 				   &dp->rxdma_mon_buf_ring.refill_buf_ring, | ||||
| 				   HAL_RXDMA_MONITOR_BUF, 0, dp->mac_id, | ||||
| @ -1569,6 +1625,17 @@ void ath11k_dp_htt_htc_t2h_msg_handler(struct ath11k_base *ab, | ||||
| 		complete(&dp->htt_tgt_version_received); | ||||
| 		break; | ||||
| 	case HTT_T2H_MSG_TYPE_PEER_MAP: | ||||
| 		vdev_id = FIELD_GET(HTT_T2H_PEER_MAP_INFO_VDEV_ID, | ||||
| 				    resp->peer_map_ev.info); | ||||
| 		peer_id = FIELD_GET(HTT_T2H_PEER_MAP_INFO_PEER_ID, | ||||
| 				    resp->peer_map_ev.info); | ||||
| 		peer_mac_h16 = FIELD_GET(HTT_T2H_PEER_MAP_INFO1_MAC_ADDR_H16, | ||||
| 					 resp->peer_map_ev.info1); | ||||
| 		ath11k_dp_get_mac_addr(resp->peer_map_ev.mac_addr_l32, | ||||
| 				       peer_mac_h16, mac_addr); | ||||
| 		ath11k_peer_map_event(ab, vdev_id, peer_id, mac_addr, 0); | ||||
| 		break; | ||||
| 	case HTT_T2H_MSG_TYPE_PEER_MAP2: | ||||
| 		vdev_id = FIELD_GET(HTT_T2H_PEER_MAP_INFO_VDEV_ID, | ||||
| 				    resp->peer_map_ev.info); | ||||
| 		peer_id = FIELD_GET(HTT_T2H_PEER_MAP_INFO_PEER_ID, | ||||
| @ -1582,6 +1649,7 @@ void ath11k_dp_htt_htc_t2h_msg_handler(struct ath11k_base *ab, | ||||
| 		ath11k_peer_map_event(ab, vdev_id, peer_id, mac_addr, ast_hash); | ||||
| 		break; | ||||
| 	case HTT_T2H_MSG_TYPE_PEER_UNMAP: | ||||
| 	case HTT_T2H_MSG_TYPE_PEER_UNMAP2: | ||||
| 		peer_id = FIELD_GET(HTT_T2H_PEER_UNMAP_INFO_PEER_ID, | ||||
| 				    resp->peer_unmap_ev.info); | ||||
| 		ath11k_peer_unmap_event(ab, peer_id); | ||||
| @ -2719,20 +2787,25 @@ fail_desc_get: | ||||
| static int ath11k_dp_rx_reap_mon_status_ring(struct ath11k_base *ab, int mac_id, | ||||
| 					     int *budget, struct sk_buff_head *skb_list) | ||||
| { | ||||
| 	struct ath11k *ar = ab->pdevs[mac_id].ar; | ||||
| 	struct ath11k_pdev_dp *dp = &ar->dp; | ||||
| 	struct dp_rxdma_ring *rx_ring = &dp->rx_mon_status_refill_ring; | ||||
| 	struct ath11k *ar; | ||||
| 	struct ath11k_pdev_dp *dp; | ||||
| 	struct dp_rxdma_ring *rx_ring; | ||||
| 	struct hal_srng *srng; | ||||
| 	void *rx_mon_status_desc; | ||||
| 	struct sk_buff *skb; | ||||
| 	struct ath11k_skb_rxcb *rxcb; | ||||
| 	struct hal_tlv_hdr *tlv; | ||||
| 	u32 cookie; | ||||
| 	int buf_id; | ||||
| 	int buf_id, srng_id; | ||||
| 	dma_addr_t paddr; | ||||
| 	u8 rbm; | ||||
| 	int num_buffs_reaped = 0; | ||||
| 
 | ||||
| 	ar = ab->pdevs[ath11k_hw_mac_id_to_pdev_id(&ab->hw_params, mac_id)].ar; | ||||
| 	dp = &ar->dp; | ||||
| 	srng_id = ath11k_hw_mac_id_to_srng_id(&ab->hw_params, mac_id); | ||||
| 	rx_ring = &dp->rx_mon_status_refill_ring[srng_id]; | ||||
| 
 | ||||
| 	srng = &ab->hal.srng_list[rx_ring->refill_buf_ring.ring_id]; | ||||
| 
 | ||||
| 	spin_lock_bh(&srng->lock); | ||||
| @ -2813,7 +2886,7 @@ move_next: | ||||
| int ath11k_dp_rx_process_mon_status(struct ath11k_base *ab, int mac_id, | ||||
| 				    struct napi_struct *napi, int budget) | ||||
| { | ||||
| 	struct ath11k *ar = ab->pdevs[mac_id].ar; | ||||
| 	struct ath11k *ar = ath11k_ab_to_ar(ab, mac_id); | ||||
| 	enum hal_rx_mon_status hal_status; | ||||
| 	struct sk_buff *skb; | ||||
| 	struct sk_buff_head skb_list; | ||||
| @ -3709,8 +3782,7 @@ static bool ath11k_dp_rx_h_reo_err(struct ath11k *ar, struct sk_buff *msdu, | ||||
| 		 * instead, it is good to drop such packets in mac80211 | ||||
| 		 * after incrementing the replay counters. | ||||
| 		 */ | ||||
| 
 | ||||
| 		/* fall through */ | ||||
| 		fallthrough; | ||||
| 	default: | ||||
| 		/* TODO: Review other errors and process them to mac80211
 | ||||
| 		 * as appropriate. | ||||
| @ -3820,7 +3892,7 @@ int ath11k_dp_rx_process_wbm_err(struct ath11k_base *ab, | ||||
| 	int total_num_buffs_reaped = 0; | ||||
| 	int ret, i; | ||||
| 
 | ||||
| 	for (i = 0; i < MAX_RADIOS; i++) | ||||
| 	for (i = 0; i < ab->num_radios; i++) | ||||
| 		__skb_queue_head_init(&msdu_list[i]); | ||||
| 
 | ||||
| 	srng = &ab->hal.srng_list[dp->rx_rel_ring.ring_id]; | ||||
| @ -3923,9 +3995,9 @@ done: | ||||
| 
 | ||||
| int ath11k_dp_process_rxdma_err(struct ath11k_base *ab, int mac_id, int budget) | ||||
| { | ||||
| 	struct ath11k *ar = ab->pdevs[mac_id].ar; | ||||
| 	struct dp_srng *err_ring = &ar->dp.rxdma_err_dst_ring; | ||||
| 	struct dp_rxdma_ring *rx_ring = &ar->dp.rx_refill_buf_ring; | ||||
| 	struct ath11k *ar; | ||||
| 	struct dp_srng *err_ring; | ||||
| 	struct dp_rxdma_ring *rx_ring; | ||||
| 	struct dp_link_desc_bank *link_desc_banks = ab->dp.link_desc_banks; | ||||
| 	struct hal_srng *srng; | ||||
| 	u32 msdu_cookies[HAL_NUM_RX_MSDUS_PER_LINK_DESC]; | ||||
| @ -3944,6 +4016,11 @@ int ath11k_dp_process_rxdma_err(struct ath11k_base *ab, int mac_id, int budget) | ||||
| 	int i; | ||||
| 	int buf_id; | ||||
| 
 | ||||
| 	ar = ab->pdevs[ath11k_hw_mac_id_to_pdev_id(&ab->hw_params, mac_id)].ar; | ||||
| 	err_ring = &ar->dp.rxdma_err_dst_ring[ath11k_hw_mac_id_to_srng_id(&ab->hw_params, | ||||
| 									  mac_id)]; | ||||
| 	rx_ring = &ar->dp.rx_refill_buf_ring; | ||||
| 
 | ||||
| 	srng = &ab->hal.srng_list[err_ring->ring_id]; | ||||
| 
 | ||||
| 	spin_lock_bh(&srng->lock); | ||||
| @ -4097,6 +4174,7 @@ int ath11k_dp_rx_pdev_alloc(struct ath11k_base *ab, int mac_id) | ||||
| 	struct ath11k *ar = ab->pdevs[mac_id].ar; | ||||
| 	struct ath11k_pdev_dp *dp = &ar->dp; | ||||
| 	u32 ring_id; | ||||
| 	int i; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	ret = ath11k_dp_rx_pdev_srng_alloc(ar); | ||||
| @ -4119,14 +4197,33 @@ int ath11k_dp_rx_pdev_alloc(struct ath11k_base *ab, int mac_id) | ||||
| 		return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	ring_id = dp->rxdma_err_dst_ring.ring_id; | ||||
| 	ret = ath11k_dp_tx_htt_srng_setup(ab, ring_id, mac_id, HAL_RXDMA_DST); | ||||
| 	if (ret) { | ||||
| 		ath11k_warn(ab, "failed to configure rxdma_err_dest_ring %d\n", | ||||
| 			    ret); | ||||
| 		return ret; | ||||
| 	if (ab->hw_params.rx_mac_buf_ring) { | ||||
| 		for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { | ||||
| 			ring_id = dp->rx_mac_buf_ring[i].ring_id; | ||||
| 			ret = ath11k_dp_tx_htt_srng_setup(ab, ring_id, | ||||
| 							  mac_id + i, HAL_RXDMA_BUF); | ||||
| 			if (ret) { | ||||
| 				ath11k_warn(ab, "failed to configure rx_mac_buf_ring%d %d\n", | ||||
| 					    i, ret); | ||||
| 				return ret; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { | ||||
| 		ring_id = dp->rxdma_err_dst_ring[i].ring_id; | ||||
| 		ret = ath11k_dp_tx_htt_srng_setup(ab, ring_id, | ||||
| 						  mac_id + i, HAL_RXDMA_DST); | ||||
| 		if (ret) { | ||||
| 			ath11k_warn(ab, "failed to configure rxdma_err_dest_ring%d %d\n", | ||||
| 				    i, ret); | ||||
| 			return ret; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (!ab->hw_params.rxdma1_enable) | ||||
| 		goto config_refill_ring; | ||||
| 
 | ||||
| 	ring_id = dp->rxdma_mon_buf_ring.refill_buf_ring.ring_id; | ||||
| 	ret = ath11k_dp_tx_htt_srng_setup(ab, ring_id, | ||||
| 					  mac_id, HAL_RXDMA_MONITOR_BUF); | ||||
| @ -4151,15 +4248,20 @@ int ath11k_dp_rx_pdev_alloc(struct ath11k_base *ab, int mac_id) | ||||
| 			    ret); | ||||
| 		return ret; | ||||
| 	} | ||||
| 	ring_id = dp->rx_mon_status_refill_ring.refill_buf_ring.ring_id; | ||||
| 	ret = ath11k_dp_tx_htt_srng_setup(ab, ring_id, mac_id, | ||||
| 					  HAL_RXDMA_MONITOR_STATUS); | ||||
| 	if (ret) { | ||||
| 		ath11k_warn(ab, | ||||
| 			    "failed to configure mon_status_refill_ring %d\n", | ||||
| 			    ret); | ||||
| 		return ret; | ||||
| 
 | ||||
| config_refill_ring: | ||||
| 	for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { | ||||
| 		ring_id = dp->rx_mon_status_refill_ring[i].refill_buf_ring.ring_id; | ||||
| 		ret = ath11k_dp_tx_htt_srng_setup(ab, ring_id, mac_id + i, | ||||
| 						  HAL_RXDMA_MONITOR_STATUS); | ||||
| 		if (ret) { | ||||
| 			ath11k_warn(ab, | ||||
| 				    "failed to configure mon_status_refill_ring%d %d\n", | ||||
| 				    i, ret); | ||||
| 			return ret; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| @ -4777,7 +4879,7 @@ static void ath11k_dp_rx_mon_status_process_tlv(struct ath11k *ar, | ||||
| static int ath11k_dp_mon_process_rx(struct ath11k_base *ab, int mac_id, | ||||
| 				    struct napi_struct *napi, int budget) | ||||
| { | ||||
| 	struct ath11k *ar = ab->pdevs[mac_id].ar; | ||||
| 	struct ath11k *ar = ath11k_ab_to_ar(ab, mac_id); | ||||
| 	struct ath11k_pdev_dp *dp = &ar->dp; | ||||
| 	struct ath11k_mon_data *pmon = (struct ath11k_mon_data *)&dp->mon_data; | ||||
| 	int num_buffs_reaped = 0; | ||||
| @ -4793,7 +4895,7 @@ static int ath11k_dp_mon_process_rx(struct ath11k_base *ab, int mac_id, | ||||
| int ath11k_dp_rx_process_mon_rings(struct ath11k_base *ab, int mac_id, | ||||
| 				   struct napi_struct *napi, int budget) | ||||
| { | ||||
| 	struct ath11k *ar = ab->pdevs[mac_id].ar; | ||||
| 	struct ath11k *ar = ath11k_ab_to_ar(ab, mac_id); | ||||
| 	int ret = 0; | ||||
| 
 | ||||
| 	if (test_bit(ATH11K_FLAG_MONITOR_ENABLED, &ar->monitor_flags)) | ||||
| @ -4832,9 +4934,15 @@ int ath11k_dp_rx_pdev_mon_attach(struct ath11k *ar) | ||||
| 		return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	/* if rxdma1_enable is false, no need to setup
 | ||||
| 	 * rxdma_mon_desc_ring. | ||||
| 	 */ | ||||
| 	if (!ar->ab->hw_params.rxdma1_enable) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	dp_srng = &dp->rxdma_mon_desc_ring; | ||||
| 	n_link_desc = dp_srng->size / | ||||
| 		ath11k_hal_srng_get_entrysize(HAL_RXDMA_MONITOR_DESC); | ||||
| 		ath11k_hal_srng_get_entrysize(ar->ab, HAL_RXDMA_MONITOR_DESC); | ||||
| 	mon_desc_srng = | ||||
| 		&ar->ab->hal.srng_list[dp->rxdma_mon_desc_ring.ring_id]; | ||||
| 
 | ||||
| @ -4848,6 +4956,7 @@ int ath11k_dp_rx_pdev_mon_attach(struct ath11k *ar) | ||||
| 	pmon->mon_last_linkdesc_paddr = 0; | ||||
| 	pmon->mon_last_buf_cookie = DP_RX_DESC_COOKIE_MAX + 1; | ||||
| 	spin_lock_init(&pmon->mon_lock); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -110,7 +110,12 @@ int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif, | ||||
| 
 | ||||
| tcl_ring_sel: | ||||
| 	tcl_ring_retry = false; | ||||
| 	ti.ring_id = ring_selector % DP_TCL_NUM_RING_MAX; | ||||
| 	/* For some chip, it can only use tcl0 to tx */ | ||||
| 	if (ar->ab->hw_params.tcl_0_only) | ||||
| 		ti.ring_id = 0; | ||||
| 	else | ||||
| 		ti.ring_id = ring_selector % DP_TCL_NUM_RING_MAX; | ||||
| 
 | ||||
| 	ring_map |= BIT(ti.ring_id); | ||||
| 
 | ||||
| 	tx_ring = &dp->tx_ring[ti.ring_id]; | ||||
| @ -221,7 +226,8 @@ tcl_ring_sel: | ||||
| 		 * checking this ring earlier for each pkt tx. | ||||
| 		 * Restart ring selection if some rings are not checked yet. | ||||
| 		 */ | ||||
| 		if (ring_map != (BIT(DP_TCL_NUM_RING_MAX) - 1)) { | ||||
| 		if (ring_map != (BIT(DP_TCL_NUM_RING_MAX) - 1) && | ||||
| 		    !ar->ab->hw_params.tcl_0_only) { | ||||
| 			tcl_ring_retry = true; | ||||
| 			ring_selector++; | ||||
| 		} | ||||
| @ -633,14 +639,28 @@ ath11k_dp_tx_get_ring_id_type(struct ath11k_base *ab, | ||||
| 	switch (ring_type) { | ||||
| 	case HAL_RXDMA_BUF: | ||||
| 		lmac_ring_id_offset = mac_id * HAL_SRNG_RINGS_PER_LMAC; | ||||
| 		if (!(ring_id == (HAL_SRNG_RING_ID_WMAC1_SW2RXDMA0_BUF + | ||||
| 				  lmac_ring_id_offset) || | ||||
| 		    ring_id == (HAL_SRNG_RING_ID_WMAC1_SW2RXDMA1_BUF + | ||||
| 				lmac_ring_id_offset))) { | ||||
| 			ret = -EINVAL; | ||||
| 
 | ||||
| 		/* for QCA6390, host fills rx buffer to fw and fw fills to
 | ||||
| 		 * rxbuf ring for each rxdma | ||||
| 		 */ | ||||
| 		if (!ab->hw_params.rx_mac_buf_ring) { | ||||
| 			if (!(ring_id == (HAL_SRNG_RING_ID_WMAC1_SW2RXDMA0_BUF + | ||||
| 					  lmac_ring_id_offset) || | ||||
| 				ring_id == (HAL_SRNG_RING_ID_WMAC1_SW2RXDMA1_BUF + | ||||
| 					lmac_ring_id_offset))) { | ||||
| 				ret = -EINVAL; | ||||
| 			} | ||||
| 			*htt_ring_id = HTT_RXDMA_HOST_BUF_RING; | ||||
| 			*htt_ring_type = HTT_SW_TO_HW_RING; | ||||
| 		} else { | ||||
| 			if (ring_id == HAL_SRNG_RING_ID_WMAC1_SW2RXDMA0_BUF) { | ||||
| 				*htt_ring_id = HTT_HOST1_TO_FW_RXBUF_RING; | ||||
| 				*htt_ring_type = HTT_SW_TO_SW_RING; | ||||
| 			} else { | ||||
| 				*htt_ring_id = HTT_RXDMA_HOST_BUF_RING; | ||||
| 				*htt_ring_type = HTT_SW_TO_HW_RING; | ||||
| 			} | ||||
| 		} | ||||
| 		*htt_ring_id = HTT_RXDMA_HOST_BUF_RING; | ||||
| 		*htt_ring_type = HTT_SW_TO_HW_RING; | ||||
| 		break; | ||||
| 	case HAL_RXDMA_DST: | ||||
| 		*htt_ring_id = HTT_RXDMA_NON_MONITOR_DEST_RING; | ||||
| @ -720,7 +740,7 @@ int ath11k_dp_tx_htt_srng_setup(struct ath11k_base *ab, u32 ring_id, | ||||
| 	cmd->ring_base_addr_hi = (u64)params.ring_base_paddr >> | ||||
| 				 HAL_ADDR_MSB_REG_SHIFT; | ||||
| 
 | ||||
| 	ret = ath11k_hal_srng_get_entrysize(ring_type); | ||||
| 	ret = ath11k_hal_srng_get_entrysize(ab, ring_type); | ||||
| 	if (ret < 0) | ||||
| 		goto err_free; | ||||
| 
 | ||||
| @ -968,8 +988,9 @@ ath11k_dp_tx_htt_h2t_ext_stats_req(struct ath11k *ar, u8 type, | ||||
| int ath11k_dp_tx_htt_monitor_mode_ring_config(struct ath11k *ar, bool reset) | ||||
| { | ||||
| 	struct ath11k_pdev_dp *dp = &ar->dp; | ||||
| 	struct ath11k_base *ab = ar->ab; | ||||
| 	struct htt_rx_ring_tlv_filter tlv_filter = {0}; | ||||
| 	int ret = 0, ring_id = 0; | ||||
| 	int ret = 0, ring_id = 0, i; | ||||
| 
 | ||||
| 	ring_id = dp->rxdma_mon_buf_ring.refill_buf_ring.ring_id; | ||||
| 
 | ||||
| @ -998,16 +1019,20 @@ int ath11k_dp_tx_htt_monitor_mode_ring_config(struct ath11k *ar, bool reset) | ||||
| 	if (ret) | ||||
| 		return ret; | ||||
| 
 | ||||
| 	ring_id = dp->rx_mon_status_refill_ring.refill_buf_ring.ring_id; | ||||
| 	if (!reset) | ||||
| 		tlv_filter.rx_filter = | ||||
| 				HTT_RX_MON_FILTER_TLV_FLAGS_MON_STATUS_RING; | ||||
| 	else | ||||
| 		tlv_filter = ath11k_mac_mon_status_filter_default; | ||||
| 	for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { | ||||
| 		ring_id = dp->rx_mon_status_refill_ring[i].refill_buf_ring.ring_id; | ||||
| 		if (!reset) | ||||
| 			tlv_filter.rx_filter = | ||||
| 					HTT_RX_MON_FILTER_TLV_FLAGS_MON_STATUS_RING; | ||||
| 		else | ||||
| 			tlv_filter = ath11k_mac_mon_status_filter_default; | ||||
| 
 | ||||
| 		ret = ath11k_dp_tx_htt_rx_filter_setup(ab, ring_id, | ||||
| 						       dp->mac_id + i, | ||||
| 						       HAL_RXDMA_MONITOR_STATUS, | ||||
| 						       DP_RXDMA_REFILL_RING_SIZE, | ||||
| 						       &tlv_filter); | ||||
| 	} | ||||
| 
 | ||||
| 	ret = ath11k_dp_tx_htt_rx_filter_setup(ar->ab, ring_id, dp->mac_id, | ||||
| 					       HAL_RXDMA_MONITOR_STATUS, | ||||
| 					       DP_RXDMA_REFILL_RING_SIZE, | ||||
| 					       &tlv_filter); | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| @ -8,7 +8,7 @@ | ||||
| #include "hal_desc.h" | ||||
| #include "hif.h" | ||||
| 
 | ||||
| static const struct hal_srng_config hw_srng_config[] = { | ||||
| static const struct hal_srng_config hw_srng_config_template[] = { | ||||
| 	/* TODO: max_rings can populated by querying HW capabilities */ | ||||
| 	{ /* REO_DST */ | ||||
| 		.start_ring_id = HAL_SRNG_RING_ID_REO2SW1, | ||||
| @ -16,14 +16,6 @@ static const struct hal_srng_config hw_srng_config[] = { | ||||
| 		.entry_size = sizeof(struct hal_reo_dest_ring) >> 2, | ||||
| 		.lmac_ring = false, | ||||
| 		.ring_dir = HAL_SRNG_DIR_DST, | ||||
| 		.reg_start = { | ||||
| 			HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO1_RING_BASE_LSB, | ||||
| 			HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO1_RING_HP, | ||||
| 		}, | ||||
| 		.reg_size = { | ||||
| 			HAL_REO2_RING_BASE_LSB - HAL_REO1_RING_BASE_LSB, | ||||
| 			HAL_REO2_RING_HP - HAL_REO1_RING_HP, | ||||
| 		}, | ||||
| 		.max_size = HAL_REO_REO2SW1_RING_BASE_MSB_RING_SIZE, | ||||
| 	}, | ||||
| 	{ /* REO_EXCEPTION */ | ||||
| @ -36,10 +28,6 @@ static const struct hal_srng_config hw_srng_config[] = { | ||||
| 		.entry_size = sizeof(struct hal_reo_dest_ring) >> 2, | ||||
| 		.lmac_ring = false, | ||||
| 		.ring_dir = HAL_SRNG_DIR_DST, | ||||
| 		.reg_start = { | ||||
| 			HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO_TCL_RING_BASE_LSB, | ||||
| 			HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO_TCL_RING_HP, | ||||
| 		}, | ||||
| 		.max_size = HAL_REO_REO2TCL_RING_BASE_MSB_RING_SIZE, | ||||
| 	}, | ||||
| 	{ /* REO_REINJECT */ | ||||
| @ -48,10 +36,6 @@ static const struct hal_srng_config hw_srng_config[] = { | ||||
| 		.entry_size = sizeof(struct hal_reo_entrance_ring) >> 2, | ||||
| 		.lmac_ring = false, | ||||
| 		.ring_dir = HAL_SRNG_DIR_SRC, | ||||
| 		.reg_start = { | ||||
| 			HAL_SEQ_WCSS_UMAC_REO_REG + HAL_SW2REO_RING_BASE_LSB, | ||||
| 			HAL_SEQ_WCSS_UMAC_REO_REG + HAL_SW2REO_RING_HP, | ||||
| 		}, | ||||
| 		.max_size = HAL_REO_SW2REO_RING_BASE_MSB_RING_SIZE, | ||||
| 	}, | ||||
| 	{ /* REO_CMD */ | ||||
| @ -61,10 +45,6 @@ static const struct hal_srng_config hw_srng_config[] = { | ||||
| 			sizeof(struct hal_reo_get_queue_stats)) >> 2, | ||||
| 		.lmac_ring = false, | ||||
| 		.ring_dir = HAL_SRNG_DIR_SRC, | ||||
| 		.reg_start = { | ||||
| 			HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO_CMD_RING_BASE_LSB, | ||||
| 			HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO_CMD_HP, | ||||
| 		}, | ||||
| 		.max_size = HAL_REO_CMD_RING_BASE_MSB_RING_SIZE, | ||||
| 	}, | ||||
| 	{ /* REO_STATUS */ | ||||
| @ -74,11 +54,6 @@ static const struct hal_srng_config hw_srng_config[] = { | ||||
| 			sizeof(struct hal_reo_get_queue_stats_status)) >> 2, | ||||
| 		.lmac_ring = false, | ||||
| 		.ring_dir = HAL_SRNG_DIR_DST, | ||||
| 		.reg_start = { | ||||
| 			HAL_SEQ_WCSS_UMAC_REO_REG + | ||||
| 				HAL_REO_STATUS_RING_BASE_LSB, | ||||
| 			HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO_STATUS_HP, | ||||
| 		}, | ||||
| 		.max_size = HAL_REO_STATUS_RING_BASE_MSB_RING_SIZE, | ||||
| 	}, | ||||
| 	{ /* TCL_DATA */ | ||||
| @ -88,14 +63,6 @@ static const struct hal_srng_config hw_srng_config[] = { | ||||
| 			     sizeof(struct hal_tcl_data_cmd)) >> 2, | ||||
| 		.lmac_ring = false, | ||||
| 		.ring_dir = HAL_SRNG_DIR_SRC, | ||||
| 		.reg_start = { | ||||
| 			HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL1_RING_BASE_LSB, | ||||
| 			HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL1_RING_HP, | ||||
| 		}, | ||||
| 		.reg_size = { | ||||
| 			HAL_TCL2_RING_BASE_LSB - HAL_TCL1_RING_BASE_LSB, | ||||
| 			HAL_TCL2_RING_HP - HAL_TCL1_RING_HP, | ||||
| 		}, | ||||
| 		.max_size = HAL_SW2TCL1_RING_BASE_MSB_RING_SIZE, | ||||
| 	}, | ||||
| 	{ /* TCL_CMD */ | ||||
| @ -105,10 +72,6 @@ static const struct hal_srng_config hw_srng_config[] = { | ||||
| 			     sizeof(struct hal_tcl_gse_cmd)) >> 2, | ||||
| 		.lmac_ring =  false, | ||||
| 		.ring_dir = HAL_SRNG_DIR_SRC, | ||||
| 		.reg_start = { | ||||
| 			HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL_RING_BASE_LSB, | ||||
| 			HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL_RING_HP, | ||||
| 		}, | ||||
| 		.max_size = HAL_SW2TCL1_CMD_RING_BASE_MSB_RING_SIZE, | ||||
| 	}, | ||||
| 	{ /* TCL_STATUS */ | ||||
| @ -118,11 +81,6 @@ static const struct hal_srng_config hw_srng_config[] = { | ||||
| 			     sizeof(struct hal_tcl_status_ring)) >> 2, | ||||
| 		.lmac_ring = false, | ||||
| 		.ring_dir = HAL_SRNG_DIR_DST, | ||||
| 		.reg_start = { | ||||
| 			HAL_SEQ_WCSS_UMAC_TCL_REG + | ||||
| 				HAL_TCL_STATUS_RING_BASE_LSB, | ||||
| 			HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL_STATUS_RING_HP, | ||||
| 		}, | ||||
| 		.max_size = HAL_TCL_STATUS_RING_BASE_MSB_RING_SIZE, | ||||
| 	}, | ||||
| 	{ /* CE_SRC */ | ||||
| @ -344,7 +302,7 @@ static void ath11k_hal_free_cont_wrp(struct ath11k_base *ab) | ||||
| static void ath11k_hal_ce_dst_setup(struct ath11k_base *ab, | ||||
| 				    struct hal_srng *srng, int ring_num) | ||||
| { | ||||
| 	const struct hal_srng_config *srng_config = &hw_srng_config[HAL_CE_DST]; | ||||
| 	struct hal_srng_config *srng_config = &ab->hal.srng_config[HAL_CE_DST]; | ||||
| 	u32 addr; | ||||
| 	u32 val; | ||||
| 
 | ||||
| @ -371,7 +329,7 @@ static void ath11k_hal_srng_dst_hw_init(struct ath11k_base *ab, | ||||
| 
 | ||||
| 	if (srng->flags & HAL_SRNG_FLAGS_MSI_INTR) { | ||||
| 		ath11k_hif_write32(ab, reg_base + | ||||
| 				   HAL_REO1_RING_MSI1_BASE_LSB_OFFSET, | ||||
| 				   HAL_REO1_RING_MSI1_BASE_LSB_OFFSET(ab), | ||||
| 				   (u32)srng->msi_addr); | ||||
| 
 | ||||
| 		val = FIELD_PREP(HAL_REO1_RING_MSI1_BASE_MSB_ADDR, | ||||
| @ -379,10 +337,10 @@ static void ath11k_hal_srng_dst_hw_init(struct ath11k_base *ab, | ||||
| 				  HAL_ADDR_MSB_REG_SHIFT)) | | ||||
| 		      HAL_REO1_RING_MSI1_BASE_MSB_MSI1_ENABLE; | ||||
| 		ath11k_hif_write32(ab, reg_base + | ||||
| 				       HAL_REO1_RING_MSI1_BASE_MSB_OFFSET, val); | ||||
| 				       HAL_REO1_RING_MSI1_BASE_MSB_OFFSET(ab), val); | ||||
| 
 | ||||
| 		ath11k_hif_write32(ab, | ||||
| 				   reg_base + HAL_REO1_RING_MSI1_DATA_OFFSET, | ||||
| 				   reg_base + HAL_REO1_RING_MSI1_DATA_OFFSET(ab), | ||||
| 				   srng->msi_data); | ||||
| 	} | ||||
| 
 | ||||
| @ -393,11 +351,11 @@ static void ath11k_hal_srng_dst_hw_init(struct ath11k_base *ab, | ||||
| 			  HAL_ADDR_MSB_REG_SHIFT)) | | ||||
| 	      FIELD_PREP(HAL_REO1_RING_BASE_MSB_RING_SIZE, | ||||
| 			 (srng->entry_size * srng->num_entries)); | ||||
| 	ath11k_hif_write32(ab, reg_base + HAL_REO1_RING_BASE_MSB_OFFSET, val); | ||||
| 	ath11k_hif_write32(ab, reg_base + HAL_REO1_RING_BASE_MSB_OFFSET(ab), val); | ||||
| 
 | ||||
| 	val = FIELD_PREP(HAL_REO1_RING_ID_RING_ID, srng->ring_id) | | ||||
| 	      FIELD_PREP(HAL_REO1_RING_ID_ENTRY_SIZE, srng->entry_size); | ||||
| 	ath11k_hif_write32(ab, reg_base + HAL_REO1_RING_ID_OFFSET, val); | ||||
| 	ath11k_hif_write32(ab, reg_base + HAL_REO1_RING_ID_OFFSET(ab), val); | ||||
| 
 | ||||
| 	/* interrupt setup */ | ||||
| 	val = FIELD_PREP(HAL_REO1_RING_PRDR_INT_SETUP_INTR_TMR_THOLD, | ||||
| @ -408,21 +366,21 @@ static void ath11k_hal_srng_dst_hw_init(struct ath11k_base *ab, | ||||
| 			   srng->entry_size)); | ||||
| 
 | ||||
| 	ath11k_hif_write32(ab, | ||||
| 			   reg_base + HAL_REO1_RING_PRODUCER_INT_SETUP_OFFSET, | ||||
| 			   reg_base + HAL_REO1_RING_PRODUCER_INT_SETUP_OFFSET(ab), | ||||
| 			   val); | ||||
| 
 | ||||
| 	hp_addr = hal->rdp.paddr + | ||||
| 		  ((unsigned long)srng->u.dst_ring.hp_addr - | ||||
| 		   (unsigned long)hal->rdp.vaddr); | ||||
| 	ath11k_hif_write32(ab, reg_base + HAL_REO1_RING_HP_ADDR_LSB_OFFSET, | ||||
| 	ath11k_hif_write32(ab, reg_base + HAL_REO1_RING_HP_ADDR_LSB_OFFSET(ab), | ||||
| 			   hp_addr & HAL_ADDR_LSB_REG_MASK); | ||||
| 	ath11k_hif_write32(ab, reg_base + HAL_REO1_RING_HP_ADDR_MSB_OFFSET, | ||||
| 	ath11k_hif_write32(ab, reg_base + HAL_REO1_RING_HP_ADDR_MSB_OFFSET(ab), | ||||
| 			   hp_addr >> HAL_ADDR_MSB_REG_SHIFT); | ||||
| 
 | ||||
| 	/* Initialize head and tail pointers to indicate ring is empty */ | ||||
| 	reg_base = srng->hwreg_base[HAL_SRNG_REG_GRP_R2]; | ||||
| 	ath11k_hif_write32(ab, reg_base, 0); | ||||
| 	ath11k_hif_write32(ab, reg_base + HAL_REO1_RING_TP_OFFSET, 0); | ||||
| 	ath11k_hif_write32(ab, reg_base + HAL_REO1_RING_TP_OFFSET(ab), 0); | ||||
| 	*srng->u.dst_ring.hp_addr = 0; | ||||
| 
 | ||||
| 	reg_base = srng->hwreg_base[HAL_SRNG_REG_GRP_R0]; | ||||
| @ -435,7 +393,7 @@ static void ath11k_hal_srng_dst_hw_init(struct ath11k_base *ab, | ||||
| 		val |= HAL_REO1_RING_MISC_MSI_SWAP; | ||||
| 	val |= HAL_REO1_RING_MISC_SRNG_ENABLE; | ||||
| 
 | ||||
| 	ath11k_hif_write32(ab, reg_base + HAL_REO1_RING_MISC_OFFSET, val); | ||||
| 	ath11k_hif_write32(ab, reg_base + HAL_REO1_RING_MISC_OFFSET(ab), val); | ||||
| } | ||||
| 
 | ||||
| static void ath11k_hal_srng_src_hw_init(struct ath11k_base *ab, | ||||
| @ -450,7 +408,7 @@ static void ath11k_hal_srng_src_hw_init(struct ath11k_base *ab, | ||||
| 
 | ||||
| 	if (srng->flags & HAL_SRNG_FLAGS_MSI_INTR) { | ||||
| 		ath11k_hif_write32(ab, reg_base + | ||||
| 				    HAL_TCL1_RING_MSI1_BASE_LSB_OFFSET, | ||||
| 				   HAL_TCL1_RING_MSI1_BASE_LSB_OFFSET(ab), | ||||
| 				   (u32)srng->msi_addr); | ||||
| 
 | ||||
| 		val = FIELD_PREP(HAL_TCL1_RING_MSI1_BASE_MSB_ADDR, | ||||
| @ -458,11 +416,11 @@ static void ath11k_hal_srng_src_hw_init(struct ath11k_base *ab, | ||||
| 				  HAL_ADDR_MSB_REG_SHIFT)) | | ||||
| 		      HAL_TCL1_RING_MSI1_BASE_MSB_MSI1_ENABLE; | ||||
| 		ath11k_hif_write32(ab, reg_base + | ||||
| 				       HAL_TCL1_RING_MSI1_BASE_MSB_OFFSET, | ||||
| 				       HAL_TCL1_RING_MSI1_BASE_MSB_OFFSET(ab), | ||||
| 				   val); | ||||
| 
 | ||||
| 		ath11k_hif_write32(ab, reg_base + | ||||
| 				       HAL_TCL1_RING_MSI1_DATA_OFFSET, | ||||
| 				       HAL_TCL1_RING_MSI1_DATA_OFFSET(ab), | ||||
| 				   srng->msi_data); | ||||
| 	} | ||||
| 
 | ||||
| @ -473,10 +431,10 @@ static void ath11k_hal_srng_src_hw_init(struct ath11k_base *ab, | ||||
| 			  HAL_ADDR_MSB_REG_SHIFT)) | | ||||
| 	      FIELD_PREP(HAL_TCL1_RING_BASE_MSB_RING_SIZE, | ||||
| 			 (srng->entry_size * srng->num_entries)); | ||||
| 	ath11k_hif_write32(ab, reg_base + HAL_TCL1_RING_BASE_MSB_OFFSET, val); | ||||
| 	ath11k_hif_write32(ab, reg_base + HAL_TCL1_RING_BASE_MSB_OFFSET(ab), val); | ||||
| 
 | ||||
| 	val = FIELD_PREP(HAL_REO1_RING_ID_ENTRY_SIZE, srng->entry_size); | ||||
| 	ath11k_hif_write32(ab, reg_base + HAL_TCL1_RING_ID_OFFSET, val); | ||||
| 	ath11k_hif_write32(ab, reg_base + HAL_TCL1_RING_ID_OFFSET(ab), val); | ||||
| 
 | ||||
| 	/* interrupt setup */ | ||||
| 	/* NOTE: IPQ8074 v2 requires the interrupt timer threshold in the
 | ||||
| @ -490,7 +448,7 @@ static void ath11k_hal_srng_src_hw_init(struct ath11k_base *ab, | ||||
| 			   srng->entry_size)); | ||||
| 
 | ||||
| 	ath11k_hif_write32(ab, | ||||
| 			   reg_base + HAL_TCL1_RING_CONSR_INT_SETUP_IX0_OFFSET, | ||||
| 			   reg_base + HAL_TCL1_RING_CONSR_INT_SETUP_IX0_OFFSET(ab), | ||||
| 			   val); | ||||
| 
 | ||||
| 	val = 0; | ||||
| @ -499,7 +457,7 @@ static void ath11k_hal_srng_src_hw_init(struct ath11k_base *ab, | ||||
| 				  srng->u.src_ring.low_threshold); | ||||
| 	} | ||||
| 	ath11k_hif_write32(ab, | ||||
| 			   reg_base + HAL_TCL1_RING_CONSR_INT_SETUP_IX1_OFFSET, | ||||
| 			   reg_base + HAL_TCL1_RING_CONSR_INT_SETUP_IX1_OFFSET(ab), | ||||
| 			   val); | ||||
| 
 | ||||
| 	if (srng->ring_id != HAL_SRNG_RING_ID_WBM_IDLE_LINK) { | ||||
| @ -507,10 +465,10 @@ static void ath11k_hal_srng_src_hw_init(struct ath11k_base *ab, | ||||
| 			  ((unsigned long)srng->u.src_ring.tp_addr - | ||||
| 			   (unsigned long)hal->rdp.vaddr); | ||||
| 		ath11k_hif_write32(ab, | ||||
| 				   reg_base + HAL_TCL1_RING_TP_ADDR_LSB_OFFSET, | ||||
| 				   reg_base + HAL_TCL1_RING_TP_ADDR_LSB_OFFSET(ab), | ||||
| 				   tp_addr & HAL_ADDR_LSB_REG_MASK); | ||||
| 		ath11k_hif_write32(ab, | ||||
| 				   reg_base + HAL_TCL1_RING_TP_ADDR_MSB_OFFSET, | ||||
| 				   reg_base + HAL_TCL1_RING_TP_ADDR_MSB_OFFSET(ab), | ||||
| 				   tp_addr >> HAL_ADDR_MSB_REG_SHIFT); | ||||
| 	} | ||||
| 
 | ||||
| @ -534,7 +492,7 @@ static void ath11k_hal_srng_src_hw_init(struct ath11k_base *ab, | ||||
| 
 | ||||
| 	val |= HAL_TCL1_RING_MISC_SRNG_ENABLE; | ||||
| 
 | ||||
| 	ath11k_hif_write32(ab, reg_base + HAL_TCL1_RING_MISC_OFFSET, val); | ||||
| 	ath11k_hif_write32(ab, reg_base + HAL_TCL1_RING_MISC_OFFSET(ab), val); | ||||
| } | ||||
| 
 | ||||
| static void ath11k_hal_srng_hw_init(struct ath11k_base *ab, | ||||
| @ -550,7 +508,7 @@ static int ath11k_hal_srng_get_ring_id(struct ath11k_base *ab, | ||||
| 				       enum hal_ring_type type, | ||||
| 				       int ring_num, int mac_id) | ||||
| { | ||||
| 	const struct hal_srng_config *srng_config = &hw_srng_config[type]; | ||||
| 	struct hal_srng_config *srng_config = &ab->hal.srng_config[type]; | ||||
| 	int ring_id; | ||||
| 
 | ||||
| 	if (ring_num >= srng_config->max_rings) { | ||||
| @ -568,26 +526,26 @@ static int ath11k_hal_srng_get_ring_id(struct ath11k_base *ab, | ||||
| 	return ring_id; | ||||
| } | ||||
| 
 | ||||
| int ath11k_hal_srng_get_entrysize(u32 ring_type) | ||||
| int ath11k_hal_srng_get_entrysize(struct ath11k_base *ab, u32 ring_type) | ||||
| { | ||||
| 	const struct hal_srng_config *srng_config; | ||||
| 	struct hal_srng_config *srng_config; | ||||
| 
 | ||||
| 	if (WARN_ON(ring_type >= HAL_MAX_RING_TYPES)) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	srng_config = &hw_srng_config[ring_type]; | ||||
| 	srng_config = &ab->hal.srng_config[ring_type]; | ||||
| 
 | ||||
| 	return (srng_config->entry_size << 2); | ||||
| } | ||||
| 
 | ||||
| int ath11k_hal_srng_get_max_entries(u32 ring_type) | ||||
| int ath11k_hal_srng_get_max_entries(struct ath11k_base *ab, u32 ring_type) | ||||
| { | ||||
| 	const struct hal_srng_config *srng_config; | ||||
| 	struct hal_srng_config *srng_config; | ||||
| 
 | ||||
| 	if (WARN_ON(ring_type >= HAL_MAX_RING_TYPES)) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	srng_config = &hw_srng_config[ring_type]; | ||||
| 	srng_config = &ab->hal.srng_config[ring_type]; | ||||
| 
 | ||||
| 	return (srng_config->max_size / srng_config->entry_size); | ||||
| } | ||||
| @ -1003,7 +961,7 @@ int ath11k_hal_srng_setup(struct ath11k_base *ab, enum hal_ring_type type, | ||||
| 			  struct hal_srng_params *params) | ||||
| { | ||||
| 	struct ath11k_hal *hal = &ab->hal; | ||||
| 	const struct hal_srng_config *srng_config = &hw_srng_config[type]; | ||||
| 	struct hal_srng_config *srng_config = &ab->hal.srng_config[type]; | ||||
| 	struct hal_srng *srng; | ||||
| 	int ring_id; | ||||
| 	u32 lmac_idx; | ||||
| @ -1027,6 +985,8 @@ int ath11k_hal_srng_setup(struct ath11k_base *ab, enum hal_ring_type type, | ||||
| 				params->intr_batch_cntr_thres_entries; | ||||
| 	srng->intr_timer_thres_us = params->intr_timer_thres_us; | ||||
| 	srng->flags = params->flags; | ||||
| 	srng->msi_addr = params->msi_addr; | ||||
| 	srng->msi_data = params->msi_data; | ||||
| 	srng->initialized = 1; | ||||
| 	spin_lock_init(&srng->lock); | ||||
| 
 | ||||
| @ -1085,7 +1045,7 @@ int ath11k_hal_srng_setup(struct ath11k_base *ab, enum hal_ring_type type, | ||||
| 		} else { | ||||
| 			srng->u.dst_ring.tp_addr = | ||||
| 				(u32 *)((unsigned long)ab->mem + reg_base + | ||||
| 					(HAL_REO1_RING_TP - HAL_REO1_RING_HP)); | ||||
| 					(HAL_REO1_RING_TP(ab) - HAL_REO1_RING_HP(ab))); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| @ -1102,6 +1062,56 @@ int ath11k_hal_srng_setup(struct ath11k_base *ab, enum hal_ring_type type, | ||||
| 	return ring_id; | ||||
| } | ||||
| 
 | ||||
| static int ath11k_hal_srng_create_config(struct ath11k_base *ab) | ||||
| { | ||||
| 	struct ath11k_hal *hal = &ab->hal; | ||||
| 	struct hal_srng_config *s; | ||||
| 
 | ||||
| 	hal->srng_config = kmemdup(hw_srng_config_template, | ||||
| 				   sizeof(hw_srng_config_template), | ||||
| 				   GFP_KERNEL); | ||||
| 	if (!hal->srng_config) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	s = &hal->srng_config[HAL_REO_DST]; | ||||
| 	s->reg_start[0] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO1_RING_BASE_LSB(ab); | ||||
| 	s->reg_start[1] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO1_RING_HP(ab); | ||||
| 	s->reg_size[0] = HAL_REO2_RING_BASE_LSB(ab) - HAL_REO1_RING_BASE_LSB(ab); | ||||
| 	s->reg_size[1] = HAL_REO2_RING_HP(ab) - HAL_REO1_RING_HP(ab); | ||||
| 
 | ||||
| 	s = &hal->srng_config[HAL_REO_EXCEPTION]; | ||||
| 	s->reg_start[0] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO_TCL_RING_BASE_LSB(ab); | ||||
| 	s->reg_start[1] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO_TCL_RING_HP(ab); | ||||
| 
 | ||||
| 	s = &hal->srng_config[HAL_REO_REINJECT]; | ||||
| 	s->reg_start[0] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_SW2REO_RING_BASE_LSB; | ||||
| 	s->reg_start[1] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_SW2REO_RING_HP; | ||||
| 
 | ||||
| 	s = &hal->srng_config[HAL_REO_CMD]; | ||||
| 	s->reg_start[0] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO_CMD_RING_BASE_LSB; | ||||
| 	s->reg_start[1] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO_CMD_HP; | ||||
| 
 | ||||
| 	s = &hal->srng_config[HAL_REO_STATUS]; | ||||
| 	s->reg_start[0] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO_STATUS_RING_BASE_LSB(ab); | ||||
| 	s->reg_start[1] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO_STATUS_HP(ab); | ||||
| 
 | ||||
| 	s = &hal->srng_config[HAL_TCL_DATA]; | ||||
| 	s->reg_start[0] = HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL1_RING_BASE_LSB(ab); | ||||
| 	s->reg_start[1] = HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL1_RING_HP; | ||||
| 	s->reg_size[0] = HAL_TCL2_RING_BASE_LSB(ab) - HAL_TCL1_RING_BASE_LSB(ab); | ||||
| 	s->reg_size[1] = HAL_TCL2_RING_HP - HAL_TCL1_RING_HP; | ||||
| 
 | ||||
| 	s = &hal->srng_config[HAL_TCL_CMD]; | ||||
| 	s->reg_start[0] = HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL_RING_BASE_LSB(ab); | ||||
| 	s->reg_start[1] = HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL_RING_HP; | ||||
| 
 | ||||
| 	s = &hal->srng_config[HAL_TCL_STATUS]; | ||||
| 	s->reg_start[0] = HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL_STATUS_RING_BASE_LSB(ab); | ||||
| 	s->reg_start[1] = HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL_STATUS_RING_HP; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| int ath11k_hal_srng_init(struct ath11k_base *ab) | ||||
| { | ||||
| 	struct ath11k_hal *hal = &ab->hal; | ||||
| @ -1109,7 +1119,9 @@ int ath11k_hal_srng_init(struct ath11k_base *ab) | ||||
| 
 | ||||
| 	memset(hal, 0, sizeof(*hal)); | ||||
| 
 | ||||
| 	hal->srng_config = hw_srng_config; | ||||
| 	ret = ath11k_hal_srng_create_config(ab); | ||||
| 	if (ret) | ||||
| 		goto err_hal; | ||||
| 
 | ||||
| 	ret = ath11k_hal_alloc_cont_rdp(ab); | ||||
| 	if (ret) | ||||
| @ -1127,12 +1139,17 @@ err_free_cont_rdp: | ||||
| err_hal: | ||||
| 	return ret; | ||||
| } | ||||
| EXPORT_SYMBOL(ath11k_hal_srng_init); | ||||
| 
 | ||||
| void ath11k_hal_srng_deinit(struct ath11k_base *ab) | ||||
| { | ||||
| 	struct ath11k_hal *hal = &ab->hal; | ||||
| 
 | ||||
| 	ath11k_hal_free_cont_rdp(ab); | ||||
| 	ath11k_hal_free_cont_wrp(ab); | ||||
| 	kfree(hal->srng_config); | ||||
| } | ||||
| EXPORT_SYMBOL(ath11k_hal_srng_deinit); | ||||
| 
 | ||||
| void ath11k_hal_dump_srng_stats(struct ath11k_base *ab) | ||||
| { | ||||
| @ -1142,10 +1159,10 @@ void ath11k_hal_dump_srng_stats(struct ath11k_base *ab) | ||||
| 	int i; | ||||
| 
 | ||||
| 	ath11k_err(ab, "Last interrupt received for each CE:\n"); | ||||
| 	for (i = 0; i < CE_COUNT; i++) { | ||||
| 	for (i = 0; i < ab->hw_params.ce_count; i++) { | ||||
| 		ce_pipe = &ab->ce.ce_pipe[i]; | ||||
| 
 | ||||
| 		if (ath11k_ce_get_attr_flags(i) & CE_ATTR_DIS_INTR) | ||||
| 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) | ||||
| 			continue; | ||||
| 
 | ||||
| 		ath11k_err(ab, "CE_id %d pipe_num %d %ums before\n", | ||||
|  | ||||
| @ -46,40 +46,47 @@ struct ath11k_base; | ||||
| /* SW2TCL(x) R0 ring configuration address */ | ||||
| #define HAL_TCL1_RING_CMN_CTRL_REG		0x00000014 | ||||
| #define HAL_TCL1_RING_DSCP_TID_MAP		0x0000002c | ||||
| #define HAL_TCL1_RING_BASE_LSB			0x00000510 | ||||
| #define HAL_TCL1_RING_BASE_MSB			0x00000514 | ||||
| #define HAL_TCL1_RING_ID			0x00000518 | ||||
| #define HAL_TCL1_RING_MISC			0x00000520 | ||||
| #define HAL_TCL1_RING_TP_ADDR_LSB		0x0000052c | ||||
| #define HAL_TCL1_RING_TP_ADDR_MSB		0x00000530 | ||||
| #define HAL_TCL1_RING_CONSUMER_INT_SETUP_IX0	0x00000540 | ||||
| #define HAL_TCL1_RING_CONSUMER_INT_SETUP_IX1	0x00000544 | ||||
| #define HAL_TCL1_RING_MSI1_BASE_LSB		0x00000558 | ||||
| #define HAL_TCL1_RING_MSI1_BASE_MSB		0x0000055c | ||||
| #define HAL_TCL1_RING_MSI1_DATA			0x00000560 | ||||
| #define HAL_TCL2_RING_BASE_LSB			0x00000568 | ||||
| #define HAL_TCL_RING_BASE_LSB			0x00000618 | ||||
| #define HAL_TCL1_RING_BASE_LSB(ab)		ab->hw_params.regs->hal_tcl1_ring_base_lsb | ||||
| #define HAL_TCL1_RING_BASE_MSB(ab)		ab->hw_params.regs->hal_tcl1_ring_base_msb | ||||
| #define HAL_TCL1_RING_ID(ab)			ab->hw_params.regs->hal_tcl1_ring_id | ||||
| #define HAL_TCL1_RING_MISC(ab)			ab->hw_params.regs->hal_tcl1_ring_misc | ||||
| #define HAL_TCL1_RING_TP_ADDR_LSB(ab) \ | ||||
| 	ab->hw_params.regs->hal_tcl1_ring_tp_addr_lsb | ||||
| #define HAL_TCL1_RING_TP_ADDR_MSB(ab) \ | ||||
| 	ab->hw_params.regs->hal_tcl1_ring_tp_addr_msb | ||||
| #define HAL_TCL1_RING_CONSUMER_INT_SETUP_IX0(ab) \ | ||||
| 	ab->hw_params.regs->hal_tcl1_ring_consumer_int_setup_ix0 | ||||
| #define HAL_TCL1_RING_CONSUMER_INT_SETUP_IX1(ab) \ | ||||
| 	ab->hw_params.regs->hal_tcl1_ring_consumer_int_setup_ix1 | ||||
| #define HAL_TCL1_RING_MSI1_BASE_LSB(ab) \ | ||||
| 	ab->hw_params.regs->hal_tcl1_ring_msi1_base_lsb | ||||
| #define HAL_TCL1_RING_MSI1_BASE_MSB(ab) \ | ||||
| 	ab->hw_params.regs->hal_tcl1_ring_msi1_base_msb | ||||
| #define HAL_TCL1_RING_MSI1_DATA(ab) \ | ||||
| 	ab->hw_params.regs->hal_tcl1_ring_msi1_data | ||||
| #define HAL_TCL2_RING_BASE_LSB(ab)		ab->hw_params.regs->hal_tcl2_ring_base_lsb | ||||
| #define HAL_TCL_RING_BASE_LSB(ab)		ab->hw_params.regs->hal_tcl_ring_base_lsb | ||||
| 
 | ||||
| #define HAL_TCL1_RING_MSI1_BASE_LSB_OFFSET \ | ||||
| 		(HAL_TCL1_RING_MSI1_BASE_LSB - HAL_TCL1_RING_BASE_LSB) | ||||
| #define HAL_TCL1_RING_MSI1_BASE_MSB_OFFSET \ | ||||
| 		(HAL_TCL1_RING_MSI1_BASE_MSB - HAL_TCL1_RING_BASE_LSB) | ||||
| #define HAL_TCL1_RING_MSI1_DATA_OFFSET \ | ||||
| 		(HAL_TCL1_RING_MSI1_DATA - HAL_TCL1_RING_BASE_LSB) | ||||
| #define HAL_TCL1_RING_BASE_MSB_OFFSET \ | ||||
| 		(HAL_TCL1_RING_BASE_MSB - HAL_TCL1_RING_BASE_LSB) | ||||
| #define HAL_TCL1_RING_ID_OFFSET \ | ||||
| 		(HAL_TCL1_RING_ID - HAL_TCL1_RING_BASE_LSB) | ||||
| #define HAL_TCL1_RING_CONSR_INT_SETUP_IX0_OFFSET \ | ||||
| 		(HAL_TCL1_RING_CONSUMER_INT_SETUP_IX0 - HAL_TCL1_RING_BASE_LSB) | ||||
| #define HAL_TCL1_RING_CONSR_INT_SETUP_IX1_OFFSET \ | ||||
| 		(HAL_TCL1_RING_CONSUMER_INT_SETUP_IX1 - HAL_TCL1_RING_BASE_LSB) | ||||
| #define HAL_TCL1_RING_TP_ADDR_LSB_OFFSET \ | ||||
| 		(HAL_TCL1_RING_TP_ADDR_LSB - HAL_TCL1_RING_BASE_LSB) | ||||
| #define HAL_TCL1_RING_TP_ADDR_MSB_OFFSET \ | ||||
| 		(HAL_TCL1_RING_TP_ADDR_MSB - HAL_TCL1_RING_BASE_LSB) | ||||
| #define HAL_TCL1_RING_MISC_OFFSET \ | ||||
| 		(HAL_TCL1_RING_MISC - HAL_TCL1_RING_BASE_LSB) | ||||
| #define HAL_TCL1_RING_MSI1_BASE_LSB_OFFSET(ab)				\ | ||||
| 	(HAL_TCL1_RING_MSI1_BASE_LSB(ab) - HAL_TCL1_RING_BASE_LSB(ab)) | ||||
| #define HAL_TCL1_RING_MSI1_BASE_MSB_OFFSET(ab)				\ | ||||
| 	(HAL_TCL1_RING_MSI1_BASE_MSB(ab) - HAL_TCL1_RING_BASE_LSB(ab)) | ||||
| #define HAL_TCL1_RING_MSI1_DATA_OFFSET(ab)				\ | ||||
| 	(HAL_TCL1_RING_MSI1_DATA(ab) - HAL_TCL1_RING_BASE_LSB(ab)) | ||||
| #define HAL_TCL1_RING_BASE_MSB_OFFSET(ab)				\ | ||||
| 	(HAL_TCL1_RING_BASE_MSB(ab) - HAL_TCL1_RING_BASE_LSB(ab)) | ||||
| #define HAL_TCL1_RING_ID_OFFSET(ab)				\ | ||||
| 	(HAL_TCL1_RING_ID(ab) - HAL_TCL1_RING_BASE_LSB(ab)) | ||||
| #define HAL_TCL1_RING_CONSR_INT_SETUP_IX0_OFFSET(ab)			\ | ||||
| 	(HAL_TCL1_RING_CONSUMER_INT_SETUP_IX0(ab) - HAL_TCL1_RING_BASE_LSB(ab)) | ||||
| #define HAL_TCL1_RING_CONSR_INT_SETUP_IX1_OFFSET(ab) \ | ||||
| 		(HAL_TCL1_RING_CONSUMER_INT_SETUP_IX1(ab) - HAL_TCL1_RING_BASE_LSB(ab)) | ||||
| #define HAL_TCL1_RING_TP_ADDR_LSB_OFFSET(ab) \ | ||||
| 		(HAL_TCL1_RING_TP_ADDR_LSB(ab) - HAL_TCL1_RING_BASE_LSB(ab)) | ||||
| #define HAL_TCL1_RING_TP_ADDR_MSB_OFFSET(ab) \ | ||||
| 		(HAL_TCL1_RING_TP_ADDR_MSB(ab) - HAL_TCL1_RING_BASE_LSB(ab)) | ||||
| #define HAL_TCL1_RING_MISC_OFFSET(ab) \ | ||||
| 		(HAL_TCL1_RING_MISC(ab) - HAL_TCL1_RING_BASE_LSB(ab)) | ||||
| 
 | ||||
| /* SW2TCL(x) R2 ring pointers (head/tail) address */ | ||||
| #define HAL_TCL1_RING_HP			0x00002000 | ||||
| @ -91,7 +98,8 @@ struct ath11k_base; | ||||
| 		(HAL_TCL1_RING_TP - HAL_TCL1_RING_HP) | ||||
| 
 | ||||
| /* TCL STATUS ring address */ | ||||
| #define HAL_TCL_STATUS_RING_BASE_LSB		0x00000720 | ||||
| #define HAL_TCL_STATUS_RING_BASE_LSB(ab) \ | ||||
| 	ab->hw_params.regs->hal_tcl_status_ring_base_lsb | ||||
| #define HAL_TCL_STATUS_RING_HP			0x00002030 | ||||
| 
 | ||||
| /* REO2SW(x) R0 ring configuration address */ | ||||
| @ -100,51 +108,63 @@ struct ath11k_base; | ||||
| #define HAL_REO1_DEST_RING_CTRL_IX_1		0x00000008 | ||||
| #define HAL_REO1_DEST_RING_CTRL_IX_2		0x0000000c | ||||
| #define HAL_REO1_DEST_RING_CTRL_IX_3		0x00000010 | ||||
| #define HAL_REO1_RING_BASE_LSB			0x0000029c | ||||
| #define HAL_REO1_RING_BASE_MSB			0x000002a0 | ||||
| #define HAL_REO1_RING_ID			0x000002a4 | ||||
| #define HAL_REO1_RING_MISC			0x000002ac | ||||
| #define HAL_REO1_RING_HP_ADDR_LSB		0x000002b0 | ||||
| #define HAL_REO1_RING_HP_ADDR_MSB		0x000002b4 | ||||
| #define HAL_REO1_RING_PRODUCER_INT_SETUP	0x000002c0 | ||||
| #define HAL_REO1_RING_MSI1_BASE_LSB		0x000002e4 | ||||
| #define HAL_REO1_RING_MSI1_BASE_MSB		0x000002e8 | ||||
| #define HAL_REO1_RING_MSI1_DATA			0x000002ec | ||||
| #define HAL_REO2_RING_BASE_LSB			0x000002f4 | ||||
| #define HAL_REO1_AGING_THRESH_IX_0		0x00000564 | ||||
| #define HAL_REO1_AGING_THRESH_IX_1		0x00000568 | ||||
| #define HAL_REO1_AGING_THRESH_IX_2		0x0000056c | ||||
| #define HAL_REO1_AGING_THRESH_IX_3		0x00000570 | ||||
| #define HAL_REO1_RING_BASE_LSB(ab)		ab->hw_params.regs->hal_reo1_ring_base_lsb | ||||
| #define HAL_REO1_RING_BASE_MSB(ab)		ab->hw_params.regs->hal_reo1_ring_base_msb | ||||
| #define HAL_REO1_RING_ID(ab)			ab->hw_params.regs->hal_reo1_ring_id | ||||
| #define HAL_REO1_RING_MISC(ab)			ab->hw_params.regs->hal_reo1_ring_misc | ||||
| #define HAL_REO1_RING_HP_ADDR_LSB(ab) \ | ||||
| 	ab->hw_params.regs->hal_reo1_ring_hp_addr_lsb | ||||
| #define HAL_REO1_RING_HP_ADDR_MSB(ab) \ | ||||
| 	ab->hw_params.regs->hal_reo1_ring_hp_addr_msb | ||||
| #define HAL_REO1_RING_PRODUCER_INT_SETUP(ab) \ | ||||
| 	ab->hw_params.regs->hal_reo1_ring_producer_int_setup | ||||
| #define HAL_REO1_RING_MSI1_BASE_LSB(ab) \ | ||||
| 	ab->hw_params.regs->hal_reo1_ring_msi1_base_lsb | ||||
| #define HAL_REO1_RING_MSI1_BASE_MSB(ab) \ | ||||
| 	ab->hw_params.regs->hal_reo1_ring_msi1_base_msb | ||||
| #define HAL_REO1_RING_MSI1_DATA(ab) \ | ||||
| 	ab->hw_params.regs->hal_reo1_ring_msi1_data | ||||
| #define HAL_REO2_RING_BASE_LSB(ab)		ab->hw_params.regs->hal_reo2_ring_base_lsb | ||||
| #define HAL_REO1_AGING_THRESH_IX_0(ab) \ | ||||
| 	ab->hw_params.regs->hal_reo1_aging_thresh_ix_0 | ||||
| #define HAL_REO1_AGING_THRESH_IX_1(ab) \ | ||||
| 	ab->hw_params.regs->hal_reo1_aging_thresh_ix_1 | ||||
| #define HAL_REO1_AGING_THRESH_IX_2(ab) \ | ||||
| 	ab->hw_params.regs->hal_reo1_aging_thresh_ix_2 | ||||
| #define HAL_REO1_AGING_THRESH_IX_3(ab) \ | ||||
| 	ab->hw_params.regs->hal_reo1_aging_thresh_ix_3 | ||||
| 
 | ||||
| #define HAL_REO1_RING_MSI1_BASE_LSB_OFFSET \ | ||||
| 		(HAL_REO1_RING_MSI1_BASE_LSB - HAL_REO1_RING_BASE_LSB) | ||||
| #define HAL_REO1_RING_MSI1_BASE_MSB_OFFSET \ | ||||
| 		(HAL_REO1_RING_MSI1_BASE_MSB - HAL_REO1_RING_BASE_LSB) | ||||
| #define HAL_REO1_RING_MSI1_DATA_OFFSET \ | ||||
| 		(HAL_REO1_RING_MSI1_DATA - HAL_REO1_RING_BASE_LSB) | ||||
| #define HAL_REO1_RING_BASE_MSB_OFFSET \ | ||||
| 		(HAL_REO1_RING_BASE_MSB - HAL_REO1_RING_BASE_LSB) | ||||
| #define HAL_REO1_RING_ID_OFFSET (HAL_REO1_RING_ID - HAL_REO1_RING_BASE_LSB) | ||||
| #define HAL_REO1_RING_PRODUCER_INT_SETUP_OFFSET \ | ||||
| 		(HAL_REO1_RING_PRODUCER_INT_SETUP - HAL_REO1_RING_BASE_LSB) | ||||
| #define HAL_REO1_RING_HP_ADDR_LSB_OFFSET \ | ||||
| 		(HAL_REO1_RING_HP_ADDR_LSB - HAL_REO1_RING_BASE_LSB) | ||||
| #define HAL_REO1_RING_HP_ADDR_MSB_OFFSET \ | ||||
| 		(HAL_REO1_RING_HP_ADDR_MSB - HAL_REO1_RING_BASE_LSB) | ||||
| #define HAL_REO1_RING_MISC_OFFSET (HAL_REO1_RING_MISC - HAL_REO1_RING_BASE_LSB) | ||||
| #define HAL_REO1_RING_MSI1_BASE_LSB_OFFSET(ab) \ | ||||
| 		(HAL_REO1_RING_MSI1_BASE_LSB(ab) - HAL_REO1_RING_BASE_LSB(ab)) | ||||
| #define HAL_REO1_RING_MSI1_BASE_MSB_OFFSET(ab) \ | ||||
| 		(HAL_REO1_RING_MSI1_BASE_MSB(ab) - HAL_REO1_RING_BASE_LSB(ab)) | ||||
| #define HAL_REO1_RING_MSI1_DATA_OFFSET(ab) \ | ||||
| 		(HAL_REO1_RING_MSI1_DATA(ab) - HAL_REO1_RING_BASE_LSB(ab)) | ||||
| #define HAL_REO1_RING_BASE_MSB_OFFSET(ab) \ | ||||
| 		(HAL_REO1_RING_BASE_MSB(ab) - HAL_REO1_RING_BASE_LSB(ab)) | ||||
| #define HAL_REO1_RING_ID_OFFSET(ab) (HAL_REO1_RING_ID(ab) - HAL_REO1_RING_BASE_LSB(ab)) | ||||
| #define HAL_REO1_RING_PRODUCER_INT_SETUP_OFFSET(ab) \ | ||||
| 		(HAL_REO1_RING_PRODUCER_INT_SETUP(ab) - HAL_REO1_RING_BASE_LSB(ab)) | ||||
| #define HAL_REO1_RING_HP_ADDR_LSB_OFFSET(ab) \ | ||||
| 		(HAL_REO1_RING_HP_ADDR_LSB(ab) - HAL_REO1_RING_BASE_LSB(ab)) | ||||
| #define HAL_REO1_RING_HP_ADDR_MSB_OFFSET(ab) \ | ||||
| 		(HAL_REO1_RING_HP_ADDR_MSB(ab) - HAL_REO1_RING_BASE_LSB(ab)) | ||||
| #define HAL_REO1_RING_MISC_OFFSET(ab) \ | ||||
| 	(HAL_REO1_RING_MISC(ab) - HAL_REO1_RING_BASE_LSB(ab)) | ||||
| 
 | ||||
| /* REO2SW(x) R2 ring pointers (head/tail) address */ | ||||
| #define HAL_REO1_RING_HP			0x00003038 | ||||
| #define HAL_REO1_RING_TP			0x0000303c | ||||
| #define HAL_REO2_RING_HP			0x00003040 | ||||
| #define HAL_REO1_RING_HP(ab)			ab->hw_params.regs->hal_reo1_ring_hp | ||||
| #define HAL_REO1_RING_TP(ab)			ab->hw_params.regs->hal_reo1_ring_tp | ||||
| #define HAL_REO2_RING_HP(ab)			ab->hw_params.regs->hal_reo2_ring_hp | ||||
| 
 | ||||
| #define HAL_REO1_RING_TP_OFFSET	(HAL_REO1_RING_TP - HAL_REO1_RING_HP) | ||||
| #define HAL_REO1_RING_TP_OFFSET(ab)	(HAL_REO1_RING_TP(ab) - HAL_REO1_RING_HP(ab)) | ||||
| 
 | ||||
| /* REO2TCL R0 ring configuration address */ | ||||
| #define HAL_REO_TCL_RING_BASE_LSB		0x000003fc | ||||
| #define HAL_REO_TCL_RING_BASE_LSB(ab) \ | ||||
| 	ab->hw_params.regs->hal_reo_tcl_ring_base_lsb | ||||
| 
 | ||||
| /* REO2TCL R2 ring pointer (head/tail) address */ | ||||
| #define HAL_REO_TCL_RING_HP			0x00003058 | ||||
| #define HAL_REO_TCL_RING_HP(ab)			ab->hw_params.regs->hal_reo_tcl_ring_hp | ||||
| 
 | ||||
| /* REO CMD R0 address */ | ||||
| #define HAL_REO_CMD_RING_BASE_LSB		0x00000194 | ||||
| @ -168,8 +188,9 @@ struct ath11k_base; | ||||
| #define HAL_CE_DST_STATUS_RING_HP		0x00000408 | ||||
| 
 | ||||
| /* REO status address */ | ||||
| #define HAL_REO_STATUS_RING_BASE_LSB		0x00000504 | ||||
| #define HAL_REO_STATUS_HP			0x00003070 | ||||
| #define HAL_REO_STATUS_RING_BASE_LSB(ab) \ | ||||
| 	ab->hw_params.regs->hal_reo_status_ring_base_lsb | ||||
| #define HAL_REO_STATUS_HP(ab)			ab->hw_params.regs->hal_reo_status_hp | ||||
| 
 | ||||
| /* WBM Idle R0 address */ | ||||
| #define HAL_WBM_IDLE_LINK_RING_BASE_LSB		0x00000860 | ||||
| @ -458,6 +479,8 @@ struct hal_srng_params { | ||||
| 	u32 flags; | ||||
| 	u32 max_buffer_len; | ||||
| 	u32 low_threshold; | ||||
| 	dma_addr_t msi_addr; | ||||
| 	u32 msi_data; | ||||
| 
 | ||||
| 	/* Add more params as needed */ | ||||
| }; | ||||
| @ -839,7 +862,7 @@ struct ath11k_hal { | ||||
| 	struct hal_srng srng_list[HAL_SRNG_RING_ID_MAX]; | ||||
| 
 | ||||
| 	/* SRNG configuration table */ | ||||
| 	const struct hal_srng_config *srng_config; | ||||
| 	struct hal_srng_config *srng_config; | ||||
| 
 | ||||
| 	/* Remote pointer memory for HW/FW updates */ | ||||
| 	struct { | ||||
| @ -885,8 +908,8 @@ void ath11k_hal_ce_src_set_desc(void *buf, dma_addr_t paddr, u32 len, u32 id, | ||||
| 				u8 byte_swap_data); | ||||
| void ath11k_hal_ce_dst_set_desc(void *buf, dma_addr_t paddr); | ||||
| u32 ath11k_hal_ce_dst_status_get_length(void *buf); | ||||
| int ath11k_hal_srng_get_entrysize(u32 ring_type); | ||||
| int ath11k_hal_srng_get_max_entries(u32 ring_type); | ||||
| int ath11k_hal_srng_get_entrysize(struct ath11k_base *ab, u32 ring_type); | ||||
| int ath11k_hal_srng_get_max_entries(struct ath11k_base *ab, u32 ring_type); | ||||
| void ath11k_hal_srng_get_params(struct ath11k_base *ab, struct hal_srng *srng, | ||||
| 				struct hal_srng_params *params); | ||||
| u32 *ath11k_hal_srng_dst_get_next_entry(struct ath11k_base *ab, | ||||
|  | ||||
| @ -786,7 +786,7 @@ void ath11k_hal_reo_init_cmd_ring(struct ath11k_base *ab, | ||||
| 
 | ||||
| 	memset(¶ms, 0, sizeof(params)); | ||||
| 
 | ||||
| 	entry_size = ath11k_hal_srng_get_entrysize(HAL_REO_CMD); | ||||
| 	entry_size = ath11k_hal_srng_get_entrysize(ab, HAL_REO_CMD); | ||||
| 	ath11k_hal_srng_get_params(ab, srng, ¶ms); | ||||
| 	entry = (u8 *)params.ring_base_vaddr; | ||||
| 
 | ||||
| @ -813,13 +813,13 @@ void ath11k_hal_reo_hw_setup(struct ath11k_base *ab, u32 ring_hash_map) | ||||
| 	       FIELD_PREP(HAL_REO1_GEN_ENABLE_AGING_FLUSH_ENABLE, 1); | ||||
| 	ath11k_hif_write32(ab, reo_base + HAL_REO1_GEN_ENABLE, val); | ||||
| 
 | ||||
| 	ath11k_hif_write32(ab, reo_base + HAL_REO1_AGING_THRESH_IX_0, | ||||
| 	ath11k_hif_write32(ab, reo_base + HAL_REO1_AGING_THRESH_IX_0(ab), | ||||
| 			   HAL_DEFAULT_REO_TIMEOUT_USEC); | ||||
| 	ath11k_hif_write32(ab, reo_base + HAL_REO1_AGING_THRESH_IX_1, | ||||
| 	ath11k_hif_write32(ab, reo_base + HAL_REO1_AGING_THRESH_IX_1(ab), | ||||
| 			   HAL_DEFAULT_REO_TIMEOUT_USEC); | ||||
| 	ath11k_hif_write32(ab, reo_base + HAL_REO1_AGING_THRESH_IX_2, | ||||
| 	ath11k_hif_write32(ab, reo_base + HAL_REO1_AGING_THRESH_IX_2(ab), | ||||
| 			   HAL_DEFAULT_REO_TIMEOUT_USEC); | ||||
| 	ath11k_hif_write32(ab, reo_base + HAL_REO1_AGING_THRESH_IX_3, | ||||
| 	ath11k_hif_write32(ab, reo_base + HAL_REO1_AGING_THRESH_IX_3(ab), | ||||
| 			   HAL_DEFAULT_REO_TIMEOUT_USEC); | ||||
| 
 | ||||
| 	ath11k_hif_write32(ab, reo_base + HAL_REO1_DEST_RING_CTRL_IX_0, | ||||
|  | ||||
| @ -141,7 +141,7 @@ void ath11k_hal_tx_init_data_ring(struct ath11k_base *ab, struct hal_srng *srng) | ||||
| 
 | ||||
| 	memset(¶ms, 0, sizeof(params)); | ||||
| 
 | ||||
| 	entry_size = ath11k_hal_srng_get_entrysize(HAL_TCL_DATA); | ||||
| 	entry_size = ath11k_hal_srng_get_entrysize(ab, HAL_TCL_DATA); | ||||
| 	ath11k_hal_srng_get_params(ab, srng, ¶ms); | ||||
| 	desc = (u8 *)params.ring_base_vaddr; | ||||
| 
 | ||||
|  | ||||
| @ -3,6 +3,9 @@ | ||||
|  * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. | ||||
|  */ | ||||
| 
 | ||||
| #ifndef _HIF_H_ | ||||
| #define _HIF_H_ | ||||
| 
 | ||||
| #include "core.h" | ||||
| 
 | ||||
| struct ath11k_hif_ops { | ||||
| @ -16,6 +19,11 @@ struct ath11k_hif_ops { | ||||
| 	void (*power_down)(struct ath11k_base *sc); | ||||
| 	int (*map_service_to_pipe)(struct ath11k_base *sc, u16 service_id, | ||||
| 				   u8 *ul_pipe, u8 *dl_pipe); | ||||
| 	int (*get_user_msi_vector)(struct ath11k_base *ab, char *user_name, | ||||
| 				   int *num_vectors, u32 *user_base_data, | ||||
| 				   u32 *base_vector); | ||||
| 	void (*get_msi_address)(struct ath11k_base *ab, u32 *msi_addr_lo, | ||||
| 				u32 *msi_addr_hi); | ||||
| }; | ||||
| 
 | ||||
| static inline int ath11k_hif_start(struct ath11k_base *sc) | ||||
| @ -63,3 +71,25 @@ static inline int ath11k_hif_map_service_to_pipe(struct ath11k_base *sc, u16 ser | ||||
| { | ||||
| 	return sc->hif.ops->map_service_to_pipe(sc, service_id, ul_pipe, dl_pipe); | ||||
| } | ||||
| 
 | ||||
| static inline int ath11k_get_user_msi_vector(struct ath11k_base *ab, char *user_name, | ||||
| 					     int *num_vectors, u32 *user_base_data, | ||||
| 					     u32 *base_vector) | ||||
| { | ||||
| 	if (!ab->hif.ops->get_user_msi_vector) | ||||
| 		return -EOPNOTSUPP; | ||||
| 
 | ||||
| 	return ab->hif.ops->get_user_msi_vector(ab, user_name, num_vectors, | ||||
| 						user_base_data, | ||||
| 						base_vector); | ||||
| } | ||||
| 
 | ||||
| static inline void ath11k_get_msi_address(struct ath11k_base *ab, u32 *msi_addr_lo, | ||||
| 					  u32 *msi_addr_hi) | ||||
| { | ||||
| 	if (!ab->hif.ops->get_msi_address) | ||||
| 		return; | ||||
| 
 | ||||
| 	ab->hif.ops->get_msi_address(ab, msi_addr_lo, msi_addr_hi); | ||||
| } | ||||
| #endif /* _HIF_H_ */ | ||||
|  | ||||
| @ -478,7 +478,7 @@ int ath11k_htc_wait_target(struct ath11k_htc *htc) | ||||
| 	if (!time_left) { | ||||
| 		ath11k_warn(ab, "failed to receive control response completion, polling..\n"); | ||||
| 
 | ||||
| 		for (i = 0; i < CE_COUNT; i++) | ||||
| 		for (i = 0; i < ab->hw_params.ce_count; i++) | ||||
| 			ath11k_ce_per_engine_service(htc->ab, i); | ||||
| 
 | ||||
| 		time_left = | ||||
| @ -748,7 +748,7 @@ int ath11k_htc_init(struct ath11k_base *ab) | ||||
| 		htc->wmi_ep_count = 3; | ||||
| 		break; | ||||
| 	default: | ||||
| 		htc->wmi_ep_count = 3; | ||||
| 		htc->wmi_ep_count = ab->hw_params.max_radios; | ||||
| 		break; | ||||
| 	} | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										378
									
								
								drivers/net/wireless/ath/ath11k/hw.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										378
									
								
								drivers/net/wireless/ath/ath11k/hw.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,378 @@ | ||||
| // SPDX-License-Identifier: BSD-3-Clause-Clear
 | ||||
| /*
 | ||||
|  * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. | ||||
|  */ | ||||
| 
 | ||||
| #include <linux/types.h> | ||||
| #include <linux/bitops.h> | ||||
| #include <linux/bitfield.h> | ||||
| 
 | ||||
| #include "hw.h" | ||||
| #include "core.h" | ||||
| #include "ce.h" | ||||
| 
 | ||||
| /* Map from pdev index to hw mac index */ | ||||
| static u8 ath11k_hw_ipq8074_mac_from_pdev_id(int pdev_idx) | ||||
| { | ||||
| 	switch (pdev_idx) { | ||||
| 	case 0: | ||||
| 		return 0; | ||||
| 	case 1: | ||||
| 		return 2; | ||||
| 	case 2: | ||||
| 		return 1; | ||||
| 	default: | ||||
| 		return ATH11K_INVALID_HW_MAC_ID; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static u8 ath11k_hw_ipq6018_mac_from_pdev_id(int pdev_idx) | ||||
| { | ||||
| 	return pdev_idx; | ||||
| } | ||||
| 
 | ||||
| static void ath11k_init_wmi_config_qca6390(struct ath11k_base *ab, | ||||
| 					   struct target_resource_config *config) | ||||
| { | ||||
| 	config->num_vdevs = 4; | ||||
| 	config->num_peers = 16; | ||||
| 	config->num_tids = 32; | ||||
| 
 | ||||
| 	config->num_offload_peers = 3; | ||||
| 	config->num_offload_reorder_buffs = 3; | ||||
| 	config->num_peer_keys = TARGET_NUM_PEER_KEYS; | ||||
| 	config->ast_skid_limit = TARGET_AST_SKID_LIMIT; | ||||
| 	config->tx_chain_mask = (1 << ab->target_caps.num_rf_chains) - 1; | ||||
| 	config->rx_chain_mask = (1 << ab->target_caps.num_rf_chains) - 1; | ||||
| 	config->rx_timeout_pri[0] = TARGET_RX_TIMEOUT_LO_PRI; | ||||
| 	config->rx_timeout_pri[1] = TARGET_RX_TIMEOUT_LO_PRI; | ||||
| 	config->rx_timeout_pri[2] = TARGET_RX_TIMEOUT_LO_PRI; | ||||
| 	config->rx_timeout_pri[3] = TARGET_RX_TIMEOUT_HI_PRI; | ||||
| 	config->rx_decap_mode = TARGET_DECAP_MODE_NATIVE_WIFI; | ||||
| 	config->scan_max_pending_req = TARGET_SCAN_MAX_PENDING_REQS; | ||||
| 	config->bmiss_offload_max_vdev = TARGET_BMISS_OFFLOAD_MAX_VDEV; | ||||
| 	config->roam_offload_max_vdev = TARGET_ROAM_OFFLOAD_MAX_VDEV; | ||||
| 	config->roam_offload_max_ap_profiles = TARGET_ROAM_OFFLOAD_MAX_AP_PROFILES; | ||||
| 	config->num_mcast_groups = 0; | ||||
| 	config->num_mcast_table_elems = 0; | ||||
| 	config->mcast2ucast_mode = 0; | ||||
| 	config->tx_dbg_log_size = TARGET_TX_DBG_LOG_SIZE; | ||||
| 	config->num_wds_entries = 0; | ||||
| 	config->dma_burst_size = 0; | ||||
| 	config->rx_skip_defrag_timeout_dup_detection_check = 0; | ||||
| 	config->vow_config = TARGET_VOW_CONFIG; | ||||
| 	config->gtk_offload_max_vdev = 2; | ||||
| 	config->num_msdu_desc = 0x400; | ||||
| 	config->beacon_tx_offload_max_vdev = 2; | ||||
| 	config->rx_batchmode = TARGET_RX_BATCHMODE; | ||||
| 
 | ||||
| 	config->peer_map_unmap_v2_support = 0; | ||||
| 	config->use_pdev_id = 1; | ||||
| 	config->max_frag_entries = 0xa; | ||||
| 	config->num_tdls_vdevs = 0x1; | ||||
| 	config->num_tdls_conn_table_entries = 8; | ||||
| 	config->beacon_tx_offload_max_vdev = 0x2; | ||||
| 	config->num_multicast_filter_entries = 0x20; | ||||
| 	config->num_wow_filters = 0x16; | ||||
| 	config->num_keep_alive_pattern = 0x1; | ||||
| 	config->num_keep_alive_pattern = 0; | ||||
| } | ||||
| 
 | ||||
| static void ath11k_init_wmi_config_ipq8074(struct ath11k_base *ab, | ||||
| 					   struct target_resource_config *config) | ||||
| { | ||||
| 	config->num_vdevs = ab->num_radios * TARGET_NUM_VDEVS; | ||||
| 
 | ||||
| 	if (ab->num_radios == 2) { | ||||
| 		config->num_peers = TARGET_NUM_PEERS(DBS); | ||||
| 		config->num_tids = TARGET_NUM_TIDS(DBS); | ||||
| 	} else if (ab->num_radios == 3) { | ||||
| 		config->num_peers = TARGET_NUM_PEERS(DBS_SBS); | ||||
| 		config->num_tids = TARGET_NUM_TIDS(DBS_SBS); | ||||
| 	} else { | ||||
| 		/* Control should not reach here */ | ||||
| 		config->num_peers = TARGET_NUM_PEERS(SINGLE); | ||||
| 		config->num_tids = TARGET_NUM_TIDS(SINGLE); | ||||
| 	} | ||||
| 	config->num_offload_peers = TARGET_NUM_OFFLD_PEERS; | ||||
| 	config->num_offload_reorder_buffs = TARGET_NUM_OFFLD_REORDER_BUFFS; | ||||
| 	config->num_peer_keys = TARGET_NUM_PEER_KEYS; | ||||
| 	config->ast_skid_limit = TARGET_AST_SKID_LIMIT; | ||||
| 	config->tx_chain_mask = (1 << ab->target_caps.num_rf_chains) - 1; | ||||
| 	config->rx_chain_mask = (1 << ab->target_caps.num_rf_chains) - 1; | ||||
| 	config->rx_timeout_pri[0] = TARGET_RX_TIMEOUT_LO_PRI; | ||||
| 	config->rx_timeout_pri[1] = TARGET_RX_TIMEOUT_LO_PRI; | ||||
| 	config->rx_timeout_pri[2] = TARGET_RX_TIMEOUT_LO_PRI; | ||||
| 	config->rx_timeout_pri[3] = TARGET_RX_TIMEOUT_HI_PRI; | ||||
| 	config->rx_decap_mode = TARGET_DECAP_MODE_NATIVE_WIFI; | ||||
| 	config->scan_max_pending_req = TARGET_SCAN_MAX_PENDING_REQS; | ||||
| 	config->bmiss_offload_max_vdev = TARGET_BMISS_OFFLOAD_MAX_VDEV; | ||||
| 	config->roam_offload_max_vdev = TARGET_ROAM_OFFLOAD_MAX_VDEV; | ||||
| 	config->roam_offload_max_ap_profiles = TARGET_ROAM_OFFLOAD_MAX_AP_PROFILES; | ||||
| 	config->num_mcast_groups = TARGET_NUM_MCAST_GROUPS; | ||||
| 	config->num_mcast_table_elems = TARGET_NUM_MCAST_TABLE_ELEMS; | ||||
| 	config->mcast2ucast_mode = TARGET_MCAST2UCAST_MODE; | ||||
| 	config->tx_dbg_log_size = TARGET_TX_DBG_LOG_SIZE; | ||||
| 	config->num_wds_entries = TARGET_NUM_WDS_ENTRIES; | ||||
| 	config->dma_burst_size = TARGET_DMA_BURST_SIZE; | ||||
| 	config->rx_skip_defrag_timeout_dup_detection_check = | ||||
| 		TARGET_RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK; | ||||
| 	config->vow_config = TARGET_VOW_CONFIG; | ||||
| 	config->gtk_offload_max_vdev = TARGET_GTK_OFFLOAD_MAX_VDEV; | ||||
| 	config->num_msdu_desc = TARGET_NUM_MSDU_DESC; | ||||
| 	config->beacon_tx_offload_max_vdev = ab->num_radios * TARGET_MAX_BCN_OFFLD; | ||||
| 	config->rx_batchmode = TARGET_RX_BATCHMODE; | ||||
| 	config->peer_map_unmap_v2_support = 1; | ||||
| 	config->twt_ap_pdev_count = 2; | ||||
| 	config->twt_ap_sta_count = 1000; | ||||
| } | ||||
| 
 | ||||
| static int ath11k_hw_mac_id_to_pdev_id_ipq8074(struct ath11k_hw_params *hw, | ||||
| 					       int mac_id) | ||||
| { | ||||
| 	return mac_id; | ||||
| } | ||||
| 
 | ||||
| static int ath11k_hw_mac_id_to_srng_id_ipq8074(struct ath11k_hw_params *hw, | ||||
| 					       int mac_id) | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int ath11k_hw_mac_id_to_pdev_id_qca6390(struct ath11k_hw_params *hw, | ||||
| 					       int mac_id) | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int ath11k_hw_mac_id_to_srng_id_qca6390(struct ath11k_hw_params *hw, | ||||
| 					       int mac_id) | ||||
| { | ||||
| 	return mac_id; | ||||
| } | ||||
| 
 | ||||
| const struct ath11k_hw_ops ipq8074_ops = { | ||||
| 	.get_hw_mac_from_pdev_id = ath11k_hw_ipq8074_mac_from_pdev_id, | ||||
| 	.wmi_init_config = ath11k_init_wmi_config_qca6390, | ||||
| 	.mac_id_to_pdev_id = ath11k_hw_mac_id_to_pdev_id_ipq8074, | ||||
| 	.mac_id_to_srng_id = ath11k_hw_mac_id_to_srng_id_ipq8074, | ||||
| }; | ||||
| 
 | ||||
| const struct ath11k_hw_ops ipq6018_ops = { | ||||
| 	.get_hw_mac_from_pdev_id = ath11k_hw_ipq6018_mac_from_pdev_id, | ||||
| 	.wmi_init_config = ath11k_init_wmi_config_ipq8074, | ||||
| 	.mac_id_to_pdev_id = ath11k_hw_mac_id_to_pdev_id_ipq8074, | ||||
| 	.mac_id_to_srng_id = ath11k_hw_mac_id_to_srng_id_ipq8074, | ||||
| }; | ||||
| 
 | ||||
| const struct ath11k_hw_ops qca6390_ops = { | ||||
| 	.get_hw_mac_from_pdev_id = ath11k_hw_ipq8074_mac_from_pdev_id, | ||||
| 	.wmi_init_config = ath11k_init_wmi_config_qca6390, | ||||
| 	.mac_id_to_pdev_id = ath11k_hw_mac_id_to_pdev_id_qca6390, | ||||
| 	.mac_id_to_srng_id = ath11k_hw_mac_id_to_srng_id_qca6390, | ||||
| }; | ||||
| 
 | ||||
| #define ATH11K_TX_RING_MASK_0 0x1 | ||||
| #define ATH11K_TX_RING_MASK_1 0x2 | ||||
| #define ATH11K_TX_RING_MASK_2 0x4 | ||||
| 
 | ||||
| #define ATH11K_RX_RING_MASK_0 0x1 | ||||
| #define ATH11K_RX_RING_MASK_1 0x2 | ||||
| #define ATH11K_RX_RING_MASK_2 0x4 | ||||
| #define ATH11K_RX_RING_MASK_3 0x8 | ||||
| 
 | ||||
| #define ATH11K_RX_ERR_RING_MASK_0 0x1 | ||||
| 
 | ||||
| #define ATH11K_RX_WBM_REL_RING_MASK_0 0x1 | ||||
| 
 | ||||
| #define ATH11K_REO_STATUS_RING_MASK_0 0x1 | ||||
| 
 | ||||
| #define ATH11K_RXDMA2HOST_RING_MASK_0 0x1 | ||||
| #define ATH11K_RXDMA2HOST_RING_MASK_1 0x2 | ||||
| #define ATH11K_RXDMA2HOST_RING_MASK_2 0x4 | ||||
| 
 | ||||
| #define ATH11K_HOST2RXDMA_RING_MASK_0 0x1 | ||||
| #define ATH11K_HOST2RXDMA_RING_MASK_1 0x2 | ||||
| #define ATH11K_HOST2RXDMA_RING_MASK_2 0x4 | ||||
| 
 | ||||
| #define ATH11K_RX_MON_STATUS_RING_MASK_0 0x1 | ||||
| #define ATH11K_RX_MON_STATUS_RING_MASK_1 0x2 | ||||
| #define ATH11K_RX_MON_STATUS_RING_MASK_2 0x4 | ||||
| 
 | ||||
| const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_ipq8074 = { | ||||
| 	.tx  = { | ||||
| 		ATH11K_TX_RING_MASK_0, | ||||
| 		ATH11K_TX_RING_MASK_1, | ||||
| 		ATH11K_TX_RING_MASK_2, | ||||
| 	}, | ||||
| 	.rx_mon_status = { | ||||
| 		0, 0, 0, 0, | ||||
| 		ATH11K_RX_MON_STATUS_RING_MASK_0, | ||||
| 		ATH11K_RX_MON_STATUS_RING_MASK_1, | ||||
| 		ATH11K_RX_MON_STATUS_RING_MASK_2, | ||||
| 	}, | ||||
| 	.rx = { | ||||
| 		0, 0, 0, 0, 0, 0, 0, | ||||
| 		ATH11K_RX_RING_MASK_0, | ||||
| 		ATH11K_RX_RING_MASK_1, | ||||
| 		ATH11K_RX_RING_MASK_2, | ||||
| 		ATH11K_RX_RING_MASK_3, | ||||
| 	}, | ||||
| 	.rx_err = { | ||||
| 		ATH11K_RX_ERR_RING_MASK_0, | ||||
| 	}, | ||||
| 	.rx_wbm_rel = { | ||||
| 		ATH11K_RX_WBM_REL_RING_MASK_0, | ||||
| 	}, | ||||
| 	.reo_status = { | ||||
| 		ATH11K_REO_STATUS_RING_MASK_0, | ||||
| 	}, | ||||
| 	.rxdma2host = { | ||||
| 		ATH11K_RXDMA2HOST_RING_MASK_0, | ||||
| 		ATH11K_RXDMA2HOST_RING_MASK_1, | ||||
| 		ATH11K_RXDMA2HOST_RING_MASK_2, | ||||
| 	}, | ||||
| 	.host2rxdma = { | ||||
| 		ATH11K_HOST2RXDMA_RING_MASK_0, | ||||
| 		ATH11K_HOST2RXDMA_RING_MASK_1, | ||||
| 		ATH11K_HOST2RXDMA_RING_MASK_2, | ||||
| 	}, | ||||
| }; | ||||
| 
 | ||||
| const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_qca6390 = { | ||||
| 	.tx  = { | ||||
| 		ATH11K_TX_RING_MASK_0, | ||||
| 		ATH11K_TX_RING_MASK_1, | ||||
| 		ATH11K_TX_RING_MASK_2, | ||||
| 	}, | ||||
| 	.rx_mon_status = { | ||||
| 		0, 0, 0, 0, | ||||
| 		ATH11K_RX_MON_STATUS_RING_MASK_0, | ||||
| 		ATH11K_RX_MON_STATUS_RING_MASK_1, | ||||
| 		ATH11K_RX_MON_STATUS_RING_MASK_2, | ||||
| 	}, | ||||
| 	.rx = { | ||||
| 		0, 0, 0, 0, 0, 0, 0, | ||||
| 		ATH11K_RX_RING_MASK_0, | ||||
| 		ATH11K_RX_RING_MASK_1, | ||||
| 		ATH11K_RX_RING_MASK_2, | ||||
| 		ATH11K_RX_RING_MASK_3, | ||||
| 	}, | ||||
| 	.rx_err = { | ||||
| 		ATH11K_RX_ERR_RING_MASK_0, | ||||
| 	}, | ||||
| 	.rx_wbm_rel = { | ||||
| 		ATH11K_RX_WBM_REL_RING_MASK_0, | ||||
| 	}, | ||||
| 	.reo_status = { | ||||
| 		ATH11K_REO_STATUS_RING_MASK_0, | ||||
| 	}, | ||||
| 	.rxdma2host = { | ||||
| 		ATH11K_RXDMA2HOST_RING_MASK_0, | ||||
| 		ATH11K_RXDMA2HOST_RING_MASK_1, | ||||
| 		ATH11K_RXDMA2HOST_RING_MASK_2, | ||||
| 	}, | ||||
| 	.host2rxdma = { | ||||
| 	}, | ||||
| }; | ||||
| 
 | ||||
| const struct ath11k_hw_regs ipq8074_regs = { | ||||
| 	/* SW2TCL(x) R0 ring configuration address */ | ||||
| 	.hal_tcl1_ring_base_lsb = 0x00000510, | ||||
| 	.hal_tcl1_ring_base_msb = 0x00000514, | ||||
| 	.hal_tcl1_ring_id = 0x00000518, | ||||
| 	.hal_tcl1_ring_misc = 0x00000520, | ||||
| 	.hal_tcl1_ring_tp_addr_lsb = 0x0000052c, | ||||
| 	.hal_tcl1_ring_tp_addr_msb = 0x00000530, | ||||
| 	.hal_tcl1_ring_consumer_int_setup_ix0 = 0x00000540, | ||||
| 	.hal_tcl1_ring_consumer_int_setup_ix1 = 0x00000544, | ||||
| 	.hal_tcl1_ring_msi1_base_lsb = 0x00000558, | ||||
| 	.hal_tcl1_ring_msi1_base_msb = 0x0000055c, | ||||
| 	.hal_tcl1_ring_msi1_data = 0x00000560, | ||||
| 	.hal_tcl2_ring_base_lsb = 0x00000568, | ||||
| 	.hal_tcl_ring_base_lsb = 0x00000618, | ||||
| 
 | ||||
| 	/* TCL STATUS ring address */ | ||||
| 	.hal_tcl_status_ring_base_lsb = 0x00000720, | ||||
| 
 | ||||
| 	/* REO2SW(x) R0 ring configuration address */ | ||||
| 	.hal_reo1_ring_base_lsb = 0x0000029c, | ||||
| 	.hal_reo1_ring_base_msb = 0x000002a0, | ||||
| 	.hal_reo1_ring_id = 0x000002a4, | ||||
| 	.hal_reo1_ring_misc = 0x000002ac, | ||||
| 	.hal_reo1_ring_hp_addr_lsb = 0x000002b0, | ||||
| 	.hal_reo1_ring_hp_addr_msb = 0x000002b4, | ||||
| 	.hal_reo1_ring_producer_int_setup = 0x000002c0, | ||||
| 	.hal_reo1_ring_msi1_base_lsb = 0x000002e4, | ||||
| 	.hal_reo1_ring_msi1_base_msb = 0x000002e8, | ||||
| 	.hal_reo1_ring_msi1_data = 0x000002ec, | ||||
| 	.hal_reo2_ring_base_lsb = 0x000002f4, | ||||
| 	.hal_reo1_aging_thresh_ix_0 = 0x00000564, | ||||
| 	.hal_reo1_aging_thresh_ix_1 = 0x00000568, | ||||
| 	.hal_reo1_aging_thresh_ix_2 = 0x0000056c, | ||||
| 	.hal_reo1_aging_thresh_ix_3 = 0x00000570, | ||||
| 
 | ||||
| 	/* REO2SW(x) R2 ring pointers (head/tail) address */ | ||||
| 	.hal_reo1_ring_hp = 0x00003038, | ||||
| 	.hal_reo1_ring_tp = 0x0000303c, | ||||
| 	.hal_reo2_ring_hp = 0x00003040, | ||||
| 
 | ||||
| 	/* REO2TCL R0 ring configuration address */ | ||||
| 	.hal_reo_tcl_ring_base_lsb = 0x000003fc, | ||||
| 	.hal_reo_tcl_ring_hp = 0x00003058, | ||||
| 
 | ||||
| 	/* REO status address */ | ||||
| 	.hal_reo_status_ring_base_lsb = 0x00000504, | ||||
| 	.hal_reo_status_hp = 0x00003070, | ||||
| 
 | ||||
| }; | ||||
| 
 | ||||
| const struct ath11k_hw_regs qca6390_regs = { | ||||
| 	/* SW2TCL(x) R0 ring configuration address */ | ||||
| 	.hal_tcl1_ring_base_lsb = 0x00000684, | ||||
| 	.hal_tcl1_ring_base_msb = 0x00000688, | ||||
| 	.hal_tcl1_ring_id = 0x0000068c, | ||||
| 	.hal_tcl1_ring_misc = 0x00000694, | ||||
| 	.hal_tcl1_ring_tp_addr_lsb = 0x000006a0, | ||||
| 	.hal_tcl1_ring_tp_addr_msb = 0x000006a4, | ||||
| 	.hal_tcl1_ring_consumer_int_setup_ix0 = 0x000006b4, | ||||
| 	.hal_tcl1_ring_consumer_int_setup_ix1 = 0x000006b8, | ||||
| 	.hal_tcl1_ring_msi1_base_lsb = 0x000006cc, | ||||
| 	.hal_tcl1_ring_msi1_base_msb = 0x000006d0, | ||||
| 	.hal_tcl1_ring_msi1_data = 0x000006d4, | ||||
| 	.hal_tcl2_ring_base_lsb = 0x000006dc, | ||||
| 	.hal_tcl_ring_base_lsb = 0x0000078c, | ||||
| 
 | ||||
| 	/* TCL STATUS ring address */ | ||||
| 	.hal_tcl_status_ring_base_lsb = 0x00000894, | ||||
| 
 | ||||
| 	/* REO2SW(x) R0 ring configuration address */ | ||||
| 	.hal_reo1_ring_base_lsb = 0x00000244, | ||||
| 	.hal_reo1_ring_base_msb = 0x00000248, | ||||
| 	.hal_reo1_ring_id = 0x0000024c, | ||||
| 	.hal_reo1_ring_misc = 0x00000254, | ||||
| 	.hal_reo1_ring_hp_addr_lsb = 0x00000258, | ||||
| 	.hal_reo1_ring_hp_addr_msb = 0x0000025c, | ||||
| 	.hal_reo1_ring_producer_int_setup = 0x00000268, | ||||
| 	.hal_reo1_ring_msi1_base_lsb = 0x0000028c, | ||||
| 	.hal_reo1_ring_msi1_base_msb = 0x00000290, | ||||
| 	.hal_reo1_ring_msi1_data = 0x00000294, | ||||
| 	.hal_reo2_ring_base_lsb = 0x0000029c, | ||||
| 	.hal_reo1_aging_thresh_ix_0 = 0x0000050c, | ||||
| 	.hal_reo1_aging_thresh_ix_1 = 0x00000510, | ||||
| 	.hal_reo1_aging_thresh_ix_2 = 0x00000514, | ||||
| 	.hal_reo1_aging_thresh_ix_3 = 0x00000518, | ||||
| 
 | ||||
| 	/* REO2SW(x) R2 ring pointers (head/tail) address */ | ||||
| 	.hal_reo1_ring_hp = 0x00003030, | ||||
| 	.hal_reo1_ring_tp = 0x00003034, | ||||
| 	.hal_reo2_ring_hp = 0x00003038, | ||||
| 
 | ||||
| 	/* REO2TCL R0 ring configuration address */ | ||||
| 	.hal_reo_tcl_ring_base_lsb = 0x000003a4, | ||||
| 	.hal_reo_tcl_ring_hp = 0x00003050, | ||||
| 
 | ||||
| 	/* REO status address */ | ||||
| 	.hal_reo_status_ring_base_lsb = 0x000004ac, | ||||
| 	.hal_reo_status_hp = 0x00003068, | ||||
| }; | ||||
| @ -6,6 +6,8 @@ | ||||
| #ifndef ATH11K_HW_H | ||||
| #define ATH11K_HW_H | ||||
| 
 | ||||
| #include "wmi.h" | ||||
| 
 | ||||
| /* Target configuration defines */ | ||||
| 
 | ||||
| /* Num VDEVS per radio */ | ||||
| @ -68,15 +70,12 @@ | ||||
| 
 | ||||
| #define ATH11K_FW_DIR			"ath11k" | ||||
| 
 | ||||
| /* IPQ8074 definitions */ | ||||
| #define IPQ8074_FW_DIR			"IPQ8074" | ||||
| #define IPQ8074_MAX_BOARD_DATA_SZ	(256 * 1024) | ||||
| #define IPQ8074_MAX_CAL_DATA_SZ		IPQ8074_MAX_BOARD_DATA_SZ | ||||
| 
 | ||||
| #define ATH11K_BOARD_MAGIC		"QCA-ATH11K-BOARD" | ||||
| #define ATH11K_BOARD_API2_FILE		"board-2.bin" | ||||
| #define ATH11K_DEFAULT_BOARD_FILE	"bdwlan.bin" | ||||
| #define ATH11K_DEFAULT_BOARD_FILE	"board.bin" | ||||
| #define ATH11K_DEFAULT_CAL_FILE		"caldata.bin" | ||||
| #define ATH11K_AMSS_FILE		"amss.bin" | ||||
| #define ATH11K_M3_FILE			"m3.bin" | ||||
| 
 | ||||
| enum ath11k_hw_rate_cck { | ||||
| 	ATH11K_HW_RATE_CCK_LP_11M = 0, | ||||
| @ -104,15 +103,100 @@ enum ath11k_bus { | ||||
| 	ATH11K_BUS_PCI, | ||||
| }; | ||||
| 
 | ||||
| #define ATH11K_EXT_IRQ_GRP_NUM_MAX 11 | ||||
| 
 | ||||
| struct ath11k_hw_ring_mask { | ||||
| 	u8 tx[ATH11K_EXT_IRQ_GRP_NUM_MAX]; | ||||
| 	u8 rx_mon_status[ATH11K_EXT_IRQ_GRP_NUM_MAX]; | ||||
| 	u8 rx[ATH11K_EXT_IRQ_GRP_NUM_MAX]; | ||||
| 	u8 rx_err[ATH11K_EXT_IRQ_GRP_NUM_MAX]; | ||||
| 	u8 rx_wbm_rel[ATH11K_EXT_IRQ_GRP_NUM_MAX]; | ||||
| 	u8 reo_status[ATH11K_EXT_IRQ_GRP_NUM_MAX]; | ||||
| 	u8 rxdma2host[ATH11K_EXT_IRQ_GRP_NUM_MAX]; | ||||
| 	u8 host2rxdma[ATH11K_EXT_IRQ_GRP_NUM_MAX]; | ||||
| }; | ||||
| 
 | ||||
| struct ath11k_hw_params { | ||||
| 	const char *name; | ||||
| 	u16 hw_rev; | ||||
| 	u8 max_radios; | ||||
| 	u32 bdf_addr; | ||||
| 
 | ||||
| 	struct { | ||||
| 		const char *dir; | ||||
| 		size_t board_size; | ||||
| 		size_t cal_size; | ||||
| 	} fw; | ||||
| 
 | ||||
| 	const struct ath11k_hw_ops *hw_ops; | ||||
| 
 | ||||
| 	const struct ath11k_hw_ring_mask *ring_mask; | ||||
| 
 | ||||
| 	bool internal_sleep_clock; | ||||
| 
 | ||||
| 	const struct ath11k_hw_regs *regs; | ||||
| 	const struct ce_attr *host_ce_config; | ||||
| 	u32 ce_count; | ||||
| 
 | ||||
| 	bool single_pdev_only; | ||||
| 
 | ||||
| 	/* For example on QCA6390 struct
 | ||||
| 	 * wmi_init_cmd_param::band_to_mac_config needs to be false as the | ||||
| 	 * firmware creates the mapping. | ||||
| 	 */ | ||||
| 	bool needs_band_to_mac; | ||||
| 
 | ||||
| 	bool rxdma1_enable; | ||||
| 	int num_rxmda_per_pdev; | ||||
| 	bool rx_mac_buf_ring; | ||||
| 	bool vdev_start_delay; | ||||
| 	bool htt_peer_map_v2; | ||||
| 	bool tcl_0_only; | ||||
| }; | ||||
| 
 | ||||
| struct ath11k_hw_ops { | ||||
| 	u8 (*get_hw_mac_from_pdev_id)(int pdev_id); | ||||
| 	void (*wmi_init_config)(struct ath11k_base *ab, | ||||
| 				struct target_resource_config *config); | ||||
| 	int (*mac_id_to_pdev_id)(struct ath11k_hw_params *hw, int mac_id); | ||||
| 	int (*mac_id_to_srng_id)(struct ath11k_hw_params *hw, int mac_id); | ||||
| }; | ||||
| 
 | ||||
| extern const struct ath11k_hw_ops ipq8074_ops; | ||||
| extern const struct ath11k_hw_ops ipq6018_ops; | ||||
| extern const struct ath11k_hw_ops qca6390_ops; | ||||
| 
 | ||||
| extern const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_ipq8074; | ||||
| extern const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_qca6390; | ||||
| 
 | ||||
| static inline | ||||
| int ath11k_hw_get_mac_from_pdev_id(struct ath11k_hw_params *hw, | ||||
| 				   int pdev_idx) | ||||
| { | ||||
| 	if (hw->hw_ops->get_hw_mac_from_pdev_id) | ||||
| 		return hw->hw_ops->get_hw_mac_from_pdev_id(pdev_idx); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static inline int ath11k_hw_mac_id_to_pdev_id(struct ath11k_hw_params *hw, | ||||
| 					      int mac_id) | ||||
| { | ||||
| 	if (hw->hw_ops->mac_id_to_pdev_id) | ||||
| 		return hw->hw_ops->mac_id_to_pdev_id(hw, mac_id); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static inline int ath11k_hw_mac_id_to_srng_id(struct ath11k_hw_params *hw, | ||||
| 					      int mac_id) | ||||
| { | ||||
| 	if (hw->hw_ops->mac_id_to_srng_id) | ||||
| 		return hw->hw_ops->mac_id_to_srng_id(hw, mac_id); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| struct ath11k_fw_ie { | ||||
| 	__le32 id; | ||||
| 	__le32 len; | ||||
| @ -130,4 +214,51 @@ enum ath11k_bd_ie_type { | ||||
| 	ATH11K_BD_IE_BOARD_EXT = 1, | ||||
| }; | ||||
| 
 | ||||
| struct ath11k_hw_regs { | ||||
| 	u32 hal_tcl1_ring_base_lsb; | ||||
| 	u32 hal_tcl1_ring_base_msb; | ||||
| 	u32 hal_tcl1_ring_id; | ||||
| 	u32 hal_tcl1_ring_misc; | ||||
| 	u32 hal_tcl1_ring_tp_addr_lsb; | ||||
| 	u32 hal_tcl1_ring_tp_addr_msb; | ||||
| 	u32 hal_tcl1_ring_consumer_int_setup_ix0; | ||||
| 	u32 hal_tcl1_ring_consumer_int_setup_ix1; | ||||
| 	u32 hal_tcl1_ring_msi1_base_lsb; | ||||
| 	u32 hal_tcl1_ring_msi1_base_msb; | ||||
| 	u32 hal_tcl1_ring_msi1_data; | ||||
| 	u32 hal_tcl2_ring_base_lsb; | ||||
| 	u32 hal_tcl_ring_base_lsb; | ||||
| 
 | ||||
| 	u32 hal_tcl_status_ring_base_lsb; | ||||
| 
 | ||||
| 	u32 hal_reo1_ring_base_lsb; | ||||
| 	u32 hal_reo1_ring_base_msb; | ||||
| 	u32 hal_reo1_ring_id; | ||||
| 	u32 hal_reo1_ring_misc; | ||||
| 	u32 hal_reo1_ring_hp_addr_lsb; | ||||
| 	u32 hal_reo1_ring_hp_addr_msb; | ||||
| 	u32 hal_reo1_ring_producer_int_setup; | ||||
| 	u32 hal_reo1_ring_msi1_base_lsb; | ||||
| 	u32 hal_reo1_ring_msi1_base_msb; | ||||
| 	u32 hal_reo1_ring_msi1_data; | ||||
| 	u32 hal_reo2_ring_base_lsb; | ||||
| 	u32 hal_reo1_aging_thresh_ix_0; | ||||
| 	u32 hal_reo1_aging_thresh_ix_1; | ||||
| 	u32 hal_reo1_aging_thresh_ix_2; | ||||
| 	u32 hal_reo1_aging_thresh_ix_3; | ||||
| 
 | ||||
| 	u32 hal_reo1_ring_hp; | ||||
| 	u32 hal_reo1_ring_tp; | ||||
| 	u32 hal_reo2_ring_hp; | ||||
| 
 | ||||
| 	u32 hal_reo_tcl_ring_base_lsb; | ||||
| 	u32 hal_reo_tcl_ring_hp; | ||||
| 
 | ||||
| 	u32 hal_reo_status_ring_base_lsb; | ||||
| 	u32 hal_reo_status_hp; | ||||
| }; | ||||
| 
 | ||||
| extern const struct ath11k_hw_regs ipq8074_regs; | ||||
| extern const struct ath11k_hw_regs qca6390_regs; | ||||
| 
 | ||||
| #endif | ||||
|  | ||||
| @ -244,6 +244,9 @@ static const u32 ath11k_smps_map[] = { | ||||
| 	[WLAN_HT_CAP_SM_PS_DISABLED] = WMI_PEER_SMPS_PS_NONE, | ||||
| }; | ||||
| 
 | ||||
| static int ath11k_start_vdev_delay(struct ieee80211_hw *hw, | ||||
| 				   struct ieee80211_vif *vif); | ||||
| 
 | ||||
| u8 ath11k_mac_bw_to_mac80211_bw(u8 bw) | ||||
| { | ||||
| 	u8 ret = 0; | ||||
| @ -521,6 +524,11 @@ struct ath11k *ath11k_mac_get_ar_by_pdev_id(struct ath11k_base *ab, u32 pdev_id) | ||||
| 	int i; | ||||
| 	struct ath11k_pdev *pdev; | ||||
| 
 | ||||
| 	if (ab->hw_params.single_pdev_only) { | ||||
| 		pdev = rcu_dereference(ab->pdevs_active[0]); | ||||
| 		return pdev ? pdev->ar : NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	if (WARN_ON(pdev_id > ab->num_radios)) | ||||
| 		return NULL; | ||||
| 
 | ||||
| @ -1138,13 +1146,13 @@ ath11k_peer_assoc_h_vht_limit(u16 tx_mcs_set, | ||||
| 			idx_limit = -1; | ||||
| 
 | ||||
| 		switch (idx_limit) { | ||||
| 		case 0: /* fall through */ | ||||
| 		case 1: /* fall through */ | ||||
| 		case 2: /* fall through */ | ||||
| 		case 3: /* fall through */ | ||||
| 		case 4: /* fall through */ | ||||
| 		case 5: /* fall through */ | ||||
| 		case 6: /* fall through */ | ||||
| 		case 0: | ||||
| 		case 1: | ||||
| 		case 2: | ||||
| 		case 3: | ||||
| 		case 4: | ||||
| 		case 5: | ||||
| 		case 6: | ||||
| 		case 7: | ||||
| 			mcs = IEEE80211_VHT_MCS_SUPPORT_0_7; | ||||
| 			break; | ||||
| @ -1156,7 +1164,7 @@ ath11k_peer_assoc_h_vht_limit(u16 tx_mcs_set, | ||||
| 			break; | ||||
| 		default: | ||||
| 			WARN_ON(1); | ||||
| 			/* fall through */ | ||||
| 			fallthrough; | ||||
| 		case -1: | ||||
| 			mcs = IEEE80211_VHT_MCS_NOT_SUPPORTED; | ||||
| 			break; | ||||
| @ -1339,7 +1347,7 @@ static void ath11k_peer_assoc_h_he(struct ath11k *ar, | ||||
| 		arg->peer_he_tx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_160] = v; | ||||
| 
 | ||||
| 		arg->peer_he_mcs_count++; | ||||
| 		/* fall through */ | ||||
| 		fallthrough; | ||||
| 
 | ||||
| 	default: | ||||
| 		v = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_80); | ||||
| @ -2114,7 +2122,7 @@ void __ath11k_mac_scan_finish(struct ath11k *ar) | ||||
| 		} else if (ar->scan.roc_notify) { | ||||
| 			ieee80211_remain_on_channel_expired(ar->hw); | ||||
| 		} | ||||
| 		/* fall through */ | ||||
| 		fallthrough; | ||||
| 	case ATH11K_SCAN_STARTING: | ||||
| 		ar->scan.state = ATH11K_SCAN_IDLE; | ||||
| 		ar->scan_channel = NULL; | ||||
| @ -2955,6 +2963,14 @@ static int ath11k_mac_station_add(struct ath11k *ar, | ||||
| 		goto free_tx_stats; | ||||
| 	} | ||||
| 
 | ||||
| 	if (ab->hw_params.vdev_start_delay) { | ||||
| 		ret = ath11k_start_vdev_delay(ar->hw, vif); | ||||
| 		if (ret) { | ||||
| 			ath11k_warn(ab, "failed to delay vdev start: %d\n", ret); | ||||
| 			goto free_tx_stats; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| 
 | ||||
| free_tx_stats: | ||||
| @ -3039,10 +3055,6 @@ static int ath11k_mac_op_sta_state(struct ieee80211_hw *hw, | ||||
| 		if (ret) | ||||
| 			ath11k_warn(ar->ab, "Failed to associate station: %pM\n", | ||||
| 				    sta->addr); | ||||
| 		else | ||||
| 			ath11k_info(ar->ab, | ||||
| 				    "Station %pM moved to assoc state\n", | ||||
| 				    sta->addr); | ||||
| 	} else if (old_state == IEEE80211_STA_ASSOC && | ||||
| 		   new_state == IEEE80211_STA_AUTH && | ||||
| 		   (vif->type == NL80211_IFTYPE_AP || | ||||
| @ -3052,10 +3064,6 @@ static int ath11k_mac_op_sta_state(struct ieee80211_hw *hw, | ||||
| 		if (ret) | ||||
| 			ath11k_warn(ar->ab, "Failed to disassociate station: %pM\n", | ||||
| 				    sta->addr); | ||||
| 		else | ||||
| 			ath11k_info(ar->ab, | ||||
| 				    "Station %pM moved to disassociated state\n", | ||||
| 				    sta->addr); | ||||
| 	} | ||||
| 
 | ||||
| 	mutex_unlock(&ar->conf_mutex); | ||||
| @ -4057,6 +4065,8 @@ void ath11k_mac_drain_tx(struct ath11k *ar) | ||||
| static int ath11k_mac_config_mon_status_default(struct ath11k *ar, bool enable) | ||||
| { | ||||
| 	struct htt_rx_ring_tlv_filter tlv_filter = {0}; | ||||
| 	struct ath11k_base *ab = ar->ab; | ||||
| 	int i, ret = 0; | ||||
| 	u32 ring_id; | ||||
| 
 | ||||
| 	if (enable) { | ||||
| @ -4064,11 +4074,16 @@ static int ath11k_mac_config_mon_status_default(struct ath11k *ar, bool enable) | ||||
| 		tlv_filter.rx_filter = ath11k_debug_rx_filter(ar); | ||||
| 	} | ||||
| 
 | ||||
| 	ring_id = ar->dp.rx_mon_status_refill_ring.refill_buf_ring.ring_id; | ||||
| 	for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { | ||||
| 		ring_id = ar->dp.rx_mon_status_refill_ring[i].refill_buf_ring.ring_id; | ||||
| 		ret = ath11k_dp_tx_htt_rx_filter_setup(ar->ab, ring_id, | ||||
| 						       ar->dp.mac_id + i, | ||||
| 						       HAL_RXDMA_MONITOR_STATUS, | ||||
| 						       DP_RX_BUFFER_SIZE, | ||||
| 						       &tlv_filter); | ||||
| 	} | ||||
| 
 | ||||
| 	return ath11k_dp_tx_htt_rx_filter_setup(ar->ab, ring_id, ar->dp.mac_id, | ||||
| 						HAL_RXDMA_MONITOR_STATUS, | ||||
| 						DP_RX_BUFFER_SIZE, &tlv_filter); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static int ath11k_mac_op_start(struct ieee80211_hw *hw) | ||||
| @ -4368,7 +4383,7 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw, | ||||
| 		break; | ||||
| 	case NL80211_IFTYPE_MESH_POINT: | ||||
| 		arvif->vdev_subtype = WMI_VDEV_SUBTYPE_MESH_11S; | ||||
| 		/* fall through */ | ||||
| 		fallthrough; | ||||
| 	case NL80211_IFTYPE_AP: | ||||
| 		arvif->vdev_type = WMI_VDEV_TYPE_AP; | ||||
| 		break; | ||||
| @ -5112,6 +5127,39 @@ unlock: | ||||
| 	mutex_unlock(&ar->conf_mutex); | ||||
| } | ||||
| 
 | ||||
| static int ath11k_start_vdev_delay(struct ieee80211_hw *hw, | ||||
| 				   struct ieee80211_vif *vif) | ||||
| { | ||||
| 	struct ath11k *ar = hw->priv; | ||||
| 	struct ath11k_base *ab = ar->ab; | ||||
| 	struct ath11k_vif *arvif = (void *)vif->drv_priv; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	if (WARN_ON(arvif->is_started)) | ||||
| 		return -EBUSY; | ||||
| 
 | ||||
| 	ret = ath11k_mac_vdev_start(arvif, &arvif->chanctx.def); | ||||
| 	if (ret) { | ||||
| 		ath11k_warn(ab, "failed to start vdev %i addr %pM on freq %d: %d\n", | ||||
| 			    arvif->vdev_id, vif->addr, | ||||
| 			    arvif->chanctx.def.chan->center_freq, ret); | ||||
| 		return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) { | ||||
| 		ret = ath11k_monitor_vdev_up(ar, arvif->vdev_id); | ||||
| 		if (ret) { | ||||
| 			ath11k_warn(ab, "failed put monitor up: %d\n", ret); | ||||
| 			return ret; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	arvif->is_started = true; | ||||
| 
 | ||||
| 	/* TODO: Setup ps and cts/rts protection */ | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| ath11k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, | ||||
| 				 struct ieee80211_vif *vif, | ||||
| @ -5128,6 +5176,13 @@ ath11k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, | ||||
| 		   "mac chanctx assign ptr %pK vdev_id %i\n", | ||||
| 		   ctx, arvif->vdev_id); | ||||
| 
 | ||||
| 	/* for QCA6390 bss peer must be created before vdev_start */ | ||||
| 	if (ab->hw_params.vdev_start_delay) { | ||||
| 		memcpy(&arvif->chanctx, ctx, sizeof(*ctx)); | ||||
| 		mutex_unlock(&ar->conf_mutex); | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	if (WARN_ON(arvif->is_started)) { | ||||
| 		mutex_unlock(&ar->conf_mutex); | ||||
| 		return -EBUSY; | ||||
| @ -5829,12 +5884,29 @@ static void ath11k_mac_update_ch_list(struct ath11k *ar, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static u32 ath11k_get_phy_id(struct ath11k *ar, u32 band) | ||||
| { | ||||
| 	struct ath11k_pdev *pdev = ar->pdev; | ||||
| 	struct ath11k_pdev_cap *pdev_cap = &pdev->cap; | ||||
| 
 | ||||
| 	if (band == WMI_HOST_WLAN_2G_CAP) | ||||
| 		return pdev_cap->band[NL80211_BAND_2GHZ].phy_id; | ||||
| 
 | ||||
| 	if (band == WMI_HOST_WLAN_5G_CAP) | ||||
| 		return pdev_cap->band[NL80211_BAND_5GHZ].phy_id; | ||||
| 
 | ||||
| 	ath11k_warn(ar->ab, "unsupported phy cap:%d\n", band); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int ath11k_mac_setup_channels_rates(struct ath11k *ar, | ||||
| 					   u32 supported_bands) | ||||
| { | ||||
| 	struct ieee80211_supported_band *band; | ||||
| 	struct ath11k_hal_reg_capabilities_ext *reg_cap; | ||||
| 	void *channels; | ||||
| 	u32 phy_id; | ||||
| 
 | ||||
| 	BUILD_BUG_ON((ARRAY_SIZE(ath11k_2ghz_channels) + | ||||
| 		      ARRAY_SIZE(ath11k_5ghz_channels) + | ||||
| @ -5857,6 +5929,11 @@ static int ath11k_mac_setup_channels_rates(struct ath11k *ar, | ||||
| 		band->n_bitrates = ath11k_g_rates_size; | ||||
| 		band->bitrates = ath11k_g_rates; | ||||
| 		ar->hw->wiphy->bands[NL80211_BAND_2GHZ] = band; | ||||
| 
 | ||||
| 		if (ar->ab->hw_params.single_pdev_only) { | ||||
| 			phy_id = ath11k_get_phy_id(ar, WMI_HOST_WLAN_2G_CAP); | ||||
| 			reg_cap = &ar->ab->hal_reg_cap[phy_id]; | ||||
| 		} | ||||
| 		ath11k_mac_update_ch_list(ar, band, | ||||
| 					  reg_cap->low_2ghz_chan, | ||||
| 					  reg_cap->high_2ghz_chan); | ||||
| @ -5901,6 +5978,12 @@ static int ath11k_mac_setup_channels_rates(struct ath11k *ar, | ||||
| 			band->n_bitrates = ath11k_a_rates_size; | ||||
| 			band->bitrates = ath11k_a_rates; | ||||
| 			ar->hw->wiphy->bands[NL80211_BAND_5GHZ] = band; | ||||
| 
 | ||||
| 			if (ar->ab->hw_params.single_pdev_only) { | ||||
| 				phy_id = ath11k_get_phy_id(ar, WMI_HOST_WLAN_5G_CAP); | ||||
| 				reg_cap = &ar->ab->hal_reg_cap[phy_id]; | ||||
| 			} | ||||
| 
 | ||||
| 			ath11k_mac_update_ch_list(ar, band, | ||||
| 						  reg_cap->low_5ghz_chan, | ||||
| 						  reg_cap->high_5ghz_chan); | ||||
| @ -6194,7 +6277,7 @@ int ath11k_mac_allocate(struct ath11k_base *ab) | ||||
| 		ar->ab = ab; | ||||
| 		ar->pdev = pdev; | ||||
| 		ar->pdev_idx = i; | ||||
| 		ar->lmac_id = ath11k_core_get_hw_mac_id(ab, i); | ||||
| 		ar->lmac_id = ath11k_hw_get_mac_from_pdev_id(&ab->hw_params, i); | ||||
| 
 | ||||
| 		ar->wmi = &ab->wmi_ab.wmi[i]; | ||||
| 		/* FIXME wmi[0] is already initialized during attach,
 | ||||
|  | ||||
							
								
								
									
										467
									
								
								drivers/net/wireless/ath/ath11k/mhi.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										467
									
								
								drivers/net/wireless/ath/ath11k/mhi.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,467 @@ | ||||
| // SPDX-License-Identifier: BSD-3-Clause-Clear
 | ||||
| /* Copyright (c) 2020 The Linux Foundation. All rights reserved. */ | ||||
| 
 | ||||
| #include <linux/msi.h> | ||||
| #include <linux/pci.h> | ||||
| 
 | ||||
| #include "core.h" | ||||
| #include "debug.h" | ||||
| #include "mhi.h" | ||||
| 
 | ||||
| #define MHI_TIMEOUT_DEFAULT_MS	90000 | ||||
| 
 | ||||
| static struct mhi_channel_config ath11k_mhi_channels[] = { | ||||
| 	{ | ||||
| 		.num = 0, | ||||
| 		.name = "LOOPBACK", | ||||
| 		.num_elements = 32, | ||||
| 		.event_ring = 0, | ||||
| 		.dir = DMA_TO_DEVICE, | ||||
| 		.ee_mask = 0x4, | ||||
| 		.pollcfg = 0, | ||||
| 		.doorbell = MHI_DB_BRST_DISABLE, | ||||
| 		.lpm_notify = false, | ||||
| 		.offload_channel = false, | ||||
| 		.doorbell_mode_switch = false, | ||||
| 		.auto_queue = false, | ||||
| 		.auto_start = false, | ||||
| 	}, | ||||
| 	{ | ||||
| 		.num = 1, | ||||
| 		.name = "LOOPBACK", | ||||
| 		.num_elements = 32, | ||||
| 		.event_ring = 0, | ||||
| 		.dir = DMA_FROM_DEVICE, | ||||
| 		.ee_mask = 0x4, | ||||
| 		.pollcfg = 0, | ||||
| 		.doorbell = MHI_DB_BRST_DISABLE, | ||||
| 		.lpm_notify = false, | ||||
| 		.offload_channel = false, | ||||
| 		.doorbell_mode_switch = false, | ||||
| 		.auto_queue = false, | ||||
| 		.auto_start = false, | ||||
| 	}, | ||||
| 	{ | ||||
| 		.num = 20, | ||||
| 		.name = "IPCR", | ||||
| 		.num_elements = 64, | ||||
| 		.event_ring = 1, | ||||
| 		.dir = DMA_TO_DEVICE, | ||||
| 		.ee_mask = 0x4, | ||||
| 		.pollcfg = 0, | ||||
| 		.doorbell = MHI_DB_BRST_DISABLE, | ||||
| 		.lpm_notify = false, | ||||
| 		.offload_channel = false, | ||||
| 		.doorbell_mode_switch = false, | ||||
| 		.auto_queue = false, | ||||
| 		.auto_start = true, | ||||
| 	}, | ||||
| 	{ | ||||
| 		.num = 21, | ||||
| 		.name = "IPCR", | ||||
| 		.num_elements = 64, | ||||
| 		.event_ring = 1, | ||||
| 		.dir = DMA_FROM_DEVICE, | ||||
| 		.ee_mask = 0x4, | ||||
| 		.pollcfg = 0, | ||||
| 		.doorbell = MHI_DB_BRST_DISABLE, | ||||
| 		.lpm_notify = false, | ||||
| 		.offload_channel = false, | ||||
| 		.doorbell_mode_switch = false, | ||||
| 		.auto_queue = true, | ||||
| 		.auto_start = true, | ||||
| 	}, | ||||
| }; | ||||
| 
 | ||||
| static struct mhi_event_config ath11k_mhi_events[] = { | ||||
| 	{ | ||||
| 		.num_elements = 32, | ||||
| 		.irq_moderation_ms = 0, | ||||
| 		.irq = 1, | ||||
| 		.mode = MHI_DB_BRST_DISABLE, | ||||
| 		.data_type = MHI_ER_CTRL, | ||||
| 		.hardware_event = false, | ||||
| 		.client_managed = false, | ||||
| 		.offload_channel = false, | ||||
| 	}, | ||||
| 	{ | ||||
| 		.num_elements = 256, | ||||
| 		.irq_moderation_ms = 1, | ||||
| 		.irq = 2, | ||||
| 		.mode = MHI_DB_BRST_DISABLE, | ||||
| 		.priority = 1, | ||||
| 		.hardware_event = false, | ||||
| 		.client_managed = false, | ||||
| 		.offload_channel = false, | ||||
| 	}, | ||||
| }; | ||||
| 
 | ||||
| static struct mhi_controller_config ath11k_mhi_config = { | ||||
| 	.max_channels = 128, | ||||
| 	.timeout_ms = 2000, | ||||
| 	.use_bounce_buf = false, | ||||
| 	.buf_len = 0, | ||||
| 	.num_channels = ARRAY_SIZE(ath11k_mhi_channels), | ||||
| 	.ch_cfg = ath11k_mhi_channels, | ||||
| 	.num_events = ARRAY_SIZE(ath11k_mhi_events), | ||||
| 	.event_cfg = ath11k_mhi_events, | ||||
| }; | ||||
| 
 | ||||
| void ath11k_mhi_set_mhictrl_reset(struct ath11k_base *ab) | ||||
| { | ||||
| 	u32 val; | ||||
| 
 | ||||
| 	val = ath11k_pci_read32(ab, MHISTATUS); | ||||
| 
 | ||||
| 	ath11k_dbg(ab, ATH11K_DBG_PCI, "MHISTATUS 0x%x\n", val); | ||||
| 
 | ||||
| 	/* Observed on QCA6390 that after SOC_GLOBAL_RESET, MHISTATUS
 | ||||
| 	 * has SYSERR bit set and thus need to set MHICTRL_RESET | ||||
| 	 * to clear SYSERR. | ||||
| 	 */ | ||||
| 	ath11k_pci_write32(ab, MHICTRL, MHICTRL_RESET_MASK); | ||||
| 
 | ||||
| 	mdelay(10); | ||||
| } | ||||
| 
 | ||||
| static void ath11k_mhi_reset_txvecdb(struct ath11k_base *ab) | ||||
| { | ||||
| 	ath11k_pci_write32(ab, PCIE_TXVECDB, 0); | ||||
| } | ||||
| 
 | ||||
| static void ath11k_mhi_reset_txvecstatus(struct ath11k_base *ab) | ||||
| { | ||||
| 	ath11k_pci_write32(ab, PCIE_TXVECSTATUS, 0); | ||||
| } | ||||
| 
 | ||||
| static void ath11k_mhi_reset_rxvecdb(struct ath11k_base *ab) | ||||
| { | ||||
| 	ath11k_pci_write32(ab, PCIE_RXVECDB, 0); | ||||
| } | ||||
| 
 | ||||
| static void ath11k_mhi_reset_rxvecstatus(struct ath11k_base *ab) | ||||
| { | ||||
| 	ath11k_pci_write32(ab, PCIE_RXVECSTATUS, 0); | ||||
| } | ||||
| 
 | ||||
| void ath11k_mhi_clear_vector(struct ath11k_base *ab) | ||||
| { | ||||
| 	ath11k_mhi_reset_txvecdb(ab); | ||||
| 	ath11k_mhi_reset_txvecstatus(ab); | ||||
| 	ath11k_mhi_reset_rxvecdb(ab); | ||||
| 	ath11k_mhi_reset_rxvecstatus(ab); | ||||
| } | ||||
| 
 | ||||
| static int ath11k_mhi_get_msi(struct ath11k_pci *ab_pci) | ||||
| { | ||||
| 	struct ath11k_base *ab = ab_pci->ab; | ||||
| 	u32 user_base_data, base_vector; | ||||
| 	int ret, num_vectors, i; | ||||
| 	int *irq; | ||||
| 
 | ||||
| 	ret = ath11k_pci_get_user_msi_assignment(ab_pci, | ||||
| 						 "MHI", &num_vectors, | ||||
| 						 &user_base_data, &base_vector); | ||||
| 	if (ret) | ||||
| 		return ret; | ||||
| 
 | ||||
| 	ath11k_dbg(ab, ATH11K_DBG_PCI, "Number of assigned MSI for MHI is %d, base vector is %d\n", | ||||
| 		   num_vectors, base_vector); | ||||
| 
 | ||||
| 	irq = kcalloc(num_vectors, sizeof(int), GFP_KERNEL); | ||||
| 	if (!irq) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	for (i = 0; i < num_vectors; i++) | ||||
| 		irq[i] = ath11k_pci_get_msi_irq(ab->dev, | ||||
| 						base_vector + i); | ||||
| 
 | ||||
| 	ab_pci->mhi_ctrl->irq = irq; | ||||
| 	ab_pci->mhi_ctrl->nr_irqs = num_vectors; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int ath11k_mhi_op_runtime_get(struct mhi_controller *mhi_cntrl) | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static void ath11k_mhi_op_runtime_put(struct mhi_controller *mhi_cntrl) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| static void ath11k_mhi_op_status_cb(struct mhi_controller *mhi_cntrl, | ||||
| 				    enum mhi_callback cb) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| static int ath11k_mhi_op_read_reg(struct mhi_controller *mhi_cntrl, | ||||
| 				  void __iomem *addr, | ||||
| 				  u32 *out) | ||||
| { | ||||
| 	*out = readl(addr); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static void ath11k_mhi_op_write_reg(struct mhi_controller *mhi_cntrl, | ||||
| 				    void __iomem *addr, | ||||
| 				    u32 val) | ||||
| { | ||||
| 	writel(val, addr); | ||||
| } | ||||
| 
 | ||||
| int ath11k_mhi_register(struct ath11k_pci *ab_pci) | ||||
| { | ||||
| 	struct ath11k_base *ab = ab_pci->ab; | ||||
| 	struct mhi_controller *mhi_ctrl; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	mhi_ctrl = kzalloc(sizeof(*mhi_ctrl), GFP_KERNEL); | ||||
| 	if (!mhi_ctrl) | ||||
| 		return PTR_ERR(mhi_ctrl); | ||||
| 
 | ||||
| 	ath11k_core_create_firmware_path(ab, ATH11K_AMSS_FILE, | ||||
| 					 ab_pci->amss_path, | ||||
| 					 sizeof(ab_pci->amss_path)); | ||||
| 
 | ||||
| 	ab_pci->mhi_ctrl = mhi_ctrl; | ||||
| 	mhi_ctrl->cntrl_dev = ab->dev; | ||||
| 	mhi_ctrl->fw_image = ab_pci->amss_path; | ||||
| 	mhi_ctrl->regs = ab->mem; | ||||
| 
 | ||||
| 	ret = ath11k_mhi_get_msi(ab_pci); | ||||
| 	if (ret) { | ||||
| 		ath11k_err(ab, "failed to get msi for mhi\n"); | ||||
| 		kfree(mhi_ctrl); | ||||
| 		return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	mhi_ctrl->iova_start = 0; | ||||
| 	mhi_ctrl->iova_stop = 0xffffffff; | ||||
| 	mhi_ctrl->sbl_size = SZ_512K; | ||||
| 	mhi_ctrl->seg_len = SZ_512K; | ||||
| 	mhi_ctrl->fbc_download = true; | ||||
| 	mhi_ctrl->runtime_get = ath11k_mhi_op_runtime_get; | ||||
| 	mhi_ctrl->runtime_put = ath11k_mhi_op_runtime_put; | ||||
| 	mhi_ctrl->status_cb = ath11k_mhi_op_status_cb; | ||||
| 	mhi_ctrl->read_reg = ath11k_mhi_op_read_reg; | ||||
| 	mhi_ctrl->write_reg = ath11k_mhi_op_write_reg; | ||||
| 
 | ||||
| 	ret = mhi_register_controller(mhi_ctrl, &ath11k_mhi_config); | ||||
| 	if (ret) { | ||||
| 		ath11k_err(ab, "failed to register to mhi bus, err = %d\n", ret); | ||||
| 		kfree(mhi_ctrl); | ||||
| 		return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| void ath11k_mhi_unregister(struct ath11k_pci *ab_pci) | ||||
| { | ||||
| 	struct mhi_controller *mhi_ctrl = ab_pci->mhi_ctrl; | ||||
| 
 | ||||
| 	mhi_unregister_controller(mhi_ctrl); | ||||
| 	kfree(mhi_ctrl->irq); | ||||
| } | ||||
| 
 | ||||
| static char *ath11k_mhi_state_to_str(enum ath11k_mhi_state mhi_state) | ||||
| { | ||||
| 	switch (mhi_state) { | ||||
| 	case ATH11K_MHI_INIT: | ||||
| 		return "INIT"; | ||||
| 	case ATH11K_MHI_DEINIT: | ||||
| 		return "DEINIT"; | ||||
| 	case ATH11K_MHI_POWER_ON: | ||||
| 		return "POWER_ON"; | ||||
| 	case ATH11K_MHI_POWER_OFF: | ||||
| 		return "POWER_OFF"; | ||||
| 	case ATH11K_MHI_FORCE_POWER_OFF: | ||||
| 		return "FORCE_POWER_OFF"; | ||||
| 	case ATH11K_MHI_SUSPEND: | ||||
| 		return "SUSPEND"; | ||||
| 	case ATH11K_MHI_RESUME: | ||||
| 		return "RESUME"; | ||||
| 	case ATH11K_MHI_TRIGGER_RDDM: | ||||
| 		return "TRIGGER_RDDM"; | ||||
| 	case ATH11K_MHI_RDDM_DONE: | ||||
| 		return "RDDM_DONE"; | ||||
| 	default: | ||||
| 		return "UNKNOWN"; | ||||
| 	} | ||||
| }; | ||||
| 
 | ||||
| static void ath11k_mhi_set_state_bit(struct ath11k_pci *ab_pci, | ||||
| 				     enum ath11k_mhi_state mhi_state) | ||||
| { | ||||
| 	struct ath11k_base *ab = ab_pci->ab; | ||||
| 
 | ||||
| 	switch (mhi_state) { | ||||
| 	case ATH11K_MHI_INIT: | ||||
| 		set_bit(ATH11K_MHI_INIT, &ab_pci->mhi_state); | ||||
| 		break; | ||||
| 	case ATH11K_MHI_DEINIT: | ||||
| 		clear_bit(ATH11K_MHI_INIT, &ab_pci->mhi_state); | ||||
| 		break; | ||||
| 	case ATH11K_MHI_POWER_ON: | ||||
| 		set_bit(ATH11K_MHI_POWER_ON, &ab_pci->mhi_state); | ||||
| 		break; | ||||
| 	case ATH11K_MHI_POWER_OFF: | ||||
| 	case ATH11K_MHI_FORCE_POWER_OFF: | ||||
| 		clear_bit(ATH11K_MHI_POWER_ON, &ab_pci->mhi_state); | ||||
| 		clear_bit(ATH11K_MHI_TRIGGER_RDDM, &ab_pci->mhi_state); | ||||
| 		clear_bit(ATH11K_MHI_RDDM_DONE, &ab_pci->mhi_state); | ||||
| 		break; | ||||
| 	case ATH11K_MHI_SUSPEND: | ||||
| 		set_bit(ATH11K_MHI_SUSPEND, &ab_pci->mhi_state); | ||||
| 		break; | ||||
| 	case ATH11K_MHI_RESUME: | ||||
| 		clear_bit(ATH11K_MHI_SUSPEND, &ab_pci->mhi_state); | ||||
| 		break; | ||||
| 	case ATH11K_MHI_TRIGGER_RDDM: | ||||
| 		set_bit(ATH11K_MHI_TRIGGER_RDDM, &ab_pci->mhi_state); | ||||
| 		break; | ||||
| 	case ATH11K_MHI_RDDM_DONE: | ||||
| 		set_bit(ATH11K_MHI_RDDM_DONE, &ab_pci->mhi_state); | ||||
| 		break; | ||||
| 	default: | ||||
| 		ath11k_err(ab, "unhandled mhi state (%d)\n", mhi_state); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static int ath11k_mhi_check_state_bit(struct ath11k_pci *ab_pci, | ||||
| 				      enum ath11k_mhi_state mhi_state) | ||||
| { | ||||
| 	struct ath11k_base *ab = ab_pci->ab; | ||||
| 
 | ||||
| 	switch (mhi_state) { | ||||
| 	case ATH11K_MHI_INIT: | ||||
| 		if (!test_bit(ATH11K_MHI_INIT, &ab_pci->mhi_state)) | ||||
| 			return 0; | ||||
| 		break; | ||||
| 	case ATH11K_MHI_DEINIT: | ||||
| 	case ATH11K_MHI_POWER_ON: | ||||
| 		if (test_bit(ATH11K_MHI_INIT, &ab_pci->mhi_state) && | ||||
| 		    !test_bit(ATH11K_MHI_POWER_ON, &ab_pci->mhi_state)) | ||||
| 			return 0; | ||||
| 		break; | ||||
| 	case ATH11K_MHI_FORCE_POWER_OFF: | ||||
| 		if (test_bit(ATH11K_MHI_POWER_ON, &ab_pci->mhi_state)) | ||||
| 			return 0; | ||||
| 		break; | ||||
| 	case ATH11K_MHI_POWER_OFF: | ||||
| 	case ATH11K_MHI_SUSPEND: | ||||
| 		if (test_bit(ATH11K_MHI_POWER_ON, &ab_pci->mhi_state) && | ||||
| 		    !test_bit(ATH11K_MHI_SUSPEND, &ab_pci->mhi_state)) | ||||
| 			return 0; | ||||
| 		break; | ||||
| 	case ATH11K_MHI_RESUME: | ||||
| 		if (test_bit(ATH11K_MHI_SUSPEND, &ab_pci->mhi_state)) | ||||
| 			return 0; | ||||
| 		break; | ||||
| 	case ATH11K_MHI_TRIGGER_RDDM: | ||||
| 		if (test_bit(ATH11K_MHI_POWER_ON, &ab_pci->mhi_state) && | ||||
| 		    !test_bit(ATH11K_MHI_TRIGGER_RDDM, &ab_pci->mhi_state)) | ||||
| 			return 0; | ||||
| 		break; | ||||
| 	case ATH11K_MHI_RDDM_DONE: | ||||
| 		return 0; | ||||
| 	default: | ||||
| 		ath11k_err(ab, "unhandled mhi state: %s(%d)\n", | ||||
| 			   ath11k_mhi_state_to_str(mhi_state), mhi_state); | ||||
| 	} | ||||
| 
 | ||||
| 	ath11k_err(ab, "failed to set mhi state %s(%d) in current mhi state (0x%lx)\n", | ||||
| 		   ath11k_mhi_state_to_str(mhi_state), mhi_state, | ||||
| 		   ab_pci->mhi_state); | ||||
| 
 | ||||
| 	return -EINVAL; | ||||
| } | ||||
| 
 | ||||
| static int ath11k_mhi_set_state(struct ath11k_pci *ab_pci, | ||||
| 				enum ath11k_mhi_state mhi_state) | ||||
| { | ||||
| 	struct ath11k_base *ab = ab_pci->ab; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	ret = ath11k_mhi_check_state_bit(ab_pci, mhi_state); | ||||
| 	if (ret) | ||||
| 		goto out; | ||||
| 
 | ||||
| 	ath11k_dbg(ab, ATH11K_DBG_PCI, "setting mhi state: %s(%d)\n", | ||||
| 		   ath11k_mhi_state_to_str(mhi_state), mhi_state); | ||||
| 
 | ||||
| 	switch (mhi_state) { | ||||
| 	case ATH11K_MHI_INIT: | ||||
| 		ret = mhi_prepare_for_power_up(ab_pci->mhi_ctrl); | ||||
| 		break; | ||||
| 	case ATH11K_MHI_DEINIT: | ||||
| 		mhi_unprepare_after_power_down(ab_pci->mhi_ctrl); | ||||
| 		ret = 0; | ||||
| 		break; | ||||
| 	case ATH11K_MHI_POWER_ON: | ||||
| 		ret = mhi_async_power_up(ab_pci->mhi_ctrl); | ||||
| 		break; | ||||
| 	case ATH11K_MHI_POWER_OFF: | ||||
| 		mhi_power_down(ab_pci->mhi_ctrl, true); | ||||
| 		ret = 0; | ||||
| 		break; | ||||
| 	case ATH11K_MHI_FORCE_POWER_OFF: | ||||
| 		mhi_power_down(ab_pci->mhi_ctrl, false); | ||||
| 		ret = 0; | ||||
| 		break; | ||||
| 	case ATH11K_MHI_SUSPEND: | ||||
| 		break; | ||||
| 	case ATH11K_MHI_RESUME: | ||||
| 		break; | ||||
| 	case ATH11K_MHI_TRIGGER_RDDM: | ||||
| 		ret = mhi_force_rddm_mode(ab_pci->mhi_ctrl); | ||||
| 		break; | ||||
| 	case ATH11K_MHI_RDDM_DONE: | ||||
| 		break; | ||||
| 	default: | ||||
| 		ath11k_err(ab, "unhandled MHI state (%d)\n", mhi_state); | ||||
| 		ret = -EINVAL; | ||||
| 	} | ||||
| 
 | ||||
| 	if (ret) | ||||
| 		goto out; | ||||
| 
 | ||||
| 	ath11k_mhi_set_state_bit(ab_pci, mhi_state); | ||||
| 
 | ||||
| 	return 0; | ||||
| 
 | ||||
| out: | ||||
| 	ath11k_err(ab, "failed to set mhi state: %s(%d)\n", | ||||
| 		   ath11k_mhi_state_to_str(mhi_state), mhi_state); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| int ath11k_mhi_start(struct ath11k_pci *ab_pci) | ||||
| { | ||||
| 	int ret; | ||||
| 
 | ||||
| 	ab_pci->mhi_ctrl->timeout_ms = MHI_TIMEOUT_DEFAULT_MS; | ||||
| 
 | ||||
| 	ret = ath11k_mhi_set_state(ab_pci, ATH11K_MHI_INIT); | ||||
| 	if (ret) | ||||
| 		goto out; | ||||
| 
 | ||||
| 	ret = ath11k_mhi_set_state(ab_pci, ATH11K_MHI_POWER_ON); | ||||
| 	if (ret) | ||||
| 		goto out; | ||||
| 
 | ||||
| 	return 0; | ||||
| 
 | ||||
| out: | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| void ath11k_mhi_stop(struct ath11k_pci *ab_pci) | ||||
| { | ||||
| 	ath11k_mhi_set_state(ab_pci, ATH11K_MHI_POWER_OFF); | ||||
| 	ath11k_mhi_set_state(ab_pci, ATH11K_MHI_DEINIT); | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										39
									
								
								drivers/net/wireless/ath/ath11k/mhi.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								drivers/net/wireless/ath/ath11k/mhi.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,39 @@ | ||||
| /* SPDX-License-Identifier: BSD-3-Clause-Clear */ | ||||
| /*
 | ||||
|  * Copyright (c) 2020 The Linux Foundation. All rights reserved. | ||||
|  */ | ||||
| #ifndef _ATH11K_MHI_H | ||||
| #define _ATH11K_MHI_H | ||||
| 
 | ||||
| #include "pci.h" | ||||
| 
 | ||||
| #define PCIE_TXVECDB				0x360 | ||||
| #define PCIE_TXVECSTATUS			0x368 | ||||
| #define PCIE_RXVECDB				0x394 | ||||
| #define PCIE_RXVECSTATUS			0x39C | ||||
| 
 | ||||
| #define MHISTATUS				0x48 | ||||
| #define MHICTRL					0x38 | ||||
| #define MHICTRL_RESET_MASK			0x2 | ||||
| 
 | ||||
| enum ath11k_mhi_state { | ||||
| 	ATH11K_MHI_INIT, | ||||
| 	ATH11K_MHI_DEINIT, | ||||
| 	ATH11K_MHI_POWER_ON, | ||||
| 	ATH11K_MHI_POWER_OFF, | ||||
| 	ATH11K_MHI_FORCE_POWER_OFF, | ||||
| 	ATH11K_MHI_SUSPEND, | ||||
| 	ATH11K_MHI_RESUME, | ||||
| 	ATH11K_MHI_TRIGGER_RDDM, | ||||
| 	ATH11K_MHI_RDDM, | ||||
| 	ATH11K_MHI_RDDM_DONE, | ||||
| }; | ||||
| 
 | ||||
| int ath11k_mhi_start(struct ath11k_pci *ar_pci); | ||||
| void ath11k_mhi_stop(struct ath11k_pci *ar_pci); | ||||
| int ath11k_mhi_register(struct ath11k_pci *ar_pci); | ||||
| void ath11k_mhi_unregister(struct ath11k_pci *ar_pci); | ||||
| void ath11k_mhi_set_mhictrl_reset(struct ath11k_base *ab); | ||||
| void ath11k_mhi_clear_vector(struct ath11k_base *ab); | ||||
| 
 | ||||
| #endif | ||||
							
								
								
									
										1173
									
								
								drivers/net/wireless/ath/ath11k/pci.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1173
									
								
								drivers/net/wireless/ath/ath11k/pci.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										65
									
								
								drivers/net/wireless/ath/ath11k/pci.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								drivers/net/wireless/ath/ath11k/pci.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,65 @@ | ||||
| /* SPDX-License-Identifier: BSD-3-Clause-Clear */ | ||||
| /*
 | ||||
|  * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. | ||||
|  */ | ||||
| #ifndef _ATH11K_PCI_H | ||||
| #define _ATH11K_PCI_H | ||||
| 
 | ||||
| #include <linux/mhi.h> | ||||
| 
 | ||||
| #include "core.h" | ||||
| 
 | ||||
| #define PCIE_SOC_GLOBAL_RESET			0x3008 | ||||
| #define PCIE_SOC_GLOBAL_RESET_V			1 | ||||
| 
 | ||||
| #define WLAON_WARM_SW_ENTRY			0x1f80504 | ||||
| #define WLAON_SOC_RESET_CAUSE_REG		0x01f8060c | ||||
| 
 | ||||
| #define PCIE_Q6_COOKIE_ADDR			0x01f80500 | ||||
| #define PCIE_Q6_COOKIE_DATA			0xc0000000 | ||||
| 
 | ||||
| /* register to wake the UMAC from power collapse */ | ||||
| #define PCIE_SCRATCH_0_SOC_PCIE_REG		0x4040 | ||||
| 
 | ||||
| /* register used for handshake mechanism to validate UMAC is awake */ | ||||
| #define PCIE_SOC_WAKE_PCIE_LOCAL_REG		0x3004 | ||||
| 
 | ||||
| struct ath11k_msi_user { | ||||
| 	char *name; | ||||
| 	int num_vectors; | ||||
| 	u32 base_vector; | ||||
| }; | ||||
| 
 | ||||
| struct ath11k_msi_config { | ||||
| 	int total_vectors; | ||||
| 	int total_users; | ||||
| 	struct ath11k_msi_user *users; | ||||
| }; | ||||
| 
 | ||||
| struct ath11k_pci { | ||||
| 	struct pci_dev *pdev; | ||||
| 	struct ath11k_base *ab; | ||||
| 	u16 dev_id; | ||||
| 	char amss_path[100]; | ||||
| 	u32 msi_ep_base_data; | ||||
| 	struct mhi_controller *mhi_ctrl; | ||||
| 	unsigned long mhi_state; | ||||
| 	u32 register_window; | ||||
| 
 | ||||
| 	/* protects register_window above */ | ||||
| 	spinlock_t window_lock; | ||||
| }; | ||||
| 
 | ||||
| static inline struct ath11k_pci *ath11k_pci_priv(struct ath11k_base *ab) | ||||
| { | ||||
| 	return (struct ath11k_pci *)ab->drv_priv; | ||||
| } | ||||
| 
 | ||||
| int ath11k_pci_get_user_msi_assignment(struct ath11k_pci *ar_pci, char *user_name, | ||||
| 				       int *num_vectors, u32 *user_base_data, | ||||
| 				       u32 *base_vector); | ||||
| int ath11k_pci_get_msi_irq(struct device *dev, unsigned int vector); | ||||
| void ath11k_pci_write32(struct ath11k_base *ab, u32 offset, u32 value); | ||||
| u32 ath11k_pci_read32(struct ath11k_base *ab, u32 offset); | ||||
| 
 | ||||
| #endif | ||||
| @ -223,9 +223,6 @@ int ath11k_peer_create(struct ath11k *ar, struct ath11k_vif *arvif, | ||||
| 	peer = ath11k_peer_find_by_pdev_idx(ar->ab, ar->pdev_idx, param->peer_addr); | ||||
| 	if (peer) { | ||||
| 		spin_unlock_bh(&ar->ab->base_lock); | ||||
| 		ath11k_info(ar->ab, | ||||
| 			    "ignoring the peer %pM creation on same pdev idx %d\n", | ||||
| 			    param->peer_addr, ar->pdev_idx); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 	spin_unlock_bh(&ar->ab->base_lock); | ||||
|  | ||||
| @ -9,6 +9,9 @@ | ||||
| #include <linux/of.h> | ||||
| #include <linux/firmware.h> | ||||
| 
 | ||||
| #define SLEEP_CLOCK_SELECT_INTERNAL_BIT	0x02 | ||||
| #define HOST_CSTATE_BIT			0x04 | ||||
| 
 | ||||
| static struct qmi_elem_info qmi_wlanfw_host_cap_req_msg_v01_ei[] = { | ||||
| 	{ | ||||
| 		.data_type	= QMI_OPT_FLAG, | ||||
| @ -1516,15 +1519,35 @@ static int ath11k_qmi_host_cap_send(struct ath11k_base *ab) | ||||
| 	req.bdf_support_valid = 1; | ||||
| 	req.bdf_support = 1; | ||||
| 
 | ||||
| 	req.m3_support_valid = 0; | ||||
| 	req.m3_support = 0; | ||||
| 
 | ||||
| 	req.m3_cache_support_valid = 0; | ||||
| 	req.m3_cache_support = 0; | ||||
| 	if (ab->bus_params.m3_fw_support) { | ||||
| 		req.m3_support_valid = 1; | ||||
| 		req.m3_support = 1; | ||||
| 		req.m3_cache_support_valid = 1; | ||||
| 		req.m3_cache_support = 1; | ||||
| 	} else { | ||||
| 		req.m3_support_valid = 0; | ||||
| 		req.m3_support = 0; | ||||
| 		req.m3_cache_support_valid = 0; | ||||
| 		req.m3_cache_support = 0; | ||||
| 	} | ||||
| 
 | ||||
| 	req.cal_done_valid = 1; | ||||
| 	req.cal_done = ab->qmi.cal_done; | ||||
| 
 | ||||
| 	if (ab->hw_params.internal_sleep_clock) { | ||||
| 		req.nm_modem_valid = 1; | ||||
| 
 | ||||
| 		/* Notify firmware that this is non-qualcomm platform. */ | ||||
| 		req.nm_modem |= HOST_CSTATE_BIT; | ||||
| 
 | ||||
| 		/* Notify firmware about the sleep clock selection,
 | ||||
| 		 * nm_modem_bit[1] is used for this purpose. Host driver on | ||||
| 		 * non-qualcomm platforms should select internal sleep | ||||
| 		 * clock. | ||||
| 		 */ | ||||
| 		req.nm_modem |= SLEEP_CLOCK_SELECT_INTERNAL_BIT; | ||||
| 	} | ||||
| 
 | ||||
| 	ret = qmi_txn_init(&ab->qmi.handle, &txn, | ||||
| 			   qmi_wlanfw_host_cap_resp_msg_v01_ei, &resp); | ||||
| 	if (ret < 0) | ||||
| @ -1634,19 +1657,30 @@ static int ath11k_qmi_respond_fw_mem_request(struct ath11k_base *ab) | ||||
| 
 | ||||
| 	memset(&resp, 0, sizeof(resp)); | ||||
| 
 | ||||
| 	req->mem_seg_len = ab->qmi.mem_seg_count; | ||||
| 	/* For QCA6390 by default FW requests a block of ~4M contiguous
 | ||||
| 	 * DMA memory, it's hard to allocate from OS. So host returns | ||||
| 	 * failure to FW and FW will then request mulitple blocks of small | ||||
| 	 * chunk size memory. | ||||
| 	 */ | ||||
| 	if (!ab->bus_params.fixed_mem_region && ab->qmi.mem_seg_count <= 2) { | ||||
| 		ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi delays mem_request %d\n", | ||||
| 			   ab->qmi.mem_seg_count); | ||||
| 		memset(req, 0, sizeof(*req)); | ||||
| 	} else { | ||||
| 		req->mem_seg_len = ab->qmi.mem_seg_count; | ||||
| 
 | ||||
| 		for (i = 0; i < req->mem_seg_len ; i++) { | ||||
| 			req->mem_seg[i].addr = ab->qmi.target_mem[i].paddr; | ||||
| 			req->mem_seg[i].size = ab->qmi.target_mem[i].size; | ||||
| 			req->mem_seg[i].type = ab->qmi.target_mem[i].type; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	ret = qmi_txn_init(&ab->qmi.handle, &txn, | ||||
| 			   qmi_wlanfw_respond_mem_resp_msg_v01_ei, &resp); | ||||
| 	if (ret < 0) | ||||
| 		goto out; | ||||
| 
 | ||||
| 	for (i = 0; i < req->mem_seg_len ; i++) { | ||||
| 		req->mem_seg[i].addr = ab->qmi.target_mem[i].paddr; | ||||
| 		req->mem_seg[i].size = ab->qmi.target_mem[i].size; | ||||
| 		req->mem_seg[i].type = ab->qmi.target_mem[i].type; | ||||
| 	} | ||||
| 
 | ||||
| 	ret = qmi_send_request(&ab->qmi.handle, NULL, &txn, | ||||
| 			       QMI_WLANFW_RESPOND_MEM_REQ_V01, | ||||
| 			       QMI_WLANFW_RESPOND_MEM_REQ_MSG_V01_MAX_LEN, | ||||
| @ -1674,15 +1708,56 @@ out: | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static void ath11k_qmi_free_target_mem_chunk(struct ath11k_base *ab) | ||||
| { | ||||
| 	int i; | ||||
| 
 | ||||
| 	if (ab->bus_params.fixed_mem_region) | ||||
| 		return; | ||||
| 
 | ||||
| 	for (i = 0; i < ab->qmi.mem_seg_count; i++) { | ||||
| 		if (!ab->qmi.target_mem[i].vaddr) | ||||
| 			continue; | ||||
| 
 | ||||
| 		dma_free_coherent(ab->dev, | ||||
| 				  ab->qmi.target_mem[i].size, | ||||
| 				  ab->qmi.target_mem[i].vaddr, | ||||
| 				  ab->qmi.target_mem[i].paddr); | ||||
| 		ab->qmi.target_mem[i].vaddr = NULL; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static int ath11k_qmi_alloc_target_mem_chunk(struct ath11k_base *ab) | ||||
| { | ||||
| 	int i; | ||||
| 	struct target_mem_chunk *chunk; | ||||
| 
 | ||||
| 	for (i = 0; i < ab->qmi.mem_seg_count; i++) { | ||||
| 		chunk = &ab->qmi.target_mem[i]; | ||||
| 		chunk->vaddr = dma_alloc_coherent(ab->dev, | ||||
| 						  chunk->size, | ||||
| 						  &chunk->paddr, | ||||
| 						  GFP_KERNEL); | ||||
| 		if (!chunk->vaddr) { | ||||
| 			ath11k_err(ab, "failed to alloc memory, size: 0x%x, type: %u\n", | ||||
| 				   chunk->size, | ||||
| 				   chunk->type); | ||||
| 			return -EINVAL; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int ath11k_qmi_assign_target_mem_chunk(struct ath11k_base *ab) | ||||
| { | ||||
| 	int i, idx; | ||||
| 
 | ||||
| 	for (i = 0, idx = 0; i < ab->qmi.mem_seg_count; i++) { | ||||
| 		switch (ab->qmi.target_mem[i].type) { | ||||
| 		case BDF_MEM_REGION_TYPE: | ||||
| 			ab->qmi.target_mem[idx].paddr = ATH11K_QMI_BDF_ADDRESS; | ||||
| 			ab->qmi.target_mem[idx].vaddr = ATH11K_QMI_BDF_ADDRESS; | ||||
| 			ab->qmi.target_mem[idx].paddr = ab->hw_params.bdf_addr; | ||||
| 			ab->qmi.target_mem[idx].vaddr = NULL; | ||||
| 			ab->qmi.target_mem[idx].size = ab->qmi.target_mem[i].size; | ||||
| 			ab->qmi.target_mem[idx].type = ab->qmi.target_mem[i].type; | ||||
| 			idx++; | ||||
| @ -1694,7 +1769,7 @@ static int ath11k_qmi_alloc_target_mem_chunk(struct ath11k_base *ab) | ||||
| 			} | ||||
| 			/* TODO ath11k does not support cold boot calibration */ | ||||
| 			ab->qmi.target_mem[idx].paddr = 0; | ||||
| 			ab->qmi.target_mem[idx].vaddr = 0; | ||||
| 			ab->qmi.target_mem[idx].vaddr = NULL; | ||||
| 			ab->qmi.target_mem[idx].size = ab->qmi.target_mem[i].size; | ||||
| 			ab->qmi.target_mem[idx].type = ab->qmi.target_mem[i].type; | ||||
| 			idx++; | ||||
| @ -1772,11 +1847,11 @@ static int ath11k_qmi_request_target_cap(struct ath11k_base *ab) | ||||
| 		strlcpy(ab->qmi.target.fw_build_id, resp.fw_build_id, | ||||
| 			sizeof(ab->qmi.target.fw_build_id)); | ||||
| 
 | ||||
| 	ath11k_info(ab, "qmi target: chip_id: 0x%x, chip_family: 0x%x, board_id: 0x%x, soc_id: 0x%x\n", | ||||
| 	ath11k_info(ab, "chip_id 0x%x chip_family 0x%x board_id 0x%x soc_id 0x%x\n", | ||||
| 		    ab->qmi.target.chip_id, ab->qmi.target.chip_family, | ||||
| 		    ab->qmi.target.board_id, ab->qmi.target.soc_id); | ||||
| 
 | ||||
| 	ath11k_info(ab, "qmi fw_version: 0x%x fw_build_timestamp: %s fw_build_id: %s", | ||||
| 	ath11k_info(ab, "fw_version 0x%x fw_build_timestamp %s fw_build_id %s", | ||||
| 		    ab->qmi.target.fw_version, | ||||
| 		    ab->qmi.target.fw_build_timestamp, | ||||
| 		    ab->qmi.target.fw_build_id); | ||||
| @ -1790,8 +1865,6 @@ ath11k_qmi_prepare_bdf_download(struct ath11k_base *ab, int type, | ||||
| 				struct qmi_wlanfw_bdf_download_req_msg_v01 *req, | ||||
| 				void __iomem *bdf_addr) | ||||
| { | ||||
| 	struct device *dev = ab->dev; | ||||
| 	char filename[ATH11K_QMI_MAX_BDF_FILE_NAME_SIZE]; | ||||
| 	const struct firmware *fw_entry; | ||||
| 	struct ath11k_board_data bd; | ||||
| 	u32 fw_size; | ||||
| @ -1812,11 +1885,10 @@ ath11k_qmi_prepare_bdf_download(struct ath11k_base *ab, int type, | ||||
| 		ath11k_core_free_bdf(ab, &bd); | ||||
| 		break; | ||||
| 	case ATH11K_QMI_FILE_TYPE_CALDATA: | ||||
| 		snprintf(filename, sizeof(filename), | ||||
| 			 "%s/%s", ab->hw_params.fw.dir, ATH11K_QMI_DEFAULT_CAL_FILE_NAME); | ||||
| 		ret = request_firmware(&fw_entry, filename, dev); | ||||
| 		fw_entry = ath11k_core_firmware_request(ab, ATH11K_DEFAULT_CAL_FILE); | ||||
| 		if (ret) { | ||||
| 			ath11k_warn(ab, "qmi failed to load CAL: %s\n", filename); | ||||
| 			ath11k_warn(ab, "failed to load %s: %d\n", | ||||
| 				    ATH11K_DEFAULT_CAL_FILE, ret); | ||||
| 			goto out; | ||||
| 		} | ||||
| 
 | ||||
| @ -1825,8 +1897,6 @@ ath11k_qmi_prepare_bdf_download(struct ath11k_base *ab, int type, | ||||
| 
 | ||||
| 		memcpy_toio(bdf_addr + ATH11K_QMI_CALDATA_OFFSET, | ||||
| 			    fw_entry->data, fw_size); | ||||
| 		ath11k_info(ab, "qmi downloading BDF: %s, size: %zu\n", | ||||
| 			    filename, fw_entry->size); | ||||
| 
 | ||||
| 		release_firmware(fw_entry); | ||||
| 		break; | ||||
| @ -1841,7 +1911,7 @@ out: | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static int ath11k_qmi_load_bdf(struct ath11k_base *ab) | ||||
| static int ath11k_qmi_load_bdf_fixed_addr(struct ath11k_base *ab) | ||||
| { | ||||
| 	struct qmi_wlanfw_bdf_download_req_msg_v01 *req; | ||||
| 	struct qmi_wlanfw_bdf_download_resp_msg_v01 resp; | ||||
| @ -1854,7 +1924,7 @@ static int ath11k_qmi_load_bdf(struct ath11k_base *ab) | ||||
| 		return -ENOMEM; | ||||
| 	memset(&resp, 0, sizeof(resp)); | ||||
| 
 | ||||
| 	bdf_addr = ioremap(ATH11K_QMI_BDF_ADDRESS, ATH11K_QMI_BDF_MAX_SIZE); | ||||
| 	bdf_addr = ioremap(ab->hw_params.bdf_addr, ATH11K_QMI_BDF_MAX_SIZE); | ||||
| 	if (!bdf_addr) { | ||||
| 		ath11k_warn(ab, "qmi ioremap error for BDF\n"); | ||||
| 		ret = -EIO; | ||||
| @ -1905,7 +1975,6 @@ static int ath11k_qmi_load_bdf(struct ath11k_base *ab) | ||||
| 			goto out_qmi_bdf; | ||||
| 		} | ||||
| 	} | ||||
| 	ath11k_info(ab, "qmi BDF downloaded\n"); | ||||
| 
 | ||||
| out_qmi_bdf: | ||||
| 	iounmap(bdf_addr); | ||||
| @ -1914,8 +1983,143 @@ out: | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static int ath11k_qmi_load_bdf_qmi(struct ath11k_base *ab) | ||||
| { | ||||
| 	struct qmi_wlanfw_bdf_download_req_msg_v01 *req; | ||||
| 	struct qmi_wlanfw_bdf_download_resp_msg_v01 resp; | ||||
| 	struct ath11k_board_data bd; | ||||
| 	unsigned int remaining; | ||||
| 	struct qmi_txn txn = {}; | ||||
| 	int ret; | ||||
| 	const u8 *temp; | ||||
| 
 | ||||
| 	req = kzalloc(sizeof(*req), GFP_KERNEL); | ||||
| 	if (!req) | ||||
| 		return -ENOMEM; | ||||
| 	memset(&resp, 0, sizeof(resp)); | ||||
| 
 | ||||
| 	memset(&bd, 0, sizeof(bd)); | ||||
| 	ret = ath11k_core_fetch_bdf(ab, &bd); | ||||
| 	if (ret) { | ||||
| 		ath11k_warn(ab, "qmi failed to load bdf:\n"); | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	temp = bd.data; | ||||
| 	remaining = bd.len; | ||||
| 
 | ||||
| 	while (remaining) { | ||||
| 		req->valid = 1; | ||||
| 		req->file_id_valid = 1; | ||||
| 		req->file_id = ab->qmi.target.board_id; | ||||
| 		req->total_size_valid = 1; | ||||
| 		req->total_size = bd.len; | ||||
| 		req->seg_id_valid = 1; | ||||
| 		req->data_valid = 1; | ||||
| 		req->data_len = ATH11K_QMI_MAX_BDF_FILE_NAME_SIZE; | ||||
| 		req->bdf_type = ATH11K_QMI_BDF_TYPE_BIN; | ||||
| 		req->bdf_type_valid = 1; | ||||
| 		req->end_valid = 1; | ||||
| 		req->end = 0; | ||||
| 
 | ||||
| 		if (remaining > QMI_WLANFW_MAX_DATA_SIZE_V01) { | ||||
| 			req->data_len = QMI_WLANFW_MAX_DATA_SIZE_V01; | ||||
| 		} else { | ||||
| 			req->data_len = remaining; | ||||
| 			req->end = 1; | ||||
| 		} | ||||
| 
 | ||||
| 		memcpy(req->data, temp, req->data_len); | ||||
| 
 | ||||
| 		ret = qmi_txn_init(&ab->qmi.handle, &txn, | ||||
| 				   qmi_wlanfw_bdf_download_resp_msg_v01_ei, | ||||
| 				   &resp); | ||||
| 		if (ret < 0) | ||||
| 			goto out_qmi_bdf; | ||||
| 
 | ||||
| 		ret = qmi_send_request(&ab->qmi.handle, NULL, &txn, | ||||
| 				       QMI_WLANFW_BDF_DOWNLOAD_REQ_V01, | ||||
| 				       QMI_WLANFW_BDF_DOWNLOAD_REQ_MSG_V01_MAX_LEN, | ||||
| 				       qmi_wlanfw_bdf_download_req_msg_v01_ei, req); | ||||
| 		if (ret < 0) { | ||||
| 			qmi_txn_cancel(&txn); | ||||
| 			goto out_qmi_bdf; | ||||
| 		} | ||||
| 
 | ||||
| 		ret = qmi_txn_wait(&txn, msecs_to_jiffies(ATH11K_QMI_WLANFW_TIMEOUT_MS)); | ||||
| 		if (ret < 0) | ||||
| 			goto out_qmi_bdf; | ||||
| 
 | ||||
| 		if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { | ||||
| 			ath11k_warn(ab, "qmi BDF download failed, result: %d, err: %d\n", | ||||
| 				    resp.resp.result, resp.resp.error); | ||||
| 			ret = resp.resp.result; | ||||
| 			goto out_qmi_bdf; | ||||
| 		} | ||||
| 		remaining -= req->data_len; | ||||
| 		temp += req->data_len; | ||||
| 		req->seg_id++; | ||||
| 	} | ||||
| 
 | ||||
| out_qmi_bdf: | ||||
| 	ath11k_core_free_bdf(ab, &bd); | ||||
| 
 | ||||
| out: | ||||
| 	kfree(req); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static int ath11k_qmi_m3_load(struct ath11k_base *ab) | ||||
| { | ||||
| 	struct m3_mem_region *m3_mem = &ab->qmi.m3_mem; | ||||
| 	const struct firmware *fw; | ||||
| 	char path[100]; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	if (m3_mem->vaddr || m3_mem->size) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	fw = ath11k_core_firmware_request(ab, ATH11K_M3_FILE); | ||||
| 	if (IS_ERR(fw)) { | ||||
| 		ret = PTR_ERR(fw); | ||||
| 		ath11k_core_create_firmware_path(ab, ATH11K_M3_FILE, | ||||
| 						 path, sizeof(path)); | ||||
| 		ath11k_err(ab, "failed to load %s: %d\n", path, ret); | ||||
| 		return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	m3_mem->vaddr = dma_alloc_coherent(ab->dev, | ||||
| 					   fw->size, &m3_mem->paddr, | ||||
| 					   GFP_KERNEL); | ||||
| 	if (!m3_mem->vaddr) { | ||||
| 		ath11k_err(ab, "failed to allocate memory for M3 with size %zu\n", | ||||
| 			   fw->size); | ||||
| 		release_firmware(fw); | ||||
| 		return -ENOMEM; | ||||
| 	} | ||||
| 
 | ||||
| 	memcpy(m3_mem->vaddr, fw->data, fw->size); | ||||
| 	m3_mem->size = fw->size; | ||||
| 	release_firmware(fw); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static void ath11k_qmi_m3_free(struct ath11k_base *ab) | ||||
| { | ||||
| 	struct m3_mem_region *m3_mem = &ab->qmi.m3_mem; | ||||
| 
 | ||||
| 	if (!ab->bus_params.m3_fw_support || !m3_mem->vaddr) | ||||
| 		return; | ||||
| 
 | ||||
| 	dma_free_coherent(ab->dev, m3_mem->size, | ||||
| 			  m3_mem->vaddr, m3_mem->paddr); | ||||
| 	m3_mem->vaddr = NULL; | ||||
| } | ||||
| 
 | ||||
| static int ath11k_qmi_wlanfw_m3_info_send(struct ath11k_base *ab) | ||||
| { | ||||
| 	struct m3_mem_region *m3_mem = &ab->qmi.m3_mem; | ||||
| 	struct qmi_wlanfw_m3_info_req_msg_v01 req; | ||||
| 	struct qmi_wlanfw_m3_info_resp_msg_v01 resp; | ||||
| 	struct qmi_txn txn = {}; | ||||
| @ -1923,8 +2127,20 @@ static int ath11k_qmi_wlanfw_m3_info_send(struct ath11k_base *ab) | ||||
| 
 | ||||
| 	memset(&req, 0, sizeof(req)); | ||||
| 	memset(&resp, 0, sizeof(resp)); | ||||
| 	req.addr = 0; | ||||
| 	req.size = 0; | ||||
| 
 | ||||
| 	if (ab->bus_params.m3_fw_support) { | ||||
| 		ret = ath11k_qmi_m3_load(ab); | ||||
| 		if (ret) { | ||||
| 			ath11k_err(ab, "failed to load m3 firmware: %d", ret); | ||||
| 			return ret; | ||||
| 		} | ||||
| 
 | ||||
| 		req.addr = m3_mem->paddr; | ||||
| 		req.size = m3_mem->size; | ||||
| 	} else { | ||||
| 		req.addr = 0; | ||||
| 		req.size = 0; | ||||
| 	} | ||||
| 
 | ||||
| 	ret = qmi_txn_init(&ab->qmi.handle, &txn, | ||||
| 			   qmi_wlanfw_m3_info_resp_msg_v01_ei, &resp); | ||||
| @ -2034,7 +2250,7 @@ static int ath11k_qmi_wlanfw_wlan_cfg_send(struct ath11k_base *ab) | ||||
| 	req->tgt_cfg_valid = 1; | ||||
| 	/* This is number of CE configs */ | ||||
| 	req->tgt_cfg_len = ab->qmi.ce_cfg.tgt_ce_len; | ||||
| 	for (pipe_num = 0; pipe_num <= req->tgt_cfg_len ; pipe_num++) { | ||||
| 	for (pipe_num = 0; pipe_num < req->tgt_cfg_len ; pipe_num++) { | ||||
| 		req->tgt_cfg[pipe_num].pipe_num = ce_cfg[pipe_num].pipenum; | ||||
| 		req->tgt_cfg[pipe_num].pipe_dir = ce_cfg[pipe_num].pipedir; | ||||
| 		req->tgt_cfg[pipe_num].nentries = ce_cfg[pipe_num].nentries; | ||||
| @ -2181,7 +2397,10 @@ static void ath11k_qmi_event_load_bdf(struct ath11k_qmi *qmi) | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	ret = ath11k_qmi_load_bdf(ab); | ||||
| 	if (ab->bus_params.fixed_bdf_addr) | ||||
| 		ret = ath11k_qmi_load_bdf_fixed_addr(ab); | ||||
| 	else | ||||
| 		ret = ath11k_qmi_load_bdf_qmi(ab); | ||||
| 	if (ret < 0) { | ||||
| 		ath11k_warn(ab, "qmi failed to load board data file:%d\n", ret); | ||||
| 		return; | ||||
| @ -2220,10 +2439,20 @@ static void ath11k_qmi_msg_mem_request_cb(struct qmi_handle *qmi_hdl, | ||||
| 			   msg->mem_seg[i].type, msg->mem_seg[i].size); | ||||
| 	} | ||||
| 
 | ||||
| 	ret = ath11k_qmi_alloc_target_mem_chunk(ab); | ||||
| 	if (ret < 0) { | ||||
| 		ath11k_warn(ab, "qmi failed to alloc target memory:%d\n", ret); | ||||
| 		return; | ||||
| 	if (ab->bus_params.fixed_mem_region) { | ||||
| 		ret = ath11k_qmi_assign_target_mem_chunk(ab); | ||||
| 		if (ret) { | ||||
| 			ath11k_warn(ab, "qmi failed to assign target memory: %d\n", | ||||
| 				    ret); | ||||
| 			return; | ||||
| 		} | ||||
| 	} else if (msg->mem_seg_len > 2) { | ||||
| 		ret = ath11k_qmi_alloc_target_mem_chunk(ab); | ||||
| 		if (ret) { | ||||
| 			ath11k_warn(ab, "qmi failed to alloc target memory: %d\n", | ||||
| 				    ret); | ||||
| 			return; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	ath11k_qmi_driver_event_post(qmi, ATH11K_QMI_EVENT_REQUEST_MEM, NULL); | ||||
| @ -2265,21 +2494,21 @@ static const struct qmi_msg_handler ath11k_qmi_msg_handlers[] = { | ||||
| 		.type = QMI_INDICATION, | ||||
| 		.msg_id = QMI_WLFW_REQUEST_MEM_IND_V01, | ||||
| 		.ei = qmi_wlanfw_request_mem_ind_msg_v01_ei, | ||||
| 		.decoded_size = sizeof(qmi_wlanfw_request_mem_ind_msg_v01_ei), | ||||
| 		.decoded_size = sizeof(struct qmi_wlanfw_request_mem_ind_msg_v01), | ||||
| 		.fn = ath11k_qmi_msg_mem_request_cb, | ||||
| 	}, | ||||
| 	{ | ||||
| 		.type = QMI_INDICATION, | ||||
| 		.msg_id = QMI_WLFW_FW_MEM_READY_IND_V01, | ||||
| 		.ei = qmi_wlanfw_mem_ready_ind_msg_v01_ei, | ||||
| 		.decoded_size = sizeof(qmi_wlanfw_mem_ready_ind_msg_v01_ei), | ||||
| 		.decoded_size = sizeof(struct qmi_wlanfw_fw_mem_ready_ind_msg_v01), | ||||
| 		.fn = ath11k_qmi_msg_mem_ready_cb, | ||||
| 	}, | ||||
| 	{ | ||||
| 		.type = QMI_INDICATION, | ||||
| 		.msg_id = QMI_WLFW_FW_READY_IND_V01, | ||||
| 		.ei = qmi_wlanfw_fw_ready_ind_msg_v01_ei, | ||||
| 		.decoded_size = sizeof(qmi_wlanfw_fw_ready_ind_msg_v01_ei), | ||||
| 		.decoded_size = sizeof(struct qmi_wlanfw_fw_ready_ind_msg_v01), | ||||
| 		.fn = ath11k_qmi_msg_fw_ready_cb, | ||||
| 	}, | ||||
| 	{ | ||||
| @ -2287,7 +2516,7 @@ static const struct qmi_msg_handler ath11k_qmi_msg_handlers[] = { | ||||
| 		.msg_id = QMI_WLFW_COLD_BOOT_CAL_DONE_IND_V01, | ||||
| 		.ei = qmi_wlanfw_cold_boot_cal_done_ind_msg_v01_ei, | ||||
| 		.decoded_size = | ||||
| 			sizeof(qmi_wlanfw_cold_boot_cal_done_ind_msg_v01_ei), | ||||
| 			sizeof(struct qmi_wlanfw_fw_cold_cal_done_ind_msg_v01), | ||||
| 		.fn = ath11k_qmi_msg_cold_boot_cal_done_cb, | ||||
| 	}, | ||||
| }; | ||||
| @ -2416,9 +2645,10 @@ int ath11k_qmi_init_service(struct ath11k_base *ab) | ||||
| 
 | ||||
| 	ret = qmi_add_lookup(&ab->qmi.handle, ATH11K_QMI_WLFW_SERVICE_ID_V01, | ||||
| 			     ATH11K_QMI_WLFW_SERVICE_VERS_V01, | ||||
| 			     ATH11K_QMI_WLFW_SERVICE_INS_ID_V01); | ||||
| 			     ab->qmi.service_ins_id); | ||||
| 	if (ret < 0) { | ||||
| 		ath11k_warn(ab, "failed to add qmi lookup\n"); | ||||
| 		destroy_workqueue(ab->qmi.event_wq); | ||||
| 		return ret; | ||||
| 	} | ||||
| 
 | ||||
| @ -2430,5 +2660,7 @@ void ath11k_qmi_deinit_service(struct ath11k_base *ab) | ||||
| 	qmi_handle_release(&ab->qmi.handle); | ||||
| 	cancel_work_sync(&ab->qmi.event_work); | ||||
| 	destroy_workqueue(ab->qmi.event_wq); | ||||
| 	ath11k_qmi_m3_free(ab); | ||||
| 	ath11k_qmi_free_target_mem_chunk(ab); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -12,18 +12,18 @@ | ||||
| #define ATH11K_HOST_VERSION_STRING		"WIN" | ||||
| #define ATH11K_QMI_WLANFW_TIMEOUT_MS		5000 | ||||
| #define ATH11K_QMI_MAX_BDF_FILE_NAME_SIZE	64 | ||||
| #define ATH11K_QMI_BDF_ADDRESS			0x4B0C0000 | ||||
| #define ATH11K_QMI_BDF_MAX_SIZE			(256 * 1024) | ||||
| #define ATH11K_QMI_CALDATA_OFFSET		(128 * 1024) | ||||
| #define ATH11K_QMI_WLANFW_MAX_BUILD_ID_LEN_V01	128 | ||||
| #define ATH11K_QMI_WLFW_SERVICE_ID_V01		0x45 | ||||
| #define ATH11K_QMI_WLFW_SERVICE_VERS_V01	0x01 | ||||
| #define ATH11K_QMI_WLFW_SERVICE_INS_ID_V01	0x02 | ||||
| #define ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_QCA6390	0x01 | ||||
| #define ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_IPQ8074	0x02 | ||||
| #define ATH11K_QMI_WLANFW_MAX_TIMESTAMP_LEN_V01	32 | ||||
| #define ATH11K_QMI_RESP_LEN_MAX			8192 | ||||
| #define ATH11K_QMI_WLANFW_MAX_NUM_MEM_SEG_V01	32 | ||||
| #define ATH11K_QMI_CALDB_SIZE			0x480000 | ||||
| #define ATH11K_QMI_DEFAULT_CAL_FILE_NAME	"caldata.bin" | ||||
| 
 | ||||
| #define QMI_WLFW_REQUEST_MEM_IND_V01		0x0035 | ||||
| #define QMI_WLFW_FW_MEM_READY_IND_V01		0x0037 | ||||
| @ -42,6 +42,11 @@ enum ath11k_qmi_file_type { | ||||
| 	ATH11K_QMI_MAX_FILE_TYPE, | ||||
| }; | ||||
| 
 | ||||
| enum ath11k_qmi_bdf_type { | ||||
| 	ATH11K_QMI_BDF_TYPE_BIN			= 0, | ||||
| 	ATH11K_QMI_BDF_TYPE_ELF			= 1, | ||||
| }; | ||||
| 
 | ||||
| enum ath11k_qmi_event_type { | ||||
| 	ATH11K_QMI_EVENT_SERVER_ARRIVE, | ||||
| 	ATH11K_QMI_EVENT_SERVER_EXIT, | ||||
| @ -85,7 +90,7 @@ struct target_mem_chunk { | ||||
| 	u32 size; | ||||
| 	u32 type; | ||||
| 	dma_addr_t paddr; | ||||
| 	u32 vaddr; | ||||
| 	u32 *vaddr; | ||||
| }; | ||||
| 
 | ||||
| struct target_info { | ||||
| @ -98,6 +103,12 @@ struct target_info { | ||||
| 	char fw_build_id[ATH11K_QMI_WLANFW_MAX_BUILD_ID_LEN_V01 + 1]; | ||||
| }; | ||||
| 
 | ||||
| struct m3_mem_region { | ||||
| 	u32 size; | ||||
| 	dma_addr_t paddr; | ||||
| 	void *vaddr; | ||||
| }; | ||||
| 
 | ||||
| struct ath11k_qmi { | ||||
| 	struct ath11k_base *ab; | ||||
| 	struct qmi_handle handle; | ||||
| @ -112,6 +123,8 @@ struct ath11k_qmi { | ||||
| 	u32 target_mem_mode; | ||||
| 	u8 cal_done; | ||||
| 	struct target_info target; | ||||
| 	struct m3_mem_region m3_mem; | ||||
| 	unsigned int service_ins_id; | ||||
| }; | ||||
| 
 | ||||
| #define QMI_WLANFW_HOST_CAP_REQ_MSG_V01_MAX_LEN		189 | ||||
| @ -254,6 +267,14 @@ struct qmi_wlanfw_fw_mem_ready_ind_msg_v01 { | ||||
| 	char placeholder; | ||||
| }; | ||||
| 
 | ||||
| struct qmi_wlanfw_fw_ready_ind_msg_v01 { | ||||
| 	char placeholder; | ||||
| }; | ||||
| 
 | ||||
| struct qmi_wlanfw_fw_cold_cal_done_ind_msg_v01 { | ||||
| 	char placeholder; | ||||
| }; | ||||
| 
 | ||||
| #define QMI_WLANFW_CAP_REQ_MSG_V01_MAX_LEN	0 | ||||
| #define QMI_WLANFW_CAP_RESP_MSG_V01_MAX_LEN	207 | ||||
| #define QMI_WLANFW_CAP_REQ_V01			0x0024 | ||||
|  | ||||
| @ -699,7 +699,7 @@ void ath11k_reg_free(struct ath11k_base *ab) | ||||
| { | ||||
| 	int i; | ||||
| 
 | ||||
| 	for (i = 0; i < MAX_RADIOS; i++) { | ||||
| 	for (i = 0; i < ab->hw_params.max_radios; i++) { | ||||
| 		kfree(ab->default_regd[i]); | ||||
| 		kfree(ab->new_regd[i]); | ||||
| 	} | ||||
|  | ||||
| @ -954,10 +954,8 @@ int ath11k_spectral_init(struct ath11k_base *ab) | ||||
| 	int i; | ||||
| 
 | ||||
| 	if (!test_bit(WMI_TLV_SERVICE_FREQINFO_IN_METADATA, | ||||
| 		      ab->wmi_ab.svc_map)) { | ||||
| 		ath11k_info(ab, "spectral not supported\n"); | ||||
| 		      ab->wmi_ab.svc_map)) | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	for (i = 0; i < ab->num_radios; i++) { | ||||
| 		ar = ab->pdevs[i].ar; | ||||
| @ -966,10 +964,8 @@ int ath11k_spectral_init(struct ath11k_base *ab) | ||||
| 		ret = ath11k_dbring_get_cap(ar->ab, ar->pdev_idx, | ||||
| 					    WMI_DIRECT_BUF_SPECTRAL, | ||||
| 					    &db_cap); | ||||
| 		if (ret) { | ||||
| 			ath11k_info(ab, "spectral not enabled for pdev %d\n", i); | ||||
| 		if (ret) | ||||
| 			continue; | ||||
| 		} | ||||
| 
 | ||||
| 		idr_init(&sp->rx_ring.bufs_idr); | ||||
| 		spin_lock_init(&sp->rx_ring.idr_lock); | ||||
|  | ||||
| @ -338,7 +338,7 @@ ath11k_pull_mac_phy_cap_svc_ready_ext(struct ath11k_pdev_wmi *wmi_handle, | ||||
| 	mac_phy_caps = wmi_mac_phy_caps + phy_idx; | ||||
| 
 | ||||
| 	pdev->pdev_id = mac_phy_caps->pdev_id; | ||||
| 	pdev_cap->supported_bands = mac_phy_caps->supported_bands; | ||||
| 	pdev_cap->supported_bands |= mac_phy_caps->supported_bands; | ||||
| 	pdev_cap->ampdu_density = mac_phy_caps->ampdu_density; | ||||
| 
 | ||||
| 	/* Take non-zero tx/rx chainmask. If tx/rx chainmask differs from
 | ||||
| @ -371,27 +371,33 @@ ath11k_pull_mac_phy_cap_svc_ready_ext(struct ath11k_pdev_wmi *wmi_handle, | ||||
| 	pdev_cap->rx_chain_mask_shift = | ||||
| 			find_first_bit((unsigned long *)&pdev_cap->rx_chain_mask, 32); | ||||
| 
 | ||||
| 	cap_band = &pdev_cap->band[NL80211_BAND_2GHZ]; | ||||
| 	cap_band->max_bw_supported = mac_phy_caps->max_bw_supported_2g; | ||||
| 	cap_band->ht_cap_info = mac_phy_caps->ht_cap_info_2g; | ||||
| 	cap_band->he_cap_info[0] = mac_phy_caps->he_cap_info_2g; | ||||
| 	cap_band->he_cap_info[1] = mac_phy_caps->he_cap_info_2g_ext; | ||||
| 	cap_band->he_mcs = mac_phy_caps->he_supp_mcs_2g; | ||||
| 	memcpy(cap_band->he_cap_phy_info, &mac_phy_caps->he_cap_phy_info_2g, | ||||
| 	       sizeof(u32) * PSOC_HOST_MAX_PHY_SIZE); | ||||
| 	memcpy(&cap_band->he_ppet, &mac_phy_caps->he_ppet2g, | ||||
| 	       sizeof(struct ath11k_ppe_threshold)); | ||||
| 	if (mac_phy_caps->supported_bands & WMI_HOST_WLAN_2G_CAP) { | ||||
| 		cap_band = &pdev_cap->band[NL80211_BAND_2GHZ]; | ||||
| 		cap_band->phy_id = mac_phy_caps->phy_id; | ||||
| 		cap_band->max_bw_supported = mac_phy_caps->max_bw_supported_2g; | ||||
| 		cap_band->ht_cap_info = mac_phy_caps->ht_cap_info_2g; | ||||
| 		cap_band->he_cap_info[0] = mac_phy_caps->he_cap_info_2g; | ||||
| 		cap_band->he_cap_info[1] = mac_phy_caps->he_cap_info_2g_ext; | ||||
| 		cap_band->he_mcs = mac_phy_caps->he_supp_mcs_2g; | ||||
| 		memcpy(cap_band->he_cap_phy_info, &mac_phy_caps->he_cap_phy_info_2g, | ||||
| 		       sizeof(u32) * PSOC_HOST_MAX_PHY_SIZE); | ||||
| 		memcpy(&cap_band->he_ppet, &mac_phy_caps->he_ppet2g, | ||||
| 		       sizeof(struct ath11k_ppe_threshold)); | ||||
| 	} | ||||
| 
 | ||||
| 	cap_band = &pdev_cap->band[NL80211_BAND_5GHZ]; | ||||
| 	cap_band->max_bw_supported = mac_phy_caps->max_bw_supported_5g; | ||||
| 	cap_band->ht_cap_info = mac_phy_caps->ht_cap_info_5g; | ||||
| 	cap_band->he_cap_info[0] = mac_phy_caps->he_cap_info_5g; | ||||
| 	cap_band->he_cap_info[1] = mac_phy_caps->he_cap_info_5g_ext; | ||||
| 	cap_band->he_mcs = mac_phy_caps->he_supp_mcs_5g; | ||||
| 	memcpy(cap_band->he_cap_phy_info, &mac_phy_caps->he_cap_phy_info_5g, | ||||
| 	       sizeof(u32) * PSOC_HOST_MAX_PHY_SIZE); | ||||
| 	memcpy(&cap_band->he_ppet, &mac_phy_caps->he_ppet5g, | ||||
| 	       sizeof(struct ath11k_ppe_threshold)); | ||||
| 	if (mac_phy_caps->supported_bands & WMI_HOST_WLAN_5G_CAP) { | ||||
| 		cap_band = &pdev_cap->band[NL80211_BAND_5GHZ]; | ||||
| 		cap_band->phy_id = mac_phy_caps->phy_id; | ||||
| 		cap_band->max_bw_supported = mac_phy_caps->max_bw_supported_5g; | ||||
| 		cap_band->ht_cap_info = mac_phy_caps->ht_cap_info_5g; | ||||
| 		cap_band->he_cap_info[0] = mac_phy_caps->he_cap_info_5g; | ||||
| 		cap_band->he_cap_info[1] = mac_phy_caps->he_cap_info_5g_ext; | ||||
| 		cap_band->he_mcs = mac_phy_caps->he_supp_mcs_5g; | ||||
| 		memcpy(cap_band->he_cap_phy_info, &mac_phy_caps->he_cap_phy_info_5g, | ||||
| 		       sizeof(u32) * PSOC_HOST_MAX_PHY_SIZE); | ||||
| 		memcpy(&cap_band->he_ppet, &mac_phy_caps->he_ppet5g, | ||||
| 		       sizeof(struct ath11k_ppe_threshold)); | ||||
| 	} | ||||
| 
 | ||||
| 	cap_band = &pdev_cap->band[NL80211_BAND_6GHZ]; | ||||
| 	cap_band->max_bw_supported = mac_phy_caps->max_bw_supported_5g; | ||||
| @ -3175,7 +3181,7 @@ static int ath11k_init_cmd_send(struct ath11k_pdev_wmi *wmi, | ||||
| 			      (param->num_band_to_mac * sizeof(*band_to_mac)); | ||||
| 
 | ||||
| 	len = sizeof(*cmd) + TLV_HDR_SIZE + sizeof(*cfg) + hw_mode_len + | ||||
| 	      (sizeof(*host_mem_chunks) * WMI_MAX_MEM_REQS); | ||||
| 	      (param->num_mem_chunks ? (sizeof(*host_mem_chunks) * WMI_MAX_MEM_REQS) : 0); | ||||
| 
 | ||||
| 	skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len); | ||||
| 	if (!skb) | ||||
| @ -3381,6 +3387,8 @@ int ath11k_wmi_cmd_init(struct ath11k_base *ab) | ||||
| 	config.twt_ap_pdev_count = ab->num_radios; | ||||
| 	config.twt_ap_sta_count = 1000; | ||||
| 
 | ||||
| 	ab->hw_params.hw_ops->wmi_init_config(ab, &config); | ||||
| 
 | ||||
| 	memcpy(&wmi_sc->wlan_resource_config, &config, sizeof(config)); | ||||
| 
 | ||||
| 	init_param.res_cfg = &wmi_sc->wlan_resource_config; | ||||
| @ -3391,9 +3399,10 @@ int ath11k_wmi_cmd_init(struct ath11k_base *ab) | ||||
| 	if (wmi_sc->preferred_hw_mode == WMI_HOST_HW_MODE_SINGLE) | ||||
| 		init_param.hw_mode_id = WMI_HOST_HW_MODE_MAX; | ||||
| 
 | ||||
| 	init_param.num_band_to_mac = ab->num_radios; | ||||
| 
 | ||||
| 	ath11k_fill_band_to_mac_param(ab, init_param.band_to_mac); | ||||
| 	if (ab->hw_params.needs_band_to_mac) { | ||||
| 		init_param.num_band_to_mac = ab->num_radios; | ||||
| 		ath11k_fill_band_to_mac_param(ab, init_param.band_to_mac); | ||||
| 	} | ||||
| 
 | ||||
| 	return ath11k_init_cmd_send(&wmi_sc->wmi[0], &init_param); | ||||
| } | ||||
| @ -3688,6 +3697,8 @@ static int ath11k_wmi_tlv_hw_mode_caps(struct ath11k_base *soc, | ||||
| 		i++; | ||||
| 	} | ||||
| 
 | ||||
| 	ath11k_dbg(soc, ATH11K_DBG_WMI, "preferred_hw_mode:%d\n", | ||||
| 		   soc->wmi_ab.preferred_hw_mode); | ||||
| 	if (soc->wmi_ab.preferred_hw_mode == WMI_HOST_HW_MODE_MAX) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| @ -3778,6 +3789,7 @@ static int ath11k_wmi_tlv_ext_soc_hal_reg_caps_parse(struct ath11k_base *soc, | ||||
| 	struct wmi_tlv_svc_rdy_ext_parse *svc_rdy_ext = data; | ||||
| 	u8 hw_mode_id = svc_rdy_ext->pref_hw_mode_caps.hw_mode_id; | ||||
| 	u32 phy_id_map; | ||||
| 	int pdev_index = 0; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	svc_rdy_ext->soc_hal_reg_caps = (struct wmi_soc_hal_reg_capabilities *)ptr; | ||||
| @ -3793,7 +3805,7 @@ static int ath11k_wmi_tlv_ext_soc_hal_reg_caps_parse(struct ath11k_base *soc, | ||||
| 							    svc_rdy_ext->soc_hal_reg_caps, | ||||
| 							    svc_rdy_ext->mac_phy_caps, | ||||
| 							    hw_mode_id, soc->num_radios, | ||||
| 							    &soc->pdevs[soc->num_radios]); | ||||
| 							    &soc->pdevs[pdev_index]); | ||||
| 		if (ret) { | ||||
| 			ath11k_warn(soc, "failed to extract mac caps, idx :%d\n", | ||||
| 				    soc->num_radios); | ||||
| @ -3802,9 +3814,25 @@ static int ath11k_wmi_tlv_ext_soc_hal_reg_caps_parse(struct ath11k_base *soc, | ||||
| 
 | ||||
| 		soc->num_radios++; | ||||
| 
 | ||||
| 		/* For QCA6390, save mac_phy capability in the same pdev */ | ||||
| 		if (soc->hw_params.single_pdev_only) | ||||
| 			pdev_index = 0; | ||||
| 		else | ||||
| 			pdev_index = soc->num_radios; | ||||
| 
 | ||||
| 		/* TODO: mac_phy_cap prints */ | ||||
| 		phy_id_map >>= 1; | ||||
| 	} | ||||
| 
 | ||||
| 	/* For QCA6390, set num_radios to 1 because host manages
 | ||||
| 	 * both 2G and 5G radio in one pdev. | ||||
| 	 * Set pdev_id = 0 and 0 means soc level. | ||||
| 	 */ | ||||
| 	if (soc->hw_params.single_pdev_only) { | ||||
| 		soc->num_radios = 1; | ||||
| 		soc->pdevs[0].pdev_id = 0; | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| @ -5434,8 +5462,17 @@ static int ath11k_reg_chan_list_event(struct ath11k_base *ab, struct sk_buff *sk | ||||
| 
 | ||||
| 	pdev_idx = reg_info->phy_id; | ||||
| 
 | ||||
| 	if (pdev_idx >= ab->num_radios) | ||||
| 		goto fallback; | ||||
| 	if (pdev_idx >= ab->num_radios) { | ||||
| 		/* Process the event for phy0 only if single_pdev_only
 | ||||
| 		 * is true. If pdev_idx is valid but not 0, discard the | ||||
| 		 * event. Otherwise, it goes to fallback. | ||||
| 		 */ | ||||
| 		if (ab->hw_params.single_pdev_only && | ||||
| 		    pdev_idx < ab->hw_params.num_rxmda_per_pdev) | ||||
| 			goto mem_free; | ||||
| 		else | ||||
| 			goto fallback; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Avoid multiple overwrites to default regd, during core
 | ||||
| 	 * stop-start after mac registration. | ||||
| @ -6682,7 +6719,7 @@ int ath11k_wmi_connect(struct ath11k_base *ab) | ||||
| 	u8 wmi_ep_count; | ||||
| 
 | ||||
| 	wmi_ep_count = ab->htc.wmi_ep_count; | ||||
| 	if (wmi_ep_count > MAX_RADIOS) | ||||
| 	if (wmi_ep_count > ab->hw_params.max_radios) | ||||
| 		return -1; | ||||
| 
 | ||||
| 	for (i = 0; i < wmi_ep_count; i++) | ||||
| @ -6704,7 +6741,7 @@ int ath11k_wmi_pdev_attach(struct ath11k_base *ab, | ||||
| { | ||||
| 	struct ath11k_pdev_wmi *wmi_handle; | ||||
| 
 | ||||
| 	if (pdev_id >= MAX_RADIOS) | ||||
| 	if (pdev_id >= ab->hw_params.max_radios) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	wmi_handle = &ab->wmi_ab.wmi[pdev_id]; | ||||
| @ -6728,6 +6765,10 @@ int ath11k_wmi_attach(struct ath11k_base *ab) | ||||
| 	ab->wmi_ab.ab = ab; | ||||
| 	ab->wmi_ab.preferred_hw_mode = WMI_HOST_HW_MODE_MAX; | ||||
| 
 | ||||
| 	/* It's overwritten when service_ext_ready is handled */ | ||||
| 	if (ab->hw_params.single_pdev_only) | ||||
| 		ab->wmi_ab.preferred_hw_mode = WMI_HOST_HW_MODE_SINGLE; | ||||
| 
 | ||||
| 	/* TODO: Init remaining wmi soc resources required */ | ||||
| 	init_completion(&ab->wmi_ab.service_ready); | ||||
| 	init_completion(&ab->wmi_ab.unified_ready); | ||||
|  | ||||
| @ -410,7 +410,7 @@ enum ath5k_radio { | ||||
|  * This article claims Super G sticks to bonding of channels 5 and 6 for | ||||
|  * USA: | ||||
|  * | ||||
|  * http://www.pcworld.com/article/id,113428-page,1/article.html
 | ||||
|  * https://www.pcworld.com/article/id,113428-page,1/article.html
 | ||||
|  * | ||||
|  * The channel bonding seems to be driver specific though. | ||||
|  * | ||||
|  | ||||
| @ -1098,7 +1098,7 @@ err: | ||||
| /**
 | ||||
|  * ath5k_drain_tx_buffs - Empty tx buffers | ||||
|  * | ||||
|  * @ah The &struct ath5k_hw | ||||
|  * @ah: The &struct ath5k_hw | ||||
|  * | ||||
|  * Empty tx buffers from all queues in preparation | ||||
|  * of a reset or during shutdown. | ||||
|  | ||||
| @ -1172,13 +1172,13 @@ ath5k_cal_data_offset_2413(struct ath5k_eeprom_info *ee, int mode) | ||||
| 			offset += ath5k_pdgains_size_2413(ee, | ||||
| 					AR5K_EEPROM_MODE_11B) + | ||||
| 					AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2; | ||||
| 		/* fall through */ | ||||
| 		fallthrough; | ||||
| 	case AR5K_EEPROM_MODE_11B: | ||||
| 		if (AR5K_EEPROM_HDR_11A(ee->ee_header)) | ||||
| 			offset += ath5k_pdgains_size_2413(ee, | ||||
| 					AR5K_EEPROM_MODE_11A) + | ||||
| 					AR5K_EEPROM_N_5GHZ_CHAN / 2; | ||||
| 		/* fall through */ | ||||
| 		fallthrough; | ||||
| 	case AR5K_EEPROM_MODE_11A: | ||||
| 		break; | ||||
| 	default: | ||||
|  | ||||
| @ -101,6 +101,7 @@ static const unsigned int ack_rates_high[] = | ||||
| /**
 | ||||
|  * ath5k_hw_get_frame_duration() - Get tx time of a frame | ||||
|  * @ah: The &struct ath5k_hw | ||||
|  * @band: One of enum nl80211_band | ||||
|  * @len: Frame's length in bytes | ||||
|  * @rate: The @struct ieee80211_rate | ||||
|  * @shortpre: Indicate short preample | ||||
| @ -670,7 +671,7 @@ ath5k_hw_init_beacon_timers(struct ath5k_hw *ah, u32 next_beacon, u32 interval) | ||||
| 		break; | ||||
| 	case NL80211_IFTYPE_ADHOC: | ||||
| 		AR5K_REG_ENABLE_BITS(ah, AR5K_TXCFG, AR5K_TXCFG_ADHOC_BCN_ATIM); | ||||
| 		/* fall through */ | ||||
| 		fallthrough; | ||||
| 	default: | ||||
| 		/* On non-STA modes timer1 is used as next DMA
 | ||||
| 		 * beacon alert (DBA) timer and timer2 as next | ||||
| @ -913,7 +914,7 @@ ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype op_mode) | ||||
| 		pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE | ||||
| 			| (ah->ah_version == AR5K_AR5210 ? | ||||
| 				AR5K_STA_ID1_PWR_SV : 0); | ||||
| 		/* fall through */ | ||||
| 		fallthrough; | ||||
| 	case NL80211_IFTYPE_MONITOR: | ||||
| 		pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE | ||||
| 			| (ah->ah_version == AR5K_AR5210 ? | ||||
| @ -945,7 +946,6 @@ ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype op_mode) | ||||
|  * ath5k_hw_pcu_init() - Initialize PCU | ||||
|  * @ah: The &struct ath5k_hw | ||||
|  * @op_mode: One of enum nl80211_iftype | ||||
|  * @mode: One of enum ath5k_driver_mode | ||||
|  * | ||||
|  * This function is used to initialize PCU by setting current | ||||
|  * operation mode and various other settings. | ||||
|  | ||||
| @ -3229,10 +3229,10 @@ ath5k_write_pwr_to_pdadc_table(struct ath5k_hw *ah, u8 ee_mode) | ||||
| 	switch (pdcurves) { | ||||
| 	case 3: | ||||
| 		reg |= AR5K_REG_SM(pdg_to_idx[2], AR5K_PHY_TPC_RG1_PDGAIN_3); | ||||
| 		/* Fall through */ | ||||
| 		fallthrough; | ||||
| 	case 2: | ||||
| 		reg |= AR5K_REG_SM(pdg_to_idx[1], AR5K_PHY_TPC_RG1_PDGAIN_2); | ||||
| 		/* Fall through */ | ||||
| 		fallthrough; | ||||
| 	case 1: | ||||
| 		reg |= AR5K_REG_SM(pdg_to_idx[0], AR5K_PHY_TPC_RG1_PDGAIN_1); | ||||
| 		break; | ||||
| @ -3353,7 +3353,7 @@ ath5k_setup_channel_powertable(struct ath5k_hw *ah, | ||||
| 					table_min[pdg] = table_max[pdg] - 126; | ||||
| 			} | ||||
| 
 | ||||
| 			/* Fall through */ | ||||
| 			fallthrough; | ||||
| 		case AR5K_PWRTABLE_PWR_TO_PCDAC: | ||||
| 		case AR5K_PWRTABLE_PWR_TO_PDADC: | ||||
| 
 | ||||
|  | ||||
| @ -522,7 +522,7 @@ ath5k_hw_set_power_mode(struct ath5k_hw *ah, enum ath5k_power_mode mode, | ||||
| 	switch (mode) { | ||||
| 	case AR5K_PM_AUTO: | ||||
| 		staid &= ~AR5K_STA_ID1_DEFAULT_ANTENNA; | ||||
| 		/* fallthrough */ | ||||
| 		fallthrough; | ||||
| 	case AR5K_PM_NETWORK_SLEEP: | ||||
| 		if (set_chip) | ||||
| 			ath5k_hw_reg_write(ah, | ||||
|  | ||||
| @ -42,7 +42,7 @@ | ||||
|  * Also check out reg.h and U.S. Patent 6677779 B1 (about buffer | ||||
|  * registers and control registers): | ||||
|  * | ||||
|  * http://www.google.com/patents?id=qNURAAAAEBAJ
 | ||||
|  * https://www.google.com/patents?id=qNURAAAAEBAJ
 | ||||
|  */ | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
| @ -3897,19 +3897,19 @@ int ath6kl_cfg80211_init(struct ath6kl *ar) | ||||
| 	switch (ar->hw.cap) { | ||||
| 	case WMI_11AN_CAP: | ||||
| 		ht = true; | ||||
| 		/* fall through */ | ||||
| 		fallthrough; | ||||
| 	case WMI_11A_CAP: | ||||
| 		band_5gig = true; | ||||
| 		break; | ||||
| 	case WMI_11GN_CAP: | ||||
| 		ht = true; | ||||
| 		/* fall through */ | ||||
| 		fallthrough; | ||||
| 	case WMI_11G_CAP: | ||||
| 		band_2gig = true; | ||||
| 		break; | ||||
| 	case WMI_11AGN_CAP: | ||||
| 		ht = true; | ||||
| 		/* fall through */ | ||||
| 		fallthrough; | ||||
| 	case WMI_11AG_CAP: | ||||
| 		band_2gig = true; | ||||
| 		band_5gig = true; | ||||
|  | ||||
| @ -1752,7 +1752,7 @@ static int __ath6kl_init_hw_start(struct ath6kl *ar) | ||||
| 
 | ||||
| 	ret = ath6kl_init_service_ep(ar); | ||||
| 	if (ret) { | ||||
| 		ath6kl_err("Endpoint service initilisation failed: %d\n", ret); | ||||
| 		ath6kl_err("Endpoint service initialization failed: %d\n", ret); | ||||
| 		goto err_cleanup_scatter; | ||||
| 	} | ||||
| 
 | ||||
|  | ||||
| @ -389,7 +389,7 @@ void ath6kl_connect_ap_mode_bss(struct ath6kl_vif *vif, u16 channel) | ||||
| 		if (!ik->valid || ik->key_type != WAPI_CRYPT) | ||||
| 			break; | ||||
| 		/* for WAPI, we need to set the delayed group key, continue: */ | ||||
| 		/* fall through */ | ||||
| 		fallthrough; | ||||
| 	case WPA_PSK_AUTH: | ||||
| 	case WPA2_PSK_AUTH: | ||||
| 	case (WPA_PSK_AUTH | WPA2_PSK_AUTH): | ||||
| @ -430,6 +430,9 @@ void ath6kl_connect_ap_mode_sta(struct ath6kl_vif *vif, u16 aid, u8 *mac_addr, | ||||
| 
 | ||||
| 	ath6kl_dbg(ATH6KL_DBG_TRC, "new station %pM aid=%d\n", mac_addr, aid); | ||||
| 
 | ||||
| 	if (aid < 1 || aid > AP_MAX_NUM_STA) | ||||
| 		return; | ||||
| 
 | ||||
| 	if (assoc_req_len > sizeof(struct ieee80211_hdr_3addr)) { | ||||
| 		struct ieee80211_mgmt *mgmt = | ||||
| 			(struct ieee80211_mgmt *) assoc_info; | ||||
|  | ||||
| @ -74,7 +74,7 @@ static const struct ani_ofdm_level_entry ofdm_level_table[] = { | ||||
|  * Regardless of alignment in time, the antenna signals add constructively after | ||||
|  * FFT and improve your reception. For more information: | ||||
|  * | ||||
|  * http://en.wikipedia.org/wiki/Maximal-ratio_combining
 | ||||
|  * https://en.wikipedia.org/wiki/Maximal-ratio_combining
 | ||||
|  */ | ||||
| 
 | ||||
| struct ani_cck_level_entry { | ||||
|  | ||||
| @ -579,14 +579,14 @@ static void ar5008_hw_init_chain_masks(struct ath_hw *ah) | ||||
| 	case 0x5: | ||||
| 		REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP, | ||||
| 			    AR_PHY_SWAP_ALT_CHAIN); | ||||
| 		/* fall through */ | ||||
| 		fallthrough; | ||||
| 	case 0x3: | ||||
| 		if (ah->hw_version.macVersion == AR_SREV_REVISION_5416_10) { | ||||
| 			REG_WRITE(ah, AR_PHY_RX_CHAINMASK, 0x7); | ||||
| 			REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, 0x7); | ||||
| 			break; | ||||
| 		} | ||||
| 		/* fall through */ | ||||
| 		fallthrough; | ||||
| 	case 0x1: | ||||
| 	case 0x2: | ||||
| 	case 0x7: | ||||
|  | ||||
| @ -267,7 +267,7 @@ ar9002_set_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_info *i) | ||||
| 	switch (i->aggr) { | ||||
| 	case AGGR_BUF_FIRST: | ||||
| 		ctl6 |= SM(i->aggr_len, AR_AggrLen); | ||||
| 		/* fall through */ | ||||
| 		fallthrough; | ||||
| 	case AGGR_BUF_MIDDLE: | ||||
| 		ctl1 |= AR_IsAggr | AR_MoreAggr; | ||||
| 		ctl6 |= SM(i->ndelim, AR_PadDelim); | ||||
|  | ||||
| @ -119,7 +119,7 @@ static int ar9002_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) | ||||
| 				aModeRefSel = 2; | ||||
| 			if (aModeRefSel) | ||||
| 				break; | ||||
| 			/* fall through */ | ||||
| 			fallthrough; | ||||
| 		case 1: | ||||
| 		default: | ||||
| 			aModeRefSel = 0; | ||||
|  | ||||
| @ -120,7 +120,7 @@ ar9003_set_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_info *i) | ||||
| 	switch (i->aggr) { | ||||
| 	case AGGR_BUF_FIRST: | ||||
| 		ctl17 |= SM(i->aggr_len, AR_AggrLen); | ||||
| 		/* fall through */ | ||||
| 		fallthrough; | ||||
| 	case AGGR_BUF_MIDDLE: | ||||
| 		ctl12 |= AR_IsAggr | AR_MoreAggr; | ||||
| 		ctl17 |= SM(i->ndelim, AR_PadDelim); | ||||
|  | ||||
| @ -706,7 +706,7 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, | ||||
| 			"Move chanctx state from FORCE_ACTIVE to IDLE\n"); | ||||
| 
 | ||||
| 		sc->sched.state = ATH_CHANCTX_STATE_IDLE; | ||||
| 		/* fall through */ | ||||
| 		fallthrough; | ||||
| 	case ATH_CHANCTX_EVENT_SWITCH: | ||||
| 		if (!test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags) || | ||||
| 		    sc->sched.state == ATH_CHANCTX_STATE_FORCE_ACTIVE || | ||||
| @ -1080,7 +1080,7 @@ static void ath_offchannel_timer(struct timer_list *t) | ||||
| 			mod_timer(&sc->offchannel.timer, jiffies + HZ / 10); | ||||
| 			break; | ||||
| 		} | ||||
| 		/* fall through */ | ||||
| 		fallthrough; | ||||
| 	case ATH_OFFCHANNEL_SUSPEND: | ||||
| 		if (!sc->offchannel.scan_req) | ||||
| 			return; | ||||
|  | ||||
| @ -402,7 +402,7 @@ static u32 ath9k_hw_def_get_eeprom(struct ath_hw *ah, | ||||
| 			return AR5416_PWR_TABLE_OFFSET_DB; | ||||
| 	case EEP_ANTENNA_GAIN_2G: | ||||
| 		band = 1; | ||||
| 		/* fall through */ | ||||
| 		fallthrough; | ||||
| 	case EEP_ANTENNA_GAIN_5G: | ||||
| 		return max_t(u8, max_t(u8, | ||||
| 			pModal[band].antennaGainCh[0], | ||||
|  | ||||
| @ -1375,7 +1375,7 @@ static void ath9k_hif_usb_disconnect(struct usb_interface *interface) | ||||
| 	if (hif_dev->flags & HIF_USB_READY) { | ||||
| 		ath9k_htc_hw_deinit(hif_dev->htc_handle, unplugged); | ||||
| 		ath9k_hif_usb_dev_deinit(hif_dev); | ||||
| 		ath9k_destoy_wmi(hif_dev->htc_handle->drv_priv); | ||||
| 		ath9k_destroy_wmi(hif_dev->htc_handle->drv_priv); | ||||
| 		ath9k_htc_hw_free(hif_dev->htc_handle); | ||||
| 	} | ||||
| 
 | ||||
|  | ||||
| @ -973,7 +973,7 @@ err_init: | ||||
| 	ath9k_stop_wmi(priv); | ||||
| 	hif_dev = (struct hif_device_usb *)htc_handle->hif_dev; | ||||
| 	ath9k_hif_usb_dealloc_urbs(hif_dev); | ||||
| 	ath9k_destoy_wmi(priv); | ||||
| 	ath9k_destroy_wmi(priv); | ||||
| err_free: | ||||
| 	ieee80211_free_hw(hw); | ||||
| 	return ret; | ||||
|  | ||||
| @ -974,7 +974,7 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv, | ||||
| 	struct ath_htc_rx_status *rxstatus; | ||||
| 	struct ath_rx_status rx_stats; | ||||
| 	bool decrypt_error = false; | ||||
| 	__be16 rs_datalen; | ||||
| 	u16 rs_datalen; | ||||
| 	bool is_phyerr; | ||||
| 
 | ||||
| 	if (skb->len < HTC_RX_FRAME_HEADER_SIZE) { | ||||
|  | ||||
| @ -339,6 +339,8 @@ void ath9k_htc_txcompletion_cb(struct htc_target *htc_handle, | ||||
| 
 | ||||
| 	if (skb) { | ||||
| 		htc_hdr = (struct htc_frame_hdr *) skb->data; | ||||
| 		if (htc_hdr->endpoint_id >= ARRAY_SIZE(htc_handle->endpoint)) | ||||
| 			goto ret; | ||||
| 		endpoint = &htc_handle->endpoint[htc_hdr->endpoint_id]; | ||||
| 		skb_pull(skb, sizeof(struct htc_frame_hdr)); | ||||
| 
 | ||||
|  | ||||
| @ -1277,12 +1277,12 @@ static void ath9k_hw_set_operating_mode(struct ath_hw *ah, int opmode) | ||||
| 			REG_SET_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); | ||||
| 			break; | ||||
| 		} | ||||
| 		/* fall through */ | ||||
| 		fallthrough; | ||||
| 	case NL80211_IFTYPE_OCB: | ||||
| 	case NL80211_IFTYPE_MESH_POINT: | ||||
| 	case NL80211_IFTYPE_AP: | ||||
| 		set |= AR_STA_ID1_STA_AP; | ||||
| 		/* fall through */ | ||||
| 		fallthrough; | ||||
| 	case NL80211_IFTYPE_STATION: | ||||
| 		REG_CLR_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); | ||||
| 		break; | ||||
| @ -2293,7 +2293,7 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period) | ||||
| 	case NL80211_IFTYPE_ADHOC: | ||||
| 		REG_SET_BIT(ah, AR_TXCFG, | ||||
| 			    AR_TXCFG_ADHOC_BEACON_ATIM_TX_POLICY); | ||||
| 		/* fall through */ | ||||
| 		fallthrough; | ||||
| 	case NL80211_IFTYPE_MESH_POINT: | ||||
| 	case NL80211_IFTYPE_AP: | ||||
| 		REG_WRITE(ah, AR_NEXT_TBTT_TIMER, next_beacon); | ||||
|  | ||||
| @ -1014,6 +1014,7 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) | ||||
| 	wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS); | ||||
| 	wiphy_ext_feature_set(hw->wiphy, | ||||
| 			      NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS); | ||||
| 	wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CAN_REPLACE_PTK0); | ||||
| } | ||||
| 
 | ||||
| int ath9k_init_device(u16 devid, struct ath_softc *sc, | ||||
|  | ||||
| @ -19,6 +19,9 @@ | ||||
| #include "ath9k.h" | ||||
| #include "btcoex.h" | ||||
| 
 | ||||
| static void ath9k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | ||||
| 			u32 queues, bool drop); | ||||
| 
 | ||||
| u8 ath9k_parse_mpdudensity(u8 mpdudensity) | ||||
| { | ||||
| 	/*
 | ||||
| @ -1701,6 +1704,15 @@ static int ath9k_set_key(struct ieee80211_hw *hw, | ||||
| 		return -EOPNOTSUPP; | ||||
| 	} | ||||
| 
 | ||||
| 	/* There may be MPDUs queued for the outgoing PTK key. Flush queues to
 | ||||
| 	 * make sure these are not send unencrypted or with a wrong (new) key | ||||
| 	 */ | ||||
| 	if (cmd == DISABLE_KEY && key->flags & IEEE80211_KEY_FLAG_PAIRWISE) { | ||||
| 		ieee80211_stop_queues(hw); | ||||
| 		ath9k_flush(hw, vif, 0, true); | ||||
| 		ieee80211_wake_queues(hw); | ||||
| 	} | ||||
| 
 | ||||
| 	mutex_lock(&sc->mutex); | ||||
| 	ath9k_ps_wakeup(sc); | ||||
| 	ath_dbg(common, CONFIG, "Set HW Key %d\n", cmd); | ||||
| @ -1934,7 +1946,7 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, | ||||
| 	case IEEE80211_AMPDU_TX_STOP_FLUSH: | ||||
| 	case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: | ||||
| 		flush = true; | ||||
| 		/* fall through */ | ||||
| 		fallthrough; | ||||
| 	case IEEE80211_AMPDU_TX_STOP_CONT: | ||||
| 		ath9k_ps_wakeup(sc); | ||||
| 		ath_tx_aggr_stop(sc, sta, tid); | ||||
|  | ||||
| @ -825,6 +825,7 @@ static void ath_pci_aspm_init(struct ath_common *common) | ||||
| 	struct pci_dev *pdev = to_pci_dev(sc->dev); | ||||
| 	struct pci_dev *parent; | ||||
| 	u16 aspm; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	if (!ah->is_pciexpress) | ||||
| 		return; | ||||
| @ -866,8 +867,8 @@ static void ath_pci_aspm_init(struct ath_common *common) | ||||
| 	if (AR_SREV_9462(ah)) | ||||
| 		pci_read_config_dword(pdev, 0x70c, &ah->config.aspm_l1_fix); | ||||
| 
 | ||||
| 	pcie_capability_read_word(parent, PCI_EXP_LNKCTL, &aspm); | ||||
| 	if (aspm & (PCI_EXP_LNKCTL_ASPM_L0S | PCI_EXP_LNKCTL_ASPM_L1)) { | ||||
| 	ret = pcie_capability_read_word(parent, PCI_EXP_LNKCTL, &aspm); | ||||
| 	if (!ret && (aspm & (PCI_EXP_LNKCTL_ASPM_L0S | PCI_EXP_LNKCTL_ASPM_L1))) { | ||||
| 		ah->aspm_enabled = true; | ||||
| 		/* Initialize PCIe PM and SERDES registers. */ | ||||
| 		ath9k_hw_configpcipowersave(ah, false); | ||||
|  | ||||
| @ -121,7 +121,7 @@ void ath9k_stop_wmi(struct ath9k_htc_priv *priv) | ||||
| 	mutex_unlock(&wmi->op_mutex); | ||||
| } | ||||
| 
 | ||||
| void ath9k_destoy_wmi(struct ath9k_htc_priv *priv) | ||||
| void ath9k_destroy_wmi(struct ath9k_htc_priv *priv) | ||||
| { | ||||
| 	kfree(priv->wmi); | ||||
| } | ||||
|  | ||||
| @ -189,7 +189,7 @@ void ath9k_wmi_event_tasklet(unsigned long data); | ||||
| void ath9k_fatal_work(struct work_struct *work); | ||||
| void ath9k_wmi_event_drain(struct ath9k_htc_priv *priv); | ||||
| void ath9k_stop_wmi(struct ath9k_htc_priv *priv); | ||||
| void ath9k_destoy_wmi(struct ath9k_htc_priv *priv); | ||||
| void ath9k_destroy_wmi(struct ath9k_htc_priv *priv); | ||||
| 
 | ||||
| #define WMI_CMD(_wmi_cmd)						\ | ||||
| 	do {								\ | ||||
|  | ||||
| @ -253,17 +253,15 @@ channel_detector_get(struct dfs_pattern_detector *dpd, u16 freq) | ||||
| static void dpd_reset(struct dfs_pattern_detector *dpd) | ||||
| { | ||||
| 	struct channel_detector *cd; | ||||
| 	if (!list_empty(&dpd->channel_detectors)) | ||||
| 		list_for_each_entry(cd, &dpd->channel_detectors, head) | ||||
| 			channel_detector_reset(dpd, cd); | ||||
| 	list_for_each_entry(cd, &dpd->channel_detectors, head) | ||||
| 		channel_detector_reset(dpd, cd); | ||||
| 
 | ||||
| } | ||||
| static void dpd_exit(struct dfs_pattern_detector *dpd) | ||||
| { | ||||
| 	struct channel_detector *cd, *cd0; | ||||
| 	if (!list_empty(&dpd->channel_detectors)) | ||||
| 		list_for_each_entry_safe(cd, cd0, &dpd->channel_detectors, head) | ||||
| 			channel_detector_exit(dpd, cd); | ||||
| 	list_for_each_entry_safe(cd, cd0, &dpd->channel_detectors, head) | ||||
| 		channel_detector_exit(dpd, cd); | ||||
| 	kfree(dpd); | ||||
| } | ||||
| 
 | ||||
| @ -331,9 +329,8 @@ static bool dpd_set_domain(struct dfs_pattern_detector *dpd, | ||||
| 		return false; | ||||
| 
 | ||||
| 	/* delete all channel detectors for previous DFS domain */ | ||||
| 	if (!list_empty(&dpd->channel_detectors)) | ||||
| 		list_for_each_entry_safe(cd, cd0, &dpd->channel_detectors, head) | ||||
| 			channel_detector_exit(dpd, cd); | ||||
| 	list_for_each_entry_safe(cd, cd0, &dpd->channel_detectors, head) | ||||
| 		channel_detector_exit(dpd, cd); | ||||
| 	dpd->radar_spec = rt->radar_types; | ||||
| 	dpd->num_radar_types = rt->num_radar_types; | ||||
| 
 | ||||
|  | ||||
| @ -334,6 +334,7 @@ void wcn36xx_dxe_tx_ack_ind(struct wcn36xx *wcn, u32 status) | ||||
| 	spin_lock_irqsave(&wcn->dxe_lock, flags); | ||||
| 	skb = wcn->tx_ack_skb; | ||||
| 	wcn->tx_ack_skb = NULL; | ||||
| 	del_timer(&wcn->tx_ack_timer); | ||||
| 	spin_unlock_irqrestore(&wcn->dxe_lock, flags); | ||||
| 
 | ||||
| 	if (!skb) { | ||||
| @ -345,6 +346,8 @@ void wcn36xx_dxe_tx_ack_ind(struct wcn36xx *wcn, u32 status) | ||||
| 
 | ||||
| 	if (status == 1) | ||||
| 		info->flags |= IEEE80211_TX_STAT_ACK; | ||||
| 	else | ||||
| 		info->flags &= ~IEEE80211_TX_STAT_ACK; | ||||
| 
 | ||||
| 	wcn36xx_dbg(WCN36XX_DBG_DXE, "dxe tx ack status: %d\n", status); | ||||
| 
 | ||||
| @ -352,6 +355,32 @@ void wcn36xx_dxe_tx_ack_ind(struct wcn36xx *wcn, u32 status) | ||||
| 	ieee80211_wake_queues(wcn->hw); | ||||
| } | ||||
| 
 | ||||
| static void wcn36xx_dxe_tx_timer(struct timer_list *t) | ||||
| { | ||||
| 	struct wcn36xx *wcn = from_timer(wcn, t, tx_ack_timer); | ||||
| 	struct ieee80211_tx_info *info; | ||||
| 	unsigned long flags; | ||||
| 	struct sk_buff *skb; | ||||
| 
 | ||||
| 	/* TX Timeout */ | ||||
| 	wcn36xx_dbg(WCN36XX_DBG_DXE, "TX timeout\n"); | ||||
| 
 | ||||
| 	spin_lock_irqsave(&wcn->dxe_lock, flags); | ||||
| 	skb = wcn->tx_ack_skb; | ||||
| 	wcn->tx_ack_skb = NULL; | ||||
| 	spin_unlock_irqrestore(&wcn->dxe_lock, flags); | ||||
| 
 | ||||
| 	if (!skb) | ||||
| 		return; | ||||
| 
 | ||||
| 	info = IEEE80211_SKB_CB(skb); | ||||
| 	info->flags &= ~IEEE80211_TX_STAT_ACK; | ||||
| 	info->flags &= ~IEEE80211_TX_STAT_NOACK_TRANSMITTED; | ||||
| 
 | ||||
| 	ieee80211_tx_status_irqsafe(wcn->hw, skb); | ||||
| 	ieee80211_wake_queues(wcn->hw); | ||||
| } | ||||
| 
 | ||||
| static void reap_tx_dxes(struct wcn36xx *wcn, struct wcn36xx_dxe_ch *ch) | ||||
| { | ||||
| 	struct wcn36xx_dxe_ctl *ctl; | ||||
| @ -397,6 +426,7 @@ static irqreturn_t wcn36xx_irq_tx_complete(int irq, void *dev) | ||||
| { | ||||
| 	struct wcn36xx *wcn = (struct wcn36xx *)dev; | ||||
| 	int int_src, int_reason; | ||||
| 	bool transmitted = false; | ||||
| 
 | ||||
| 	wcn36xx_dxe_read_register(wcn, WCN36XX_DXE_INT_SRC_RAW_REG, &int_src); | ||||
| 
 | ||||
| @ -434,8 +464,10 @@ static irqreturn_t wcn36xx_irq_tx_complete(int irq, void *dev) | ||||
| 			    int_reason); | ||||
| 
 | ||||
| 		if (int_reason & (WCN36XX_CH_STAT_INT_DONE_MASK | | ||||
| 				  WCN36XX_CH_STAT_INT_ED_MASK)) | ||||
| 				  WCN36XX_CH_STAT_INT_ED_MASK)) { | ||||
| 			reap_tx_dxes(wcn, &wcn->dxe_tx_h_ch); | ||||
| 			transmitted = true; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (int_src & WCN36XX_INT_MASK_CHAN_TX_L) { | ||||
| @ -473,10 +505,28 @@ static irqreturn_t wcn36xx_irq_tx_complete(int irq, void *dev) | ||||
| 			    int_reason); | ||||
| 
 | ||||
| 		if (int_reason & (WCN36XX_CH_STAT_INT_DONE_MASK | | ||||
| 				  WCN36XX_CH_STAT_INT_ED_MASK)) | ||||
| 				  WCN36XX_CH_STAT_INT_ED_MASK)) { | ||||
| 			reap_tx_dxes(wcn, &wcn->dxe_tx_l_ch); | ||||
| 			transmitted = true; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	spin_lock(&wcn->dxe_lock); | ||||
| 	if (wcn->tx_ack_skb && transmitted) { | ||||
| 		struct ieee80211_tx_info *info = IEEE80211_SKB_CB(wcn->tx_ack_skb); | ||||
| 
 | ||||
| 		/* TX complete, no need to wait for 802.11 ack indication */ | ||||
| 		if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS && | ||||
| 		    info->flags & IEEE80211_TX_CTL_NO_ACK) { | ||||
| 			info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; | ||||
| 			del_timer(&wcn->tx_ack_timer); | ||||
| 			ieee80211_tx_status_irqsafe(wcn->hw, wcn->tx_ack_skb); | ||||
| 			wcn->tx_ack_skb = NULL; | ||||
| 			ieee80211_wake_queues(wcn->hw); | ||||
| 		} | ||||
| 	} | ||||
| 	spin_unlock(&wcn->dxe_lock); | ||||
| 
 | ||||
| 	return IRQ_HANDLED; | ||||
| } | ||||
| 
 | ||||
| @ -916,6 +966,8 @@ int wcn36xx_dxe_init(struct wcn36xx *wcn) | ||||
| 	if (ret < 0) | ||||
| 		goto out_err_irq; | ||||
| 
 | ||||
| 	timer_setup(&wcn->tx_ack_timer, wcn36xx_dxe_tx_timer, 0); | ||||
| 
 | ||||
| 	return 0; | ||||
| 
 | ||||
| out_err_irq: | ||||
| @ -934,6 +986,7 @@ void wcn36xx_dxe_deinit(struct wcn36xx *wcn) | ||||
| { | ||||
| 	free_irq(wcn->tx_irq, wcn); | ||||
| 	free_irq(wcn->rx_irq, wcn); | ||||
| 	del_timer(&wcn->tx_ack_timer); | ||||
| 
 | ||||
| 	if (wcn->tx_ack_skb) { | ||||
| 		ieee80211_tx_status_irqsafe(wcn->hw, wcn->tx_ack_skb); | ||||
|  | ||||
| @ -163,7 +163,7 @@ static struct ieee80211_supported_band wcn_band_5ghz = { | ||||
| 		.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16, | ||||
| 		.mcs = { | ||||
| 			.rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, | ||||
| 			.rx_highest = cpu_to_le16(72), | ||||
| 			.rx_highest = cpu_to_le16(150), | ||||
| 			.tx_params = IEEE80211_HT_MCS_TX_DEFINED, | ||||
| 		} | ||||
| 	} | ||||
| @ -1083,6 +1083,7 @@ static int wcn36xx_ampdu_action(struct ieee80211_hw *hw, | ||||
| 	u16 tid = params->tid; | ||||
| 	u16 *ssn = ¶ms->ssn; | ||||
| 	int ret = 0; | ||||
| 	u8 session; | ||||
| 
 | ||||
| 	wcn36xx_dbg(WCN36XX_DBG_MAC, "mac ampdu action action %d tid %d\n", | ||||
| 		    action, tid); | ||||
| @ -1092,10 +1093,11 @@ static int wcn36xx_ampdu_action(struct ieee80211_hw *hw, | ||||
| 	switch (action) { | ||||
| 	case IEEE80211_AMPDU_RX_START: | ||||
| 		sta_priv->tid = tid; | ||||
| 		wcn36xx_smd_add_ba_session(wcn, sta, tid, ssn, 0, | ||||
| 			get_sta_index(vif, sta_priv)); | ||||
| 		wcn36xx_smd_add_ba(wcn); | ||||
| 		wcn36xx_smd_trigger_ba(wcn, get_sta_index(vif, sta_priv)); | ||||
| 		session = wcn36xx_smd_add_ba_session(wcn, sta, tid, ssn, 0, | ||||
| 						     get_sta_index(vif, sta_priv)); | ||||
| 		wcn36xx_smd_add_ba(wcn, session); | ||||
| 		wcn36xx_smd_trigger_ba(wcn, get_sta_index(vif, sta_priv), tid, | ||||
| 				       session); | ||||
| 		break; | ||||
| 	case IEEE80211_AMPDU_RX_STOP: | ||||
| 		wcn36xx_smd_del_ba(wcn, tid, get_sta_index(vif, sta_priv)); | ||||
| @ -1173,6 +1175,7 @@ static int wcn36xx_init_ieee80211(struct wcn36xx *wcn) | ||||
| 	ieee80211_hw_set(wcn->hw, SIGNAL_DBM); | ||||
| 	ieee80211_hw_set(wcn->hw, HAS_RATE_CONTROL); | ||||
| 	ieee80211_hw_set(wcn->hw, SINGLE_SCAN_ON_ALL_BANDS); | ||||
| 	ieee80211_hw_set(wcn->hw, REPORTS_TX_ACK_STATUS); | ||||
| 
 | ||||
| 	wcn->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | | ||||
| 		BIT(NL80211_IFTYPE_AP) | | ||||
|  | ||||
| @ -45,8 +45,8 @@ static struct wcn36xx_cfg_val wcn36xx_cfg_vals[] = { | ||||
| 	WCN36XX_CFG_VAL(MAX_MEDIUM_TIME, 6000), | ||||
| 	WCN36XX_CFG_VAL(MAX_MPDUS_IN_AMPDU, 64), | ||||
| 	WCN36XX_CFG_VAL(RTS_THRESHOLD, 2347), | ||||
| 	WCN36XX_CFG_VAL(SHORT_RETRY_LIMIT, 6), | ||||
| 	WCN36XX_CFG_VAL(LONG_RETRY_LIMIT, 6), | ||||
| 	WCN36XX_CFG_VAL(SHORT_RETRY_LIMIT, 15), | ||||
| 	WCN36XX_CFG_VAL(LONG_RETRY_LIMIT, 15), | ||||
| 	WCN36XX_CFG_VAL(FRAGMENTATION_THRESHOLD, 8000), | ||||
| 	WCN36XX_CFG_VAL(DYNAMIC_THRESHOLD_ZERO, 5), | ||||
| 	WCN36XX_CFG_VAL(DYNAMIC_THRESHOLD_ONE, 10), | ||||
| @ -2102,6 +2102,22 @@ out: | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static int wcn36xx_smd_add_ba_session_rsp(void *buf, int len, u8 *session) | ||||
| { | ||||
| 	struct wcn36xx_hal_add_ba_session_rsp_msg *rsp; | ||||
| 
 | ||||
| 	if (len < sizeof(*rsp)) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	rsp = (struct wcn36xx_hal_add_ba_session_rsp_msg *)buf; | ||||
| 	if (rsp->status != WCN36XX_FW_MSG_RESULT_SUCCESS) | ||||
| 		return rsp->status; | ||||
| 
 | ||||
| 	*session = rsp->ba_session_id; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| int wcn36xx_smd_add_ba_session(struct wcn36xx *wcn, | ||||
| 		struct ieee80211_sta *sta, | ||||
| 		u16 tid, | ||||
| @ -2110,6 +2126,7 @@ int wcn36xx_smd_add_ba_session(struct wcn36xx *wcn, | ||||
| 		u8 sta_index) | ||||
| { | ||||
| 	struct wcn36xx_hal_add_ba_session_req_msg msg_body; | ||||
| 	u8 session_id; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	mutex_lock(&wcn->hal_mutex); | ||||
| @ -2135,17 +2152,20 @@ int wcn36xx_smd_add_ba_session(struct wcn36xx *wcn, | ||||
| 		wcn36xx_err("Sending hal_add_ba_session failed\n"); | ||||
| 		goto out; | ||||
| 	} | ||||
| 	ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); | ||||
| 	ret = wcn36xx_smd_add_ba_session_rsp(wcn->hal_buf, wcn->hal_rsp_len, | ||||
| 					     &session_id); | ||||
| 	if (ret) { | ||||
| 		wcn36xx_err("hal_add_ba_session response failed err=%d\n", ret); | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	ret = session_id; | ||||
| out: | ||||
| 	mutex_unlock(&wcn->hal_mutex); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| int wcn36xx_smd_add_ba(struct wcn36xx *wcn) | ||||
| int wcn36xx_smd_add_ba(struct wcn36xx *wcn, u8 session_id) | ||||
| { | ||||
| 	struct wcn36xx_hal_add_ba_req_msg msg_body; | ||||
| 	int ret; | ||||
| @ -2153,7 +2173,7 @@ int wcn36xx_smd_add_ba(struct wcn36xx *wcn) | ||||
| 	mutex_lock(&wcn->hal_mutex); | ||||
| 	INIT_HAL_MSG(msg_body, WCN36XX_HAL_ADD_BA_REQ); | ||||
| 
 | ||||
| 	msg_body.session_id = 0; | ||||
| 	msg_body.session_id = session_id; | ||||
| 	msg_body.win_size = WCN36XX_AGGR_BUFFER_SIZE; | ||||
| 
 | ||||
| 	PREPARE_HAL_BUF(wcn->hal_buf, msg_body); | ||||
| @ -2212,7 +2232,7 @@ static int wcn36xx_smd_trigger_ba_rsp(void *buf, int len) | ||||
| 	return rsp->status; | ||||
| } | ||||
| 
 | ||||
| int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index) | ||||
| int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index, u16 tid, u8 session_id) | ||||
| { | ||||
| 	struct wcn36xx_hal_trigger_ba_req_msg msg_body; | ||||
| 	struct wcn36xx_hal_trigger_ba_req_candidate *candidate; | ||||
| @ -2221,7 +2241,7 @@ int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index) | ||||
| 	mutex_lock(&wcn->hal_mutex); | ||||
| 	INIT_HAL_MSG(msg_body, WCN36XX_HAL_TRIGGER_BA_REQ); | ||||
| 
 | ||||
| 	msg_body.session_id = 0; | ||||
| 	msg_body.session_id = session_id; | ||||
| 	msg_body.candidate_cnt = 1; | ||||
| 	msg_body.header.len += sizeof(*candidate); | ||||
| 	PREPARE_HAL_BUF(wcn->hal_buf, msg_body); | ||||
| @ -2229,7 +2249,7 @@ int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index) | ||||
| 	candidate = (struct wcn36xx_hal_trigger_ba_req_candidate *) | ||||
| 		(wcn->hal_buf + sizeof(msg_body)); | ||||
| 	candidate->sta_index = sta_index; | ||||
| 	candidate->tid_bitmap = 1; | ||||
| 	candidate->tid_bitmap = 1 << tid; | ||||
| 
 | ||||
| 	ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); | ||||
| 	if (ret) { | ||||
|  | ||||
| @ -132,9 +132,9 @@ int wcn36xx_smd_add_ba_session(struct wcn36xx *wcn, | ||||
| 		u16 *ssn, | ||||
| 		u8 direction, | ||||
| 		u8 sta_index); | ||||
| int wcn36xx_smd_add_ba(struct wcn36xx *wcn); | ||||
| int wcn36xx_smd_add_ba(struct wcn36xx *wcn, u8 session_id); | ||||
| int wcn36xx_smd_del_ba(struct wcn36xx *wcn, u16 tid, u8 sta_index); | ||||
| int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index); | ||||
| int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index, u16 tid, u8 session_id); | ||||
| 
 | ||||
| int wcn36xx_smd_update_cfg(struct wcn36xx *wcn, u32 cfg_id, u32 value); | ||||
| 
 | ||||
|  | ||||
| @ -23,9 +23,104 @@ static inline int get_rssi0(struct wcn36xx_rx_bd *bd) | ||||
| 	return 100 - ((bd->phy_stat0 >> 24) & 0xff); | ||||
| } | ||||
| 
 | ||||
| struct wcn36xx_rate { | ||||
| 	u16 bitrate; | ||||
| 	u16 mcs_or_legacy_index; | ||||
| 	enum mac80211_rx_encoding encoding; | ||||
| 	enum mac80211_rx_encoding_flags encoding_flags; | ||||
| 	enum rate_info_bw bw; | ||||
| }; | ||||
| 
 | ||||
| static const struct wcn36xx_rate wcn36xx_rate_table[] = { | ||||
| 	/* 11b rates */ | ||||
| 	{  10, 0, RX_ENC_LEGACY, 0, RATE_INFO_BW_20 }, | ||||
| 	{  20, 1, RX_ENC_LEGACY, 0, RATE_INFO_BW_20 }, | ||||
| 	{  55, 2, RX_ENC_LEGACY, 0, RATE_INFO_BW_20 }, | ||||
| 	{ 110, 3, RX_ENC_LEGACY, 0, RATE_INFO_BW_20 }, | ||||
| 
 | ||||
| 	/* 11b SP (short preamble) */ | ||||
| 	{  10, 0, RX_ENC_LEGACY, RX_ENC_FLAG_SHORTPRE, RATE_INFO_BW_20 }, | ||||
| 	{  20, 1, RX_ENC_LEGACY, RX_ENC_FLAG_SHORTPRE, RATE_INFO_BW_20 }, | ||||
| 	{  55, 2, RX_ENC_LEGACY, RX_ENC_FLAG_SHORTPRE, RATE_INFO_BW_20 }, | ||||
| 	{ 110, 3, RX_ENC_LEGACY, RX_ENC_FLAG_SHORTPRE, RATE_INFO_BW_20 }, | ||||
| 
 | ||||
| 	/* 11ag */ | ||||
| 	{  60, 4, RX_ENC_LEGACY, 0, RATE_INFO_BW_20 }, | ||||
| 	{  90, 5, RX_ENC_LEGACY, 0, RATE_INFO_BW_20 }, | ||||
| 	{ 120, 6, RX_ENC_LEGACY, 0, RATE_INFO_BW_20 }, | ||||
| 	{ 180, 7, RX_ENC_LEGACY, 0, RATE_INFO_BW_20 }, | ||||
| 	{ 240, 8, RX_ENC_LEGACY, 0, RATE_INFO_BW_20 }, | ||||
| 	{ 360, 9, RX_ENC_LEGACY, 0, RATE_INFO_BW_20 }, | ||||
| 	{ 480, 10, RX_ENC_LEGACY, 0, RATE_INFO_BW_20 }, | ||||
| 	{ 540, 11, RX_ENC_LEGACY, 0, RATE_INFO_BW_20 }, | ||||
| 
 | ||||
| 	/* 11n */ | ||||
| 	{  65, 0, RX_ENC_HT, 0, RATE_INFO_BW_20 }, | ||||
| 	{ 130, 1, RX_ENC_HT, 0, RATE_INFO_BW_20 }, | ||||
| 	{ 195, 2, RX_ENC_HT, 0, RATE_INFO_BW_20 }, | ||||
| 	{ 260, 3, RX_ENC_HT, 0, RATE_INFO_BW_20 }, | ||||
| 	{ 390, 4, RX_ENC_HT, 0, RATE_INFO_BW_20 }, | ||||
| 	{ 520, 5, RX_ENC_HT, 0, RATE_INFO_BW_20 }, | ||||
| 	{ 585, 6, RX_ENC_HT, 0, RATE_INFO_BW_20 }, | ||||
| 	{ 650, 7, RX_ENC_HT, 0, RATE_INFO_BW_20 }, | ||||
| 
 | ||||
| 	/* 11n SGI */ | ||||
| 	{  72, 0, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_20 }, | ||||
| 	{ 144, 1, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_20 }, | ||||
| 	{ 217, 2, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_20 }, | ||||
| 	{ 289, 3, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_20 }, | ||||
| 	{ 434, 4, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_20 }, | ||||
| 	{ 578, 5, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_20 }, | ||||
| 	{ 650, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_20 }, | ||||
| 	{ 722, 7, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_20 }, | ||||
| 
 | ||||
| 	/* 11n GF (greenfield) */ | ||||
| 	{  65, 0, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_20 }, | ||||
| 	{ 130, 1, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_20 }, | ||||
| 	{ 195, 2, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_20 }, | ||||
| 	{ 260, 3, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_20 }, | ||||
| 	{ 390, 4, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_20 }, | ||||
| 	{ 520, 5, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_20 }, | ||||
| 	{ 585, 6, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_20 }, | ||||
| 	{ 650, 7, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_20 }, | ||||
| 
 | ||||
| 	/* 11n CB (channel bonding) */ | ||||
| 	{ 135, 0, RX_ENC_HT, 0, RATE_INFO_BW_40 }, | ||||
| 	{ 270, 1, RX_ENC_HT, 0, RATE_INFO_BW_40 }, | ||||
| 	{ 405, 2, RX_ENC_HT, 0, RATE_INFO_BW_40 }, | ||||
| 	{ 540, 3, RX_ENC_HT, 0, RATE_INFO_BW_40 }, | ||||
| 	{ 810, 4, RX_ENC_HT, 0, RATE_INFO_BW_40 }, | ||||
| 	{ 1080, 5, RX_ENC_HT, 0, RATE_INFO_BW_40 }, | ||||
| 	{ 1215, 6, RX_ENC_HT, 0, RATE_INFO_BW_40 }, | ||||
| 	{ 1350, 7, RX_ENC_HT, 0, RATE_INFO_BW_40 }, | ||||
| 
 | ||||
| 	/* 11n CB + SGI */ | ||||
| 	{ 150, 0, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, | ||||
| 	{ 300, 1, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, | ||||
| 	{ 450, 2, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, | ||||
| 	{ 600, 3, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, | ||||
| 	{ 900, 4, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, | ||||
| 	{ 1200, 5, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, | ||||
| 	{ 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, | ||||
| 	{ 1500, 7, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, | ||||
| 
 | ||||
| 	/* 11n GF + CB */ | ||||
| 	{ 135, 0, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_40 }, | ||||
| 	{ 270, 1, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_40 }, | ||||
| 	{ 405, 2, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_40 }, | ||||
| 	{ 540, 3, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_40 }, | ||||
| 	{ 810, 4, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_40 }, | ||||
| 	{ 1080, 5, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_40 }, | ||||
| 	{ 1215, 6, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_40 }, | ||||
| 	{ 1350, 7, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_40 }, | ||||
| 
 | ||||
| 	/* TODO: AC rates */ | ||||
| }; | ||||
| 
 | ||||
| int wcn36xx_rx_skb(struct wcn36xx *wcn, struct sk_buff *skb) | ||||
| { | ||||
| 	struct ieee80211_rx_status status; | ||||
| 	const struct wcn36xx_rate *rate; | ||||
| 	struct ieee80211_hdr *hdr; | ||||
| 	struct wcn36xx_rx_bd *bd; | ||||
| 	u16 fc, sn; | ||||
| @ -61,7 +156,6 @@ int wcn36xx_rx_skb(struct wcn36xx *wcn, struct sk_buff *skb) | ||||
| 	status.mactime = 10; | ||||
| 	status.signal = -get_rssi0(bd); | ||||
| 	status.antenna = 1; | ||||
| 	status.rate_idx = 1; | ||||
| 	status.flag = 0; | ||||
| 	status.rx_flags = 0; | ||||
| 	status.flag |= RX_FLAG_IV_STRIPPED | | ||||
| @ -70,6 +164,19 @@ int wcn36xx_rx_skb(struct wcn36xx *wcn, struct sk_buff *skb) | ||||
| 
 | ||||
| 	wcn36xx_dbg(WCN36XX_DBG_RX, "status.flags=%x\n", status.flag); | ||||
| 
 | ||||
| 	if (bd->rate_id < ARRAY_SIZE(wcn36xx_rate_table)) { | ||||
| 		rate = &wcn36xx_rate_table[bd->rate_id]; | ||||
| 		status.encoding = rate->encoding; | ||||
| 		status.enc_flags = rate->encoding_flags; | ||||
| 		status.bw = rate->bw; | ||||
| 		status.rate_idx = rate->mcs_or_legacy_index; | ||||
| 	} else { | ||||
| 		status.encoding = 0; | ||||
| 		status.bw = 0; | ||||
| 		status.enc_flags = 0; | ||||
| 		status.rate_idx = 0; | ||||
| 	} | ||||
| 
 | ||||
| 	memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); | ||||
| 
 | ||||
| 	if (ieee80211_is_beacon(hdr->frame_control)) { | ||||
| @ -100,7 +207,8 @@ static void wcn36xx_set_tx_pdu(struct wcn36xx_tx_bd *bd, | ||||
| 		bd->pdu.mpdu_header_off; | ||||
| 	bd->pdu.mpdu_len = len; | ||||
| 	bd->pdu.tid = tid; | ||||
| 	bd->pdu.bd_ssn = WCN36XX_TXBD_SSN_FILL_DPU_QOS; | ||||
| 	/* Use seq number generated by mac80211 */ | ||||
| 	bd->pdu.bd_ssn = WCN36XX_TXBD_SSN_FILL_HOST; | ||||
| } | ||||
| 
 | ||||
| static inline struct wcn36xx_vif *get_vif_by_addr(struct wcn36xx *wcn, | ||||
| @ -160,9 +268,11 @@ static void wcn36xx_set_tx_data(struct wcn36xx_tx_bd *bd, | ||||
| 				bool bcast) | ||||
| { | ||||
| 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | ||||
| 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||||
| 	struct ieee80211_vif *vif = NULL; | ||||
| 	struct wcn36xx_vif *__vif_priv = NULL; | ||||
| 	bool is_data_qos; | ||||
| 	bool is_data_qos = ieee80211_is_data_qos(hdr->frame_control); | ||||
| 	u16 tid = 0; | ||||
| 
 | ||||
| 	bd->bd_rate = WCN36XX_BD_RATE_DATA; | ||||
| 
 | ||||
| @ -191,9 +301,21 @@ static void wcn36xx_set_tx_data(struct wcn36xx_tx_bd *bd, | ||||
| 		bd->dpu_sign = __vif_priv->self_ucast_dpu_sign; | ||||
| 	} | ||||
| 
 | ||||
| 	if (ieee80211_is_nullfunc(hdr->frame_control) || | ||||
| 	   (sta_priv && !sta_priv->is_data_encrypted)) | ||||
| 	if (is_data_qos) { | ||||
| 		tid = ieee80211_get_tid(hdr); | ||||
| 		/* TID->QID is one-to-one mapping */ | ||||
| 		bd->queue_id = tid; | ||||
| 	} | ||||
| 
 | ||||
| 	if (info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT || | ||||
| 	    (sta_priv && !sta_priv->is_data_encrypted)) { | ||||
| 		bd->dpu_ne = 1; | ||||
| 	} | ||||
| 
 | ||||
| 	if (ieee80211_is_any_nullfunc(hdr->frame_control)) { | ||||
| 		/* Don't use a regular queue for null packet (no ampdu) */ | ||||
| 		bd->queue_id = WCN36XX_TX_U_WQ_ID; | ||||
| 	} | ||||
| 
 | ||||
| 	if (bcast) { | ||||
| 		bd->ub = 1; | ||||
| @ -201,13 +323,11 @@ static void wcn36xx_set_tx_data(struct wcn36xx_tx_bd *bd, | ||||
| 	} | ||||
| 	*vif_priv = __vif_priv; | ||||
| 
 | ||||
| 	is_data_qos = ieee80211_is_data_qos(hdr->frame_control); | ||||
| 
 | ||||
| 	wcn36xx_set_tx_pdu(bd, | ||||
| 			   is_data_qos ? | ||||
| 			   sizeof(struct ieee80211_qos_hdr) : | ||||
| 			   sizeof(struct ieee80211_hdr_3addr), | ||||
| 			   skb->len, sta_priv ? sta_priv->tid : 0); | ||||
| 			   skb->len, tid); | ||||
| 
 | ||||
| 	if (sta_priv && is_data_qos) | ||||
| 		wcn36xx_tx_start_ampdu(wcn, sta_priv, skb); | ||||
| @ -287,9 +407,9 @@ int wcn36xx_start_tx(struct wcn36xx *wcn, | ||||
| 
 | ||||
| 	bd.dpu_rf = WCN36XX_BMU_WQ_TX; | ||||
| 
 | ||||
| 	bd.tx_comp = !!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS); | ||||
| 	if (bd.tx_comp) { | ||||
| 	if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) { | ||||
| 		wcn36xx_dbg(WCN36XX_DBG_DXE, "TX_ACK status requested\n"); | ||||
| 
 | ||||
| 		spin_lock_irqsave(&wcn->dxe_lock, flags); | ||||
| 		if (wcn->tx_ack_skb) { | ||||
| 			spin_unlock_irqrestore(&wcn->dxe_lock, flags); | ||||
| @ -302,10 +422,15 @@ int wcn36xx_start_tx(struct wcn36xx *wcn, | ||||
| 
 | ||||
| 		/* Only one at a time is supported by fw. Stop the TX queues
 | ||||
| 		 * until the ack status gets back. | ||||
| 		 * | ||||
| 		 * TODO: Add watchdog in case FW does not answer | ||||
| 		 */ | ||||
| 		ieee80211_stop_queues(wcn->hw); | ||||
| 
 | ||||
| 		/* TX watchdog if no TX irq or ack indication received  */ | ||||
| 		mod_timer(&wcn->tx_ack_timer, jiffies + HZ / 10); | ||||
| 
 | ||||
| 		/* Request ack indication from the firmware */ | ||||
| 		if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) | ||||
| 			bd.tx_comp = 1; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Data frames served first*/ | ||||
| @ -319,7 +444,7 @@ int wcn36xx_start_tx(struct wcn36xx *wcn, | ||||
| 	bd.tx_bd_sign = 0xbdbdbdbd; | ||||
| 
 | ||||
| 	ret = wcn36xx_dxe_tx_frame(wcn, vif_priv, &bd, skb, is_low); | ||||
| 	if (ret && bd.tx_comp) { | ||||
| 	if (ret && (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)) { | ||||
| 		/* If the skb has not been transmitted,
 | ||||
| 		 * don't keep a reference to it. | ||||
| 		 */ | ||||
|  | ||||
| @ -245,6 +245,7 @@ struct wcn36xx { | ||||
| 	struct wcn36xx_dxe_mem_pool data_mem_pool; | ||||
| 
 | ||||
| 	struct sk_buff		*tx_ack_skb; | ||||
| 	struct timer_list	tx_ack_timer; | ||||
| 
 | ||||
| 	/* RF module */ | ||||
| 	unsigned		rf_id; | ||||
|  | ||||
| @ -1739,7 +1739,7 @@ static int wil_cancel_remain_on_channel(struct wiphy *wiphy, | ||||
| 	return wil_p2p_cancel_listen(vif, cookie); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
| /*
 | ||||
|  * find a specific IE in a list of IEs | ||||
|  * return a pointer to the beginning of IE in the list | ||||
|  * or NULL if not found | ||||
| @ -1766,7 +1766,7 @@ static const u8 *_wil_cfg80211_find_ie(const u8 *ies, u16 ies_len, const u8 *ie, | ||||
| 				       ies_len); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
| /*
 | ||||
|  * merge the IEs in two lists into a single list. | ||||
|  * do not include IEs from the second list which exist in the first list. | ||||
|  * add only vendor specific IEs from second list to keep | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user