diff options
author | Jouni Malinen <jouni.malinen@atheros.com> | 2009-03-02 08:06:31 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-03-05 14:39:38 -0500 |
commit | 672903b329579ff43ae3d553cf55bd82041921c1 (patch) | |
tree | 50f06169a9563f45fd0630d7287c373421fcbebf /drivers/net/wireless/ath9k/hw.c | |
parent | e65c22633c14eabe9593a71a727f81544378b892 (diff) |
ath9k: Document keycache operations
There are number of small details about the keycache operations that
are very easy to miss (and forget), so better include detailed
comments in ath9k_hw_set_keycache_entry() to avoid having to figure
out this every time when having to touch this area.
Signed-off-by: Jouni Malinen <jouni.malinen@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath9k/hw.c')
-rw-r--r-- | drivers/net/wireless/ath9k/hw.c | 76 |
1 files changed, 73 insertions, 3 deletions
diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c index 2acbb84dc2ba..5672f43e58e2 100644 --- a/drivers/net/wireless/ath9k/hw.c +++ b/drivers/net/wireless/ath9k/hw.c | |||
@@ -2482,18 +2482,49 @@ bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry, | |||
2482 | if (k->kv_len <= LEN_WEP104) | 2482 | if (k->kv_len <= LEN_WEP104) |
2483 | key4 &= 0xff; | 2483 | key4 &= 0xff; |
2484 | 2484 | ||
2485 | /* | ||
2486 | * Note: Key cache registers access special memory area that requires | ||
2487 | * two 32-bit writes to actually update the values in the internal | ||
2488 | * memory. Consequently, the exact order and pairs used here must be | ||
2489 | * maintained. | ||
2490 | */ | ||
2491 | |||
2485 | if (keyType == AR_KEYTABLE_TYPE_TKIP && ATH9K_IS_MIC_ENABLED(ah)) { | 2492 | if (keyType == AR_KEYTABLE_TYPE_TKIP && ATH9K_IS_MIC_ENABLED(ah)) { |
2486 | u16 micentry = entry + 64; | 2493 | u16 micentry = entry + 64; |
2487 | 2494 | ||
2495 | /* | ||
2496 | * Write inverted key[47:0] first to avoid Michael MIC errors | ||
2497 | * on frames that could be sent or received at the same time. | ||
2498 | * The correct key will be written in the end once everything | ||
2499 | * else is ready. | ||
2500 | */ | ||
2488 | REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), ~key0); | 2501 | REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), ~key0); |
2489 | REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), ~key1); | 2502 | REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), ~key1); |
2503 | |||
2504 | /* Write key[95:48] */ | ||
2490 | REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2); | 2505 | REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2); |
2491 | REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3); | 2506 | REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3); |
2507 | |||
2508 | /* Write key[127:96] and key type */ | ||
2492 | REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4); | 2509 | REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4); |
2493 | REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType); | 2510 | REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType); |
2511 | |||
2512 | /* Write MAC address for the entry */ | ||
2494 | (void) ath9k_hw_keysetmac(ah, entry, mac); | 2513 | (void) ath9k_hw_keysetmac(ah, entry, mac); |
2495 | 2514 | ||
2496 | if (ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA) { | 2515 | if (ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA) { |
2516 | /* | ||
2517 | * TKIP uses two key cache entries: | ||
2518 | * Michael MIC TX/RX keys in the same key cache entry | ||
2519 | * (idx = main index + 64): | ||
2520 | * key0 [31:0] = RX key [31:0] | ||
2521 | * key1 [15:0] = TX key [31:16] | ||
2522 | * key1 [31:16] = reserved | ||
2523 | * key2 [31:0] = RX key [63:32] | ||
2524 | * key3 [15:0] = TX key [15:0] | ||
2525 | * key3 [31:16] = reserved | ||
2526 | * key4 [31:0] = TX key [63:32] | ||
2527 | */ | ||
2497 | u32 mic0, mic1, mic2, mic3, mic4; | 2528 | u32 mic0, mic1, mic2, mic3, mic4; |
2498 | 2529 | ||
2499 | mic0 = get_unaligned_le32(k->kv_mic + 0); | 2530 | mic0 = get_unaligned_le32(k->kv_mic + 0); |
@@ -2501,45 +2532,84 @@ bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry, | |||
2501 | mic1 = get_unaligned_le16(k->kv_txmic + 2) & 0xffff; | 2532 | mic1 = get_unaligned_le16(k->kv_txmic + 2) & 0xffff; |
2502 | mic3 = get_unaligned_le16(k->kv_txmic + 0) & 0xffff; | 2533 | mic3 = get_unaligned_le16(k->kv_txmic + 0) & 0xffff; |
2503 | mic4 = get_unaligned_le32(k->kv_txmic + 4); | 2534 | mic4 = get_unaligned_le32(k->kv_txmic + 4); |
2535 | |||
2536 | /* Write RX[31:0] and TX[31:16] */ | ||
2504 | REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0); | 2537 | REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0); |
2505 | REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), mic1); | 2538 | REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), mic1); |
2539 | |||
2540 | /* Write RX[63:32] and TX[15:0] */ | ||
2506 | REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2); | 2541 | REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2); |
2507 | REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), mic3); | 2542 | REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), mic3); |
2543 | |||
2544 | /* Write TX[63:32] and keyType(reserved) */ | ||
2508 | REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), mic4); | 2545 | REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), mic4); |
2509 | REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry), | 2546 | REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry), |
2510 | AR_KEYTABLE_TYPE_CLR); | 2547 | AR_KEYTABLE_TYPE_CLR); |
2511 | 2548 | ||
2512 | } else { | 2549 | } else { |
2550 | /* | ||
2551 | * TKIP uses four key cache entries (two for group | ||
2552 | * keys): | ||
2553 | * Michael MIC TX/RX keys are in different key cache | ||
2554 | * entries (idx = main index + 64 for TX and | ||
2555 | * main index + 32 + 96 for RX): | ||
2556 | * key0 [31:0] = TX/RX MIC key [31:0] | ||
2557 | * key1 [31:0] = reserved | ||
2558 | * key2 [31:0] = TX/RX MIC key [63:32] | ||
2559 | * key3 [31:0] = reserved | ||
2560 | * key4 [31:0] = reserved | ||
2561 | * | ||
2562 | * Upper layer code will call this function separately | ||
2563 | * for TX and RX keys when these registers offsets are | ||
2564 | * used. | ||
2565 | */ | ||
2513 | u32 mic0, mic2; | 2566 | u32 mic0, mic2; |
2514 | 2567 | ||
2515 | mic0 = get_unaligned_le32(k->kv_mic + 0); | 2568 | mic0 = get_unaligned_le32(k->kv_mic + 0); |
2516 | mic2 = get_unaligned_le32(k->kv_mic + 4); | 2569 | mic2 = get_unaligned_le32(k->kv_mic + 4); |
2570 | |||
2571 | /* Write MIC key[31:0] */ | ||
2517 | REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0); | 2572 | REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0); |
2518 | REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0); | 2573 | REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0); |
2574 | |||
2575 | /* Write MIC key[63:32] */ | ||
2519 | REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2); | 2576 | REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2); |
2520 | REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0); | 2577 | REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0); |
2578 | |||
2579 | /* Write TX[63:32] and keyType(reserved) */ | ||
2521 | REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), 0); | 2580 | REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), 0); |
2522 | REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry), | 2581 | REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry), |
2523 | AR_KEYTABLE_TYPE_CLR); | 2582 | AR_KEYTABLE_TYPE_CLR); |
2524 | } | 2583 | } |
2584 | |||
2585 | /* MAC address registers are reserved for the MIC entry */ | ||
2525 | REG_WRITE(ah, AR_KEYTABLE_MAC0(micentry), 0); | 2586 | REG_WRITE(ah, AR_KEYTABLE_MAC0(micentry), 0); |
2526 | REG_WRITE(ah, AR_KEYTABLE_MAC1(micentry), 0); | 2587 | REG_WRITE(ah, AR_KEYTABLE_MAC1(micentry), 0); |
2588 | |||
2589 | /* | ||
2590 | * Write the correct (un-inverted) key[47:0] last to enable | ||
2591 | * TKIP now that all other registers are set with correct | ||
2592 | * values. | ||
2593 | */ | ||
2527 | REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0); | 2594 | REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0); |
2528 | REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1); | 2595 | REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1); |
2529 | } else { | 2596 | } else { |
2597 | /* Write key[47:0] */ | ||
2530 | REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0); | 2598 | REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0); |
2531 | REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1); | 2599 | REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1); |
2600 | |||
2601 | /* Write key[95:48] */ | ||
2532 | REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2); | 2602 | REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2); |
2533 | REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3); | 2603 | REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3); |
2604 | |||
2605 | /* Write key[127:96] and key type */ | ||
2534 | REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4); | 2606 | REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4); |
2535 | REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType); | 2607 | REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType); |
2536 | 2608 | ||
2609 | /* Write MAC address for the entry */ | ||
2537 | (void) ath9k_hw_keysetmac(ah, entry, mac); | 2610 | (void) ath9k_hw_keysetmac(ah, entry, mac); |
2538 | } | 2611 | } |
2539 | 2612 | ||
2540 | if (ah->curchan == NULL) | ||
2541 | return true; | ||
2542 | |||
2543 | return true; | 2613 | return true; |
2544 | } | 2614 | } |
2545 | 2615 | ||