aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSujith Manoharan <c_manoha@qca.qualcomm.com>2013-10-24 02:34:39 -0400
committerJohn W. Linville <linville@tuxdriver.com>2013-12-02 14:24:53 -0500
commitef6b19e40f525777a0052956bf7d9a1985f74993 (patch)
treeb9fecb0348318be8f8be43763bbbed8a4f8cb5b6
parent4dd3564030020f8beb8dc7bbfea05781648836d0 (diff)
ath9k: Fix TX99 config option usage
Use CONFIG_ATH9K_TX99 to properly enclose the tx99 code and make sure that it is not compiled as part of the driver when it is not selected. Move the tx99 code to a new file tx99.c and also add ATH9K_DEBUGFS as a dependency in Kconfig. This reduces the module size on platforms like OpenWrt where ATH9K_DEBUGFS is selected, but TX99 might be disabled. Cc: Luis R. Rodriguez <mcgrof@do-not-panic.com> Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/ath/ath9k/Kconfig2
-rw-r--r--drivers/net/wireless/ath/ath9k/Makefile4
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k.h20
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.c115
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c130
-rw-r--r--drivers/net/wireless/ath/ath9k/tx99.c263
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c4
7 files changed, 290 insertions, 248 deletions
diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig
index 32f139e2e897..3ffa4ea8fcbc 100644
--- a/drivers/net/wireless/ath/ath9k/Kconfig
+++ b/drivers/net/wireless/ath/ath9k/Kconfig
@@ -86,7 +86,7 @@ config ATH9K_DFS_CERTIFIED
86 86
87config ATH9K_TX99 87config ATH9K_TX99
88 bool "Atheros ath9k TX99 testing support" 88 bool "Atheros ath9k TX99 testing support"
89 depends on CFG80211_CERTIFICATION_ONUS 89 depends on ATH9K_DEBUGFS && CFG80211_CERTIFICATION_ONUS
90 default n 90 default n
91 ---help--- 91 ---help---
92 Say N. This should only be enabled on systems undergoing 92 Say N. This should only be enabled on systems undergoing
diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile
index 6205ef5a9321..f86a261e708a 100644
--- a/drivers/net/wireless/ath/ath9k/Makefile
+++ b/drivers/net/wireless/ath/ath9k/Makefile
@@ -13,9 +13,9 @@ ath9k-$(CONFIG_ATH9K_PCI) += pci.o
13ath9k-$(CONFIG_ATH9K_AHB) += ahb.o 13ath9k-$(CONFIG_ATH9K_AHB) += ahb.o
14ath9k-$(CONFIG_ATH9K_DEBUGFS) += debug.o 14ath9k-$(CONFIG_ATH9K_DEBUGFS) += debug.o
15ath9k-$(CONFIG_ATH9K_DFS_DEBUGFS) += dfs_debug.o 15ath9k-$(CONFIG_ATH9K_DFS_DEBUGFS) += dfs_debug.o
16ath9k-$(CONFIG_ATH9K_DFS_CERTIFIED) += \ 16ath9k-$(CONFIG_ATH9K_DFS_CERTIFIED) += dfs.o
17 dfs.o
18ath9k-$(CONFIG_PM_SLEEP) += wow.o 17ath9k-$(CONFIG_PM_SLEEP) += wow.o
18ath9k-$(CONFIG_ATH9K_TX99) += tx99.o
19 19
20obj-$(CONFIG_ATH9K) += ath9k.o 20obj-$(CONFIG_ATH9K) += ath9k.o
21 21
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 9cf412c6c32c..b39ffac3b93a 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -948,10 +948,25 @@ struct fft_sample_ht20_40 {
948 u8 data[SPECTRAL_HT20_40_NUM_BINS]; 948 u8 data[SPECTRAL_HT20_40_NUM_BINS];
949} __packed; 949} __packed;
950 950
951int ath9k_tx99_init(struct ath_softc *sc); 951/********/
952void ath9k_tx99_deinit(struct ath_softc *sc); 952/* TX99 */
953/********/
954
955#ifdef CONFIG_ATH9K_TX99
956void ath9k_tx99_init_debug(struct ath_softc *sc);
953int ath9k_tx99_send(struct ath_softc *sc, struct sk_buff *skb, 957int ath9k_tx99_send(struct ath_softc *sc, struct sk_buff *skb,
954 struct ath_tx_control *txctl); 958 struct ath_tx_control *txctl);
959#else
960static inline void ath9k_tx99_init_debug(struct ath_softc *sc)
961{
962}
963static inline int ath9k_tx99_send(struct ath_softc *sc,
964 struct sk_buff *skb,
965 struct ath_tx_control *txctl)
966{
967 return 0;
968}
969#endif /* CONFIG_ATH9K_TX99 */
955 970
956void ath9k_tasklet(unsigned long data); 971void ath9k_tasklet(unsigned long data);
957int ath_cabq_update(struct ath_softc *); 972int ath_cabq_update(struct ath_softc *);
@@ -968,6 +983,7 @@ extern bool is_ath9k_unloaded;
968 983
969u8 ath9k_parse_mpdudensity(u8 mpdudensity); 984u8 ath9k_parse_mpdudensity(u8 mpdudensity);
970irqreturn_t ath_isr(int irq, void *dev); 985irqreturn_t ath_isr(int irq, void *dev);
986int ath_reset(struct ath_softc *sc);
971int ath9k_init_device(u16 devid, struct ath_softc *sc, 987int ath9k_init_device(u16 devid, struct ath_softc *sc,
972 const struct ath_bus_ops *bus_ops); 988 const struct ath_bus_ops *bus_ops);
973void ath9k_deinit_device(struct ath_softc *sc); 989void ath9k_deinit_device(struct ath_softc *sc);
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index 83a2c59f680b..2f7dccfdb727 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -1778,111 +1778,6 @@ void ath9k_deinit_debug(struct ath_softc *sc)
1778 } 1778 }
1779} 1779}
1780 1780
1781static ssize_t read_file_tx99(struct file *file, char __user *user_buf,
1782 size_t count, loff_t *ppos)
1783{
1784 struct ath_softc *sc = file->private_data;
1785 char buf[3];
1786 unsigned int len;
1787
1788 len = sprintf(buf, "%d\n", sc->tx99_state);
1789 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1790}
1791
1792static ssize_t write_file_tx99(struct file *file, const char __user *user_buf,
1793 size_t count, loff_t *ppos)
1794{
1795 struct ath_softc *sc = file->private_data;
1796 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
1797 char buf[32];
1798 bool start;
1799 ssize_t len;
1800 int r;
1801
1802 if (sc->nvifs > 1)
1803 return -EOPNOTSUPP;
1804
1805 len = min(count, sizeof(buf) - 1);
1806 if (copy_from_user(buf, user_buf, len))
1807 return -EFAULT;
1808
1809 if (strtobool(buf, &start))
1810 return -EINVAL;
1811
1812 if (start == sc->tx99_state) {
1813 if (!start)
1814 return count;
1815 ath_dbg(common, XMIT, "Resetting TX99\n");
1816 ath9k_tx99_deinit(sc);
1817 }
1818
1819 if (!start) {
1820 ath9k_tx99_deinit(sc);
1821 return count;
1822 }
1823
1824 r = ath9k_tx99_init(sc);
1825 if (r)
1826 return r;
1827
1828 return count;
1829}
1830
1831static const struct file_operations fops_tx99 = {
1832 .read = read_file_tx99,
1833 .write = write_file_tx99,
1834 .open = simple_open,
1835 .owner = THIS_MODULE,
1836 .llseek = default_llseek,
1837};
1838
1839static ssize_t read_file_tx99_power(struct file *file,
1840 char __user *user_buf,
1841 size_t count, loff_t *ppos)
1842{
1843 struct ath_softc *sc = file->private_data;
1844 char buf[32];
1845 unsigned int len;
1846
1847 len = sprintf(buf, "%d (%d dBm)\n",
1848 sc->tx99_power,
1849 sc->tx99_power / 2);
1850
1851 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1852}
1853
1854static ssize_t write_file_tx99_power(struct file *file,
1855 const char __user *user_buf,
1856 size_t count, loff_t *ppos)
1857{
1858 struct ath_softc *sc = file->private_data;
1859 int r;
1860 u8 tx_power;
1861
1862 r = kstrtou8_from_user(user_buf, count, 0, &tx_power);
1863 if (r)
1864 return r;
1865
1866 if (tx_power > MAX_RATE_POWER)
1867 return -EINVAL;
1868
1869 sc->tx99_power = tx_power;
1870
1871 ath9k_ps_wakeup(sc);
1872 ath9k_hw_tx99_set_txpower(sc->sc_ah, sc->tx99_power);
1873 ath9k_ps_restore(sc);
1874
1875 return count;
1876}
1877
1878static const struct file_operations fops_tx99_power = {
1879 .read = read_file_tx99_power,
1880 .write = write_file_tx99_power,
1881 .open = simple_open,
1882 .owner = THIS_MODULE,
1883 .llseek = default_llseek,
1884};
1885
1886int ath9k_init_debug(struct ath_hw *ah) 1781int ath9k_init_debug(struct ath_hw *ah)
1887{ 1782{
1888 struct ath_common *common = ath9k_hw_common(ah); 1783 struct ath_common *common = ath9k_hw_common(ah);
@@ -1899,6 +1794,7 @@ int ath9k_init_debug(struct ath_hw *ah)
1899#endif 1794#endif
1900 1795
1901 ath9k_dfs_init_debug(sc); 1796 ath9k_dfs_init_debug(sc);
1797 ath9k_tx99_init_debug(sc);
1902 1798
1903 debugfs_create_file("dma", S_IRUSR, sc->debug.debugfs_phy, sc, 1799 debugfs_create_file("dma", S_IRUSR, sc->debug.debugfs_phy, sc,
1904 &fops_dma); 1800 &fops_dma);
@@ -1974,15 +1870,6 @@ int ath9k_init_debug(struct ath_hw *ah)
1974 debugfs_create_file("btcoex", S_IRUSR, sc->debug.debugfs_phy, sc, 1870 debugfs_create_file("btcoex", S_IRUSR, sc->debug.debugfs_phy, sc,
1975 &fops_btcoex); 1871 &fops_btcoex);
1976#endif 1872#endif
1977 if (config_enabled(CONFIG_ATH9K_TX99) &&
1978 AR_SREV_9300_20_OR_LATER(ah)) {
1979 debugfs_create_file("tx99", S_IRUSR | S_IWUSR,
1980 sc->debug.debugfs_phy, sc,
1981 &fops_tx99);
1982 debugfs_create_file("tx99_power", S_IRUSR | S_IWUSR,
1983 sc->debug.debugfs_phy, sc,
1984 &fops_tx99_power);
1985 }
1986 1873
1987 return 0; 1874 return 0;
1988} 1875}
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 74f452c7b166..3d1739864350 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -627,7 +627,7 @@ chip_reset:
627#undef SCHED_INTR 627#undef SCHED_INTR
628} 628}
629 629
630static int ath_reset(struct ath_softc *sc) 630int ath_reset(struct ath_softc *sc)
631{ 631{
632 int r; 632 int r;
633 633
@@ -2373,134 +2373,6 @@ static void ath9k_channel_switch_beacon(struct ieee80211_hw *hw,
2373 sc->csa_vif = vif; 2373 sc->csa_vif = vif;
2374} 2374}
2375 2375
2376static void ath9k_tx99_stop(struct ath_softc *sc)
2377{
2378 struct ath_hw *ah = sc->sc_ah;
2379 struct ath_common *common = ath9k_hw_common(ah);
2380
2381 ath_drain_all_txq(sc);
2382 ath_startrecv(sc);
2383
2384 ath9k_hw_set_interrupts(ah);
2385 ath9k_hw_enable_interrupts(ah);
2386
2387 ieee80211_wake_queues(sc->hw);
2388
2389 kfree_skb(sc->tx99_skb);
2390 sc->tx99_skb = NULL;
2391 sc->tx99_state = false;
2392
2393 ath9k_hw_tx99_stop(sc->sc_ah);
2394 ath_dbg(common, XMIT, "TX99 stopped\n");
2395}
2396
2397static struct sk_buff *ath9k_build_tx99_skb(struct ath_softc *sc)
2398{
2399 static u8 PN9Data[] = {0xff, 0x87, 0xb8, 0x59, 0xb7, 0xa1, 0xcc, 0x24,
2400 0x57, 0x5e, 0x4b, 0x9c, 0x0e, 0xe9, 0xea, 0x50,
2401 0x2a, 0xbe, 0xb4, 0x1b, 0xb6, 0xb0, 0x5d, 0xf1,
2402 0xe6, 0x9a, 0xe3, 0x45, 0xfd, 0x2c, 0x53, 0x18,
2403 0x0c, 0xca, 0xc9, 0xfb, 0x49, 0x37, 0xe5, 0xa8,
2404 0x51, 0x3b, 0x2f, 0x61, 0xaa, 0x72, 0x18, 0x84,
2405 0x02, 0x23, 0x23, 0xab, 0x63, 0x89, 0x51, 0xb3,
2406 0xe7, 0x8b, 0x72, 0x90, 0x4c, 0xe8, 0xfb, 0xc0};
2407 u32 len = 1200;
2408 struct ieee80211_hw *hw = sc->hw;
2409 struct ieee80211_hdr *hdr;
2410 struct ieee80211_tx_info *tx_info;
2411 struct sk_buff *skb;
2412
2413 skb = alloc_skb(len, GFP_KERNEL);
2414 if (!skb)
2415 return NULL;
2416
2417 skb_put(skb, len);
2418
2419 memset(skb->data, 0, len);
2420
2421 hdr = (struct ieee80211_hdr *)skb->data;
2422 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA);
2423 hdr->duration_id = 0;
2424
2425 memcpy(hdr->addr1, hw->wiphy->perm_addr, ETH_ALEN);
2426 memcpy(hdr->addr2, hw->wiphy->perm_addr, ETH_ALEN);
2427 memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN);
2428
2429 hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);
2430
2431 tx_info = IEEE80211_SKB_CB(skb);
2432 memset(tx_info, 0, sizeof(*tx_info));
2433 tx_info->band = hw->conf.chandef.chan->band;
2434 tx_info->flags = IEEE80211_TX_CTL_NO_ACK;
2435 tx_info->control.vif = sc->tx99_vif;
2436
2437 memcpy(skb->data + sizeof(*hdr), PN9Data, sizeof(PN9Data));
2438
2439 return skb;
2440}
2441
2442void ath9k_tx99_deinit(struct ath_softc *sc)
2443{
2444 ath_reset(sc);
2445
2446 ath9k_ps_wakeup(sc);
2447 ath9k_tx99_stop(sc);
2448 ath9k_ps_restore(sc);
2449}
2450
2451int ath9k_tx99_init(struct ath_softc *sc)
2452{
2453 struct ieee80211_hw *hw = sc->hw;
2454 struct ath_hw *ah = sc->sc_ah;
2455 struct ath_common *common = ath9k_hw_common(ah);
2456 struct ath_tx_control txctl;
2457 int r;
2458
2459 if (sc->sc_flags & SC_OP_INVALID) {
2460 ath_err(common,
2461 "driver is in invalid state unable to use TX99");
2462 return -EINVAL;
2463 }
2464
2465 sc->tx99_skb = ath9k_build_tx99_skb(sc);
2466 if (!sc->tx99_skb)
2467 return -ENOMEM;
2468
2469 memset(&txctl, 0, sizeof(txctl));
2470 txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
2471
2472 ath_reset(sc);
2473
2474 ath9k_ps_wakeup(sc);
2475
2476 ath9k_hw_disable_interrupts(ah);
2477 atomic_set(&ah->intr_ref_cnt, -1);
2478 ath_drain_all_txq(sc);
2479 ath_stoprecv(sc);
2480
2481 sc->tx99_state = true;
2482
2483 ieee80211_stop_queues(hw);
2484
2485 if (sc->tx99_power == MAX_RATE_POWER + 1)
2486 sc->tx99_power = MAX_RATE_POWER;
2487
2488 ath9k_hw_tx99_set_txpower(ah, sc->tx99_power);
2489 r = ath9k_tx99_send(sc, sc->tx99_skb, &txctl);
2490 if (r) {
2491 ath_dbg(common, XMIT, "Failed to xmit TX99 skb\n");
2492 return r;
2493 }
2494
2495 ath_dbg(common, XMIT, "TX99 xmit started using %d ( %ddBm)\n",
2496 sc->tx99_power,
2497 sc->tx99_power / 2);
2498
2499 /* We leave the harware awake as it will be chugging on */
2500
2501 return 0;
2502}
2503
2504struct ieee80211_ops ath9k_ops = { 2376struct ieee80211_ops ath9k_ops = {
2505 .tx = ath9k_tx, 2377 .tx = ath9k_tx,
2506 .start = ath9k_start, 2378 .start = ath9k_start,
diff --git a/drivers/net/wireless/ath/ath9k/tx99.c b/drivers/net/wireless/ath/ath9k/tx99.c
new file mode 100644
index 000000000000..6668197c277c
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/tx99.c
@@ -0,0 +1,263 @@
1/*
2 * Copyright (c) 2013 Qualcomm Atheros, Inc.
3 *
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.
7 *
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.
15 */
16
17#include "ath9k.h"
18
19static void ath9k_tx99_stop(struct ath_softc *sc)
20{
21 struct ath_hw *ah = sc->sc_ah;
22 struct ath_common *common = ath9k_hw_common(ah);
23
24 ath_drain_all_txq(sc);
25 ath_startrecv(sc);
26
27 ath9k_hw_set_interrupts(ah);
28 ath9k_hw_enable_interrupts(ah);
29
30 ieee80211_wake_queues(sc->hw);
31
32 kfree_skb(sc->tx99_skb);
33 sc->tx99_skb = NULL;
34 sc->tx99_state = false;
35
36 ath9k_hw_tx99_stop(sc->sc_ah);
37 ath_dbg(common, XMIT, "TX99 stopped\n");
38}
39
40static struct sk_buff *ath9k_build_tx99_skb(struct ath_softc *sc)
41{
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};
50 u32 len = 1200;
51 struct ieee80211_hw *hw = sc->hw;
52 struct ieee80211_hdr *hdr;
53 struct ieee80211_tx_info *tx_info;
54 struct sk_buff *skb;
55
56 skb = alloc_skb(len, GFP_KERNEL);
57 if (!skb)
58 return NULL;
59
60 skb_put(skb, len);
61
62 memset(skb->data, 0, len);
63
64 hdr = (struct ieee80211_hdr *)skb->data;
65 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA);
66 hdr->duration_id = 0;
67
68 memcpy(hdr->addr1, hw->wiphy->perm_addr, ETH_ALEN);
69 memcpy(hdr->addr2, hw->wiphy->perm_addr, ETH_ALEN);
70 memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN);
71
72 hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);
73
74 tx_info = IEEE80211_SKB_CB(skb);
75 memset(tx_info, 0, sizeof(*tx_info));
76 tx_info->band = hw->conf.chandef.chan->band;
77 tx_info->flags = IEEE80211_TX_CTL_NO_ACK;
78 tx_info->control.vif = sc->tx99_vif;
79
80 memcpy(skb->data + sizeof(*hdr), PN9Data, sizeof(PN9Data));
81
82 return skb;
83}
84
85static void ath9k_tx99_deinit(struct ath_softc *sc)
86{
87 ath_reset(sc);
88
89 ath9k_ps_wakeup(sc);
90 ath9k_tx99_stop(sc);
91 ath9k_ps_restore(sc);
92}
93
94static int ath9k_tx99_init(struct ath_softc *sc)
95{
96 struct ieee80211_hw *hw = sc->hw;
97 struct ath_hw *ah = sc->sc_ah;
98 struct ath_common *common = ath9k_hw_common(ah);
99 struct ath_tx_control txctl;
100 int r;
101
102 if (sc->sc_flags & SC_OP_INVALID) {
103 ath_err(common,
104 "driver is in invalid state unable to use TX99");
105 return -EINVAL;
106 }
107
108 sc->tx99_skb = ath9k_build_tx99_skb(sc);
109 if (!sc->tx99_skb)
110 return -ENOMEM;
111
112 memset(&txctl, 0, sizeof(txctl));
113 txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
114
115 ath_reset(sc);
116
117 ath9k_ps_wakeup(sc);
118
119 ath9k_hw_disable_interrupts(ah);
120 atomic_set(&ah->intr_ref_cnt, -1);
121 ath_drain_all_txq(sc);
122 ath_stoprecv(sc);
123
124 sc->tx99_state = true;
125
126 ieee80211_stop_queues(hw);
127
128 if (sc->tx99_power == MAX_RATE_POWER + 1)
129 sc->tx99_power = MAX_RATE_POWER;
130
131 ath9k_hw_tx99_set_txpower(ah, sc->tx99_power);
132 r = ath9k_tx99_send(sc, sc->tx99_skb, &txctl);
133 if (r) {
134 ath_dbg(common, XMIT, "Failed to xmit TX99 skb\n");
135 return r;
136 }
137
138 ath_dbg(common, XMIT, "TX99 xmit started using %d ( %ddBm)\n",
139 sc->tx99_power,
140 sc->tx99_power / 2);
141
142 /* We leave the harware awake as it will be chugging on */
143
144 return 0;
145}
146
147static ssize_t read_file_tx99(struct file *file, char __user *user_buf,
148 size_t count, loff_t *ppos)
149{
150 struct ath_softc *sc = file->private_data;
151 char buf[3];
152 unsigned int len;
153
154 len = sprintf(buf, "%d\n", sc->tx99_state);
155 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
156}
157
158static ssize_t write_file_tx99(struct file *file, const char __user *user_buf,
159 size_t count, loff_t *ppos)
160{
161 struct ath_softc *sc = file->private_data;
162 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
163 char buf[32];
164 bool start;
165 ssize_t len;
166 int r;
167
168 if (sc->nvifs > 1)
169 return -EOPNOTSUPP;
170
171 len = min(count, sizeof(buf) - 1);
172 if (copy_from_user(buf, user_buf, len))
173 return -EFAULT;
174
175 if (strtobool(buf, &start))
176 return -EINVAL;
177
178 if (start == sc->tx99_state) {
179 if (!start)
180 return count;
181 ath_dbg(common, XMIT, "Resetting TX99\n");
182 ath9k_tx99_deinit(sc);
183 }
184
185 if (!start) {
186 ath9k_tx99_deinit(sc);
187 return count;
188 }
189
190 r = ath9k_tx99_init(sc);
191 if (r)
192 return r;
193
194 return count;
195}
196
197static const struct file_operations fops_tx99 = {
198 .read = read_file_tx99,
199 .write = write_file_tx99,
200 .open = simple_open,
201 .owner = THIS_MODULE,
202 .llseek = default_llseek,
203};
204
205static ssize_t read_file_tx99_power(struct file *file,
206 char __user *user_buf,
207 size_t count, loff_t *ppos)
208{
209 struct ath_softc *sc = file->private_data;
210 char buf[32];
211 unsigned int len;
212
213 len = sprintf(buf, "%d (%d dBm)\n",
214 sc->tx99_power,
215 sc->tx99_power / 2);
216
217 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
218}
219
220static ssize_t write_file_tx99_power(struct file *file,
221 const char __user *user_buf,
222 size_t count, loff_t *ppos)
223{
224 struct ath_softc *sc = file->private_data;
225 int r;
226 u8 tx_power;
227
228 r = kstrtou8_from_user(user_buf, count, 0, &tx_power);
229 if (r)
230 return r;
231
232 if (tx_power > MAX_RATE_POWER)
233 return -EINVAL;
234
235 sc->tx99_power = tx_power;
236
237 ath9k_ps_wakeup(sc);
238 ath9k_hw_tx99_set_txpower(sc->sc_ah, sc->tx99_power);
239 ath9k_ps_restore(sc);
240
241 return count;
242}
243
244static const struct file_operations fops_tx99_power = {
245 .read = read_file_tx99_power,
246 .write = write_file_tx99_power,
247 .open = simple_open,
248 .owner = THIS_MODULE,
249 .llseek = default_llseek,
250};
251
252void ath9k_tx99_init_debug(struct ath_softc *sc)
253{
254 if (!AR_SREV_9300_20_OR_LATER(sc->sc_ah))
255 return;
256
257 debugfs_create_file("tx99", S_IRUSR | S_IWUSR,
258 sc->debug.debugfs_phy, sc,
259 &fops_tx99);
260 debugfs_create_file("tx99_power", S_IRUSR | S_IWUSR,
261 sc->debug.debugfs_phy, sc,
262 &fops_tx99_power);
263}
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 09cdbcd09739..95f6c5a8ee12 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -2749,6 +2749,8 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
2749 } 2749 }
2750} 2750}
2751 2751
2752#ifdef CONFIG_ATH9K_TX99
2753
2752int ath9k_tx99_send(struct ath_softc *sc, struct sk_buff *skb, 2754int ath9k_tx99_send(struct ath_softc *sc, struct sk_buff *skb,
2753 struct ath_tx_control *txctl) 2755 struct ath_tx_control *txctl)
2754{ 2756{
@@ -2791,3 +2793,5 @@ int ath9k_tx99_send(struct ath_softc *sc, struct sk_buff *skb,
2791 2793
2792 return 0; 2794 return 0;
2793} 2795}
2796
2797#endif /* CONFIG_ATH9K_TX99 */