Skip to contentSkip to conversation

rtw89: add Realtek 802.11ax driver

PATCH Superseded Ping-Ke Shih 2 participants 4 messages Jan 4, 2021 – Jan 11, 2021 Realtek wireless driver (rtw89)

v2 of 7 Superseded Latest is v7 →

lore
Share & tools
lore

Ping-Ke Shih

author maintainer
#0 lore raw

v2 cover rtw89: add Realtek 802.11ax driver

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

- 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
Signature · 1 line
2.21.0
author maintainer
#1 lore raw

PATCH v2 1/18 rtw89: add CAM files

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.

---
 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
drivers/net/wireless/realtek/rtw89/cam.c new file +669 -0
new file mode 100644
index 000000000000..6b00a29b1e9c
@@ -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]);
+}
drivers/net/wireless/realtek/rtw89/cam.h new file +164 -0

164 lines not on this page · raw message

Signature · 1 line
2.21.0
author maintainer
#2 lore raw

PATCH v2 2/18 rtw89: add BT coexistence files

In reply to Ping-Ke Shih

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.

---
 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
drivers/net/wireless/realtek/rtw89/coex.c new file +385 -0
new file mode 100644
index 000000000000..cf402bc76b6f
@@ -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);
+}
drivers/net/wireless/realtek/rtw89/coex.h new file +102 -0

102 lines not on this page · raw message

Signature · 1 line
2.21.0
#3 lore raw
In reply to Ping-Ke Shih
Quoted 11 lines · 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.

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.

Signature · 3 lines
https://patchwork.kernel.org/project/linux-wireless/list/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches