1 | /* |
2 | * Atheros CARL9170 driver |
3 | * |
4 | * MAC programming |
5 | * |
6 | * Copyright 2008, Johannes Berg <johannes@sipsolutions.net> |
7 | * |
8 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License as published by |
10 | * the Free Software Foundation; either version 2 of the License, or |
11 | * (at your option) any later version. |
12 | * |
13 | * This program is distributed in the hope that it will be useful, |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | * GNU General Public License for more details. |
17 | * |
18 | * You should have received a copy of the GNU General Public License |
19 | * along with this program; see the file COPYING. If not, see |
20 | * http://www.gnu.org/licenses/. |
21 | * |
22 | * This file incorporates work covered by the following copyright and |
23 | * permission notice: |
24 | * Copyright (c) 2007-2008 Atheros Communications, Inc. |
25 | * |
26 | * Permission to use, copy, modify, and/or distribute this software for any |
27 | * purpose with or without fee is hereby granted, provided that the above |
28 | * copyright notice and this permission notice appear in all copies. |
29 | * |
30 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
31 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
32 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
33 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
34 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
35 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
36 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
37 | */ |
38 | |
39 | #include <asm/unaligned.h> |
40 | |
41 | #include "carl9170.h" |
42 | #include "cmd.h" |
43 | |
44 | int carl9170_set_dyn_sifs_ack(struct ar9170 *ar) |
45 | { |
46 | u32 val; |
47 | |
48 | if (conf_is_ht40(conf: &ar->hw->conf)) |
49 | val = 0x010a; |
50 | else { |
51 | if (ar->hw->conf.chandef.chan->band == NL80211_BAND_2GHZ) |
52 | val = 0x105; |
53 | else |
54 | val = 0x104; |
55 | } |
56 | |
57 | return carl9170_write_reg(ar, AR9170_MAC_REG_DYNAMIC_SIFS_ACK, val); |
58 | } |
59 | |
60 | int carl9170_set_rts_cts_rate(struct ar9170 *ar) |
61 | { |
62 | u32 rts_rate, cts_rate; |
63 | |
64 | if (conf_is_ht(conf: &ar->hw->conf)) { |
65 | /* 12 mbit OFDM */ |
66 | rts_rate = 0x1da; |
67 | cts_rate = 0x10a; |
68 | } else { |
69 | if (ar->hw->conf.chandef.chan->band == NL80211_BAND_2GHZ) { |
70 | /* 11 mbit CCK */ |
71 | rts_rate = 033; |
72 | cts_rate = 003; |
73 | } else { |
74 | /* 6 mbit OFDM */ |
75 | rts_rate = 0x1bb; |
76 | cts_rate = 0x10b; |
77 | } |
78 | } |
79 | |
80 | return carl9170_write_reg(ar, AR9170_MAC_REG_RTS_CTS_RATE, |
81 | val: rts_rate | (cts_rate) << 16); |
82 | } |
83 | |
84 | int carl9170_set_slot_time(struct ar9170 *ar) |
85 | { |
86 | struct ieee80211_vif *vif; |
87 | u32 slottime = 20; |
88 | |
89 | rcu_read_lock(); |
90 | vif = carl9170_get_main_vif(ar); |
91 | if (!vif) { |
92 | rcu_read_unlock(); |
93 | return 0; |
94 | } |
95 | |
96 | if ((ar->hw->conf.chandef.chan->band == NL80211_BAND_5GHZ) || |
97 | vif->bss_conf.use_short_slot) |
98 | slottime = 9; |
99 | |
100 | rcu_read_unlock(); |
101 | |
102 | return carl9170_write_reg(ar, AR9170_MAC_REG_SLOT_TIME, |
103 | val: slottime << 10); |
104 | } |
105 | |
106 | int carl9170_set_mac_rates(struct ar9170 *ar) |
107 | { |
108 | struct ieee80211_vif *vif; |
109 | u32 basic, mandatory; |
110 | |
111 | rcu_read_lock(); |
112 | vif = carl9170_get_main_vif(ar); |
113 | |
114 | if (!vif) { |
115 | rcu_read_unlock(); |
116 | return 0; |
117 | } |
118 | |
119 | basic = (vif->bss_conf.basic_rates & 0xf); |
120 | basic |= (vif->bss_conf.basic_rates & 0xff0) << 4; |
121 | rcu_read_unlock(); |
122 | |
123 | if (ar->hw->conf.chandef.chan->band == NL80211_BAND_5GHZ) |
124 | mandatory = 0xff00; /* OFDM 6/9/12/18/24/36/48/54 */ |
125 | else |
126 | mandatory = 0xff0f; /* OFDM (6/9../54) + CCK (1/2/5.5/11) */ |
127 | |
128 | carl9170_regwrite_begin(ar); |
129 | carl9170_regwrite(AR9170_MAC_REG_BASIC_RATE, basic); |
130 | carl9170_regwrite(AR9170_MAC_REG_MANDATORY_RATE, mandatory); |
131 | carl9170_regwrite_finish(); |
132 | |
133 | return carl9170_regwrite_result(); |
134 | } |
135 | |
136 | int carl9170_set_qos(struct ar9170 *ar) |
137 | { |
138 | carl9170_regwrite_begin(ar); |
139 | |
140 | carl9170_regwrite(AR9170_MAC_REG_AC0_CW, ar->edcf[0].cw_min | |
141 | (ar->edcf[0].cw_max << 16)); |
142 | carl9170_regwrite(AR9170_MAC_REG_AC1_CW, ar->edcf[1].cw_min | |
143 | (ar->edcf[1].cw_max << 16)); |
144 | carl9170_regwrite(AR9170_MAC_REG_AC2_CW, ar->edcf[2].cw_min | |
145 | (ar->edcf[2].cw_max << 16)); |
146 | carl9170_regwrite(AR9170_MAC_REG_AC3_CW, ar->edcf[3].cw_min | |
147 | (ar->edcf[3].cw_max << 16)); |
148 | carl9170_regwrite(AR9170_MAC_REG_AC4_CW, ar->edcf[4].cw_min | |
149 | (ar->edcf[4].cw_max << 16)); |
150 | |
151 | carl9170_regwrite(AR9170_MAC_REG_AC2_AC1_AC0_AIFS, |
152 | ((ar->edcf[0].aifs * 9 + 10)) | |
153 | ((ar->edcf[1].aifs * 9 + 10) << 12) | |
154 | ((ar->edcf[2].aifs * 9 + 10) << 24)); |
155 | carl9170_regwrite(AR9170_MAC_REG_AC4_AC3_AC2_AIFS, |
156 | ((ar->edcf[2].aifs * 9 + 10) >> 8) | |
157 | ((ar->edcf[3].aifs * 9 + 10) << 4) | |
158 | ((ar->edcf[4].aifs * 9 + 10) << 16)); |
159 | |
160 | carl9170_regwrite(AR9170_MAC_REG_AC1_AC0_TXOP, |
161 | ar->edcf[0].txop | ar->edcf[1].txop << 16); |
162 | carl9170_regwrite(AR9170_MAC_REG_AC3_AC2_TXOP, |
163 | ar->edcf[2].txop | ar->edcf[3].txop << 16 | |
164 | ar->edcf[4].txop << 24); |
165 | |
166 | carl9170_regwrite_finish(); |
167 | |
168 | return carl9170_regwrite_result(); |
169 | } |
170 | |
171 | int carl9170_init_mac(struct ar9170 *ar) |
172 | { |
173 | carl9170_regwrite_begin(ar); |
174 | |
175 | /* switch MAC to OTUS interface */ |
176 | carl9170_regwrite(0x1c3600, 0x3); |
177 | |
178 | carl9170_regwrite(AR9170_MAC_REG_ACK_EXTENSION, 0x40); |
179 | |
180 | carl9170_regwrite(AR9170_MAC_REG_RETRY_MAX, 0x0); |
181 | |
182 | carl9170_regwrite(AR9170_MAC_REG_FRAMETYPE_FILTER, |
183 | AR9170_MAC_FTF_MONITOR); |
184 | |
185 | /* enable MMIC */ |
186 | carl9170_regwrite(AR9170_MAC_REG_SNIFFER, |
187 | AR9170_MAC_SNIFFER_DEFAULTS); |
188 | |
189 | carl9170_regwrite(AR9170_MAC_REG_RX_THRESHOLD, 0xc1f80); |
190 | |
191 | carl9170_regwrite(AR9170_MAC_REG_RX_PE_DELAY, 0x70); |
192 | carl9170_regwrite(AR9170_MAC_REG_EIFS_AND_SIFS, 0xa144000); |
193 | carl9170_regwrite(AR9170_MAC_REG_SLOT_TIME, 9 << 10); |
194 | |
195 | /* CF-END & CF-ACK rate => 24M OFDM */ |
196 | carl9170_regwrite(AR9170_MAC_REG_TID_CFACK_CFEND_RATE, 0x59900000); |
197 | |
198 | /* NAV protects ACK only (in TXOP) */ |
199 | carl9170_regwrite(AR9170_MAC_REG_TXOP_DURATION, 0x201); |
200 | |
201 | /* Set Beacon PHY CTRL's TPC to 0x7, TA1=1 */ |
202 | /* OTUS set AM to 0x1 */ |
203 | carl9170_regwrite(AR9170_MAC_REG_BCN_HT1, 0x8000170); |
204 | |
205 | carl9170_regwrite(AR9170_MAC_REG_BACKOFF_PROTECT, 0x105); |
206 | |
207 | /* Aggregation MAX number and timeout */ |
208 | carl9170_regwrite(AR9170_MAC_REG_AMPDU_FACTOR, 0x8000a); |
209 | carl9170_regwrite(AR9170_MAC_REG_AMPDU_DENSITY, 0x140a07); |
210 | |
211 | carl9170_regwrite(AR9170_MAC_REG_FRAMETYPE_FILTER, |
212 | AR9170_MAC_FTF_DEFAULTS); |
213 | |
214 | carl9170_regwrite(AR9170_MAC_REG_RX_CONTROL, |
215 | AR9170_MAC_RX_CTRL_DEAGG | |
216 | AR9170_MAC_RX_CTRL_SHORT_FILTER); |
217 | |
218 | /* rate sets */ |
219 | carl9170_regwrite(AR9170_MAC_REG_BASIC_RATE, 0x150f); |
220 | carl9170_regwrite(AR9170_MAC_REG_MANDATORY_RATE, 0x150f); |
221 | carl9170_regwrite(AR9170_MAC_REG_RTS_CTS_RATE, 0x0030033); |
222 | |
223 | /* MIMO response control */ |
224 | carl9170_regwrite(AR9170_MAC_REG_ACK_TPC, 0x4003c1e); |
225 | |
226 | carl9170_regwrite(AR9170_MAC_REG_AMPDU_RX_THRESH, 0xffff); |
227 | |
228 | /* set PHY register read timeout (??) */ |
229 | carl9170_regwrite(AR9170_MAC_REG_MISC_680, 0xf00008); |
230 | |
231 | /* Disable Rx TimeOut, workaround for BB. */ |
232 | carl9170_regwrite(AR9170_MAC_REG_RX_TIMEOUT, 0x0); |
233 | |
234 | /* Set WLAN DMA interrupt mode: generate int per packet */ |
235 | carl9170_regwrite(AR9170_MAC_REG_TXRX_MPI, 0x110011); |
236 | |
237 | carl9170_regwrite(AR9170_MAC_REG_FCS_SELECT, |
238 | AR9170_MAC_FCS_FIFO_PROT); |
239 | |
240 | /* Disables the CF_END frame, undocumented register */ |
241 | carl9170_regwrite(AR9170_MAC_REG_TXOP_NOT_ENOUGH_IND, |
242 | 0x141e0f48); |
243 | |
244 | /* reset group hash table */ |
245 | carl9170_regwrite(AR9170_MAC_REG_GROUP_HASH_TBL_L, 0xffffffff); |
246 | carl9170_regwrite(AR9170_MAC_REG_GROUP_HASH_TBL_H, 0xffffffff); |
247 | |
248 | /* disable PRETBTT interrupt */ |
249 | carl9170_regwrite(AR9170_MAC_REG_PRETBTT, 0x0); |
250 | carl9170_regwrite(AR9170_MAC_REG_BCN_PERIOD, 0x0); |
251 | |
252 | carl9170_regwrite_finish(); |
253 | |
254 | return carl9170_regwrite_result(); |
255 | } |
256 | |
257 | static int carl9170_set_mac_reg(struct ar9170 *ar, |
258 | const u32 reg, const u8 *mac) |
259 | { |
260 | static const u8 zero[ETH_ALEN] = { 0 }; |
261 | |
262 | if (!mac) |
263 | mac = zero; |
264 | |
265 | carl9170_regwrite_begin(ar); |
266 | |
267 | carl9170_regwrite(reg, get_unaligned_le32(mac)); |
268 | carl9170_regwrite(reg + 4, get_unaligned_le16(mac + 4)); |
269 | |
270 | carl9170_regwrite_finish(); |
271 | |
272 | return carl9170_regwrite_result(); |
273 | } |
274 | |
275 | int carl9170_mod_virtual_mac(struct ar9170 *ar, const unsigned int id, |
276 | const u8 *mac) |
277 | { |
278 | if (WARN_ON(id >= ar->fw.vif_num)) |
279 | return -EINVAL; |
280 | |
281 | return carl9170_set_mac_reg(ar, |
282 | AR9170_MAC_REG_ACK_TABLE + (id - 1) * 8, mac); |
283 | } |
284 | |
285 | int carl9170_update_multicast(struct ar9170 *ar, const u64 mc_hash) |
286 | { |
287 | int err; |
288 | |
289 | carl9170_regwrite_begin(ar); |
290 | carl9170_regwrite(AR9170_MAC_REG_GROUP_HASH_TBL_H, mc_hash >> 32); |
291 | carl9170_regwrite(AR9170_MAC_REG_GROUP_HASH_TBL_L, mc_hash); |
292 | carl9170_regwrite_finish(); |
293 | err = carl9170_regwrite_result(); |
294 | if (err) |
295 | return err; |
296 | |
297 | ar->cur_mc_hash = mc_hash; |
298 | return 0; |
299 | } |
300 | |
301 | int carl9170_set_operating_mode(struct ar9170 *ar) |
302 | { |
303 | struct ieee80211_vif *vif; |
304 | struct ath_common *common = &ar->common; |
305 | u8 *mac_addr, *bssid; |
306 | u32 cam_mode = AR9170_MAC_CAM_DEFAULTS; |
307 | u32 enc_mode = AR9170_MAC_ENCRYPTION_DEFAULTS | |
308 | AR9170_MAC_ENCRYPTION_MGMT_RX_SOFTWARE; |
309 | u32 rx_ctrl = AR9170_MAC_RX_CTRL_DEAGG | |
310 | AR9170_MAC_RX_CTRL_SHORT_FILTER; |
311 | u32 sniffer = AR9170_MAC_SNIFFER_DEFAULTS; |
312 | int err = 0; |
313 | |
314 | rcu_read_lock(); |
315 | vif = carl9170_get_main_vif(ar); |
316 | |
317 | if (vif) { |
318 | mac_addr = common->macaddr; |
319 | bssid = common->curbssid; |
320 | |
321 | switch (vif->type) { |
322 | case NL80211_IFTYPE_ADHOC: |
323 | cam_mode |= AR9170_MAC_CAM_IBSS; |
324 | break; |
325 | case NL80211_IFTYPE_MESH_POINT: |
326 | case NL80211_IFTYPE_AP: |
327 | cam_mode |= AR9170_MAC_CAM_AP; |
328 | |
329 | /* iwlagn 802.11n STA Workaround */ |
330 | rx_ctrl |= AR9170_MAC_RX_CTRL_PASS_TO_HOST; |
331 | break; |
332 | case NL80211_IFTYPE_STATION: |
333 | cam_mode |= AR9170_MAC_CAM_STA; |
334 | rx_ctrl |= AR9170_MAC_RX_CTRL_PASS_TO_HOST; |
335 | break; |
336 | default: |
337 | WARN(1, "Unsupported operation mode %x\n" , vif->type); |
338 | err = -EOPNOTSUPP; |
339 | break; |
340 | } |
341 | } else { |
342 | /* |
343 | * Enable monitor mode |
344 | * |
345 | * rx_ctrl |= AR9170_MAC_RX_CTRL_ACK_IN_SNIFFER; |
346 | * sniffer |= AR9170_MAC_SNIFFER_ENABLE_PROMISC; |
347 | * |
348 | * When the hardware is in SNIFFER_PROMISC mode, |
349 | * it generates spurious ACKs for every incoming |
350 | * frame. This confuses every peer in the |
351 | * vicinity and the network throughput will suffer |
352 | * badly. |
353 | * |
354 | * Hence, the hardware will be put into station |
355 | * mode and just the rx filters are disabled. |
356 | */ |
357 | cam_mode |= AR9170_MAC_CAM_STA; |
358 | rx_ctrl |= AR9170_MAC_RX_CTRL_PASS_TO_HOST; |
359 | mac_addr = common->macaddr; |
360 | bssid = NULL; |
361 | } |
362 | rcu_read_unlock(); |
363 | |
364 | if (err) |
365 | return err; |
366 | |
367 | if (ar->rx_software_decryption) |
368 | enc_mode |= AR9170_MAC_ENCRYPTION_RX_SOFTWARE; |
369 | |
370 | if (ar->sniffer_enabled) { |
371 | enc_mode |= AR9170_MAC_ENCRYPTION_RX_SOFTWARE; |
372 | } |
373 | |
374 | err = carl9170_set_mac_reg(ar, AR9170_MAC_REG_MAC_ADDR_L, mac: mac_addr); |
375 | if (err) |
376 | return err; |
377 | |
378 | err = carl9170_set_mac_reg(ar, AR9170_MAC_REG_BSSID_L, mac: bssid); |
379 | if (err) |
380 | return err; |
381 | |
382 | carl9170_regwrite_begin(ar); |
383 | carl9170_regwrite(AR9170_MAC_REG_SNIFFER, sniffer); |
384 | carl9170_regwrite(AR9170_MAC_REG_CAM_MODE, cam_mode); |
385 | carl9170_regwrite(AR9170_MAC_REG_ENCRYPTION, enc_mode); |
386 | carl9170_regwrite(AR9170_MAC_REG_RX_CONTROL, rx_ctrl); |
387 | carl9170_regwrite_finish(); |
388 | |
389 | return carl9170_regwrite_result(); |
390 | } |
391 | |
392 | int carl9170_set_hwretry_limit(struct ar9170 *ar, const unsigned int max_retry) |
393 | { |
394 | u32 tmp = min_t(u32, 0x33333, max_retry * 0x11111); |
395 | |
396 | return carl9170_write_reg(ar, AR9170_MAC_REG_RETRY_MAX, val: tmp); |
397 | } |
398 | |
399 | int carl9170_set_beacon_timers(struct ar9170 *ar) |
400 | { |
401 | struct ieee80211_vif *vif; |
402 | u32 v = 0; |
403 | u32 pretbtt = 0; |
404 | |
405 | rcu_read_lock(); |
406 | vif = carl9170_get_main_vif(ar); |
407 | |
408 | if (vif) { |
409 | struct carl9170_vif_info *mvif; |
410 | mvif = (void *) vif->drv_priv; |
411 | |
412 | if (mvif->enable_beacon && !WARN_ON(!ar->beacon_enabled)) { |
413 | ar->global_beacon_int = vif->bss_conf.beacon_int / |
414 | ar->beacon_enabled; |
415 | |
416 | SET_VAL(AR9170_MAC_BCN_DTIM, v, |
417 | vif->bss_conf.dtim_period); |
418 | |
419 | switch (vif->type) { |
420 | case NL80211_IFTYPE_MESH_POINT: |
421 | case NL80211_IFTYPE_ADHOC: |
422 | v |= AR9170_MAC_BCN_IBSS_MODE; |
423 | break; |
424 | case NL80211_IFTYPE_AP: |
425 | v |= AR9170_MAC_BCN_AP_MODE; |
426 | break; |
427 | default: |
428 | WARN_ON_ONCE(1); |
429 | break; |
430 | } |
431 | } else if (vif->type == NL80211_IFTYPE_STATION) { |
432 | ar->global_beacon_int = vif->bss_conf.beacon_int; |
433 | |
434 | SET_VAL(AR9170_MAC_BCN_DTIM, v, |
435 | ar->hw->conf.ps_dtim_period); |
436 | |
437 | v |= AR9170_MAC_BCN_STA_PS | |
438 | AR9170_MAC_BCN_PWR_MGT; |
439 | } |
440 | |
441 | if (ar->global_beacon_int) { |
442 | if (ar->global_beacon_int < 15) { |
443 | rcu_read_unlock(); |
444 | return -ERANGE; |
445 | } |
446 | |
447 | ar->global_pretbtt = ar->global_beacon_int - |
448 | CARL9170_PRETBTT_KUS; |
449 | } else { |
450 | ar->global_pretbtt = 0; |
451 | } |
452 | } else { |
453 | ar->global_beacon_int = 0; |
454 | ar->global_pretbtt = 0; |
455 | } |
456 | |
457 | rcu_read_unlock(); |
458 | |
459 | SET_VAL(AR9170_MAC_BCN_PERIOD, v, ar->global_beacon_int); |
460 | SET_VAL(AR9170_MAC_PRETBTT, pretbtt, ar->global_pretbtt); |
461 | SET_VAL(AR9170_MAC_PRETBTT2, pretbtt, ar->global_pretbtt); |
462 | |
463 | carl9170_regwrite_begin(ar); |
464 | carl9170_regwrite(AR9170_MAC_REG_PRETBTT, pretbtt); |
465 | carl9170_regwrite(AR9170_MAC_REG_BCN_PERIOD, v); |
466 | carl9170_regwrite_finish(); |
467 | return carl9170_regwrite_result(); |
468 | } |
469 | |
470 | int carl9170_upload_key(struct ar9170 *ar, const u8 id, const u8 *mac, |
471 | const u8 ktype, const u8 keyidx, const u8 *keydata, |
472 | const int keylen) |
473 | { |
474 | struct carl9170_set_key_cmd key = { }; |
475 | static const u8 bcast[ETH_ALEN] = { |
476 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; |
477 | |
478 | mac = mac ? : bcast; |
479 | |
480 | key.user = cpu_to_le16(id); |
481 | key.keyId = cpu_to_le16(keyidx); |
482 | key.type = cpu_to_le16(ktype); |
483 | memcpy(&key.macAddr, mac, ETH_ALEN); |
484 | if (keydata) |
485 | memcpy(&key.key, keydata, keylen); |
486 | |
487 | return carl9170_exec_cmd(ar, CARL9170_CMD_EKEY, |
488 | plen: sizeof(key), payload: (u8 *)&key, rlen: 0, NULL); |
489 | } |
490 | |
491 | int carl9170_disable_key(struct ar9170 *ar, const u8 id) |
492 | { |
493 | struct carl9170_disable_key_cmd key = { }; |
494 | |
495 | key.user = cpu_to_le16(id); |
496 | |
497 | return carl9170_exec_cmd(ar, CARL9170_CMD_DKEY, |
498 | plen: sizeof(key), payload: (u8 *)&key, rlen: 0, NULL); |
499 | } |
500 | |
501 | int carl9170_set_mac_tpc(struct ar9170 *ar, struct ieee80211_channel *channel) |
502 | { |
503 | unsigned int power, chains; |
504 | |
505 | if (ar->eeprom.tx_mask != 1) |
506 | chains = AR9170_TX_PHY_TXCHAIN_2; |
507 | else |
508 | chains = AR9170_TX_PHY_TXCHAIN_1; |
509 | |
510 | switch (channel->band) { |
511 | case NL80211_BAND_2GHZ: |
512 | power = ar->power_2G_ofdm[0] & 0x3f; |
513 | break; |
514 | case NL80211_BAND_5GHZ: |
515 | power = ar->power_5G_leg[0] & 0x3f; |
516 | break; |
517 | default: |
518 | BUG(); |
519 | } |
520 | |
521 | power = min_t(unsigned int, power, ar->hw->conf.power_level * 2); |
522 | |
523 | carl9170_regwrite_begin(ar); |
524 | carl9170_regwrite(AR9170_MAC_REG_ACK_TPC, |
525 | 0x3c1e | power << 20 | chains << 26); |
526 | carl9170_regwrite(AR9170_MAC_REG_RTS_CTS_TPC, |
527 | power << 5 | chains << 11 | |
528 | power << 21 | chains << 27); |
529 | carl9170_regwrite(AR9170_MAC_REG_CFEND_QOSNULL_TPC, |
530 | power << 5 | chains << 11 | |
531 | power << 21 | chains << 27); |
532 | carl9170_regwrite_finish(); |
533 | return carl9170_regwrite_result(); |
534 | } |
535 | |