Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright (c) 2013 Qualcomm Atheros, Inc.
0003  *
0004  * Permission to use, copy, modify, and/or distribute this software for any
0005  * purpose with or without fee is hereby granted, provided that the above
0006  * copyright notice and this permission notice appear in all copies.
0007  *
0008  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
0009  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
0010  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
0011  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
0012  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
0013  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
0014  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
0015  */
0016 
0017 #include "ath9k.h"
0018 
0019 static void ath9k_tx99_stop(struct ath_softc *sc)
0020 {
0021     struct ath_hw *ah = sc->sc_ah;
0022     struct ath_common *common = ath9k_hw_common(ah);
0023 
0024     ath_drain_all_txq(sc);
0025     ath_startrecv(sc);
0026 
0027     ath9k_hw_set_interrupts(ah);
0028     ath9k_hw_enable_interrupts(ah);
0029 
0030     ieee80211_wake_queues(sc->hw);
0031 
0032     kfree_skb(sc->tx99_skb);
0033     sc->tx99_skb = NULL;
0034     sc->tx99_state = false;
0035 
0036     ath9k_hw_tx99_stop(sc->sc_ah);
0037     ath_dbg(common, XMIT, "TX99 stopped\n");
0038 }
0039 
0040 static struct sk_buff *ath9k_build_tx99_skb(struct ath_softc *sc)
0041 {
0042     static u8 PN9Data[] = {0xff, 0x87, 0xb8, 0x59, 0xb7, 0xa1, 0xcc, 0x24,
0043                    0x57, 0x5e, 0x4b, 0x9c, 0x0e, 0xe9, 0xea, 0x50,
0044                    0x2a, 0xbe, 0xb4, 0x1b, 0xb6, 0xb0, 0x5d, 0xf1,
0045                    0xe6, 0x9a, 0xe3, 0x45, 0xfd, 0x2c, 0x53, 0x18,
0046                    0x0c, 0xca, 0xc9, 0xfb, 0x49, 0x37, 0xe5, 0xa8,
0047                    0x51, 0x3b, 0x2f, 0x61, 0xaa, 0x72, 0x18, 0x84,
0048                    0x02, 0x23, 0x23, 0xab, 0x63, 0x89, 0x51, 0xb3,
0049                    0xe7, 0x8b, 0x72, 0x90, 0x4c, 0xe8, 0xfb, 0xc0};
0050     u32 len = 1200;
0051     struct ieee80211_tx_rate *rate;
0052     struct ieee80211_hw *hw = sc->hw;
0053     struct ath_hw *ah = sc->sc_ah;
0054     struct ieee80211_hdr *hdr;
0055     struct ieee80211_tx_info *tx_info;
0056     struct sk_buff *skb;
0057     struct ath_vif *avp;
0058 
0059     skb = alloc_skb(len, GFP_KERNEL);
0060     if (!skb)
0061         return NULL;
0062 
0063     skb_put(skb, len);
0064 
0065     memset(skb->data, 0, len);
0066 
0067     hdr = (struct ieee80211_hdr *)skb->data;
0068     hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA);
0069     hdr->duration_id = 0;
0070 
0071     memcpy(hdr->addr1, hw->wiphy->perm_addr, ETH_ALEN);
0072     memcpy(hdr->addr2, hw->wiphy->perm_addr, ETH_ALEN);
0073     memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN);
0074 
0075     if (sc->tx99_vif) {
0076         avp = (struct ath_vif *) sc->tx99_vif->drv_priv;
0077         hdr->seq_ctrl |= cpu_to_le16(avp->seq_no);
0078     }
0079 
0080     tx_info = IEEE80211_SKB_CB(skb);
0081     memset(tx_info, 0, sizeof(*tx_info));
0082     rate = &tx_info->control.rates[0];
0083     tx_info->band = sc->cur_chan->chandef.chan->band;
0084     tx_info->flags = IEEE80211_TX_CTL_NO_ACK;
0085     tx_info->control.vif = sc->tx99_vif;
0086     rate->count = 1;
0087     if (ah->curchan && IS_CHAN_HT(ah->curchan)) {
0088         rate->flags |= IEEE80211_TX_RC_MCS;
0089         if (IS_CHAN_HT40(ah->curchan))
0090             rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
0091     }
0092 
0093     memcpy(skb->data + sizeof(*hdr), PN9Data, sizeof(PN9Data));
0094 
0095     return skb;
0096 }
0097 
0098 static void ath9k_tx99_deinit(struct ath_softc *sc)
0099 {
0100     ath_reset(sc, NULL);
0101 
0102     ath9k_ps_wakeup(sc);
0103     ath9k_tx99_stop(sc);
0104     ath9k_ps_restore(sc);
0105 }
0106 
0107 static int ath9k_tx99_init(struct ath_softc *sc)
0108 {
0109     struct ieee80211_hw *hw = sc->hw;
0110     struct ath_hw *ah = sc->sc_ah;
0111     struct ath_common *common = ath9k_hw_common(ah);
0112     struct ath_tx_control txctl;
0113     int r;
0114 
0115     if (test_bit(ATH_OP_INVALID, &common->op_flags)) {
0116         ath_err(common,
0117             "driver is in invalid state unable to use TX99");
0118         return -EINVAL;
0119     }
0120 
0121     sc->tx99_skb = ath9k_build_tx99_skb(sc);
0122     if (!sc->tx99_skb)
0123         return -ENOMEM;
0124 
0125     memset(&txctl, 0, sizeof(txctl));
0126     txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
0127 
0128     ath_reset(sc, NULL);
0129 
0130     ath9k_ps_wakeup(sc);
0131 
0132     ath9k_hw_disable_interrupts(ah);
0133     ath_drain_all_txq(sc);
0134     ath_stoprecv(sc);
0135 
0136     sc->tx99_state = true;
0137 
0138     ieee80211_stop_queues(hw);
0139 
0140     if (sc->tx99_power == MAX_RATE_POWER + 1)
0141         sc->tx99_power = MAX_RATE_POWER;
0142 
0143     ath9k_hw_tx99_set_txpower(ah, sc->tx99_power);
0144     r = ath9k_tx99_send(sc, sc->tx99_skb, &txctl);
0145     if (r) {
0146         ath_dbg(common, XMIT, "Failed to xmit TX99 skb\n");
0147         return r;
0148     }
0149 
0150     ath_dbg(common, XMIT, "TX99 xmit started using %d ( %ddBm)\n",
0151         sc->tx99_power,
0152         sc->tx99_power / 2);
0153 
0154     /* We leave the hardware awake as it will be chugging on */
0155 
0156     return 0;
0157 }
0158 
0159 static ssize_t read_file_tx99(struct file *file, char __user *user_buf,
0160                   size_t count, loff_t *ppos)
0161 {
0162     struct ath_softc *sc = file->private_data;
0163     char buf[3];
0164     unsigned int len;
0165 
0166     len = sprintf(buf, "%d\n", sc->tx99_state);
0167     return simple_read_from_buffer(user_buf, count, ppos, buf, len);
0168 }
0169 
0170 static ssize_t write_file_tx99(struct file *file, const char __user *user_buf,
0171                    size_t count, loff_t *ppos)
0172 {
0173     struct ath_softc *sc = file->private_data;
0174     struct ath_common *common = ath9k_hw_common(sc->sc_ah);
0175     char buf[32];
0176     bool start;
0177     ssize_t len;
0178     int r;
0179 
0180     if (count < 1)
0181         return -EINVAL;
0182 
0183     if (sc->cur_chan->nvifs > 1)
0184         return -EOPNOTSUPP;
0185 
0186     len = min(count, sizeof(buf) - 1);
0187     if (copy_from_user(buf, user_buf, len))
0188         return -EFAULT;
0189 
0190     buf[len] = '\0';
0191 
0192     if (strtobool(buf, &start))
0193         return -EINVAL;
0194 
0195     mutex_lock(&sc->mutex);
0196 
0197     if (start == sc->tx99_state) {
0198         if (!start)
0199             goto out;
0200         ath_dbg(common, XMIT, "Resetting TX99\n");
0201         ath9k_tx99_deinit(sc);
0202     }
0203 
0204     if (!start) {
0205         ath9k_tx99_deinit(sc);
0206         goto out;
0207     }
0208 
0209     r = ath9k_tx99_init(sc);
0210     if (r) {
0211         mutex_unlock(&sc->mutex);
0212         return r;
0213     }
0214 out:
0215     mutex_unlock(&sc->mutex);
0216     return count;
0217 }
0218 
0219 static const struct file_operations fops_tx99 = {
0220     .read = read_file_tx99,
0221     .write = write_file_tx99,
0222     .open = simple_open,
0223     .owner = THIS_MODULE,
0224     .llseek = default_llseek,
0225 };
0226 
0227 static ssize_t read_file_tx99_power(struct file *file,
0228                     char __user *user_buf,
0229                     size_t count, loff_t *ppos)
0230 {
0231     struct ath_softc *sc = file->private_data;
0232     char buf[32];
0233     unsigned int len;
0234 
0235     len = sprintf(buf, "%d (%d dBm)\n",
0236               sc->tx99_power,
0237               sc->tx99_power / 2);
0238 
0239     return simple_read_from_buffer(user_buf, count, ppos, buf, len);
0240 }
0241 
0242 static ssize_t write_file_tx99_power(struct file *file,
0243                      const char __user *user_buf,
0244                      size_t count, loff_t *ppos)
0245 {
0246     struct ath_softc *sc = file->private_data;
0247     int r;
0248     u8 tx_power;
0249 
0250     r = kstrtou8_from_user(user_buf, count, 0, &tx_power);
0251     if (r)
0252         return r;
0253 
0254     if (tx_power > MAX_RATE_POWER)
0255         return -EINVAL;
0256 
0257     sc->tx99_power = tx_power;
0258 
0259     ath9k_ps_wakeup(sc);
0260     ath9k_hw_tx99_set_txpower(sc->sc_ah, sc->tx99_power);
0261     ath9k_ps_restore(sc);
0262 
0263     return count;
0264 }
0265 
0266 static const struct file_operations fops_tx99_power = {
0267     .read = read_file_tx99_power,
0268     .write = write_file_tx99_power,
0269     .open = simple_open,
0270     .owner = THIS_MODULE,
0271     .llseek = default_llseek,
0272 };
0273 
0274 void ath9k_tx99_init_debug(struct ath_softc *sc)
0275 {
0276     if (!AR_SREV_9280_20_OR_LATER(sc->sc_ah))
0277         return;
0278 
0279     debugfs_create_file("tx99", 0600,
0280                 sc->debug.debugfs_phy, sc,
0281                 &fops_tx99);
0282     debugfs_create_file("tx99_power", 0600,
0283                 sc->debug.debugfs_phy, sc,
0284                 &fops_tx99_power);
0285 }