|
@@ -2482,18 +2482,49 @@ bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry,
|
|
|
if (k->kv_len <= LEN_WEP104)
|
|
|
key4 &= 0xff;
|
|
|
|
|
|
+ /*
|
|
|
+ * Note: Key cache registers access special memory area that requires
|
|
|
+ * two 32-bit writes to actually update the values in the internal
|
|
|
+ * memory. Consequently, the exact order and pairs used here must be
|
|
|
+ * maintained.
|
|
|
+ */
|
|
|
+
|
|
|
if (keyType == AR_KEYTABLE_TYPE_TKIP && ATH9K_IS_MIC_ENABLED(ah)) {
|
|
|
u16 micentry = entry + 64;
|
|
|
|
|
|
+ /*
|
|
|
+ * Write inverted key[47:0] first to avoid Michael MIC errors
|
|
|
+ * on frames that could be sent or received at the same time.
|
|
|
+ * The correct key will be written in the end once everything
|
|
|
+ * else is ready.
|
|
|
+ */
|
|
|
REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), ~key0);
|
|
|
REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), ~key1);
|
|
|
+
|
|
|
+ /* Write key[95:48] */
|
|
|
REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2);
|
|
|
REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3);
|
|
|
+
|
|
|
+ /* Write key[127:96] and key type */
|
|
|
REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4);
|
|
|
REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType);
|
|
|
+
|
|
|
+ /* Write MAC address for the entry */
|
|
|
(void) ath9k_hw_keysetmac(ah, entry, mac);
|
|
|
|
|
|
if (ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA) {
|
|
|
+ /*
|
|
|
+ * TKIP uses two key cache entries:
|
|
|
+ * Michael MIC TX/RX keys in the same key cache entry
|
|
|
+ * (idx = main index + 64):
|
|
|
+ * key0 [31:0] = RX key [31:0]
|
|
|
+ * key1 [15:0] = TX key [31:16]
|
|
|
+ * key1 [31:16] = reserved
|
|
|
+ * key2 [31:0] = RX key [63:32]
|
|
|
+ * key3 [15:0] = TX key [15:0]
|
|
|
+ * key3 [31:16] = reserved
|
|
|
+ * key4 [31:0] = TX key [63:32]
|
|
|
+ */
|
|
|
u32 mic0, mic1, mic2, mic3, mic4;
|
|
|
|
|
|
mic0 = get_unaligned_le32(k->kv_mic + 0);
|
|
@@ -2501,45 +2532,84 @@ bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry,
|
|
|
mic1 = get_unaligned_le16(k->kv_txmic + 2) & 0xffff;
|
|
|
mic3 = get_unaligned_le16(k->kv_txmic + 0) & 0xffff;
|
|
|
mic4 = get_unaligned_le32(k->kv_txmic + 4);
|
|
|
+
|
|
|
+ /* Write RX[31:0] and TX[31:16] */
|
|
|
REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0);
|
|
|
REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), mic1);
|
|
|
+
|
|
|
+ /* Write RX[63:32] and TX[15:0] */
|
|
|
REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2);
|
|
|
REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), mic3);
|
|
|
+
|
|
|
+ /* Write TX[63:32] and keyType(reserved) */
|
|
|
REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), mic4);
|
|
|
REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry),
|
|
|
AR_KEYTABLE_TYPE_CLR);
|
|
|
|
|
|
} else {
|
|
|
+ /*
|
|
|
+ * TKIP uses four key cache entries (two for group
|
|
|
+ * keys):
|
|
|
+ * Michael MIC TX/RX keys are in different key cache
|
|
|
+ * entries (idx = main index + 64 for TX and
|
|
|
+ * main index + 32 + 96 for RX):
|
|
|
+ * key0 [31:0] = TX/RX MIC key [31:0]
|
|
|
+ * key1 [31:0] = reserved
|
|
|
+ * key2 [31:0] = TX/RX MIC key [63:32]
|
|
|
+ * key3 [31:0] = reserved
|
|
|
+ * key4 [31:0] = reserved
|
|
|
+ *
|
|
|
+ * Upper layer code will call this function separately
|
|
|
+ * for TX and RX keys when these registers offsets are
|
|
|
+ * used.
|
|
|
+ */
|
|
|
u32 mic0, mic2;
|
|
|
|
|
|
mic0 = get_unaligned_le32(k->kv_mic + 0);
|
|
|
mic2 = get_unaligned_le32(k->kv_mic + 4);
|
|
|
+
|
|
|
+ /* Write MIC key[31:0] */
|
|
|
REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0);
|
|
|
REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0);
|
|
|
+
|
|
|
+ /* Write MIC key[63:32] */
|
|
|
REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2);
|
|
|
REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0);
|
|
|
+
|
|
|
+ /* Write TX[63:32] and keyType(reserved) */
|
|
|
REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), 0);
|
|
|
REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry),
|
|
|
AR_KEYTABLE_TYPE_CLR);
|
|
|
}
|
|
|
+
|
|
|
+ /* MAC address registers are reserved for the MIC entry */
|
|
|
REG_WRITE(ah, AR_KEYTABLE_MAC0(micentry), 0);
|
|
|
REG_WRITE(ah, AR_KEYTABLE_MAC1(micentry), 0);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Write the correct (un-inverted) key[47:0] last to enable
|
|
|
+ * TKIP now that all other registers are set with correct
|
|
|
+ * values.
|
|
|
+ */
|
|
|
REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0);
|
|
|
REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1);
|
|
|
} else {
|
|
|
+ /* Write key[47:0] */
|
|
|
REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0);
|
|
|
REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1);
|
|
|
+
|
|
|
+ /* Write key[95:48] */
|
|
|
REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2);
|
|
|
REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3);
|
|
|
+
|
|
|
+ /* Write key[127:96] and key type */
|
|
|
REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4);
|
|
|
REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType);
|
|
|
|
|
|
+ /* Write MAC address for the entry */
|
|
|
(void) ath9k_hw_keysetmac(ah, entry, mac);
|
|
|
}
|
|
|
|
|
|
- if (ah->curchan == NULL)
|
|
|
- return true;
|
|
|
-
|
|
|
return true;
|
|
|
}
|
|
|
|