18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright (c) 2013 Eugene Krasnikov <k.eugene.e@gmail.com>
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Permission to use, copy, modify, and/or distribute this software for any
58c2ecf20Sopenharmony_ci * purpose with or without fee is hereby granted, provided that the above
68c2ecf20Sopenharmony_ci * copyright notice and this permission notice appear in all copies.
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
98c2ecf20Sopenharmony_ci * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
108c2ecf20Sopenharmony_ci * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
118c2ecf20Sopenharmony_ci * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
128c2ecf20Sopenharmony_ci * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
138c2ecf20Sopenharmony_ci * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
148c2ecf20Sopenharmony_ci * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
158c2ecf20Sopenharmony_ci */
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#include "txrx.h"
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_cistatic inline int get_rssi0(struct wcn36xx_rx_bd *bd)
228c2ecf20Sopenharmony_ci{
238c2ecf20Sopenharmony_ci	return 100 - ((bd->phy_stat0 >> 24) & 0xff);
248c2ecf20Sopenharmony_ci}
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_cistruct wcn36xx_rate {
278c2ecf20Sopenharmony_ci	u16 bitrate;
288c2ecf20Sopenharmony_ci	u16 mcs_or_legacy_index;
298c2ecf20Sopenharmony_ci	enum mac80211_rx_encoding encoding;
308c2ecf20Sopenharmony_ci	enum mac80211_rx_encoding_flags encoding_flags;
318c2ecf20Sopenharmony_ci	enum rate_info_bw bw;
328c2ecf20Sopenharmony_ci};
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci/* Buffer descriptor rx_ch field is limited to 5-bit (4+1), a mapping is used
358c2ecf20Sopenharmony_ci * for 11A Channels.
368c2ecf20Sopenharmony_ci */
378c2ecf20Sopenharmony_cistatic const u8 ab_rx_ch_map[] = { 36, 40, 44, 48, 52, 56, 60, 64, 100, 104,
388c2ecf20Sopenharmony_ci				   108, 112, 116, 120, 124, 128, 132, 136, 140,
398c2ecf20Sopenharmony_ci				   149, 153, 157, 161, 165, 144 };
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_cistatic const struct wcn36xx_rate wcn36xx_rate_table[] = {
428c2ecf20Sopenharmony_ci	/* 11b rates */
438c2ecf20Sopenharmony_ci	{  10, 0, RX_ENC_LEGACY, 0, RATE_INFO_BW_20 },
448c2ecf20Sopenharmony_ci	{  20, 1, RX_ENC_LEGACY, 0, RATE_INFO_BW_20 },
458c2ecf20Sopenharmony_ci	{  55, 2, RX_ENC_LEGACY, 0, RATE_INFO_BW_20 },
468c2ecf20Sopenharmony_ci	{ 110, 3, RX_ENC_LEGACY, 0, RATE_INFO_BW_20 },
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	/* 11b SP (short preamble) */
498c2ecf20Sopenharmony_ci	{  10, 0, RX_ENC_LEGACY, RX_ENC_FLAG_SHORTPRE, RATE_INFO_BW_20 },
508c2ecf20Sopenharmony_ci	{  20, 1, RX_ENC_LEGACY, RX_ENC_FLAG_SHORTPRE, RATE_INFO_BW_20 },
518c2ecf20Sopenharmony_ci	{  55, 2, RX_ENC_LEGACY, RX_ENC_FLAG_SHORTPRE, RATE_INFO_BW_20 },
528c2ecf20Sopenharmony_ci	{ 110, 3, RX_ENC_LEGACY, RX_ENC_FLAG_SHORTPRE, RATE_INFO_BW_20 },
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	/* 11ag */
558c2ecf20Sopenharmony_ci	{  60, 4, RX_ENC_LEGACY, 0, RATE_INFO_BW_20 },
568c2ecf20Sopenharmony_ci	{  90, 5, RX_ENC_LEGACY, 0, RATE_INFO_BW_20 },
578c2ecf20Sopenharmony_ci	{ 120, 6, RX_ENC_LEGACY, 0, RATE_INFO_BW_20 },
588c2ecf20Sopenharmony_ci	{ 180, 7, RX_ENC_LEGACY, 0, RATE_INFO_BW_20 },
598c2ecf20Sopenharmony_ci	{ 240, 8, RX_ENC_LEGACY, 0, RATE_INFO_BW_20 },
608c2ecf20Sopenharmony_ci	{ 360, 9, RX_ENC_LEGACY, 0, RATE_INFO_BW_20 },
618c2ecf20Sopenharmony_ci	{ 480, 10, RX_ENC_LEGACY, 0, RATE_INFO_BW_20 },
628c2ecf20Sopenharmony_ci	{ 540, 11, RX_ENC_LEGACY, 0, RATE_INFO_BW_20 },
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	/* 11n */
658c2ecf20Sopenharmony_ci	{  65, 0, RX_ENC_HT, 0, RATE_INFO_BW_20 },
668c2ecf20Sopenharmony_ci	{ 130, 1, RX_ENC_HT, 0, RATE_INFO_BW_20 },
678c2ecf20Sopenharmony_ci	{ 195, 2, RX_ENC_HT, 0, RATE_INFO_BW_20 },
688c2ecf20Sopenharmony_ci	{ 260, 3, RX_ENC_HT, 0, RATE_INFO_BW_20 },
698c2ecf20Sopenharmony_ci	{ 390, 4, RX_ENC_HT, 0, RATE_INFO_BW_20 },
708c2ecf20Sopenharmony_ci	{ 520, 5, RX_ENC_HT, 0, RATE_INFO_BW_20 },
718c2ecf20Sopenharmony_ci	{ 585, 6, RX_ENC_HT, 0, RATE_INFO_BW_20 },
728c2ecf20Sopenharmony_ci	{ 650, 7, RX_ENC_HT, 0, RATE_INFO_BW_20 },
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	/* 11n SGI */
758c2ecf20Sopenharmony_ci	{  72, 0, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_20 },
768c2ecf20Sopenharmony_ci	{ 144, 1, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_20 },
778c2ecf20Sopenharmony_ci	{ 217, 2, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_20 },
788c2ecf20Sopenharmony_ci	{ 289, 3, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_20 },
798c2ecf20Sopenharmony_ci	{ 434, 4, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_20 },
808c2ecf20Sopenharmony_ci	{ 578, 5, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_20 },
818c2ecf20Sopenharmony_ci	{ 650, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_20 },
828c2ecf20Sopenharmony_ci	{ 722, 7, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_20 },
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	/* 11n GF (greenfield) */
858c2ecf20Sopenharmony_ci	{  65, 0, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_20 },
868c2ecf20Sopenharmony_ci	{ 130, 1, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_20 },
878c2ecf20Sopenharmony_ci	{ 195, 2, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_20 },
888c2ecf20Sopenharmony_ci	{ 260, 3, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_20 },
898c2ecf20Sopenharmony_ci	{ 390, 4, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_20 },
908c2ecf20Sopenharmony_ci	{ 520, 5, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_20 },
918c2ecf20Sopenharmony_ci	{ 585, 6, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_20 },
928c2ecf20Sopenharmony_ci	{ 650, 7, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_20 },
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	/* 11n CB (channel bonding) */
958c2ecf20Sopenharmony_ci	{ 135, 0, RX_ENC_HT, 0, RATE_INFO_BW_40 },
968c2ecf20Sopenharmony_ci	{ 270, 1, RX_ENC_HT, 0, RATE_INFO_BW_40 },
978c2ecf20Sopenharmony_ci	{ 405, 2, RX_ENC_HT, 0, RATE_INFO_BW_40 },
988c2ecf20Sopenharmony_ci	{ 540, 3, RX_ENC_HT, 0, RATE_INFO_BW_40 },
998c2ecf20Sopenharmony_ci	{ 810, 4, RX_ENC_HT, 0, RATE_INFO_BW_40 },
1008c2ecf20Sopenharmony_ci	{ 1080, 5, RX_ENC_HT, 0, RATE_INFO_BW_40 },
1018c2ecf20Sopenharmony_ci	{ 1215, 6, RX_ENC_HT, 0, RATE_INFO_BW_40 },
1028c2ecf20Sopenharmony_ci	{ 1350, 7, RX_ENC_HT, 0, RATE_INFO_BW_40 },
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	/* 11n CB + SGI */
1058c2ecf20Sopenharmony_ci	{ 150, 0, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 },
1068c2ecf20Sopenharmony_ci	{ 300, 1, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 },
1078c2ecf20Sopenharmony_ci	{ 450, 2, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 },
1088c2ecf20Sopenharmony_ci	{ 600, 3, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 },
1098c2ecf20Sopenharmony_ci	{ 900, 4, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 },
1108c2ecf20Sopenharmony_ci	{ 1200, 5, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 },
1118c2ecf20Sopenharmony_ci	{ 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 },
1128c2ecf20Sopenharmony_ci	{ 1500, 7, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 },
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	/* 11n GF + CB */
1158c2ecf20Sopenharmony_ci	{ 135, 0, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_40 },
1168c2ecf20Sopenharmony_ci	{ 270, 1, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_40 },
1178c2ecf20Sopenharmony_ci	{ 405, 2, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_40 },
1188c2ecf20Sopenharmony_ci	{ 540, 3, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_40 },
1198c2ecf20Sopenharmony_ci	{ 810, 4, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_40 },
1208c2ecf20Sopenharmony_ci	{ 1080, 5, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_40 },
1218c2ecf20Sopenharmony_ci	{ 1215, 6, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_40 },
1228c2ecf20Sopenharmony_ci	{ 1350, 7, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_40 },
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	/* 11ac reserved indices */
1258c2ecf20Sopenharmony_ci	{ 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 },
1268c2ecf20Sopenharmony_ci	{ 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 },
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	/* 11ac 20 MHz 800ns GI MCS 0-8 */
1298c2ecf20Sopenharmony_ci	{   65, 0, RX_ENC_HT, 0, RATE_INFO_BW_20 },
1308c2ecf20Sopenharmony_ci	{  130, 1, RX_ENC_HT, 0, RATE_INFO_BW_20 },
1318c2ecf20Sopenharmony_ci	{  195, 2, RX_ENC_HT, 0, RATE_INFO_BW_20 },
1328c2ecf20Sopenharmony_ci	{  260, 3, RX_ENC_HT, 0, RATE_INFO_BW_20 },
1338c2ecf20Sopenharmony_ci	{  390, 4, RX_ENC_HT, 0, RATE_INFO_BW_20 },
1348c2ecf20Sopenharmony_ci	{  520, 5, RX_ENC_HT, 0, RATE_INFO_BW_20 },
1358c2ecf20Sopenharmony_ci	{  585, 6, RX_ENC_HT, 0, RATE_INFO_BW_20 },
1368c2ecf20Sopenharmony_ci	{  650, 7, RX_ENC_HT, 0, RATE_INFO_BW_20 },
1378c2ecf20Sopenharmony_ci	{  780, 8, RX_ENC_HT, 0, RATE_INFO_BW_20 },
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	/* 11ac reserved indices */
1408c2ecf20Sopenharmony_ci	{ 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 },
1418c2ecf20Sopenharmony_ci	{ 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 },
1428c2ecf20Sopenharmony_ci	{ 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 },
1438c2ecf20Sopenharmony_ci	{ 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 },
1448c2ecf20Sopenharmony_ci	{ 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 },
1458c2ecf20Sopenharmony_ci	{ 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 },
1468c2ecf20Sopenharmony_ci	{ 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 },
1478c2ecf20Sopenharmony_ci	{ 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 },
1488c2ecf20Sopenharmony_ci	{ 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 },
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	/* 11ac 20 MHz 400ns SGI MCS 6-8 */
1518c2ecf20Sopenharmony_ci	{  655, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_20 },
1528c2ecf20Sopenharmony_ci	{  722, 7, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_20 },
1538c2ecf20Sopenharmony_ci	{  866, 8, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_20 },
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	/* 11ac reserved indices */
1568c2ecf20Sopenharmony_ci	{ 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 },
1578c2ecf20Sopenharmony_ci	{ 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 },
1588c2ecf20Sopenharmony_ci	{ 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 },
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	/* 11ac 40 MHz 800ns GI MCS 0-9 */
1618c2ecf20Sopenharmony_ci	{  135, 0, RX_ENC_HT, 0, RATE_INFO_BW_40 },
1628c2ecf20Sopenharmony_ci	{  270, 1, RX_ENC_HT, 0, RATE_INFO_BW_40 },
1638c2ecf20Sopenharmony_ci	{  405, 2, RX_ENC_HT, 0, RATE_INFO_BW_40 },
1648c2ecf20Sopenharmony_ci	{  540, 3, RX_ENC_HT, 0, RATE_INFO_BW_40 },
1658c2ecf20Sopenharmony_ci	{  810, 4, RX_ENC_HT, 0, RATE_INFO_BW_40 },
1668c2ecf20Sopenharmony_ci	{ 1080, 5, RX_ENC_HT, 0, RATE_INFO_BW_40 },
1678c2ecf20Sopenharmony_ci	{ 1215, 6, RX_ENC_HT, 0, RATE_INFO_BW_40 },
1688c2ecf20Sopenharmony_ci	{ 1350, 7, RX_ENC_HT, 0, RATE_INFO_BW_40 },
1698c2ecf20Sopenharmony_ci	{ 1350, 7, RX_ENC_HT, 0, RATE_INFO_BW_40 },
1708c2ecf20Sopenharmony_ci	{ 1620, 8, RX_ENC_HT, 0, RATE_INFO_BW_40 },
1718c2ecf20Sopenharmony_ci	{ 1800, 9, RX_ENC_HT, 0, RATE_INFO_BW_40 },
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	/* 11ac reserved indices */
1748c2ecf20Sopenharmony_ci	{ 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 },
1758c2ecf20Sopenharmony_ci	{ 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 },
1768c2ecf20Sopenharmony_ci	{ 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 },
1778c2ecf20Sopenharmony_ci	{ 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 },
1788c2ecf20Sopenharmony_ci	{ 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 },
1798c2ecf20Sopenharmony_ci	{ 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 },
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	/* 11ac 40 MHz 400ns SGI MCS 5-7 */
1828c2ecf20Sopenharmony_ci	{ 1200, 5, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 },
1838c2ecf20Sopenharmony_ci	{ 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 },
1848c2ecf20Sopenharmony_ci	{ 1500, 7, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 },
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	/* 11ac reserved index */
1878c2ecf20Sopenharmony_ci	{ 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 },
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	/* 11ac 40 MHz 400ns SGI MCS 5-7 */
1908c2ecf20Sopenharmony_ci	{ 1800, 8, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 },
1918c2ecf20Sopenharmony_ci	{ 2000, 9, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 },
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	/* 11ac reserved index */
1948c2ecf20Sopenharmony_ci	{ 1350, 6, RX_ENC_HT,  RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 },
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	/* 11ac 80 MHz 800ns GI MCS 0-7 */
1978c2ecf20Sopenharmony_ci	{  292, 0, RX_ENC_HT, 0, RATE_INFO_BW_80},
1988c2ecf20Sopenharmony_ci	{  585, 1, RX_ENC_HT, 0, RATE_INFO_BW_80},
1998c2ecf20Sopenharmony_ci	{  877, 2, RX_ENC_HT, 0, RATE_INFO_BW_80},
2008c2ecf20Sopenharmony_ci	{ 1170, 3, RX_ENC_HT, 0, RATE_INFO_BW_80},
2018c2ecf20Sopenharmony_ci	{ 1755, 4, RX_ENC_HT, 0, RATE_INFO_BW_80},
2028c2ecf20Sopenharmony_ci	{ 2340, 5, RX_ENC_HT, 0, RATE_INFO_BW_80},
2038c2ecf20Sopenharmony_ci	{ 2632, 6, RX_ENC_HT, 0, RATE_INFO_BW_80},
2048c2ecf20Sopenharmony_ci	{ 2925, 7, RX_ENC_HT, 0, RATE_INFO_BW_80},
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	/* 11 ac reserved index */
2078c2ecf20Sopenharmony_ci	{ 1350, 6, RX_ENC_HT,  RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 },
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	/* 11ac 80 MHz 800 ns GI MCS 8-9 */
2108c2ecf20Sopenharmony_ci	{ 3510, 8, RX_ENC_HT, 0, RATE_INFO_BW_80},
2118c2ecf20Sopenharmony_ci	{ 3900, 9, RX_ENC_HT, 0, RATE_INFO_BW_80},
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	/* 11 ac reserved indices */
2148c2ecf20Sopenharmony_ci	{ 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 },
2158c2ecf20Sopenharmony_ci	{ 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 },
2168c2ecf20Sopenharmony_ci	{ 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 },
2178c2ecf20Sopenharmony_ci	{ 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 },
2188c2ecf20Sopenharmony_ci	{ 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 },
2198c2ecf20Sopenharmony_ci	{ 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 },
2208c2ecf20Sopenharmony_ci	{ 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 },
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	/* 11ac 80 MHz 400 ns SGI MCS 6-7 */
2238c2ecf20Sopenharmony_ci	{ 2925, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_80 },
2248c2ecf20Sopenharmony_ci	{ 3250, 7, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_80 },
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	/* 11ac reserved index */
2278c2ecf20Sopenharmony_ci	{ 1350, 6, RX_ENC_HT,  RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 },
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	/* 11ac 80 MHz 400ns SGI MCS 8-9 */
2308c2ecf20Sopenharmony_ci	{ 3900, 8, RX_ENC_VHT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_80 },
2318c2ecf20Sopenharmony_ci	{ 4333, 9, RX_ENC_VHT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_80 },
2328c2ecf20Sopenharmony_ci};
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ciint wcn36xx_rx_skb(struct wcn36xx *wcn, struct sk_buff *skb)
2358c2ecf20Sopenharmony_ci{
2368c2ecf20Sopenharmony_ci	struct ieee80211_rx_status status;
2378c2ecf20Sopenharmony_ci	const struct wcn36xx_rate *rate;
2388c2ecf20Sopenharmony_ci	struct ieee80211_hdr *hdr;
2398c2ecf20Sopenharmony_ci	struct wcn36xx_rx_bd *bd;
2408c2ecf20Sopenharmony_ci	u16 fc, sn;
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	/*
2438c2ecf20Sopenharmony_ci	 * All fields must be 0, otherwise it can lead to
2448c2ecf20Sopenharmony_ci	 * unexpected consequences.
2458c2ecf20Sopenharmony_ci	 */
2468c2ecf20Sopenharmony_ci	memset(&status, 0, sizeof(status));
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	bd = (struct wcn36xx_rx_bd *)skb->data;
2498c2ecf20Sopenharmony_ci	buff_to_be((u32 *)bd, sizeof(*bd)/sizeof(u32));
2508c2ecf20Sopenharmony_ci	wcn36xx_dbg_dump(WCN36XX_DBG_RX_DUMP,
2518c2ecf20Sopenharmony_ci			 "BD   <<< ", (char *)bd,
2528c2ecf20Sopenharmony_ci			 sizeof(struct wcn36xx_rx_bd));
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	skb_put(skb, bd->pdu.mpdu_header_off + bd->pdu.mpdu_len);
2558c2ecf20Sopenharmony_ci	skb_pull(skb, bd->pdu.mpdu_header_off);
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	hdr = (struct ieee80211_hdr *) skb->data;
2588c2ecf20Sopenharmony_ci	fc = __le16_to_cpu(hdr->frame_control);
2598c2ecf20Sopenharmony_ci	sn = IEEE80211_SEQ_TO_SN(__le16_to_cpu(hdr->seq_ctrl));
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	status.mactime = 10;
2628c2ecf20Sopenharmony_ci	status.signal = -get_rssi0(bd);
2638c2ecf20Sopenharmony_ci	status.antenna = 1;
2648c2ecf20Sopenharmony_ci	status.flag = 0;
2658c2ecf20Sopenharmony_ci	status.rx_flags = 0;
2668c2ecf20Sopenharmony_ci	status.flag |= RX_FLAG_IV_STRIPPED |
2678c2ecf20Sopenharmony_ci		       RX_FLAG_MMIC_STRIPPED |
2688c2ecf20Sopenharmony_ci		       RX_FLAG_DECRYPTED;
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	wcn36xx_dbg(WCN36XX_DBG_RX, "status.flags=%x\n", status.flag);
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	if (bd->scan_learn) {
2738c2ecf20Sopenharmony_ci		/* If packet originate from hardware scanning, extract the
2748c2ecf20Sopenharmony_ci		 * band/channel from bd descriptor.
2758c2ecf20Sopenharmony_ci		 */
2768c2ecf20Sopenharmony_ci		u8 hwch = (bd->reserved0 << 4) + bd->rx_ch;
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci		if (bd->rf_band != 1 && hwch <= sizeof(ab_rx_ch_map) && hwch >= 1) {
2798c2ecf20Sopenharmony_ci			status.band = NL80211_BAND_5GHZ;
2808c2ecf20Sopenharmony_ci			status.freq = ieee80211_channel_to_frequency(ab_rx_ch_map[hwch - 1],
2818c2ecf20Sopenharmony_ci								     status.band);
2828c2ecf20Sopenharmony_ci		} else {
2838c2ecf20Sopenharmony_ci			status.band = NL80211_BAND_2GHZ;
2848c2ecf20Sopenharmony_ci			status.freq = ieee80211_channel_to_frequency(hwch, status.band);
2858c2ecf20Sopenharmony_ci		}
2868c2ecf20Sopenharmony_ci	} else {
2878c2ecf20Sopenharmony_ci		status.band = WCN36XX_BAND(wcn);
2888c2ecf20Sopenharmony_ci		status.freq = WCN36XX_CENTER_FREQ(wcn);
2898c2ecf20Sopenharmony_ci	}
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	if (bd->rate_id < ARRAY_SIZE(wcn36xx_rate_table)) {
2928c2ecf20Sopenharmony_ci		rate = &wcn36xx_rate_table[bd->rate_id];
2938c2ecf20Sopenharmony_ci		status.encoding = rate->encoding;
2948c2ecf20Sopenharmony_ci		status.enc_flags = rate->encoding_flags;
2958c2ecf20Sopenharmony_ci		status.bw = rate->bw;
2968c2ecf20Sopenharmony_ci		status.rate_idx = rate->mcs_or_legacy_index;
2978c2ecf20Sopenharmony_ci		status.nss = 1;
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci		if (status.band == NL80211_BAND_5GHZ &&
3008c2ecf20Sopenharmony_ci		    status.encoding == RX_ENC_LEGACY &&
3018c2ecf20Sopenharmony_ci		    status.rate_idx >= 4) {
3028c2ecf20Sopenharmony_ci			/* no dsss rates in 5Ghz rates table */
3038c2ecf20Sopenharmony_ci			status.rate_idx -= 4;
3048c2ecf20Sopenharmony_ci		}
3058c2ecf20Sopenharmony_ci	} else {
3068c2ecf20Sopenharmony_ci		status.encoding = 0;
3078c2ecf20Sopenharmony_ci		status.bw = 0;
3088c2ecf20Sopenharmony_ci		status.enc_flags = 0;
3098c2ecf20Sopenharmony_ci		status.rate_idx = 0;
3108c2ecf20Sopenharmony_ci	}
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	if (ieee80211_is_beacon(hdr->frame_control) ||
3138c2ecf20Sopenharmony_ci	    ieee80211_is_probe_resp(hdr->frame_control))
3148c2ecf20Sopenharmony_ci		status.boottime_ns = ktime_get_boottime_ns();
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	if (ieee80211_is_beacon(hdr->frame_control)) {
3198c2ecf20Sopenharmony_ci		wcn36xx_dbg(WCN36XX_DBG_BEACON, "beacon skb %p len %d fc %04x sn %d\n",
3208c2ecf20Sopenharmony_ci			    skb, skb->len, fc, sn);
3218c2ecf20Sopenharmony_ci		wcn36xx_dbg_dump(WCN36XX_DBG_BEACON_DUMP, "SKB <<< ",
3228c2ecf20Sopenharmony_ci				 (char *)skb->data, skb->len);
3238c2ecf20Sopenharmony_ci	} else {
3248c2ecf20Sopenharmony_ci		wcn36xx_dbg(WCN36XX_DBG_RX, "rx skb %p len %d fc %04x sn %d\n",
3258c2ecf20Sopenharmony_ci			    skb, skb->len, fc, sn);
3268c2ecf20Sopenharmony_ci		wcn36xx_dbg_dump(WCN36XX_DBG_RX_DUMP, "SKB <<< ",
3278c2ecf20Sopenharmony_ci				 (char *)skb->data, skb->len);
3288c2ecf20Sopenharmony_ci	}
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	ieee80211_rx_irqsafe(wcn->hw, skb);
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	return 0;
3338c2ecf20Sopenharmony_ci}
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_cistatic void wcn36xx_set_tx_pdu(struct wcn36xx_tx_bd *bd,
3368c2ecf20Sopenharmony_ci			       u32 mpdu_header_len,
3378c2ecf20Sopenharmony_ci			       u32 len,
3388c2ecf20Sopenharmony_ci			       u16 tid)
3398c2ecf20Sopenharmony_ci{
3408c2ecf20Sopenharmony_ci	bd->pdu.mpdu_header_len = mpdu_header_len;
3418c2ecf20Sopenharmony_ci	bd->pdu.mpdu_header_off = sizeof(*bd);
3428c2ecf20Sopenharmony_ci	bd->pdu.mpdu_data_off = bd->pdu.mpdu_header_len +
3438c2ecf20Sopenharmony_ci		bd->pdu.mpdu_header_off;
3448c2ecf20Sopenharmony_ci	bd->pdu.mpdu_len = len;
3458c2ecf20Sopenharmony_ci	bd->pdu.tid = tid;
3468c2ecf20Sopenharmony_ci}
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_cistatic inline struct wcn36xx_vif *get_vif_by_addr(struct wcn36xx *wcn,
3498c2ecf20Sopenharmony_ci						  u8 *addr)
3508c2ecf20Sopenharmony_ci{
3518c2ecf20Sopenharmony_ci	struct wcn36xx_vif *vif_priv = NULL;
3528c2ecf20Sopenharmony_ci	struct ieee80211_vif *vif = NULL;
3538c2ecf20Sopenharmony_ci	list_for_each_entry(vif_priv, &wcn->vif_list, list) {
3548c2ecf20Sopenharmony_ci			vif = wcn36xx_priv_to_vif(vif_priv);
3558c2ecf20Sopenharmony_ci			if (memcmp(vif->addr, addr, ETH_ALEN) == 0)
3568c2ecf20Sopenharmony_ci				return vif_priv;
3578c2ecf20Sopenharmony_ci	}
3588c2ecf20Sopenharmony_ci	wcn36xx_warn("vif %pM not found\n", addr);
3598c2ecf20Sopenharmony_ci	return NULL;
3608c2ecf20Sopenharmony_ci}
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_cistatic void wcn36xx_tx_start_ampdu(struct wcn36xx *wcn,
3638c2ecf20Sopenharmony_ci				   struct wcn36xx_sta *sta_priv,
3648c2ecf20Sopenharmony_ci				   struct sk_buff *skb)
3658c2ecf20Sopenharmony_ci{
3668c2ecf20Sopenharmony_ci	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
3678c2ecf20Sopenharmony_ci	struct ieee80211_sta *sta;
3688c2ecf20Sopenharmony_ci	u8 *qc, tid;
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	if (!conf_is_ht(&wcn->hw->conf))
3718c2ecf20Sopenharmony_ci		return;
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	sta = wcn36xx_priv_to_sta(sta_priv);
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	if (WARN_ON(!ieee80211_is_data_qos(hdr->frame_control)))
3768c2ecf20Sopenharmony_ci		return;
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	if (skb_get_queue_mapping(skb) == IEEE80211_AC_VO)
3798c2ecf20Sopenharmony_ci		return;
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	qc = ieee80211_get_qos_ctl(hdr);
3828c2ecf20Sopenharmony_ci	tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	spin_lock(&sta_priv->ampdu_lock);
3858c2ecf20Sopenharmony_ci	if (sta_priv->ampdu_state[tid] != WCN36XX_AMPDU_NONE)
3868c2ecf20Sopenharmony_ci		goto out_unlock;
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	if (sta_priv->non_agg_frame_ct++ >= WCN36XX_AMPDU_START_THRESH) {
3898c2ecf20Sopenharmony_ci		sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_START;
3908c2ecf20Sopenharmony_ci		sta_priv->non_agg_frame_ct = 0;
3918c2ecf20Sopenharmony_ci		ieee80211_start_tx_ba_session(sta, tid, 0);
3928c2ecf20Sopenharmony_ci	}
3938c2ecf20Sopenharmony_ciout_unlock:
3948c2ecf20Sopenharmony_ci	spin_unlock(&sta_priv->ampdu_lock);
3958c2ecf20Sopenharmony_ci}
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_cistatic void wcn36xx_set_tx_data(struct wcn36xx_tx_bd *bd,
3988c2ecf20Sopenharmony_ci				struct wcn36xx *wcn,
3998c2ecf20Sopenharmony_ci				struct wcn36xx_vif **vif_priv,
4008c2ecf20Sopenharmony_ci				struct wcn36xx_sta *sta_priv,
4018c2ecf20Sopenharmony_ci				struct sk_buff *skb,
4028c2ecf20Sopenharmony_ci				bool bcast)
4038c2ecf20Sopenharmony_ci{
4048c2ecf20Sopenharmony_ci	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
4058c2ecf20Sopenharmony_ci	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
4068c2ecf20Sopenharmony_ci	struct ieee80211_vif *vif = NULL;
4078c2ecf20Sopenharmony_ci	struct wcn36xx_vif *__vif_priv = NULL;
4088c2ecf20Sopenharmony_ci	bool is_data_qos = ieee80211_is_data_qos(hdr->frame_control);
4098c2ecf20Sopenharmony_ci	u16 tid = 0;
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	bd->bd_rate = WCN36XX_BD_RATE_DATA;
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci	/*
4148c2ecf20Sopenharmony_ci	 * For not unicast frames mac80211 will not set sta pointer so use
4158c2ecf20Sopenharmony_ci	 * self_sta_index instead.
4168c2ecf20Sopenharmony_ci	 */
4178c2ecf20Sopenharmony_ci	if (sta_priv) {
4188c2ecf20Sopenharmony_ci		__vif_priv = sta_priv->vif;
4198c2ecf20Sopenharmony_ci		vif = wcn36xx_priv_to_vif(__vif_priv);
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci		bd->dpu_sign = sta_priv->ucast_dpu_sign;
4228c2ecf20Sopenharmony_ci		if (vif->type == NL80211_IFTYPE_STATION) {
4238c2ecf20Sopenharmony_ci			bd->sta_index = sta_priv->bss_sta_index;
4248c2ecf20Sopenharmony_ci			bd->dpu_desc_idx = sta_priv->bss_dpu_desc_index;
4258c2ecf20Sopenharmony_ci		} else if (vif->type == NL80211_IFTYPE_AP ||
4268c2ecf20Sopenharmony_ci			   vif->type == NL80211_IFTYPE_ADHOC ||
4278c2ecf20Sopenharmony_ci			   vif->type == NL80211_IFTYPE_MESH_POINT) {
4288c2ecf20Sopenharmony_ci			bd->sta_index = sta_priv->sta_index;
4298c2ecf20Sopenharmony_ci			bd->dpu_desc_idx = sta_priv->dpu_desc_index;
4308c2ecf20Sopenharmony_ci		}
4318c2ecf20Sopenharmony_ci	} else {
4328c2ecf20Sopenharmony_ci		__vif_priv = get_vif_by_addr(wcn, hdr->addr2);
4338c2ecf20Sopenharmony_ci		bd->sta_index = __vif_priv->self_sta_index;
4348c2ecf20Sopenharmony_ci		bd->dpu_desc_idx = __vif_priv->self_dpu_desc_index;
4358c2ecf20Sopenharmony_ci		bd->dpu_sign = __vif_priv->self_ucast_dpu_sign;
4368c2ecf20Sopenharmony_ci	}
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	if (is_data_qos) {
4398c2ecf20Sopenharmony_ci		tid = ieee80211_get_tid(hdr);
4408c2ecf20Sopenharmony_ci		/* TID->QID is one-to-one mapping */
4418c2ecf20Sopenharmony_ci		bd->queue_id = tid;
4428c2ecf20Sopenharmony_ci		bd->pdu.bd_ssn = WCN36XX_TXBD_SSN_FILL_DPU_QOS;
4438c2ecf20Sopenharmony_ci	} else {
4448c2ecf20Sopenharmony_ci		bd->pdu.bd_ssn = WCN36XX_TXBD_SSN_FILL_DPU_NON_QOS;
4458c2ecf20Sopenharmony_ci	}
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	if (info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT ||
4488c2ecf20Sopenharmony_ci	    (sta_priv && !sta_priv->is_data_encrypted)) {
4498c2ecf20Sopenharmony_ci		bd->dpu_ne = 1;
4508c2ecf20Sopenharmony_ci	}
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci	if (ieee80211_is_any_nullfunc(hdr->frame_control)) {
4538c2ecf20Sopenharmony_ci		/* Don't use a regular queue for null packet (no ampdu) */
4548c2ecf20Sopenharmony_ci		bd->queue_id = WCN36XX_TX_U_WQ_ID;
4558c2ecf20Sopenharmony_ci		bd->bd_rate = WCN36XX_BD_RATE_CTRL;
4568c2ecf20Sopenharmony_ci		if (ieee80211_is_qos_nullfunc(hdr->frame_control))
4578c2ecf20Sopenharmony_ci			bd->pdu.bd_ssn = WCN36XX_TXBD_SSN_FILL_HOST;
4588c2ecf20Sopenharmony_ci	}
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	if (bcast) {
4618c2ecf20Sopenharmony_ci		bd->ub = 1;
4628c2ecf20Sopenharmony_ci		bd->ack_policy = 1;
4638c2ecf20Sopenharmony_ci	}
4648c2ecf20Sopenharmony_ci	*vif_priv = __vif_priv;
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	wcn36xx_set_tx_pdu(bd,
4678c2ecf20Sopenharmony_ci			   is_data_qos ?
4688c2ecf20Sopenharmony_ci			   sizeof(struct ieee80211_qos_hdr) :
4698c2ecf20Sopenharmony_ci			   sizeof(struct ieee80211_hdr_3addr),
4708c2ecf20Sopenharmony_ci			   skb->len, tid);
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	if (sta_priv && is_data_qos)
4738c2ecf20Sopenharmony_ci		wcn36xx_tx_start_ampdu(wcn, sta_priv, skb);
4748c2ecf20Sopenharmony_ci}
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_cistatic void wcn36xx_set_tx_mgmt(struct wcn36xx_tx_bd *bd,
4778c2ecf20Sopenharmony_ci				struct wcn36xx *wcn,
4788c2ecf20Sopenharmony_ci				struct wcn36xx_vif **vif_priv,
4798c2ecf20Sopenharmony_ci				struct sk_buff *skb,
4808c2ecf20Sopenharmony_ci				bool bcast)
4818c2ecf20Sopenharmony_ci{
4828c2ecf20Sopenharmony_ci	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
4838c2ecf20Sopenharmony_ci	struct wcn36xx_vif *__vif_priv =
4848c2ecf20Sopenharmony_ci		get_vif_by_addr(wcn, hdr->addr2);
4858c2ecf20Sopenharmony_ci	bd->sta_index = __vif_priv->self_sta_index;
4868c2ecf20Sopenharmony_ci	bd->dpu_desc_idx = __vif_priv->self_dpu_desc_index;
4878c2ecf20Sopenharmony_ci	bd->dpu_ne = 1;
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	/* default rate for unicast */
4908c2ecf20Sopenharmony_ci	if (ieee80211_is_mgmt(hdr->frame_control))
4918c2ecf20Sopenharmony_ci		bd->bd_rate = (WCN36XX_BAND(wcn) == NL80211_BAND_5GHZ) ?
4928c2ecf20Sopenharmony_ci			WCN36XX_BD_RATE_CTRL :
4938c2ecf20Sopenharmony_ci			WCN36XX_BD_RATE_MGMT;
4948c2ecf20Sopenharmony_ci	else if (ieee80211_is_ctl(hdr->frame_control))
4958c2ecf20Sopenharmony_ci		bd->bd_rate = WCN36XX_BD_RATE_CTRL;
4968c2ecf20Sopenharmony_ci	else
4978c2ecf20Sopenharmony_ci		wcn36xx_warn("frame control type unknown\n");
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	/*
5008c2ecf20Sopenharmony_ci	 * In joining state trick hardware that probe is sent as
5018c2ecf20Sopenharmony_ci	 * unicast even if address is broadcast.
5028c2ecf20Sopenharmony_ci	 */
5038c2ecf20Sopenharmony_ci	if (__vif_priv->is_joining &&
5048c2ecf20Sopenharmony_ci	    ieee80211_is_probe_req(hdr->frame_control))
5058c2ecf20Sopenharmony_ci		bcast = false;
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci	if (bcast) {
5088c2ecf20Sopenharmony_ci		/* broadcast */
5098c2ecf20Sopenharmony_ci		bd->ub = 1;
5108c2ecf20Sopenharmony_ci		/* No ack needed not unicast */
5118c2ecf20Sopenharmony_ci		bd->ack_policy = 1;
5128c2ecf20Sopenharmony_ci		bd->queue_id = WCN36XX_TX_B_WQ_ID;
5138c2ecf20Sopenharmony_ci	} else
5148c2ecf20Sopenharmony_ci		bd->queue_id = WCN36XX_TX_U_WQ_ID;
5158c2ecf20Sopenharmony_ci	*vif_priv = __vif_priv;
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	bd->pdu.bd_ssn = WCN36XX_TXBD_SSN_FILL_DPU_NON_QOS;
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci	wcn36xx_set_tx_pdu(bd,
5208c2ecf20Sopenharmony_ci			   ieee80211_is_data_qos(hdr->frame_control) ?
5218c2ecf20Sopenharmony_ci			   sizeof(struct ieee80211_qos_hdr) :
5228c2ecf20Sopenharmony_ci			   sizeof(struct ieee80211_hdr_3addr),
5238c2ecf20Sopenharmony_ci			   skb->len, WCN36XX_TID);
5248c2ecf20Sopenharmony_ci}
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ciint wcn36xx_start_tx(struct wcn36xx *wcn,
5278c2ecf20Sopenharmony_ci		     struct wcn36xx_sta *sta_priv,
5288c2ecf20Sopenharmony_ci		     struct sk_buff *skb)
5298c2ecf20Sopenharmony_ci{
5308c2ecf20Sopenharmony_ci	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
5318c2ecf20Sopenharmony_ci	struct wcn36xx_vif *vif_priv = NULL;
5328c2ecf20Sopenharmony_ci	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
5338c2ecf20Sopenharmony_ci	bool is_low = ieee80211_is_data(hdr->frame_control);
5348c2ecf20Sopenharmony_ci	bool bcast = is_broadcast_ether_addr(hdr->addr1) ||
5358c2ecf20Sopenharmony_ci		is_multicast_ether_addr(hdr->addr1);
5368c2ecf20Sopenharmony_ci	bool ack_ind = (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) &&
5378c2ecf20Sopenharmony_ci					!(info->flags & IEEE80211_TX_CTL_NO_ACK);
5388c2ecf20Sopenharmony_ci	struct wcn36xx_tx_bd bd;
5398c2ecf20Sopenharmony_ci	int ret;
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci	memset(&bd, 0, sizeof(bd));
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	wcn36xx_dbg(WCN36XX_DBG_TX,
5448c2ecf20Sopenharmony_ci		    "tx skb %p len %d fc %04x sn %d %s %s\n",
5458c2ecf20Sopenharmony_ci		    skb, skb->len, __le16_to_cpu(hdr->frame_control),
5468c2ecf20Sopenharmony_ci		    IEEE80211_SEQ_TO_SN(__le16_to_cpu(hdr->seq_ctrl)),
5478c2ecf20Sopenharmony_ci		    is_low ? "low" : "high", bcast ? "bcast" : "ucast");
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci	wcn36xx_dbg_dump(WCN36XX_DBG_TX_DUMP, "", skb->data, skb->len);
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci	bd.dpu_rf = WCN36XX_BMU_WQ_TX;
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci	if (unlikely(ack_ind)) {
5548c2ecf20Sopenharmony_ci		wcn36xx_dbg(WCN36XX_DBG_DXE, "TX_ACK status requested\n");
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci		/* Only one at a time is supported by fw. Stop the TX queues
5578c2ecf20Sopenharmony_ci		 * until the ack status gets back.
5588c2ecf20Sopenharmony_ci		 */
5598c2ecf20Sopenharmony_ci		ieee80211_stop_queues(wcn->hw);
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci		/* Request ack indication from the firmware */
5628c2ecf20Sopenharmony_ci		bd.tx_comp = 1;
5638c2ecf20Sopenharmony_ci	}
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	/* Data frames served first*/
5668c2ecf20Sopenharmony_ci	if (is_low)
5678c2ecf20Sopenharmony_ci		wcn36xx_set_tx_data(&bd, wcn, &vif_priv, sta_priv, skb, bcast);
5688c2ecf20Sopenharmony_ci	else
5698c2ecf20Sopenharmony_ci		/* MGMT and CTRL frames are handeld here*/
5708c2ecf20Sopenharmony_ci		wcn36xx_set_tx_mgmt(&bd, wcn, &vif_priv, skb, bcast);
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci	buff_to_be((u32 *)&bd, sizeof(bd)/sizeof(u32));
5738c2ecf20Sopenharmony_ci	bd.tx_bd_sign = 0xbdbdbdbd;
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci	ret = wcn36xx_dxe_tx_frame(wcn, vif_priv, &bd, skb, is_low);
5768c2ecf20Sopenharmony_ci	if (unlikely(ret && ack_ind)) {
5778c2ecf20Sopenharmony_ci		/* If the skb has not been transmitted, resume TX queue */
5788c2ecf20Sopenharmony_ci		ieee80211_wake_queues(wcn->hw);
5798c2ecf20Sopenharmony_ci	}
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci	return ret;
5828c2ecf20Sopenharmony_ci}
583