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