xref: /freebsd/sys/contrib/dev/rtw89/cam.c (revision 6d67aabd63555ab62a2f2b7f52a75ef100a2fe75)
18e93258fSBjoern A. Zeeb // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
28e93258fSBjoern A. Zeeb /* Copyright(c) 2019-2020  Realtek Corporation
38e93258fSBjoern A. Zeeb  */
48e93258fSBjoern A. Zeeb 
58e93258fSBjoern A. Zeeb #include "cam.h"
68e93258fSBjoern A. Zeeb #include "debug.h"
78e93258fSBjoern A. Zeeb #include "fw.h"
88e93258fSBjoern A. Zeeb #include "mac.h"
98e93258fSBjoern A. Zeeb 
108e93258fSBjoern A. Zeeb static struct sk_buff *
118e93258fSBjoern A. Zeeb rtw89_cam_get_sec_key_cmd(struct rtw89_dev *rtwdev,
128e93258fSBjoern A. Zeeb 			  struct rtw89_sec_cam_entry *sec_cam,
138e93258fSBjoern A. Zeeb 			  bool ext_key)
148e93258fSBjoern A. Zeeb {
158e93258fSBjoern A. Zeeb 	struct sk_buff *skb;
168e93258fSBjoern A. Zeeb 	u32 cmd_len = H2C_SEC_CAM_LEN;
178e93258fSBjoern A. Zeeb 	u32 key32[4];
188e93258fSBjoern A. Zeeb 	u8 *cmd;
198e93258fSBjoern A. Zeeb 	int i, j;
208e93258fSBjoern A. Zeeb 
218e93258fSBjoern A. Zeeb 	skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, cmd_len);
228e93258fSBjoern A. Zeeb 	if (!skb)
238e93258fSBjoern A. Zeeb 		return NULL;
248e93258fSBjoern A. Zeeb 
258e93258fSBjoern A. Zeeb 	skb_put_zero(skb, cmd_len);
268e93258fSBjoern A. Zeeb 
278e93258fSBjoern A. Zeeb 	for (i = 0; i < 4; i++) {
288e93258fSBjoern A. Zeeb 		j = i * 4;
298e93258fSBjoern A. Zeeb 		j += ext_key ? 16 : 0;
308e93258fSBjoern A. Zeeb 		key32[i] = FIELD_PREP(GENMASK(7, 0), sec_cam->key[j + 0]) |
318e93258fSBjoern A. Zeeb 			   FIELD_PREP(GENMASK(15, 8), sec_cam->key[j + 1]) |
328e93258fSBjoern A. Zeeb 			   FIELD_PREP(GENMASK(23, 16), sec_cam->key[j + 2]) |
338e93258fSBjoern A. Zeeb 			   FIELD_PREP(GENMASK(31, 24), sec_cam->key[j + 3]);
348e93258fSBjoern A. Zeeb 	}
358e93258fSBjoern A. Zeeb 
368e93258fSBjoern A. Zeeb 	cmd = skb->data;
378e93258fSBjoern A. Zeeb 	RTW89_SET_FWCMD_SEC_IDX(cmd, sec_cam->sec_cam_idx + (ext_key ? 1 : 0));
388e93258fSBjoern A. Zeeb 	RTW89_SET_FWCMD_SEC_OFFSET(cmd, sec_cam->offset);
398e93258fSBjoern A. Zeeb 	RTW89_SET_FWCMD_SEC_LEN(cmd, sec_cam->len);
408e93258fSBjoern A. Zeeb 	RTW89_SET_FWCMD_SEC_TYPE(cmd, sec_cam->type);
418e93258fSBjoern A. Zeeb 	RTW89_SET_FWCMD_SEC_EXT_KEY(cmd, ext_key);
428e93258fSBjoern A. Zeeb 	RTW89_SET_FWCMD_SEC_SPP_MODE(cmd, sec_cam->spp_mode);
438e93258fSBjoern A. Zeeb 	RTW89_SET_FWCMD_SEC_KEY0(cmd, key32[0]);
448e93258fSBjoern A. Zeeb 	RTW89_SET_FWCMD_SEC_KEY1(cmd, key32[1]);
458e93258fSBjoern A. Zeeb 	RTW89_SET_FWCMD_SEC_KEY2(cmd, key32[2]);
468e93258fSBjoern A. Zeeb 	RTW89_SET_FWCMD_SEC_KEY3(cmd, key32[3]);
478e93258fSBjoern A. Zeeb 
488e93258fSBjoern A. Zeeb 	return skb;
498e93258fSBjoern A. Zeeb }
508e93258fSBjoern A. Zeeb 
518e93258fSBjoern A. Zeeb static int rtw89_cam_send_sec_key_cmd(struct rtw89_dev *rtwdev,
528e93258fSBjoern A. Zeeb 				      struct rtw89_sec_cam_entry *sec_cam)
538e93258fSBjoern A. Zeeb {
548e93258fSBjoern A. Zeeb 	struct sk_buff *skb, *ext_skb;
558e93258fSBjoern A. Zeeb 	int ret;
568e93258fSBjoern A. Zeeb 
578e93258fSBjoern A. Zeeb 	skb = rtw89_cam_get_sec_key_cmd(rtwdev, sec_cam, false);
588e93258fSBjoern A. Zeeb 	if (!skb) {
598e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "failed to get sec key command\n");
608e93258fSBjoern A. Zeeb 		return -ENOMEM;
618e93258fSBjoern A. Zeeb 	}
628e93258fSBjoern A. Zeeb 
638e93258fSBjoern A. Zeeb 	rtw89_h2c_pkt_set_hdr(rtwdev, skb,
648e93258fSBjoern A. Zeeb 			      FWCMD_TYPE_H2C,
658e93258fSBjoern A. Zeeb 			      H2C_CAT_MAC,
668e93258fSBjoern A. Zeeb 			      H2C_CL_MAC_SEC_CAM,
678e93258fSBjoern A. Zeeb 			      H2C_FUNC_MAC_SEC_UPD, 1, 0,
688e93258fSBjoern A. Zeeb 			      H2C_SEC_CAM_LEN);
698e93258fSBjoern A. Zeeb 	ret = rtw89_h2c_tx(rtwdev, skb, false);
708e93258fSBjoern A. Zeeb 	if (ret) {
718e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "failed to send sec key h2c: %d\n", ret);
728e93258fSBjoern A. Zeeb 		dev_kfree_skb(skb);
738e93258fSBjoern A. Zeeb 		return ret;
748e93258fSBjoern A. Zeeb 	}
758e93258fSBjoern A. Zeeb 
768e93258fSBjoern A. Zeeb 	if (!sec_cam->ext_key)
778e93258fSBjoern A. Zeeb 		return 0;
788e93258fSBjoern A. Zeeb 
798e93258fSBjoern A. Zeeb 	ext_skb = rtw89_cam_get_sec_key_cmd(rtwdev, sec_cam, true);
808e93258fSBjoern A. Zeeb 	if (!ext_skb) {
818e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "failed to get ext sec key command\n");
828e93258fSBjoern A. Zeeb 		return -ENOMEM;
838e93258fSBjoern A. Zeeb 	}
848e93258fSBjoern A. Zeeb 
858e93258fSBjoern A. Zeeb 	rtw89_h2c_pkt_set_hdr(rtwdev, ext_skb,
868e93258fSBjoern A. Zeeb 			      FWCMD_TYPE_H2C,
878e93258fSBjoern A. Zeeb 			      H2C_CAT_MAC,
888e93258fSBjoern A. Zeeb 			      H2C_CL_MAC_SEC_CAM,
898e93258fSBjoern A. Zeeb 			      H2C_FUNC_MAC_SEC_UPD,
908e93258fSBjoern A. Zeeb 			      1, 0, H2C_SEC_CAM_LEN);
918e93258fSBjoern A. Zeeb 	ret = rtw89_h2c_tx(rtwdev, ext_skb, false);
928e93258fSBjoern A. Zeeb 	if (ret) {
938e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "failed to send ext sec key h2c: %d\n", ret);
948e93258fSBjoern A. Zeeb 		dev_kfree_skb(ext_skb);
958e93258fSBjoern A. Zeeb 		return ret;
968e93258fSBjoern A. Zeeb 	}
978e93258fSBjoern A. Zeeb 
988e93258fSBjoern A. Zeeb 	return 0;
998e93258fSBjoern A. Zeeb }
1008e93258fSBjoern A. Zeeb 
1018e93258fSBjoern A. Zeeb static int rtw89_cam_get_avail_sec_cam(struct rtw89_dev *rtwdev,
1028e93258fSBjoern A. Zeeb 				       u8 *sec_cam_idx, bool ext_key)
1038e93258fSBjoern A. Zeeb {
1048e93258fSBjoern A. Zeeb 	const struct rtw89_chip_info *chip = rtwdev->chip;
1058e93258fSBjoern A. Zeeb 	struct rtw89_cam_info *cam_info = &rtwdev->cam_info;
1068e93258fSBjoern A. Zeeb 	u8 sec_cam_num = chip->scam_num;
1078e93258fSBjoern A. Zeeb 	u8 idx = 0;
1088e93258fSBjoern A. Zeeb 
1098e93258fSBjoern A. Zeeb 	if (!ext_key) {
1108e93258fSBjoern A. Zeeb 		idx = find_first_zero_bit(cam_info->sec_cam_map, sec_cam_num);
1118e93258fSBjoern A. Zeeb 		if (idx >= sec_cam_num)
1128e93258fSBjoern A. Zeeb 			return -EBUSY;
1138e93258fSBjoern A. Zeeb 
1148e93258fSBjoern A. Zeeb 		set_bit(idx, cam_info->sec_cam_map);
1158e93258fSBjoern A. Zeeb 		*sec_cam_idx = idx;
1168e93258fSBjoern A. Zeeb 
1178e93258fSBjoern A. Zeeb 		return 0;
1188e93258fSBjoern A. Zeeb 	}
1198e93258fSBjoern A. Zeeb 
1208e93258fSBjoern A. Zeeb again:
1218e93258fSBjoern A. Zeeb 	idx = find_next_zero_bit(cam_info->sec_cam_map, sec_cam_num, idx);
1228e93258fSBjoern A. Zeeb 	if (idx >= sec_cam_num - 1)
1238e93258fSBjoern A. Zeeb 		return -EBUSY;
1248e93258fSBjoern A. Zeeb 	/* ext keys need two cam entries for 256-bit key */
1258e93258fSBjoern A. Zeeb 	if (test_bit(idx + 1, cam_info->sec_cam_map)) {
1268e93258fSBjoern A. Zeeb 		idx++;
1278e93258fSBjoern A. Zeeb 		goto again;
1288e93258fSBjoern A. Zeeb 	}
1298e93258fSBjoern A. Zeeb 
1308e93258fSBjoern A. Zeeb 	set_bit(idx, cam_info->sec_cam_map);
1318e93258fSBjoern A. Zeeb 	set_bit(idx + 1, cam_info->sec_cam_map);
1328e93258fSBjoern A. Zeeb 	*sec_cam_idx = idx;
1338e93258fSBjoern A. Zeeb 
1348e93258fSBjoern A. Zeeb 	return 0;
1358e93258fSBjoern A. Zeeb }
1368e93258fSBjoern A. Zeeb 
1378e93258fSBjoern A. Zeeb static int rtw89_cam_get_addr_cam_key_idx(struct rtw89_addr_cam_entry *addr_cam,
1388e93258fSBjoern A. Zeeb 					  struct rtw89_sec_cam_entry *sec_cam,
1398e93258fSBjoern A. Zeeb 					  struct ieee80211_key_conf *key,
1408e93258fSBjoern A. Zeeb 					  u8 *key_idx)
1418e93258fSBjoern A. Zeeb {
1428e93258fSBjoern A. Zeeb 	u8 idx;
1438e93258fSBjoern A. Zeeb 
1448e93258fSBjoern A. Zeeb 	/* RTW89_ADDR_CAM_SEC_NONE	: not enabled
1458e93258fSBjoern A. Zeeb 	 * RTW89_ADDR_CAM_SEC_ALL_UNI	: 0 - 6 unicast
1468e93258fSBjoern A. Zeeb 	 * RTW89_ADDR_CAM_SEC_NORMAL	: 0 - 1 unicast, 2 - 4 group, 5 - 6 BIP
1478e93258fSBjoern A. Zeeb 	 * RTW89_ADDR_CAM_SEC_4GROUP	: 0 - 1 unicast, 2 - 5 group, 6 BIP
1488e93258fSBjoern A. Zeeb 	 */
1498e93258fSBjoern A. Zeeb 	switch (addr_cam->sec_ent_mode) {
1508e93258fSBjoern A. Zeeb 	case RTW89_ADDR_CAM_SEC_NONE:
1518e93258fSBjoern A. Zeeb 		return -EINVAL;
1528e93258fSBjoern A. Zeeb 	case RTW89_ADDR_CAM_SEC_ALL_UNI:
1538e93258fSBjoern A. Zeeb 		idx = find_first_zero_bit(addr_cam->sec_cam_map,
1548e93258fSBjoern A. Zeeb 					  RTW89_SEC_CAM_IN_ADDR_CAM);
1558e93258fSBjoern A. Zeeb 		if (idx >= RTW89_SEC_CAM_IN_ADDR_CAM)
1568e93258fSBjoern A. Zeeb 			return -EBUSY;
1578e93258fSBjoern A. Zeeb 		*key_idx = idx;
1588e93258fSBjoern A. Zeeb 		break;
1598e93258fSBjoern A. Zeeb 	case RTW89_ADDR_CAM_SEC_NORMAL:
1608e93258fSBjoern A. Zeeb 		if (sec_cam->type == RTW89_SEC_KEY_TYPE_BIP_CCMP128) {
1618e93258fSBjoern A. Zeeb 			idx = find_next_zero_bit(addr_cam->sec_cam_map,
1628e93258fSBjoern A. Zeeb 						 RTW89_SEC_CAM_IN_ADDR_CAM, 5);
1638e93258fSBjoern A. Zeeb 			if (idx > 6)
1648e93258fSBjoern A. Zeeb 				return -EBUSY;
1658e93258fSBjoern A. Zeeb 			*key_idx = idx;
1668e93258fSBjoern A. Zeeb 			break;
1678e93258fSBjoern A. Zeeb 		}
1688e93258fSBjoern A. Zeeb 
1698e93258fSBjoern A. Zeeb 		if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) {
1708e93258fSBjoern A. Zeeb 			idx = find_next_zero_bit(addr_cam->sec_cam_map,
1718e93258fSBjoern A. Zeeb 						 RTW89_SEC_CAM_IN_ADDR_CAM, 0);
1728e93258fSBjoern A. Zeeb 			if (idx > 1)
1738e93258fSBjoern A. Zeeb 				return -EBUSY;
1748e93258fSBjoern A. Zeeb 			*key_idx = idx;
1758e93258fSBjoern A. Zeeb 			break;
1768e93258fSBjoern A. Zeeb 		}
1778e93258fSBjoern A. Zeeb 
1788e93258fSBjoern A. Zeeb 		/* Group keys */
1798e93258fSBjoern A. Zeeb 		idx = find_next_zero_bit(addr_cam->sec_cam_map,
1808e93258fSBjoern A. Zeeb 					 RTW89_SEC_CAM_IN_ADDR_CAM, 2);
1818e93258fSBjoern A. Zeeb 		if (idx > 4)
1828e93258fSBjoern A. Zeeb 			return -EBUSY;
1838e93258fSBjoern A. Zeeb 		*key_idx = idx;
1848e93258fSBjoern A. Zeeb 		break;
1858e93258fSBjoern A. Zeeb 	case RTW89_ADDR_CAM_SEC_4GROUP:
1868e93258fSBjoern A. Zeeb 		if (sec_cam->type == RTW89_SEC_KEY_TYPE_BIP_CCMP128) {
1878e93258fSBjoern A. Zeeb 			if (test_bit(6, addr_cam->sec_cam_map))
1888e93258fSBjoern A. Zeeb 				return -EINVAL;
1898e93258fSBjoern A. Zeeb 			*key_idx = 6;
1908e93258fSBjoern A. Zeeb 			break;
1918e93258fSBjoern A. Zeeb 		}
1928e93258fSBjoern A. Zeeb 
1938e93258fSBjoern A. Zeeb 		if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) {
1948e93258fSBjoern A. Zeeb 			idx = find_next_zero_bit(addr_cam->sec_cam_map,
1958e93258fSBjoern A. Zeeb 						 RTW89_SEC_CAM_IN_ADDR_CAM, 0);
1968e93258fSBjoern A. Zeeb 			if (idx > 1)
1978e93258fSBjoern A. Zeeb 				return -EBUSY;
1988e93258fSBjoern A. Zeeb 			*key_idx = idx;
1998e93258fSBjoern A. Zeeb 			break;
2008e93258fSBjoern A. Zeeb 		}
2018e93258fSBjoern A. Zeeb 
2028e93258fSBjoern A. Zeeb 		/* Group keys */
2038e93258fSBjoern A. Zeeb 		idx = find_next_zero_bit(addr_cam->sec_cam_map,
2048e93258fSBjoern A. Zeeb 					 RTW89_SEC_CAM_IN_ADDR_CAM, 2);
2058e93258fSBjoern A. Zeeb 		if (idx > 5)
2068e93258fSBjoern A. Zeeb 			return -EBUSY;
2078e93258fSBjoern A. Zeeb 		*key_idx = idx;
2088e93258fSBjoern A. Zeeb 		break;
2098e93258fSBjoern A. Zeeb 	}
2108e93258fSBjoern A. Zeeb 
2118e93258fSBjoern A. Zeeb 	return 0;
2128e93258fSBjoern A. Zeeb }
2138e93258fSBjoern A. Zeeb 
214*6d67aabdSBjoern A. Zeeb static int rtw89_cam_detach_sec_cam(struct rtw89_dev *rtwdev,
215*6d67aabdSBjoern A. Zeeb 				    struct ieee80211_vif *vif,
216*6d67aabdSBjoern A. Zeeb 				    struct ieee80211_sta *sta,
217*6d67aabdSBjoern A. Zeeb 				    const struct rtw89_sec_cam_entry *sec_cam,
218*6d67aabdSBjoern A. Zeeb 				    bool inform_fw)
219*6d67aabdSBjoern A. Zeeb {
220*6d67aabdSBjoern A. Zeeb 	struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta);
221*6d67aabdSBjoern A. Zeeb 	struct rtw89_vif *rtwvif;
222*6d67aabdSBjoern A. Zeeb 	struct rtw89_addr_cam_entry *addr_cam;
223*6d67aabdSBjoern A. Zeeb 	unsigned int i;
224*6d67aabdSBjoern A. Zeeb 	int ret = 0;
225*6d67aabdSBjoern A. Zeeb 
226*6d67aabdSBjoern A. Zeeb 	if (!vif) {
227*6d67aabdSBjoern A. Zeeb 		rtw89_err(rtwdev, "No iface for deleting sec cam\n");
228*6d67aabdSBjoern A. Zeeb 		return -EINVAL;
229*6d67aabdSBjoern A. Zeeb 	}
230*6d67aabdSBjoern A. Zeeb 
231*6d67aabdSBjoern A. Zeeb 	rtwvif = (struct rtw89_vif *)vif->drv_priv;
232*6d67aabdSBjoern A. Zeeb 	addr_cam = rtw89_get_addr_cam_of(rtwvif, rtwsta);
233*6d67aabdSBjoern A. Zeeb 
234*6d67aabdSBjoern A. Zeeb 	for_each_set_bit(i, addr_cam->sec_cam_map, RTW89_SEC_CAM_IN_ADDR_CAM) {
235*6d67aabdSBjoern A. Zeeb 		if (addr_cam->sec_ent[i] != sec_cam->sec_cam_idx)
236*6d67aabdSBjoern A. Zeeb 			continue;
237*6d67aabdSBjoern A. Zeeb 
238*6d67aabdSBjoern A. Zeeb 		clear_bit(i, addr_cam->sec_cam_map);
239*6d67aabdSBjoern A. Zeeb 	}
240*6d67aabdSBjoern A. Zeeb 
241*6d67aabdSBjoern A. Zeeb 	if (inform_fw) {
242*6d67aabdSBjoern A. Zeeb 		ret = rtw89_chip_h2c_dctl_sec_cam(rtwdev, rtwvif, rtwsta);
243*6d67aabdSBjoern A. Zeeb 		if (ret)
244*6d67aabdSBjoern A. Zeeb 			rtw89_err(rtwdev,
245*6d67aabdSBjoern A. Zeeb 				  "failed to update dctl cam del key: %d\n", ret);
246*6d67aabdSBjoern A. Zeeb 		ret = rtw89_fw_h2c_cam(rtwdev, rtwvif, rtwsta, NULL);
247*6d67aabdSBjoern A. Zeeb 		if (ret)
248*6d67aabdSBjoern A. Zeeb 			rtw89_err(rtwdev, "failed to update cam del key: %d\n", ret);
249*6d67aabdSBjoern A. Zeeb 	}
250*6d67aabdSBjoern A. Zeeb 
251*6d67aabdSBjoern A. Zeeb 	return ret;
252*6d67aabdSBjoern A. Zeeb }
253*6d67aabdSBjoern A. Zeeb 
2548e93258fSBjoern A. Zeeb static int rtw89_cam_attach_sec_cam(struct rtw89_dev *rtwdev,
2558e93258fSBjoern A. Zeeb 				    struct ieee80211_vif *vif,
2568e93258fSBjoern A. Zeeb 				    struct ieee80211_sta *sta,
2578e93258fSBjoern A. Zeeb 				    struct ieee80211_key_conf *key,
2588e93258fSBjoern A. Zeeb 				    struct rtw89_sec_cam_entry *sec_cam)
2598e93258fSBjoern A. Zeeb {
2608e93258fSBjoern A. Zeeb 	struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta);
2618e93258fSBjoern A. Zeeb 	struct rtw89_vif *rtwvif;
2628e93258fSBjoern A. Zeeb 	struct rtw89_addr_cam_entry *addr_cam;
2638e93258fSBjoern A. Zeeb 	u8 key_idx = 0;
2648e93258fSBjoern A. Zeeb 	int ret;
2658e93258fSBjoern A. Zeeb 
2668e93258fSBjoern A. Zeeb 	if (!vif) {
2678e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "No iface for adding sec cam\n");
2688e93258fSBjoern A. Zeeb 		return -EINVAL;
2698e93258fSBjoern A. Zeeb 	}
2708e93258fSBjoern A. Zeeb 
2718e93258fSBjoern A. Zeeb 	rtwvif = (struct rtw89_vif *)vif->drv_priv;
2728e93258fSBjoern A. Zeeb 	addr_cam = rtw89_get_addr_cam_of(rtwvif, rtwsta);
273*6d67aabdSBjoern A. Zeeb 
274*6d67aabdSBjoern A. Zeeb 	if (key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
275*6d67aabdSBjoern A. Zeeb 	    key->cipher == WLAN_CIPHER_SUITE_WEP104)
276*6d67aabdSBjoern A. Zeeb 		addr_cam->sec_ent_mode = RTW89_ADDR_CAM_SEC_ALL_UNI;
277*6d67aabdSBjoern A. Zeeb 
2788e93258fSBjoern A. Zeeb 	ret = rtw89_cam_get_addr_cam_key_idx(addr_cam, sec_cam, key, &key_idx);
2798e93258fSBjoern A. Zeeb 	if (ret) {
2808e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "failed to get addr cam key idx %d, %d\n",
2818e93258fSBjoern A. Zeeb 			  addr_cam->sec_ent_mode, sec_cam->type);
2828e93258fSBjoern A. Zeeb 		return ret;
2838e93258fSBjoern A. Zeeb 	}
2848e93258fSBjoern A. Zeeb 
2858e93258fSBjoern A. Zeeb 	addr_cam->sec_ent_keyid[key_idx] = key->keyidx;
2868e93258fSBjoern A. Zeeb 	addr_cam->sec_ent[key_idx] = sec_cam->sec_cam_idx;
2878e93258fSBjoern A. Zeeb 	set_bit(key_idx, addr_cam->sec_cam_map);
2888e93258fSBjoern A. Zeeb 	ret = rtw89_chip_h2c_dctl_sec_cam(rtwdev, rtwvif, rtwsta);
2898e93258fSBjoern A. Zeeb 	if (ret) {
2908e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "failed to update dctl cam sec entry: %d\n",
2918e93258fSBjoern A. Zeeb 			  ret);
2928e93258fSBjoern A. Zeeb 		return ret;
2938e93258fSBjoern A. Zeeb 	}
2948e93258fSBjoern A. Zeeb 	ret = rtw89_fw_h2c_cam(rtwdev, rtwvif, rtwsta, NULL);
2958e93258fSBjoern A. Zeeb 	if (ret) {
2968e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "failed to update addr cam sec entry: %d\n",
2978e93258fSBjoern A. Zeeb 			  ret);
2988e93258fSBjoern A. Zeeb 		clear_bit(key_idx, addr_cam->sec_cam_map);
2998e93258fSBjoern A. Zeeb 		return ret;
3008e93258fSBjoern A. Zeeb 	}
3018e93258fSBjoern A. Zeeb 
3028e93258fSBjoern A. Zeeb 	return 0;
3038e93258fSBjoern A. Zeeb }
3048e93258fSBjoern A. Zeeb 
3058e93258fSBjoern A. Zeeb static int rtw89_cam_sec_key_install(struct rtw89_dev *rtwdev,
3068e93258fSBjoern A. Zeeb 				     struct ieee80211_vif *vif,
3078e93258fSBjoern A. Zeeb 				     struct ieee80211_sta *sta,
3088e93258fSBjoern A. Zeeb 				     struct ieee80211_key_conf *key,
3098e93258fSBjoern A. Zeeb 				     u8 hw_key_type, bool ext_key)
3108e93258fSBjoern A. Zeeb {
3118e93258fSBjoern A. Zeeb 	struct rtw89_sec_cam_entry *sec_cam = NULL;
3128e93258fSBjoern A. Zeeb 	struct rtw89_cam_info *cam_info = &rtwdev->cam_info;
3138e93258fSBjoern A. Zeeb 	u8 sec_cam_idx;
3148e93258fSBjoern A. Zeeb 	int ret;
3158e93258fSBjoern A. Zeeb 
3168e93258fSBjoern A. Zeeb 	/* maximum key length 256-bit */
3178e93258fSBjoern A. Zeeb 	if (key->keylen > 32) {
3188e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "invalid sec key length %d\n", key->keylen);
3198e93258fSBjoern A. Zeeb 		return -EINVAL;
3208e93258fSBjoern A. Zeeb 	}
3218e93258fSBjoern A. Zeeb 
3228e93258fSBjoern A. Zeeb 	ret = rtw89_cam_get_avail_sec_cam(rtwdev, &sec_cam_idx, ext_key);
3238e93258fSBjoern A. Zeeb 	if (ret) {
3248e93258fSBjoern A. Zeeb 		rtw89_warn(rtwdev, "no available sec cam: %d ext: %d\n",
3258e93258fSBjoern A. Zeeb 			   ret, ext_key);
3268e93258fSBjoern A. Zeeb 		return ret;
3278e93258fSBjoern A. Zeeb 	}
3288e93258fSBjoern A. Zeeb 
3298e93258fSBjoern A. Zeeb 	sec_cam = kzalloc(sizeof(*sec_cam), GFP_KERNEL);
3308e93258fSBjoern A. Zeeb 	if (!sec_cam) {
3318e93258fSBjoern A. Zeeb 		ret = -ENOMEM;
3328e93258fSBjoern A. Zeeb 		goto err_release_cam;
3338e93258fSBjoern A. Zeeb 	}
3348e93258fSBjoern A. Zeeb 
335*6d67aabdSBjoern A. Zeeb 	key->hw_key_idx = sec_cam_idx;
336*6d67aabdSBjoern A. Zeeb 	cam_info->sec_entries[sec_cam_idx] = sec_cam;
337*6d67aabdSBjoern A. Zeeb 
3388e93258fSBjoern A. Zeeb 	sec_cam->sec_cam_idx = sec_cam_idx;
3398e93258fSBjoern A. Zeeb 	sec_cam->type = hw_key_type;
3408e93258fSBjoern A. Zeeb 	sec_cam->len = RTW89_SEC_CAM_LEN;
3418e93258fSBjoern A. Zeeb 	sec_cam->ext_key = ext_key;
3428e93258fSBjoern A. Zeeb 	memcpy(sec_cam->key, key->key, key->keylen);
3438e93258fSBjoern A. Zeeb 	ret = rtw89_cam_send_sec_key_cmd(rtwdev, sec_cam);
3448e93258fSBjoern A. Zeeb 	if (ret) {
3458e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "failed to send sec key cmd: %d\n", ret);
3468e93258fSBjoern A. Zeeb 		goto err_release_cam;
3478e93258fSBjoern A. Zeeb 	}
3488e93258fSBjoern A. Zeeb 
3498e93258fSBjoern A. Zeeb 	/* associate with addr cam */
3508e93258fSBjoern A. Zeeb 	ret = rtw89_cam_attach_sec_cam(rtwdev, vif, sta, key, sec_cam);
3518e93258fSBjoern A. Zeeb 	if (ret) {
3528e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "failed to attach sec cam: %d\n", ret);
3538e93258fSBjoern A. Zeeb 		goto err_release_cam;
3548e93258fSBjoern A. Zeeb 	}
3558e93258fSBjoern A. Zeeb 
3568e93258fSBjoern A. Zeeb 	return 0;
3578e93258fSBjoern A. Zeeb 
3588e93258fSBjoern A. Zeeb err_release_cam:
359*6d67aabdSBjoern A. Zeeb 	cam_info->sec_entries[sec_cam_idx] = NULL;
3608e93258fSBjoern A. Zeeb 	kfree(sec_cam);
3618e93258fSBjoern A. Zeeb 	clear_bit(sec_cam_idx, cam_info->sec_cam_map);
3628e93258fSBjoern A. Zeeb 	if (ext_key)
3638e93258fSBjoern A. Zeeb 		clear_bit(sec_cam_idx + 1, cam_info->sec_cam_map);
3648e93258fSBjoern A. Zeeb 
3658e93258fSBjoern A. Zeeb 	return ret;
3668e93258fSBjoern A. Zeeb }
3678e93258fSBjoern A. Zeeb 
3688e93258fSBjoern A. Zeeb int rtw89_cam_sec_key_add(struct rtw89_dev *rtwdev,
3698e93258fSBjoern A. Zeeb 			  struct ieee80211_vif *vif,
3708e93258fSBjoern A. Zeeb 			  struct ieee80211_sta *sta,
3718e93258fSBjoern A. Zeeb 			  struct ieee80211_key_conf *key)
3728e93258fSBjoern A. Zeeb {
3738e93258fSBjoern A. Zeeb 	const struct rtw89_chip_info *chip = rtwdev->chip;
3748e93258fSBjoern A. Zeeb 	u8 hw_key_type;
3758e93258fSBjoern A. Zeeb 	bool ext_key = false;
3768e93258fSBjoern A. Zeeb 	int ret;
3778e93258fSBjoern A. Zeeb 
3788e93258fSBjoern A. Zeeb 	switch (key->cipher) {
3798e93258fSBjoern A. Zeeb 	case WLAN_CIPHER_SUITE_WEP40:
3808e93258fSBjoern A. Zeeb 		hw_key_type = RTW89_SEC_KEY_TYPE_WEP40;
3818e93258fSBjoern A. Zeeb 		break;
3828e93258fSBjoern A. Zeeb 	case WLAN_CIPHER_SUITE_WEP104:
3838e93258fSBjoern A. Zeeb 		hw_key_type = RTW89_SEC_KEY_TYPE_WEP104;
3848e93258fSBjoern A. Zeeb 		break;
3858e93258fSBjoern A. Zeeb 	case WLAN_CIPHER_SUITE_CCMP:
3868e93258fSBjoern A. Zeeb 		hw_key_type = RTW89_SEC_KEY_TYPE_CCMP128;
3878e93258fSBjoern A. Zeeb 		key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;
3888e93258fSBjoern A. Zeeb 		break;
3898e93258fSBjoern A. Zeeb 	case WLAN_CIPHER_SUITE_CCMP_256:
3908e93258fSBjoern A. Zeeb 		hw_key_type = RTW89_SEC_KEY_TYPE_CCMP256;
3918e93258fSBjoern A. Zeeb 		key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;
3928e93258fSBjoern A. Zeeb 		ext_key = true;
3938e93258fSBjoern A. Zeeb 		break;
3948e93258fSBjoern A. Zeeb 	case WLAN_CIPHER_SUITE_GCMP:
3958e93258fSBjoern A. Zeeb 		hw_key_type = RTW89_SEC_KEY_TYPE_GCMP128;
3968e93258fSBjoern A. Zeeb 		key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;
3978e93258fSBjoern A. Zeeb 		break;
3988e93258fSBjoern A. Zeeb 	case WLAN_CIPHER_SUITE_GCMP_256:
3998e93258fSBjoern A. Zeeb 		hw_key_type = RTW89_SEC_KEY_TYPE_GCMP256;
4008e93258fSBjoern A. Zeeb 		key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;
4018e93258fSBjoern A. Zeeb 		ext_key = true;
4028e93258fSBjoern A. Zeeb 		break;
403*6d67aabdSBjoern A. Zeeb 	case WLAN_CIPHER_SUITE_AES_CMAC:
404*6d67aabdSBjoern A. Zeeb 		hw_key_type = RTW89_SEC_KEY_TYPE_BIP_CCMP128;
405*6d67aabdSBjoern A. Zeeb 		break;
4068e93258fSBjoern A. Zeeb 	default:
4078e93258fSBjoern A. Zeeb 		return -EOPNOTSUPP;
4088e93258fSBjoern A. Zeeb 	}
4098e93258fSBjoern A. Zeeb 
4108e93258fSBjoern A. Zeeb 	if (!chip->hw_sec_hdr)
4118e93258fSBjoern A. Zeeb 		key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
4128e93258fSBjoern A. Zeeb 
4138e93258fSBjoern A. Zeeb 	ret = rtw89_cam_sec_key_install(rtwdev, vif, sta, key, hw_key_type,
4148e93258fSBjoern A. Zeeb 					ext_key);
4158e93258fSBjoern A. Zeeb 	if (ret) {
4168e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "failed to install key type %d ext %d: %d\n",
4178e93258fSBjoern A. Zeeb 			  hw_key_type, ext_key, ret);
4188e93258fSBjoern A. Zeeb 		return ret;
4198e93258fSBjoern A. Zeeb 	}
4208e93258fSBjoern A. Zeeb 
4218e93258fSBjoern A. Zeeb 	return 0;
4228e93258fSBjoern A. Zeeb }
4238e93258fSBjoern A. Zeeb 
4248e93258fSBjoern A. Zeeb int rtw89_cam_sec_key_del(struct rtw89_dev *rtwdev,
4258e93258fSBjoern A. Zeeb 			  struct ieee80211_vif *vif,
4268e93258fSBjoern A. Zeeb 			  struct ieee80211_sta *sta,
4278e93258fSBjoern A. Zeeb 			  struct ieee80211_key_conf *key,
4288e93258fSBjoern A. Zeeb 			  bool inform_fw)
4298e93258fSBjoern A. Zeeb {
4308e93258fSBjoern A. Zeeb 	struct rtw89_cam_info *cam_info = &rtwdev->cam_info;
431*6d67aabdSBjoern A. Zeeb 	const struct rtw89_sec_cam_entry *sec_cam;
4328e93258fSBjoern A. Zeeb 	u8 sec_cam_idx;
433*6d67aabdSBjoern A. Zeeb 	int ret;
4348e93258fSBjoern A. Zeeb 
435*6d67aabdSBjoern A. Zeeb 	sec_cam_idx = key->hw_key_idx;
436*6d67aabdSBjoern A. Zeeb 	sec_cam = cam_info->sec_entries[sec_cam_idx];
4378e93258fSBjoern A. Zeeb 	if (!sec_cam)
4388e93258fSBjoern A. Zeeb 		return -EINVAL;
4398e93258fSBjoern A. Zeeb 
440*6d67aabdSBjoern A. Zeeb 	ret = rtw89_cam_detach_sec_cam(rtwdev, vif, sta, sec_cam, inform_fw);
4418e93258fSBjoern A. Zeeb 
4428e93258fSBjoern A. Zeeb 	/* clear valid bit in addr cam will disable sec cam,
4438e93258fSBjoern A. Zeeb 	 * so we don't need to send H2C command again
4448e93258fSBjoern A. Zeeb 	 */
445*6d67aabdSBjoern A. Zeeb 	cam_info->sec_entries[sec_cam_idx] = NULL;
4468e93258fSBjoern A. Zeeb 	clear_bit(sec_cam_idx, cam_info->sec_cam_map);
4478e93258fSBjoern A. Zeeb 	if (sec_cam->ext_key)
4488e93258fSBjoern A. Zeeb 		clear_bit(sec_cam_idx + 1, cam_info->sec_cam_map);
4498e93258fSBjoern A. Zeeb 
4508e93258fSBjoern A. Zeeb 	kfree(sec_cam);
4518e93258fSBjoern A. Zeeb 
4528e93258fSBjoern A. Zeeb 	return ret;
4538e93258fSBjoern A. Zeeb }
4548e93258fSBjoern A. Zeeb 
4558e93258fSBjoern A. Zeeb static void rtw89_cam_reset_key_iter(struct ieee80211_hw *hw,
4568e93258fSBjoern A. Zeeb 				     struct ieee80211_vif *vif,
4578e93258fSBjoern A. Zeeb 				     struct ieee80211_sta *sta,
4588e93258fSBjoern A. Zeeb 				     struct ieee80211_key_conf *key,
4598e93258fSBjoern A. Zeeb 				     void *data)
4608e93258fSBjoern A. Zeeb {
4618e93258fSBjoern A. Zeeb 	struct rtw89_dev *rtwdev = (struct rtw89_dev *)data;
4628e93258fSBjoern A. Zeeb 
4638e93258fSBjoern A. Zeeb 	rtw89_cam_sec_key_del(rtwdev, vif, sta, key, false);
4648e93258fSBjoern A. Zeeb }
4658e93258fSBjoern A. Zeeb 
4668e93258fSBjoern A. Zeeb void rtw89_cam_deinit_addr_cam(struct rtw89_dev *rtwdev,
4678e93258fSBjoern A. Zeeb 			       struct rtw89_addr_cam_entry *addr_cam)
4688e93258fSBjoern A. Zeeb {
4698e93258fSBjoern A. Zeeb 	struct rtw89_cam_info *cam_info = &rtwdev->cam_info;
4708e93258fSBjoern A. Zeeb 
4718e93258fSBjoern A. Zeeb 	addr_cam->valid = false;
4728e93258fSBjoern A. Zeeb 	clear_bit(addr_cam->addr_cam_idx, cam_info->addr_cam_map);
4738e93258fSBjoern A. Zeeb }
4748e93258fSBjoern A. Zeeb 
4758e93258fSBjoern A. Zeeb void rtw89_cam_deinit_bssid_cam(struct rtw89_dev *rtwdev,
4768e93258fSBjoern A. Zeeb 				struct rtw89_bssid_cam_entry *bssid_cam)
4778e93258fSBjoern A. Zeeb {
4788e93258fSBjoern A. Zeeb 	struct rtw89_cam_info *cam_info = &rtwdev->cam_info;
4798e93258fSBjoern A. Zeeb 
4808e93258fSBjoern A. Zeeb 	bssid_cam->valid = false;
4818e93258fSBjoern A. Zeeb 	clear_bit(bssid_cam->bssid_cam_idx, cam_info->bssid_cam_map);
4828e93258fSBjoern A. Zeeb }
4838e93258fSBjoern A. Zeeb 
4848e93258fSBjoern A. Zeeb void rtw89_cam_deinit(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
4858e93258fSBjoern A. Zeeb {
4868e93258fSBjoern A. Zeeb 	struct rtw89_addr_cam_entry *addr_cam = &rtwvif->addr_cam;
4878e93258fSBjoern A. Zeeb 	struct rtw89_bssid_cam_entry *bssid_cam = &rtwvif->bssid_cam;
4888e93258fSBjoern A. Zeeb 
4898e93258fSBjoern A. Zeeb 	rtw89_cam_deinit_addr_cam(rtwdev, addr_cam);
4908e93258fSBjoern A. Zeeb 	rtw89_cam_deinit_bssid_cam(rtwdev, bssid_cam);
4918e93258fSBjoern A. Zeeb }
4928e93258fSBjoern A. Zeeb 
4938e93258fSBjoern A. Zeeb void rtw89_cam_reset_keys(struct rtw89_dev *rtwdev)
4948e93258fSBjoern A. Zeeb {
4958e93258fSBjoern A. Zeeb 	rcu_read_lock();
4968e93258fSBjoern A. Zeeb 	ieee80211_iter_keys_rcu(rtwdev->hw, NULL, rtw89_cam_reset_key_iter, rtwdev);
4978e93258fSBjoern A. Zeeb 	rcu_read_unlock();
4988e93258fSBjoern A. Zeeb }
4998e93258fSBjoern A. Zeeb 
5008e93258fSBjoern A. Zeeb static int rtw89_cam_get_avail_addr_cam(struct rtw89_dev *rtwdev,
5018e93258fSBjoern A. Zeeb 					u8 *addr_cam_idx)
5028e93258fSBjoern A. Zeeb {
5038e93258fSBjoern A. Zeeb 	const struct rtw89_chip_info *chip = rtwdev->chip;
5048e93258fSBjoern A. Zeeb 	struct rtw89_cam_info *cam_info = &rtwdev->cam_info;
5058e93258fSBjoern A. Zeeb 	u8 addr_cam_num = chip->acam_num;
5068e93258fSBjoern A. Zeeb 	u8 idx;
5078e93258fSBjoern A. Zeeb 
5088e93258fSBjoern A. Zeeb 	idx = find_first_zero_bit(cam_info->addr_cam_map, addr_cam_num);
5098e93258fSBjoern A. Zeeb 	if (idx >= addr_cam_num)
5108e93258fSBjoern A. Zeeb 		return -EBUSY;
5118e93258fSBjoern A. Zeeb 
5128e93258fSBjoern A. Zeeb 	set_bit(idx, cam_info->addr_cam_map);
5138e93258fSBjoern A. Zeeb 	*addr_cam_idx = idx;
5148e93258fSBjoern A. Zeeb 
5158e93258fSBjoern A. Zeeb 	return 0;
5168e93258fSBjoern A. Zeeb }
5178e93258fSBjoern A. Zeeb 
518*6d67aabdSBjoern A. Zeeb static u8 rtw89_get_addr_cam_entry_size(struct rtw89_dev *rtwdev)
519*6d67aabdSBjoern A. Zeeb {
520*6d67aabdSBjoern A. Zeeb 	const struct rtw89_chip_info *chip = rtwdev->chip;
521*6d67aabdSBjoern A. Zeeb 
522*6d67aabdSBjoern A. Zeeb 	switch (chip->chip_id) {
523*6d67aabdSBjoern A. Zeeb 	case RTL8852A:
524*6d67aabdSBjoern A. Zeeb 	case RTL8852B:
525*6d67aabdSBjoern A. Zeeb 	case RTL8851B:
526*6d67aabdSBjoern A. Zeeb 	case RTL8852BT:
527*6d67aabdSBjoern A. Zeeb 		return ADDR_CAM_ENT_SIZE;
528*6d67aabdSBjoern A. Zeeb 	default:
529*6d67aabdSBjoern A. Zeeb 		return ADDR_CAM_ENT_SHORT_SIZE;
530*6d67aabdSBjoern A. Zeeb 	}
531*6d67aabdSBjoern A. Zeeb }
532*6d67aabdSBjoern A. Zeeb 
5338e93258fSBjoern A. Zeeb int rtw89_cam_init_addr_cam(struct rtw89_dev *rtwdev,
5348e93258fSBjoern A. Zeeb 			    struct rtw89_addr_cam_entry *addr_cam,
5358e93258fSBjoern A. Zeeb 			    const struct rtw89_bssid_cam_entry *bssid_cam)
5368e93258fSBjoern A. Zeeb {
5378e93258fSBjoern A. Zeeb 	u8 addr_cam_idx;
5388e93258fSBjoern A. Zeeb 	int i;
5398e93258fSBjoern A. Zeeb 	int ret;
5408e93258fSBjoern A. Zeeb 
5418e93258fSBjoern A. Zeeb 	if (unlikely(addr_cam->valid)) {
5428e93258fSBjoern A. Zeeb 		rtw89_debug(rtwdev, RTW89_DBG_FW,
5438e93258fSBjoern A. Zeeb 			    "addr cam is already valid; skip init\n");
5448e93258fSBjoern A. Zeeb 		return 0;
5458e93258fSBjoern A. Zeeb 	}
5468e93258fSBjoern A. Zeeb 
5478e93258fSBjoern A. Zeeb 	ret = rtw89_cam_get_avail_addr_cam(rtwdev, &addr_cam_idx);
5488e93258fSBjoern A. Zeeb 	if (ret) {
5498e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "failed to get available addr cam\n");
5508e93258fSBjoern A. Zeeb 		return ret;
5518e93258fSBjoern A. Zeeb 	}
5528e93258fSBjoern A. Zeeb 
5538e93258fSBjoern A. Zeeb 	addr_cam->addr_cam_idx = addr_cam_idx;
554*6d67aabdSBjoern A. Zeeb 	addr_cam->len = rtw89_get_addr_cam_entry_size(rtwdev);
5558e93258fSBjoern A. Zeeb 	addr_cam->offset = 0;
5568e93258fSBjoern A. Zeeb 	addr_cam->valid = true;
5578e93258fSBjoern A. Zeeb 	addr_cam->addr_mask = 0;
5588e93258fSBjoern A. Zeeb 	addr_cam->mask_sel = RTW89_NO_MSK;
5598e93258fSBjoern A. Zeeb 	addr_cam->sec_ent_mode = RTW89_ADDR_CAM_SEC_NORMAL;
5608e93258fSBjoern A. Zeeb 	bitmap_zero(addr_cam->sec_cam_map, RTW89_SEC_CAM_IN_ADDR_CAM);
5618e93258fSBjoern A. Zeeb 
5628e93258fSBjoern A. Zeeb 	for (i = 0; i < RTW89_SEC_CAM_IN_ADDR_CAM; i++) {
5638e93258fSBjoern A. Zeeb 		addr_cam->sec_ent_keyid[i] = 0;
5648e93258fSBjoern A. Zeeb 		addr_cam->sec_ent[i] = 0;
5658e93258fSBjoern A. Zeeb 	}
5668e93258fSBjoern A. Zeeb 
5678e93258fSBjoern A. Zeeb 	/* associate addr cam with bssid cam */
5688e93258fSBjoern A. Zeeb 	addr_cam->bssid_cam_idx = bssid_cam->bssid_cam_idx;
5698e93258fSBjoern A. Zeeb 
5708e93258fSBjoern A. Zeeb 	return 0;
5718e93258fSBjoern A. Zeeb }
5728e93258fSBjoern A. Zeeb 
5738e93258fSBjoern A. Zeeb static int rtw89_cam_get_avail_bssid_cam(struct rtw89_dev *rtwdev,
5748e93258fSBjoern A. Zeeb 					 u8 *bssid_cam_idx)
5758e93258fSBjoern A. Zeeb {
5768e93258fSBjoern A. Zeeb 	const struct rtw89_chip_info *chip = rtwdev->chip;
5778e93258fSBjoern A. Zeeb 	struct rtw89_cam_info *cam_info = &rtwdev->cam_info;
5788e93258fSBjoern A. Zeeb 	u8 bssid_cam_num = chip->bcam_num;
5798e93258fSBjoern A. Zeeb 	u8 idx;
5808e93258fSBjoern A. Zeeb 
5818e93258fSBjoern A. Zeeb 	idx = find_first_zero_bit(cam_info->bssid_cam_map, bssid_cam_num);
5828e93258fSBjoern A. Zeeb 	if (idx >= bssid_cam_num)
5838e93258fSBjoern A. Zeeb 		return -EBUSY;
5848e93258fSBjoern A. Zeeb 
5858e93258fSBjoern A. Zeeb 	set_bit(idx, cam_info->bssid_cam_map);
5868e93258fSBjoern A. Zeeb 	*bssid_cam_idx = idx;
5878e93258fSBjoern A. Zeeb 
5888e93258fSBjoern A. Zeeb 	return 0;
5898e93258fSBjoern A. Zeeb }
5908e93258fSBjoern A. Zeeb 
5918e93258fSBjoern A. Zeeb int rtw89_cam_init_bssid_cam(struct rtw89_dev *rtwdev,
5928e93258fSBjoern A. Zeeb 			     struct rtw89_vif *rtwvif,
5938e93258fSBjoern A. Zeeb 			     struct rtw89_bssid_cam_entry *bssid_cam,
5948e93258fSBjoern A. Zeeb 			     const u8 *bssid)
5958e93258fSBjoern A. Zeeb {
5968e93258fSBjoern A. Zeeb 	u8 bssid_cam_idx;
5978e93258fSBjoern A. Zeeb 	int ret;
5988e93258fSBjoern A. Zeeb 
5998e93258fSBjoern A. Zeeb 	if (unlikely(bssid_cam->valid)) {
6008e93258fSBjoern A. Zeeb 		rtw89_debug(rtwdev, RTW89_DBG_FW,
6018e93258fSBjoern A. Zeeb 			    "bssid cam is already valid; skip init\n");
6028e93258fSBjoern A. Zeeb 		return 0;
6038e93258fSBjoern A. Zeeb 	}
6048e93258fSBjoern A. Zeeb 
6058e93258fSBjoern A. Zeeb 	ret = rtw89_cam_get_avail_bssid_cam(rtwdev, &bssid_cam_idx);
6068e93258fSBjoern A. Zeeb 	if (ret) {
6078e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "failed to get available bssid cam\n");
6088e93258fSBjoern A. Zeeb 		return ret;
6098e93258fSBjoern A. Zeeb 	}
6108e93258fSBjoern A. Zeeb 
6118e93258fSBjoern A. Zeeb 	bssid_cam->bssid_cam_idx = bssid_cam_idx;
6128e93258fSBjoern A. Zeeb 	bssid_cam->phy_idx = rtwvif->phy_idx;
6138e93258fSBjoern A. Zeeb 	bssid_cam->len = BSSID_CAM_ENT_SIZE;
6148e93258fSBjoern A. Zeeb 	bssid_cam->offset = 0;
6158e93258fSBjoern A. Zeeb 	bssid_cam->valid = true;
6168e93258fSBjoern A. Zeeb 	ether_addr_copy(bssid_cam->bssid, bssid);
6178e93258fSBjoern A. Zeeb 
6188e93258fSBjoern A. Zeeb 	return 0;
6198e93258fSBjoern A. Zeeb }
6208e93258fSBjoern A. Zeeb 
6218e93258fSBjoern A. Zeeb void rtw89_cam_bssid_changed(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
6228e93258fSBjoern A. Zeeb {
6238e93258fSBjoern A. Zeeb 	struct rtw89_bssid_cam_entry *bssid_cam = &rtwvif->bssid_cam;
6248e93258fSBjoern A. Zeeb 
6258e93258fSBjoern A. Zeeb 	ether_addr_copy(bssid_cam->bssid, rtwvif->bssid);
6268e93258fSBjoern A. Zeeb }
6278e93258fSBjoern A. Zeeb 
6288e93258fSBjoern A. Zeeb int rtw89_cam_init(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
6298e93258fSBjoern A. Zeeb {
6308e93258fSBjoern A. Zeeb 	struct rtw89_addr_cam_entry *addr_cam = &rtwvif->addr_cam;
6318e93258fSBjoern A. Zeeb 	struct rtw89_bssid_cam_entry *bssid_cam = &rtwvif->bssid_cam;
6328e93258fSBjoern A. Zeeb 	int ret;
6338e93258fSBjoern A. Zeeb 
6348e93258fSBjoern A. Zeeb 	ret = rtw89_cam_init_bssid_cam(rtwdev, rtwvif, bssid_cam, rtwvif->bssid);
6358e93258fSBjoern A. Zeeb 	if (ret) {
6368e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "failed to init bssid cam\n");
6378e93258fSBjoern A. Zeeb 		return ret;
6388e93258fSBjoern A. Zeeb 	}
6398e93258fSBjoern A. Zeeb 
6408e93258fSBjoern A. Zeeb 	ret = rtw89_cam_init_addr_cam(rtwdev, addr_cam, bssid_cam);
6418e93258fSBjoern A. Zeeb 	if (ret) {
6428e93258fSBjoern A. Zeeb 		rtw89_err(rtwdev, "failed to init addr cam\n");
6438e93258fSBjoern A. Zeeb 		return ret;
6448e93258fSBjoern A. Zeeb 	}
6458e93258fSBjoern A. Zeeb 
6468e93258fSBjoern A. Zeeb 	return 0;
6478e93258fSBjoern A. Zeeb }
6488e93258fSBjoern A. Zeeb 
6498e93258fSBjoern A. Zeeb int rtw89_cam_fill_bssid_cam_info(struct rtw89_dev *rtwdev,
6508e93258fSBjoern A. Zeeb 				  struct rtw89_vif *rtwvif,
6518e93258fSBjoern A. Zeeb 				  struct rtw89_sta *rtwsta, u8 *cmd)
6528e93258fSBjoern A. Zeeb {
6538e93258fSBjoern A. Zeeb 	struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);
6548e93258fSBjoern A. Zeeb 	struct rtw89_bssid_cam_entry *bssid_cam = rtw89_get_bssid_cam_of(rtwvif, rtwsta);
6558e93258fSBjoern A. Zeeb 	u8 bss_color = vif->bss_conf.he_bss_color.color;
6568e93258fSBjoern A. Zeeb 	u8 bss_mask;
6578e93258fSBjoern A. Zeeb 
6588e93258fSBjoern A. Zeeb 	if (vif->bss_conf.nontransmitted)
6598e93258fSBjoern A. Zeeb 		bss_mask = RTW89_BSSID_MATCH_5_BYTES;
6608e93258fSBjoern A. Zeeb 	else
6618e93258fSBjoern A. Zeeb 		bss_mask = RTW89_BSSID_MATCH_ALL;
6628e93258fSBjoern A. Zeeb 
6638e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_BSSID_IDX(cmd, bssid_cam->bssid_cam_idx);
6648e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_BSSID_OFFSET(cmd, bssid_cam->offset);
6658e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_BSSID_LEN(cmd, bssid_cam->len);
6668e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_BSSID_VALID(cmd, bssid_cam->valid);
6678e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_BSSID_MASK(cmd, bss_mask);
6688e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_BSSID_BB_SEL(cmd, bssid_cam->phy_idx);
6698e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_BSSID_BSS_COLOR(cmd, bss_color);
6708e93258fSBjoern A. Zeeb 
6718e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_BSSID_BSSID0(cmd, bssid_cam->bssid[0]);
6728e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_BSSID_BSSID1(cmd, bssid_cam->bssid[1]);
6738e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_BSSID_BSSID2(cmd, bssid_cam->bssid[2]);
6748e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_BSSID_BSSID3(cmd, bssid_cam->bssid[3]);
6758e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_BSSID_BSSID4(cmd, bssid_cam->bssid[4]);
6768e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_BSSID_BSSID5(cmd, bssid_cam->bssid[5]);
6778e93258fSBjoern A. Zeeb 
6788e93258fSBjoern A. Zeeb 	return 0;
6798e93258fSBjoern A. Zeeb }
6808e93258fSBjoern A. Zeeb 
6818e93258fSBjoern A. Zeeb static u8 rtw89_cam_addr_hash(u8 start, const u8 *addr)
6828e93258fSBjoern A. Zeeb {
6838e93258fSBjoern A. Zeeb 	u8 hash = 0;
6848e93258fSBjoern A. Zeeb 	u8 i;
6858e93258fSBjoern A. Zeeb 
6868e93258fSBjoern A. Zeeb 	for (i = start; i < ETH_ALEN; i++)
6878e93258fSBjoern A. Zeeb 		hash ^= addr[i];
6888e93258fSBjoern A. Zeeb 
6898e93258fSBjoern A. Zeeb 	return hash;
6908e93258fSBjoern A. Zeeb }
6918e93258fSBjoern A. Zeeb 
6928e93258fSBjoern A. Zeeb void rtw89_cam_fill_addr_cam_info(struct rtw89_dev *rtwdev,
6938e93258fSBjoern A. Zeeb 				  struct rtw89_vif *rtwvif,
6948e93258fSBjoern A. Zeeb 				  struct rtw89_sta *rtwsta,
6958e93258fSBjoern A. Zeeb 				  const u8 *scan_mac_addr,
6968e93258fSBjoern A. Zeeb 				  u8 *cmd)
6978e93258fSBjoern A. Zeeb {
6988e93258fSBjoern A. Zeeb 	struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);
6998e93258fSBjoern A. Zeeb 	struct rtw89_addr_cam_entry *addr_cam = rtw89_get_addr_cam_of(rtwvif, rtwsta);
7008e93258fSBjoern A. Zeeb 	struct ieee80211_sta *sta = rtwsta_to_sta_safe(rtwsta);
7018e93258fSBjoern A. Zeeb 	const u8 *sma = scan_mac_addr ? scan_mac_addr : rtwvif->mac_addr;
7028e93258fSBjoern A. Zeeb 	u8 sma_hash, tma_hash, addr_msk_start;
7038e93258fSBjoern A. Zeeb 	u8 sma_start = 0;
7048e93258fSBjoern A. Zeeb 	u8 tma_start = 0;
7058e93258fSBjoern A. Zeeb 	u8 *tma = sta ? sta->addr : rtwvif->bssid;
7068e93258fSBjoern A. Zeeb 
7078e93258fSBjoern A. Zeeb 	if (addr_cam->addr_mask != 0) {
7088e93258fSBjoern A. Zeeb 		addr_msk_start = __ffs(addr_cam->addr_mask);
7098e93258fSBjoern A. Zeeb 		if (addr_cam->mask_sel == RTW89_SMA)
7108e93258fSBjoern A. Zeeb 			sma_start = addr_msk_start;
7118e93258fSBjoern A. Zeeb 		else if (addr_cam->mask_sel == RTW89_TMA)
7128e93258fSBjoern A. Zeeb 			tma_start = addr_msk_start;
7138e93258fSBjoern A. Zeeb 	}
7148e93258fSBjoern A. Zeeb 	sma_hash = rtw89_cam_addr_hash(sma_start, sma);
7158e93258fSBjoern A. Zeeb 	tma_hash = rtw89_cam_addr_hash(tma_start, tma);
7168e93258fSBjoern A. Zeeb 
7178e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_IDX(cmd, addr_cam->addr_cam_idx);
7188e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_OFFSET(cmd, addr_cam->offset);
7198e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_LEN(cmd, addr_cam->len);
7208e93258fSBjoern A. Zeeb 
7218e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_VALID(cmd, addr_cam->valid);
7228e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_NET_TYPE(cmd, rtwvif->net_type);
7238e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_BCN_HIT_COND(cmd, rtwvif->bcn_hit_cond);
7248e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_HIT_RULE(cmd, rtwvif->hit_rule);
7258e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_BB_SEL(cmd, rtwvif->phy_idx);
7268e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_ADDR_MASK(cmd, addr_cam->addr_mask);
7278e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_MASK_SEL(cmd, addr_cam->mask_sel);
7288e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_SMA_HASH(cmd, sma_hash);
7298e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_TMA_HASH(cmd, tma_hash);
7308e93258fSBjoern A. Zeeb 
7318e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_BSSID_CAM_IDX(cmd, addr_cam->bssid_cam_idx);
7328e93258fSBjoern A. Zeeb 
7338e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_SMA0(cmd, sma[0]);
7348e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_SMA1(cmd, sma[1]);
7358e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_SMA2(cmd, sma[2]);
7368e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_SMA3(cmd, sma[3]);
7378e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_SMA4(cmd, sma[4]);
7388e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_SMA5(cmd, sma[5]);
7398e93258fSBjoern A. Zeeb 
7408e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_TMA0(cmd, tma[0]);
7418e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_TMA1(cmd, tma[1]);
7428e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_TMA2(cmd, tma[2]);
7438e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_TMA3(cmd, tma[3]);
7448e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_TMA4(cmd, tma[4]);
7458e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_TMA5(cmd, tma[5]);
7468e93258fSBjoern A. Zeeb 
7478e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_PORT_INT(cmd, rtwvif->port);
7488e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_TSF_SYNC(cmd, rtwvif->port);
7498e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_TF_TRS(cmd, rtwvif->trigger);
7508e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_LSIG_TXOP(cmd, rtwvif->lsig_txop);
7518e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_TGT_IND(cmd, rtwvif->tgt_ind);
7528e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_FRM_TGT_IND(cmd, rtwvif->frm_tgt_ind);
7538e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_MACID(cmd, rtwsta ? rtwsta->mac_id : rtwvif->mac_id);
7548e93258fSBjoern A. Zeeb 	if (rtwvif->net_type == RTW89_NET_TYPE_INFRA)
7558e93258fSBjoern A. Zeeb 		FWCMD_SET_ADDR_AID12(cmd, vif->cfg.aid & 0xfff);
7568e93258fSBjoern A. Zeeb 	else if (rtwvif->net_type == RTW89_NET_TYPE_AP_MODE)
7578e93258fSBjoern A. Zeeb 		FWCMD_SET_ADDR_AID12(cmd, sta ? sta->aid & 0xfff : 0);
7588e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_WOL_PATTERN(cmd, rtwvif->wowlan_pattern);
7598e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_WOL_UC(cmd, rtwvif->wowlan_uc);
7608e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_WOL_MAGIC(cmd, rtwvif->wowlan_magic);
7618e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_WAPI(cmd, addr_cam->wapi);
7628e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_SEC_ENT_MODE(cmd, addr_cam->sec_ent_mode);
7638e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_SEC_ENT0_KEYID(cmd, addr_cam->sec_ent_keyid[0]);
7648e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_SEC_ENT1_KEYID(cmd, addr_cam->sec_ent_keyid[1]);
7658e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_SEC_ENT2_KEYID(cmd, addr_cam->sec_ent_keyid[2]);
7668e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_SEC_ENT3_KEYID(cmd, addr_cam->sec_ent_keyid[3]);
7678e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_SEC_ENT4_KEYID(cmd, addr_cam->sec_ent_keyid[4]);
7688e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_SEC_ENT5_KEYID(cmd, addr_cam->sec_ent_keyid[5]);
7698e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_SEC_ENT6_KEYID(cmd, addr_cam->sec_ent_keyid[6]);
7708e93258fSBjoern A. Zeeb 
7718e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_SEC_ENT_VALID(cmd, addr_cam->sec_cam_map[0] & 0xff);
7728e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_SEC_ENT0(cmd, addr_cam->sec_ent[0]);
7738e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_SEC_ENT1(cmd, addr_cam->sec_ent[1]);
7748e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_SEC_ENT2(cmd, addr_cam->sec_ent[2]);
7758e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_SEC_ENT3(cmd, addr_cam->sec_ent[3]);
7768e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_SEC_ENT4(cmd, addr_cam->sec_ent[4]);
7778e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_SEC_ENT5(cmd, addr_cam->sec_ent[5]);
7788e93258fSBjoern A. Zeeb 	FWCMD_SET_ADDR_SEC_ENT6(cmd, addr_cam->sec_ent[6]);
7798e93258fSBjoern A. Zeeb }
7808e93258fSBjoern A. Zeeb 
7818e93258fSBjoern A. Zeeb void rtw89_cam_fill_dctl_sec_cam_info_v1(struct rtw89_dev *rtwdev,
7828e93258fSBjoern A. Zeeb 					 struct rtw89_vif *rtwvif,
7838e93258fSBjoern A. Zeeb 					 struct rtw89_sta *rtwsta,
784*6d67aabdSBjoern A. Zeeb 					 struct rtw89_h2c_dctlinfo_ud_v1 *h2c)
7858e93258fSBjoern A. Zeeb {
7868e93258fSBjoern A. Zeeb 	struct rtw89_addr_cam_entry *addr_cam = rtw89_get_addr_cam_of(rtwvif, rtwsta);
787*6d67aabdSBjoern A. Zeeb 	struct rtw89_wow_param *rtw_wow = &rtwdev->wow;
788*6d67aabdSBjoern A. Zeeb 	u8 *ptk_tx_iv = rtw_wow->key_info.ptk_tx_iv;
7898e93258fSBjoern A. Zeeb 
790*6d67aabdSBjoern A. Zeeb 	h2c->c0 = le32_encode_bits(rtwsta ? rtwsta->mac_id : rtwvif->mac_id,
791*6d67aabdSBjoern A. Zeeb 				   DCTLINFO_V1_C0_MACID) |
792*6d67aabdSBjoern A. Zeeb 		  le32_encode_bits(1, DCTLINFO_V1_C0_OP);
7938e93258fSBjoern A. Zeeb 
794*6d67aabdSBjoern A. Zeeb 	h2c->w4 = le32_encode_bits(addr_cam->sec_ent_keyid[0],
795*6d67aabdSBjoern A. Zeeb 				   DCTLINFO_V1_W4_SEC_ENT0_KEYID) |
796*6d67aabdSBjoern A. Zeeb 		  le32_encode_bits(addr_cam->sec_ent_keyid[1],
797*6d67aabdSBjoern A. Zeeb 				   DCTLINFO_V1_W4_SEC_ENT1_KEYID) |
798*6d67aabdSBjoern A. Zeeb 		  le32_encode_bits(addr_cam->sec_ent_keyid[2],
799*6d67aabdSBjoern A. Zeeb 				   DCTLINFO_V1_W4_SEC_ENT2_KEYID) |
800*6d67aabdSBjoern A. Zeeb 		  le32_encode_bits(addr_cam->sec_ent_keyid[3],
801*6d67aabdSBjoern A. Zeeb 				   DCTLINFO_V1_W4_SEC_ENT3_KEYID) |
802*6d67aabdSBjoern A. Zeeb 		  le32_encode_bits(addr_cam->sec_ent_keyid[4],
803*6d67aabdSBjoern A. Zeeb 				   DCTLINFO_V1_W4_SEC_ENT4_KEYID) |
804*6d67aabdSBjoern A. Zeeb 		  le32_encode_bits(addr_cam->sec_ent_keyid[5],
805*6d67aabdSBjoern A. Zeeb 				   DCTLINFO_V1_W4_SEC_ENT5_KEYID) |
806*6d67aabdSBjoern A. Zeeb 		  le32_encode_bits(addr_cam->sec_ent_keyid[6],
807*6d67aabdSBjoern A. Zeeb 				   DCTLINFO_V1_W4_SEC_ENT6_KEYID);
808*6d67aabdSBjoern A. Zeeb 	h2c->m4 = cpu_to_le32(DCTLINFO_V1_W4_SEC_ENT0_KEYID |
809*6d67aabdSBjoern A. Zeeb 			      DCTLINFO_V1_W4_SEC_ENT1_KEYID |
810*6d67aabdSBjoern A. Zeeb 			      DCTLINFO_V1_W4_SEC_ENT2_KEYID |
811*6d67aabdSBjoern A. Zeeb 			      DCTLINFO_V1_W4_SEC_ENT3_KEYID |
812*6d67aabdSBjoern A. Zeeb 			      DCTLINFO_V1_W4_SEC_ENT4_KEYID |
813*6d67aabdSBjoern A. Zeeb 			      DCTLINFO_V1_W4_SEC_ENT5_KEYID |
814*6d67aabdSBjoern A. Zeeb 			      DCTLINFO_V1_W4_SEC_ENT6_KEYID);
8158e93258fSBjoern A. Zeeb 
816*6d67aabdSBjoern A. Zeeb 	h2c->w5 = le32_encode_bits(addr_cam->sec_cam_map[0] & 0xff,
817*6d67aabdSBjoern A. Zeeb 				   DCTLINFO_V1_W5_SEC_ENT_VALID) |
818*6d67aabdSBjoern A. Zeeb 		  le32_encode_bits(addr_cam->sec_ent[0],
819*6d67aabdSBjoern A. Zeeb 				   DCTLINFO_V1_W5_SEC_ENT0) |
820*6d67aabdSBjoern A. Zeeb 		  le32_encode_bits(addr_cam->sec_ent[1],
821*6d67aabdSBjoern A. Zeeb 				   DCTLINFO_V1_W5_SEC_ENT1) |
822*6d67aabdSBjoern A. Zeeb 		  le32_encode_bits(addr_cam->sec_ent[2],
823*6d67aabdSBjoern A. Zeeb 				   DCTLINFO_V1_W5_SEC_ENT2);
824*6d67aabdSBjoern A. Zeeb 	h2c->m5 = cpu_to_le32(DCTLINFO_V1_W5_SEC_ENT_VALID |
825*6d67aabdSBjoern A. Zeeb 			      DCTLINFO_V1_W5_SEC_ENT0      |
826*6d67aabdSBjoern A. Zeeb 			      DCTLINFO_V1_W5_SEC_ENT1      |
827*6d67aabdSBjoern A. Zeeb 			      DCTLINFO_V1_W5_SEC_ENT2);
828*6d67aabdSBjoern A. Zeeb 
829*6d67aabdSBjoern A. Zeeb 	h2c->w6 = le32_encode_bits(addr_cam->sec_ent[3],
830*6d67aabdSBjoern A. Zeeb 				   DCTLINFO_V1_W6_SEC_ENT3) |
831*6d67aabdSBjoern A. Zeeb 		  le32_encode_bits(addr_cam->sec_ent[4],
832*6d67aabdSBjoern A. Zeeb 				   DCTLINFO_V1_W6_SEC_ENT4) |
833*6d67aabdSBjoern A. Zeeb 		  le32_encode_bits(addr_cam->sec_ent[5],
834*6d67aabdSBjoern A. Zeeb 				   DCTLINFO_V1_W6_SEC_ENT5) |
835*6d67aabdSBjoern A. Zeeb 		  le32_encode_bits(addr_cam->sec_ent[6],
836*6d67aabdSBjoern A. Zeeb 				   DCTLINFO_V1_W6_SEC_ENT6);
837*6d67aabdSBjoern A. Zeeb 	h2c->m6 = cpu_to_le32(DCTLINFO_V1_W6_SEC_ENT3 |
838*6d67aabdSBjoern A. Zeeb 			      DCTLINFO_V1_W6_SEC_ENT4 |
839*6d67aabdSBjoern A. Zeeb 			      DCTLINFO_V1_W6_SEC_ENT5 |
840*6d67aabdSBjoern A. Zeeb 			      DCTLINFO_V1_W6_SEC_ENT6);
841*6d67aabdSBjoern A. Zeeb 
842*6d67aabdSBjoern A. Zeeb 	if (rtw_wow->ptk_alg) {
843*6d67aabdSBjoern A. Zeeb 		h2c->w0 = le32_encode_bits(ptk_tx_iv[0] | ptk_tx_iv[1] << 8,
844*6d67aabdSBjoern A. Zeeb 					   DCTLINFO_V1_W0_AES_IV_L);
845*6d67aabdSBjoern A. Zeeb 		h2c->m0 = cpu_to_le32(DCTLINFO_V1_W0_AES_IV_L);
846*6d67aabdSBjoern A. Zeeb 
847*6d67aabdSBjoern A. Zeeb 		h2c->w1 = le32_encode_bits(ptk_tx_iv[4]       |
848*6d67aabdSBjoern A. Zeeb 					   ptk_tx_iv[5] << 8  |
849*6d67aabdSBjoern A. Zeeb 					   ptk_tx_iv[6] << 16 |
850*6d67aabdSBjoern A. Zeeb 					   ptk_tx_iv[7] << 24,
851*6d67aabdSBjoern A. Zeeb 					   DCTLINFO_V1_W1_AES_IV_H);
852*6d67aabdSBjoern A. Zeeb 		h2c->m1 = cpu_to_le32(DCTLINFO_V1_W1_AES_IV_H);
853*6d67aabdSBjoern A. Zeeb 
854*6d67aabdSBjoern A. Zeeb 		h2c->w4 |= le32_encode_bits(rtw_wow->ptk_keyidx,
855*6d67aabdSBjoern A. Zeeb 					    DCTLINFO_V1_W4_SEC_KEY_ID);
856*6d67aabdSBjoern A. Zeeb 		h2c->m4 |= cpu_to_le32(DCTLINFO_V1_W4_SEC_KEY_ID);
857*6d67aabdSBjoern A. Zeeb 	}
858*6d67aabdSBjoern A. Zeeb }
859*6d67aabdSBjoern A. Zeeb 
860*6d67aabdSBjoern A. Zeeb void rtw89_cam_fill_dctl_sec_cam_info_v2(struct rtw89_dev *rtwdev,
861*6d67aabdSBjoern A. Zeeb 					 struct rtw89_vif *rtwvif,
862*6d67aabdSBjoern A. Zeeb 					 struct rtw89_sta *rtwsta,
863*6d67aabdSBjoern A. Zeeb 					 struct rtw89_h2c_dctlinfo_ud_v2 *h2c)
864*6d67aabdSBjoern A. Zeeb {
865*6d67aabdSBjoern A. Zeeb 	struct rtw89_addr_cam_entry *addr_cam = rtw89_get_addr_cam_of(rtwvif, rtwsta);
866*6d67aabdSBjoern A. Zeeb 	struct rtw89_wow_param *rtw_wow = &rtwdev->wow;
867*6d67aabdSBjoern A. Zeeb 	u8 *ptk_tx_iv = rtw_wow->key_info.ptk_tx_iv;
868*6d67aabdSBjoern A. Zeeb 
869*6d67aabdSBjoern A. Zeeb 	h2c->c0 = le32_encode_bits(rtwsta ? rtwsta->mac_id : rtwvif->mac_id,
870*6d67aabdSBjoern A. Zeeb 				   DCTLINFO_V2_C0_MACID) |
871*6d67aabdSBjoern A. Zeeb 		  le32_encode_bits(1, DCTLINFO_V2_C0_OP);
872*6d67aabdSBjoern A. Zeeb 
873*6d67aabdSBjoern A. Zeeb 	h2c->w4 = le32_encode_bits(addr_cam->sec_ent_keyid[0],
874*6d67aabdSBjoern A. Zeeb 				   DCTLINFO_V2_W4_SEC_ENT0_KEYID) |
875*6d67aabdSBjoern A. Zeeb 		  le32_encode_bits(addr_cam->sec_ent_keyid[1],
876*6d67aabdSBjoern A. Zeeb 				   DCTLINFO_V2_W4_SEC_ENT1_KEYID) |
877*6d67aabdSBjoern A. Zeeb 		  le32_encode_bits(addr_cam->sec_ent_keyid[2],
878*6d67aabdSBjoern A. Zeeb 				   DCTLINFO_V2_W4_SEC_ENT2_KEYID) |
879*6d67aabdSBjoern A. Zeeb 		  le32_encode_bits(addr_cam->sec_ent_keyid[3],
880*6d67aabdSBjoern A. Zeeb 				   DCTLINFO_V2_W4_SEC_ENT3_KEYID) |
881*6d67aabdSBjoern A. Zeeb 		  le32_encode_bits(addr_cam->sec_ent_keyid[4],
882*6d67aabdSBjoern A. Zeeb 				   DCTLINFO_V2_W4_SEC_ENT4_KEYID) |
883*6d67aabdSBjoern A. Zeeb 		  le32_encode_bits(addr_cam->sec_ent_keyid[5],
884*6d67aabdSBjoern A. Zeeb 				   DCTLINFO_V2_W4_SEC_ENT5_KEYID) |
885*6d67aabdSBjoern A. Zeeb 		  le32_encode_bits(addr_cam->sec_ent_keyid[6],
886*6d67aabdSBjoern A. Zeeb 				   DCTLINFO_V2_W4_SEC_ENT6_KEYID);
887*6d67aabdSBjoern A. Zeeb 	h2c->m4 = cpu_to_le32(DCTLINFO_V2_W4_SEC_ENT0_KEYID |
888*6d67aabdSBjoern A. Zeeb 			      DCTLINFO_V2_W4_SEC_ENT1_KEYID |
889*6d67aabdSBjoern A. Zeeb 			      DCTLINFO_V2_W4_SEC_ENT2_KEYID |
890*6d67aabdSBjoern A. Zeeb 			      DCTLINFO_V2_W4_SEC_ENT3_KEYID |
891*6d67aabdSBjoern A. Zeeb 			      DCTLINFO_V2_W4_SEC_ENT4_KEYID |
892*6d67aabdSBjoern A. Zeeb 			      DCTLINFO_V2_W4_SEC_ENT5_KEYID |
893*6d67aabdSBjoern A. Zeeb 			      DCTLINFO_V2_W4_SEC_ENT6_KEYID);
894*6d67aabdSBjoern A. Zeeb 
895*6d67aabdSBjoern A. Zeeb 	h2c->w5 = le32_encode_bits(addr_cam->sec_cam_map[0],
896*6d67aabdSBjoern A. Zeeb 				   DCTLINFO_V2_W5_SEC_ENT_VALID_V1) |
897*6d67aabdSBjoern A. Zeeb 		  le32_encode_bits(addr_cam->sec_ent[0],
898*6d67aabdSBjoern A. Zeeb 				   DCTLINFO_V2_W5_SEC_ENT0_V1);
899*6d67aabdSBjoern A. Zeeb 	h2c->m5 = cpu_to_le32(DCTLINFO_V2_W5_SEC_ENT_VALID_V1 |
900*6d67aabdSBjoern A. Zeeb 			      DCTLINFO_V2_W5_SEC_ENT0_V1);
901*6d67aabdSBjoern A. Zeeb 
902*6d67aabdSBjoern A. Zeeb 	h2c->w6 = le32_encode_bits(addr_cam->sec_ent[1],
903*6d67aabdSBjoern A. Zeeb 				   DCTLINFO_V2_W6_SEC_ENT1_V1) |
904*6d67aabdSBjoern A. Zeeb 		  le32_encode_bits(addr_cam->sec_ent[2],
905*6d67aabdSBjoern A. Zeeb 				   DCTLINFO_V2_W6_SEC_ENT2_V1) |
906*6d67aabdSBjoern A. Zeeb 		  le32_encode_bits(addr_cam->sec_ent[3],
907*6d67aabdSBjoern A. Zeeb 				   DCTLINFO_V2_W6_SEC_ENT3_V1) |
908*6d67aabdSBjoern A. Zeeb 		  le32_encode_bits(addr_cam->sec_ent[4],
909*6d67aabdSBjoern A. Zeeb 				   DCTLINFO_V2_W6_SEC_ENT4_V1);
910*6d67aabdSBjoern A. Zeeb 	h2c->m6 = cpu_to_le32(DCTLINFO_V2_W6_SEC_ENT1_V1 |
911*6d67aabdSBjoern A. Zeeb 			      DCTLINFO_V2_W6_SEC_ENT2_V1 |
912*6d67aabdSBjoern A. Zeeb 			      DCTLINFO_V2_W6_SEC_ENT3_V1 |
913*6d67aabdSBjoern A. Zeeb 			      DCTLINFO_V2_W6_SEC_ENT4_V1);
914*6d67aabdSBjoern A. Zeeb 
915*6d67aabdSBjoern A. Zeeb 	h2c->w7 = le32_encode_bits(addr_cam->sec_ent[5],
916*6d67aabdSBjoern A. Zeeb 				   DCTLINFO_V2_W7_SEC_ENT5_V1) |
917*6d67aabdSBjoern A. Zeeb 		  le32_encode_bits(addr_cam->sec_ent[6],
918*6d67aabdSBjoern A. Zeeb 				   DCTLINFO_V2_W7_SEC_ENT6_V1);
919*6d67aabdSBjoern A. Zeeb 	h2c->m7 = cpu_to_le32(DCTLINFO_V2_W7_SEC_ENT5_V1 |
920*6d67aabdSBjoern A. Zeeb 			      DCTLINFO_V2_W7_SEC_ENT6_V1);
921*6d67aabdSBjoern A. Zeeb 
922*6d67aabdSBjoern A. Zeeb 	if (rtw_wow->ptk_alg) {
923*6d67aabdSBjoern A. Zeeb 		h2c->w0 = le32_encode_bits(ptk_tx_iv[0] | ptk_tx_iv[1] << 8,
924*6d67aabdSBjoern A. Zeeb 					   DCTLINFO_V2_W0_AES_IV_L);
925*6d67aabdSBjoern A. Zeeb 		h2c->m0 = cpu_to_le32(DCTLINFO_V2_W0_AES_IV_L);
926*6d67aabdSBjoern A. Zeeb 
927*6d67aabdSBjoern A. Zeeb 		h2c->w1 = le32_encode_bits(ptk_tx_iv[4] |
928*6d67aabdSBjoern A. Zeeb 					   ptk_tx_iv[5] << 8 |
929*6d67aabdSBjoern A. Zeeb 					   ptk_tx_iv[6] << 16 |
930*6d67aabdSBjoern A. Zeeb 					   ptk_tx_iv[7] << 24,
931*6d67aabdSBjoern A. Zeeb 					   DCTLINFO_V2_W1_AES_IV_H);
932*6d67aabdSBjoern A. Zeeb 		h2c->m1 = cpu_to_le32(DCTLINFO_V2_W1_AES_IV_H);
933*6d67aabdSBjoern A. Zeeb 
934*6d67aabdSBjoern A. Zeeb 		h2c->w4 |= le32_encode_bits(rtw_wow->ptk_keyidx,
935*6d67aabdSBjoern A. Zeeb 					    DCTLINFO_V2_W4_SEC_KEY_ID);
936*6d67aabdSBjoern A. Zeeb 		h2c->m4 |= cpu_to_le32(DCTLINFO_V2_W4_SEC_KEY_ID);
937*6d67aabdSBjoern A. Zeeb 	}
9388e93258fSBjoern A. Zeeb }
939