diff options
author | John W. Linville <linville@tuxdriver.com> | 2013-02-08 22:16:17 +0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2013-02-08 22:16:17 +0400 |
commit | f5237f278f30a92401539a54f87ee0c717b6f818 (patch) | |
tree | 209d4fd6fb00e660c76ca8ac5d4caed59dbb9957 /drivers/net/wireless/ath | |
parent | b285109dde7b873b5dc671ef1b3ae3090f4bc72f (diff) | |
parent | b26f5f09ebdeb85ab152344cc1d6d484a3ce967d (diff) | |
download | linux-f5237f278f30a92401539a54f87ee0c717b6f818.tar.xz |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next into for-davem
Diffstat (limited to 'drivers/net/wireless/ath')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/Kconfig | 1 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/ath9k.h | 17 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/debug.c | 193 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/debug.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/init.c | 9 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/mac.c | 8 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/main.c | 23 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/mci.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/recv.c | 80 | ||||
-rw-r--r-- | drivers/net/wireless/ath/wil6210/cfg80211.c | 9 | ||||
-rw-r--r-- | drivers/net/wireless/ath/wil6210/interrupt.c | 55 | ||||
-rw-r--r-- | drivers/net/wireless/ath/wil6210/main.c | 63 | ||||
-rw-r--r-- | drivers/net/wireless/ath/wil6210/netdev.c | 31 | ||||
-rw-r--r-- | drivers/net/wireless/ath/wil6210/pcie_bus.c | 4 | ||||
-rw-r--r-- | drivers/net/wireless/ath/wil6210/txrx.c | 107 | ||||
-rw-r--r-- | drivers/net/wireless/ath/wil6210/wil6210.h | 22 | ||||
-rw-r--r-- | drivers/net/wireless/ath/wil6210/wmi.c | 107 |
17 files changed, 477 insertions, 256 deletions
diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig index 7647ed6b73d7..17507dc8a1e7 100644 --- a/drivers/net/wireless/ath/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig @@ -58,6 +58,7 @@ config ATH9K_DEBUGFS bool "Atheros ath9k debugging" depends on ATH9K select MAC80211_DEBUGFS + select RELAY ---help--- Say Y, if you need access to ath9k's statistics for interrupts, rate control, etc. diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index b2d6c18d1678..97c90b21e1cb 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -319,6 +319,8 @@ struct ath_rx { struct ath_rx_edma rx_edma[ATH9K_RX_QUEUE_MAX]; struct sk_buff *frag; + + u32 ampdu_ref; }; int ath_startrecv(struct ath_softc *sc); @@ -754,6 +756,7 @@ struct ath_softc { /* relay(fs) channel for spectral scan */ struct rchan *rfs_chan_spec_scan; enum spectral_mode spectral_mode; + struct ath_spec_scan spec_config; int scanning; #ifdef CONFIG_PM_SLEEP @@ -863,31 +866,31 @@ static inline u8 spectral_bitmap_weight(u8 *bins) * interface. */ enum ath_fft_sample_type { - ATH_FFT_SAMPLE_HT20 = 0, + ATH_FFT_SAMPLE_HT20 = 1, }; struct fft_sample_tlv { u8 type; /* see ath_fft_sample */ - u16 length; + __be16 length; /* type dependent data follows */ } __packed; struct fft_sample_ht20 { struct fft_sample_tlv tlv; - u8 __alignment; + u8 max_exp; - u16 freq; + __be16 freq; s8 rssi; s8 noise; - u16 max_magnitude; + __be16 max_magnitude; u8 max_index; u8 bitmap_weight; - u64 tsf; + __be64 tsf; - u16 data[SPECTRAL_HT20_NUM_BINS]; + u8 data[SPECTRAL_HT20_NUM_BINS]; } __packed; void ath9k_tasklet(unsigned long data); diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 6c5d313ebcb7..3714b971d18e 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -895,6 +895,7 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf, RXS_ERR("RX-Bytes-All", rx_bytes_all); RXS_ERR("RX-Beacons", rx_beacons); RXS_ERR("RX-Frags", rx_frags); + RXS_ERR("RX-Spectral", rx_spectral); if (len > size) len = size; @@ -1035,6 +1036,182 @@ static const struct file_operations fops_spec_scan_ctl = { .llseek = default_llseek, }; +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, +}; + +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, +}; + +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, +}; + +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, +}; + static struct dentry *create_buf_file_handler(const char *filename, struct dentry *parent, umode_t mode, @@ -1059,11 +1236,13 @@ static int remove_buf_file_handler(struct dentry *dentry) void ath_debug_send_fft_sample(struct ath_softc *sc, struct fft_sample_tlv *fft_sample_tlv) { + int length; if (!sc->rfs_chan_spec_scan) return; - relay_write(sc->rfs_chan_spec_scan, fft_sample_tlv, - fft_sample_tlv->length + sizeof(*fft_sample_tlv)); + length = __be16_to_cpu(fft_sample_tlv->length) + + sizeof(*fft_sample_tlv); + relay_write(sc->rfs_chan_spec_scan, fft_sample_tlv, length); } static struct rchan_callbacks rfs_spec_scan_cb = { @@ -1893,6 +2072,16 @@ int ath9k_init_debug(struct ath_hw *ah) 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); #ifdef CONFIG_ATH9K_MAC_DEBUG debugfs_create_file("samples", S_IRUSR, sc->debug.debugfs_phy, sc, diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index a22c0d780700..410d6d8f1aa7 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -219,6 +219,7 @@ struct ath_tx_stats { * @rx_too_many_frags_err: Frames dropped due to too-many-frags received. * @rx_beacons: No. of beacons received. * @rx_frags: No. of rx-fragements received. + * @rx_spectral: No of spectral packets received. */ struct ath_rx_stats { u32 rx_pkts_all; @@ -237,6 +238,7 @@ struct ath_rx_stats { u32 rx_too_many_frags_err; u32 rx_beacons; u32 rx_frags; + u32 rx_spectral; }; struct ath_stats { diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 4b1abc7da98c..af932c9444de 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -497,6 +497,13 @@ static void ath9k_init_misc(struct ath_softc *sc) if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) sc->ant_comb.count = ATH_ANT_DIV_COMB_INIT_COUNT; + + sc->spec_config.enabled = 0; + sc->spec_config.short_repeat = true; + sc->spec_config.count = 8; + sc->spec_config.endless = false; + sc->spec_config.period = 0xFF; + sc->spec_config.fft_period = 0xF; } static void ath9k_eeprom_request_cb(const struct firmware *eeprom_blob, @@ -915,7 +922,7 @@ static void ath9k_deinit_softc(struct ath_softc *sc) ath9k_eeprom_release(sc); - if (sc->rfs_chan_spec_scan) { + if (config_enabled(CONFIG_ATH9K_DEBUGFS) && sc->rfs_chan_spec_scan) { relay_close(sc->rfs_chan_spec_scan); sc->rfs_chan_spec_scan = NULL; } diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index b42be910a83d..811007ec07a7 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -605,13 +605,13 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds, * reported, then decryption and MIC errors are irrelevant, * the frame is going to be dropped either way */ - if (ads.ds_rxstatus8 & AR_CRCErr) - rs->rs_status |= ATH9K_RXERR_CRC; - else if (ads.ds_rxstatus8 & AR_PHYErr) { + if (ads.ds_rxstatus8 & AR_PHYErr) { rs->rs_status |= ATH9K_RXERR_PHY; phyerr = MS(ads.ds_rxstatus8, AR_PHYErrCode); rs->rs_phyerr = phyerr; - } else if (ads.ds_rxstatus8 & AR_DecryptCRCErr) + } else if (ads.ds_rxstatus8 & AR_CRCErr) + rs->rs_status |= ATH9K_RXERR_CRC; + else if (ads.ds_rxstatus8 & AR_DecryptCRCErr) rs->rs_status |= ATH9K_RXERR_DECRYPT; else if (ads.ds_rxstatus8 & AR_MichaelErr) rs->rs_status |= ATH9K_RXERR_MIC; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 4b72b660f180..5432f1247e2e 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1099,45 +1099,34 @@ int ath9k_spectral_scan_config(struct ieee80211_hw *hw, struct ath_softc *sc = hw->priv; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); - struct ath_spec_scan param; if (!ath9k_hw_ops(ah)->spectral_scan_trigger) { ath_err(common, "spectrum analyzer not implemented on this hardware\n"); return -1; } - /* NOTE: this will generate a few samples ... - * - * TODO: review default parameters, and/or define an interface to set - * them. - */ - param.enabled = 1; - param.short_repeat = true; - param.count = 8; - param.endless = false; - param.period = 0xFF; - param.fft_period = 0xF; - switch (spectral_mode) { case SPECTRAL_DISABLED: - param.enabled = 0; + sc->spec_config.enabled = 0; break; case SPECTRAL_BACKGROUND: /* send endless samples. * TODO: is this really useful for "background"? */ - param.endless = 1; + sc->spec_config.endless = 1; + sc->spec_config.enabled = 1; break; case SPECTRAL_CHANSCAN: - break; case SPECTRAL_MANUAL: + sc->spec_config.endless = 0; + sc->spec_config.enabled = 1; break; default: return -1; } ath9k_ps_wakeup(sc); - ath9k_hw_ops(ah)->spectral_scan_config(ah, ¶m); + ath9k_hw_ops(ah)->spectral_scan_config(ah, &sc->spec_config); ath9k_ps_restore(sc); sc->spectral_mode = spectral_mode; diff --git a/drivers/net/wireless/ath/ath9k/mci.c b/drivers/net/wireless/ath/ath9k/mci.c index d2074334ec9b..815bee21c19a 100644 --- a/drivers/net/wireless/ath/ath9k/mci.c +++ b/drivers/net/wireless/ath/ath9k/mci.c @@ -474,8 +474,6 @@ void ath_mci_cleanup(struct ath_softc *sc) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_hw *ah = sc->sc_ah; - struct ath_mci_coex *mci = &sc->mci_coex; - struct ath_mci_buf *buf = &mci->sched_buf; ar9003_mci_cleanup(ah); diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index d7c129bb571b..2d0fd17a1917 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -1016,18 +1016,20 @@ static void ath9k_rx_skb_postprocess(struct ath_common *common, rxs->flag &= ~RX_FLAG_DECRYPTED; } +#ifdef CONFIG_ATH9K_DEBUGFS static s8 fix_rssi_inv_only(u8 rssi_val) { if (rssi_val == 128) rssi_val = 0; return (s8) rssi_val; } +#endif - -static void ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr, - struct ath_rx_status *rs, u64 tsf) +/* returns 1 if this was a spectral frame, even if not handled. */ +static int ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr, + struct ath_rx_status *rs, u64 tsf) { -#ifdef CONFIG_ATH_DEBUG +#ifdef CONFIG_ATH9K_DEBUGFS struct ath_hw *ah = sc->sc_ah; u8 bins[SPECTRAL_HT20_NUM_BINS]; u8 *vdata = (u8 *)hdr; @@ -1035,7 +1037,8 @@ static void ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr, struct ath_radar_info *radar_info; struct ath_ht20_mag_info *mag_info; int len = rs->rs_datalen; - int i, dc_pos; + int dc_pos; + u16 length, max_magnitude; /* AR9280 and before report via ATH9K_PHYERR_RADAR, AR93xx and newer * via ATH9K_PHYERR_SPECTRAL. Haven't seen ATH9K_PHYERR_FALSE_RADAR_EXT @@ -1044,7 +1047,14 @@ static void ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr, if (rs->rs_phyerr != ATH9K_PHYERR_RADAR && rs->rs_phyerr != ATH9K_PHYERR_FALSE_RADAR_EXT && rs->rs_phyerr != ATH9K_PHYERR_SPECTRAL) - return; + return 0; + + /* check if spectral scan bit is set. This does not have to be checked + * if received through a SPECTRAL phy error, but shouldn't hurt. + */ + radar_info = ((struct ath_radar_info *)&vdata[len]) - 1; + if (!(radar_info->pulse_bw_info & SPECTRAL_SCAN_BITMASK)) + return 0; /* Variation in the data length is possible and will be fixed later. * Note that we only support HT20 for now. @@ -1053,19 +1063,13 @@ static void ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr, */ if ((len > SPECTRAL_HT20_TOTAL_DATA_LEN + 2) || (len < SPECTRAL_HT20_TOTAL_DATA_LEN - 1)) - return; - - /* check if spectral scan bit is set. This does not have to be checked - * if received through a SPECTRAL phy error, but shouldn't hurt. - */ - radar_info = ((struct ath_radar_info *)&vdata[len]) - 1; - if (!(radar_info->pulse_bw_info & SPECTRAL_SCAN_BITMASK)) - return; + return 1; fft_sample.tlv.type = ATH_FFT_SAMPLE_HT20; - fft_sample.tlv.length = sizeof(fft_sample) - sizeof(fft_sample.tlv); + length = sizeof(fft_sample) - sizeof(fft_sample.tlv); + fft_sample.tlv.length = __cpu_to_be16(length); - fft_sample.freq = ah->curchan->chan->center_freq; + fft_sample.freq = __cpu_to_be16(ah->curchan->chan->center_freq); fft_sample.rssi = fix_rssi_inv_only(rs->rs_rssi_ctl0); fft_sample.noise = ah->noise; @@ -1093,7 +1097,7 @@ static void ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr, memcpy(&bins[32], &vdata[33], SPECTRAL_HT20_NUM_BINS - 32); break; default: - return; + return 1; } /* DC value (value in the middle) is the blind spot of the spectral @@ -1105,19 +1109,41 @@ static void ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr, /* mag data is at the end of the frame, in front of radar_info */ mag_info = ((struct ath_ht20_mag_info *)radar_info) - 1; - /* Apply exponent and grab further auxiliary information. */ - for (i = 0; i < SPECTRAL_HT20_NUM_BINS; i++) - fft_sample.data[i] = bins[i] << mag_info->max_exp; + /* copy raw bins without scaling them */ + memcpy(fft_sample.data, bins, SPECTRAL_HT20_NUM_BINS); + fft_sample.max_exp = mag_info->max_exp & 0xf; - fft_sample.max_magnitude = spectral_max_magnitude(mag_info->all_bins); + max_magnitude = spectral_max_magnitude(mag_info->all_bins); + fft_sample.max_magnitude = __cpu_to_be16(max_magnitude); fft_sample.max_index = spectral_max_index(mag_info->all_bins); fft_sample.bitmap_weight = spectral_bitmap_weight(mag_info->all_bins); - fft_sample.tsf = tsf; + fft_sample.tsf = __cpu_to_be64(tsf); ath_debug_send_fft_sample(sc, &fft_sample.tlv); + return 1; +#else + return 0; #endif } +static void ath9k_apply_ampdu_details(struct ath_softc *sc, + struct ath_rx_status *rs, struct ieee80211_rx_status *rxs) +{ + if (rs->rs_isaggr) { + rxs->flag |= RX_FLAG_AMPDU_DETAILS | RX_FLAG_AMPDU_LAST_KNOWN; + + rxs->ampdu_reference = sc->rx.ampdu_ref; + + if (!rs->rs_moreaggr) { + rxs->flag |= RX_FLAG_AMPDU_IS_LAST; + sc->rx.ampdu_ref++; + } + + if (rs->rs_flags & ATH9K_RX_DELIM_CRC_PRE) + rxs->flag |= RX_FLAG_AMPDU_DELIM_CRC_ERROR; + } +} + int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) { struct ath_buf *bf; @@ -1202,8 +1228,12 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) unlikely(tsf_lower - rs.rs_tstamp > 0x10000000)) rxs->mactime += 0x100000000ULL; - if ((rs.rs_status & ATH9K_RXERR_PHY)) - ath_process_fft(sc, hdr, &rs, rxs->mactime); + if (rs.rs_status & ATH9K_RXERR_PHY) { + if (ath_process_fft(sc, hdr, &rs, rxs->mactime)) { + RX_STAT_INC(rx_spectral); + goto requeue_drop_frag; + } + } retval = ath9k_rx_skb_preprocess(common, hw, hdr, &rs, rxs, &decrypt_error); @@ -1320,6 +1350,8 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) if ((ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) && sc->ant_rx == 3) ath_ant_comb_scan(sc, &rs); + ath9k_apply_ampdu_details(sc, &rs, rxs); + ieee80211_rx(hw, skb); requeue_drop_frag: diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 116f4e807ae1..002851fceb2f 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -204,7 +204,6 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, break; default: return -EOPNOTSUPP; - } /* FW don't support scan after connection attempt */ @@ -228,8 +227,8 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, } /* 0-based channel indexes */ cmd.cmd.channel_list[cmd.cmd.num_channels++].channel = ch - 1; - wil_dbg(wil, "Scan for ch %d : %d MHz\n", ch, - request->channels[i]->center_freq); + wil_dbg_misc(wil, "Scan for ch %d : %d MHz\n", ch, + request->channels[i]->center_freq); } return wmi_send(wil, WMI_START_SCAN_CMDID, &cmd, sizeof(cmd.cmd) + @@ -425,8 +424,8 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, return -EINVAL; } - wil_dbg(wil, "AP on Channel %d %d MHz, %s\n", channel->hw_value, - channel->center_freq, info->privacy ? "secure" : "open"); + wil_dbg_misc(wil, "AP on Channel %d %d MHz, %s\n", channel->hw_value, + channel->center_freq, info->privacy ? "secure" : "open"); print_hex_dump_bytes("SSID ", DUMP_PREFIX_OFFSET, info->ssid, info->ssid_len); diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index 38049da71049..dc97e7b2609c 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c @@ -38,7 +38,9 @@ #define WIL6210_IMC_RX BIT_DMA_EP_RX_ICR_RX_DONE #define WIL6210_IMC_TX (BIT_DMA_EP_TX_ICR_TX_DONE | \ BIT_DMA_EP_TX_ICR_TX_DONE_N(0)) -#define WIL6210_IMC_MISC (ISR_MISC_FW_READY | ISR_MISC_MBOX_EVT) +#define WIL6210_IMC_MISC (ISR_MISC_FW_READY | \ + ISR_MISC_MBOX_EVT | \ + ISR_MISC_FW_ERROR) #define WIL6210_IRQ_PSEUDO_MASK (u32)(~(BIT_DMA_PSEUDO_CAUSE_RX | \ BIT_DMA_PSEUDO_CAUSE_TX | \ @@ -50,7 +52,6 @@ static inline void wil_icr_clear(u32 x, void __iomem *addr) { - } #else /* defined(CONFIG_WIL6210_ISR_COR) */ /* configure to Write-1-to-Clear mode */ @@ -94,7 +95,7 @@ static void wil6210_mask_irq_misc(struct wil6210_priv *wil) static void wil6210_mask_irq_pseudo(struct wil6210_priv *wil) { - wil_dbg_IRQ(wil, "%s()\n", __func__); + wil_dbg_irq(wil, "%s()\n", __func__); iowrite32(WIL6210_IRQ_DISABLE, wil->csr + HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW)); @@ -125,7 +126,7 @@ static void wil6210_unmask_irq_misc(struct wil6210_priv *wil) static void wil6210_unmask_irq_pseudo(struct wil6210_priv *wil) { - wil_dbg_IRQ(wil, "%s()\n", __func__); + wil_dbg_irq(wil, "%s()\n", __func__); set_bit(wil_status_irqen, &wil->status); @@ -135,7 +136,7 @@ static void wil6210_unmask_irq_pseudo(struct wil6210_priv *wil) void wil6210_disable_irq(struct wil6210_priv *wil) { - wil_dbg_IRQ(wil, "%s()\n", __func__); + wil_dbg_irq(wil, "%s()\n", __func__); wil6210_mask_irq_tx(wil); wil6210_mask_irq_rx(wil); @@ -145,7 +146,7 @@ void wil6210_disable_irq(struct wil6210_priv *wil) void wil6210_enable_irq(struct wil6210_priv *wil) { - wil_dbg_IRQ(wil, "%s()\n", __func__); + wil_dbg_irq(wil, "%s()\n", __func__); iowrite32(WIL_ICR_ICC_VALUE, wil->csr + HOSTADDR(RGF_DMA_EP_RX_ICR) + offsetof(struct RGF_ICR, ICC)); @@ -167,7 +168,7 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie) HOSTADDR(RGF_DMA_EP_RX_ICR) + offsetof(struct RGF_ICR, ICR)); - wil_dbg_IRQ(wil, "ISR RX 0x%08x\n", isr); + wil_dbg_irq(wil, "ISR RX 0x%08x\n", isr); if (!isr) { wil_err(wil, "spurious IRQ: RX\n"); @@ -177,7 +178,7 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie) wil6210_mask_irq_rx(wil); if (isr & BIT_DMA_EP_RX_ICR_RX_DONE) { - wil_dbg_IRQ(wil, "RX done\n"); + wil_dbg_irq(wil, "RX done\n"); isr &= ~BIT_DMA_EP_RX_ICR_RX_DONE; wil_rx_handle(wil); } @@ -197,7 +198,7 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie) HOSTADDR(RGF_DMA_EP_TX_ICR) + offsetof(struct RGF_ICR, ICR)); - wil_dbg_IRQ(wil, "ISR TX 0x%08x\n", isr); + wil_dbg_irq(wil, "ISR TX 0x%08x\n", isr); if (!isr) { wil_err(wil, "spurious IRQ: TX\n"); @@ -208,13 +209,13 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie) if (isr & BIT_DMA_EP_TX_ICR_TX_DONE) { uint i; - wil_dbg_IRQ(wil, "TX done\n"); + wil_dbg_irq(wil, "TX done\n"); isr &= ~BIT_DMA_EP_TX_ICR_TX_DONE; for (i = 0; i < 24; i++) { u32 mask = BIT_DMA_EP_TX_ICR_TX_DONE_N(i); if (isr & mask) { isr &= ~mask; - wil_dbg_IRQ(wil, "TX done(%i)\n", i); + wil_dbg_irq(wil, "TX done(%i)\n", i); wil_tx_complete(wil, i); } } @@ -228,6 +229,17 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie) return IRQ_HANDLED; } +static void wil_notify_fw_error(struct wil6210_priv *wil) +{ + struct device *dev = &wil_to_ndev(wil)->dev; + char *envp[3] = { + [0] = "SOURCE=wil6210", + [1] = "EVENT=FW_ERROR", + [2] = NULL, + }; + kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp); +} + static irqreturn_t wil6210_irq_misc(int irq, void *cookie) { struct wil6210_priv *wil = cookie; @@ -235,7 +247,7 @@ static irqreturn_t wil6210_irq_misc(int irq, void *cookie) HOSTADDR(RGF_DMA_EP_MISC_ICR) + offsetof(struct RGF_ICR, ICR)); - wil_dbg_IRQ(wil, "ISR MISC 0x%08x\n", isr); + wil_dbg_irq(wil, "ISR MISC 0x%08x\n", isr); if (!isr) { wil_err(wil, "spurious IRQ: MISC\n"); @@ -244,8 +256,15 @@ static irqreturn_t wil6210_irq_misc(int irq, void *cookie) wil6210_mask_irq_misc(wil); + if (isr & ISR_MISC_FW_ERROR) { + wil_dbg_irq(wil, "IRQ: Firmware error\n"); + clear_bit(wil_status_fwready, &wil->status); + wil_notify_fw_error(wil); + isr &= ~ISR_MISC_FW_ERROR; + } + if (isr & ISR_MISC_FW_READY) { - wil_dbg_IRQ(wil, "IRQ: FW ready\n"); + wil_dbg_irq(wil, "IRQ: FW ready\n"); /** * Actual FW ready indicated by the * WMI_FW_READY_EVENTID @@ -268,10 +287,10 @@ static irqreturn_t wil6210_irq_misc_thread(int irq, void *cookie) struct wil6210_priv *wil = cookie; u32 isr = wil->isr_misc; - wil_dbg_IRQ(wil, "Thread ISR MISC 0x%08x\n", isr); + wil_dbg_irq(wil, "Thread ISR MISC 0x%08x\n", isr); if (isr & ISR_MISC_MBOX_EVT) { - wil_dbg_IRQ(wil, "MBOX event\n"); + wil_dbg_irq(wil, "MBOX event\n"); wmi_recv_cmd(wil); isr &= ~ISR_MISC_MBOX_EVT; } @@ -293,7 +312,7 @@ static irqreturn_t wil6210_thread_irq(int irq, void *cookie) { struct wil6210_priv *wil = cookie; - wil_dbg_IRQ(wil, "Thread IRQ\n"); + wil_dbg_irq(wil, "Thread IRQ\n"); /* Discover real IRQ cause */ if (wil->isr_misc) wil6210_irq_misc_thread(irq, cookie); @@ -370,6 +389,8 @@ static irqreturn_t wil6210_hardirq(int irq, void *cookie) if (wil6210_debug_irq_mask(wil, pseudo_cause)) return IRQ_NONE; + wil_dbg_irq(wil, "Pseudo IRQ 0x%08x\n", pseudo_cause); + wil6210_mask_irq_pseudo(wil); /* Discover real IRQ cause @@ -401,8 +422,6 @@ static irqreturn_t wil6210_hardirq(int irq, void *cookie) if (rc != IRQ_WAKE_THREAD) wil6210_unmask_irq_pseudo(wil); - wil_dbg_IRQ(wil, "Hard IRQ 0x%08x\n", pseudo_cause); - return rc; } diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 95fcd361322b..761c389586d4 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -64,7 +64,7 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, void *bssid) struct net_device *ndev = wil_to_ndev(wil); struct wireless_dev *wdev = wil->wdev; - wil_dbg(wil, "%s()\n", __func__); + wil_dbg_misc(wil, "%s()\n", __func__); wil_link_off(wil); clear_bit(wil_status_fwconnected, &wil->status); @@ -80,11 +80,13 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, void *bssid) GFP_KERNEL); break; default: - ; + break; } for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) wil_vring_fini_tx(wil, i); + + clear_bit(wil_status_dontscan, &wil->status); } static void wil_disconnect_worker(struct work_struct *work) @@ -99,7 +101,7 @@ static void wil_connect_timer_fn(ulong x) { struct wil6210_priv *wil = (void *)x; - wil_dbg(wil, "Connect timeout\n"); + wil_dbg_misc(wil, "Connect timeout\n"); /* reschedule to thread context - disconnect won't * run from atomic context @@ -107,9 +109,18 @@ static void wil_connect_timer_fn(ulong x) schedule_work(&wil->disconnect_worker); } +static void wil_cache_mbox_regs(struct wil6210_priv *wil) +{ + /* make shadow copy of registers that should not change on run time */ + wil_memcpy_fromio_32(&wil->mbox_ctl, wil->csr + HOST_MBOX, + sizeof(struct wil6210_mbox_ctl)); + wil_mbox_ring_le2cpus(&wil->mbox_ctl.rx); + wil_mbox_ring_le2cpus(&wil->mbox_ctl.tx); +} + int wil_priv_init(struct wil6210_priv *wil) { - wil_dbg(wil, "%s()\n", __func__); + wil_dbg_misc(wil, "%s()\n", __func__); mutex_init(&wil->mutex); mutex_init(&wil->wmi_mutex); @@ -136,11 +147,7 @@ int wil_priv_init(struct wil6210_priv *wil) return -EAGAIN; } - /* make shadow copy of registers that should not change on run time */ - wil_memcpy_fromio_32(&wil->mbox_ctl, wil->csr + HOST_MBOX, - sizeof(struct wil6210_mbox_ctl)); - wil_mbox_ring_le2cpus(&wil->mbox_ctl.rx); - wil_mbox_ring_le2cpus(&wil->mbox_ctl.tx); + wil_cache_mbox_regs(wil); return 0; } @@ -162,7 +169,7 @@ void wil_priv_deinit(struct wil6210_priv *wil) static void wil_target_reset(struct wil6210_priv *wil) { - wil_dbg(wil, "Resetting...\n"); + wil_dbg_misc(wil, "Resetting...\n"); /* register write */ #define W(a, v) iowrite32(v, wil->csr + HOSTADDR(a)) @@ -202,7 +209,7 @@ static void wil_target_reset(struct wil6210_priv *wil) msleep(2000); - wil_dbg(wil, "Reset completed\n"); + wil_dbg_misc(wil, "Reset completed\n"); #undef W #undef S @@ -225,8 +232,8 @@ static int wil_wait_for_fw_ready(struct wil6210_priv *wil) wil_err(wil, "Firmware not ready\n"); return -ETIME; } else { - wil_dbg(wil, "FW ready after %d ms\n", - jiffies_to_msecs(to-left)); + wil_dbg_misc(wil, "FW ready after %d ms\n", + jiffies_to_msecs(to-left)); } return 0; } @@ -243,13 +250,13 @@ int wil_reset(struct wil6210_priv *wil) cancel_work_sync(&wil->disconnect_worker); wil6210_disconnect(wil, NULL); + wil6210_disable_irq(wil); + wil->status = 0; + wmi_event_flush(wil); - flush_workqueue(wil->wmi_wq); flush_workqueue(wil->wmi_wq_conn); - - wil6210_disable_irq(wil); - wil->status = 0; + flush_workqueue(wil->wmi_wq); /* TODO: put MAC in reset */ wil_target_reset(wil); @@ -258,11 +265,7 @@ int wil_reset(struct wil6210_priv *wil) wil->pending_connect_cid = -1; INIT_COMPLETION(wil->wmi_ready); - /* make shadow copy of registers that should not change on run time */ - wil_memcpy_fromio_32(&wil->mbox_ctl, wil->csr + HOST_MBOX, - sizeof(struct wil6210_mbox_ctl)); - wil_mbox_ring_le2cpus(&wil->mbox_ctl.rx); - wil_mbox_ring_le2cpus(&wil->mbox_ctl.tx); + wil_cache_mbox_regs(wil); /* TODO: release MAC reset */ wil6210_enable_irq(wil); @@ -278,7 +281,7 @@ void wil_link_on(struct wil6210_priv *wil) { struct net_device *ndev = wil_to_ndev(wil); - wil_dbg(wil, "%s()\n", __func__); + wil_dbg_misc(wil, "%s()\n", __func__); netif_carrier_on(ndev); netif_tx_wake_all_queues(ndev); @@ -288,7 +291,7 @@ void wil_link_off(struct wil6210_priv *wil) { struct net_device *ndev = wil_to_ndev(wil); - wil_dbg(wil, "%s()\n", __func__); + wil_dbg_misc(wil, "%s()\n", __func__); netif_tx_stop_all_queues(ndev); netif_carrier_off(ndev); @@ -311,27 +314,27 @@ static int __wil_up(struct wil6210_priv *wil) wmi_nettype = wil_iftype_nl2wmi(NL80211_IFTYPE_ADHOC); switch (wdev->iftype) { case NL80211_IFTYPE_STATION: - wil_dbg(wil, "type: STATION\n"); + wil_dbg_misc(wil, "type: STATION\n"); bi = 0; ndev->type = ARPHRD_ETHER; break; case NL80211_IFTYPE_AP: - wil_dbg(wil, "type: AP\n"); + wil_dbg_misc(wil, "type: AP\n"); bi = 100; ndev->type = ARPHRD_ETHER; break; case NL80211_IFTYPE_P2P_CLIENT: - wil_dbg(wil, "type: P2P_CLIENT\n"); + wil_dbg_misc(wil, "type: P2P_CLIENT\n"); bi = 0; ndev->type = ARPHRD_ETHER; break; case NL80211_IFTYPE_P2P_GO: - wil_dbg(wil, "type: P2P_GO\n"); + wil_dbg_misc(wil, "type: P2P_GO\n"); bi = 100; ndev->type = ARPHRD_ETHER; break; case NL80211_IFTYPE_MONITOR: - wil_dbg(wil, "type: Monitor\n"); + wil_dbg_misc(wil, "type: Monitor\n"); bi = 0; ndev->type = ARPHRD_IEEE80211_RADIOTAP; /* ARPHRD_IEEE80211 or ARPHRD_IEEE80211_RADIOTAP ? */ @@ -354,7 +357,7 @@ static int __wil_up(struct wil6210_priv *wil) wmi_set_channel(wil, channel->hw_value); break; default: - ; + break; } /* MAC address - pre-requisite for other commands */ diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c index 3068b5cb53a7..8ce2e33dce20 100644 --- a/drivers/net/wireless/ath/wil6210/netdev.c +++ b/drivers/net/wireless/ath/wil6210/netdev.c @@ -35,37 +35,12 @@ static int wil_stop(struct net_device *ndev) return wil_down(wil); } -/* - * AC to queue mapping - * - * AC_VO -> queue 3 - * AC_VI -> queue 2 - * AC_BE -> queue 1 - * AC_BK -> queue 0 - */ -static u16 wil_select_queue(struct net_device *ndev, struct sk_buff *skb) -{ - static const u16 wil_1d_to_queue[8] = { 1, 0, 0, 1, 2, 2, 3, 3 }; - struct wil6210_priv *wil = ndev_to_wil(ndev); - u16 rc; - - skb->priority = cfg80211_classify8021d(skb); - - rc = wil_1d_to_queue[skb->priority]; - - wil_dbg_TXRX(wil, "%s() %d -> %d\n", __func__, (int)skb->priority, - (int)rc); - - return rc; -} - static const struct net_device_ops wil_netdev_ops = { .ndo_open = wil_open, .ndo_stop = wil_stop, .ndo_start_xmit = wil_start_xmit, - .ndo_select_queue = wil_select_queue, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, }; void *wil_if_alloc(struct device *dev, void __iomem *csr) @@ -97,7 +72,7 @@ void *wil_if_alloc(struct device *dev, void __iomem *csr) ch = wdev->wiphy->bands[IEEE80211_BAND_60GHZ]->channels; cfg80211_chandef_create(&wdev->preset_chandef, ch, NL80211_CHAN_NO_HT); - ndev = alloc_netdev_mqs(0, "wlan%d", ether_setup, WIL6210_TX_QUEUES, 1); + ndev = alloc_netdev(0, "wlan%d", ether_setup); if (!ndev) { dev_err(dev, "alloc_netdev_mqs failed\n"); rc = -ENOMEM; diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index 0fc83edd6bad..81c35c6e3832 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -53,7 +53,7 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil) } wil->n_msi = use_msi; if (wil->n_msi) { - wil_dbg(wil, "Setup %d MSI interrupts\n", use_msi); + wil_dbg_misc(wil, "Setup %d MSI interrupts\n", use_msi); rc = pci_enable_msi_block(pdev, wil->n_msi); if (rc && (wil->n_msi == 3)) { wil_err(wil, "3 MSI mode failed, try 1 MSI\n"); @@ -65,7 +65,7 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil) wil->n_msi = 0; } } else { - wil_dbg(wil, "MSI interrupts disabled, use INTx\n"); + wil_dbg_misc(wil, "MSI interrupts disabled, use INTx\n"); } rc = wil6210_init_irq(wil, pdev->irq); diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index f29c294413cf..64b971fdc3cc 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -100,8 +100,8 @@ static int wil_vring_alloc(struct wil6210_priv *wil, struct vring *vring) d->dma.status = TX_DMA_STATUS_DU; } - wil_dbg(wil, "vring[%d] 0x%p:0x%016llx 0x%p\n", vring->size, - vring->va, (unsigned long long)vring->pa, vring->ctx); + wil_dbg_misc(wil, "vring[%d] 0x%p:0x%016llx 0x%p\n", vring->size, + vring->va, (unsigned long long)vring->pa, vring->ctx); return 0; } @@ -353,8 +353,8 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, if (ndev->type == ARPHRD_IEEE80211_RADIOTAP) wil_rx_add_radiotap_header(wil, skb, d); - wil_dbg_TXRX(wil, "Rx[%3d] : %d bytes\n", vring->swhead, d->dma.length); - wil_hex_dump_TXRX("Rx ", DUMP_PREFIX_NONE, 32, 4, + wil_dbg_txrx(wil, "Rx[%3d] : %d bytes\n", vring->swhead, d->dma.length); + wil_hex_dump_txrx("Rx ", DUMP_PREFIX_NONE, 32, 4, (const void *)d, sizeof(*d), false); wil_vring_advance_head(vring, 1); @@ -369,7 +369,7 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, */ ftype = wil_rxdesc_ftype(d) << 2; if (ftype != IEEE80211_FTYPE_DATA) { - wil_dbg_TXRX(wil, "Non-data frame ftype 0x%08x\n", ftype); + wil_dbg_txrx(wil, "Non-data frame ftype 0x%08x\n", ftype); /* TODO: process it */ kfree_skb(skb); return NULL; @@ -430,6 +430,8 @@ static void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev) int rc; unsigned int len = skb->len; + skb_orphan(skb); + if (in_interrupt()) rc = netif_rx(skb); else @@ -459,13 +461,11 @@ void wil_rx_handle(struct wil6210_priv *wil) wil_err(wil, "Rx IRQ while Rx not yet initialized\n"); return; } - wil_dbg_TXRX(wil, "%s()\n", __func__); + wil_dbg_txrx(wil, "%s()\n", __func__); while (NULL != (skb = wil_vring_reap_rx(wil, v))) { - wil_hex_dump_TXRX("Rx ", DUMP_PREFIX_OFFSET, 16, 1, + wil_hex_dump_txrx("Rx ", DUMP_PREFIX_OFFSET, 16, 1, skb->data, skb_headlen(skb), false); - skb_orphan(skb); - if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) { skb->dev = ndev; skb_reset_mac_header(skb); @@ -484,53 +484,18 @@ void wil_rx_handle(struct wil6210_priv *wil) int wil_rx_init(struct wil6210_priv *wil) { - struct net_device *ndev = wil_to_ndev(wil); - struct wireless_dev *wdev = wil->wdev; struct vring *vring = &wil->vring_rx; int rc; - struct wmi_cfg_rx_chain_cmd cmd = { - .action = WMI_RX_CHAIN_ADD, - .rx_sw_ring = { - .max_mpdu_size = cpu_to_le16(RX_BUF_LEN), - }, - .mid = 0, /* TODO - what is it? */ - .decap_trans_type = WMI_DECAP_TYPE_802_3, - }; - struct { - struct wil6210_mbox_hdr_wmi wmi; - struct wmi_cfg_rx_chain_done_event evt; - } __packed evt; vring->size = WIL6210_RX_RING_SIZE; rc = wil_vring_alloc(wil, vring); if (rc) return rc; - cmd.rx_sw_ring.ring_mem_base = cpu_to_le64(vring->pa); - cmd.rx_sw_ring.ring_size = cpu_to_le16(vring->size); - if (wdev->iftype == NL80211_IFTYPE_MONITOR) { - struct ieee80211_channel *ch = wdev->preset_chandef.chan; - - cmd.sniffer_cfg.mode = cpu_to_le32(WMI_SNIFFER_ON); - if (ch) - cmd.sniffer_cfg.channel = ch->hw_value - 1; - cmd.sniffer_cfg.phy_info_mode = - cpu_to_le32(ndev->type == ARPHRD_IEEE80211_RADIOTAP); - cmd.sniffer_cfg.phy_support = - cpu_to_le32((wil->monitor_flags & MONITOR_FLAG_CONTROL) - ? WMI_SNIFFER_CP : WMI_SNIFFER_DP); - } - /* typical time for secure PCP is 840ms */ - rc = wmi_call(wil, WMI_CFG_RX_CHAIN_CMDID, &cmd, sizeof(cmd), - WMI_CFG_RX_CHAIN_DONE_EVENTID, &evt, sizeof(evt), 2000); + rc = wmi_rx_chain_add(wil, vring); if (rc) goto err_free; - vring->hwtail = le32_to_cpu(evt.evt.rx_ring_tail_ptr); - - wil_dbg(wil, "Rx init: status %d tail 0x%08x\n", - le32_to_cpu(evt.evt.status), vring->hwtail); - rc = wil_rx_refill(wil, vring->size); if (rc) goto err_free; @@ -546,25 +511,8 @@ void wil_rx_fini(struct wil6210_priv *wil) { struct vring *vring = &wil->vring_rx; - if (vring->va) { - int rc; - struct wmi_cfg_rx_chain_cmd cmd = { - .action = cpu_to_le32(WMI_RX_CHAIN_DEL), - .rx_sw_ring = { - .max_mpdu_size = cpu_to_le16(RX_BUF_LEN), - }, - }; - struct { - struct wil6210_mbox_hdr_wmi wmi; - struct wmi_cfg_rx_chain_done_event cfg; - } __packed wmi_rx_cfg_reply; - - rc = wmi_call(wil, WMI_CFG_RX_CHAIN_CMDID, &cmd, sizeof(cmd), - WMI_CFG_RX_CHAIN_DONE_EVENTID, - &wmi_rx_cfg_reply, sizeof(wmi_rx_cfg_reply), - 100); + if (vring->va) wil_vring_free(wil, vring, 0); - } } int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, @@ -617,6 +565,7 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, if (reply.cmd.status != WMI_VRING_CFG_SUCCESS) { wil_err(wil, "Tx config failed, status 0x%02x\n", reply.cmd.status); + rc = -EINVAL; goto out_free; } vring->hwtail = le32_to_cpu(reply.cmd.tx_vring_tail_ptr); @@ -689,7 +638,7 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, uint i = swhead; dma_addr_t pa; - wil_dbg_TXRX(wil, "%s()\n", __func__); + wil_dbg_txrx(wil, "%s()\n", __func__); if (avail < vring->size/8) netif_tx_stop_all_queues(wil_to_ndev(wil)); @@ -706,9 +655,9 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, pa = dma_map_single(dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE); - wil_dbg_TXRX(wil, "Tx skb %d bytes %p -> %#08llx\n", skb_headlen(skb), + wil_dbg_txrx(wil, "Tx skb %d bytes %p -> %#08llx\n", skb_headlen(skb), skb->data, (unsigned long long)pa); - wil_hex_dump_TXRX("Tx ", DUMP_PREFIX_OFFSET, 16, 1, + wil_hex_dump_txrx("Tx ", DUMP_PREFIX_OFFSET, 16, 1, skb->data, skb_headlen(skb), false); if (unlikely(dma_mapping_error(dev, pa))) @@ -737,12 +686,12 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_DMA_IT_POS); d->dma.d0 |= (vring_index << DMA_CFG_DESC_TX_0_QID_POS); - wil_hex_dump_TXRX("Tx ", DUMP_PREFIX_NONE, 32, 4, + wil_hex_dump_txrx("Tx ", DUMP_PREFIX_NONE, 32, 4, (const void *)d, sizeof(*d), false); /* advance swhead */ wil_vring_advance_head(vring, nr_frags + 1); - wil_dbg_TXRX(wil, "Tx swhead %d -> %d\n", swhead, vring->swhead); + wil_dbg_txrx(wil, "Tx swhead %d -> %d\n", swhead, vring->swhead); iowrite32(vring->swhead, wil->csr + HOSTADDR(vring->hwtail)); /* hold reference to skb * to prevent skb release before accounting @@ -775,7 +724,7 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) struct vring *vring; int rc; - wil_dbg_TXRX(wil, "%s()\n", __func__); + wil_dbg_txrx(wil, "%s()\n", __func__); if (!test_bit(wil_status_fwready, &wil->status)) { wil_err(wil, "FW not ready\n"); goto drop; @@ -802,15 +751,13 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) } switch (rc) { case 0: - ndev->stats.tx_packets++; - ndev->stats.tx_bytes += skb->len; + /* statistics will be updated on the tx_complete */ dev_kfree_skb_any(skb); return NETDEV_TX_OK; case -ENOMEM: return NETDEV_TX_BUSY; default: - ; /* goto drop; */ - break; + break; /* goto drop; */ } drop: netif_tx_stop_all_queues(ndev); @@ -827,6 +774,7 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) */ void wil_tx_complete(struct wil6210_priv *wil, int ringid) { + struct net_device *ndev = wil_to_ndev(wil); struct device *dev = wil_to_dev(wil); struct vring *vring = &wil->vring_tx[ringid]; @@ -835,7 +783,7 @@ void wil_tx_complete(struct wil6210_priv *wil, int ringid) return; } - wil_dbg_TXRX(wil, "%s(%d)\n", __func__, ringid); + wil_dbg_txrx(wil, "%s(%d)\n", __func__, ringid); while (!wil_vring_is_empty(vring)) { volatile struct vring_tx_desc *d = &vring->va[vring->swtail].tx; @@ -844,16 +792,23 @@ void wil_tx_complete(struct wil6210_priv *wil, int ringid) if (!(d->dma.status & TX_DMA_STATUS_DU)) break; - wil_dbg_TXRX(wil, + wil_dbg_txrx(wil, "Tx[%3d] : %d bytes, status 0x%02x err 0x%02x\n", vring->swtail, d->dma.length, d->dma.status, d->dma.error); - wil_hex_dump_TXRX("TxC ", DUMP_PREFIX_NONE, 32, 4, + wil_hex_dump_txrx("TxC ", DUMP_PREFIX_NONE, 32, 4, (const void *)d, sizeof(*d), false); pa = d->dma.addr_low | ((u64)d->dma.addr_high << 32); skb = vring->ctx[vring->swtail]; if (skb) { + if (d->dma.error == 0) { + ndev->stats.tx_packets++; + ndev->stats.tx_bytes += skb->len; + } else { + ndev->stats.tx_errors++; + } + dma_unmap_single(dev, pa, d->dma.length, DMA_TO_DEVICE); dev_kfree_skb_any(skb); vring->ctx[vring->swtail] = NULL; diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 9bcfffa4006c..aea961ff8f08 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -36,8 +36,6 @@ static inline u32 WIL_GET_BITS(u32 x, int b0, int b1) #define WIL6210_MEM_SIZE (2*1024*1024UL) -#define WIL6210_TX_QUEUES (4) - #define WIL6210_RX_RING_SIZE (128) #define WIL6210_TX_RING_SIZE (128) #define WIL6210_MAX_TX_RINGS (24) @@ -101,8 +99,7 @@ struct RGF_ICR { #define RGF_DMA_EP_MISC_ICR (0x881bec) /* struct RGF_ICR */ #define BIT_DMA_EP_MISC_ICR_RX_HTRSH BIT(0) #define BIT_DMA_EP_MISC_ICR_TX_NO_ACT BIT(1) - #define BIT_DMA_EP_MISC_ICR_FW_INT0 BIT(28) - #define BIT_DMA_EP_MISC_ICR_FW_INT1 BIT(29) + #define BIT_DMA_EP_MISC_ICR_FW_INT(n) BIT(28+n) /* n = [0..3] */ /* Interrupt moderation control */ #define RGF_DMA_ITR_CNT_TRSH (0x881c5c) @@ -121,8 +118,9 @@ struct RGF_ICR { #define SW_INT_MBOX BIT_USER_USER_ICR_SW_INT_2 /* ISR register bits */ -#define ISR_MISC_FW_READY BIT_DMA_EP_MISC_ICR_FW_INT0 -#define ISR_MISC_MBOX_EVT BIT_DMA_EP_MISC_ICR_FW_INT1 +#define ISR_MISC_FW_READY BIT_DMA_EP_MISC_ICR_FW_INT(0) +#define ISR_MISC_MBOX_EVT BIT_DMA_EP_MISC_ICR_FW_INT(1) +#define ISR_MISC_FW_ERROR BIT_DMA_EP_MISC_ICR_FW_INT(3) /* Hardware definitions end */ @@ -272,17 +270,18 @@ struct wil6210_priv { #define wil_info(wil, fmt, arg...) netdev_info(wil_to_ndev(wil), fmt, ##arg) #define wil_err(wil, fmt, arg...) netdev_err(wil_to_ndev(wil), fmt, ##arg) -#define wil_dbg_IRQ(wil, fmt, arg...) wil_dbg(wil, "DBG[ IRQ]" fmt, ##arg) -#define wil_dbg_TXRX(wil, fmt, arg...) wil_dbg(wil, "DBG[TXRX]" fmt, ##arg) -#define wil_dbg_WMI(wil, fmt, arg...) wil_dbg(wil, "DBG[ WMI]" fmt, ##arg) +#define wil_dbg_irq(wil, fmt, arg...) wil_dbg(wil, "DBG[ IRQ]" fmt, ##arg) +#define wil_dbg_txrx(wil, fmt, arg...) wil_dbg(wil, "DBG[TXRX]" fmt, ##arg) +#define wil_dbg_wmi(wil, fmt, arg...) wil_dbg(wil, "DBG[ WMI]" fmt, ##arg) +#define wil_dbg_misc(wil, fmt, arg...) wil_dbg(wil, "DBG[MISC]" fmt, ##arg) -#define wil_hex_dump_TXRX(prefix_str, prefix_type, rowsize, \ +#define wil_hex_dump_txrx(prefix_str, prefix_type, rowsize, \ groupsize, buf, len, ascii) \ wil_print_hex_dump_debug("DBG[TXRX]" prefix_str,\ prefix_type, rowsize, \ groupsize, buf, len, ascii) -#define wil_hex_dump_WMI(prefix_str, prefix_type, rowsize, \ +#define wil_hex_dump_wmi(prefix_str, prefix_type, rowsize, \ groupsize, buf, len, ascii) \ wil_print_hex_dump_debug("DBG[ WMI]" prefix_str,\ prefix_type, rowsize, \ @@ -328,6 +327,7 @@ int wmi_add_cipher_key(struct wil6210_priv *wil, u8 key_index, const void *mac_addr, int key_len, const void *key); int wmi_echo(struct wil6210_priv *wil); int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie); +int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring); int wil6210_init_irq(struct wil6210_priv *wil, int irq); void wil6210_fini_irq(struct wil6210_priv *wil, int irq); diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 12915f6e7617..0b70e17cd1fb 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -18,8 +18,10 @@ #include <linux/io.h> #include <linux/list.h> #include <linux/etherdevice.h> +#include <linux/if_arp.h> #include "wil6210.h" +#include "txrx.h" #include "wmi.h" /** @@ -186,7 +188,6 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len) wil_err(wil, "WMI size too large: %d bytes, max is %d\n", (int)(sizeof(cmd) + len), r->entry_size); return -ERANGE; - } might_sleep(); @@ -213,7 +214,7 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len) } /* next head */ next_head = r->base + ((r->head - r->base + sizeof(d_head)) % r->size); - wil_dbg_WMI(wil, "Head 0x%08x -> 0x%08x\n", r->head, next_head); + wil_dbg_wmi(wil, "Head 0x%08x -> 0x%08x\n", r->head, next_head); /* wait till FW finish with previous command */ for (retry = 5; retry > 0; retry--) { r->tail = ioread32(wil->csr + HOST_MBOX + @@ -234,10 +235,10 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len) } cmd.hdr.seq = cpu_to_le16(++wil->wmi_seq); /* set command */ - wil_dbg_WMI(wil, "WMI command 0x%04x [%d]\n", cmdid, len); - wil_hex_dump_WMI("Cmd ", DUMP_PREFIX_OFFSET, 16, 1, &cmd, + wil_dbg_wmi(wil, "WMI command 0x%04x [%d]\n", cmdid, len); + wil_hex_dump_wmi("Cmd ", DUMP_PREFIX_OFFSET, 16, 1, &cmd, sizeof(cmd), true); - wil_hex_dump_WMI("cmd ", DUMP_PREFIX_OFFSET, 16, 1, buf, + wil_hex_dump_wmi("cmd ", DUMP_PREFIX_OFFSET, 16, 1, buf, len, true); wil_memcpy_toio_32(dst, &cmd, sizeof(cmd)); wil_memcpy_toio_32(dst + sizeof(cmd), buf, len); @@ -273,7 +274,7 @@ static void wmi_evt_ready(struct wil6210_priv *wil, int id, void *d, int len) struct wmi_ready_event *evt = d; u32 ver = le32_to_cpu(evt->sw_version); - wil_dbg_WMI(wil, "FW ver. %d; MAC %pM\n", ver, evt->mac); + wil_dbg_wmi(wil, "FW ver. %d; MAC %pM\n", ver, evt->mac); if (!is_valid_ether_addr(ndev->dev_addr)) { memcpy(ndev->dev_addr, evt->mac, ETH_ALEN); @@ -286,7 +287,7 @@ static void wmi_evt_ready(struct wil6210_priv *wil, int id, void *d, int len) static void wmi_evt_fw_ready(struct wil6210_priv *wil, int id, void *d, int len) { - wil_dbg_WMI(wil, "WMI: FW ready\n"); + wil_dbg_wmi(wil, "WMI: FW ready\n"); set_bit(wil_status_fwready, &wil->status); /* reuse wmi_ready for the firmware ready indication */ @@ -309,11 +310,11 @@ static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len) u32 d_len = le32_to_cpu(data->info.len); u16 d_status = le16_to_cpu(data->info.status); - wil_dbg_WMI(wil, "MGMT: channel %d MCS %d SNR %d\n", + wil_dbg_wmi(wil, "MGMT: channel %d MCS %d SNR %d\n", data->info.channel, data->info.mcs, data->info.snr); - wil_dbg_WMI(wil, "status 0x%04x len %d stype %04x\n", d_status, d_len, + wil_dbg_wmi(wil, "status 0x%04x len %d stype %04x\n", d_status, d_len, le16_to_cpu(data->info.stype)); - wil_dbg_WMI(wil, "qid %d mid %d cid %d\n", + wil_dbg_wmi(wil, "qid %d mid %d cid %d\n", data->info.qid, data->info.mid, data->info.cid); if (!channel) { @@ -329,13 +330,13 @@ static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len) const u8 *ie_buf = rx_mgmt_frame->u.beacon.variable; size_t ie_len = d_len - offsetof(struct ieee80211_mgmt, u.beacon.variable); - wil_dbg_WMI(wil, "Capability info : 0x%04x\n", cap); + wil_dbg_wmi(wil, "Capability info : 0x%04x\n", cap); bss = cfg80211_inform_bss(wiphy, channel, rx_mgmt_frame->bssid, tsf, cap, bi, ie_buf, ie_len, signal, GFP_KERNEL); if (bss) { - wil_dbg_WMI(wil, "Added BSS %pM\n", + wil_dbg_wmi(wil, "Added BSS %pM\n", rx_mgmt_frame->bssid); cfg80211_put_bss(bss); } else { @@ -351,7 +352,7 @@ static void wmi_evt_scan_complete(struct wil6210_priv *wil, int id, struct wmi_scan_complete_event *data = d; bool aborted = (data->status != 0); - wil_dbg_WMI(wil, "SCAN_COMPLETE(0x%08x)\n", data->status); + wil_dbg_wmi(wil, "SCAN_COMPLETE(0x%08x)\n", data->status); cfg80211_scan_done(wil->scan_request, aborted); wil->scan_request = NULL; } else { @@ -386,9 +387,9 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len) return; } ch = evt->channel + 1; - wil_dbg_WMI(wil, "Connect %pM channel [%d] cid %d\n", + wil_dbg_wmi(wil, "Connect %pM channel [%d] cid %d\n", evt->bssid, ch, evt->cid); - wil_hex_dump_WMI("connect AI : ", DUMP_PREFIX_OFFSET, 16, 1, + wil_hex_dump_wmi("connect AI : ", DUMP_PREFIX_OFFSET, 16, 1, evt->assoc_info, len - sizeof(*evt), true); /* figure out IE's */ @@ -450,14 +451,13 @@ static void wmi_evt_disconnect(struct wil6210_priv *wil, int id, { struct wmi_disconnect_event *evt = d; - wil_dbg_WMI(wil, "Disconnect %pM reason %d proto %d wmi\n", + wil_dbg_wmi(wil, "Disconnect %pM reason %d proto %d wmi\n", evt->bssid, evt->protocol_reason_status, evt->disconnect_reason); wil->sinfo_gen++; wil6210_disconnect(wil, evt->bssid); - clear_bit(wil_status_dontscan, &wil->status); } static void wmi_evt_notify(struct wil6210_priv *wil, int id, void *d, int len) @@ -476,7 +476,7 @@ static void wmi_evt_notify(struct wil6210_priv *wil, int id, void *d, int len) wil->stats.my_tx_sector = le16_to_cpu(evt->my_tx_sector); wil->stats.peer_rx_sector = le16_to_cpu(evt->other_rx_sector); wil->stats.peer_tx_sector = le16_to_cpu(evt->other_tx_sector); - wil_dbg_WMI(wil, "Link status, MCS %d TSF 0x%016llx\n" + wil_dbg_wmi(wil, "Link status, MCS %d TSF 0x%016llx\n" "BF status 0x%08x SNR 0x%08x\n" "Tx Tpt %d goodput %d Rx goodput %d\n" "Sectors(rx:tx) my %d:%d peer %d:%d\n", @@ -501,7 +501,7 @@ static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id, struct sk_buff *skb; struct ethhdr *eth; - wil_dbg_WMI(wil, "EAPOL len %d from %pM\n", eapol_len, + wil_dbg_wmi(wil, "EAPOL len %d from %pM\n", eapol_len, evt->src_mac); if (eapol_len > 196) { /* TODO: revisit size limit */ @@ -599,15 +599,15 @@ void wmi_recv_cmd(struct wil6210_priv *wil) iowrite32(0, wil->csr + HOSTADDR(r->tail) + offsetof(struct wil6210_mbox_ring_desc, sync)); /* indicate */ - wil_dbg_WMI(wil, "Mbox evt %04x %04x %04x %02x\n", + wil_dbg_wmi(wil, "Mbox evt %04x %04x %04x %02x\n", le16_to_cpu(hdr.seq), len, le16_to_cpu(hdr.type), hdr.flags); if ((hdr.type == WIL_MBOX_HDR_TYPE_WMI) && (len >= sizeof(struct wil6210_mbox_hdr_wmi))) { - wil_dbg_WMI(wil, "WMI event 0x%04x\n", + wil_dbg_wmi(wil, "WMI event 0x%04x\n", evt->event.wmi.id); } - wil_hex_dump_WMI("evt ", DUMP_PREFIX_OFFSET, 16, 1, + wil_hex_dump_wmi("evt ", DUMP_PREFIX_OFFSET, 16, 1, &evt->event.hdr, sizeof(hdr) + len, true); /* advance tail */ @@ -623,7 +623,7 @@ void wmi_recv_cmd(struct wil6210_priv *wil) { int q = queue_work(wil->wmi_wq, &wil->wmi_event_worker); - wil_dbg_WMI(wil, "queue_work -> %d\n", q); + wil_dbg_wmi(wil, "queue_work -> %d\n", q); } } } @@ -650,7 +650,7 @@ int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len, cmdid, reply_id, to_msec); rc = -ETIME; } else { - wil_dbg_WMI(wil, + wil_dbg_wmi(wil, "wmi_call(0x%04x->0x%04x) completed in %d msec\n", cmdid, reply_id, to_msec - jiffies_to_msecs(remain)); @@ -680,7 +680,7 @@ int wmi_set_mac_address(struct wil6210_priv *wil, void *addr) memcpy(cmd.mac, addr, ETH_ALEN); - wil_dbg_WMI(wil, "Set MAC %pM\n", addr); + wil_dbg_wmi(wil, "Set MAC %pM\n", addr); return wmi_send(wil, WMI_SET_MAC_ADDRESS_CMDID, &cmd, sizeof(cmd)); } @@ -778,7 +778,7 @@ int wmi_tx_eapol(struct wil6210_priv *wil, struct sk_buff *skb) skb_set_mac_header(skb, 0); eth = eth_hdr(skb); - wil_dbg_WMI(wil, "EAPOL %d bytes to %pM\n", eapol_len, eth->h_dest); + wil_dbg_wmi(wil, "EAPOL %d bytes to %pM\n", eapol_len, eth->h_dest); for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) { if (memcmp(wil->dst_addr[i], eth->h_dest, ETH_ALEN) == 0) goto found_dest; @@ -853,11 +853,60 @@ int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie) return rc; } +int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring) +{ + struct wireless_dev *wdev = wil->wdev; + struct net_device *ndev = wil_to_ndev(wil); + struct wmi_cfg_rx_chain_cmd cmd = { + .action = WMI_RX_CHAIN_ADD, + .rx_sw_ring = { + .max_mpdu_size = cpu_to_le16(RX_BUF_LEN), + .ring_mem_base = cpu_to_le64(vring->pa), + .ring_size = cpu_to_le16(vring->size), + }, + .mid = 0, /* TODO - what is it? */ + .decap_trans_type = WMI_DECAP_TYPE_802_3, + }; + struct { + struct wil6210_mbox_hdr_wmi wmi; + struct wmi_cfg_rx_chain_done_event evt; + } __packed evt; + int rc; + + if (wdev->iftype == NL80211_IFTYPE_MONITOR) { + struct ieee80211_channel *ch = wdev->preset_chandef.chan; + + cmd.sniffer_cfg.mode = cpu_to_le32(WMI_SNIFFER_ON); + if (ch) + cmd.sniffer_cfg.channel = ch->hw_value - 1; + cmd.sniffer_cfg.phy_info_mode = + cpu_to_le32(ndev->type == ARPHRD_IEEE80211_RADIOTAP); + cmd.sniffer_cfg.phy_support = + cpu_to_le32((wil->monitor_flags & MONITOR_FLAG_CONTROL) + ? WMI_SNIFFER_CP : WMI_SNIFFER_DP); + } + /* typical time for secure PCP is 840ms */ + rc = wmi_call(wil, WMI_CFG_RX_CHAIN_CMDID, &cmd, sizeof(cmd), + WMI_CFG_RX_CHAIN_DONE_EVENTID, &evt, sizeof(evt), 2000); + if (rc) + return rc; + + vring->hwtail = le32_to_cpu(evt.evt.rx_ring_tail_ptr); + + wil_dbg_misc(wil, "Rx init: status %d tail 0x%08x\n", + le32_to_cpu(evt.evt.status), vring->hwtail); + + if (le32_to_cpu(evt.evt.status) != WMI_CFG_RX_CHAIN_SUCCESS) + rc = -EINVAL; + + return rc; +} + void wmi_event_flush(struct wil6210_priv *wil) { struct pending_wmi_event *evt, *t; - wil_dbg_WMI(wil, "%s()\n", __func__); + wil_dbg_wmi(wil, "%s()\n", __func__); list_for_each_entry_safe(evt, t, &wil->pending_wmi_ev, list) { list_del(&evt->list); @@ -899,7 +948,7 @@ static void wmi_event_handle(struct wil6210_priv *wil, wmi_evt_call_handler(wil, id, evt_data, len - sizeof(*wmi)); } - wil_dbg_WMI(wil, "Complete WMI 0x%04x\n", id); + wil_dbg_wmi(wil, "Complete WMI 0x%04x\n", id); complete(&wil->wmi_ready); return; } @@ -964,7 +1013,7 @@ void wmi_connect_worker(struct work_struct *work) return; } - wil_dbg_WMI(wil, "Configure for connection CID %d\n", + wil_dbg_wmi(wil, "Configure for connection CID %d\n", wil->pending_connect_cid); rc = wil_vring_init_tx(wil, 0, WIL6210_TX_RING_SIZE, |