18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright (c) 2009 Atheros Communications Inc.
38c2ecf20Sopenharmony_ci * Copyright (c) 2010 Bruno Randolf <br1@einfach.org>
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Permission to use, copy, modify, and/or distribute this software for any
68c2ecf20Sopenharmony_ci * purpose with or without fee is hereby granted, provided that the above
78c2ecf20Sopenharmony_ci * copyright notice and this permission notice appear in all copies.
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
108c2ecf20Sopenharmony_ci * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
118c2ecf20Sopenharmony_ci * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
128c2ecf20Sopenharmony_ci * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
138c2ecf20Sopenharmony_ci * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
148c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
158c2ecf20Sopenharmony_ci * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
168c2ecf20Sopenharmony_ci */
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include <linux/export.h>
198c2ecf20Sopenharmony_ci#include <asm/unaligned.h>
208c2ecf20Sopenharmony_ci#include <net/mac80211.h>
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#include "ath.h"
238c2ecf20Sopenharmony_ci#include "reg.h"
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#define REG_READ			(common->ops->read)
268c2ecf20Sopenharmony_ci#define REG_WRITE(_ah, _reg, _val)	(common->ops->write)(_ah, _val, _reg)
278c2ecf20Sopenharmony_ci#define ENABLE_REGWRITE_BUFFER(_ah)			\
288c2ecf20Sopenharmony_ci	if (common->ops->enable_write_buffer)		\
298c2ecf20Sopenharmony_ci		common->ops->enable_write_buffer((_ah));
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci#define REGWRITE_BUFFER_FLUSH(_ah)			\
328c2ecf20Sopenharmony_ci	if (common->ops->write_flush)			\
338c2ecf20Sopenharmony_ci		common->ops->write_flush((_ah));
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci#define IEEE80211_WEP_NKID      4       /* number of key ids */
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci/************************/
398c2ecf20Sopenharmony_ci/* Key Cache Management */
408c2ecf20Sopenharmony_ci/************************/
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cibool ath_hw_keyreset(struct ath_common *common, u16 entry)
438c2ecf20Sopenharmony_ci{
448c2ecf20Sopenharmony_ci	u32 keyType;
458c2ecf20Sopenharmony_ci	void *ah = common->ah;
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	if (entry >= common->keymax) {
488c2ecf20Sopenharmony_ci		ath_err(common, "keyreset: keycache entry %u out of range\n",
498c2ecf20Sopenharmony_ci			entry);
508c2ecf20Sopenharmony_ci		return false;
518c2ecf20Sopenharmony_ci	}
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	keyType = REG_READ(ah, AR_KEYTABLE_TYPE(entry));
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	ENABLE_REGWRITE_BUFFER(ah);
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), 0);
588c2ecf20Sopenharmony_ci	REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), 0);
598c2ecf20Sopenharmony_ci	REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), 0);
608c2ecf20Sopenharmony_ci	REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), 0);
618c2ecf20Sopenharmony_ci	REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), 0);
628c2ecf20Sopenharmony_ci	REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), AR_KEYTABLE_TYPE_CLR);
638c2ecf20Sopenharmony_ci	REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), 0);
648c2ecf20Sopenharmony_ci	REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), 0);
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	if (keyType == AR_KEYTABLE_TYPE_TKIP) {
678c2ecf20Sopenharmony_ci		u16 micentry = entry + 64;
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci		REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), 0);
708c2ecf20Sopenharmony_ci		REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0);
718c2ecf20Sopenharmony_ci		REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), 0);
728c2ecf20Sopenharmony_ci		REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0);
738c2ecf20Sopenharmony_ci		if (common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED) {
748c2ecf20Sopenharmony_ci			REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), 0);
758c2ecf20Sopenharmony_ci			REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry),
768c2ecf20Sopenharmony_ci				  AR_KEYTABLE_TYPE_CLR);
778c2ecf20Sopenharmony_ci		}
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	}
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	REGWRITE_BUFFER_FLUSH(ah);
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	return true;
848c2ecf20Sopenharmony_ci}
858c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ath_hw_keyreset);
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_cibool ath_hw_keysetmac(struct ath_common *common, u16 entry, const u8 *mac)
888c2ecf20Sopenharmony_ci{
898c2ecf20Sopenharmony_ci	u32 macHi, macLo;
908c2ecf20Sopenharmony_ci	u32 unicast_flag = AR_KEYTABLE_VALID;
918c2ecf20Sopenharmony_ci	void *ah = common->ah;
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	if (entry >= common->keymax) {
948c2ecf20Sopenharmony_ci		ath_err(common, "keysetmac: keycache entry %u out of range\n",
958c2ecf20Sopenharmony_ci			entry);
968c2ecf20Sopenharmony_ci		return false;
978c2ecf20Sopenharmony_ci	}
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	if (mac != NULL) {
1008c2ecf20Sopenharmony_ci		/*
1018c2ecf20Sopenharmony_ci		 * AR_KEYTABLE_VALID indicates that the address is a unicast
1028c2ecf20Sopenharmony_ci		 * address, which must match the transmitter address for
1038c2ecf20Sopenharmony_ci		 * decrypting frames.
1048c2ecf20Sopenharmony_ci		 * Not setting this bit allows the hardware to use the key
1058c2ecf20Sopenharmony_ci		 * for multicast frame decryption.
1068c2ecf20Sopenharmony_ci		 */
1078c2ecf20Sopenharmony_ci		if (mac[0] & 0x01)
1088c2ecf20Sopenharmony_ci			unicast_flag = 0;
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci		macLo = get_unaligned_le32(mac);
1118c2ecf20Sopenharmony_ci		macHi = get_unaligned_le16(mac + 4);
1128c2ecf20Sopenharmony_ci		macLo >>= 1;
1138c2ecf20Sopenharmony_ci		macLo |= (macHi & 1) << 31;
1148c2ecf20Sopenharmony_ci		macHi >>= 1;
1158c2ecf20Sopenharmony_ci	} else {
1168c2ecf20Sopenharmony_ci		macLo = macHi = 0;
1178c2ecf20Sopenharmony_ci	}
1188c2ecf20Sopenharmony_ci	ENABLE_REGWRITE_BUFFER(ah);
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), macLo);
1218c2ecf20Sopenharmony_ci	REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), macHi | unicast_flag);
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	REGWRITE_BUFFER_FLUSH(ah);
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	return true;
1268c2ecf20Sopenharmony_ci}
1278c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ath_hw_keysetmac);
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_cistatic bool ath_hw_set_keycache_entry(struct ath_common *common, u16 entry,
1308c2ecf20Sopenharmony_ci				      const struct ath_keyval *k,
1318c2ecf20Sopenharmony_ci				      const u8 *mac)
1328c2ecf20Sopenharmony_ci{
1338c2ecf20Sopenharmony_ci	void *ah = common->ah;
1348c2ecf20Sopenharmony_ci	u32 key0, key1, key2, key3, key4;
1358c2ecf20Sopenharmony_ci	u32 keyType;
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	if (entry >= common->keymax) {
1388c2ecf20Sopenharmony_ci		ath_err(common, "set-entry: keycache entry %u out of range\n",
1398c2ecf20Sopenharmony_ci			entry);
1408c2ecf20Sopenharmony_ci		return false;
1418c2ecf20Sopenharmony_ci	}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	switch (k->kv_type) {
1448c2ecf20Sopenharmony_ci	case ATH_CIPHER_AES_OCB:
1458c2ecf20Sopenharmony_ci		keyType = AR_KEYTABLE_TYPE_AES;
1468c2ecf20Sopenharmony_ci		break;
1478c2ecf20Sopenharmony_ci	case ATH_CIPHER_AES_CCM:
1488c2ecf20Sopenharmony_ci		if (!(common->crypt_caps & ATH_CRYPT_CAP_CIPHER_AESCCM)) {
1498c2ecf20Sopenharmony_ci			ath_dbg(common, ANY,
1508c2ecf20Sopenharmony_ci				"AES-CCM not supported by this mac rev\n");
1518c2ecf20Sopenharmony_ci			return false;
1528c2ecf20Sopenharmony_ci		}
1538c2ecf20Sopenharmony_ci		keyType = AR_KEYTABLE_TYPE_CCM;
1548c2ecf20Sopenharmony_ci		break;
1558c2ecf20Sopenharmony_ci	case ATH_CIPHER_TKIP:
1568c2ecf20Sopenharmony_ci		keyType = AR_KEYTABLE_TYPE_TKIP;
1578c2ecf20Sopenharmony_ci		if (entry + 64 >= common->keymax) {
1588c2ecf20Sopenharmony_ci			ath_dbg(common, ANY,
1598c2ecf20Sopenharmony_ci				"entry %u inappropriate for TKIP\n", entry);
1608c2ecf20Sopenharmony_ci			return false;
1618c2ecf20Sopenharmony_ci		}
1628c2ecf20Sopenharmony_ci		break;
1638c2ecf20Sopenharmony_ci	case ATH_CIPHER_WEP:
1648c2ecf20Sopenharmony_ci		if (k->kv_len < WLAN_KEY_LEN_WEP40) {
1658c2ecf20Sopenharmony_ci			ath_dbg(common, ANY, "WEP key length %u too small\n",
1668c2ecf20Sopenharmony_ci				k->kv_len);
1678c2ecf20Sopenharmony_ci			return false;
1688c2ecf20Sopenharmony_ci		}
1698c2ecf20Sopenharmony_ci		if (k->kv_len <= WLAN_KEY_LEN_WEP40)
1708c2ecf20Sopenharmony_ci			keyType = AR_KEYTABLE_TYPE_40;
1718c2ecf20Sopenharmony_ci		else if (k->kv_len <= WLAN_KEY_LEN_WEP104)
1728c2ecf20Sopenharmony_ci			keyType = AR_KEYTABLE_TYPE_104;
1738c2ecf20Sopenharmony_ci		else
1748c2ecf20Sopenharmony_ci			keyType = AR_KEYTABLE_TYPE_128;
1758c2ecf20Sopenharmony_ci		break;
1768c2ecf20Sopenharmony_ci	case ATH_CIPHER_CLR:
1778c2ecf20Sopenharmony_ci		keyType = AR_KEYTABLE_TYPE_CLR;
1788c2ecf20Sopenharmony_ci		break;
1798c2ecf20Sopenharmony_ci	default:
1808c2ecf20Sopenharmony_ci		ath_err(common, "cipher %u not supported\n", k->kv_type);
1818c2ecf20Sopenharmony_ci		return false;
1828c2ecf20Sopenharmony_ci	}
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	key0 = get_unaligned_le32(k->kv_val + 0);
1858c2ecf20Sopenharmony_ci	key1 = get_unaligned_le16(k->kv_val + 4);
1868c2ecf20Sopenharmony_ci	key2 = get_unaligned_le32(k->kv_val + 6);
1878c2ecf20Sopenharmony_ci	key3 = get_unaligned_le16(k->kv_val + 10);
1888c2ecf20Sopenharmony_ci	key4 = get_unaligned_le32(k->kv_val + 12);
1898c2ecf20Sopenharmony_ci	if (k->kv_len <= WLAN_KEY_LEN_WEP104)
1908c2ecf20Sopenharmony_ci		key4 &= 0xff;
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	/*
1938c2ecf20Sopenharmony_ci	 * Note: Key cache registers access special memory area that requires
1948c2ecf20Sopenharmony_ci	 * two 32-bit writes to actually update the values in the internal
1958c2ecf20Sopenharmony_ci	 * memory. Consequently, the exact order and pairs used here must be
1968c2ecf20Sopenharmony_ci	 * maintained.
1978c2ecf20Sopenharmony_ci	 */
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	if (keyType == AR_KEYTABLE_TYPE_TKIP) {
2008c2ecf20Sopenharmony_ci		u16 micentry = entry + 64;
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci		/*
2038c2ecf20Sopenharmony_ci		 * Write inverted key[47:0] first to avoid Michael MIC errors
2048c2ecf20Sopenharmony_ci		 * on frames that could be sent or received at the same time.
2058c2ecf20Sopenharmony_ci		 * The correct key will be written in the end once everything
2068c2ecf20Sopenharmony_ci		 * else is ready.
2078c2ecf20Sopenharmony_ci		 */
2088c2ecf20Sopenharmony_ci		REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), ~key0);
2098c2ecf20Sopenharmony_ci		REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), ~key1);
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci		/* Write key[95:48] */
2128c2ecf20Sopenharmony_ci		REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2);
2138c2ecf20Sopenharmony_ci		REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3);
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci		/* Write key[127:96] and key type */
2168c2ecf20Sopenharmony_ci		REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4);
2178c2ecf20Sopenharmony_ci		REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType);
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci		/* Write MAC address for the entry */
2208c2ecf20Sopenharmony_ci		(void) ath_hw_keysetmac(common, entry, mac);
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci		if (common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED) {
2238c2ecf20Sopenharmony_ci			/*
2248c2ecf20Sopenharmony_ci			 * TKIP uses two key cache entries:
2258c2ecf20Sopenharmony_ci			 * Michael MIC TX/RX keys in the same key cache entry
2268c2ecf20Sopenharmony_ci			 * (idx = main index + 64):
2278c2ecf20Sopenharmony_ci			 * key0 [31:0] = RX key [31:0]
2288c2ecf20Sopenharmony_ci			 * key1 [15:0] = TX key [31:16]
2298c2ecf20Sopenharmony_ci			 * key1 [31:16] = reserved
2308c2ecf20Sopenharmony_ci			 * key2 [31:0] = RX key [63:32]
2318c2ecf20Sopenharmony_ci			 * key3 [15:0] = TX key [15:0]
2328c2ecf20Sopenharmony_ci			 * key3 [31:16] = reserved
2338c2ecf20Sopenharmony_ci			 * key4 [31:0] = TX key [63:32]
2348c2ecf20Sopenharmony_ci			 */
2358c2ecf20Sopenharmony_ci			u32 mic0, mic1, mic2, mic3, mic4;
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci			mic0 = get_unaligned_le32(k->kv_mic + 0);
2388c2ecf20Sopenharmony_ci			mic2 = get_unaligned_le32(k->kv_mic + 4);
2398c2ecf20Sopenharmony_ci			mic1 = get_unaligned_le16(k->kv_txmic + 2) & 0xffff;
2408c2ecf20Sopenharmony_ci			mic3 = get_unaligned_le16(k->kv_txmic + 0) & 0xffff;
2418c2ecf20Sopenharmony_ci			mic4 = get_unaligned_le32(k->kv_txmic + 4);
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci			ENABLE_REGWRITE_BUFFER(ah);
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci			/* Write RX[31:0] and TX[31:16] */
2468c2ecf20Sopenharmony_ci			REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0);
2478c2ecf20Sopenharmony_ci			REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), mic1);
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci			/* Write RX[63:32] and TX[15:0] */
2508c2ecf20Sopenharmony_ci			REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2);
2518c2ecf20Sopenharmony_ci			REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), mic3);
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci			/* Write TX[63:32] and keyType(reserved) */
2548c2ecf20Sopenharmony_ci			REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), mic4);
2558c2ecf20Sopenharmony_ci			REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry),
2568c2ecf20Sopenharmony_ci				  AR_KEYTABLE_TYPE_CLR);
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci			REGWRITE_BUFFER_FLUSH(ah);
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci		} else {
2618c2ecf20Sopenharmony_ci			/*
2628c2ecf20Sopenharmony_ci			 * TKIP uses four key cache entries (two for group
2638c2ecf20Sopenharmony_ci			 * keys):
2648c2ecf20Sopenharmony_ci			 * Michael MIC TX/RX keys are in different key cache
2658c2ecf20Sopenharmony_ci			 * entries (idx = main index + 64 for TX and
2668c2ecf20Sopenharmony_ci			 * main index + 32 + 96 for RX):
2678c2ecf20Sopenharmony_ci			 * key0 [31:0] = TX/RX MIC key [31:0]
2688c2ecf20Sopenharmony_ci			 * key1 [31:0] = reserved
2698c2ecf20Sopenharmony_ci			 * key2 [31:0] = TX/RX MIC key [63:32]
2708c2ecf20Sopenharmony_ci			 * key3 [31:0] = reserved
2718c2ecf20Sopenharmony_ci			 * key4 [31:0] = reserved
2728c2ecf20Sopenharmony_ci			 *
2738c2ecf20Sopenharmony_ci			 * Upper layer code will call this function separately
2748c2ecf20Sopenharmony_ci			 * for TX and RX keys when these registers offsets are
2758c2ecf20Sopenharmony_ci			 * used.
2768c2ecf20Sopenharmony_ci			 */
2778c2ecf20Sopenharmony_ci			u32 mic0, mic2;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci			mic0 = get_unaligned_le32(k->kv_mic + 0);
2808c2ecf20Sopenharmony_ci			mic2 = get_unaligned_le32(k->kv_mic + 4);
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci			ENABLE_REGWRITE_BUFFER(ah);
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci			/* Write MIC key[31:0] */
2858c2ecf20Sopenharmony_ci			REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0);
2868c2ecf20Sopenharmony_ci			REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0);
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci			/* Write MIC key[63:32] */
2898c2ecf20Sopenharmony_ci			REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2);
2908c2ecf20Sopenharmony_ci			REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0);
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci			/* Write TX[63:32] and keyType(reserved) */
2938c2ecf20Sopenharmony_ci			REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), 0);
2948c2ecf20Sopenharmony_ci			REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry),
2958c2ecf20Sopenharmony_ci				  AR_KEYTABLE_TYPE_CLR);
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci			REGWRITE_BUFFER_FLUSH(ah);
2988c2ecf20Sopenharmony_ci		}
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci		ENABLE_REGWRITE_BUFFER(ah);
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci		/* MAC address registers are reserved for the MIC entry */
3038c2ecf20Sopenharmony_ci		REG_WRITE(ah, AR_KEYTABLE_MAC0(micentry), 0);
3048c2ecf20Sopenharmony_ci		REG_WRITE(ah, AR_KEYTABLE_MAC1(micentry), 0);
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci		/*
3078c2ecf20Sopenharmony_ci		 * Write the correct (un-inverted) key[47:0] last to enable
3088c2ecf20Sopenharmony_ci		 * TKIP now that all other registers are set with correct
3098c2ecf20Sopenharmony_ci		 * values.
3108c2ecf20Sopenharmony_ci		 */
3118c2ecf20Sopenharmony_ci		REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0);
3128c2ecf20Sopenharmony_ci		REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1);
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci		REGWRITE_BUFFER_FLUSH(ah);
3158c2ecf20Sopenharmony_ci	} else {
3168c2ecf20Sopenharmony_ci		ENABLE_REGWRITE_BUFFER(ah);
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci		/* Write key[47:0] */
3198c2ecf20Sopenharmony_ci		REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0);
3208c2ecf20Sopenharmony_ci		REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1);
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci		/* Write key[95:48] */
3238c2ecf20Sopenharmony_ci		REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2);
3248c2ecf20Sopenharmony_ci		REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3);
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci		/* Write key[127:96] and key type */
3278c2ecf20Sopenharmony_ci		REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4);
3288c2ecf20Sopenharmony_ci		REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType);
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci		REGWRITE_BUFFER_FLUSH(ah);
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci		/* Write MAC address for the entry */
3338c2ecf20Sopenharmony_ci		(void) ath_hw_keysetmac(common, entry, mac);
3348c2ecf20Sopenharmony_ci	}
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	return true;
3378c2ecf20Sopenharmony_ci}
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_cistatic int ath_setkey_tkip(struct ath_common *common, u16 keyix, const u8 *key,
3408c2ecf20Sopenharmony_ci			   struct ath_keyval *hk, const u8 *addr,
3418c2ecf20Sopenharmony_ci			   bool authenticator)
3428c2ecf20Sopenharmony_ci{
3438c2ecf20Sopenharmony_ci	const u8 *key_rxmic;
3448c2ecf20Sopenharmony_ci	const u8 *key_txmic;
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	key_txmic = key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY;
3478c2ecf20Sopenharmony_ci	key_rxmic = key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY;
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	if (addr == NULL) {
3508c2ecf20Sopenharmony_ci		/*
3518c2ecf20Sopenharmony_ci		 * Group key installation - only two key cache entries are used
3528c2ecf20Sopenharmony_ci		 * regardless of splitmic capability since group key is only
3538c2ecf20Sopenharmony_ci		 * used either for TX or RX.
3548c2ecf20Sopenharmony_ci		 */
3558c2ecf20Sopenharmony_ci		if (authenticator) {
3568c2ecf20Sopenharmony_ci			memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic));
3578c2ecf20Sopenharmony_ci			memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_mic));
3588c2ecf20Sopenharmony_ci		} else {
3598c2ecf20Sopenharmony_ci			memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
3608c2ecf20Sopenharmony_ci			memcpy(hk->kv_txmic, key_rxmic, sizeof(hk->kv_mic));
3618c2ecf20Sopenharmony_ci		}
3628c2ecf20Sopenharmony_ci		return ath_hw_set_keycache_entry(common, keyix, hk, addr);
3638c2ecf20Sopenharmony_ci	}
3648c2ecf20Sopenharmony_ci	if (common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED) {
3658c2ecf20Sopenharmony_ci		/* TX and RX keys share the same key cache entry. */
3668c2ecf20Sopenharmony_ci		memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
3678c2ecf20Sopenharmony_ci		memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_txmic));
3688c2ecf20Sopenharmony_ci		return ath_hw_set_keycache_entry(common, keyix, hk, addr);
3698c2ecf20Sopenharmony_ci	}
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	/* Separate key cache entries for TX and RX */
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	/* TX key goes at first index, RX key at +32. */
3748c2ecf20Sopenharmony_ci	memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic));
3758c2ecf20Sopenharmony_ci	if (!ath_hw_set_keycache_entry(common, keyix, hk, NULL)) {
3768c2ecf20Sopenharmony_ci		/* TX MIC entry failed. No need to proceed further */
3778c2ecf20Sopenharmony_ci		ath_err(common, "Setting TX MIC Key Failed\n");
3788c2ecf20Sopenharmony_ci		return 0;
3798c2ecf20Sopenharmony_ci	}
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
3828c2ecf20Sopenharmony_ci	/* XXX delete tx key on failure? */
3838c2ecf20Sopenharmony_ci	return ath_hw_set_keycache_entry(common, keyix + 32, hk, addr);
3848c2ecf20Sopenharmony_ci}
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_cistatic int ath_reserve_key_cache_slot_tkip(struct ath_common *common)
3878c2ecf20Sopenharmony_ci{
3888c2ecf20Sopenharmony_ci	int i;
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	for (i = IEEE80211_WEP_NKID; i < common->keymax / 2; i++) {
3918c2ecf20Sopenharmony_ci		if (test_bit(i, common->keymap) ||
3928c2ecf20Sopenharmony_ci		    test_bit(i + 64, common->keymap))
3938c2ecf20Sopenharmony_ci			continue; /* At least one part of TKIP key allocated */
3948c2ecf20Sopenharmony_ci		if (!(common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED) &&
3958c2ecf20Sopenharmony_ci		    (test_bit(i + 32, common->keymap) ||
3968c2ecf20Sopenharmony_ci		     test_bit(i + 64 + 32, common->keymap)))
3978c2ecf20Sopenharmony_ci			continue; /* At least one part of TKIP key allocated */
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci		/* Found a free slot for a TKIP key */
4008c2ecf20Sopenharmony_ci		return i;
4018c2ecf20Sopenharmony_ci	}
4028c2ecf20Sopenharmony_ci	return -1;
4038c2ecf20Sopenharmony_ci}
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_cistatic int ath_reserve_key_cache_slot(struct ath_common *common,
4068c2ecf20Sopenharmony_ci				      u32 cipher)
4078c2ecf20Sopenharmony_ci{
4088c2ecf20Sopenharmony_ci	int i;
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	if (cipher == WLAN_CIPHER_SUITE_TKIP)
4118c2ecf20Sopenharmony_ci		return ath_reserve_key_cache_slot_tkip(common);
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci	/* First, try to find slots that would not be available for TKIP. */
4148c2ecf20Sopenharmony_ci	if (!(common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED)) {
4158c2ecf20Sopenharmony_ci		for (i = IEEE80211_WEP_NKID; i < common->keymax / 4; i++) {
4168c2ecf20Sopenharmony_ci			if (!test_bit(i, common->keymap) &&
4178c2ecf20Sopenharmony_ci			    (test_bit(i + 32, common->keymap) ||
4188c2ecf20Sopenharmony_ci			     test_bit(i + 64, common->keymap) ||
4198c2ecf20Sopenharmony_ci			     test_bit(i + 64 + 32, common->keymap)))
4208c2ecf20Sopenharmony_ci				return i;
4218c2ecf20Sopenharmony_ci			if (!test_bit(i + 32, common->keymap) &&
4228c2ecf20Sopenharmony_ci			    (test_bit(i, common->keymap) ||
4238c2ecf20Sopenharmony_ci			     test_bit(i + 64, common->keymap) ||
4248c2ecf20Sopenharmony_ci			     test_bit(i + 64 + 32, common->keymap)))
4258c2ecf20Sopenharmony_ci				return i + 32;
4268c2ecf20Sopenharmony_ci			if (!test_bit(i + 64, common->keymap) &&
4278c2ecf20Sopenharmony_ci			    (test_bit(i , common->keymap) ||
4288c2ecf20Sopenharmony_ci			     test_bit(i + 32, common->keymap) ||
4298c2ecf20Sopenharmony_ci			     test_bit(i + 64 + 32, common->keymap)))
4308c2ecf20Sopenharmony_ci				return i + 64;
4318c2ecf20Sopenharmony_ci			if (!test_bit(i + 64 + 32, common->keymap) &&
4328c2ecf20Sopenharmony_ci			    (test_bit(i, common->keymap) ||
4338c2ecf20Sopenharmony_ci			     test_bit(i + 32, common->keymap) ||
4348c2ecf20Sopenharmony_ci			     test_bit(i + 64, common->keymap)))
4358c2ecf20Sopenharmony_ci				return i + 64 + 32;
4368c2ecf20Sopenharmony_ci		}
4378c2ecf20Sopenharmony_ci	} else {
4388c2ecf20Sopenharmony_ci		for (i = IEEE80211_WEP_NKID; i < common->keymax / 2; i++) {
4398c2ecf20Sopenharmony_ci			if (!test_bit(i, common->keymap) &&
4408c2ecf20Sopenharmony_ci			    test_bit(i + 64, common->keymap))
4418c2ecf20Sopenharmony_ci				return i;
4428c2ecf20Sopenharmony_ci			if (test_bit(i, common->keymap) &&
4438c2ecf20Sopenharmony_ci			    !test_bit(i + 64, common->keymap))
4448c2ecf20Sopenharmony_ci				return i + 64;
4458c2ecf20Sopenharmony_ci		}
4468c2ecf20Sopenharmony_ci	}
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	/* No partially used TKIP slots, pick any available slot */
4498c2ecf20Sopenharmony_ci	for (i = IEEE80211_WEP_NKID; i < common->keymax; i++) {
4508c2ecf20Sopenharmony_ci		/* Do not allow slots that could be needed for TKIP group keys
4518c2ecf20Sopenharmony_ci		 * to be used. This limitation could be removed if we know that
4528c2ecf20Sopenharmony_ci		 * TKIP will not be used. */
4538c2ecf20Sopenharmony_ci		if (i >= 64 && i < 64 + IEEE80211_WEP_NKID)
4548c2ecf20Sopenharmony_ci			continue;
4558c2ecf20Sopenharmony_ci		if (!(common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED)) {
4568c2ecf20Sopenharmony_ci			if (i >= 32 && i < 32 + IEEE80211_WEP_NKID)
4578c2ecf20Sopenharmony_ci				continue;
4588c2ecf20Sopenharmony_ci			if (i >= 64 + 32 && i < 64 + 32 + IEEE80211_WEP_NKID)
4598c2ecf20Sopenharmony_ci				continue;
4608c2ecf20Sopenharmony_ci		}
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci		if (!test_bit(i, common->keymap))
4638c2ecf20Sopenharmony_ci			return i; /* Found a free slot for a key */
4648c2ecf20Sopenharmony_ci	}
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	/* No free slot found */
4678c2ecf20Sopenharmony_ci	return -1;
4688c2ecf20Sopenharmony_ci}
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci/*
4718c2ecf20Sopenharmony_ci * Configure encryption in the HW.
4728c2ecf20Sopenharmony_ci */
4738c2ecf20Sopenharmony_ciint ath_key_config(struct ath_common *common,
4748c2ecf20Sopenharmony_ci			  struct ieee80211_vif *vif,
4758c2ecf20Sopenharmony_ci			  struct ieee80211_sta *sta,
4768c2ecf20Sopenharmony_ci			  struct ieee80211_key_conf *key)
4778c2ecf20Sopenharmony_ci{
4788c2ecf20Sopenharmony_ci	struct ath_keyval hk;
4798c2ecf20Sopenharmony_ci	const u8 *mac = NULL;
4808c2ecf20Sopenharmony_ci	u8 gmac[ETH_ALEN];
4818c2ecf20Sopenharmony_ci	int ret = 0;
4828c2ecf20Sopenharmony_ci	int idx;
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci	memset(&hk, 0, sizeof(hk));
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	switch (key->cipher) {
4878c2ecf20Sopenharmony_ci	case 0:
4888c2ecf20Sopenharmony_ci		hk.kv_type = ATH_CIPHER_CLR;
4898c2ecf20Sopenharmony_ci		break;
4908c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_WEP40:
4918c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_WEP104:
4928c2ecf20Sopenharmony_ci		hk.kv_type = ATH_CIPHER_WEP;
4938c2ecf20Sopenharmony_ci		break;
4948c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_TKIP:
4958c2ecf20Sopenharmony_ci		hk.kv_type = ATH_CIPHER_TKIP;
4968c2ecf20Sopenharmony_ci		break;
4978c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_CCMP:
4988c2ecf20Sopenharmony_ci		hk.kv_type = ATH_CIPHER_AES_CCM;
4998c2ecf20Sopenharmony_ci		break;
5008c2ecf20Sopenharmony_ci	default:
5018c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
5028c2ecf20Sopenharmony_ci	}
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci	hk.kv_len = key->keylen;
5058c2ecf20Sopenharmony_ci	if (key->keylen)
5068c2ecf20Sopenharmony_ci		memcpy(&hk.kv_values, key->key, key->keylen);
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci	if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
5098c2ecf20Sopenharmony_ci		switch (vif->type) {
5108c2ecf20Sopenharmony_ci		case NL80211_IFTYPE_AP:
5118c2ecf20Sopenharmony_ci			memcpy(gmac, vif->addr, ETH_ALEN);
5128c2ecf20Sopenharmony_ci			gmac[0] |= 0x01;
5138c2ecf20Sopenharmony_ci			mac = gmac;
5148c2ecf20Sopenharmony_ci			idx = ath_reserve_key_cache_slot(common, key->cipher);
5158c2ecf20Sopenharmony_ci			break;
5168c2ecf20Sopenharmony_ci		case NL80211_IFTYPE_ADHOC:
5178c2ecf20Sopenharmony_ci			if (!sta) {
5188c2ecf20Sopenharmony_ci				idx = key->keyidx;
5198c2ecf20Sopenharmony_ci				break;
5208c2ecf20Sopenharmony_ci			}
5218c2ecf20Sopenharmony_ci			memcpy(gmac, sta->addr, ETH_ALEN);
5228c2ecf20Sopenharmony_ci			gmac[0] |= 0x01;
5238c2ecf20Sopenharmony_ci			mac = gmac;
5248c2ecf20Sopenharmony_ci			idx = ath_reserve_key_cache_slot(common, key->cipher);
5258c2ecf20Sopenharmony_ci			break;
5268c2ecf20Sopenharmony_ci		default:
5278c2ecf20Sopenharmony_ci			idx = key->keyidx;
5288c2ecf20Sopenharmony_ci			break;
5298c2ecf20Sopenharmony_ci		}
5308c2ecf20Sopenharmony_ci	} else if (key->keyidx) {
5318c2ecf20Sopenharmony_ci		if (WARN_ON(!sta))
5328c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
5338c2ecf20Sopenharmony_ci		mac = sta->addr;
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci		if (vif->type != NL80211_IFTYPE_AP) {
5368c2ecf20Sopenharmony_ci			/* Only keyidx 0 should be used with unicast key, but
5378c2ecf20Sopenharmony_ci			 * allow this for client mode for now. */
5388c2ecf20Sopenharmony_ci			idx = key->keyidx;
5398c2ecf20Sopenharmony_ci		} else
5408c2ecf20Sopenharmony_ci			return -EIO;
5418c2ecf20Sopenharmony_ci	} else {
5428c2ecf20Sopenharmony_ci		if (WARN_ON(!sta))
5438c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
5448c2ecf20Sopenharmony_ci		mac = sta->addr;
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci		idx = ath_reserve_key_cache_slot(common, key->cipher);
5478c2ecf20Sopenharmony_ci	}
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci	if (idx < 0)
5508c2ecf20Sopenharmony_ci		return -ENOSPC; /* no free key cache entries */
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	if (key->cipher == WLAN_CIPHER_SUITE_TKIP)
5538c2ecf20Sopenharmony_ci		ret = ath_setkey_tkip(common, idx, key->key, &hk, mac,
5548c2ecf20Sopenharmony_ci				      vif->type == NL80211_IFTYPE_AP);
5558c2ecf20Sopenharmony_ci	else
5568c2ecf20Sopenharmony_ci		ret = ath_hw_set_keycache_entry(common, idx, &hk, mac);
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_ci	if (!ret)
5598c2ecf20Sopenharmony_ci		return -EIO;
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci	set_bit(idx, common->keymap);
5628c2ecf20Sopenharmony_ci	if (key->cipher == WLAN_CIPHER_SUITE_CCMP)
5638c2ecf20Sopenharmony_ci		set_bit(idx, common->ccmp_keymap);
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	if (key->cipher == WLAN_CIPHER_SUITE_TKIP) {
5668c2ecf20Sopenharmony_ci		set_bit(idx + 64, common->keymap);
5678c2ecf20Sopenharmony_ci		set_bit(idx, common->tkip_keymap);
5688c2ecf20Sopenharmony_ci		set_bit(idx + 64, common->tkip_keymap);
5698c2ecf20Sopenharmony_ci		if (!(common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED)) {
5708c2ecf20Sopenharmony_ci			set_bit(idx + 32, common->keymap);
5718c2ecf20Sopenharmony_ci			set_bit(idx + 64 + 32, common->keymap);
5728c2ecf20Sopenharmony_ci			set_bit(idx + 32, common->tkip_keymap);
5738c2ecf20Sopenharmony_ci			set_bit(idx + 64 + 32, common->tkip_keymap);
5748c2ecf20Sopenharmony_ci		}
5758c2ecf20Sopenharmony_ci	}
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci	return idx;
5788c2ecf20Sopenharmony_ci}
5798c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ath_key_config);
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci/*
5828c2ecf20Sopenharmony_ci * Delete Key.
5838c2ecf20Sopenharmony_ci */
5848c2ecf20Sopenharmony_civoid ath_key_delete(struct ath_common *common, u8 hw_key_idx)
5858c2ecf20Sopenharmony_ci{
5868c2ecf20Sopenharmony_ci	/* Leave CCMP and TKIP (main key) configured to avoid disabling
5878c2ecf20Sopenharmony_ci	 * encryption for potentially pending frames already in a TXQ with the
5888c2ecf20Sopenharmony_ci	 * keyix pointing to this key entry. Instead, only clear the MAC address
5898c2ecf20Sopenharmony_ci	 * to prevent RX processing from using this key cache entry.
5908c2ecf20Sopenharmony_ci	 */
5918c2ecf20Sopenharmony_ci	if (test_bit(hw_key_idx, common->ccmp_keymap) ||
5928c2ecf20Sopenharmony_ci	    test_bit(hw_key_idx, common->tkip_keymap))
5938c2ecf20Sopenharmony_ci		ath_hw_keysetmac(common, hw_key_idx, NULL);
5948c2ecf20Sopenharmony_ci	else
5958c2ecf20Sopenharmony_ci		ath_hw_keyreset(common, hw_key_idx);
5968c2ecf20Sopenharmony_ci	if (hw_key_idx < IEEE80211_WEP_NKID)
5978c2ecf20Sopenharmony_ci		return;
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_ci	clear_bit(hw_key_idx, common->keymap);
6008c2ecf20Sopenharmony_ci	clear_bit(hw_key_idx, common->ccmp_keymap);
6018c2ecf20Sopenharmony_ci	if (!test_bit(hw_key_idx, common->tkip_keymap))
6028c2ecf20Sopenharmony_ci		return;
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_ci	clear_bit(hw_key_idx + 64, common->keymap);
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci	clear_bit(hw_key_idx, common->tkip_keymap);
6078c2ecf20Sopenharmony_ci	clear_bit(hw_key_idx + 64, common->tkip_keymap);
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci	if (!(common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED)) {
6108c2ecf20Sopenharmony_ci		ath_hw_keyreset(common, hw_key_idx + 32);
6118c2ecf20Sopenharmony_ci		clear_bit(hw_key_idx + 32, common->keymap);
6128c2ecf20Sopenharmony_ci		clear_bit(hw_key_idx + 64 + 32, common->keymap);
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci		clear_bit(hw_key_idx + 32, common->tkip_keymap);
6158c2ecf20Sopenharmony_ci		clear_bit(hw_key_idx + 64 + 32, common->tkip_keymap);
6168c2ecf20Sopenharmony_ci	}
6178c2ecf20Sopenharmony_ci}
6188c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ath_key_delete);
619