This driver named rtw89, which is the next generation of rtw88, supports
Realtek 8852AE 802.11ax 2x2 chip whose new features are OFDMA, DBCC,
Spatial reuse, TWT and BSS coloring; now some of them aren't implemented
though.
The chip architecture is entirely different from the chips supported by
rtw88 like RTL8822CE 802.11ac chip. First of all, register address ranges
are totally redefined, so it's impossible to reuse register definition. To
communicate with firmware, new H2C/C2H format is proposed. In order to have
better utilization, TX DMA flow is changed to two stages DMA. To provide
rich RX status information, additional RX PPDU packets are added.
Since there are so many differences mentioned above, we decide to propose
a new driver. It has many authors, they are listed in alphabetic order:
Chin-Yen Lee <[email protected]>
Ping-Ke Shih <[email protected]>
Po Hao Huang <[email protected]>
Tzu-En Huang <[email protected]>
Vincent Fann <[email protected]>
Yan-Hsuan Chuang <[email protected]>
Zong-Zhe Yang <[email protected]>
v2:
- fix compiler warnings made by W=1
Reported-by: kernel test robot <[email protected]>
- sort header file alphabetically
- fix "networking block comments" reported by checkpatch
Ping-Ke Shih (18):
rtw89: add CAM files
rtw89: add BT coexistence files
rtw89: add core and trx files
rtw89: add debug files
rtw89: add efuse files
rtw89: add files to download and communicate with firmware
rtw89: add MAC files
rtw89: implement mac80211 ops
rtw89: add pci files
rtw89: add phy files
rtw89: define register names
rtw89: add regulatory support
rtw89: 8852a: add 8852a specific files
rtw89: 8852a: add 8852a RFK files
rtw89: 8852a: add 8852a RFK tables
rtw89: 8852a: add 8852a tables
rtw89: add ser to recover error reported by firmware
rtw89: add Kconfig and Makefile
drivers/net/wireless/realtek/Kconfig | 1 +
drivers/net/wireless/realtek/Makefile | 1 +
drivers/net/wireless/realtek/rtw89/Kconfig | 50 +
drivers/net/wireless/realtek/rtw89/Makefile | 23 +
drivers/net/wireless/realtek/rtw89/cam.c | 669 +
drivers/net/wireless/realtek/rtw89/cam.h | 164 +
drivers/net/wireless/realtek/rtw89/coex.c | 385 +
drivers/net/wireless/realtek/rtw89/coex.h | 102 +
drivers/net/wireless/realtek/rtw89/core.c | 1733 ++
drivers/net/wireless/realtek/rtw89/core.h | 1909 ++
drivers/net/wireless/realtek/rtw89/debug.c | 1927 ++
drivers/net/wireless/realtek/rtw89/debug.h | 75 +
drivers/net/wireless/realtek/rtw89/efuse.c | 188 +
drivers/net/wireless/realtek/rtw89/efuse.h | 13 +
drivers/net/wireless/realtek/rtw89/fw.c | 990 +
drivers/net/wireless/realtek/rtw89/fw.h | 1056 +
drivers/net/wireless/realtek/rtw89/mac.c | 3257 ++
drivers/net/wireless/realtek/rtw89/mac.h | 763 +
drivers/net/wireless/realtek/rtw89/mac80211.c | 521 +
drivers/net/wireless/realtek/rtw89/pci.c | 2567 ++
drivers/net/wireless/realtek/rtw89/pci.h | 560 +
drivers/net/wireless/realtek/rtw89/phy.c | 2473 ++
drivers/net/wireless/realtek/rtw89/phy.h | 278 +
drivers/net/wireless/realtek/rtw89/reg.h | 1843 ++
drivers/net/wireless/realtek/rtw89/regd.c | 351 +
drivers/net/wireless/realtek/rtw89/rtw8852a.c | 1340 +
drivers/net/wireless/realtek/rtw89/rtw8852a.h | 78 +
.../net/wireless/realtek/rtw89/rtw8852a_rfk.c | 3558 +++
.../net/wireless/realtek/rtw89/rtw8852a_rfk.h | 20 +
.../realtek/rtw89/rtw8852a_rfk_table.c | 1561 +
.../realtek/rtw89/rtw8852a_rfk_table.h | 129 +
.../wireless/realtek/rtw89/rtw8852a_table.c | 24997 ++++++++++++++++
.../wireless/realtek/rtw89/rtw8852a_table.h | 28 +
drivers/net/wireless/realtek/rtw89/ser.c | 427 +
drivers/net/wireless/realtek/rtw89/ser.h | 14 +
drivers/net/wireless/realtek/rtw89/txrx.h | 385 +
36 files changed, 54436 insertions(+)
create mode 100644 drivers/net/wireless/realtek/rtw89/Kconfig
create mode 100644 drivers/net/wireless/realtek/rtw89/Makefile
create mode 100644 drivers/net/wireless/realtek/rtw89/cam.c
create mode 100644 drivers/net/wireless/realtek/rtw89/cam.h
create mode 100644 drivers/net/wireless/realtek/rtw89/coex.c
create mode 100644 drivers/net/wireless/realtek/rtw89/coex.h
create mode 100644 drivers/net/wireless/realtek/rtw89/core.c
create mode 100644 drivers/net/wireless/realtek/rtw89/core.h
create mode 100644 drivers/net/wireless/realtek/rtw89/debug.c
create mode 100644 drivers/net/wireless/realtek/rtw89/debug.h
create mode 100644 drivers/net/wireless/realtek/rtw89/efuse.c
create mode 100644 drivers/net/wireless/realtek/rtw89/efuse.h
create mode 100644 drivers/net/wireless/realtek/rtw89/fw.c
create mode 100644 drivers/net/wireless/realtek/rtw89/fw.h
create mode 100644 drivers/net/wireless/realtek/rtw89/mac.c
create mode 100644 drivers/net/wireless/realtek/rtw89/mac.h
create mode 100644 drivers/net/wireless/realtek/rtw89/mac80211.c
create mode 100644 drivers/net/wireless/realtek/rtw89/pci.c
create mode 100644 drivers/net/wireless/realtek/rtw89/pci.h
create mode 100644 drivers/net/wireless/realtek/rtw89/phy.c
create mode 100644 drivers/net/wireless/realtek/rtw89/phy.h
create mode 100644 drivers/net/wireless/realtek/rtw89/reg.h
create mode 100644 drivers/net/wireless/realtek/rtw89/regd.c
create mode 100644 drivers/net/wireless/realtek/rtw89/rtw8852a.c
create mode 100644 drivers/net/wireless/realtek/rtw89/rtw8852a.h
create mode 100644 drivers/net/wireless/realtek/rtw89/rtw8852a_rfk.c
create mode 100644 drivers/net/wireless/realtek/rtw89/rtw8852a_rfk.h
create mode 100644 drivers/net/wireless/realtek/rtw89/rtw8852a_rfk_table.c
create mode 100644 drivers/net/wireless/realtek/rtw89/rtw8852a_rfk_table.h
create mode 100644 drivers/net/wireless/realtek/rtw89/rtw8852a_table.c
create mode 100644 drivers/net/wireless/realtek/rtw89/rtw8852a_table.h
create mode 100644 drivers/net/wireless/realtek/rtw89/ser.c
create mode 100644 drivers/net/wireless/realtek/rtw89/ser.h
create mode 100644 drivers/net/wireless/realtek/rtw89/txrx.h
--
2.21.0
BT coexistence uses TDMA-based mechanism to coordinate with WiFi and BT.
Currently, it only set antenna statically for WiFi-only case, and full
version will be updated later.
Signed-off-by: Ping-Ke Shih <[email protected]>
---
drivers/net/wireless/realtek/rtw89/coex.c | 385 ++++++++++++++++++++++
drivers/net/wireless/realtek/rtw89/coex.h | 102 ++++++
2 files changed, 487 insertions(+)
create mode 100644 drivers/net/wireless/realtek/rtw89/coex.c
create mode 100644 drivers/net/wireless/realtek/rtw89/coex.h
diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c
new file mode 100644
index 000000000000..cf402bc76b6f
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw89/coex.c
@@ -0,0 +1,385 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/* Copyright(c) 2019-2020 Realtek Corporation
+ */
+
+#include "coex.h"
+#include "debug.h"
+#include "mac.h"
+
+enum btc_phymap {
+ BTC_PHY_0 = BIT(0),
+ BTC_PHY_1 = BIT(1),
+ BTC_PHY_ALL = BIT(0) | BIT(1),
+};
+
+enum btc_cx_state_map {
+ BTC_WIDLE = 0,
+ BTC_WBUSY_BNOSCAN,
+ BTC_WBUSY_BSCAN,
+ BTC_WSCAN_BNOSCAN,
+ BTC_WSCAN_BSCAN,
+ BTC_WLINKING
+};
+
+enum btc_ant_phase {
+ BTC_ANT_WPOWERON = 0,
+ BTC_ANT_WINIT,
+ BTC_ANT_WONLY,
+ BTC_ANT_WOFF,
+ BTC_ANT_W2G,
+ BTC_ANT_W5G,
+ BTC_ANT_W25G,
+ BTC_ANT_FREERUN,
+ BTC_ANT_WRFK,
+ BTC_ANT_BRFK,
+ BTC_ANT_MAX
+};
+
+enum btc_plt {
+ BTC_PLT_NONE = 0,
+ BTC_PLT_LTE_RX = BIT(0),
+ BTC_PLT_GNT_BT_TX = BIT(1),
+ BTC_PLT_GNT_BT_RX = BIT(2),
+ BTC_PLT_GNT_WL = BIT(3),
+ BTC_PLT_BT = BIT(1) | BIT(2),
+ BTC_PLT_ALL = 0xf
+};
+
+enum btc_cx_poicy_main_type {
+ BTC_CXP_OFF = 0,
+ BTC_CXP_OFFB,
+ BTC_CXP_OFFE,
+ BTC_CXP_FIX,
+ BTC_CXP_PFIX,
+ BTC_CXP_AUTO,
+ BTC_CXP_PAUTO,
+ BTC_CXP_AUTO2,
+ BTC_CXP_PAUTO2,
+ BTC_CXP_MANUAL,
+ BTC_CXP_USERDEF0,
+ BTC_CXP_MAIN_MAX
+};
+
+enum btc_cx_poicy_type {
+ /* TDMA off + pri: BT > WL */
+ BTC_CXP_OFF_BT = (BTC_CXP_OFF << 8) | 0,
+
+ /* TDMA off + pri: WL > BT */
+ BTC_CXP_OFF_WL = (BTC_CXP_OFF << 8) | 1,
+
+ /* TDMA off + pri: BT = WL */
+ BTC_CXP_OFF_EQ0 = (BTC_CXP_OFF << 8) | 2,
+
+ /* TDMA off + pri: BT = WL > BT_Lo */
+ BTC_CXP_OFF_EQ1 = (BTC_CXP_OFF << 8) | 3,
+
+ /* TDMA off + pri: WL = BT, BT_Rx > WL_Lo_Tx */
+ BTC_CXP_OFF_EQ2 = (BTC_CXP_OFF << 8) | 4,
+
+ /* TDMA off + pri: WL_Rx = BT, BT_HI > WL_Tx > BT_Lo */
+ BTC_CXP_OFF_EQ3 = (BTC_CXP_OFF << 8) | 5,
+
+ /* TDMA off + pri: BT_Hi > WL > BT_Lo */
+ BTC_CXP_OFF_BWB0 = (BTC_CXP_OFF << 8) | 6,
+
+ /* TDMA off + pri: WL_Hi-Tx > BT_Hi_Rx, BT_Hi > WL > BT_Lo */
+ BTC_CXP_OFF_BWB1 = (BTC_CXP_OFF << 8) | 7,
+
+ /* TDMA off+Bcn-Protect + pri: WL_Hi-Tx > BT_Hi_Rx, BT_Hi > WL > BT_Lo*/
+ BTC_CXP_OFFB_BWB0 = (BTC_CXP_OFFB << 8) | 0,
+
+ /* TDMA off + Ext-Ctrl + pri: default */
+ BTC_CXP_OFFE_DEF = (BTC_CXP_OFFE << 8) | 0,
+
+ /* TDMA Fix slot-0: W1:B1 = 30:30 */
+ BTC_CXP_FIX_TD3030 = (BTC_CXP_FIX << 8) | 0,
+
+ /* TDMA Fix slot-1: W1:B1 = 50:50 */
+ BTC_CXP_FIX_TD5050 = (BTC_CXP_FIX << 8) | 1,
+
+ /* TDMA Fix slot-2: W1:B1 = 20:30 */
+ BTC_CXP_FIX_TD2030 = (BTC_CXP_FIX << 8) | 2,
+
+ /* TDMA Fix slot-3: W1:B1 = 40:10 */
+ BTC_CXP_FIX_TD4010 = (BTC_CXP_FIX << 8) | 3,
+
+ /* TDMA Fix slot-4: W1:B1 = 70:10 */
+ BTC_CXP_FIX_TD7010 = (BTC_CXP_FIX << 8) | 4,
+
+ /* TDMA Fix slot-5: W1:B1 = 20:60 */
+ BTC_CXP_FIX_TD2060 = (BTC_CXP_FIX << 8) | 5,
+
+ /* TDMA Fix slot-6: W1:B1 = 30:60 */
+ BTC_CXP_FIX_TD3060 = (BTC_CXP_FIX << 8) | 6,
+
+ /* TDMA Fix slot-6: W1:B1 = 20:80 */
+ BTC_CXP_FIX_TD2080 = (BTC_CXP_FIX << 8) | 7,
+
+ /* PS-TDMA Fix slot-0: W1:B1 = 30:30 */
+ BTC_CXP_PFIX_TD3030 = (BTC_CXP_PFIX << 8) | 0,
+
+ /* PS-TDMA Fix slot-1: W1:B1 = 50:50 */
+ BTC_CXP_PFIX_TD5050 = (BTC_CXP_PFIX << 8) | 1,
+
+ /* PS-TDMA Fix slot-2: W1:B1 = 20:30 */
+ BTC_CXP_PFIX_TD2030 = (BTC_CXP_PFIX << 8) | 2,
+
+ /* PS-TDMA Fix slot-3: W1:B1 = 20:60 */
+ BTC_CXP_PFIX_TD2060 = (BTC_CXP_PFIX << 8) | 3,
+
+ /* PS-TDMA Fix slot-4: W1:B1 = 30:70 */
+ BTC_CXP_PFIX_TD3070 = (BTC_CXP_PFIX << 8) | 4,
+
+ /* PS-TDMA Fix slot-5: W1:B1 = 20:80 */
+ BTC_CXP_PFIX_TD2080 = (BTC_CXP_PFIX << 8) | 5,
+
+ /* TDMA Auto slot-0: W1:B1 = 50:100 */
+ BTC_CXP_AUTO_TD50100 = (BTC_CXP_AUTO << 8) | 0,
+
+ /* TDMA Auto slot-1: W1:B1 = 60:150 */
+ BTC_CXP_AUTO_TD60150 = (BTC_CXP_AUTO << 8) | 1,
+
+ /* TDMA Auto slot-2: W1:B1 = 20:150 */
+ BTC_CXP_AUTO_TD20150 = (BTC_CXP_AUTO << 8) | 2,
+
+ /* PS-TDMA Auto slot-0: W1:B1 = 50:100 */
+ BTC_CXP_PAUTO_TD50100 = (BTC_CXP_PAUTO << 8) | 0,
+
+ /* PS-TDMA Auto slot-1: W1:B1 = 60:150 */
+ BTC_CXP_PAUTO_TD60150 = (BTC_CXP_PAUTO << 8) | 1,
+
+ /* PS-TDMA Auto slot-2: W1:B1 = 20:150 */
+ BTC_CXP_PAUTO_TD20150 = (BTC_CXP_PAUTO << 8) | 2,
+
+ /* TDMA Auto slot2-0: W1:B4 = 30:50 */
+ BTC_CXP_AUTO2_TD3050 = (BTC_CXP_AUTO2 << 8) | 0,
+
+ /* TDMA Auto slot2-1: W1:B4 = 30:70 */
+ BTC_CXP_AUTO2_TD3070 = (BTC_CXP_AUTO2 << 8) | 1,
+
+ /* TDMA Auto slot2-2: W1:B4 = 50:50 */
+ BTC_CXP_AUTO2_TD5050 = (BTC_CXP_AUTO2 << 8) | 2,
+
+ /* TDMA Auto slot2-3: W1:B4 = 60:60 */
+ BTC_CXP_AUTO2_TD6060 = (BTC_CXP_AUTO2 << 8) | 3,
+
+ /* TDMA Auto slot2-4: W1:B4 = 20:80 */
+ BTC_CXP_AUTO2_TD2080 = (BTC_CXP_AUTO2 << 8) | 4,
+
+ /* PS-TDMA Auto slot2-0: W1:B4 = 30:50 */
+ BTC_CXP_PAUTO2_TD3050 = (BTC_CXP_PAUTO2 << 8) | 0,
+
+ /* PS-TDMA Auto slot2-1: W1:B4 = 30:70 */
+ BTC_CXP_PAUTO2_TD3070 = (BTC_CXP_PAUTO2 << 8) | 1,
+
+ /* PS-TDMA Auto slot2-2: W1:B4 = 50:50 */
+ BTC_CXP_PAUTO2_TD5050 = (BTC_CXP_PAUTO2 << 8) | 2,
+
+ /* PS-TDMA Auto slot2-3: W1:B4 = 60:60 */
+ BTC_CXP_PAUTO2_TD6060 = (BTC_CXP_PAUTO2 << 8) | 3,
+
+ /* PS-TDMA Auto slot2-4: W1:B4 = 20:80 */
+ BTC_CXP_PAUTO2_TD2080 = (BTC_CXP_PAUTO2 << 8) | 4,
+
+ BTC_CXP_MAX = 0xffff
+};
+
+#define BTC_PHY_MAX 2
+#define BTC_CXP_MASK GENMASK(15, 8)
+
+enum btc_gnt_state {
+ BTC_GNT_HW = 0,
+ BTC_GNT_SW_LO,
+ BTC_GNT_SW_HI,
+ BTC_GNT_MAX
+};
+
+enum btc_reason {
+ BTC_RSN_NTFY_INIT,
+ BTC_RSN_NTFY_SWBAND,
+ BTC_RSN_NUM,
+};
+
+enum btc_action {
+ BTC_ACT_WL_ONLY,
+ BTC_ACT_NUM,
+};
+
+static void _set_policy(struct rtw89_dev *rtwdev, u16 policy_type,
+ enum btc_action action)
+{
+}
+
+static void _set_gnt_wl(struct rtw89_dev *rtwdev, u8 phy_map, u8 state)
+{
+ struct rtw89_btc *btc = &rtwdev->btc;
+ struct rtw89_btc_dm *dm = &btc->dm;
+ struct rtw89_mac_ax_gnt *g = dm->gnt.band;
+ u8 i;
+
+ if (phy_map > BTC_PHY_ALL)
+ return;
+
+ for (i = 0; i < BTC_PHY_MAX; i++) {
+ if (!(phy_map & BIT(i)))
+ continue;
+
+ switch (state) {
+ case BTC_GNT_HW:
+ g[i].gnt_wl_sw_en = 0;
+ g[i].gnt_wl = 0;
+ break;
+ case BTC_GNT_SW_LO:
+ g[i].gnt_wl_sw_en = 1;
+ g[i].gnt_wl = 0;
+ break;
+ case BTC_GNT_SW_HI:
+ g[i].gnt_wl_sw_en = 1;
+ g[i].gnt_wl = 1;
+ break;
+ }
+ }
+
+ rtw89_mac_cfg_gnt(rtwdev, &dm->gnt);
+}
+
+static void _set_gnt_bt(struct rtw89_dev *rtwdev, u8 phy_map, u8 state)
+{
+ struct rtw89_btc *btc = &rtwdev->btc;
+ struct rtw89_btc_dm *dm = &btc->dm;
+ struct rtw89_mac_ax_gnt *g = dm->gnt.band;
+ u8 i;
+
+ if (phy_map > BTC_PHY_ALL)
+ return;
+
+ for (i = 0; i < BTC_PHY_MAX; i++) {
+ if (!(phy_map & BIT(i)))
+ continue;
+
+ switch (state) {
+ case BTC_GNT_HW:
+ g[i].gnt_bt_sw_en = 0;
+ g[i].gnt_bt = 0;
+ break;
+ case BTC_GNT_SW_LO:
+ g[i].gnt_bt_sw_en = 1;
+ g[i].gnt_bt = 0;
+ break;
+ case BTC_GNT_SW_HI:
+ g[i].gnt_bt_sw_en = 1;
+ g[i].gnt_bt = 1;
+ break;
+ }
+ }
+
+ rtw89_mac_cfg_gnt(rtwdev, &dm->gnt);
+}
+
+static void _set_bt_plut(struct rtw89_dev *rtwdev, u8 phy_map, u8 tx_val, u8 rx_val)
+{
+ struct rtw89_mac_ax_plt plt;
+
+ plt.band = RTW89_MAC_0;
+ plt.tx = tx_val;
+ plt.rx = rx_val;
+
+ if (phy_map & BTC_PHY_0)
+ rtw89_mac_cfg_plt(rtwdev, &plt);
+
+ if (!rtwdev->dbcc_en)
+ return;
+
+ plt.band = RTW89_MAC_1;
+ if (phy_map & BTC_PHY_1)
+ rtw89_mac_cfg_plt(rtwdev, &plt);
+}
+
+static void _set_ant(struct rtw89_dev *rtwdev, bool force_exec, u8 phy_map, u8 type)
+{
+ switch (type) {
+ case BTC_ANT_WONLY:
+ _set_gnt_wl(rtwdev, phy_map, BTC_GNT_SW_HI);
+ _set_gnt_bt(rtwdev, phy_map, BTC_GNT_SW_LO);
+ rtw89_mac_cfg_ctrl_path(rtwdev, true);
+ _set_bt_plut(rtwdev, BTC_PHY_ALL, BTC_PLT_NONE, BTC_PLT_NONE);
+ break;
+ default:
+ break;
+ }
+}
+
+static void _action_wl_only(struct rtw89_dev *rtwdev)
+{
+ _set_ant(rtwdev, FC_EXEC, BTC_PHY_ALL, BTC_ANT_WONLY);
+ _set_policy(rtwdev, BTC_CXP_OFF_BT, BTC_ACT_WL_ONLY);
+}
+
+static void _run_coex(struct rtw89_dev *rtwdev, enum btc_reason reason)
+{
+ struct rtw89_btc_dm *dm = &rtwdev->btc.dm;
+
+ lockdep_assert_held(&rtwdev->mutex);
+
+ if (dm->wl_only)
+ _action_wl_only(rtwdev);
+}
+
+void rtw89_btc_ntfy_init(struct rtw89_dev *rtwdev, u8 mode)
+{
+ struct rtw89_btc_dm *dm = &rtwdev->btc.dm;
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+
+ dm->wl_only = mode == BTC_MODE_WL ? 1 : 0;
+
+ chip->ops->btc_set_rfe(rtwdev);
+
+ chip->ops->btc_init_cfg(rtwdev);
+
+ _run_coex(rtwdev, BTC_RSN_NTFY_INIT);
+
+ rtw89_ctrl_btg(rtwdev, true);
+}
+
+void rtw89_btc_ntfy_scan_start(struct rtw89_dev *rtwdev, u8 phy_idx, u8 band)
+{
+}
+
+void rtw89_btc_ntfy_scan_finish(struct rtw89_dev *rtwdev, u8 phy_idx)
+{
+}
+
+void rtw89_btc_ntfy_switch_band(struct rtw89_dev *rtwdev, u8 phy_idx, u8 band)
+{
+ _run_coex(rtwdev, BTC_RSN_NTFY_SWBAND);
+}
+
+static bool _ntfy_wl_rfk(struct rtw89_dev *rtwdev, u8 phy_path,
+ enum btc_wl_rfk_type type,
+ enum btc_wl_rfk_state state)
+{
+ return true;
+}
+
+void rtw89_btc_ntfy_wl_rfk(struct rtw89_dev *rtwdev, u8 phy_map,
+ enum btc_wl_rfk_type type,
+ enum btc_wl_rfk_state state)
+{
+ u8 band;
+
+ band = FIELD_GET(BTC_RFK_BAND_MAP, phy_map);
+
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[RFK] RFK notify (%s / PHY%u / K_type = %u / path_idx = %lu / process = %s)\n",
+ band == RTW89_BAND_2G ? "2G" :
+ band == RTW89_BAND_5G ? "5G" : "6G",
+ !!(FIELD_GET(BTC_RFK_PHY_MAP, phy_map) & BIT(RTW89_PHY_1)),
+ type,
+ FIELD_GET(BTC_RFK_PATH_MAP, phy_map),
+ state == BTC_WRFK_STOP ? "RFK_STOP" :
+ state == BTC_WRFK_START ? "RFK_START" :
+ state == BTC_WRFK_ONESHOT_START ? "ONE-SHOT_START" :
+ "ONE-SHOT_STOP");
+
+ _ntfy_wl_rfk(rtwdev, phy_map, type, state);
+}
diff --git a/drivers/net/wireless/realtek/rtw89/coex.h b/drivers/net/wireless/realtek/rtw89/coex.h
new file mode 100644
index 000000000000..02302de37388
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw89/coex.h
@@ -0,0 +1,102 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
+/* Copyright(c) 2019-2020 Realtek Corporation
+ */
+
+#ifndef __RTW89_COEX_H__
+#define __RTW89_COEX_H__
+
+#include "core.h"
+
+enum btc_mode {
+ BTC_MODE_NORMAL,
+ BTC_MODE_WL,
+ BTC_MODE_BT,
+ BTC_MODE_WLOFF,
+ BTC_MODE_MAX
+};
+
+enum btc_wl_rfk_type {
+ BTC_WRFKT_IQK = 0,
+ BTC_WRFKT_LCK = 1,
+ BTC_WRFKT_DPK = 2,
+ BTC_WRFKT_TXGAPK = 3,
+ BTC_WRFKT_DACK = 4,
+ BTC_WRFKT_RXDCK = 5,
+ BTC_WRFKT_TSSI = 6,
+};
+
+#define NM_EXEC false
+#define FC_EXEC true
+
+#define BTC_RFK_PATH_MAP GENMASK(3, 0)
+#define BTC_RFK_PHY_MAP GENMASK(5, 4)
+#define BTC_RFK_BAND_MAP GENMASK(7, 6)
+
+enum btc_wl_rfk_state {
+ BTC_WRFK_STOP = 0,
+ BTC_WRFK_START = 1,
+ BTC_WRFK_ONESHOT_START = 2,
+ BTC_WRFK_ONESHOT_STOP = 3,
+};
+
+enum btc_pri {
+ BTC_PRI_MASK_RX_RESP = 0,
+ BTC_PRI_MASK_TX_RESP,
+ BTC_PRI_MASK_BEACON,
+ BTC_PRI_MASK_RX_CCK,
+ BTC_PRI_MASK_MAX
+};
+
+enum btc_wtrs {
+ BTC_WTRX_SS_GROUP = 0x0,
+ BTC_WTRX_TX_GROUP = 0x2,
+ BTC_WTRX_RX_GROUP = 0x3,
+ BTC_WTRX_MAX,
+};
+
+enum btc_ant {
+ BTC_ANT_SHARED = 0,
+ BTC_ANT_DEDICATED,
+ BTC_ANTTYPE_MAX
+};
+
+enum btc_bt_btg {
+ BTC_BT_ALONE = 0,
+ BTC_BT_BTG
+};
+
+enum btc_switch {
+ BTC_SWITCH_INTERNAL = 0,
+ BTC_SWITCH_EXTERNAL
+};
+
+void rtw89_btc_ntfy_init(struct rtw89_dev *rtwdev, u8 mode);
+void rtw89_btc_ntfy_scan_start(struct rtw89_dev *rtwdev, u8 phy_idx, u8 band);
+void rtw89_btc_ntfy_scan_finish(struct rtw89_dev *rtwdev, u8 phy_idx);
+void rtw89_btc_ntfy_switch_band(struct rtw89_dev *rtwdev, u8 phy_idx, u8 band);
+void rtw89_btc_ntfy_wl_rfk(struct rtw89_dev *rtwdev, u8 phy_map,
+ enum btc_wl_rfk_type type,
+ enum btc_wl_rfk_state state);
+
+static inline u8 rtw89_btc_phymap(struct rtw89_dev *rtwdev,
+ enum rtw89_phy_idx phy_idx,
+ enum rtw89_rf_path_bit paths)
+{
+ struct rtw89_hal *hal = &rtwdev->hal;
+ u8 phy_map;
+
+ phy_map = FIELD_PREP(BTC_RFK_PATH_MAP, paths) |
+ FIELD_PREP(BTC_RFK_PHY_MAP, BIT(phy_idx)) |
+ FIELD_PREP(BTC_RFK_BAND_MAP, hal->current_band_type);
+
+ return phy_map;
+}
+
+static inline u8 rtw89_btc_path_phymap(struct rtw89_dev *rtwdev,
+ enum rtw89_phy_idx phy_idx,
+ enum rtw89_rf_path path)
+{
+ return rtw89_btc_phymap(rtwdev, phy_idx, BIT(path));
+}
+
+#endif
--
2.21.0
Three kinds of CAM, security, address and bssid, are implemented in the
chip, and then we control them via H2C commands.
Every vif contains one address and one bssid CAM entries, and both are
allocated while vif is adding. Once any state is changed, driver notices
firmware. For example, add/remove vif, sta assoc/disassoc, and changed
security key.
When connecting to an AP with security, a security CAM entry is allocated
from security CAM pool and filled key values, and then attached to the
address CAM that contains seven keys entries for unicast, group and BIP
keys. Since the functions of these seven keys are predefined by firmware,
we should attach key to proper position depends on security entry mode and
key type.
Signed-off-by: Ping-Ke Shih <[email protected]>
---
drivers/net/wireless/realtek/rtw89/cam.c | 669 +++++++++++++++++++++++
drivers/net/wireless/realtek/rtw89/cam.h | 164 ++++++
2 files changed, 833 insertions(+)
create mode 100644 drivers/net/wireless/realtek/rtw89/cam.c
create mode 100644 drivers/net/wireless/realtek/rtw89/cam.h
diff --git a/drivers/net/wireless/realtek/rtw89/cam.c b/drivers/net/wireless/realtek/rtw89/cam.c
new file mode 100644
index 000000000000..6b00a29b1e9c
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw89/cam.c
@@ -0,0 +1,669 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/* Copyright(c) 2019-2020 Realtek Corporation
+ */
+
+#include "cam.h"
+#include "debug.h"
+#include "fw.h"
+#include "mac.h"
+
+static struct sk_buff *
+rtw89_cam_get_sec_key_cmd(struct rtw89_dev *rtwdev,
+ struct rtw89_sec_cam_entry *sec_cam,
+ bool ext_key)
+{
+ struct sk_buff *skb;
+ u32 cmd_len = H2C_SEC_CAM_LEN;
+ u32 key32[4];
+ u8 *cmd;
+ int i, j;
+
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(cmd_len);
+ if (!skb)
+ return NULL;
+
+ skb_put_zero(skb, cmd_len);
+
+ for (i = 0; i < 4; i++) {
+ j = i * 4;
+ j += ext_key ? 16 : 0;
+ key32[i] = FIELD_PREP(GENMASK(7, 0), sec_cam->key[j + 0]) |
+ FIELD_PREP(GENMASK(15, 8), sec_cam->key[j + 1]) |
+ FIELD_PREP(GENMASK(23, 16), sec_cam->key[j + 2]) |
+ FIELD_PREP(GENMASK(31, 24), sec_cam->key[j + 3]);
+ }
+
+ cmd = skb->data;
+ RTW89_SET_FWCMD_SEC_IDX(cmd, sec_cam->sec_cam_idx);
+ RTW89_SET_FWCMD_SEC_OFFSET(cmd, sec_cam->offset);
+ RTW89_SET_FWCMD_SEC_LEN(cmd, sec_cam->len);
+ RTW89_SET_FWCMD_SEC_TYPE(cmd, sec_cam->type);
+ RTW89_SET_FWCMD_SEC_EXT_KEY(cmd, ext_key);
+ RTW89_SET_FWCMD_SEC_SPP_MODE(cmd, sec_cam->spp_mode);
+ RTW89_SET_FWCMD_SEC_KEY0(cmd, key32[0]);
+ RTW89_SET_FWCMD_SEC_KEY1(cmd, key32[1]);
+ RTW89_SET_FWCMD_SEC_KEY2(cmd, key32[2]);
+ RTW89_SET_FWCMD_SEC_KEY3(cmd, key32[3]);
+
+ return skb;
+}
+
+static int rtw89_cam_send_sec_key_cmd(struct rtw89_dev *rtwdev,
+ struct rtw89_sec_cam_entry *sec_cam)
+{
+ struct sk_buff *skb, *ext_skb;
+ int ret;
+
+ skb = rtw89_cam_get_sec_key_cmd(rtwdev, sec_cam, false);
+ if (!skb) {
+ rtw89_err(rtwdev, "failed to get sec key command\n");
+ return -ENOMEM;
+ }
+
+ rtw89_h2c_pkt_set_hdr(rtwdev, skb,
+ FWCMD_TYPE_H2C,
+ H2C_CAT_MAC,
+ H2C_CL_MAC_SEC_CAM,
+ H2C_FUNC_MAC_SEC_UPD, 1, 0,
+ H2C_SEC_CAM_LEN);
+ ret = rtw89_h2c_tx(rtwdev, skb, false);
+ if (ret) {
+ rtw89_err(rtwdev, "failed to send sec key h2c: %d\n", ret);
+ dev_kfree_skb(skb);
+ return ret;
+ }
+
+ if (!sec_cam->ext_key)
+ return 0;
+
+ ext_skb = rtw89_cam_get_sec_key_cmd(rtwdev, sec_cam, true);
+ if (!skb) {
+ rtw89_err(rtwdev, "failed to get ext sec key command\n");
+ return -ENOMEM;
+ }
+
+ rtw89_h2c_pkt_set_hdr(rtwdev, ext_skb,
+ FWCMD_TYPE_H2C,
+ H2C_CAT_MAC,
+ H2C_CL_MAC_SEC_CAM,
+ H2C_FUNC_MAC_SEC_UPD,
+ 1, 0, H2C_SEC_CAM_LEN);
+ ret = rtw89_h2c_tx(rtwdev, ext_skb, false);
+ if (ret) {
+ rtw89_err(rtwdev, "failed to send ext sec key h2c: %d\n", ret);
+ dev_kfree_skb(ext_skb);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int rtw89_cam_get_avail_sec_cam(struct rtw89_dev *rtwdev,
+ u8 *sec_cam_idx, bool ext_key)
+{
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ struct rtw89_cam_info *cam_info = &rtwdev->cam_info;
+ u8 sec_cam_num = chip->scam_num;
+ u8 idx = 0;
+
+ if (!ext_key) {
+ idx = find_first_zero_bit(cam_info->sec_cam_map, sec_cam_num);
+ if (idx >= sec_cam_num)
+ return -EBUSY;
+
+ set_bit(idx, cam_info->sec_cam_map);
+ *sec_cam_idx = idx;
+
+ return 0;
+ }
+
+again:
+ idx = find_next_zero_bit(cam_info->sec_cam_map, sec_cam_num, idx);
+ if (idx >= sec_cam_num - 1)
+ return -EBUSY;
+ /* ext keys need two cam entries for 256-bit key */
+ if (test_bit(idx + 1, cam_info->sec_cam_map)) {
+ idx++;
+ goto again;
+ }
+
+ set_bit(idx, cam_info->sec_cam_map);
+ set_bit(idx + 1, cam_info->sec_cam_map);
+ *sec_cam_idx = idx;
+
+ return 0;
+}
+
+static int rtw89_cam_get_addr_cam_key_idx(struct rtw89_addr_cam_entry *addr_cam,
+ struct rtw89_sec_cam_entry *sec_cam,
+ struct ieee80211_key_conf *key,
+ u8 *key_idx)
+{
+ u8 idx;
+
+ /* RTW89_ADDR_CAM_SEC_NONE : not enabled
+ * RTW89_ADDR_CAM_SEC_ALL_UNI : 0 - 6 unicast
+ * RTW89_ADDR_CAM_SEC_NORMAL : 0 - 1 unicast, 2 - 4 group, 5 - 6 BIP
+ * RTW89_ADDR_CAM_SEC_4GROUP : 0 - 1 unicast, 2 - 5 group, 6 BIP
+ */
+ switch (addr_cam->sec_ent_mode) {
+ case RTW89_ADDR_CAM_SEC_NONE:
+ return -EINVAL;
+ case RTW89_ADDR_CAM_SEC_ALL_UNI:
+ if (!(key->flags | IEEE80211_KEY_FLAG_PAIRWISE))
+ return -EINVAL;
+ idx = find_first_zero_bit(addr_cam->sec_cam_map,
+ RTW89_SEC_CAM_IN_ADDR_CAM);
+ if (idx >= RTW89_SEC_CAM_IN_ADDR_CAM)
+ return -EBUSY;
+ *key_idx = idx;
+ break;
+ case RTW89_ADDR_CAM_SEC_NORMAL:
+ if (sec_cam->type == RTW89_SEC_KEY_TYPE_BIP_CCMP128) {
+ idx = find_next_zero_bit(addr_cam->sec_cam_map,
+ RTW89_SEC_CAM_IN_ADDR_CAM, 5);
+ if (idx > 6)
+ return -EBUSY;
+ *key_idx = idx;
+ break;
+ }
+
+ if (key->flags | IEEE80211_KEY_FLAG_PAIRWISE) {
+ idx = find_next_zero_bit(addr_cam->sec_cam_map,
+ RTW89_SEC_CAM_IN_ADDR_CAM, 0);
+ if (idx > 1)
+ return -EBUSY;
+ *key_idx = idx;
+ break;
+ }
+
+ /* Group keys */
+ idx = find_next_zero_bit(addr_cam->sec_cam_map,
+ RTW89_SEC_CAM_IN_ADDR_CAM, 2);
+ if (idx > 4)
+ return -EBUSY;
+ *key_idx = idx;
+ break;
+ case RTW89_ADDR_CAM_SEC_4GROUP:
+ if (sec_cam->type == RTW89_SEC_KEY_TYPE_BIP_CCMP128) {
+ if (test_bit(6, addr_cam->sec_cam_map))
+ return -EINVAL;
+ *key_idx = 6;
+ break;
+ }
+
+ if (key->flags | IEEE80211_KEY_FLAG_PAIRWISE) {
+ idx = find_next_zero_bit(addr_cam->sec_cam_map,
+ RTW89_SEC_CAM_IN_ADDR_CAM, 0);
+ if (idx > 1)
+ return -EBUSY;
+ *key_idx = idx;
+ break;
+ }
+
+ /* Group keys */
+ idx = find_next_zero_bit(addr_cam->sec_cam_map,
+ RTW89_SEC_CAM_IN_ADDR_CAM, 2);
+ if (idx > 5)
+ return -EBUSY;
+ *key_idx = idx;
+ break;
+ }
+
+ return 0;
+}
+
+static int rtw89_cam_attach_sec_cam(struct rtw89_dev *rtwdev,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key,
+ struct rtw89_sec_cam_entry *sec_cam)
+{
+ struct rtw89_vif *rtwvif;
+ struct rtw89_addr_cam_entry *addr_cam;
+ u8 key_idx = 0;
+ int ret;
+
+ if (!vif) {
+ rtw89_err(rtwdev, "No iface for adding sec cam\n");
+ return -EINVAL;
+ }
+
+ rtwvif = (struct rtw89_vif *)vif->drv_priv;
+ addr_cam = &rtwvif->addr_cam;
+ ret = rtw89_cam_get_addr_cam_key_idx(addr_cam, sec_cam, key, &key_idx);
+ if (ret) {
+ rtw89_err(rtwdev, "failed to get addr cam key idx %d, %d\n",
+ addr_cam->sec_ent_mode, sec_cam->type);
+ return ret;
+ }
+
+ key->hw_key_idx = key_idx;
+ addr_cam->sec_ent_keyid[key_idx] = key->keyidx;
+ addr_cam->sec_ent[key_idx] = sec_cam->sec_cam_idx;
+ addr_cam->sec_entries[key_idx] = sec_cam;
+ set_bit(key_idx, addr_cam->sec_cam_map);
+ ret = rtw89_fw_h2c_cam(rtwdev, rtwvif);
+ if (ret) {
+ rtw89_err(rtwdev, "failed to update addr cam sec entry: %d\n",
+ ret);
+ clear_bit(key_idx, addr_cam->sec_cam_map);
+ addr_cam->sec_entries[key_idx] = NULL;
+ return ret;
+ }
+
+ return 0;
+}
+
+static int rtw89_cam_sec_key_install(struct rtw89_dev *rtwdev,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key,
+ u8 hw_key_type, bool ext_key)
+{
+ struct rtw89_sec_cam_entry *sec_cam = NULL;
+ struct rtw89_cam_info *cam_info = &rtwdev->cam_info;
+ u8 sec_cam_idx;
+ int ret;
+
+ /* maximum key length 256-bit */
+ if (key->keylen > 32) {
+ rtw89_err(rtwdev, "invalid sec key length %d\n", key->keylen);
+ return -EINVAL;
+ }
+
+ ret = rtw89_cam_get_avail_sec_cam(rtwdev, &sec_cam_idx, ext_key);
+ if (ret) {
+ rtw89_warn(rtwdev, "no available sec cam: %d ext: %d\n",
+ ret, ext_key);
+ return ret;
+ }
+
+ sec_cam = kzalloc(sizeof(*sec_cam), GFP_KERNEL);
+ if (!sec_cam) {
+ ret = -ENOMEM;
+ goto err_release_cam;
+ }
+
+ sec_cam->sec_cam_idx = sec_cam_idx;
+ sec_cam->type = hw_key_type;
+ sec_cam->len = RTW89_SEC_CAM_LEN;
+ sec_cam->ext_key = ext_key;
+ memcpy(sec_cam->key, key->key, key->keylen);
+ ret = rtw89_cam_send_sec_key_cmd(rtwdev, sec_cam);
+ if (ret) {
+ rtw89_err(rtwdev, "failed to send sec key cmd: %d\n", ret);
+ goto err_release_cam;
+ }
+
+ /* associate with addr cam */
+ ret = rtw89_cam_attach_sec_cam(rtwdev, vif, sta, key, sec_cam);
+ if (ret) {
+ rtw89_err(rtwdev, "failed to attach sec cam: %d\n", ret);
+ goto err_release_cam;
+ }
+
+ return 0;
+
+err_release_cam:
+ kfree(sec_cam);
+ clear_bit(sec_cam_idx, cam_info->sec_cam_map);
+ if (ext_key)
+ clear_bit(sec_cam_idx + 1, cam_info->sec_cam_map);
+
+ return ret;
+}
+
+int rtw89_cam_sec_key_add(struct rtw89_dev *rtwdev,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key)
+{
+ u8 hw_key_type;
+ bool ext_key = false;
+ int ret;
+
+ switch (key->cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ hw_key_type = RTW89_SEC_KEY_TYPE_WEP40;
+ break;
+ case WLAN_CIPHER_SUITE_WEP104:
+ hw_key_type = RTW89_SEC_KEY_TYPE_WEP104;
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ hw_key_type = RTW89_SEC_KEY_TYPE_TKIP;
+ key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ hw_key_type = RTW89_SEC_KEY_TYPE_CCMP128;
+ key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;
+ break;
+ case WLAN_CIPHER_SUITE_CCMP_256:
+ case WLAN_CIPHER_SUITE_GCMP:
+ case WLAN_CIPHER_SUITE_GCMP_256:
+ case WLAN_CIPHER_SUITE_AES_CMAC:
+ case WLAN_CIPHER_SUITE_BIP_CMAC_256:
+ case WLAN_CIPHER_SUITE_BIP_GMAC_128:
+ case WLAN_CIPHER_SUITE_BIP_GMAC_256:
+ /* suppress error messages */
+ return -EOPNOTSUPP;
+ default:
+ return -ENOTSUPP;
+ }
+
+ key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+
+ ret = rtw89_cam_sec_key_install(rtwdev, vif, sta, key, hw_key_type,
+ ext_key);
+ if (ret) {
+ rtw89_err(rtwdev, "failed to install key type %d ext %d: %d\n",
+ hw_key_type, ext_key, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+int rtw89_cam_sec_key_del(struct rtw89_dev *rtwdev,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key)
+{
+ struct rtw89_cam_info *cam_info = &rtwdev->cam_info;
+ struct rtw89_vif *rtwvif;
+ struct rtw89_addr_cam_entry *addr_cam;
+ struct rtw89_sec_cam_entry *sec_cam;
+ u8 key_idx = key->hw_key_idx;
+ u8 sec_cam_idx;
+ int ret;
+
+ if (!vif) {
+ rtw89_err(rtwdev, "No iface for deleting sec cam\n");
+ return -EINVAL;
+ }
+
+ rtwvif = (struct rtw89_vif *)vif->drv_priv;
+ addr_cam = &rtwvif->addr_cam;
+ sec_cam = addr_cam->sec_entries[key_idx];
+
+ /* detach sec cam from addr cam */
+ clear_bit(key_idx, addr_cam->sec_cam_map);
+ addr_cam->sec_entries[key_idx] = NULL;
+ ret = rtw89_fw_h2c_cam(rtwdev, rtwvif);
+ if (ret)
+ rtw89_err(rtwdev, "failed to update cam del key: %d\n", ret);
+
+ /* clear valid bit in addr cam will disable sec cam,
+ * so we don't need to send H2C command again
+ */
+ sec_cam_idx = sec_cam->sec_cam_idx;
+ clear_bit(sec_cam_idx, cam_info->sec_cam_map);
+ if (sec_cam->ext_key)
+ clear_bit(sec_cam_idx + 1, cam_info->sec_cam_map);
+
+ kfree(sec_cam);
+
+ return ret;
+}
+
+void rtw89_cam_deinit(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
+{
+ struct rtw89_cam_info *cam_info = &rtwdev->cam_info;
+ struct rtw89_addr_cam_entry *addr_cam = &rtwvif->addr_cam;
+ struct rtw89_bssid_cam_entry *bssid_cam = &rtwvif->bssid_cam;
+
+ addr_cam->valid = false;
+ bssid_cam->valid = false;
+ clear_bit(addr_cam->addr_cam_idx, cam_info->addr_cam_map);
+ clear_bit(bssid_cam->bssid_cam_idx, cam_info->bssid_cam_map);
+}
+
+static int rtw89_cam_get_avail_addr_cam(struct rtw89_dev *rtwdev,
+ u8 *addr_cam_idx)
+{
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ struct rtw89_cam_info *cam_info = &rtwdev->cam_info;
+ u8 addr_cam_num = chip->acam_num;
+ u8 idx;
+
+ idx = find_first_zero_bit(cam_info->addr_cam_map, addr_cam_num);
+ if (idx >= addr_cam_num)
+ return -EBUSY;
+
+ set_bit(idx, cam_info->addr_cam_map);
+ *addr_cam_idx = idx;
+
+ return 0;
+}
+
+static int rtw89_cam_init_addr_cam(struct rtw89_dev *rtwdev,
+ struct rtw89_vif *rtwvif)
+{
+ struct rtw89_addr_cam_entry *addr_cam = &rtwvif->addr_cam;
+ u8 addr_cam_idx;
+ int i;
+ int ret;
+
+ ret = rtw89_cam_get_avail_addr_cam(rtwdev, &addr_cam_idx);
+ if (ret) {
+ rtw89_err(rtwdev, "failed to get available addr cam\n");
+ return ret;
+ }
+
+ addr_cam->addr_cam_idx = addr_cam_idx;
+ addr_cam->len = ADDR_CAM_ENT_SIZE;
+ addr_cam->offset = 0;
+ addr_cam->valid = true;
+ addr_cam->addr_mask = 0;
+ addr_cam->mask_sel = RTW89_NO_MSK;
+ bitmap_zero(addr_cam->sec_cam_map, RTW89_SEC_CAM_IN_ADDR_CAM);
+ ether_addr_copy(addr_cam->sma, rtwvif->mac_addr);
+
+ for (i = 0; i < RTW89_SEC_CAM_IN_ADDR_CAM; i++) {
+ addr_cam->sec_ent_keyid[i] = 0;
+ addr_cam->sec_ent[i] = 0;
+ }
+
+ return 0;
+}
+
+static int rtw89_cam_get_avail_bssid_cam(struct rtw89_dev *rtwdev,
+ u8 *bssid_cam_idx)
+{
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ struct rtw89_cam_info *cam_info = &rtwdev->cam_info;
+ u8 bssid_cam_num = chip->bcam_num;
+ u8 idx;
+
+ idx = find_first_zero_bit(cam_info->bssid_cam_map, bssid_cam_num);
+ if (idx >= bssid_cam_num)
+ return -EBUSY;
+
+ set_bit(idx, cam_info->bssid_cam_map);
+ *bssid_cam_idx = idx;
+
+ return 0;
+}
+
+static int rtw89_cam_init_bssid_cam(struct rtw89_dev *rtwdev,
+ struct rtw89_vif *rtwvif)
+{
+ struct rtw89_bssid_cam_entry *bssid_cam = &rtwvif->bssid_cam;
+ u8 bssid_cam_idx;
+ int ret;
+
+ ret = rtw89_cam_get_avail_bssid_cam(rtwdev, &bssid_cam_idx);
+ if (ret) {
+ rtw89_err(rtwdev, "failed to get available bssid cam\n");
+ return ret;
+ }
+
+ bssid_cam->bssid_cam_idx = bssid_cam_idx;
+ bssid_cam->phy_idx = rtwvif->phy_idx;
+ bssid_cam->len = BSSID_CAM_ENT_SIZE;
+ bssid_cam->offset = 0;
+ bssid_cam->valid = true;
+ ether_addr_copy(bssid_cam->bssid, rtwvif->bssid);
+
+ return 0;
+}
+
+void rtw89_cam_bssid_changed(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
+{
+ struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);
+ struct rtw89_addr_cam_entry *addr_cam = &rtwvif->addr_cam;
+ struct rtw89_bssid_cam_entry *bssid_cam = &rtwvif->bssid_cam;
+
+ if (vif->type == NL80211_IFTYPE_STATION)
+ ether_addr_copy(addr_cam->tma, rtwvif->bssid);
+ ether_addr_copy(bssid_cam->bssid, rtwvif->bssid);
+}
+
+int rtw89_cam_init(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
+{
+ struct rtw89_addr_cam_entry *addr_cam = &rtwvif->addr_cam;
+ struct rtw89_bssid_cam_entry *bssid_cam = &rtwvif->bssid_cam;
+ int ret;
+
+ ret = rtw89_cam_init_addr_cam(rtwdev, rtwvif);
+ if (ret) {
+ rtw89_err(rtwdev, "failed to init addr cam\n");
+ return ret;
+ }
+
+ ret = rtw89_cam_init_bssid_cam(rtwdev, rtwvif);
+ if (ret) {
+ rtw89_err(rtwdev, "failed to init bssid cam\n");
+ return ret;
+ }
+
+ /* associate addr cam with bssid cam */
+ addr_cam->bssid_cam_idx = bssid_cam->bssid_cam_idx;
+
+ return 0;
+}
+
+int rtw89_cam_fill_bssid_cam_info(struct rtw89_dev *rtwdev,
+ struct rtw89_vif *rtwvif, u8 *cmd)
+{
+ struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);
+ struct rtw89_bssid_cam_entry *bssid_cam = &rtwvif->bssid_cam;
+ u8 bss_color = vif->bss_conf.he_bss_color.color;
+
+ FWCMD_SET_ADDR_BSSID_IDX(cmd, bssid_cam->bssid_cam_idx);
+ FWCMD_SET_ADDR_BSSID_OFFSET(cmd, bssid_cam->offset);
+ FWCMD_SET_ADDR_BSSID_LEN(cmd, bssid_cam->len);
+ FWCMD_SET_ADDR_BSSID_VALID(cmd, bssid_cam->valid);
+ FWCMD_SET_ADDR_BSSID_BB_SEL(cmd, bssid_cam->phy_idx);
+ FWCMD_SET_ADDR_BSSID_BSS_COLOR(cmd, bss_color);
+
+ FWCMD_SET_ADDR_BSSID_BSSID0(cmd, bssid_cam->bssid[0]);
+ FWCMD_SET_ADDR_BSSID_BSSID1(cmd, bssid_cam->bssid[1]);
+ FWCMD_SET_ADDR_BSSID_BSSID2(cmd, bssid_cam->bssid[2]);
+ FWCMD_SET_ADDR_BSSID_BSSID3(cmd, bssid_cam->bssid[3]);
+ FWCMD_SET_ADDR_BSSID_BSSID4(cmd, bssid_cam->bssid[4]);
+ FWCMD_SET_ADDR_BSSID_BSSID5(cmd, bssid_cam->bssid[5]);
+
+ return 0;
+}
+
+static u8 rtw89_cam_addr_hash(u8 start, u8 *addr)
+{
+ u8 hash = 0;
+ u8 i;
+
+ for (i = start; i < ETH_ALEN; i++)
+ hash ^= addr[i];
+
+ return hash;
+}
+
+void rtw89_cam_fill_addr_cam_info(struct rtw89_dev *rtwdev,
+ struct rtw89_vif *rtwvif,
+ u8 *cmd)
+{
+ struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);
+ struct ieee80211_sta *sta;
+ struct rtw89_sta *rtwsta;
+ struct rtw89_addr_cam_entry *addr_cam = &rtwvif->addr_cam;
+ u8 sma_hash, tma_hash, addr_msk_start;
+ u8 sma_start = 0;
+ u8 tma_start = 0;
+
+ if (addr_cam->addr_mask != 0) {
+ addr_msk_start = __ffs(addr_cam->addr_mask);
+ if (addr_cam->mask_sel == RTW89_SMA)
+ sma_start = addr_msk_start;
+ else if (addr_cam->mask_sel == RTW89_TMA)
+ tma_start = addr_msk_start;
+ }
+ sma_hash = rtw89_cam_addr_hash(sma_start, rtwvif->mac_addr);
+ tma_hash = rtw89_cam_addr_hash(tma_start, addr_cam->tma);
+
+ FWCMD_SET_ADDR_IDX(cmd, addr_cam->addr_cam_idx);
+ FWCMD_SET_ADDR_OFFSET(cmd, addr_cam->offset);
+ FWCMD_SET_ADDR_LEN(cmd, addr_cam->len);
+
+ FWCMD_SET_ADDR_VALID(cmd, addr_cam->valid);
+ FWCMD_SET_ADDR_NET_TYPE(cmd, rtwvif->net_type);
+ FWCMD_SET_ADDR_BCN_HIT_COND(cmd, rtwvif->bcn_hit_cond);
+ FWCMD_SET_ADDR_HIT_RULE(cmd, rtwvif->hit_rule);
+ FWCMD_SET_ADDR_BB_SEL(cmd, rtwvif->phy_idx);
+ FWCMD_SET_ADDR_ADDR_MASK(cmd, addr_cam->addr_mask);
+ FWCMD_SET_ADDR_MASK_SEL(cmd, addr_cam->mask_sel);
+ FWCMD_SET_ADDR_SMA_HASH(cmd, sma_hash);
+ FWCMD_SET_ADDR_TMA_HASH(cmd, tma_hash);
+
+ FWCMD_SET_ADDR_BSSID_CAM_IDX(cmd, addr_cam->bssid_cam_idx);
+
+ FWCMD_SET_ADDR_SMA0(cmd, rtwvif->mac_addr[0]);
+ FWCMD_SET_ADDR_SMA1(cmd, rtwvif->mac_addr[1]);
+ FWCMD_SET_ADDR_SMA2(cmd, rtwvif->mac_addr[2]);
+ FWCMD_SET_ADDR_SMA3(cmd, rtwvif->mac_addr[3]);
+ FWCMD_SET_ADDR_SMA4(cmd, rtwvif->mac_addr[4]);
+ FWCMD_SET_ADDR_SMA5(cmd, rtwvif->mac_addr[5]);
+
+ FWCMD_SET_ADDR_TMA0(cmd, addr_cam->tma[0]);
+ FWCMD_SET_ADDR_TMA1(cmd, addr_cam->tma[1]);
+ FWCMD_SET_ADDR_TMA2(cmd, addr_cam->tma[2]);
+ FWCMD_SET_ADDR_TMA3(cmd, addr_cam->tma[3]);
+ FWCMD_SET_ADDR_TMA4(cmd, addr_cam->tma[4]);
+ FWCMD_SET_ADDR_TMA5(cmd, addr_cam->tma[5]);
+
+ FWCMD_SET_ADDR_PORT_INT(cmd, rtwvif->port);
+ FWCMD_SET_ADDR_TSF_SYNC(cmd, rtwvif->port);
+ FWCMD_SET_ADDR_TF_TRS(cmd, rtwvif->trigger);
+ FWCMD_SET_ADDR_LSIG_TXOP(cmd, rtwvif->lsig_txop);
+ FWCMD_SET_ADDR_TGT_IND(cmd, rtwvif->tgt_ind);
+ FWCMD_SET_ADDR_FRM_TGT_IND(cmd, rtwvif->frm_tgt_ind);
+
+ if (vif->type == NL80211_IFTYPE_STATION) {
+ sta = rtwvif->mgd.ap;
+ if (sta) {
+ rtwsta = (struct rtw89_sta *)sta->drv_priv;
+ FWCMD_SET_ADDR_MACID(cmd, rtwsta->mac_id);
+ FWCMD_SET_ADDR_AID12(cmd, vif->bss_conf.aid & 0xfff);
+ }
+ }
+ FWCMD_SET_ADDR_WOL_PATTERN(cmd, rtwvif->wowlan_pattern);
+ FWCMD_SET_ADDR_WOL_UC(cmd, rtwvif->wowlan_uc);
+ FWCMD_SET_ADDR_WOL_MAGIC(cmd, rtwvif->wowlan_magic);
+ FWCMD_SET_ADDR_WAPI(cmd, addr_cam->wapi);
+ FWCMD_SET_ADDR_SEC_ENT_MODE(cmd, addr_cam->sec_ent_mode);
+ FWCMD_SET_ADDR_SEC_ENT0_KEYID(cmd, addr_cam->sec_ent_keyid[0]);
+ FWCMD_SET_ADDR_SEC_ENT1_KEYID(cmd, addr_cam->sec_ent_keyid[1]);
+ FWCMD_SET_ADDR_SEC_ENT2_KEYID(cmd, addr_cam->sec_ent_keyid[2]);
+ FWCMD_SET_ADDR_SEC_ENT3_KEYID(cmd, addr_cam->sec_ent_keyid[3]);
+ FWCMD_SET_ADDR_SEC_ENT4_KEYID(cmd, addr_cam->sec_ent_keyid[4]);
+ FWCMD_SET_ADDR_SEC_ENT5_KEYID(cmd, addr_cam->sec_ent_keyid[5]);
+ FWCMD_SET_ADDR_SEC_ENT6_KEYID(cmd, addr_cam->sec_ent_keyid[6]);
+
+ FWCMD_SET_ADDR_SEC_ENT_VALID(cmd, addr_cam->sec_cam_map[0] & 0xff);
+ FWCMD_SET_ADDR_SEC_ENT0(cmd, addr_cam->sec_ent[0]);
+ FWCMD_SET_ADDR_SEC_ENT1(cmd, addr_cam->sec_ent[1]);
+ FWCMD_SET_ADDR_SEC_ENT2(cmd, addr_cam->sec_ent[2]);
+ FWCMD_SET_ADDR_SEC_ENT3(cmd, addr_cam->sec_ent[3]);
+ FWCMD_SET_ADDR_SEC_ENT4(cmd, addr_cam->sec_ent[4]);
+ FWCMD_SET_ADDR_SEC_ENT5(cmd, addr_cam->sec_ent[5]);
+ FWCMD_SET_ADDR_SEC_ENT6(cmd, addr_cam->sec_ent[6]);
+}
diff --git a/drivers/net/wireless/realtek/rtw89/cam.h b/drivers/net/wireless/realtek/rtw89/cam.h
new file mode 100644
index 000000000000..d6b20db5dc60
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw89/cam.h
@@ -0,0 +1,164 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
+/* Copyright(c) 2019-2020 Realtek Corporation
+ */
+
+#ifndef __RTW89_CAM_H__
+#define __RTW89_CAM_H__
+
+#include "core.h"
+
+#define RTW89_SEC_CAM_LEN 20
+
+#define FWCMD_SET_ADDR_IDX(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 1, value, GENMASK(7, 0))
+#define FWCMD_SET_ADDR_OFFSET(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 1, value, GENMASK(15, 8))
+#define FWCMD_SET_ADDR_LEN(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 1, value, GENMASK(23, 16))
+#define FWCMD_SET_ADDR_VALID(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 2, value, BIT(0))
+#define FWCMD_SET_ADDR_NET_TYPE(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 2, value, GENMASK(2, 1))
+#define FWCMD_SET_ADDR_BCN_HIT_COND(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 2, value, GENMASK(4, 3))
+#define FWCMD_SET_ADDR_HIT_RULE(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 2, value, GENMASK(6, 5))
+#define FWCMD_SET_ADDR_BB_SEL(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 2, value, BIT(7))
+#define FWCMD_SET_ADDR_ADDR_MASK(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 2, value, GENMASK(13, 8))
+#define FWCMD_SET_ADDR_MASK_SEL(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 2, value, GENMASK(15, 14))
+#define FWCMD_SET_ADDR_SMA_HASH(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 2, value, GENMASK(23, 16))
+#define FWCMD_SET_ADDR_TMA_HASH(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 2, value, GENMASK(31, 24))
+#define FWCMD_SET_ADDR_BSSID_CAM_IDX(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 3, value, GENMASK(5, 0))
+#define FWCMD_SET_ADDR_SMA0(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 4, value, GENMASK(7, 0))
+#define FWCMD_SET_ADDR_SMA1(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 4, value, GENMASK(15, 8))
+#define FWCMD_SET_ADDR_SMA2(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 4, value, GENMASK(23, 16))
+#define FWCMD_SET_ADDR_SMA3(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 4, value, GENMASK(31, 24))
+#define FWCMD_SET_ADDR_SMA4(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 5, value, GENMASK(7, 0))
+#define FWCMD_SET_ADDR_SMA5(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 5, value, GENMASK(15, 8))
+#define FWCMD_SET_ADDR_TMA0(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 5, value, GENMASK(23, 16))
+#define FWCMD_SET_ADDR_TMA1(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 5, value, GENMASK(31, 24))
+#define FWCMD_SET_ADDR_TMA2(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 6, value, GENMASK(7, 0))
+#define FWCMD_SET_ADDR_TMA3(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 6, value, GENMASK(15, 8))
+#define FWCMD_SET_ADDR_TMA4(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 6, value, GENMASK(23, 16))
+#define FWCMD_SET_ADDR_TMA5(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 6, value, GENMASK(31, 24))
+#define FWCMD_SET_ADDR_MACID(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 8, value, GENMASK(7, 0))
+#define FWCMD_SET_ADDR_PORT_INT(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 8, value, GENMASK(10, 8))
+#define FWCMD_SET_ADDR_TSF_SYNC(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 8, value, GENMASK(13, 11))
+#define FWCMD_SET_ADDR_TF_TRS(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 8, value, BIT(14))
+#define FWCMD_SET_ADDR_LSIG_TXOP(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 8, value, BIT(15))
+#define FWCMD_SET_ADDR_TGT_IND(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 8, value, GENMASK(26, 24))
+#define FWCMD_SET_ADDR_FRM_TGT_IND(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 8, value, GENMASK(29, 27))
+#define FWCMD_SET_ADDR_AID12(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 9, value, GENMASK(11, 0))
+#define FWCMD_SET_ADDR_AID12_0(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 9, value, GENMASK(7, 0))
+#define FWCMD_SET_ADDR_AID12_1(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 9, value, GENMASK(11, 8))
+#define FWCMD_SET_ADDR_WOL_PATTERN(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 9, value, BIT(12))
+#define FWCMD_SET_ADDR_WOL_UC(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 9, value, BIT(13))
+#define FWCMD_SET_ADDR_WOL_MAGIC(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 9, value, BIT(14))
+#define FWCMD_SET_ADDR_WAPI(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 9, value, BIT(15))
+#define FWCMD_SET_ADDR_SEC_ENT_MODE(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 9, value, GENMASK(17, 16))
+#define FWCMD_SET_ADDR_SEC_ENT0_KEYID(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 9, value, GENMASK(19, 18))
+#define FWCMD_SET_ADDR_SEC_ENT1_KEYID(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 9, value, GENMASK(21, 20))
+#define FWCMD_SET_ADDR_SEC_ENT2_KEYID(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 9, value, GENMASK(23, 22))
+#define FWCMD_SET_ADDR_SEC_ENT3_KEYID(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 9, value, GENMASK(25, 24))
+#define FWCMD_SET_ADDR_SEC_ENT4_KEYID(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 9, value, GENMASK(27, 26))
+#define FWCMD_SET_ADDR_SEC_ENT5_KEYID(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 9, value, GENMASK(29, 28))
+#define FWCMD_SET_ADDR_SEC_ENT6_KEYID(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 9, value, GENMASK(31, 30))
+#define FWCMD_SET_ADDR_SEC_ENT_VALID(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 10, value, GENMASK(7, 0))
+#define FWCMD_SET_ADDR_SEC_ENT0(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 10, value, GENMASK(15, 8))
+#define FWCMD_SET_ADDR_SEC_ENT1(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 10, value, GENMASK(23, 16))
+#define FWCMD_SET_ADDR_SEC_ENT2(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 10, value, GENMASK(31, 24))
+#define FWCMD_SET_ADDR_SEC_ENT3(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 11, value, GENMASK(7, 0))
+#define FWCMD_SET_ADDR_SEC_ENT4(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 11, value, GENMASK(15, 8))
+#define FWCMD_SET_ADDR_SEC_ENT5(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 11, value, GENMASK(23, 16))
+#define FWCMD_SET_ADDR_SEC_ENT6(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 11, value, GENMASK(31, 24))
+#define FWCMD_SET_ADDR_BSSID_IDX(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 12, value, GENMASK(7, 0))
+#define FWCMD_SET_ADDR_BSSID_OFFSET(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 12, value, GENMASK(15, 8))
+#define FWCMD_SET_ADDR_BSSID_LEN(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 12, value, GENMASK(23, 16))
+#define FWCMD_SET_ADDR_BSSID_VALID(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 13, value, BIT(0))
+#define FWCMD_SET_ADDR_BSSID_BB_SEL(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 13, value, BIT(1))
+#define FWCMD_SET_ADDR_BSSID_BSS_COLOR(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 13, value, GENMASK(13, 8))
+#define FWCMD_SET_ADDR_BSSID_BSSID0(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 13, value, GENMASK(23, 16))
+#define FWCMD_SET_ADDR_BSSID_BSSID1(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 13, value, GENMASK(31, 24))
+#define FWCMD_SET_ADDR_BSSID_BSSID2(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 14, value, GENMASK(7, 0))
+#define FWCMD_SET_ADDR_BSSID_BSSID3(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 14, value, GENMASK(15, 8))
+#define FWCMD_SET_ADDR_BSSID_BSSID4(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 14, value, GENMASK(23, 16))
+#define FWCMD_SET_ADDR_BSSID_BSSID5(cmd, value) \
+ le32p_replace_bits((__le32 *)(cmd) + 14, value, GENMASK(31, 24))
+
+int rtw89_cam_init(struct rtw89_dev *rtwdev, struct rtw89_vif *vif);
+void rtw89_cam_deinit(struct rtw89_dev *rtwdev, struct rtw89_vif *vif);
+void rtw89_cam_fill_addr_cam_info(struct rtw89_dev *rtwdev,
+ struct rtw89_vif *vif, u8 *cmd);
+int rtw89_cam_fill_bssid_cam_info(struct rtw89_dev *rtwdev,
+ struct rtw89_vif *vif, u8 *cmd);
+int rtw89_cam_sec_key_add(struct rtw89_dev *rtwdev,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key);
+int rtw89_cam_sec_key_del(struct rtw89_dev *rtwdev,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key);
+void rtw89_cam_bssid_changed(struct rtw89_dev *rtwdev,
+ struct rtw89_vif *rtwvif);
+
+#endif
--
2.21.0
Den 4.1.2021 kl. 11:17, skrev Ping-Ke Shih:
> This driver named rtw89, which is the next generation of rtw88, supports
> Realtek 8852AE 802.11ax 2x2 chip whose new features are OFDMA, DBCC,
> Spatial reuse, TWT and BSS coloring; now some of them aren't implemented
> though.
>
Hi, for some reason patch 16/18 does not show up in patchwork.
Where can one get the needed firmware:
$ modinfo rtw89_core.ko.xz |grep firmware
firmware: rtw89/rtw8852a_fw.bin
Also, the driver is missing the pci alias to get autoloading to work,
like the attached patch.
--
Thomas
> -----Original Message-----
> From: Thomas Backlund [mailto:[email protected]]
> Sent: Tuesday, January 05, 2021 12:31 AM
> To: [email protected]
> Cc: Pkshih
> Subject: Re: [PATCH V2 00/18] rtw89: add Realtek 802.11ax driver
>
> Den 4.1.2021 kl. 11:17, skrev Ping-Ke Shih:
> > This driver named rtw89, which is the next generation of rtw88, supports
> > Realtek 8852AE 802.11ax 2x2 chip whose new features are OFDMA, DBCC,
> > Spatial reuse, TWT and BSS coloring; now some of them aren't implemented
> > though.
> >
>
> Hi, for some reason patch 16/18 does not show up in patchwork.
I'm not sure what happened, but it's there now.
https://patchwork.kernel.org/project/linux-wireless/patch/[email protected]/
>
> Where can one get the needed firmware:
>
> $ modinfo rtw89_core.ko.xz |grep firmware
> firmware: rtw89/rtw8852a_fw.bin
We are still working on a stable firmware.
If you need an alpha version firmware, I can send you a copy privately.
>
>
> Also, the driver is missing the pci alias to get autoloading to work,
> like the attached patch.
I'll merge it into V3.
Thank you
---
Ping-Ke
Ping-Ke Shih <[email protected]> writes:
> This driver named rtw89, which is the next generation of rtw88, supports
> Realtek 8852AE 802.11ax 2x2 chip whose new features are OFDMA, DBCC,
> Spatial reuse, TWT and BSS coloring; now some of them aren't implemented
> though.
>
> The chip architecture is entirely different from the chips supported by
> rtw88 like RTL8822CE 802.11ac chip. First of all, register address ranges
> are totally redefined, so it's impossible to reuse register definition. To
> communicate with firmware, new H2C/C2H format is proposed. In order to have
> better utilization, TX DMA flow is changed to two stages DMA. To provide
> rich RX status information, additional RX PPDU packets are added.
Thanks for the good introduction. Do note that currently there are two
new drivers before rtw89, so reviewing this will most likely take some
time.
--
https://patchwork.kernel.org/project/linux-wireless/list/
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches