2 * Copyright (c) 2013 Qualcomm Atheros, Inc.
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 static void ath9k_tx99_stop(struct ath_softc
*sc
)
21 struct ath_hw
*ah
= sc
->sc_ah
;
22 struct ath_common
*common
= ath9k_hw_common(ah
);
24 ath_drain_all_txq(sc
);
27 ath9k_hw_set_interrupts(ah
);
28 ath9k_hw_enable_interrupts(ah
);
30 ieee80211_wake_queues(sc
->hw
);
32 kfree_skb(sc
->tx99_skb
);
34 sc
->tx99_state
= false;
36 ath9k_hw_tx99_stop(sc
->sc_ah
);
37 ath_dbg(common
, XMIT
, "TX99 stopped\n");
40 static struct sk_buff
*ath9k_build_tx99_skb(struct ath_softc
*sc
)
42 static u8 PN9Data
[] = {0xff, 0x87, 0xb8, 0x59, 0xb7, 0xa1, 0xcc, 0x24,
43 0x57, 0x5e, 0x4b, 0x9c, 0x0e, 0xe9, 0xea, 0x50,
44 0x2a, 0xbe, 0xb4, 0x1b, 0xb6, 0xb0, 0x5d, 0xf1,
45 0xe6, 0x9a, 0xe3, 0x45, 0xfd, 0x2c, 0x53, 0x18,
46 0x0c, 0xca, 0xc9, 0xfb, 0x49, 0x37, 0xe5, 0xa8,
47 0x51, 0x3b, 0x2f, 0x61, 0xaa, 0x72, 0x18, 0x84,
48 0x02, 0x23, 0x23, 0xab, 0x63, 0x89, 0x51, 0xb3,
49 0xe7, 0x8b, 0x72, 0x90, 0x4c, 0xe8, 0xfb, 0xc0};
51 struct ieee80211_tx_rate
*rate
;
52 struct ieee80211_hw
*hw
= sc
->hw
;
53 struct ath_hw
*ah
= sc
->sc_ah
;
54 struct ieee80211_hdr
*hdr
;
55 struct ieee80211_tx_info
*tx_info
;
62 avp
= (struct ath_vif
*)sc
->tx99_vif
->drv_priv
;
64 skb
= alloc_skb(len
, GFP_KERNEL
);
70 memset(skb
->data
, 0, len
);
72 hdr
= (struct ieee80211_hdr
*)skb
->data
;
73 hdr
->frame_control
= cpu_to_le16(IEEE80211_FTYPE_DATA
);
76 memcpy(hdr
->addr1
, hw
->wiphy
->perm_addr
, ETH_ALEN
);
77 memcpy(hdr
->addr2
, hw
->wiphy
->perm_addr
, ETH_ALEN
);
78 memcpy(hdr
->addr3
, hw
->wiphy
->perm_addr
, ETH_ALEN
);
80 hdr
->seq_ctrl
|= cpu_to_le16(avp
->seq_no
);
82 tx_info
= IEEE80211_SKB_CB(skb
);
83 memset(tx_info
, 0, sizeof(*tx_info
));
84 rate
= &tx_info
->control
.rates
[0];
85 tx_info
->band
= sc
->cur_chan
->chandef
.chan
->band
;
86 tx_info
->flags
= IEEE80211_TX_CTL_NO_ACK
;
87 tx_info
->control
.vif
= sc
->tx99_vif
;
89 if (ah
->curchan
&& IS_CHAN_HT(ah
->curchan
)) {
90 rate
->flags
|= IEEE80211_TX_RC_MCS
;
91 if (IS_CHAN_HT40(ah
->curchan
))
92 rate
->flags
|= IEEE80211_TX_RC_40_MHZ_WIDTH
;
95 memcpy(skb
->data
+ sizeof(*hdr
), PN9Data
, sizeof(PN9Data
));
100 static void ath9k_tx99_deinit(struct ath_softc
*sc
)
106 ath9k_ps_restore(sc
);
109 static int ath9k_tx99_init(struct ath_softc
*sc
)
111 struct ieee80211_hw
*hw
= sc
->hw
;
112 struct ath_hw
*ah
= sc
->sc_ah
;
113 struct ath_common
*common
= ath9k_hw_common(ah
);
114 struct ath_tx_control txctl
;
117 if (test_bit(ATH_OP_INVALID
, &common
->op_flags
)) {
119 "driver is in invalid state unable to use TX99");
123 sc
->tx99_skb
= ath9k_build_tx99_skb(sc
);
127 memset(&txctl
, 0, sizeof(txctl
));
128 txctl
.txq
= sc
->tx
.txq_map
[IEEE80211_AC_VO
];
134 ath9k_hw_disable_interrupts(ah
);
135 atomic_set(&ah
->intr_ref_cnt
, -1);
136 ath_drain_all_txq(sc
);
139 sc
->tx99_state
= true;
141 ieee80211_stop_queues(hw
);
143 if (sc
->tx99_power
== MAX_RATE_POWER
+ 1)
144 sc
->tx99_power
= MAX_RATE_POWER
;
146 ath9k_hw_tx99_set_txpower(ah
, sc
->tx99_power
);
147 r
= ath9k_tx99_send(sc
, sc
->tx99_skb
, &txctl
);
149 ath_dbg(common
, XMIT
, "Failed to xmit TX99 skb\n");
153 ath_dbg(common
, XMIT
, "TX99 xmit started using %d ( %ddBm)\n",
157 /* We leave the harware awake as it will be chugging on */
162 static ssize_t
read_file_tx99(struct file
*file
, char __user
*user_buf
,
163 size_t count
, loff_t
*ppos
)
165 struct ath_softc
*sc
= file
->private_data
;
169 len
= sprintf(buf
, "%d\n", sc
->tx99_state
);
170 return simple_read_from_buffer(user_buf
, count
, ppos
, buf
, len
);
173 static ssize_t
write_file_tx99(struct file
*file
, const char __user
*user_buf
,
174 size_t count
, loff_t
*ppos
)
176 struct ath_softc
*sc
= file
->private_data
;
177 struct ath_common
*common
= ath9k_hw_common(sc
->sc_ah
);
186 if (sc
->cur_chan
->nvifs
> 1)
189 len
= min(count
, sizeof(buf
) - 1);
190 if (copy_from_user(buf
, user_buf
, len
))
195 if (strtobool(buf
, &start
))
198 mutex_lock(&sc
->mutex
);
200 if (start
== sc
->tx99_state
) {
203 ath_dbg(common
, XMIT
, "Resetting TX99\n");
204 ath9k_tx99_deinit(sc
);
208 ath9k_tx99_deinit(sc
);
212 r
= ath9k_tx99_init(sc
);
214 mutex_unlock(&sc
->mutex
);
218 mutex_unlock(&sc
->mutex
);
222 static const struct file_operations fops_tx99
= {
223 .read
= read_file_tx99
,
224 .write
= write_file_tx99
,
226 .owner
= THIS_MODULE
,
227 .llseek
= default_llseek
,
230 static ssize_t
read_file_tx99_power(struct file
*file
,
231 char __user
*user_buf
,
232 size_t count
, loff_t
*ppos
)
234 struct ath_softc
*sc
= file
->private_data
;
238 len
= sprintf(buf
, "%d (%d dBm)\n",
242 return simple_read_from_buffer(user_buf
, count
, ppos
, buf
, len
);
245 static ssize_t
write_file_tx99_power(struct file
*file
,
246 const char __user
*user_buf
,
247 size_t count
, loff_t
*ppos
)
249 struct ath_softc
*sc
= file
->private_data
;
253 r
= kstrtou8_from_user(user_buf
, count
, 0, &tx_power
);
257 if (tx_power
> MAX_RATE_POWER
)
260 sc
->tx99_power
= tx_power
;
263 ath9k_hw_tx99_set_txpower(sc
->sc_ah
, sc
->tx99_power
);
264 ath9k_ps_restore(sc
);
269 static const struct file_operations fops_tx99_power
= {
270 .read
= read_file_tx99_power
,
271 .write
= write_file_tx99_power
,
273 .owner
= THIS_MODULE
,
274 .llseek
= default_llseek
,
277 void ath9k_tx99_init_debug(struct ath_softc
*sc
)
279 if (!AR_SREV_9300_20_OR_LATER(sc
->sc_ah
))
282 debugfs_create_file("tx99", S_IRUSR
| S_IWUSR
,
283 sc
->debug
.debugfs_phy
, sc
,
285 debugfs_create_file("tx99_power", S_IRUSR
| S_IWUSR
,
286 sc
->debug
.debugfs_phy
, sc
,