++ fft_sample_20.noise = ah->noise;
++
++ mag_info = ((struct ath_ht20_mag_info *)radar_info) - 1;
++ magnitude = spectral_max_magnitude(mag_info->all_bins);
++ fft_sample_20.max_magnitude = __cpu_to_be16(magnitude);
++ max_index = spectral_max_index(mag_info->all_bins);
++ fft_sample_20.max_index = max_index;
++ bitmap_w = spectral_bitmap_weight(mag_info->all_bins);
++ fft_sample_20.bitmap_weight = bitmap_w;
++ fft_sample_20.max_exp = mag_info->max_exp & 0xf;
++
++ fft_sample_20.tsf = __cpu_to_be64(tsf);
++
++ tlv = (struct fft_sample_tlv *)&fft_sample_20;
++ }
++
++ ath_debug_send_fft_sample(sc, tlv);
++
++ return 1;
++}
++
++/*********************/
++/* spectral_scan_ctl */
++/*********************/
++
++static ssize_t read_file_spec_scan_ctl(struct file *file, char __user *user_buf,
++ size_t count, loff_t *ppos)
++{
++ struct ath_softc *sc = file->private_data;
++ char *mode = "";
++ unsigned int len;
++
++ switch (sc->spectral_mode) {
++ case SPECTRAL_DISABLED:
++ mode = "disable";
++ break;
++ case SPECTRAL_BACKGROUND:
++ mode = "background";
++ break;
++ case SPECTRAL_CHANSCAN:
++ mode = "chanscan";
++ break;
++ case SPECTRAL_MANUAL:
++ mode = "manual";
++ break;
++ }
++ len = strlen(mode);
++ return simple_read_from_buffer(user_buf, count, ppos, mode, len);
++}
++
++static ssize_t write_file_spec_scan_ctl(struct file *file,
++ const char __user *user_buf,
++ size_t count, loff_t *ppos)
++{
++ struct ath_softc *sc = file->private_data;
++ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
++ char buf[32];
++ ssize_t len;
++
++ if (config_enabled(CPTCFG_ATH9K_TX99))
++ return -EOPNOTSUPP;
++
++ len = min(count, sizeof(buf) - 1);
++ if (copy_from_user(buf, user_buf, len))
++ return -EFAULT;
++
++ buf[len] = '\0';
++
++ if (strncmp("trigger", buf, 7) == 0) {
++ ath9k_spectral_scan_trigger(sc->hw);
++ } else if (strncmp("background", buf, 9) == 0) {
++ ath9k_spectral_scan_config(sc->hw, SPECTRAL_BACKGROUND);
++ ath_dbg(common, CONFIG, "spectral scan: background mode enabled\n");
++ } else if (strncmp("chanscan", buf, 8) == 0) {
++ ath9k_spectral_scan_config(sc->hw, SPECTRAL_CHANSCAN);
++ ath_dbg(common, CONFIG, "spectral scan: channel scan mode enabled\n");
++ } else if (strncmp("manual", buf, 6) == 0) {
++ ath9k_spectral_scan_config(sc->hw, SPECTRAL_MANUAL);
++ ath_dbg(common, CONFIG, "spectral scan: manual mode enabled\n");
++ } else if (strncmp("disable", buf, 7) == 0) {
++ ath9k_spectral_scan_config(sc->hw, SPECTRAL_DISABLED);
++ ath_dbg(common, CONFIG, "spectral scan: disabled\n");
++ } else {
++ return -EINVAL;
++ }
++
++ return count;
++}
++
++static const struct file_operations fops_spec_scan_ctl = {
++ .read = read_file_spec_scan_ctl,
++ .write = write_file_spec_scan_ctl,
++ .open = simple_open,
++ .owner = THIS_MODULE,
++ .llseek = default_llseek,
++};
++
++/*************************/
++/* spectral_short_repeat */
++/*************************/
++
++static ssize_t read_file_spectral_short_repeat(struct file *file,
++ char __user *user_buf,
++ size_t count, loff_t *ppos)
++{
++ struct ath_softc *sc = file->private_data;
++ char buf[32];
++ unsigned int len;
++
++ len = sprintf(buf, "%d\n", sc->spec_config.short_repeat);
++ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
++}
++
++static ssize_t write_file_spectral_short_repeat(struct file *file,
++ const char __user *user_buf,
++ size_t count, loff_t *ppos)
++{
++ struct ath_softc *sc = file->private_data;
++ unsigned long val;
++ char buf[32];
++ ssize_t len;
++
++ len = min(count, sizeof(buf) - 1);
++ if (copy_from_user(buf, user_buf, len))
++ return -EFAULT;
++
++ buf[len] = '\0';
++ if (kstrtoul(buf, 0, &val))
++ return -EINVAL;
++
++ if (val < 0 || val > 1)
++ return -EINVAL;
++
++ sc->spec_config.short_repeat = val;
++ return count;
++}
++
++static const struct file_operations fops_spectral_short_repeat = {
++ .read = read_file_spectral_short_repeat,
++ .write = write_file_spectral_short_repeat,
++ .open = simple_open,
++ .owner = THIS_MODULE,
++ .llseek = default_llseek,
++};
++
++/******************/
++/* spectral_count */
++/******************/
++
++static ssize_t read_file_spectral_count(struct file *file,
++ char __user *user_buf,
++ size_t count, loff_t *ppos)
++{
++ struct ath_softc *sc = file->private_data;
++ char buf[32];
++ unsigned int len;
++
++ len = sprintf(buf, "%d\n", sc->spec_config.count);
++ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
++}
++
++static ssize_t write_file_spectral_count(struct file *file,
++ const char __user *user_buf,
++ size_t count, loff_t *ppos)
++{
++ struct ath_softc *sc = file->private_data;
++ unsigned long val;
++ char buf[32];
++ ssize_t len;
++
++ len = min(count, sizeof(buf) - 1);
++ if (copy_from_user(buf, user_buf, len))
++ return -EFAULT;
++
++ buf[len] = '\0';
++ if (kstrtoul(buf, 0, &val))
++ return -EINVAL;
++
++ if (val < 0 || val > 255)
++ return -EINVAL;
++
++ sc->spec_config.count = val;
++ return count;
++}
++
++static const struct file_operations fops_spectral_count = {
++ .read = read_file_spectral_count,
++ .write = write_file_spectral_count,
++ .open = simple_open,
++ .owner = THIS_MODULE,
++ .llseek = default_llseek,
++};
++
++/*******************/
++/* spectral_period */
++/*******************/
++
++static ssize_t read_file_spectral_period(struct file *file,
++ char __user *user_buf,
++ size_t count, loff_t *ppos)
++{
++ struct ath_softc *sc = file->private_data;
++ char buf[32];
++ unsigned int len;
++
++ len = sprintf(buf, "%d\n", sc->spec_config.period);
++ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
++}
++
++static ssize_t write_file_spectral_period(struct file *file,
++ const char __user *user_buf,
++ size_t count, loff_t *ppos)
++{
++ struct ath_softc *sc = file->private_data;
++ unsigned long val;
++ char buf[32];
++ ssize_t len;
++
++ len = min(count, sizeof(buf) - 1);
++ if (copy_from_user(buf, user_buf, len))
++ return -EFAULT;
++
++ buf[len] = '\0';
++ if (kstrtoul(buf, 0, &val))
++ return -EINVAL;
++
++ if (val < 0 || val > 255)
++ return -EINVAL;
++
++ sc->spec_config.period = val;
++ return count;
++}
++
++static const struct file_operations fops_spectral_period = {
++ .read = read_file_spectral_period,
++ .write = write_file_spectral_period,
++ .open = simple_open,
++ .owner = THIS_MODULE,
++ .llseek = default_llseek,
++};
++
++/***********************/
++/* spectral_fft_period */
++/***********************/
++
++static ssize_t read_file_spectral_fft_period(struct file *file,
++ char __user *user_buf,
++ size_t count, loff_t *ppos)
++{
++ struct ath_softc *sc = file->private_data;
++ char buf[32];
++ unsigned int len;
++
++ len = sprintf(buf, "%d\n", sc->spec_config.fft_period);
++ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
++}
++
++static ssize_t write_file_spectral_fft_period(struct file *file,
++ const char __user *user_buf,
++ size_t count, loff_t *ppos)
++{
++ struct ath_softc *sc = file->private_data;
++ unsigned long val;
++ char buf[32];
++ ssize_t len;
++
++ len = min(count, sizeof(buf) - 1);
++ if (copy_from_user(buf, user_buf, len))
++ return -EFAULT;
++
++ buf[len] = '\0';
++ if (kstrtoul(buf, 0, &val))
++ return -EINVAL;
++
++ if (val < 0 || val > 15)
++ return -EINVAL;
++
++ sc->spec_config.fft_period = val;
++ return count;
++}
++
++static const struct file_operations fops_spectral_fft_period = {
++ .read = read_file_spectral_fft_period,
++ .write = write_file_spectral_fft_period,
++ .open = simple_open,
++ .owner = THIS_MODULE,
++ .llseek = default_llseek,
++};
++
++/*******************/
++/* Relay interface */
++/*******************/
++
++static struct dentry *create_buf_file_handler(const char *filename,
++ struct dentry *parent,
++ umode_t mode,
++ struct rchan_buf *buf,
++ int *is_global)
++{
++ struct dentry *buf_file;
++
++ buf_file = debugfs_create_file(filename, mode, parent, buf,
++ &relay_file_operations);
++ *is_global = 1;
++ return buf_file;
++}
++
++static int remove_buf_file_handler(struct dentry *dentry)
++{
++ debugfs_remove(dentry);
++
++ return 0;
++}
++
++struct rchan_callbacks rfs_spec_scan_cb = {
++ .create_buf_file = create_buf_file_handler,
++ .remove_buf_file = remove_buf_file_handler,
++};
++
++/*********************/
++/* Debug Init/Deinit */
++/*********************/
++
++void ath9k_spectral_deinit_debug(struct ath_softc *sc)
++{
++ if (config_enabled(CPTCFG_ATH9K_DEBUGFS) && sc->rfs_chan_spec_scan) {
++ relay_close(sc->rfs_chan_spec_scan);
++ sc->rfs_chan_spec_scan = NULL;
++ }
++}
++
++void ath9k_spectral_init_debug(struct ath_softc *sc)
++{
++ sc->rfs_chan_spec_scan = relay_open("spectral_scan",
++ sc->debug.debugfs_phy,
++ 1024, 256, &rfs_spec_scan_cb,
++ NULL);
++ debugfs_create_file("spectral_scan_ctl",
++ S_IRUSR | S_IWUSR,
++ sc->debug.debugfs_phy, sc,
++ &fops_spec_scan_ctl);
++ debugfs_create_file("spectral_short_repeat",
++ S_IRUSR | S_IWUSR,
++ sc->debug.debugfs_phy, sc,
++ &fops_spectral_short_repeat);
++ debugfs_create_file("spectral_count",
++ S_IRUSR | S_IWUSR,
++ sc->debug.debugfs_phy, sc,
++ &fops_spectral_count);
++ debugfs_create_file("spectral_period",
++ S_IRUSR | S_IWUSR,
++ sc->debug.debugfs_phy, sc,
++ &fops_spectral_period);
++ debugfs_create_file("spectral_fft_period",
++ S_IRUSR | S_IWUSR,
++ sc->debug.debugfs_phy, sc,
++ &fops_spectral_fft_period);
++}
+--- /dev/null
++++ b/drivers/net/wireless/ath/ath9k/spectral.h
+@@ -0,0 +1,212 @@
++/*
++ * Copyright (c) 2013 Qualcomm Atheros, Inc.
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++ */
++
++#ifndef SPECTRAL_H
++#define SPECTRAL_H
++
++/* enum spectral_mode:
++ *
++ * @SPECTRAL_DISABLED: spectral mode is disabled
++ * @SPECTRAL_BACKGROUND: hardware sends samples when it is not busy with
++ * something else.
++ * @SPECTRAL_MANUAL: spectral scan is enabled, triggering for samples
++ * is performed manually.
++ * @SPECTRAL_CHANSCAN: Like manual, but also triggered when changing channels
++ * during a channel scan.
++ */
++enum spectral_mode {
++ SPECTRAL_DISABLED = 0,
++ SPECTRAL_BACKGROUND,
++ SPECTRAL_MANUAL,
++ SPECTRAL_CHANSCAN,
++};
++
++#define SPECTRAL_SCAN_BITMASK 0x10
++/* Radar info packet format, used for DFS and spectral formats. */
++struct ath_radar_info {
++ u8 pulse_length_pri;
++ u8 pulse_length_ext;
++ u8 pulse_bw_info;
++} __packed;
++
++/* The HT20 spectral data has 4 bytes of additional information at it's end.
++ *
++ * [7:0]: all bins {max_magnitude[1:0], bitmap_weight[5:0]}
++ * [7:0]: all bins max_magnitude[9:2]
++ * [7:0]: all bins {max_index[5:0], max_magnitude[11:10]}
++ * [3:0]: max_exp (shift amount to size max bin to 8-bit unsigned)
++ */
++struct ath_ht20_mag_info {
++ u8 all_bins[3];
++ u8 max_exp;
++} __packed;
++
++#define SPECTRAL_HT20_NUM_BINS 56
++
++/* WARNING: don't actually use this struct! MAC may vary the amount of
++ * data by -1/+2. This struct is for reference only.
++ */
++struct ath_ht20_fft_packet {
++ u8 data[SPECTRAL_HT20_NUM_BINS];
++ struct ath_ht20_mag_info mag_info;
++ struct ath_radar_info radar_info;
++} __packed;
++
++#define SPECTRAL_HT20_TOTAL_DATA_LEN (sizeof(struct ath_ht20_fft_packet))
++
++/* Dynamic 20/40 mode:
++ *
++ * [7:0]: lower bins {max_magnitude[1:0], bitmap_weight[5:0]}
++ * [7:0]: lower bins max_magnitude[9:2]
++ * [7:0]: lower bins {max_index[5:0], max_magnitude[11:10]}
++ * [7:0]: upper bins {max_magnitude[1:0], bitmap_weight[5:0]}
++ * [7:0]: upper bins max_magnitude[9:2]
++ * [7:0]: upper bins {max_index[5:0], max_magnitude[11:10]}
++ * [3:0]: max_exp (shift amount to size max bin to 8-bit unsigned)
++ */
++struct ath_ht20_40_mag_info {
++ u8 lower_bins[3];
++ u8 upper_bins[3];
++ u8 max_exp;
++} __packed;
++
++#define SPECTRAL_HT20_40_NUM_BINS 128
++
++/* WARNING: don't actually use this struct! MAC may vary the amount of
++ * data. This struct is for reference only.
++ */
++struct ath_ht20_40_fft_packet {
++ u8 data[SPECTRAL_HT20_40_NUM_BINS];
++ struct ath_ht20_40_mag_info mag_info;
++ struct ath_radar_info radar_info;
++} __packed;
++
++
++#define SPECTRAL_HT20_40_TOTAL_DATA_LEN (sizeof(struct ath_ht20_40_fft_packet))
++
++/* grabs the max magnitude from the all/upper/lower bins */
++static inline u16 spectral_max_magnitude(u8 *bins)
++{
++ return (bins[0] & 0xc0) >> 6 |
++ (bins[1] & 0xff) << 2 |
++ (bins[2] & 0x03) << 10;
++}
++
++/* return the max magnitude from the all/upper/lower bins */
++static inline u8 spectral_max_index(u8 *bins)
++{
++ s8 m = (bins[2] & 0xfc) >> 2;
++
++ /* TODO: this still doesn't always report the right values ... */
++ if (m > 32)
++ m |= 0xe0;
++ else
++ m &= ~0xe0;
++
++ return m + 29;
++}
++
++/* return the bitmap weight from the all/upper/lower bins */
++static inline u8 spectral_bitmap_weight(u8 *bins)
++{
++ return bins[0] & 0x3f;
++}
++
++/* FFT sample format given to userspace via debugfs.
++ *
++ * Please keep the type/length at the front position and change
++ * other fields after adding another sample type
++ *
++ * TODO: this might need rework when switching to nl80211-based
++ * interface.
++ */
++enum ath_fft_sample_type {
++ ATH_FFT_SAMPLE_HT20 = 1,
++ ATH_FFT_SAMPLE_HT20_40,
++};
++
++struct fft_sample_tlv {
++ u8 type; /* see ath_fft_sample */
++ __be16 length;
++ /* type dependent data follows */
++} __packed;
++
++struct fft_sample_ht20 {
++ struct fft_sample_tlv tlv;
++
++ u8 max_exp;
++
++ __be16 freq;
++ s8 rssi;
++ s8 noise;
++
++ __be16 max_magnitude;
++ u8 max_index;
++ u8 bitmap_weight;
++
++ __be64 tsf;
++
++ u8 data[SPECTRAL_HT20_NUM_BINS];
++} __packed;
++
++struct fft_sample_ht20_40 {
++ struct fft_sample_tlv tlv;
++
++ u8 channel_type;
++ __be16 freq;
++
++ s8 lower_rssi;
++ s8 upper_rssi;
++
++ __be64 tsf;
++
++ s8 lower_noise;
++ s8 upper_noise;
++
++ __be16 lower_max_magnitude;
++ __be16 upper_max_magnitude;
++
++ u8 lower_max_index;
++ u8 upper_max_index;
++
++ u8 lower_bitmap_weight;
++ u8 upper_bitmap_weight;
++
++ u8 max_exp;
++
++ u8 data[SPECTRAL_HT20_40_NUM_BINS];
++} __packed;
++
++void ath9k_spectral_init_debug(struct ath_softc *sc);
++void ath9k_spectral_deinit_debug(struct ath_softc *sc);
++
++void ath9k_spectral_scan_trigger(struct ieee80211_hw *hw);
++int ath9k_spectral_scan_config(struct ieee80211_hw *hw,
++ enum spectral_mode spectral_mode);
++
++#ifdef CPTCFG_ATH9K_DEBUGFS
++int ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr,
++ struct ath_rx_status *rs, u64 tsf);
++#else
++static inline int ath_process_fft(struct ath_softc *sc,
++ struct ieee80211_hdr *hdr,
++ struct ath_rx_status *rs, u64 tsf)
++{
++ return 0;
++}
++#endif /* CPTCFG_ATH9K_DEBUGFS */
++
++#endif /* SPECTRAL_H */
+--- a/include/net/mac80211.h
++++ b/include/net/mac80211.h
+@@ -1566,6 +1566,9 @@ enum ieee80211_hw_flags {
+ * @extra_tx_headroom: headroom to reserve in each transmit skb
+ * for use by the driver (e.g. for transmit headers.)
+ *
++ * @extra_beacon_tailroom: tailroom to reserve in each beacon tx skb.
++ * Can be used by drivers to add extra IEs.
++ *
+ * @channel_change_time: time (in microseconds) it takes to change channels.
+ *
+ * @max_signal: Maximum value for signal (rssi) in RX information, used
+@@ -1644,6 +1647,7 @@ struct ieee80211_hw {
+ void *priv;
+ u32 flags;
+ unsigned int extra_tx_headroom;
++ unsigned int extra_beacon_tailroom;
+ int channel_change_time;
+ int vif_data_size;
+ int sta_data_size;
+@@ -4595,4 +4599,49 @@ bool ieee80211_tx_prepare_skb(struct iee
+ struct ieee80211_vif *vif, struct sk_buff *skb,
+ int band, struct ieee80211_sta **sta);
+
++/**
++ * struct ieee80211_noa_data - holds temporary data for tracking P2P NoA state
++ *
++ * @next_tsf: TSF timestamp of the next absent state change
++ * @has_next_tsf: next absent state change event pending
++ *
++ * @absent: descriptor bitmask, set if GO is currently absent
++ *
++ * private:
++ *
++ * @count: count fields from the NoA descriptors
++ * @desc: adjusted data from the NoA
++ */
++struct ieee80211_noa_data {
++ u32 next_tsf;
++ bool has_next_tsf;
++
++ u8 absent;
++
++ u8 count[IEEE80211_P2P_NOA_DESC_MAX];
++ struct {
++ u32 start;
++ u32 duration;
++ u32 interval;
++ } desc[IEEE80211_P2P_NOA_DESC_MAX];
++};
++
++/**
++ * ieee80211_parse_p2p_noa - initialize NoA tracking data from P2P IE
++ *
++ * @attr: P2P NoA IE
++ * @data: NoA tracking data
++ * @tsf: current TSF timestamp
++ */
++int ieee80211_parse_p2p_noa(const struct ieee80211_p2p_noa_attr *attr,
++ struct ieee80211_noa_data *data, u32 tsf);
++
++/**
++ * ieee80211_update_p2p_noa - get next pending P2P GO absent state change
++ *
++ * @data: NoA tracking data
++ * @tsf: current TSF timestamp
++ */
++void ieee80211_update_p2p_noa(struct ieee80211_noa_data *data, u32 tsf);
++
+ #endif /* MAC80211_H */
+--- a/drivers/net/wireless/ath/ath9k/hw-ops.h
++++ b/drivers/net/wireless/ath/ath9k/hw-ops.h
+@@ -49,9 +49,10 @@ static inline bool ath9k_hw_calibrate(st
+ return ath9k_hw_ops(ah)->calibrate(ah, chan, rxchainmask, longcal);
+ }
+
+-static inline bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked)
++static inline bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked,
++ u32 *sync_cause_p)
+ {
+- return ath9k_hw_ops(ah)->get_isr(ah, masked);
++ return ath9k_hw_ops(ah)->get_isr(ah, masked, sync_cause_p);
+ }