aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath5k/pcu.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/ath5k/pcu.c')
-rw-r--r--drivers/net/wireless/ath5k/pcu.c233
1 files changed, 187 insertions, 46 deletions
diff --git a/drivers/net/wireless/ath5k/pcu.c b/drivers/net/wireless/ath5k/pcu.c
index a47df9a24aa1..0cac05c6a9ce 100644
--- a/drivers/net/wireless/ath5k/pcu.c
+++ b/drivers/net/wireless/ath5k/pcu.c
@@ -46,34 +46,45 @@ int ath5k_hw_set_opmode(struct ath5k_hw *ah)
46{ 46{
47 u32 pcu_reg, beacon_reg, low_id, high_id; 47 u32 pcu_reg, beacon_reg, low_id, high_id;
48 48
49 pcu_reg = 0; 49
50 /* Preserve rest settings */
51 pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000;
52 pcu_reg &= ~(AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_AP
53 | AR5K_STA_ID1_KEYSRCH_MODE
54 | (ah->ah_version == AR5K_AR5210 ?
55 (AR5K_STA_ID1_PWR_SV | AR5K_STA_ID1_NO_PSPOLL) : 0));
56
50 beacon_reg = 0; 57 beacon_reg = 0;
51 58
52 ATH5K_TRACE(ah->ah_sc); 59 ATH5K_TRACE(ah->ah_sc);
53 60
54 switch (ah->ah_op_mode) { 61 switch (ah->ah_op_mode) {
55 case NL80211_IFTYPE_ADHOC: 62 case NL80211_IFTYPE_ADHOC:
56 pcu_reg |= AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_DESC_ANTENNA | 63 pcu_reg |= AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_KEYSRCH_MODE;
57 (ah->ah_version == AR5K_AR5210 ?
58 AR5K_STA_ID1_NO_PSPOLL : 0);
59 beacon_reg |= AR5K_BCR_ADHOC; 64 beacon_reg |= AR5K_BCR_ADHOC;
65 if (ah->ah_version == AR5K_AR5210)
66 pcu_reg |= AR5K_STA_ID1_NO_PSPOLL;
67 else
68 AR5K_REG_DISABLE_BITS(ah, AR5K_CFG, AR5K_CFG_ADHOC);
60 break; 69 break;
61 70
62 case NL80211_IFTYPE_AP: 71 case NL80211_IFTYPE_AP:
63 case NL80211_IFTYPE_MESH_POINT: 72 case NL80211_IFTYPE_MESH_POINT:
64 pcu_reg |= AR5K_STA_ID1_AP | AR5K_STA_ID1_RTS_DEF_ANTENNA | 73 pcu_reg |= AR5K_STA_ID1_AP | AR5K_STA_ID1_KEYSRCH_MODE;
65 (ah->ah_version == AR5K_AR5210 ?
66 AR5K_STA_ID1_NO_PSPOLL : 0);
67 beacon_reg |= AR5K_BCR_AP; 74 beacon_reg |= AR5K_BCR_AP;
75 if (ah->ah_version == AR5K_AR5210)
76 pcu_reg |= AR5K_STA_ID1_NO_PSPOLL;
77 else
78 AR5K_REG_ENABLE_BITS(ah, AR5K_CFG, AR5K_CFG_ADHOC);
68 break; 79 break;
69 80
70 case NL80211_IFTYPE_STATION: 81 case NL80211_IFTYPE_STATION:
71 pcu_reg |= AR5K_STA_ID1_DEFAULT_ANTENNA | 82 pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE
72 (ah->ah_version == AR5K_AR5210 ? 83 | (ah->ah_version == AR5K_AR5210 ?
73 AR5K_STA_ID1_PWR_SV : 0); 84 AR5K_STA_ID1_PWR_SV : 0);
74 case NL80211_IFTYPE_MONITOR: 85 case NL80211_IFTYPE_MONITOR:
75 pcu_reg |= AR5K_STA_ID1_DEFAULT_ANTENNA | 86 pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE
76 (ah->ah_version == AR5K_AR5210 ? 87 | (ah->ah_version == AR5K_AR5210 ?
77 AR5K_STA_ID1_NO_PSPOLL : 0); 88 AR5K_STA_ID1_NO_PSPOLL : 0);
78 break; 89 break;
79 90
@@ -130,6 +141,8 @@ void ath5k_hw_update_mib_counters(struct ath5k_hw *ah,
130 ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RXCLR); 141 ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RXCLR);
131 ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_CYCLE); 142 ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_CYCLE);
132 } 143 }
144
145 /* TODO: Handle ANI stats */
133} 146}
134 147
135/** 148/**
@@ -258,16 +271,19 @@ void ath5k_hw_get_lladdr(struct ath5k_hw *ah, u8 *mac)
258int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac) 271int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac)
259{ 272{
260 u32 low_id, high_id; 273 u32 low_id, high_id;
274 u32 pcu_reg;
261 275
262 ATH5K_TRACE(ah->ah_sc); 276 ATH5K_TRACE(ah->ah_sc);
263 /* Set new station ID */ 277 /* Set new station ID */
264 memcpy(ah->ah_sta_id, mac, ETH_ALEN); 278 memcpy(ah->ah_sta_id, mac, ETH_ALEN);
265 279
280 pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000;
281
266 low_id = AR5K_LOW_ID(mac); 282 low_id = AR5K_LOW_ID(mac);
267 high_id = AR5K_HIGH_ID(mac); 283 high_id = AR5K_HIGH_ID(mac);
268 284
269 ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0); 285 ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0);
270 ath5k_hw_reg_write(ah, high_id, AR5K_STA_ID1); 286 ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1);
271 287
272 return 0; 288 return 0;
273} 289}
@@ -290,8 +306,10 @@ void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id)
290 * Set simple BSSID mask on 5212 306 * Set simple BSSID mask on 5212
291 */ 307 */
292 if (ah->ah_version == AR5K_AR5212) { 308 if (ah->ah_version == AR5K_AR5212) {
293 ath5k_hw_reg_write(ah, 0xffffffff, AR5K_BSS_IDM0); 309 ath5k_hw_reg_write(ah, AR5K_LOW_ID(ah->ah_bssid_mask),
294 ath5k_hw_reg_write(ah, 0xffffffff, AR5K_BSS_IDM1); 310 AR5K_BSS_IDM0);
311 ath5k_hw_reg_write(ah, AR5K_HIGH_ID(ah->ah_bssid_mask),
312 AR5K_BSS_IDM1);
295 } 313 }
296 314
297 /* 315 /*
@@ -415,6 +433,9 @@ int ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask)
415 u32 low_id, high_id; 433 u32 low_id, high_id;
416 ATH5K_TRACE(ah->ah_sc); 434 ATH5K_TRACE(ah->ah_sc);
417 435
436 /* Cache bssid mask so that we can restore it
437 * on reset */
438 memcpy(ah->ah_bssid_mask, mask, ETH_ALEN);
418 if (ah->ah_version == AR5K_AR5212) { 439 if (ah->ah_version == AR5K_AR5212) {
419 low_id = AR5K_LOW_ID(mask); 440 low_id = AR5K_LOW_ID(mask);
420 high_id = AR5K_HIGH_ID(mask); 441 high_id = AR5K_HIGH_ID(mask);
@@ -576,7 +597,7 @@ void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter)
576 filter |= AR5K_RX_FILTER_PROM; 597 filter |= AR5K_RX_FILTER_PROM;
577 } 598 }
578 599
579 /*Zero length DMA*/ 600 /*Zero length DMA (phy error reporting) */
580 if (data) 601 if (data)
581 AR5K_REG_ENABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA); 602 AR5K_REG_ENABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA);
582 else 603 else
@@ -661,7 +682,12 @@ void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval)
661 * Set the additional timers by mode 682 * Set the additional timers by mode
662 */ 683 */
663 switch (ah->ah_op_mode) { 684 switch (ah->ah_op_mode) {
685 case NL80211_IFTYPE_MONITOR:
664 case NL80211_IFTYPE_STATION: 686 case NL80211_IFTYPE_STATION:
687 /* In STA mode timer1 is used as next wakeup
688 * timer and timer2 as next CFP duration start
689 * timer. Both in 1/8TUs. */
690 /* TODO: PCF handling */
665 if (ah->ah_version == AR5K_AR5210) { 691 if (ah->ah_version == AR5K_AR5210) {
666 timer1 = 0xffffffff; 692 timer1 = 0xffffffff;
667 timer2 = 0xffffffff; 693 timer2 = 0xffffffff;
@@ -669,27 +695,60 @@ void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval)
669 timer1 = 0x0000ffff; 695 timer1 = 0x0000ffff;
670 timer2 = 0x0007ffff; 696 timer2 = 0x0007ffff;
671 } 697 }
698 /* Mark associated AP as PCF incapable for now */
699 AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, AR5K_STA_ID1_PCF);
672 break; 700 break;
673 701 case NL80211_IFTYPE_ADHOC:
702 AR5K_REG_ENABLE_BITS(ah, AR5K_TXCFG, AR5K_TXCFG_ADHOC_BCN_ATIM);
674 default: 703 default:
704 /* On non-STA modes timer1 is used as next DMA
705 * beacon alert (DBA) timer and timer2 as next
706 * software beacon alert. Both in 1/8TUs. */
675 timer1 = (next_beacon - AR5K_TUNE_DMA_BEACON_RESP) << 3; 707 timer1 = (next_beacon - AR5K_TUNE_DMA_BEACON_RESP) << 3;
676 timer2 = (next_beacon - AR5K_TUNE_SW_BEACON_RESP) << 3; 708 timer2 = (next_beacon - AR5K_TUNE_SW_BEACON_RESP) << 3;
709 break;
677 } 710 }
678 711
712 /* Timer3 marks the end of our ATIM window
713 * a zero length window is not allowed because
714 * we 'll get no beacons */
679 timer3 = next_beacon + (ah->ah_atim_window ? ah->ah_atim_window : 1); 715 timer3 = next_beacon + (ah->ah_atim_window ? ah->ah_atim_window : 1);
680 716
681 /* 717 /*
682 * Set the beacon register and enable all timers. 718 * Set the beacon register and enable all timers.
683 * (next beacon, DMA beacon, software beacon, ATIM window time)
684 */ 719 */
685 ath5k_hw_reg_write(ah, next_beacon, AR5K_TIMER0); 720 /* When in AP mode zero timer0 to start TSF */
721 if (ah->ah_op_mode == NL80211_IFTYPE_AP)
722 ath5k_hw_reg_write(ah, 0, AR5K_TIMER0);
723 else
724 ath5k_hw_reg_write(ah, next_beacon, AR5K_TIMER0);
686 ath5k_hw_reg_write(ah, timer1, AR5K_TIMER1); 725 ath5k_hw_reg_write(ah, timer1, AR5K_TIMER1);
687 ath5k_hw_reg_write(ah, timer2, AR5K_TIMER2); 726 ath5k_hw_reg_write(ah, timer2, AR5K_TIMER2);
688 ath5k_hw_reg_write(ah, timer3, AR5K_TIMER3); 727 ath5k_hw_reg_write(ah, timer3, AR5K_TIMER3);
689 728
729 /* Force a TSF reset if requested and enable beacons */
730 if (interval & AR5K_BEACON_RESET_TSF)
731 ath5k_hw_reset_tsf(ah);
732
690 ath5k_hw_reg_write(ah, interval & (AR5K_BEACON_PERIOD | 733 ath5k_hw_reg_write(ah, interval & (AR5K_BEACON_PERIOD |
691 AR5K_BEACON_RESET_TSF | AR5K_BEACON_ENABLE), 734 AR5K_BEACON_ENABLE),
692 AR5K_BEACON); 735 AR5K_BEACON);
736
737 /* Flush any pending BMISS interrupts on ISR by
738 * performing a clear-on-write operation on PISR
739 * register for the BMISS bit (writing a bit on
740 * ISR togles a reset for that bit and leaves
741 * the rest bits intact) */
742 if (ah->ah_version == AR5K_AR5210)
743 ath5k_hw_reg_write(ah, AR5K_ISR_BMISS, AR5K_ISR);
744 else
745 ath5k_hw_reg_write(ah, AR5K_ISR_BMISS, AR5K_PISR);
746
747 /* TODO: Set enchanced sleep registers on AR5212
748 * based on vif->bss_conf params, until then
749 * disable power save reporting.*/
750 AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, AR5K_STA_ID1_PWR_SV);
751
693} 752}
694 753
695#if 0 754#if 0
@@ -899,14 +958,26 @@ int ath5k_hw_beaconq_finish(struct ath5k_hw *ah, unsigned long phys_addr)
899 */ 958 */
900int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry) 959int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry)
901{ 960{
902 unsigned int i; 961 unsigned int i, type;
962 u16 micentry = entry + AR5K_KEYTABLE_MIC_OFFSET;
903 963
904 ATH5K_TRACE(ah->ah_sc); 964 ATH5K_TRACE(ah->ah_sc);
905 AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE); 965 AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE);
906 966
967 type = ath5k_hw_reg_read(ah, AR5K_KEYTABLE_TYPE(entry));
968
907 for (i = 0; i < AR5K_KEYCACHE_SIZE; i++) 969 for (i = 0; i < AR5K_KEYCACHE_SIZE; i++)
908 ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_OFF(entry, i)); 970 ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_OFF(entry, i));
909 971
972 /* Reset associated MIC entry if TKIP
973 * is enabled located at offset (entry + 64) */
974 if (type == AR5K_KEYTABLE_TYPE_TKIP) {
975 AR5K_ASSERT_ENTRY(micentry, AR5K_KEYTABLE_SIZE);
976 for (i = 0; i < AR5K_KEYCACHE_SIZE / 2 ; i++)
977 ath5k_hw_reg_write(ah, 0,
978 AR5K_KEYTABLE_OFF(micentry, i));
979 }
980
910 /* 981 /*
911 * Set NULL encryption on AR5212+ 982 * Set NULL encryption on AR5212+
912 * 983 *
@@ -916,10 +987,16 @@ int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry)
916 * Note2: Windows driver (ndiswrapper) sets this to 987 * Note2: Windows driver (ndiswrapper) sets this to
917 * 0x00000714 instead of 0x00000007 988 * 0x00000714 instead of 0x00000007
918 */ 989 */
919 if (ah->ah_version > AR5K_AR5211) 990 if (ah->ah_version > AR5K_AR5211) {
920 ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL, 991 ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL,
921 AR5K_KEYTABLE_TYPE(entry)); 992 AR5K_KEYTABLE_TYPE(entry));
922 993
994 if (type == AR5K_KEYTABLE_TYPE_TKIP) {
995 ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL,
996 AR5K_KEYTABLE_TYPE(micentry));
997 }
998 }
999
923 return 0; 1000 return 0;
924} 1001}
925 1002
@@ -936,6 +1013,23 @@ int ath5k_hw_is_key_valid(struct ath5k_hw *ah, u16 entry)
936 AR5K_KEYTABLE_VALID; 1013 AR5K_KEYTABLE_VALID;
937} 1014}
938 1015
1016static
1017int ath5k_keycache_type(const struct ieee80211_key_conf *key)
1018{
1019 switch (key->alg) {
1020 case ALG_TKIP:
1021 return AR5K_KEYTABLE_TYPE_TKIP;
1022 case ALG_CCMP:
1023 return AR5K_KEYTABLE_TYPE_CCM;
1024 case ALG_WEP:
1025 if (key->keylen == LEN_WEP40)
1026 return AR5K_KEYTABLE_TYPE_40;
1027 else if (key->keylen == LEN_WEP104)
1028 return AR5K_KEYTABLE_TYPE_104;
1029 }
1030 return -EINVAL;
1031}
1032
939/* 1033/*
940 * Set a key entry on the table 1034 * Set a key entry on the table
941 */ 1035 */
@@ -943,40 +1037,53 @@ int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry,
943 const struct ieee80211_key_conf *key, const u8 *mac) 1037 const struct ieee80211_key_conf *key, const u8 *mac)
944{ 1038{
945 unsigned int i; 1039 unsigned int i;
1040 int keylen;
946 __le32 key_v[5] = {}; 1041 __le32 key_v[5] = {};
1042 __le32 key0 = 0, key1 = 0;
1043 __le32 *rxmic, *txmic;
947 u32 keytype; 1044 u32 keytype;
1045 u16 micentry = entry + AR5K_KEYTABLE_MIC_OFFSET;
1046 bool is_tkip;
1047 const u8 *key_ptr;
948 1048
949 ATH5K_TRACE(ah->ah_sc); 1049 ATH5K_TRACE(ah->ah_sc);
950 1050
951 /* key->keylen comes in from mac80211 in bytes */ 1051 is_tkip = (key->alg == ALG_TKIP);
952 1052
953 if (key->keylen > AR5K_KEYTABLE_SIZE / 8) 1053 /*
1054 * key->keylen comes in from mac80211 in bytes.
1055 * TKIP is 128 bit + 128 bit mic
1056 */
1057 keylen = (is_tkip) ? (128 / 8) : key->keylen;
1058
1059 if (entry > AR5K_KEYTABLE_SIZE ||
1060 (is_tkip && micentry > AR5K_KEYTABLE_SIZE))
954 return -EOPNOTSUPP; 1061 return -EOPNOTSUPP;
955 1062
956 switch (key->keylen) { 1063 if (unlikely(keylen > 16))
957 /* WEP 40-bit = 40-bit entered key + 24 bit IV = 64-bit */ 1064 return -EOPNOTSUPP;
958 case 40 / 8:
959 memcpy(&key_v[0], key->key, 5);
960 keytype = AR5K_KEYTABLE_TYPE_40;
961 break;
962 1065
963 /* WEP 104-bit = 104-bit entered key + 24-bit IV = 128-bit */ 1066 keytype = ath5k_keycache_type(key);
964 case 104 / 8: 1067 if (keytype < 0)
965 memcpy(&key_v[0], &key->key[0], 6); 1068 return keytype;
966 memcpy(&key_v[2], &key->key[6], 6);
967 memcpy(&key_v[4], &key->key[12], 1);
968 keytype = AR5K_KEYTABLE_TYPE_104;
969 break;
970 /* WEP 128-bit = 128-bit entered key + 24 bit IV = 152-bit */
971 case 128 / 8:
972 memcpy(&key_v[0], &key->key[0], 6);
973 memcpy(&key_v[2], &key->key[6], 6);
974 memcpy(&key_v[4], &key->key[12], 4);
975 keytype = AR5K_KEYTABLE_TYPE_128;
976 break;
977 1069
978 default: 1070 /*
979 return -EINVAL; /* shouldn't happen */ 1071 * each key block is 6 bytes wide, written as pairs of
1072 * alternating 32 and 16 bit le values.
1073 */
1074 key_ptr = key->key;
1075 for (i = 0; keylen >= 6; keylen -= 6) {
1076 memcpy(&key_v[i], key_ptr, 6);
1077 i += 2;
1078 key_ptr += 6;
1079 }
1080 if (keylen)
1081 memcpy(&key_v[i], key_ptr, keylen);
1082
1083 /* intentionally corrupt key until mic is installed */
1084 if (is_tkip) {
1085 key0 = key_v[0] = ~key_v[0];
1086 key1 = key_v[1] = ~key_v[1];
980 } 1087 }
981 1088
982 for (i = 0; i < ARRAY_SIZE(key_v); i++) 1089 for (i = 0; i < ARRAY_SIZE(key_v); i++)
@@ -985,6 +1092,40 @@ int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry,
985 1092
986 ath5k_hw_reg_write(ah, keytype, AR5K_KEYTABLE_TYPE(entry)); 1093 ath5k_hw_reg_write(ah, keytype, AR5K_KEYTABLE_TYPE(entry));
987 1094
1095 if (is_tkip) {
1096 /* Install rx/tx MIC */
1097 rxmic = (__le32 *) &key->key[16];
1098 txmic = (__le32 *) &key->key[24];
1099
1100 if (ah->ah_combined_mic) {
1101 key_v[0] = rxmic[0];
1102 key_v[1] = cpu_to_le32(le32_to_cpu(txmic[0]) >> 16);
1103 key_v[2] = rxmic[1];
1104 key_v[3] = cpu_to_le32(le32_to_cpu(txmic[0]) & 0xffff);
1105 key_v[4] = txmic[1];
1106 } else {
1107 key_v[0] = rxmic[0];
1108 key_v[1] = 0;
1109 key_v[2] = rxmic[1];
1110 key_v[3] = 0;
1111 key_v[4] = 0;
1112 }
1113 for (i = 0; i < ARRAY_SIZE(key_v); i++)
1114 ath5k_hw_reg_write(ah, le32_to_cpu(key_v[i]),
1115 AR5K_KEYTABLE_OFF(micentry, i));
1116
1117 ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL,
1118 AR5K_KEYTABLE_TYPE(micentry));
1119 ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_MAC0(micentry));
1120 ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_MAC1(micentry));
1121
1122 /* restore first 2 words of key */
1123 ath5k_hw_reg_write(ah, le32_to_cpu(~key0),
1124 AR5K_KEYTABLE_OFF(entry, 0));
1125 ath5k_hw_reg_write(ah, le32_to_cpu(~key1),
1126 AR5K_KEYTABLE_OFF(entry, 1));
1127 }
1128
988 return ath5k_hw_set_key_lladdr(ah, entry, mac); 1129 return ath5k_hw_set_key_lladdr(ah, entry, mac);
989} 1130}
990 1131