diff options
author | Sujith Manoharan <c_manoha@qca.qualcomm.com> | 2013-10-24 02:34:39 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2013-12-02 14:24:53 -0500 |
commit | ef6b19e40f525777a0052956bf7d9a1985f74993 (patch) | |
tree | b9fecb0348318be8f8be43763bbbed8a4f8cb5b6 | |
parent | 4dd3564030020f8beb8dc7bbfea05781648836d0 (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/Kconfig | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/Makefile | 4 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/ath9k.h | 20 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/debug.c | 115 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/main.c | 130 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/tx99.c | 263 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/xmit.c | 4 |
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 | ||
87 | config ATH9K_TX99 | 87 | config 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 | |||
13 | ath9k-$(CONFIG_ATH9K_AHB) += ahb.o | 13 | ath9k-$(CONFIG_ATH9K_AHB) += ahb.o |
14 | ath9k-$(CONFIG_ATH9K_DEBUGFS) += debug.o | 14 | ath9k-$(CONFIG_ATH9K_DEBUGFS) += debug.o |
15 | ath9k-$(CONFIG_ATH9K_DFS_DEBUGFS) += dfs_debug.o | 15 | ath9k-$(CONFIG_ATH9K_DFS_DEBUGFS) += dfs_debug.o |
16 | ath9k-$(CONFIG_ATH9K_DFS_CERTIFIED) += \ | 16 | ath9k-$(CONFIG_ATH9K_DFS_CERTIFIED) += dfs.o |
17 | dfs.o | ||
18 | ath9k-$(CONFIG_PM_SLEEP) += wow.o | 17 | ath9k-$(CONFIG_PM_SLEEP) += wow.o |
18 | ath9k-$(CONFIG_ATH9K_TX99) += tx99.o | ||
19 | 19 | ||
20 | obj-$(CONFIG_ATH9K) += ath9k.o | 20 | obj-$(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 | ||
951 | int ath9k_tx99_init(struct ath_softc *sc); | 951 | /********/ |
952 | void ath9k_tx99_deinit(struct ath_softc *sc); | 952 | /* TX99 */ |
953 | /********/ | ||
954 | |||
955 | #ifdef CONFIG_ATH9K_TX99 | ||
956 | void ath9k_tx99_init_debug(struct ath_softc *sc); | ||
953 | int ath9k_tx99_send(struct ath_softc *sc, struct sk_buff *skb, | 957 | int 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 | ||
960 | static inline void ath9k_tx99_init_debug(struct ath_softc *sc) | ||
961 | { | ||
962 | } | ||
963 | static 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 | ||
956 | void ath9k_tasklet(unsigned long data); | 971 | void ath9k_tasklet(unsigned long data); |
957 | int ath_cabq_update(struct ath_softc *); | 972 | int ath_cabq_update(struct ath_softc *); |
@@ -968,6 +983,7 @@ extern bool is_ath9k_unloaded; | |||
968 | 983 | ||
969 | u8 ath9k_parse_mpdudensity(u8 mpdudensity); | 984 | u8 ath9k_parse_mpdudensity(u8 mpdudensity); |
970 | irqreturn_t ath_isr(int irq, void *dev); | 985 | irqreturn_t ath_isr(int irq, void *dev); |
986 | int ath_reset(struct ath_softc *sc); | ||
971 | int ath9k_init_device(u16 devid, struct ath_softc *sc, | 987 | int 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); |
973 | void ath9k_deinit_device(struct ath_softc *sc); | 989 | void 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 | ||
1781 | static 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 | |||
1792 | static 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 | |||
1831 | static 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 | |||
1839 | static 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 | |||
1854 | static 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 | |||
1878 | static 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 | |||
1886 | int ath9k_init_debug(struct ath_hw *ah) | 1781 | int 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 | ||
630 | static int ath_reset(struct ath_softc *sc) | 630 | int 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 | ||
2376 | static 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 | |||
2397 | static 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 | |||
2442 | void 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 | |||
2451 | int 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 | |||
2504 | struct ieee80211_ops ath9k_ops = { | 2376 | struct 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 | |||
19 | static 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 | |||
40 | static 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 | |||
85 | static 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 | |||
94 | static 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 | |||
147 | static 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 | |||
158 | static 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 | |||
197 | static 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 | |||
205 | static 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 | |||
220 | static 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 | |||
244 | static 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 | |||
252 | void 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 | |||
2752 | int ath9k_tx99_send(struct ath_softc *sc, struct sk_buff *skb, | 2754 | int 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 */ | ||