diff options
181 files changed, 6206 insertions, 5146 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 568ea93..46ce7c6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1658,10 +1658,9 @@ F: drivers/net/ethernet/broadcom/tg3.* BROADCOM BRCM80211 IEEE802.11n WIRELESS DRIVER M: Brett Rudley <brudley@broadcom.com> -M: Roland Vossen <rvossen@broadcom.com> M: Arend van Spriel <arend@broadcom.com> M: Franky (Zhenhui) Lin <frankyl@broadcom.com> -M: Kan Yan <kanyan@broadcom.com> +M: Hante Meuleman <meuleman@broadcom.com> L: linux-wireless@vger.kernel.org L: brcm80211-dev-list@broadcom.com S: Supported @@ -5067,6 +5066,7 @@ F: net/nfc/ F: include/linux/nfc.h F: include/net/nfc/ F: drivers/nfc/ +F: include/linux/platform_data/pn544.h NFS, SUNRPC, AND LOCKD CLIENTS M: Trond Myklebust <Trond.Myklebust@netapp.com> diff --git a/drivers/bcma/driver_pci_host.c b/drivers/bcma/driver_pci_host.c index e564495..e6b5c89 100644 --- a/drivers/bcma/driver_pci_host.c +++ b/drivers/bcma/driver_pci_host.c @@ -538,7 +538,7 @@ DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, bcma_core_pci_fixup_pcibridge); static void bcma_core_pci_fixup_addresses(struct pci_dev *dev) { struct resource *res; - int pos; + int pos, err; if (dev->bus->ops->read != bcma_core_pci_hostmode_read_config) { /* This is not a device on the PCI-core bridge. */ @@ -551,8 +551,12 @@ static void bcma_core_pci_fixup_addresses(struct pci_dev *dev) for (pos = 0; pos < 6; pos++) { res = &dev->resource[pos]; - if (res->flags & (IORESOURCE_IO | IORESOURCE_MEM)) - pci_assign_resource(dev, pos); + if (res->flags & (IORESOURCE_IO | IORESOURCE_MEM)) { + err = pci_assign_resource(dev, pos); + if (err) + pr_err("PCI: Problem fixing up the addresses on %s\n", + pci_name(dev)); + } } } DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, bcma_core_pci_fixup_addresses); diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index fc2de55..b00000e 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -67,6 +67,7 @@ static struct usb_device_id ath3k_table[] = { { USB_DEVICE(0x13d3, 0x3304) }, { USB_DEVICE(0x0930, 0x0215) }, { USB_DEVICE(0x0489, 0xE03D) }, + { USB_DEVICE(0x0489, 0xE027) }, /* Atheros AR9285 Malbec with sflash firmware */ { USB_DEVICE(0x03F0, 0x311D) }, diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 5693b9b..a1d4ede 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -125,6 +125,7 @@ static struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x13d3, 0x3304), .driver_info = BTUSB_IGNORE }, { USB_DEVICE(0x0930, 0x0215), .driver_info = BTUSB_IGNORE }, { USB_DEVICE(0x0489, 0xe03d), .driver_info = BTUSB_IGNORE }, + { USB_DEVICE(0x0489, 0xe027), .driver_info = BTUSB_IGNORE }, /* Atheros AR9285 Malbec with sflash firmware */ { USB_DEVICE(0x03f0, 0x311d), .driver_info = BTUSB_IGNORE }, diff --git a/drivers/net/wireless/ath/Kconfig b/drivers/net/wireless/ath/Kconfig index c25dcf1..1a67a4f 100644 --- a/drivers/net/wireless/ath/Kconfig +++ b/drivers/net/wireless/ath/Kconfig @@ -1,4 +1,7 @@ -menuconfig ATH_COMMON +config ATH_COMMON + tristate + +menuconfig ATH_CARDS tristate "Atheros Wireless Cards" depends on CFG80211 && (!UML || BROKEN) ---help--- @@ -14,7 +17,7 @@ menuconfig ATH_COMMON http://wireless.kernel.org/en/users/Drivers/Atheros -if ATH_COMMON +if ATH_CARDS config ATH_DEBUG bool "Atheros wireless debugging" diff --git a/drivers/net/wireless/ath/ar5523/Kconfig b/drivers/net/wireless/ath/ar5523/Kconfig index 11d99ee..0d320cc 100644 --- a/drivers/net/wireless/ath/ar5523/Kconfig +++ b/drivers/net/wireless/ath/ar5523/Kconfig @@ -1,6 +1,7 @@ config AR5523 tristate "Atheros AR5523 wireless driver support" depends on MAC80211 && USB + select ATH_COMMON select FW_LOADER ---help--- This module add support for AR5523 based USB dongles such as D-Link diff --git a/drivers/net/wireless/ath/ath5k/Kconfig b/drivers/net/wireless/ath/ath5k/Kconfig index 338c5c4..c9f81a3 100644 --- a/drivers/net/wireless/ath/ath5k/Kconfig +++ b/drivers/net/wireless/ath/ath5k/Kconfig @@ -1,6 +1,7 @@ config ATH5K tristate "Atheros 5xxx wireless cards support" depends on (PCI || ATHEROS_AR231X) && MAC80211 + select ATH_COMMON select MAC80211_LEDS select LEDS_CLASS select NEW_LEDS diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index cdd1923..2fd5bab 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -1349,7 +1349,7 @@ ath5k_receive_frame(struct ath5k_hw *ah, struct sk_buff *skb, * right now, so it's not too bad... */ rxs->mactime = ath5k_extend_tsf(ah, rs->rs_tstamp); - rxs->flag |= RX_FLAG_MACTIME_MPDU; + rxs->flag |= RX_FLAG_MACTIME_START; rxs->freq = ah->curchan->center_freq; rxs->band = ah->curchan->band; diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 83d8c5e..5516a8c 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -1074,15 +1074,18 @@ out: void ath6kl_cfg80211_ch_switch_notify(struct ath6kl_vif *vif, int freq, enum wmi_phy_mode mode) { - enum nl80211_channel_type type; + struct cfg80211_chan_def chandef; ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "channel switch notify nw_type %d freq %d mode %d\n", vif->nw_type, freq, mode); - type = (mode == WMI_11G_HT20) ? NL80211_CHAN_HT20 : NL80211_CHAN_NO_HT; + cfg80211_chandef_create(&chandef, + ieee80211_get_channel(vif->ar->wiphy, freq), + (mode == WMI_11G_HT20) ? + NL80211_CHAN_HT20 : NL80211_CHAN_NO_HT); - cfg80211_ch_switch_notify(vif->ndev, freq, type); + cfg80211_ch_switch_notify(vif->ndev, &chandef); } static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, @@ -1594,8 +1597,8 @@ static int ath6kl_cfg80211_join_ibss(struct wiphy *wiphy, vif->ssid_len = ibss_param->ssid_len; memcpy(vif->ssid, ibss_param->ssid, vif->ssid_len); - if (ibss_param->channel) - vif->ch_hint = ibss_param->channel->center_freq; + if (ibss_param->chandef.chan) + vif->ch_hint = ibss_param->chandef.chan->center_freq; if (ibss_param->channel_fixed) { /* @@ -2878,7 +2881,7 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, p.ssid_len = vif->ssid_len; memcpy(p.ssid, vif->ssid, vif->ssid_len); p.dot11_auth_mode = vif->dot11_auth_mode; - p.ch = cpu_to_le16(info->channel->center_freq); + p.ch = cpu_to_le16(info->chandef.chan->center_freq); /* Enable uAPSD support by default */ res = ath6kl_wmi_ap_set_apsd(ar->wmi, vif->fw_vif_idx, true); @@ -2909,8 +2912,9 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, return res; } - if (ath6kl_set_htcap(vif, info->channel->band, - info->channel_type != NL80211_CHAN_NO_HT)) + if (ath6kl_set_htcap(vif, info->chandef.chan->band, + cfg80211_get_chandef_type(&info->chandef) + != NL80211_CHAN_NO_HT)) return -EIO; /* @@ -3006,7 +3010,6 @@ static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev, static int ath6kl_remain_on_channel(struct wiphy *wiphy, struct wireless_dev *wdev, struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type, unsigned int duration, u64 *cookie) { @@ -3165,10 +3168,8 @@ static bool ath6kl_is_p2p_go_ssid(const u8 *buf, size_t len) static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, struct ieee80211_channel *chan, bool offchan, - enum nl80211_channel_type channel_type, - bool channel_type_valid, unsigned int wait, - const u8 *buf, size_t len, bool no_cck, - bool dont_wait_for_ack, u64 *cookie) + unsigned int wait, const u8 *buf, size_t len, + bool no_cck, bool dont_wait_for_ack, u64 *cookie) { struct ath6kl_vif *vif = ath6kl_vif_from_wdev(wdev); struct ath6kl *ar = ath6kl_priv(vif->ndev); diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index 55ccf97..998f8b0 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -474,7 +474,7 @@ static int ath6kl_wmi_remain_on_chnl_event_rx(struct wmi *wmi, u8 *datap, return -EINVAL; } id = vif->last_roc_id; - cfg80211_ready_on_channel(&vif->wdev, id, chan, NL80211_CHAN_NO_HT, + cfg80211_ready_on_channel(&vif->wdev, id, chan, dur, GFP_ATOMIC); return 0; @@ -513,8 +513,7 @@ static int ath6kl_wmi_cancel_remain_on_chnl_event_rx(struct wmi *wmi, else id = vif->last_roc_id; /* timeout on uncanceled r-o-c */ vif->last_cancel_roc_id = 0; - cfg80211_remain_on_channel_expired(&vif->wdev, id, chan, - NL80211_CHAN_NO_HT, GFP_ATOMIC); + cfg80211_remain_on_channel_expired(&vif->wdev, id, chan, GFP_ATOMIC); return 0; } diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig index c7aa664..5fc15bf 100644 --- a/drivers/net/wireless/ath/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig @@ -17,6 +17,7 @@ config ATH9K_BTCOEX_SUPPORT config ATH9K tristate "Atheros 802.11n wireless cards support" depends on MAC80211 + select ATH_COMMON select ATH9K_HW select MAC80211_LEDS select LEDS_CLASS diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.c b/drivers/net/wireless/ath/ath9k/ar9003_mci.c index 42b4412..8dd0692 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mci.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.c @@ -714,7 +714,6 @@ bool ar9003_mci_start_reset(struct ath_hw *ah, struct ath9k_channel *chan) return true; } -EXPORT_SYMBOL(ar9003_mci_start_reset); int ar9003_mci_end_reset(struct ath_hw *ah, struct ath9k_channel *chan, struct ath9k_hw_cal_data *caldata) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 4e125d8..86e26a1 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -129,10 +129,10 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd, #define ATH_TXMAXTRY 13 #define TID_TO_WME_AC(_tid) \ - ((((_tid) == 0) || ((_tid) == 3)) ? WME_AC_BE : \ - (((_tid) == 1) || ((_tid) == 2)) ? WME_AC_BK : \ - (((_tid) == 4) || ((_tid) == 5)) ? WME_AC_VI : \ - WME_AC_VO) + ((((_tid) == 0) || ((_tid) == 3)) ? IEEE80211_AC_BE : \ + (((_tid) == 1) || ((_tid) == 2)) ? IEEE80211_AC_BK : \ + (((_tid) == 4) || ((_tid) == 5)) ? IEEE80211_AC_VI : \ + IEEE80211_AC_VO) #define ATH_AGGR_DELIM_SZ 4 #define ATH_AGGR_MINPLEN 256 /* in bytes, minimum packet length */ @@ -259,19 +259,21 @@ struct ath_atx_tid { }; struct ath_node { -#ifdef CONFIG_ATH9K_DEBUGFS - struct list_head list; /* for sc->nodes */ -#endif + struct ath_softc *sc; struct ieee80211_sta *sta; /* station struct we're part of */ struct ieee80211_vif *vif; /* interface with which we're associated */ - struct ath_atx_tid tid[WME_NUM_TID]; - struct ath_atx_ac ac[WME_NUM_AC]; + struct ath_atx_tid tid[IEEE80211_NUM_TIDS]; + struct ath_atx_ac ac[IEEE80211_NUM_ACS]; int ps_key; u16 maxampdu; u8 mpdudensity; bool sleeping; + +#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_DEBUGFS) + struct dentry *node_stat; +#endif }; #define AGGR_CLEANUP BIT(1) @@ -299,9 +301,9 @@ struct ath_tx { struct list_head txbuf; struct ath_txq txq[ATH9K_NUM_TX_QUEUES]; struct ath_descdma txdma; - struct ath_txq *txq_map[WME_NUM_AC]; - u32 txq_max_pending[WME_NUM_AC]; - u16 max_aggr_framelen[WME_NUM_AC][4][32]; + struct ath_txq *txq_map[IEEE80211_NUM_ACS]; + u32 txq_max_pending[IEEE80211_NUM_ACS]; + u16 max_aggr_framelen[IEEE80211_NUM_ACS][4][32]; }; struct ath_rx_edma { @@ -461,6 +463,12 @@ void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type); /* BTCOEX */ /**********/ +#define ATH_DUMP_BTCOEX(_s, _val) \ + do { \ + len += snprintf(buf + len, size - len, \ + "%20s : %10d\n", _s, (_val)); \ + } while (0) + enum bt_op_flags { BT_OP_PRIORITY_DETECTED, BT_OP_SCAN, @@ -482,6 +490,7 @@ struct ath_btcoex { int rssi_count; struct ath_gen_timer *no_stomp_timer; /* Timer for no BT stomping */ struct ath_mci_profile mci; + u8 stomp_audio; }; #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT @@ -494,7 +503,7 @@ void ath9k_btcoex_timer_pause(struct ath_softc *sc); void ath9k_btcoex_handle_interrupt(struct ath_softc *sc, u32 status); u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc, u32 max_4ms_framelen); void ath9k_btcoex_stop_gen_timer(struct ath_softc *sc); -int ath9k_dump_btcoex(struct ath_softc *sc, u8 *buf, u32 len, u32 size); +int ath9k_dump_btcoex(struct ath_softc *sc, u8 *buf, u32 size); #else static inline int ath9k_init_btcoex(struct ath_softc *sc) { @@ -521,8 +530,7 @@ static inline u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc, static inline void ath9k_btcoex_stop_gen_timer(struct ath_softc *sc) { } -static inline int ath9k_dump_btcoex(struct ath_softc *sc, u8 *buf, - u32 len, u32 size) +static inline int ath9k_dump_btcoex(struct ath_softc *sc, u8 *buf, u32 size) { return 0; } @@ -717,9 +725,6 @@ struct ath_softc { #ifdef CONFIG_ATH9K_DEBUGFS struct ath9k_debug debug; - spinlock_t nodes_lock; - struct list_head nodes; /* basically, stations */ - unsigned int tx_complete_poll_work_seen; #endif struct ath_beacon_config cur_beacon_conf; struct delayed_work tx_complete_work; diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 1b48414..531fffd 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -46,7 +46,7 @@ static void ath9k_beaconq_config(struct ath_softc *sc) qi.tqi_cwmax = 0; } else { /* Adhoc mode; important thing is to use 2x cwmin. */ - txq = sc->tx.txq_map[WME_AC_BE]; + txq = sc->tx.txq_map[IEEE80211_AC_BE]; ath9k_hw_get_txq_props(ah, txq->axq_qnum, &qi_be); qi.tqi_aifs = qi_be.tqi_aifs; if (ah->slottime == ATH9K_SLOT_TIME_20) diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c index c90e9bc..9963b0b 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.c +++ b/drivers/net/wireless/ath/ath9k/btcoex.c @@ -49,6 +49,7 @@ static const u32 mci_wlan_weights[ATH_BTCOEX_STOMP_MAX] { 0x01017d01, 0x3b3b3b01, 0x3b3b3b01, 0x3b3b3b3b }, /* STOMP_LOW */ { 0x01017d01, 0x01010101, 0x01010101, 0x01010101 }, /* STOMP_NONE */ { 0x01017d01, 0x013b0101, 0x3b3b0101, 0x3b3b013b }, /* STOMP_LOW_FTP */ + { 0xffffff01, 0xffffffff, 0xffffff01, 0xffffffff }, /* STOMP_AUDIO */ }; void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum) diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h index 2f84ab2..6de26ea 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.h +++ b/drivers/net/wireless/ath/ath9k/btcoex.h @@ -50,6 +50,7 @@ enum ath_stomp_type { ATH_BTCOEX_STOMP_LOW, ATH_BTCOEX_STOMP_NONE, ATH_BTCOEX_STOMP_LOW_FTP, + ATH_BTCOEX_STOMP_AUDIO, ATH_BTCOEX_STOMP_MAX }; diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h index ad14fec..5f845be 100644 --- a/drivers/net/wireless/ath/ath9k/common.h +++ b/drivers/net/wireless/ath/ath9k/common.h @@ -23,18 +23,10 @@ /* Common header for Atheros 802.11n base driver cores */ -#define WME_NUM_TID 16 #define WME_BA_BMP_SIZE 64 #define WME_MAX_BA WME_BA_BMP_SIZE #define ATH_TID_MAX_BUFS (2 * WME_MAX_BA) -/* These must match mac80211 skb queue mapping numbers */ -#define WME_AC_VO 0 -#define WME_AC_VI 1 -#define WME_AC_BE 2 -#define WME_AC_BK 3 -#define WME_NUM_AC 4 - #define ATH_RSSI_DUMMY_MARKER 0x127 #define ATH_RSSI_LPF_LEN 10 #define RSSI_LPF_THRESHOLD -20 diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index a8be94b..13ff9ed 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -512,62 +512,19 @@ static const struct file_operations fops_interrupt = { .llseek = default_llseek, }; -#define PR_QNUM(_n) sc->tx.txq_map[_n]->axq_qnum -#define PR(str, elem) \ - do { \ - len += snprintf(buf + len, size - len, \ - "%s%13u%11u%10u%10u\n", str, \ - sc->debug.stats.txstats[PR_QNUM(WME_AC_BE)].elem, \ - sc->debug.stats.txstats[PR_QNUM(WME_AC_BK)].elem, \ - sc->debug.stats.txstats[PR_QNUM(WME_AC_VI)].elem, \ - sc->debug.stats.txstats[PR_QNUM(WME_AC_VO)].elem); \ - if (len >= size) \ - goto done; \ -} while(0) - -#define PRX(str, elem) \ -do { \ - len += snprintf(buf + len, size - len, \ - "%s%13u%11u%10u%10u\n", str, \ - (unsigned int)(sc->tx.txq_map[WME_AC_BE]->elem), \ - (unsigned int)(sc->tx.txq_map[WME_AC_BK]->elem), \ - (unsigned int)(sc->tx.txq_map[WME_AC_VI]->elem), \ - (unsigned int)(sc->tx.txq_map[WME_AC_VO]->elem)); \ - if (len >= size) \ - goto done; \ -} while(0) - -#define PRQLE(str, elem) \ -do { \ - len += snprintf(buf + len, size - len, \ - "%s%13i%11i%10i%10i\n", str, \ - list_empty(&sc->tx.txq_map[WME_AC_BE]->elem), \ - list_empty(&sc->tx.txq_map[WME_AC_BK]->elem), \ - list_empty(&sc->tx.txq_map[WME_AC_VI]->elem), \ - list_empty(&sc->tx.txq_map[WME_AC_VO]->elem)); \ - if (len >= size) \ - goto done; \ -} while (0) - static ssize_t read_file_xmit(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct ath_softc *sc = file->private_data; char *buf; - unsigned int len = 0, size = 8000; - int i; + unsigned int len = 0, size = 2048; ssize_t retval = 0; - char tmp[32]; buf = kzalloc(size, GFP_KERNEL); if (buf == NULL) return -ENOMEM; - len += sprintf(buf, "Num-Tx-Queues: %i tx-queues-setup: 0x%x" - " poll-work-seen: %u\n" - "%30s %10s%10s%10s\n\n", - ATH9K_NUM_TX_QUEUES, sc->tx.txqsetup, - sc->tx_complete_poll_work_seen, + len += sprintf(buf, "%30s %10s%10s%10s\n\n", "BE", "BK", "VI", "VO"); PR("MPDUs Queued: ", queued); @@ -587,62 +544,11 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf, PR("DELIM Underrun: ", delim_underrun); PR("TX-Pkts-All: ", tx_pkts_all); PR("TX-Bytes-All: ", tx_bytes_all); - PR("hw-put-tx-buf: ", puttxbuf); - PR("hw-tx-start: ", txstart); - PR("hw-tx-proc-desc: ", txprocdesc); + PR("HW-put-tx-buf: ", puttxbuf); + PR("HW-tx-start: ", txstart); + PR("HW-tx-proc-desc: ", txprocdesc); PR("TX-Failed: ", txfailed); - len += snprintf(buf + len, size - len, - "%s%11p%11p%10p%10p\n", "txq-memory-address:", - sc->tx.txq_map[WME_AC_BE], - sc->tx.txq_map[WME_AC_BK], - sc->tx.txq_map[WME_AC_VI], - sc->tx.txq_map[WME_AC_VO]); - if (len >= size) - goto done; - - PRX("axq-qnum: ", axq_qnum); - PRX("axq-depth: ", axq_depth); - PRX("axq-ampdu_depth: ", axq_ampdu_depth); - PRX("axq-stopped ", stopped); - PRX("tx-in-progress ", axq_tx_inprogress); - PRX("pending-frames ", pending_frames); - PRX("txq_headidx: ", txq_headidx); - PRX("txq_tailidx: ", txq_headidx); - - PRQLE("axq_q empty: ", axq_q); - PRQLE("axq_acq empty: ", axq_acq); - for (i = 0; i < ATH_TXFIFO_DEPTH; i++) { - snprintf(tmp, sizeof(tmp) - 1, "txq_fifo[%i] empty: ", i); - PRQLE(tmp, txq_fifo[i]); - } - /* Print out more detailed queue-info */ - for (i = 0; i <= WME_AC_BK; i++) { - struct ath_txq *txq = &(sc->tx.txq[i]); - struct ath_atx_ac *ac; - struct ath_atx_tid *tid; - if (len >= size) - goto done; - spin_lock_bh(&txq->axq_lock); - if (!list_empty(&txq->axq_acq)) { - ac = list_first_entry(&txq->axq_acq, struct ath_atx_ac, - list); - len += snprintf(buf + len, size - len, - "txq[%i] first-ac: %p sched: %i\n", - i, ac, ac->sched); - if (list_empty(&ac->tid_q) || (len >= size)) - goto done_for; - tid = list_first_entry(&ac->tid_q, struct ath_atx_tid, - list); - len += snprintf(buf + len, size - len, - " first-tid: %p sched: %i paused: %i\n", - tid, tid->sched, tid->paused); - } - done_for: - spin_unlock_bh(&txq->axq_lock); - } - -done: if (len > size) len = size; @@ -652,62 +558,41 @@ done: return retval; } -static ssize_t read_file_stations(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) +static ssize_t read_file_queues(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) { struct ath_softc *sc = file->private_data; + struct ath_txq *txq; char *buf; - unsigned int len = 0, size = 64000; - struct ath_node *an = NULL; + unsigned int len = 0, size = 1024; ssize_t retval = 0; - int q; + int i; + char *qname[4] = {"VO", "VI", "BE", "BK"}; buf = kzalloc(size, GFP_KERNEL); if (buf == NULL) return -ENOMEM; - len += snprintf(buf + len, size - len, - "Stations:\n" - " tid: addr sched paused buf_q-empty an ac baw\n" - " ac: addr sched tid_q-empty txq\n"); - - spin_lock(&sc->nodes_lock); - list_for_each_entry(an, &sc->nodes, list) { - unsigned short ma = an->maxampdu; - if (ma == 0) - ma = 65535; /* see ath_lookup_rate */ - len += snprintf(buf + len, size - len, - "iface: %pM sta: %pM max-ampdu: %hu mpdu-density: %uus\n", - an->vif->addr, an->sta->addr, ma, - (unsigned int)(an->mpdudensity)); - if (len >= size) - goto done; - - for (q = 0; q < WME_NUM_TID; q++) { - struct ath_atx_tid *tid = &(an->tid[q]); - len += snprintf(buf + len, size - len, - " tid: %p %s %s %i %p %p %hu\n", - tid, tid->sched ? "sched" : "idle", - tid->paused ? "paused" : "running", - skb_queue_empty(&tid->buf_q), - tid->an, tid->ac, tid->baw_size); - if (len >= size) - goto done; - } + for (i = 0; i < IEEE80211_NUM_ACS; i++) { + txq = sc->tx.txq_map[i]; + len += snprintf(buf + len, size - len, "(%s): ", qname[i]); - for (q = 0; q < WME_NUM_AC; q++) { - struct ath_atx_ac *ac = &(an->ac[q]); - len += snprintf(buf + len, size - len, - " ac: %p %s %i %p\n", - ac, ac->sched ? "sched" : "idle", - list_empty(&ac->tid_q), ac->txq); - if (len >= size) - goto done; - } + ath_txq_lock(sc, txq); + + len += snprintf(buf + len, size - len, "%s: %d ", + "qnum", txq->axq_qnum); + len += snprintf(buf + len, size - len, "%s: %2d ", + "qdepth", txq->axq_depth); + len += snprintf(buf + len, size - len, "%s: %2d ", + "ampdu-depth", txq->axq_ampdu_depth); + len += snprintf(buf + len, size - len, "%s: %3d ", + "pending", txq->pending_frames); + len += snprintf(buf + len, size - len, "%s: %d\n", + "stopped", txq->stopped); + + ath_txq_unlock(sc, txq); } -done: - spin_unlock(&sc->nodes_lock); if (len > size) len = size; @@ -837,6 +722,9 @@ static ssize_t read_file_reset(struct file *file, char __user *user_buf, len += snprintf(buf + len, sizeof(buf) - len, "%17s: %2d\n", "PLL RX Hang", sc->debug.stats.reset[RESET_TYPE_PLL_HANG]); + len += snprintf(buf + len, sizeof(buf) - len, + "%17s: %2d\n", "MCI Reset", + sc->debug.stats.reset[RESET_TYPE_MCI]); if (len > sizeof(buf)) len = sizeof(buf); @@ -919,8 +807,8 @@ static const struct file_operations fops_xmit = { .llseek = default_llseek, }; -static const struct file_operations fops_stations = { - .read = read_file_stations, +static const struct file_operations fops_queues = { + .read = read_file_queues, .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, @@ -1599,8 +1487,14 @@ static ssize_t read_file_btcoex(struct file *file, char __user *user_buf, if (buf == NULL) return -ENOMEM; - len = ath9k_dump_btcoex(sc, buf, len, size); + if (!sc->sc_ah->common.btcoex_enabled) { + len = snprintf(buf, size, "%s\n", + "BTCOEX is disabled"); + goto exit; + } + len = ath9k_dump_btcoex(sc, buf, size); +exit: retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); kfree(buf); @@ -1615,6 +1509,215 @@ static const struct file_operations fops_btcoex = { }; #endif +static ssize_t read_file_node_stat(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_node *an = file->private_data; + struct ath_softc *sc = an->sc; + struct ath_atx_tid *tid; + struct ath_atx_ac *ac; + struct ath_txq *txq; + u32 len = 0, size = 4096; + char *buf; + size_t retval; + int tidno, acno; + + buf = kzalloc(size, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + if (!an->sta->ht_cap.ht_supported) { + len = snprintf(buf, size, "%s\n", + "HT not supported"); + goto exit; + } + + len = snprintf(buf, size, "Max-AMPDU: %d\n", + an->maxampdu); + len += snprintf(buf + len, size - len, "MPDU Density: %d\n\n", + an->mpdudensity); + + len += snprintf(buf + len, size - len, + "%2s%7s\n", "AC", "SCHED"); + + for (acno = 0, ac = &an->ac[acno]; + acno < IEEE80211_NUM_ACS; acno++, ac++) { + txq = ac->txq; + ath_txq_lock(sc, txq); + len += snprintf(buf + len, size - len, + "%2d%7d\n", + acno, ac->sched); + ath_txq_unlock(sc, txq); + } + + len += snprintf(buf + len, size - len, + "\n%3s%11s%10s%10s%10s%10s%9s%6s%8s\n", + "TID", "SEQ_START", "SEQ_NEXT", "BAW_SIZE", + "BAW_HEAD", "BAW_TAIL", "BAR_IDX", "SCHED", "PAUSED"); + + for (tidno = 0, tid = &an->tid[tidno]; + tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { + txq = tid->ac->txq; + ath_txq_lock(sc, txq); + len += snprintf(buf + len, size - len, + "%3d%11d%10d%10d%10d%10d%9d%6d%8d\n", + tid->tidno, tid->seq_start, tid->seq_next, + tid->baw_size, tid->baw_head, tid->baw_tail, + tid->bar_index, tid->sched, tid->paused); + ath_txq_unlock(sc, txq); + } +exit: + retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + + return retval; +} + +static const struct file_operations fops_node_stat = { + .read = read_file_node_stat, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +void ath9k_sta_add_debugfs(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct dentry *dir) +{ + struct ath_node *an = (struct ath_node *)sta->drv_priv; + an->node_stat = debugfs_create_file("node_stat", S_IRUGO, + dir, an, &fops_node_stat); +} + +void ath9k_sta_remove_debugfs(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct dentry *dir) +{ + struct ath_node *an = (struct ath_node *)sta->drv_priv; + debugfs_remove(an->node_stat); +} + +/* Ethtool support for get-stats */ + +#define AMKSTR(nm) #nm "_BE", #nm "_BK", #nm "_VI", #nm "_VO" +static const char ath9k_gstrings_stats[][ETH_GSTRING_LEN] = { + "tx_pkts_nic", + "tx_bytes_nic", + "rx_pkts_nic", + "rx_bytes_nic", + AMKSTR(d_tx_pkts), + AMKSTR(d_tx_bytes), + AMKSTR(d_tx_mpdus_queued), + AMKSTR(d_tx_mpdus_completed), + AMKSTR(d_tx_mpdu_xretries), + AMKSTR(d_tx_aggregates), + AMKSTR(d_tx_ampdus_queued_hw), + AMKSTR(d_tx_ampdus_queued_sw), + AMKSTR(d_tx_ampdus_completed), + AMKSTR(d_tx_ampdu_retries), + AMKSTR(d_tx_ampdu_xretries), + AMKSTR(d_tx_fifo_underrun), + AMKSTR(d_tx_op_exceeded), + AMKSTR(d_tx_timer_expiry), + AMKSTR(d_tx_desc_cfg_err), + AMKSTR(d_tx_data_underrun), + AMKSTR(d_tx_delim_underrun), + "d_rx_decrypt_crc_err", + "d_rx_phy_err", + "d_rx_mic_err", + "d_rx_pre_delim_crc_err", + "d_rx_post_delim_crc_err", + "d_rx_decrypt_busy_err", + + "d_rx_phyerr_radar", + "d_rx_phyerr_ofdm_timing", + "d_rx_phyerr_cck_timing", + +}; +#define ATH9K_SSTATS_LEN ARRAY_SIZE(ath9k_gstrings_stats) + +void ath9k_get_et_strings(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + u32 sset, u8 *data) +{ + if (sset == ETH_SS_STATS) + memcpy(data, *ath9k_gstrings_stats, + sizeof(ath9k_gstrings_stats)); +} + +int ath9k_get_et_sset_count(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, int sset) +{ + if (sset == ETH_SS_STATS) + return ATH9K_SSTATS_LEN; + return 0; +} + +#define AWDATA(elem) \ + do { \ + data[i++] = sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BE)].elem; \ + data[i++] = sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BK)].elem; \ + data[i++] = sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VI)].elem; \ + data[i++] = sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VO)].elem; \ + } while (0) + +#define AWDATA_RX(elem) \ + do { \ + data[i++] = sc->debug.stats.rxstats.elem; \ + } while (0) + +void ath9k_get_et_stats(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ethtool_stats *stats, u64 *data) +{ + struct ath_softc *sc = hw->priv; + int i = 0; + + data[i++] = (sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BE)].tx_pkts_all + + sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BK)].tx_pkts_all + + sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VI)].tx_pkts_all + + sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VO)].tx_pkts_all); + data[i++] = (sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BE)].tx_bytes_all + + sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BK)].tx_bytes_all + + sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VI)].tx_bytes_all + + sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VO)].tx_bytes_all); + AWDATA_RX(rx_pkts_all); + AWDATA_RX(rx_bytes_all); + + AWDATA(tx_pkts_all); + AWDATA(tx_bytes_all); + AWDATA(queued); + AWDATA(completed); + AWDATA(xretries); + AWDATA(a_aggr); + AWDATA(a_queued_hw); + AWDATA(a_queued_sw); + AWDATA(a_completed); + AWDATA(a_retries); + AWDATA(a_xretries); + AWDATA(fifo_underrun); + AWDATA(xtxop); + AWDATA(timer_exp); + AWDATA(desc_cfg_err); + AWDATA(data_underrun); + AWDATA(delim_underrun); + + AWDATA_RX(decrypt_crc_err); + AWDATA_RX(phy_err); + AWDATA_RX(mic_err); + AWDATA_RX(pre_delim_crc_err); + AWDATA_RX(post_delim_crc_err); + AWDATA_RX(decrypt_busy_err); + + AWDATA_RX(phy_err_stats[ATH9K_PHYERR_RADAR]); + AWDATA_RX(phy_err_stats[ATH9K_PHYERR_OFDM_TIMING]); + AWDATA_RX(phy_err_stats[ATH9K_PHYERR_CCK_TIMING]); + + WARN_ON(i != ATH9K_SSTATS_LEN); +} + int ath9k_init_debug(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); @@ -1638,16 +1741,16 @@ int ath9k_init_debug(struct ath_hw *ah) &fops_interrupt); debugfs_create_file("xmit", S_IRUSR, sc->debug.debugfs_phy, sc, &fops_xmit); + debugfs_create_file("queues", S_IRUSR, sc->debug.debugfs_phy, sc, + &fops_queues); debugfs_create_u32("qlen_bk", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, - &sc->tx.txq_max_pending[WME_AC_BK]); + &sc->tx.txq_max_pending[IEEE80211_AC_BK]); debugfs_create_u32("qlen_be", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, - &sc->tx.txq_max_pending[WME_AC_BE]); + &sc->tx.txq_max_pending[IEEE80211_AC_BE]); debugfs_create_u32("qlen_vi", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, - &sc->tx.txq_max_pending[WME_AC_VI]); + &sc->tx.txq_max_pending[IEEE80211_AC_VI]); debugfs_create_u32("qlen_vo", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, - &sc->tx.txq_max_pending[WME_AC_VO]); - debugfs_create_file("stations", S_IRUSR, sc->debug.debugfs_phy, sc, - &fops_stations); + &sc->tx.txq_max_pending[IEEE80211_AC_VO]); debugfs_create_file("misc", S_IRUSR, sc->debug.debugfs_phy, sc, &fops_misc); debugfs_create_file("reset", 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 2ed9785..72d4893 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -41,6 +41,7 @@ enum ath_reset_type { RESET_TYPE_PLL_HANG, RESET_TYPE_MAC_HANG, RESET_TYPE_BEACON_STUCK, + RESET_TYPE_MCI, __RESET_TYPE_MAX }; @@ -178,6 +179,21 @@ struct ath_tx_stats { u32 txfailed; }; +/* + * Various utility macros to print TX/Queue counters. + */ +#define PR_QNUM(_n) sc->tx.txq_map[_n]->axq_qnum +#define TXSTATS sc->debug.stats.txstats +#define PR(str, elem) \ + do { \ + len += snprintf(buf + len, size - len, \ + "%s%13u%11u%10u%10u\n", str, \ + TXSTATS[PR_QNUM(IEEE80211_AC_BE)].elem, \ + TXSTATS[PR_QNUM(IEEE80211_AC_BK)].elem, \ + TXSTATS[PR_QNUM(IEEE80211_AC_VI)].elem, \ + TXSTATS[PR_QNUM(IEEE80211_AC_VO)].elem); \ + } while(0) + #define RX_STAT_INC(c) (sc->debug.stats.rxstats.c++) /** @@ -226,7 +242,7 @@ struct ath_rx_stats { struct ath_stats { struct ath_interrupt_stats istats; - struct ath_tx_stats txstats[ATH9K_NUM_TX_QUEUES]; + struct ath_tx_stats txstats[IEEE80211_NUM_ACS]; struct ath_rx_stats rxstats; struct ath_dfs_stats dfs_stats; u32 reset[__RESET_TYPE_MAX]; @@ -291,7 +307,22 @@ void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf, struct ath_tx_status *ts, struct ath_txq *txq, unsigned int flags); void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs); - +int ath9k_get_et_sset_count(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, int sset); +void ath9k_get_et_stats(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ethtool_stats *stats, u64 *data); +void ath9k_get_et_strings(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + u32 sset, u8 *data); +void ath9k_sta_add_debugfs(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct dentry *dir); +void ath9k_sta_remove_debugfs(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct dentry *dir); #else #define RX_STAT_INC(c) /* NOP */ diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c index a8ea57b..4b412aa 100644 --- a/drivers/net/wireless/ath/ath9k/gpio.c +++ b/drivers/net/wireless/ath/ath9k/gpio.c @@ -247,6 +247,9 @@ static void ath_btcoex_period_timer(unsigned long data) stomp_type = ATH_BTCOEX_STOMP_ALL; timer_period = btcoex->btscan_no_stomp; } + } else if (btcoex->stomp_audio >= 5) { + stomp_type = ATH_BTCOEX_STOMP_AUDIO; + btcoex->stomp_audio = 0; } ath9k_hw_btcoex_bt_stomp(ah, stomp_type); @@ -295,7 +298,7 @@ static void ath_btcoex_no_stomp_timer(void *arg) (!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI) && test_bit(BT_OP_SCAN, &btcoex->op_flags))) ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_NONE); - else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL) + else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL) ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_LOW); ath9k_hw_btcoex_enable(ah); @@ -471,7 +474,7 @@ int ath9k_init_btcoex(struct ath_softc *sc) r = ath_init_btcoex_timer(sc); if (r) return -1; - txq = sc->tx.txq_map[WME_AC_BE]; + txq = sc->tx.txq_map[IEEE80211_AC_BE]; ath9k_hw_init_btcoex_hw(sc->sc_ah, txq->axq_qnum); sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW; if (ath9k_hw_mci_is_enabled(ah)) { @@ -494,35 +497,31 @@ int ath9k_init_btcoex(struct ath_softc *sc) return 0; } -int ath9k_dump_btcoex(struct ath_softc *sc, u8 *buf, u32 len, u32 size) +static int ath9k_dump_mci_btcoex(struct ath_softc *sc, u8 *buf, u32 size) { -#define ATH_DUMP_BTCOEX(_s, _val) \ - do { \ - len += snprintf(buf + len, size - len, \ - "%20s : %10d\n", _s, (_val)); \ - } while (0) - struct ath_btcoex *btcoex = &sc->btcoex; struct ath_mci_profile *mci = &btcoex->mci; struct ath_hw *ah = sc->sc_ah; struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; + u32 len = 0; int i; ATH_DUMP_BTCOEX("Total BT profiles", NUM_PROF(mci)); - ATH_DUMP_BTCOEX("Number of MGMT", mci->num_mgmt); - ATH_DUMP_BTCOEX("Number of SCO", mci->num_sco); - ATH_DUMP_BTCOEX("Number of A2DP", mci->num_a2dp); - ATH_DUMP_BTCOEX("Number of HID", mci->num_hid); - ATH_DUMP_BTCOEX("Number of PAN", mci->num_pan); - ATH_DUMP_BTCOEX("Number of ACL", mci->num_other_acl); - ATH_DUMP_BTCOEX("Number of BDR", mci->num_bdr); + ATH_DUMP_BTCOEX("MGMT", mci->num_mgmt); + ATH_DUMP_BTCOEX("SCO", mci->num_sco); + ATH_DUMP_BTCOEX("A2DP", mci->num_a2dp); + ATH_DUMP_BTCOEX("HID", mci->num_hid); + ATH_DUMP_BTCOEX("PAN", mci->num_pan); + ATH_DUMP_BTCOEX("ACL", mci->num_other_acl); + ATH_DUMP_BTCOEX("BDR", mci->num_bdr); ATH_DUMP_BTCOEX("Aggr. Limit", mci->aggr_limit); ATH_DUMP_BTCOEX("Stomp Type", btcoex->bt_stomp_type); ATH_DUMP_BTCOEX("BTCoex Period (msec)", btcoex->btcoex_period); ATH_DUMP_BTCOEX("Duty Cycle", btcoex->duty_cycle); ATH_DUMP_BTCOEX("BT Wait time", btcoex->bt_wait_time); ATH_DUMP_BTCOEX("Concurrent Tx", btcoex_hw->mci.concur_tx); - ATH_DUMP_BTCOEX("Concur RSSI count", btcoex->rssi_count); + ATH_DUMP_BTCOEX("Concurrent RSSI cnt", btcoex->rssi_count); + len += snprintf(buf + len, size - len, "BT Weights: "); for (i = 0; i < AR9300_NUM_BT_WEIGHTS; i++) len += snprintf(buf + len, size - len, "%08x ", @@ -537,9 +536,32 @@ int ath9k_dump_btcoex(struct ath_softc *sc, u8 *buf, u32 len, u32 size) for (i = 0; i < ATH_BTCOEX_STOMP_MAX; i++) len += snprintf(buf + len, size - len, "%08x ", btcoex_hw->tx_prio[i]); + len += snprintf(buf + len, size - len, "\n"); -#undef ATH_DUMP_BTCOEX return len; } + +static int ath9k_dump_legacy_btcoex(struct ath_softc *sc, u8 *buf, u32 size) +{ + + struct ath_btcoex *btcoex = &sc->btcoex; + u32 len = 0; + + ATH_DUMP_BTCOEX("Stomp Type", btcoex->bt_stomp_type); + ATH_DUMP_BTCOEX("BTCoex Period (msec)", btcoex->btcoex_period); + ATH_DUMP_BTCOEX("Duty Cycle", btcoex->duty_cycle); + ATH_DUMP_BTCOEX("BT Wait time", btcoex->bt_wait_time); + + return len; +} + +int ath9k_dump_btcoex(struct ath_softc *sc, u8 *buf, u32 size) +{ + if (ath9k_hw_mci_is_enabled(sc->sc_ah)) + return ath9k_dump_mci_btcoex(sc, buf, size); + else + return ath9k_dump_legacy_btcoex(sc, buf, size); +} + #endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */ diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index b30596f..96bfb18 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -331,7 +331,7 @@ struct ath_tx_stats { u32 skb_success; u32 skb_failed; u32 cab_queued; - u32 queue_stats[WME_NUM_AC]; + u32 queue_stats[IEEE80211_NUM_ACS]; }; struct ath_rx_stats { @@ -493,7 +493,7 @@ struct ath9k_htc_priv { int beaconq; int cabq; - int hwq_map[WME_NUM_AC]; + int hwq_map[IEEE80211_NUM_ACS]; #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT struct ath_btcoex btcoex; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index 1318d79..d0ce1f5 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -33,7 +33,7 @@ void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv) qi.tqi_cwmin = 0; qi.tqi_cwmax = 0; } else if (priv->ah->opmode == NL80211_IFTYPE_ADHOC) { - int qnum = priv->hwq_map[WME_AC_BE]; + int qnum = priv->hwq_map[IEEE80211_AC_BE]; ath9k_hw_get_txq_props(ah, qnum, &qi_be); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c index 3035deb..87110de5 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c @@ -218,16 +218,16 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf, len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", "BE queued", - priv->debug.tx_stats.queue_stats[WME_AC_BE]); + priv->debug.tx_stats.queue_stats[IEEE80211_AC_BE]); len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", "BK queued", - priv->debug.tx_stats.queue_stats[WME_AC_BK]); + priv->debug.tx_stats.queue_stats[IEEE80211_AC_BK]); len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", "VI queued", - priv->debug.tx_stats.queue_stats[WME_AC_VI]); + priv->debug.tx_stats.queue_stats[IEEE80211_AC_VI]); len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", "VO queued", - priv->debug.tx_stats.queue_stats[WME_AC_VO]); + priv->debug.tx_stats.queue_stats[IEEE80211_AC_VO]); if (len > sizeof(buf)) len = sizeof(buf); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c index 0eacfc1..105582d 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c @@ -207,7 +207,7 @@ void ath9k_htc_init_btcoex(struct ath9k_htc_priv *priv, char *product) priv->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW; ath9k_hw_btcoex_init_3wire(priv->ah); ath_htc_init_btcoex_work(priv); - qnum = priv->hwq_map[WME_AC_BE]; + qnum = priv->hwq_map[IEEE80211_AC_BE]; ath9k_hw_init_btcoex_hw(priv->ah, qnum); break; default: diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index 5ecf128..05d5ba6 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -549,20 +549,20 @@ static int ath9k_init_queues(struct ath9k_htc_priv *priv) goto err; } - if (!ath9k_htc_txq_setup(priv, WME_AC_BE)) { + if (!ath9k_htc_txq_setup(priv, IEEE80211_AC_BE)) { ath_err(common, "Unable to setup xmit queue for BE traffic\n"); goto err; } - if (!ath9k_htc_txq_setup(priv, WME_AC_BK)) { + if (!ath9k_htc_txq_setup(priv, IEEE80211_AC_BK)) { ath_err(common, "Unable to setup xmit queue for BK traffic\n"); goto err; } - if (!ath9k_htc_txq_setup(priv, WME_AC_VI)) { + if (!ath9k_htc_txq_setup(priv, IEEE80211_AC_VI)) { ath_err(common, "Unable to setup xmit queue for VI traffic\n"); goto err; } - if (!ath9k_htc_txq_setup(priv, WME_AC_VO)) { + if (!ath9k_htc_txq_setup(priv, IEEE80211_AC_VO)) { ath_err(common, "Unable to setup xmit queue for VO traffic\n"); goto err; } diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 02cce95..9c07a8f 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -1349,7 +1349,7 @@ static int ath9k_htc_conf_tx(struct ieee80211_hw *hw, struct ath9k_tx_queue_info qi; int ret = 0, qnum; - if (queue >= WME_NUM_AC) + if (queue >= IEEE80211_NUM_ACS) return 0; mutex_lock(&priv->mutex); @@ -1376,7 +1376,7 @@ static int ath9k_htc_conf_tx(struct ieee80211_hw *hw, } if ((priv->ah->opmode == NL80211_IFTYPE_ADHOC) && - (qnum == priv->hwq_map[WME_AC_BE])) + (qnum == priv->hwq_map[IEEE80211_AC_BE])) ath9k_htc_beaconq_config(priv); out: ath9k_htc_ps_restore(priv); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index 06cdcb7..28cd50e 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c @@ -21,10 +21,10 @@ /******/ static const int subtype_txq_to_hwq[] = { - [WME_AC_BE] = ATH_TXQ_AC_BE, - [WME_AC_BK] = ATH_TXQ_AC_BK, - [WME_AC_VI] = ATH_TXQ_AC_VI, - [WME_AC_VO] = ATH_TXQ_AC_VO, + [IEEE80211_AC_BE] = ATH_TXQ_AC_BE, + [IEEE80211_AC_BK] = ATH_TXQ_AC_BK, + [IEEE80211_AC_VI] = ATH_TXQ_AC_VI, + [IEEE80211_AC_VO] = ATH_TXQ_AC_VO, }; #define ATH9K_HTC_INIT_TXQ(subtype) do { \ @@ -41,15 +41,15 @@ int get_hw_qnum(u16 queue, int *hwq_map) { switch (queue) { case 0: - return hwq_map[WME_AC_VO]; + return hwq_map[IEEE80211_AC_VO]; case 1: - return hwq_map[WME_AC_VI]; + return hwq_map[IEEE80211_AC_VI]; case 2: - return hwq_map[WME_AC_BE]; + return hwq_map[IEEE80211_AC_BE]; case 3: - return hwq_map[WME_AC_BK]; + return hwq_map[IEEE80211_AC_BK]; default: - return hwq_map[WME_AC_BE]; + return hwq_map[IEEE80211_AC_BE]; } } @@ -106,20 +106,20 @@ static inline enum htc_endpoint_id get_htc_epid(struct ath9k_htc_priv *priv, switch (qnum) { case 0: - TX_QSTAT_INC(WME_AC_VO); + TX_QSTAT_INC(IEEE80211_AC_VO); epid = priv->data_vo_ep; break; case 1: - TX_QSTAT_INC(WME_AC_VI); + TX_QSTAT_INC(IEEE80211_AC_VI); epid = priv->data_vi_ep; break; case 2: - TX_QSTAT_INC(WME_AC_BE); + TX_QSTAT_INC(IEEE80211_AC_BE); epid = priv->data_be_ep; break; case 3: default: - TX_QSTAT_INC(WME_AC_BK); + TX_QSTAT_INC(IEEE80211_AC_BK); epid = priv->data_bk_ep; break; } @@ -1082,7 +1082,7 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv, rx_status->freq = hw->conf.channel->center_freq; rx_status->signal = rxbuf->rxstatus.rs_rssi + ATH_DEFAULT_NOISE_FLOOR; rx_status->antenna = rxbuf->rxstatus.rs_antenna; - rx_status->flag |= RX_FLAG_MACTIME_MPDU; + rx_status->flag |= RX_FLAG_MACTIME_START; return true; diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 756191b..e06bcec 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1456,7 +1456,7 @@ static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type) switch (type) { case ATH9K_RESET_POWER_ON: ret = ath9k_hw_set_reset_power_on(ah); - if (!ret) + if (ret) ah->reset_power_on = true; break; case ATH9K_RESET_WARM: diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 546bae9..80cae53 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -435,7 +435,7 @@ static int ath9k_init_queues(struct ath_softc *sc) sc->config.cabqReadytime = ATH_CABQ_READY_TIME; ath_cabq_update(sc); - for (i = 0; i < WME_NUM_AC; i++) { + for (i = 0; i < IEEE80211_NUM_ACS; i++) { sc->tx.txq_map[i] = ath_txq_setup(sc, ATH9K_TX_QUEUE_DATA, i); sc->tx.txq_map[i]->mac80211_qnum = i; sc->tx.txq_max_pending[i] = ATH_MAX_QDEPTH; @@ -563,10 +563,6 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, spin_lock_init(&sc->sc_serial_rw); spin_lock_init(&sc->sc_pm_lock); mutex_init(&sc->mutex); -#ifdef CONFIG_ATH9K_DEBUGFS - spin_lock_init(&sc->nodes_lock); - INIT_LIST_HEAD(&sc->nodes); -#endif #ifdef CONFIG_ATH9K_MAC_DEBUG spin_lock_init(&sc->debug.samp_lock); #endif diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c index 223b969..fc6b075 100644 --- a/drivers/net/wireless/ath/ath9k/link.c +++ b/drivers/net/wireless/ath/ath9k/link.c @@ -27,9 +27,6 @@ void ath_tx_complete_poll_work(struct work_struct *work) struct ath_txq *txq; int i; bool needreset = false; -#ifdef CONFIG_ATH9K_DEBUGFS - sc->tx_complete_poll_work_seen++; -#endif for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) if (ATH_TXQ_SETUP(sc, i)) { @@ -211,7 +208,7 @@ static bool ath_paprd_send_frame(struct ath_softc *sc, struct sk_buff *skb, int int time_left; memset(&txctl, 0, sizeof(txctl)); - txctl.txq = sc->tx.txq_map[WME_AC_BE]; + txctl.txq = sc->tx.txq_map[IEEE80211_AC_BE]; memset(tx_info, 0, sizeof(*tx_info)); tx_info->band = hw->conf.channel->band; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 9594b6f..be30a9a 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -331,11 +331,7 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta, u8 density; an = (struct ath_node *)sta->drv_priv; -#ifdef CONFIG_ATH9K_DEBUGFS - spin_lock(&sc->nodes_lock); - list_add(&an->list, &sc->nodes); - spin_unlock(&sc->nodes_lock); -#endif + an->sc = sc; an->sta = sta; an->vif = vif; @@ -352,13 +348,6 @@ static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta) { struct ath_node *an = (struct ath_node *)sta->drv_priv; -#ifdef CONFIG_ATH9K_DEBUGFS - spin_lock(&sc->nodes_lock); - list_del(&an->list); - spin_unlock(&sc->nodes_lock); - an->sta = NULL; -#endif - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) ath_tx_node_cleanup(sc, an); } @@ -494,17 +483,6 @@ irqreturn_t ath_isr(int irq, void *dev) if (status & SCHED_INTR) sched = true; -#ifdef CONFIG_PM_SLEEP - if (status & ATH9K_INT_BMISS) { - if (atomic_read(&sc->wow_sleep_proc_intr) == 0) { - ath_dbg(common, ANY, "during WoW we got a BMISS\n"); - atomic_inc(&sc->wow_got_bmiss_intr); - atomic_dec(&sc->wow_sleep_proc_intr); - } - ath_dbg(common, INTERRUPT, "beacon miss interrupt\n"); - } -#endif - /* * If a FATAL or RXORN interrupt is received, we have to reset the * chip immediately. @@ -523,7 +501,15 @@ irqreturn_t ath_isr(int irq, void *dev) goto chip_reset; } - +#ifdef CONFIG_PM_SLEEP + if (status & ATH9K_INT_BMISS) { + if (atomic_read(&sc->wow_sleep_proc_intr) == 0) { + ath_dbg(common, ANY, "during WoW we got a BMISS\n"); + atomic_inc(&sc->wow_got_bmiss_intr); + atomic_dec(&sc->wow_sleep_proc_intr); + } + } +#endif if (status & ATH9K_INT_SWBA) tasklet_schedule(&sc->bcon_tasklet); @@ -1328,7 +1314,7 @@ static int ath9k_conf_tx(struct ieee80211_hw *hw, struct ath9k_tx_queue_info qi; int ret = 0; - if (queue >= WME_NUM_AC) + if (queue >= IEEE80211_NUM_ACS) return 0; txq = sc->tx.txq_map[queue]; @@ -1897,134 +1883,6 @@ static int ath9k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) return 0; } -#ifdef CONFIG_ATH9K_DEBUGFS - -/* Ethtool support for get-stats */ - -#define AMKSTR(nm) #nm "_BE", #nm "_BK", #nm "_VI", #nm "_VO" -static const char ath9k_gstrings_stats[][ETH_GSTRING_LEN] = { - "tx_pkts_nic", - "tx_bytes_nic", - "rx_pkts_nic", - "rx_bytes_nic", - AMKSTR(d_tx_pkts), - AMKSTR(d_tx_bytes), - AMKSTR(d_tx_mpdus_queued), - AMKSTR(d_tx_mpdus_completed), - AMKSTR(d_tx_mpdu_xretries), - AMKSTR(d_tx_aggregates), - AMKSTR(d_tx_ampdus_queued_hw), - AMKSTR(d_tx_ampdus_queued_sw), - AMKSTR(d_tx_ampdus_completed), - AMKSTR(d_tx_ampdu_retries), - AMKSTR(d_tx_ampdu_xretries), - AMKSTR(d_tx_fifo_underrun), - AMKSTR(d_tx_op_exceeded), - AMKSTR(d_tx_timer_expiry), - AMKSTR(d_tx_desc_cfg_err), - AMKSTR(d_tx_data_underrun), - AMKSTR(d_tx_delim_underrun), - - "d_rx_decrypt_crc_err", - "d_rx_phy_err", - "d_rx_mic_err", - "d_rx_pre_delim_crc_err", - "d_rx_post_delim_crc_err", - "d_rx_decrypt_busy_err", - - "d_rx_phyerr_radar", - "d_rx_phyerr_ofdm_timing", - "d_rx_phyerr_cck_timing", - -}; -#define ATH9K_SSTATS_LEN ARRAY_SIZE(ath9k_gstrings_stats) - -static void ath9k_get_et_strings(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - u32 sset, u8 *data) -{ - if (sset == ETH_SS_STATS) - memcpy(data, *ath9k_gstrings_stats, - sizeof(ath9k_gstrings_stats)); -} - -static int ath9k_get_et_sset_count(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, int sset) -{ - if (sset == ETH_SS_STATS) - return ATH9K_SSTATS_LEN; - return 0; -} - -#define PR_QNUM(_n) (sc->tx.txq_map[_n]->axq_qnum) -#define AWDATA(elem) \ - do { \ - data[i++] = sc->debug.stats.txstats[PR_QNUM(WME_AC_BE)].elem; \ - data[i++] = sc->debug.stats.txstats[PR_QNUM(WME_AC_BK)].elem; \ - data[i++] = sc->debug.stats.txstats[PR_QNUM(WME_AC_VI)].elem; \ - data[i++] = sc->debug.stats.txstats[PR_QNUM(WME_AC_VO)].elem; \ - } while (0) - -#define AWDATA_RX(elem) \ - do { \ - data[i++] = sc->debug.stats.rxstats.elem; \ - } while (0) - -static void ath9k_get_et_stats(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ethtool_stats *stats, u64 *data) -{ - struct ath_softc *sc = hw->priv; - int i = 0; - - data[i++] = (sc->debug.stats.txstats[PR_QNUM(WME_AC_BE)].tx_pkts_all + - sc->debug.stats.txstats[PR_QNUM(WME_AC_BK)].tx_pkts_all + - sc->debug.stats.txstats[PR_QNUM(WME_AC_VI)].tx_pkts_all + - sc->debug.stats.txstats[PR_QNUM(WME_AC_VO)].tx_pkts_all); - data[i++] = (sc->debug.stats.txstats[PR_QNUM(WME_AC_BE)].tx_bytes_all + - sc->debug.stats.txstats[PR_QNUM(WME_AC_BK)].tx_bytes_all + - sc->debug.stats.txstats[PR_QNUM(WME_AC_VI)].tx_bytes_all + - sc->debug.stats.txstats[PR_QNUM(WME_AC_VO)].tx_bytes_all); - AWDATA_RX(rx_pkts_all); - AWDATA_RX(rx_bytes_all); - - AWDATA(tx_pkts_all); - AWDATA(tx_bytes_all); - AWDATA(queued); - AWDATA(completed); - AWDATA(xretries); - AWDATA(a_aggr); - AWDATA(a_queued_hw); - AWDATA(a_queued_sw); - AWDATA(a_completed); - AWDATA(a_retries); - AWDATA(a_xretries); - AWDATA(fifo_underrun); - AWDATA(xtxop); - AWDATA(timer_exp); - AWDATA(desc_cfg_err); - AWDATA(data_underrun); - AWDATA(delim_underrun); - - AWDATA_RX(decrypt_crc_err); - AWDATA_RX(phy_err); - AWDATA_RX(mic_err); - AWDATA_RX(pre_delim_crc_err); - AWDATA_RX(post_delim_crc_err); - AWDATA_RX(decrypt_busy_err); - - AWDATA_RX(phy_err_stats[ATH9K_PHYERR_RADAR]); - AWDATA_RX(phy_err_stats[ATH9K_PHYERR_OFDM_TIMING]); - AWDATA_RX(phy_err_stats[ATH9K_PHYERR_CCK_TIMING]); - - WARN_ON(i != ATH9K_SSTATS_LEN); -} - -/* End of ethtool get-stats functions */ - -#endif - - #ifdef CONFIG_PM_SLEEP static void ath9k_wow_map_triggers(struct ath_softc *sc, @@ -2418,7 +2276,12 @@ struct ieee80211_ops ath9k_ops = { #ifdef CONFIG_ATH9K_DEBUGFS .get_et_sset_count = ath9k_get_et_sset_count, - .get_et_stats = ath9k_get_et_stats, - .get_et_strings = ath9k_get_et_strings, + .get_et_stats = ath9k_get_et_stats, + .get_et_strings = ath9k_get_et_strings, +#endif + +#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_DEBUGFS) + .sta_add_debugfs = ath9k_sta_add_debugfs, + .sta_remove_debugfs = ath9k_sta_remove_debugfs, #endif }; diff --git a/drivers/net/wireless/ath/ath9k/mci.c b/drivers/net/wireless/ath/ath9k/mci.c index 0dd2cbb..5c02702 100644 --- a/drivers/net/wireless/ath/ath9k/mci.c +++ b/drivers/net/wireless/ath/ath9k/mci.c @@ -207,23 +207,6 @@ skip_tuning: ath9k_btcoex_timer_resume(sc); } -static void ath_mci_wait_btcal_done(struct ath_softc *sc) -{ - struct ath_hw *ah = sc->sc_ah; - - /* Stop tx & rx */ - ieee80211_stop_queues(sc->hw); - ath_stoprecv(sc); - ath_drain_all_txq(sc, false); - - /* Wait for cal done */ - ar9003_mci_start_reset(ah, ah->curchan); - - /* Resume tx & rx */ - ath_startrecv(sc); - ieee80211_wake_queues(sc->hw); -} - static void ath_mci_cal_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload) { struct ath_hw *ah = sc->sc_ah; @@ -235,7 +218,7 @@ static void ath_mci_cal_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload) case MCI_GPM_BT_CAL_REQ: if (mci_hw->bt_state == MCI_BT_AWAKE) { mci_hw->bt_state = MCI_BT_CAL_START; - ath_mci_wait_btcal_done(sc); + ath9k_queue_reset(sc, RESET_TYPE_MCI); } ath_dbg(common, MCI, "MCI State : %d\n", mci_hw->bt_state); break; @@ -274,8 +257,9 @@ static void ath_mci_set_concur_txprio(struct ath_softc *sc) { struct ath_btcoex *btcoex = &sc->btcoex; struct ath_mci_profile *mci = &btcoex->mci; - u8 stomp_txprio[] = { 0, 0, 0, 0 }; /* all, low, none, low_ftp */ + u8 stomp_txprio[ATH_BTCOEX_STOMP_MAX]; + memset(stomp_txprio, 0, sizeof(stomp_txprio)); if (mci->num_mgmt) { stomp_txprio[ATH_BTCOEX_STOMP_ALL] = ATH_MCI_INQUIRY_PRIO; if (!mci->num_pan && !mci->num_other_acl) @@ -578,6 +562,8 @@ void ath_mci_intr(struct ath_softc *sc) mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_GPM; while (more_data == MCI_GPM_MORE) { + if (test_bit(SC_OP_HW_RESET, &sc->sc_flags)) + return; pgpm = mci->gpm_buf.bf_addr; offset = ar9003_mci_get_next_gpm_offset(ah, false, @@ -744,12 +730,30 @@ void ath9k_mci_set_txpower(struct ath_softc *sc, bool setchannel, ath9k_hw_set_txpowerlimit(ah, sc->config.txpowlimit, false); } +static void ath9k_mci_stomp_audio(struct ath_softc *sc) +{ + struct ath_hw *ah = sc->sc_ah; + struct ath_btcoex *btcoex = &sc->btcoex; + struct ath_mci_profile *mci = &btcoex->mci; + + if (!mci->num_sco && !mci->num_a2dp) + return; + + if (ah->stats.avgbrssi > 25) { + btcoex->stomp_audio = 0; + return; + } + + btcoex->stomp_audio++; +} void ath9k_mci_update_rssi(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; struct ath_btcoex *btcoex = &sc->btcoex; struct ath9k_hw_mci *mci_hw = &sc->sc_ah->btcoex_hw.mci; + ath9k_mci_stomp_audio(sc); + if (!(mci_hw->config & ATH_MCI_CONFIG_CONCUR_TX)) return; diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 9553203..8e9b826 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -287,7 +287,7 @@ static void ath_pci_remove(struct pci_dev *pdev) pci_release_region(pdev, 0); } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int ath_pci_suspend(struct device *device) { @@ -333,22 +333,15 @@ static int ath_pci_resume(struct device *device) return 0; } -static const struct dev_pm_ops ath9k_pm_ops = { - .suspend = ath_pci_suspend, - .resume = ath_pci_resume, - .freeze = ath_pci_suspend, - .thaw = ath_pci_resume, - .poweroff = ath_pci_suspend, - .restore = ath_pci_resume, -}; +static SIMPLE_DEV_PM_OPS(ath9k_pm_ops, ath_pci_suspend, ath_pci_resume); #define ATH9K_PM_OPS (&ath9k_pm_ops) -#else /* !CONFIG_PM */ +#else /* !CONFIG_PM_SLEEP */ #define ATH9K_PM_OPS NULL -#endif /* !CONFIG_PM */ +#endif /* !CONFIG_PM_SLEEP */ MODULE_DEVICE_TABLE(pci, ath_pci_id_table); diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 27ed80b..714558d 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -982,16 +982,6 @@ static void ath_rc_update_per(struct ath_softc *sc, } } -static void ath_debug_stat_retries(struct ath_rate_priv *rc, int rix, - int xretries, int retries, u8 per) -{ - struct ath_rc_stats *stats = &rc->rcstats[rix]; - - stats->xretries += xretries; - stats->retries += retries; - stats->per = per; -} - static void ath_rc_update_ht(struct ath_softc *sc, struct ath_rate_priv *ath_rc_priv, struct ieee80211_tx_info *tx_info, @@ -1065,14 +1055,6 @@ static void ath_rc_update_ht(struct ath_softc *sc, } -static void ath_debug_stat_rc(struct ath_rate_priv *rc, int final_rate) -{ - struct ath_rc_stats *stats; - - stats = &rc->rcstats[final_rate]; - stats->success++; -} - static void ath_rc_tx_status(struct ath_softc *sc, struct ath_rate_priv *ath_rc_priv, struct sk_buff *skb) @@ -1350,7 +1332,25 @@ static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband, } } -#ifdef CONFIG_ATH9K_DEBUGFS +#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_DEBUGFS) + +void ath_debug_stat_rc(struct ath_rate_priv *rc, int final_rate) +{ + struct ath_rc_stats *stats; + + stats = &rc->rcstats[final_rate]; + stats->success++; +} + +void ath_debug_stat_retries(struct ath_rate_priv *rc, int rix, + int xretries, int retries, u8 per) +{ + struct ath_rc_stats *stats = &rc->rcstats[rix]; + + stats->xretries += xretries; + stats->retries += retries; + stats->per = per; +} static ssize_t read_file_rcstat(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -1428,10 +1428,17 @@ static void ath_rate_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir) { struct ath_rate_priv *rc = priv_sta; - debugfs_create_file("rc_stats", S_IRUGO, dir, rc, &fops_rcstat); + rc->debugfs_rcstats = debugfs_create_file("rc_stats", S_IRUGO, + dir, rc, &fops_rcstat); +} + +static void ath_rate_remove_sta_debugfs(void *priv, void *priv_sta) +{ + struct ath_rate_priv *rc = priv_sta; + debugfs_remove(rc->debugfs_rcstats); } -#endif /* CONFIG_ATH9K_DEBUGFS */ +#endif /* CONFIG_MAC80211_DEBUGFS && CONFIG_ATH9K_DEBUGFS */ static void *ath_rate_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) { @@ -1476,8 +1483,10 @@ static struct rate_control_ops ath_rate_ops = { .free = ath_rate_free, .alloc_sta = ath_rate_alloc_sta, .free_sta = ath_rate_free_sta, -#ifdef CONFIG_ATH9K_DEBUGFS + +#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_DEBUGFS) .add_sta_debugfs = ath_rate_add_sta_debugfs, + .remove_sta_debugfs = ath_rate_remove_sta_debugfs, #endif }; diff --git a/drivers/net/wireless/ath/ath9k/rc.h b/drivers/net/wireless/ath/ath9k/rc.h index 268e67d..267dbfc 100644 --- a/drivers/net/wireless/ath/ath9k/rc.h +++ b/drivers/net/wireless/ath/ath9k/rc.h @@ -211,10 +211,26 @@ struct ath_rate_priv { struct ath_rateset neg_ht_rates; const struct ath_rate_table *rate_table; +#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_DEBUGFS) struct dentry *debugfs_rcstats; struct ath_rc_stats rcstats[RATE_TABLE_SIZE]; +#endif }; +#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_DEBUGFS) +void ath_debug_stat_rc(struct ath_rate_priv *rc, int final_rate); +void ath_debug_stat_retries(struct ath_rate_priv *rc, int rix, + int xretries, int retries, u8 per); +#else +static inline void ath_debug_stat_rc(struct ath_rate_priv *rc, int final_rate) +{ +} +static inline void ath_debug_stat_retries(struct ath_rate_priv *rc, int rix, + int xretries, int retries, u8 per) +{ +} +#endif + #ifdef CONFIG_ATH9K_RATE_CONTROL int ath_rate_control_register(void); void ath_rate_control_unregister(void); diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index a04028b..6aafbb7 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -976,7 +976,7 @@ static int ath9k_rx_skb_preprocess(struct ath_common *common, rx_status->freq = hw->conf.channel->center_freq; rx_status->signal = ah->noise + rx_stats->rs_rssi; rx_status->antenna = rx_stats->rs_antenna; - rx_status->flag |= RX_FLAG_MACTIME_MPDU; + rx_status->flag |= RX_FLAG_MACTIME_START; if (rx_stats->rs_moreaggr) rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL; diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 1ffca75..90e48a0 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -312,7 +312,6 @@ static struct ath_buf *ath_tx_get_buffer(struct ath_softc *sc) } bf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list); - bf->bf_next = NULL; list_del(&bf->list); spin_unlock_bh(&sc->tx.txbuflock); @@ -394,7 +393,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, u16 seq_st = 0, acked_cnt = 0, txfail_cnt = 0, seq_first; u32 ba[WME_BA_BMP_SIZE >> 5]; int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0; - bool rc_update = true; + bool rc_update = true, isba; struct ieee80211_tx_rate rates[4]; struct ath_frame_info *fi; int nframes; @@ -438,13 +437,17 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK; tid = ATH_AN_2_TID(an, tidno); seq_first = tid->seq_start; + isba = ts->ts_flags & ATH9K_TX_BA; /* * The hardware occasionally sends a tx status for the wrong TID. * In this case, the BA status cannot be considered valid and all * subframes need to be retransmitted + * + * Only BlockAcks have a TID and therefore normal Acks cannot be + * checked */ - if (tidno != ts->tid) + if (isba && tidno != ts->tid) txok = false; isaggr = bf_isaggr(bf); @@ -1259,7 +1262,7 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc, int tidno; for (tidno = 0, tid = &an->tid[tidno]; - tidno < WME_NUM_TID; tidno++, tid++) { + tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { if (!tid->sched) continue; @@ -1293,7 +1296,7 @@ void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an) int tidno; for (tidno = 0, tid = &an->tid[tidno]; - tidno < WME_NUM_TID; tidno++, tid++) { + tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { ac = tid->ac; txq = ac->txq; @@ -1350,10 +1353,10 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) struct ath_hw *ah = sc->sc_ah; struct ath9k_tx_queue_info qi; static const int subtype_txq_to_hwq[] = { - [WME_AC_BE] = ATH_TXQ_AC_BE, - [WME_AC_BK] = ATH_TXQ_AC_BK, - [WME_AC_VI] = ATH_TXQ_AC_VI, - [WME_AC_VO] = ATH_TXQ_AC_VO, + [IEEE80211_AC_BE] = ATH_TXQ_AC_BE, + [IEEE80211_AC_BK] = ATH_TXQ_AC_BK, + [IEEE80211_AC_VI] = ATH_TXQ_AC_VI, + [IEEE80211_AC_VO] = ATH_TXQ_AC_VO, }; int axq_qnum, i; @@ -2315,6 +2318,8 @@ void ath_tx_edma_tasklet(struct ath_softc *sc) ath_txq_lock(sc, txq); + TX_STAT_INC(txq->axq_qnum, txprocdesc); + if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) { ath_txq_unlock(sc, txq); return; @@ -2442,7 +2447,7 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an) int tidno, acno; for (tidno = 0, tid = &an->tid[tidno]; - tidno < WME_NUM_TID; + tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { tid->an = an; tid->tidno = tidno; @@ -2460,7 +2465,7 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an) } for (acno = 0, ac = &an->ac[acno]; - acno < WME_NUM_AC; acno++, ac++) { + acno < IEEE80211_NUM_ACS; acno++, ac++) { ac->sched = false; ac->txq = sc->tx.txq_map[acno]; INIT_LIST_HEAD(&ac->tid_q); @@ -2475,7 +2480,7 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an) int tidno; for (tidno = 0, tid = &an->tid[tidno]; - tidno < WME_NUM_TID; tidno++, tid++) { + tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { ac = tid->ac; txq = ac->txq; diff --git a/drivers/net/wireless/ath/carl9170/Kconfig b/drivers/net/wireless/ath/carl9170/Kconfig index 267d5dc..13a2045 100644 --- a/drivers/net/wireless/ath/carl9170/Kconfig +++ b/drivers/net/wireless/ath/carl9170/Kconfig @@ -1,6 +1,7 @@ config CARL9170 tristate "Linux Community AR9170 802.11n USB support" depends on USB && MAC80211 && EXPERIMENTAL + select ATH_COMMON select FW_LOADER select CRC32 help diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index 136510e..8cb206a 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c @@ -796,7 +796,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) status.mactime += mactime; if (low_mactime_now <= mactime) status.mactime -= 0x10000; - status.flag |= RX_FLAG_MACTIME_MPDU; + status.flag |= RX_FLAG_MACTIME_START; } chanid = (chanstat & B43_RX_CHAN_ID) >> B43_RX_CHAN_ID_SHIFT; diff --git a/drivers/net/wireless/b43legacy/xmit.c b/drivers/net/wireless/b43legacy/xmit.c index b8ffea6..849a28c 100644 --- a/drivers/net/wireless/b43legacy/xmit.c +++ b/drivers/net/wireless/b43legacy/xmit.c @@ -557,7 +557,7 @@ void b43legacy_rx(struct b43legacy_wldev *dev, status.mactime += mactime; if (low_mactime_now <= mactime) status.mactime -= 0x10000; - status.flag |= RX_FLAG_MACTIME_MPDU; + status.flag |= RX_FLAG_MACTIME_START; } chanid = (chanstat & B43legacy_RX_CHAN_ID) >> diff --git a/drivers/net/wireless/brcm80211/Kconfig b/drivers/net/wireless/brcm80211/Kconfig index b480088..1d92d87 100644 --- a/drivers/net/wireless/brcm80211/Kconfig +++ b/drivers/net/wireless/brcm80211/Kconfig @@ -55,6 +55,17 @@ config BRCMFMAC_USB IEEE802.11n embedded FullMAC WLAN driver. Say Y if you want to use the driver for an USB wireless card. +config BRCM_TRACING + bool "Broadcom device tracing" + depends on BRCMSMAC || BRCMFMAC + ---help--- + If you say Y here, the Broadcom wireless drivers will register + with ftrace to dump event information into the trace ringbuffer. + Tracing can be enabled at runtime to aid in debugging wireless + issues. This option adds a small amount of overhead when tracing + is disabled. If unsure, say Y to allow developers to better help + you when wireless problems occur. + config BRCMDBG bool "Broadcom driver debug functions" depends on BRCMSMAC || BRCMFMAC diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fweh.c b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c index 1e4188c..7a00c46 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fweh.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c @@ -314,7 +314,7 @@ static void brcmf_fweh_event_worker(struct work_struct *work) while ((event = brcmf_fweh_dequeue_event(fweh))) { ifp = drvr->iflist[event->ifidx]; - brcmf_dbg(EVENT, "event %s (%u) ifidx %u bsscfg %u addr %pM:\n", + brcmf_dbg(EVENT, "event %s (%u) ifidx %u bsscfg %u addr %pM\n", brcmf_fweh_event_name(event->code), event->code, event->emsg.ifidx, event->emsg.bsscfgidx, event->emsg.addr); @@ -337,7 +337,7 @@ static void brcmf_fweh_event_worker(struct work_struct *work) emsg.version, emsg.flags, emsg.status, emsg.reason); brcmf_dbg_hex_dump(BRCMF_EVENT_ON(), event->data, min_t(u32, emsg.datalen, 64), - "appended:"); + "event payload, len=%d\n", emsg.datalen); /* special handling of interface event */ if (event->code == BRCMF_E_IF) { @@ -494,6 +494,9 @@ void brcmf_fweh_process_event(struct brcmf_pub *drvr, alloc_flag = GFP_ATOMIC; event = kzalloc(sizeof(*event) + datalen, alloc_flag); + if (!event) + return; + event->code = code; event->ifidx = *ifidx; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/brcm80211/brcmfmac/usb.c index feaca14..39a5baa 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/usb.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c @@ -18,6 +18,7 @@ #include <linux/module.h> #include <linux/firmware.h> #include <linux/usb.h> +#include <linux/vmalloc.h> #include <brcmu_utils.h> #include <brcmu_wifi.h> diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index 769c134..96bc349 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -447,7 +447,7 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev, struct vif_params *params) { struct brcmf_if *ifp = netdev_priv(ndev); - struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); + struct brcmf_cfg80211_vif *vif = ifp->vif; s32 infra = 0; s32 ap = 0; s32 err = 0; @@ -461,15 +461,15 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev, type); return -EOPNOTSUPP; case NL80211_IFTYPE_ADHOC: - cfg->conf->mode = WL_MODE_IBSS; + vif->mode = WL_MODE_IBSS; infra = 0; break; case NL80211_IFTYPE_STATION: - cfg->conf->mode = WL_MODE_BSS; + vif->mode = WL_MODE_BSS; infra = 1; break; case NL80211_IFTYPE_AP: - cfg->conf->mode = WL_MODE_AP; + vif->mode = WL_MODE_AP; ap = 1; break; default: @@ -478,18 +478,16 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev, } if (ap) { - set_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state); + set_bit(BRCMF_VIF_STATUS_AP_CREATING, &vif->sme_state); WL_INFO("IF Type = AP\n"); } else { - err = brcmf_fil_cmd_int_set(netdev_priv(ndev), - BRCMF_C_SET_INFRA, infra); + err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, infra); if (err) { WL_ERR("WLC_SET_INFRA error (%d)\n", err); err = -EAGAIN; goto done; } - WL_INFO("IF Type = %s\n", - (cfg->conf->mode == WL_MODE_IBSS) ? + WL_INFO("IF Type = %s\n", (vif->mode == WL_MODE_IBSS) ? "Adhoc" : "Infra"); } ndev->ieee80211_ptr->iftype = type; @@ -963,22 +961,21 @@ static void brcmf_ch_to_chanspec(int ch, struct brcmf_join_params *join_params, } } -static void brcmf_link_down(struct brcmf_cfg80211_info *cfg) +static void brcmf_link_down(struct brcmf_cfg80211_vif *vif) { - struct net_device *ndev = NULL; s32 err = 0; WL_TRACE("Enter\n"); - if (cfg->link_up) { - ndev = cfg_to_ndev(cfg); + if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state)) { WL_INFO("Call WLC_DISASSOC to stop excess roaming\n "); - err = brcmf_fil_cmd_data_set(netdev_priv(ndev), + err = brcmf_fil_cmd_data_set(vif->ifp, BRCMF_C_DISASSOC, NULL, 0); if (err) WL_ERR("WLC_DISASSOC failed (%d)\n", err); - cfg->link_up = false; + clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state); } + clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state); WL_TRACE("Exit\n"); } @@ -1013,8 +1010,8 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev, else WL_CONN("No BSSID specified\n"); - if (params->channel) - WL_CONN("channel: %d\n", params->channel->center_freq); + if (params->chandef.chan) + WL_CONN("channel: %d\n", params->chandef.chan->center_freq); else WL_CONN("no channel specified\n"); @@ -1087,12 +1084,12 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev, } /* Channel */ - if (params->channel) { + if (params->chandef.chan) { u32 target_channel; cfg->channel = ieee80211_frequency_to_channel( - params->channel->center_freq); + params->chandef.chan->center_freq); if (params->channel_fixed) { /* adding chanspec */ brcmf_ch_to_chanspec(cfg->channel, @@ -1130,7 +1127,6 @@ done: static s32 brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev) { - struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_if *ifp = netdev_priv(ndev); s32 err = 0; @@ -1138,7 +1134,7 @@ brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev) if (!check_vif_up(ifp->vif)) return -EIO; - brcmf_link_down(cfg); + brcmf_link_down(ifp->vif); WL_TRACE("Exit\n"); @@ -1496,7 +1492,6 @@ static s32 brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev, u16 reason_code) { - struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_cfg80211_profile *profile = &ifp->vif->profile; struct brcmf_scb_val_le scbval; @@ -1515,8 +1510,6 @@ brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev, if (err) WL_ERR("error (%d)\n", err); - cfg->link_up = false; - WL_TRACE("Exit\n"); return err; } @@ -1716,7 +1709,6 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, u8 key_idx, bool pairwise, const u8 *mac_addr, struct key_params *params) { - struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_wsec_key key; s32 val; @@ -1758,7 +1750,7 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, WL_CONN("WLAN_CIPHER_SUITE_WEP104\n"); break; case WLAN_CIPHER_SUITE_TKIP: - if (cfg->conf->mode != WL_MODE_AP) { + if (ifp->vif->mode != WL_MODE_AP) { WL_CONN("Swapping key\n"); memcpy(keybuf, &key.data[24], sizeof(keybuf)); memcpy(&key.data[24], &key.data[16], sizeof(keybuf)); @@ -1908,7 +1900,6 @@ static s32 brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, u8 *mac, struct station_info *sinfo) { - struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_cfg80211_profile *profile = &ifp->vif->profile; struct brcmf_scb_val_le scb_val; @@ -1922,7 +1913,7 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, if (!check_vif_up(ifp->vif)) return -EIO; - if (cfg->conf->mode == WL_MODE_AP) { + if (ifp->vif->mode == WL_MODE_AP) { memcpy(&sta_info_le, mac, ETH_ALEN); err = brcmf_fil_iovar_data_get(ifp, "sta_info", &sta_info_le, @@ -1939,7 +1930,7 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, } WL_TRACE("STA idle time : %d ms, connected time :%d sec\n", sinfo->inactive_time, sinfo->connected_time); - } else if (cfg->conf->mode == WL_MODE_BSS) { + } else if (ifp->vif->mode == WL_MODE_BSS) { if (memcmp(mac, bssid, ETH_ALEN)) { WL_ERR("Wrong Mac address cfg_mac-%pM wl_bssid-%pM\n", mac, bssid); @@ -2249,9 +2240,9 @@ CleanUp: return err; } -static bool brcmf_is_ibssmode(struct brcmf_cfg80211_info *cfg) +static bool brcmf_is_ibssmode(struct brcmf_cfg80211_vif *vif) { - return cfg->conf->mode == WL_MODE_IBSS; + return vif->mode == WL_MODE_IBSS; } /* @@ -2336,7 +2327,7 @@ static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg) s32 err = 0; WL_TRACE("Enter\n"); - if (brcmf_is_ibssmode(cfg)) + if (brcmf_is_ibssmode(ifp->vif)) return err; ssid = &profile->ssid; @@ -2596,17 +2587,13 @@ static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy, * While going to suspend if associated with AP disassociate * from AP to save power while system is in suspended state */ - if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state) || - test_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state)) { - WL_INFO("Disassociating from AP before suspend\n"); - brcmf_link_down(cfg); - - /* Make sure WPA_Supplicant receives all the event - * generated due to DISASSOC call to the fw to keep - * the state fw and WPA_Supplicant state consistent - */ - brcmf_delay(500); - } + brcmf_link_down(vif); + + /* Make sure WPA_Supplicant receives all the event + * generated due to DISASSOC call to the fw to keep + * the state fw and WPA_Supplicant state consistent + */ + brcmf_delay(500); } /* end any scanning */ @@ -3306,11 +3293,12 @@ brcmf_parse_vndr_ies(const u8 *vndr_ie_buf, u32 vndr_ie_len, if (vndr_ies->count >= MAX_VNDR_IE_NUMBER) break; next: - remaining_len -= ie->len; - if (remaining_len <= 2) + remaining_len -= (ie->len + TLV_HDR_LEN); + if (remaining_len <= TLV_HDR_LEN) ie = NULL; else - ie = (struct brcmf_tlv *)(((u8 *)ie) + ie->len); + ie = (struct brcmf_tlv *)(((u8 *)ie) + ie->len + + TLV_HDR_LEN); } return err; } @@ -3409,11 +3397,11 @@ s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag, } } - if (mgmt_ie_buf != NULL) { + if (mgmt_ie_buf && *mgmt_ie_len) { if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) && (memcmp(mgmt_ie_buf, curr_ie_buf, parsed_ie_buf_len) == 0)) { - WL_TRACE("Previous mgmt IE is equals to current IE"); + WL_TRACE("Previous mgmt IE equals to current IE\n"); goto exit; } @@ -3451,6 +3439,16 @@ s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag, for (i = 0; i < new_vndr_ies.count; i++) { vndrie_info = &new_vndr_ies.ie_info[i]; + /* verify remained buf size before copy data */ + if (remained_buf_len < (vndrie_info->vndrie.len + + VNDR_IE_VSIE_OFFSET)) { + WL_ERR("no space in mgmt_ie_buf: len left %d", + remained_buf_len); + break; + } + remained_buf_len -= (vndrie_info->ie_len + + VNDR_IE_VSIE_OFFSET); + WL_TRACE("ADDED ID : %d, Len: %d, OUI:%02x:%02x:%02x\n", vndrie_info->vndrie.id, vndrie_info->vndrie.len, @@ -3462,13 +3460,6 @@ s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag, vndrie_info->ie_ptr, vndrie_info->ie_len, "add"); - /* verify remained buf size before copy data */ - remained_buf_len -= vndrie_info->ie_len; - if (remained_buf_len < 0) { - WL_ERR("no space in mgmt_ie_buf: len left %d", - remained_buf_len); - break; - } /* save the parsed IE in wl struct */ memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr, @@ -3506,7 +3497,8 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, s32 bssidx = 0; WL_TRACE("channel_type=%d, beacon_interval=%d, dtim_period=%d,\n", - settings->channel_type, settings->beacon_interval, + cfg80211_get_chandef_type(&settings->chandef), + settings->beacon_interval, settings->dtim_period); WL_TRACE("ssid=%s(%zu), auth_type=%d, inactivity_timeout=%d\n", settings->ssid, settings->ssid_len, settings->auth_type, @@ -3642,22 +3634,20 @@ exit: static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev) { struct brcmf_if *ifp = netdev_priv(ndev); - struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); s32 err = -EPERM; WL_TRACE("Enter\n"); - if (cfg->conf->mode == WL_MODE_AP) { + if (ifp->vif->mode == WL_MODE_AP) { /* Due to most likely deauths outstanding we sleep */ /* first to make sure they get processed by fw. */ msleep(400); - err = brcmf_fil_cmd_int_set(netdev_priv(ndev), - BRCMF_C_SET_AP, 0); + err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 0); if (err < 0) { WL_ERR("setting AP mode failed %d\n", err); goto exit; } - err = brcmf_fil_cmd_int_set(netdev_priv(ndev), BRCMF_C_UP, 0); + err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0); if (err < 0) { WL_ERR("BRCMF_C_UP error %d\n", err); goto exit; @@ -3848,23 +3838,20 @@ static void brcmf_free_vif(struct brcmf_cfg80211_vif *vif) } } -static bool brcmf_is_linkup(struct brcmf_cfg80211_info *cfg, - const struct brcmf_event_msg *e) +static bool brcmf_is_linkup(const struct brcmf_event_msg *e) { u32 event = e->event_code; u32 status = e->status; if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) { WL_CONN("Processing set ssid\n"); - cfg->link_up = true; return true; } return false; } -static bool brcmf_is_linkdown(struct brcmf_cfg80211_info *cfg, - const struct brcmf_event_msg *e) +static bool brcmf_is_linkdown(const struct brcmf_event_msg *e) { u32 event = e->event_code; u16 flags = e->flags; @@ -4114,11 +4101,11 @@ brcmf_notify_connect_status(struct brcmf_if *ifp, struct brcmf_cfg80211_profile *profile = &ifp->vif->profile; s32 err = 0; - if (cfg->conf->mode == WL_MODE_AP) { + if (ifp->vif->mode == WL_MODE_AP) { err = brcmf_notify_connect_status_ap(cfg, ndev, e, data); - } else if (brcmf_is_linkup(cfg, e)) { + } else if (brcmf_is_linkup(e)) { WL_CONN("Linkup\n"); - if (brcmf_is_ibssmode(cfg)) { + if (brcmf_is_ibssmode(ifp->vif)) { memcpy(profile->bssid, e->addr, ETH_ALEN); wl_inform_ibss(cfg, ndev, e->addr); cfg80211_ibss_joined(ndev, e->addr, GFP_KERNEL); @@ -4128,26 +4115,19 @@ brcmf_notify_connect_status(struct brcmf_if *ifp, &ifp->vif->sme_state); } else brcmf_bss_connect_done(cfg, ndev, e, true); - } else if (brcmf_is_linkdown(cfg, e)) { + } else if (brcmf_is_linkdown(e)) { WL_CONN("Linkdown\n"); - if (brcmf_is_ibssmode(cfg)) { - clear_bit(BRCMF_VIF_STATUS_CONNECTING, - &ifp->vif->sme_state); - if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED, - &ifp->vif->sme_state)) - brcmf_link_down(cfg); - } else { + if (!brcmf_is_ibssmode(ifp->vif)) { brcmf_bss_connect_done(cfg, ndev, e, false); if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED, - &ifp->vif->sme_state)) { + &ifp->vif->sme_state)) cfg80211_disconnected(ndev, 0, NULL, 0, GFP_KERNEL); - brcmf_link_down(cfg); - } } + brcmf_link_down(ifp->vif); brcmf_init_prof(ndev_to_prof(ndev)); } else if (brcmf_is_nonetwork(cfg, e)) { - if (brcmf_is_ibssmode(cfg)) + if (brcmf_is_ibssmode(ifp->vif)) clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state); else @@ -4196,7 +4176,6 @@ brcmf_notify_mic_status(struct brcmf_if *ifp, static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf) { - conf->mode = (u32)-1; conf->frag_threshold = (u32)-1; conf->rts_threshold = (u32)-1; conf->retry_short = (u32)-1; @@ -4281,7 +4260,6 @@ static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg) mutex_init(&cfg->usr_sync); brcmf_init_escan(cfg); brcmf_init_conf(cfg->conf); - brcmf_link_down(cfg); return err; } @@ -4289,7 +4267,6 @@ static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg) static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg) { cfg->dongle_up = false; /* dongle down */ - brcmf_link_down(cfg); brcmf_abort_scanning(cfg); brcmf_deinit_priv_mem(cfg); } @@ -4536,11 +4513,8 @@ static s32 __brcmf_cfg80211_down(struct brcmf_if *ifp) * While going down, if associated with AP disassociate * from AP to save power */ - if ((test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state) || - test_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state)) && - check_vif_up(ifp->vif)) { - WL_INFO("Disassociating from AP"); - brcmf_link_down(cfg); + if (check_vif_up(ifp->vif)) { + brcmf_link_down(ifp->vif); /* Make sure WPA_Supplicant receives all the event generated due to DISASSOC call to the fw to keep diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h index e2ef851..d60de18 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h @@ -128,7 +128,6 @@ enum wl_mode { /* dongle configuration */ struct brcmf_cfg80211_conf { - u32 mode; /* adhoc , infrastructure or ap */ u32 frag_threshold; u32 rts_threshold; u32 retry_short; @@ -359,7 +358,6 @@ struct brcmf_pno_scanresults_le { * @active_scan: current scan mode. * @sched_escan: e-scan for scheduled scan support running. * @ibss_starter: indicates this sta is ibss starter. - * @link_up: link/connection up flag. * @pwr_save: indicate whether dongle to support power save mode. * @dongle_up: indicate whether dongle up or not. * @roam_on: on/off switch for dongle self-roaming. @@ -391,7 +389,6 @@ struct brcmf_cfg80211_info { bool active_scan; bool sched_escan; bool ibss_starter; - bool link_up; bool pwr_save; bool dongle_up; bool roam_on; diff --git a/drivers/net/wireless/brcm80211/brcmsmac/Makefile b/drivers/net/wireless/brcm80211/brcmsmac/Makefile index e227c4c..d3d4151 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/Makefile +++ b/drivers/net/wireless/brcm80211/brcmsmac/Makefile @@ -40,7 +40,8 @@ BRCMSMAC_OFILES := \ phy/phytbl_n.o \ phy/phy_qmath.o \ dma.o \ - brcms_trace_events.o + brcms_trace_events.o \ + debug.o MODULEPFX := brcmsmac diff --git a/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c b/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c index be5bcfb..1de94f3 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c @@ -21,6 +21,8 @@ #include "antsel.h" #include "main.h" #include "ampdu.h" +#include "debug.h" +#include "brcms_trace_events.h" /* max number of mpdus in an ampdu */ #define AMPDU_MAX_MPDU 32 @@ -40,8 +42,6 @@ #define AMPDU_DEF_RETRY_LIMIT 5 /* default tx retry limit at reg rate */ #define AMPDU_DEF_RR_RETRY_LIMIT 2 -/* default weight of ampdu in txfifo */ -#define AMPDU_DEF_TXPKT_WEIGHT 2 /* default ffpld reserved bytes */ #define AMPDU_DEF_FFPLD_RSVD 2048 /* # of inis to be freed on detach */ @@ -114,7 +114,6 @@ struct brcms_fifo_info { * mpdu_density: min mpdu spacing (0-7) ==> 2^(x-1)/8 usec * max_pdu: max pdus allowed in ampdu * dur: max duration of an ampdu (in msec) - * txpkt_weight: weight of ampdu in txfifo; reduces rate lag * rx_factor: maximum rx ampdu factor (0-3) ==> 2^(13+x) bytes * ffpld_rsvd: number of bytes to reserve for preload * max_txlen: max size of ampdu per mcs, bw and sgi @@ -136,7 +135,6 @@ struct ampdu_info { u8 mpdu_density; s8 max_pdu; u8 dur; - u8 txpkt_weight; u8 rx_factor; u32 ffpld_rsvd; u32 max_txlen[MCS_TABLE_SIZE][2][2]; @@ -183,18 +181,19 @@ static bool brcms_c_ampdu_cap(struct ampdu_info *ampdu) static int brcms_c_ampdu_set(struct ampdu_info *ampdu, bool on) { struct brcms_c_info *wlc = ampdu->wlc; + struct bcma_device *core = wlc->hw->d11core; wlc->pub->_ampdu = false; if (on) { if (!(wlc->pub->_n_enab & SUPPORT_11N)) { - wiphy_err(ampdu->wlc->wiphy, "wl%d: driver not " - "nmode enabled\n", wlc->pub->unit); + brcms_err(core, "wl%d: driver not nmode enabled\n", + wlc->pub->unit); return -ENOTSUPP; } if (!brcms_c_ampdu_cap(ampdu)) { - wiphy_err(ampdu->wlc->wiphy, "wl%d: device not " - "ampdu capable\n", wlc->pub->unit); + brcms_err(core, "wl%d: device not ampdu capable\n", + wlc->pub->unit); return -ENOTSUPP; } wlc->pub->_ampdu = on; @@ -247,7 +246,6 @@ struct ampdu_info *brcms_c_ampdu_attach(struct brcms_c_info *wlc) ampdu->mpdu_density = AMPDU_DEF_MPDU_DENSITY; ampdu->max_pdu = AUTO; ampdu->dur = AMPDU_MAX_DUR; - ampdu->txpkt_weight = AMPDU_DEF_TXPKT_WEIGHT; ampdu->ffpld_rsvd = AMPDU_DEF_FFPLD_RSVD; /* @@ -374,7 +372,8 @@ static int brcms_c_ffpld_check_txfunfl(struct brcms_c_info *wlc, int fid) offsetof(struct macstat, txfunfl[fid])); new_txunfl = (u16) (cur_txunfl - fifo->prev_txfunfl); if (new_txunfl == 0) { - BCMMSG(wlc->wiphy, "TX status FRAG set but no tx underflows\n"); + brcms_dbg_ht(wlc->hw->d11core, + "TX status FRAG set but no tx underflows\n"); return -1; } fifo->prev_txfunfl = cur_txunfl; @@ -396,8 +395,8 @@ static int brcms_c_ffpld_check_txfunfl(struct brcms_c_info *wlc, int fid) if (fifo->accum_txfunfl < 10) return 0; - BCMMSG(wlc->wiphy, "ampdu_count %d tx_underflows %d\n", - current_ampdu_cnt, fifo->accum_txfunfl); + brcms_dbg_ht(wlc->hw->d11core, "ampdu_count %d tx_underflows %d\n", + current_ampdu_cnt, fifo->accum_txfunfl); /* compute the current ratio of tx unfl per ampdu. @@ -450,9 +449,10 @@ static int brcms_c_ffpld_check_txfunfl(struct brcms_c_info *wlc, int fid) (max_mpdu * FFPLD_MPDU_SIZE - fifo->ampdu_pld_size)) / (max_mpdu * FFPLD_MPDU_SIZE)) * 100; - BCMMSG(wlc->wiphy, "DMA estimated transfer rate %d; " - "pre-load size %d\n", - fifo->dmaxferrate, fifo->ampdu_pld_size); + brcms_dbg_ht(wlc->hw->d11core, + "DMA estimated transfer rate %d; " + "pre-load size %d\n", + fifo->dmaxferrate, fifo->ampdu_pld_size); } else { /* decrease ampdu size */ @@ -486,7 +486,7 @@ brcms_c_ampdu_tx_operational(struct brcms_c_info *wlc, u8 tid, scb_ampdu = &scb->scb_ampdu; if (!ampdu->ini_enable[tid]) { - wiphy_err(ampdu->wlc->wiphy, "%s: Rejecting tid %d\n", + brcms_err(wlc->hw->d11core, "%s: Rejecting tid %d\n", __func__, tid); return; } @@ -498,378 +498,324 @@ brcms_c_ampdu_tx_operational(struct brcms_c_info *wlc, u8 tid, scb_ampdu->max_rx_ampdu_bytes = max_rx_ampdu_bytes; } -int -brcms_c_sendampdu(struct ampdu_info *ampdu, struct brcms_txq_info *qi, - struct sk_buff **pdu, int prec) +void brcms_c_ampdu_reset_session(struct brcms_ampdu_session *session, + struct brcms_c_info *wlc) { - struct brcms_c_info *wlc; - struct sk_buff *p, *pkt[AMPDU_MAX_MPDU]; - u8 tid, ndelim; - int err = 0; - u8 preamble_type = BRCMS_GF_PREAMBLE; - u8 fbr_preamble_type = BRCMS_GF_PREAMBLE; - u8 rts_preamble_type = BRCMS_LONG_PREAMBLE; - u8 rts_fbr_preamble_type = BRCMS_LONG_PREAMBLE; + session->wlc = wlc; + skb_queue_head_init(&session->skb_list); + session->max_ampdu_len = 0; /* determined from first MPDU */ + session->max_ampdu_frames = 0; /* determined from first MPDU */ + session->ampdu_len = 0; + session->dma_len = 0; +} - bool rr = true, fbr = false; - uint i, count = 0, fifo, seg_cnt = 0; - u16 plen, len, seq = 0, mcl, mch, index, frameid, dma_len = 0; - u32 ampdu_len, max_ampdu_bytes = 0; - struct d11txh *txh = NULL; +/* + * Preps the given packet for AMPDU based on the session data. If the + * frame cannot be accomodated in the current session, -ENOSPC is + * returned. + */ +int brcms_c_ampdu_add_frame(struct brcms_ampdu_session *session, + struct sk_buff *p) +{ + struct brcms_c_info *wlc = session->wlc; + struct ampdu_info *ampdu = wlc->ampdu; + struct scb *scb = &wlc->pri_scb; + struct scb_ampdu *scb_ampdu = &scb->scb_ampdu; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(p); + struct ieee80211_tx_rate *txrate = tx_info->status.rates; + struct d11txh *txh = (struct d11txh *)p->data; + unsigned ampdu_frames; + u8 ndelim, tid; u8 *plcp; - struct ieee80211_hdr *h; - struct scb *scb; - struct scb_ampdu *scb_ampdu; - struct scb_ampdu_tid_ini *ini; - u8 mcs = 0; - bool use_rts = false, use_cts = false; - u32 rspec = 0, rspec_fallback = 0; - u32 rts_rspec = 0, rts_rspec_fallback = 0; - u16 mimo_ctlchbw = PHY_TXC1_BW_20MHZ; - struct ieee80211_rts *rts; - u8 rr_retry_limit; - struct brcms_fifo_info *f; + uint len; + u16 mcl; bool fbr_iscck; - struct ieee80211_tx_info *tx_info; - u16 qlen; - struct wiphy *wiphy; - - wlc = ampdu->wlc; - wiphy = wlc->wiphy; - p = *pdu; - - tid = (u8) (p->priority); + bool rr; - f = ampdu->fifo_tb + prio2fifo[tid]; + ndelim = txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM]; + plcp = (u8 *)(txh + 1); + fbr_iscck = !(le16_to_cpu(txh->XtraFrameTypes) & 0x03); + len = fbr_iscck ? BRCMS_GET_CCK_PLCP_LEN(txh->FragPLCPFallback) : + BRCMS_GET_MIMO_PLCP_LEN(txh->FragPLCPFallback); + len = roundup(len, 4) + (ndelim + 1) * AMPDU_DELIMITER_LEN; - scb = &wlc->pri_scb; - scb_ampdu = &scb->scb_ampdu; - ini = &scb_ampdu->ini[tid]; + ampdu_frames = skb_queue_len(&session->skb_list); + if (ampdu_frames != 0) { + struct sk_buff *first; - /* Let pressure continue to build ... */ - qlen = pktq_plen(&qi->q, prec); - if (ini->tx_in_transit > 0 && - qlen < min(scb_ampdu->max_pdu, ini->ba_wsize)) - /* Collect multiple MPDU's to be sent in the next AMPDU */ - return -EBUSY; + if (ampdu_frames + 1 > session->max_ampdu_frames || + session->ampdu_len + len > session->max_ampdu_len) + return -ENOSPC; - /* at this point we intend to transmit an AMPDU */ - rr_retry_limit = ampdu->rr_retry_limit_tid[tid]; - ampdu_len = 0; - dma_len = 0; - while (p) { - struct ieee80211_tx_rate *txrate; - - tx_info = IEEE80211_SKB_CB(p); - txrate = tx_info->status.rates; + /* + * We aren't really out of space if the new frame is of + * a different priority, but we want the same behaviour + * so return -ENOSPC anyway. + * + * XXX: The old AMPDU code did this, but is it really + * necessary? + */ + first = skb_peek(&session->skb_list); + if (p->priority != first->priority) + return -ENOSPC; + } - if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { - err = brcms_c_prep_pdu(wlc, p, &fifo); - } else { - wiphy_err(wiphy, "%s: AMPDU flag is off!\n", __func__); - *pdu = NULL; - err = 0; - break; - } + /* + * Now that we're sure this frame can be accomodated, update the + * session information. + */ + session->ampdu_len += len; + session->dma_len += p->len; - if (err) { - if (err == -EBUSY) { - wiphy_err(wiphy, "wl%d: sendampdu: " - "prep_xdu retry; seq 0x%x\n", - wlc->pub->unit, seq); - *pdu = p; - break; - } + tid = (u8)p->priority; - /* error in the packet; reject it */ - wiphy_err(wiphy, "wl%d: sendampdu: prep_xdu " - "rejected; seq 0x%x\n", wlc->pub->unit, seq); - *pdu = NULL; - break; - } + /* Handle retry limits */ + if (txrate[0].count <= ampdu->rr_retry_limit_tid[tid]) { + txrate[0].count++; + rr = true; + } else { + txrate[1].count++; + rr = false; + } - /* pkt is good to be aggregated */ - txh = (struct d11txh *) p->data; - plcp = (u8 *) (txh + 1); - h = (struct ieee80211_hdr *)(plcp + D11_PHY_HDR_LEN); - seq = le16_to_cpu(h->seq_ctrl) >> SEQNUM_SHIFT; - index = TX_SEQ_TO_INDEX(seq); + if (ampdu_frames == 0) { + u8 plcp0, plcp3, is40, sgi, mcs; + uint fifo = le16_to_cpu(txh->TxFrameID) & TXFID_QUEUE_MASK; + struct brcms_fifo_info *f = &du->fifo_tb[fifo]; - /* check mcl fields and test whether it can be agg'd */ - mcl = le16_to_cpu(txh->MacTxControlLow); - mcl &= ~TXC_AMPDU_MASK; - fbr_iscck = !(le16_to_cpu(txh->XtraFrameTypes) & 0x3); - txh->PreloadSize = 0; /* always default to 0 */ - - /* Handle retry limits */ - if (txrate[0].count <= rr_retry_limit) { - txrate[0].count++; - rr = true; - fbr = false; + if (rr) { + plcp0 = plcp[0]; + plcp3 = plcp[3]; } else { - fbr = true; - rr = false; - txrate[1].count++; - } - - /* extract the length info */ - len = fbr_iscck ? BRCMS_GET_CCK_PLCP_LEN(txh->FragPLCPFallback) - : BRCMS_GET_MIMO_PLCP_LEN(txh->FragPLCPFallback); - - /* retrieve null delimiter count */ - ndelim = txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM]; - seg_cnt += 1; + plcp0 = txh->FragPLCPFallback[0]; + plcp3 = txh->FragPLCPFallback[3]; - BCMMSG(wlc->wiphy, "wl%d: mpdu %d plcp_len %d\n", - wlc->pub->unit, count, len); - - /* - * aggregateable mpdu. For ucode/hw agg, - * test whether need to break or change the epoch - */ - if (count == 0) { - mcl |= (TXC_AMPDU_FIRST << TXC_AMPDU_SHIFT); - /* refill the bits since might be a retx mpdu */ - mcl |= TXC_STARTMSDU; - rts = (struct ieee80211_rts *)&txh->rts_frame; - - if (ieee80211_is_rts(rts->frame_control)) { - mcl |= TXC_SENDRTS; - use_rts = true; - } - if (ieee80211_is_cts(rts->frame_control)) { - mcl |= TXC_SENDCTS; - use_cts = true; - } - } else { - mcl |= (TXC_AMPDU_MIDDLE << TXC_AMPDU_SHIFT); - mcl &= ~(TXC_STARTMSDU | TXC_SENDRTS | TXC_SENDCTS); } - len = roundup(len, 4); - ampdu_len += (len + (ndelim + 1) * AMPDU_DELIMITER_LEN); + /* Limit AMPDU size based on MCS */ + is40 = (plcp0 & MIMO_PLCP_40MHZ) ? 1 : 0; + sgi = plcp3_issgi(plcp3) ? 1 : 0; + mcs = plcp0 & ~MIMO_PLCP_40MHZ; + session->max_ampdu_len = min(scb_ampdu->max_rx_ampdu_bytes, + ampdu->max_txlen[mcs][is40][sgi]); - dma_len += (u16) p->len; + session->max_ampdu_frames = scb_ampdu->max_pdu; + if (mcs_2_rate(mcs, true, false) >= f->dmaxferrate) { + session->max_ampdu_frames = + min_t(u16, f->mcs2ampdu_table[mcs], + session->max_ampdu_frames); + } + } - BCMMSG(wlc->wiphy, "wl%d: ampdu_len %d" - " seg_cnt %d null delim %d\n", - wlc->pub->unit, ampdu_len, seg_cnt, ndelim); + /* + * Treat all frames as "middle" frames of AMPDU here. First and + * last frames must be fixed up after all MPDUs have been prepped. + */ + mcl = le16_to_cpu(txh->MacTxControlLow); + mcl &= ~TXC_AMPDU_MASK; + mcl |= (TXC_AMPDU_MIDDLE << TXC_AMPDU_SHIFT); + mcl &= ~(TXC_STARTMSDU | TXC_SENDRTS | TXC_SENDCTS); + txh->MacTxControlLow = cpu_to_le16(mcl); + txh->PreloadSize = 0; /* always default to 0 */ - txh->MacTxControlLow = cpu_to_le16(mcl); + skb_queue_tail(&session->skb_list, p); - /* this packet is added */ - pkt[count++] = p; + return 0; +} - /* patch the first MPDU */ - if (count == 1) { - u8 plcp0, plcp3, is40, sgi; +void brcms_c_ampdu_finalize(struct brcms_ampdu_session *session) +{ + struct brcms_c_info *wlc = session->wlc; + struct ampdu_info *ampdu = wlc->ampdu; + struct sk_buff *first, *last; + struct d11txh *txh; + struct ieee80211_tx_info *tx_info; + struct ieee80211_tx_rate *txrate; + u8 ndelim; + u8 *plcp; + uint len; + uint fifo; + struct brcms_fifo_info *f; + u16 mcl; + bool fbr; + bool fbr_iscck; + struct ieee80211_rts *rts; + bool use_rts = false, use_cts = false; + u16 dma_len = session->dma_len; + u16 mimo_ctlchbw = PHY_TXC1_BW_20MHZ; + u32 rspec = 0, rspec_fallback = 0; + u32 rts_rspec = 0, rts_rspec_fallback = 0; + u8 plcp0, plcp3, is40, sgi, mcs; + u16 mch; + u8 preamble_type = BRCMS_GF_PREAMBLE; + u8 fbr_preamble_type = BRCMS_GF_PREAMBLE; + u8 rts_preamble_type = BRCMS_LONG_PREAMBLE; + u8 rts_fbr_preamble_type = BRCMS_LONG_PREAMBLE; - if (rr) { - plcp0 = plcp[0]; - plcp3 = plcp[3]; - } else { - plcp0 = txh->FragPLCPFallback[0]; - plcp3 = txh->FragPLCPFallback[3]; + if (skb_queue_empty(&session->skb_list)) + return; - } - is40 = (plcp0 & MIMO_PLCP_40MHZ) ? 1 : 0; - sgi = plcp3_issgi(plcp3) ? 1 : 0; - mcs = plcp0 & ~MIMO_PLCP_40MHZ; - max_ampdu_bytes = - min(scb_ampdu->max_rx_ampdu_bytes, - ampdu->max_txlen[mcs][is40][sgi]); - - if (is40) - mimo_ctlchbw = - CHSPEC_SB_UPPER(wlc_phy_chanspec_get( - wlc->band->pi)) - ? PHY_TXC1_BW_20MHZ_UP : PHY_TXC1_BW_20MHZ; - - /* rebuild the rspec and rspec_fallback */ - rspec = RSPEC_MIMORATE; - rspec |= plcp[0] & ~MIMO_PLCP_40MHZ; - if (plcp[0] & MIMO_PLCP_40MHZ) - rspec |= (PHY_TXC1_BW_40MHZ << RSPEC_BW_SHIFT); - - if (fbr_iscck) /* CCK */ - rspec_fallback = cck_rspec(cck_phy2mac_rate - (txh->FragPLCPFallback[0])); - else { /* MIMO */ - rspec_fallback = RSPEC_MIMORATE; - rspec_fallback |= - txh->FragPLCPFallback[0] & ~MIMO_PLCP_40MHZ; - if (txh->FragPLCPFallback[0] & MIMO_PLCP_40MHZ) - rspec_fallback |= - (PHY_TXC1_BW_40MHZ << - RSPEC_BW_SHIFT); - } + first = skb_peek(&session->skb_list); + last = skb_peek_tail(&session->skb_list); + + /* Need to fix up last MPDU first to adjust AMPDU length */ + txh = (struct d11txh *)last->data; + fifo = le16_to_cpu(txh->TxFrameID) & TXFID_QUEUE_MASK; + f = &du->fifo_tb[fifo]; + + mcl = le16_to_cpu(txh->MacTxControlLow); + mcl &= ~TXC_AMPDU_MASK; + mcl |= (TXC_AMPDU_LAST << TXC_AMPDU_SHIFT); + txh->MacTxControlLow = cpu_to_le16(mcl); + + /* remove the null delimiter after last mpdu */ + ndelim = txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM]; + txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM] = 0; + session->ampdu_len -= ndelim * AMPDU_DELIMITER_LEN; + + /* remove the pad len from last mpdu */ + fbr_iscck = ((le16_to_cpu(txh->XtraFrameTypes) & 0x3) == 0); + len = fbr_iscck ? BRCMS_GET_CCK_PLCP_LEN(txh->FragPLCPFallback) : + BRCMS_GET_MIMO_PLCP_LEN(txh->FragPLCPFallback); + session->ampdu_len -= roundup(len, 4) - len; + + /* Now fix up the first MPDU */ + tx_info = IEEE80211_SKB_CB(first); + txrate = tx_info->status.rates; + txh = (struct d11txh *)first->data; + plcp = (u8 *)(txh + 1); + rts = (struct ieee80211_rts *)&txh->rts_frame; + + mcl = le16_to_cpu(txh->MacTxControlLow); + /* If only one MPDU leave it marked as last */ + if (first != last) { + mcl &= ~TXC_AMPDU_MASK; + mcl |= (TXC_AMPDU_FIRST << TXC_AMPDU_SHIFT); + } + mcl |= TXC_STARTMSDU; + if (ieee80211_is_rts(rts->frame_control)) { + mcl |= TXC_SENDRTS; + use_rts = true; + } + if (ieee80211_is_cts(rts->frame_control)) { + mcl |= TXC_SENDCTS; + use_cts = true; + } + txh->MacTxControlLow = cpu_to_le16(mcl); - if (use_rts || use_cts) { - rts_rspec = - brcms_c_rspec_to_rts_rspec(wlc, - rspec, false, mimo_ctlchbw); - rts_rspec_fallback = - brcms_c_rspec_to_rts_rspec(wlc, - rspec_fallback, false, mimo_ctlchbw); - } - } + fbr = txrate[1].count > 0; + if (!fbr) { + plcp0 = plcp[0]; + plcp3 = plcp[3]; + } else { + plcp0 = txh->FragPLCPFallback[0]; + plcp3 = txh->FragPLCPFallback[3]; + } + is40 = (plcp0 & MIMO_PLCP_40MHZ) ? 1 : 0; + sgi = plcp3_issgi(plcp3) ? 1 : 0; + mcs = plcp0 & ~MIMO_PLCP_40MHZ; + + if (is40) { + if (CHSPEC_SB_UPPER(wlc_phy_chanspec_get(wlc->band->pi))) + mimo_ctlchbw = PHY_TXC1_BW_20MHZ_UP; + else + mimo_ctlchbw = PHY_TXC1_BW_20MHZ; + } - /* if (first mpdu for host agg) */ - /* test whether to add more */ - if ((mcs_2_rate(mcs, true, false) >= f->dmaxferrate) && - (count == f->mcs2ampdu_table[mcs])) { - BCMMSG(wlc->wiphy, "wl%d: PR 37644: stopping" - " ampdu at %d for mcs %d\n", - wlc->pub->unit, count, mcs); - break; - } + /* rebuild the rspec and rspec_fallback */ + rspec = RSPEC_MIMORATE; + rspec |= plcp[0] & ~MIMO_PLCP_40MHZ; + if (plcp[0] & MIMO_PLCP_40MHZ) + rspec |= (PHY_TXC1_BW_40MHZ << RSPEC_BW_SHIFT); - if (count == scb_ampdu->max_pdu) - break; + fbr_iscck = !(le16_to_cpu(txh->XtraFrameTypes) & 0x03); + if (fbr_iscck) { + rspec_fallback = + cck_rspec(cck_phy2mac_rate(txh->FragPLCPFallback[0])); + } else { + rspec_fallback = RSPEC_MIMORATE; + rspec_fallback |= txh->FragPLCPFallback[0] & ~MIMO_PLCP_40MHZ; + if (txh->FragPLCPFallback[0] & MIMO_PLCP_40MHZ) + rspec_fallback |= PHY_TXC1_BW_40MHZ << RSPEC_BW_SHIFT; + } - /* - * check to see if the next pkt is - * a candidate for aggregation - */ - p = pktq_ppeek(&qi->q, prec); - if (p) { - tx_info = IEEE80211_SKB_CB(p); - if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && - ((u8) (p->priority) == tid)) { - plen = p->len + AMPDU_MAX_MPDU_OVERHEAD; - plen = max(scb_ampdu->min_len, plen); + if (use_rts || use_cts) { + rts_rspec = + brcms_c_rspec_to_rts_rspec(wlc, rspec, + false, mimo_ctlchbw); + rts_rspec_fallback = + brcms_c_rspec_to_rts_rspec(wlc, rspec_fallback, + false, mimo_ctlchbw); + } - if ((plen + ampdu_len) > max_ampdu_bytes) { - p = NULL; - continue; - } + BRCMS_SET_MIMO_PLCP_LEN(plcp, session->ampdu_len); + /* mark plcp to indicate ampdu */ + BRCMS_SET_MIMO_PLCP_AMPDU(plcp); - /* - * check if there are enough - * descriptors available - */ - if (*wlc->core->txavail[fifo] <= seg_cnt + 1) { - wiphy_err(wiphy, "%s: No fifo space " - "!!\n", __func__); - p = NULL; - continue; - } - /* next packet fit for aggregation so dequeue */ - p = brcmu_pktq_pdeq(&qi->q, prec); - } else { - p = NULL; - } - } - } /* end while(p) */ + /* reset the mixed mode header durations */ + if (txh->MModeLen) { + u16 mmodelen = brcms_c_calc_lsig_len(wlc, rspec, + session->ampdu_len); + txh->MModeLen = cpu_to_le16(mmodelen); + preamble_type = BRCMS_MM_PREAMBLE; + } + if (txh->MModeFbrLen) { + u16 mmfbrlen = brcms_c_calc_lsig_len(wlc, rspec_fallback, + session->ampdu_len); + txh->MModeFbrLen = cpu_to_le16(mmfbrlen); + fbr_preamble_type = BRCMS_MM_PREAMBLE; + } - ini->tx_in_transit += count; + /* set the preload length */ + if (mcs_2_rate(mcs, true, false) >= f->dmaxferrate) { + dma_len = min(dma_len, f->ampdu_pld_size); + txh->PreloadSize = cpu_to_le16(dma_len); + } else { + txh->PreloadSize = 0; + } - if (count) { - /* patch up the last txh */ - txh = (struct d11txh *) pkt[count - 1]->data; - mcl = le16_to_cpu(txh->MacTxControlLow); - mcl &= ~TXC_AMPDU_MASK; - mcl |= (TXC_AMPDU_LAST << TXC_AMPDU_SHIFT); - txh->MacTxControlLow = cpu_to_le16(mcl); - - /* remove the null delimiter after last mpdu */ - ndelim = txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM]; - txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM] = 0; - ampdu_len -= ndelim * AMPDU_DELIMITER_LEN; - - /* remove the pad len from last mpdu */ - fbr_iscck = ((le16_to_cpu(txh->XtraFrameTypes) & 0x3) == 0); - len = fbr_iscck ? BRCMS_GET_CCK_PLCP_LEN(txh->FragPLCPFallback) - : BRCMS_GET_MIMO_PLCP_LEN(txh->FragPLCPFallback); - ampdu_len -= roundup(len, 4) - len; - - /* patch up the first txh & plcp */ - txh = (struct d11txh *) pkt[0]->data; - plcp = (u8 *) (txh + 1); + mch = le16_to_cpu(txh->MacTxControlHigh); - BRCMS_SET_MIMO_PLCP_LEN(plcp, ampdu_len); - /* mark plcp to indicate ampdu */ - BRCMS_SET_MIMO_PLCP_AMPDU(plcp); + /* update RTS dur fields */ + if (use_rts || use_cts) { + u16 durid; + if ((mch & TXC_PREAMBLE_RTS_MAIN_SHORT) == + TXC_PREAMBLE_RTS_MAIN_SHORT) + rts_preamble_type = BRCMS_SHORT_PREAMBLE; - /* reset the mixed mode header durations */ - if (txh->MModeLen) { - u16 mmodelen = - brcms_c_calc_lsig_len(wlc, rspec, ampdu_len); - txh->MModeLen = cpu_to_le16(mmodelen); - preamble_type = BRCMS_MM_PREAMBLE; - } - if (txh->MModeFbrLen) { - u16 mmfbrlen = - brcms_c_calc_lsig_len(wlc, rspec_fallback, - ampdu_len); - txh->MModeFbrLen = cpu_to_le16(mmfbrlen); - fbr_preamble_type = BRCMS_MM_PREAMBLE; - } + if ((mch & TXC_PREAMBLE_RTS_FB_SHORT) == + TXC_PREAMBLE_RTS_FB_SHORT) + rts_fbr_preamble_type = BRCMS_SHORT_PREAMBLE; - /* set the preload length */ - if (mcs_2_rate(mcs, true, false) >= f->dmaxferrate) { - dma_len = min(dma_len, f->ampdu_pld_size); - txh->PreloadSize = cpu_to_le16(dma_len); - } else - txh->PreloadSize = 0; - - mch = le16_to_cpu(txh->MacTxControlHigh); - - /* update RTS dur fields */ - if (use_rts || use_cts) { - u16 durid; - rts = (struct ieee80211_rts *)&txh->rts_frame; - if ((mch & TXC_PREAMBLE_RTS_MAIN_SHORT) == - TXC_PREAMBLE_RTS_MAIN_SHORT) - rts_preamble_type = BRCMS_SHORT_PREAMBLE; - - if ((mch & TXC_PREAMBLE_RTS_FB_SHORT) == - TXC_PREAMBLE_RTS_FB_SHORT) - rts_fbr_preamble_type = BRCMS_SHORT_PREAMBLE; - - durid = - brcms_c_compute_rtscts_dur(wlc, use_cts, rts_rspec, + durid = brcms_c_compute_rtscts_dur(wlc, use_cts, rts_rspec, rspec, rts_preamble_type, - preamble_type, ampdu_len, - true); - rts->duration = cpu_to_le16(durid); - durid = brcms_c_compute_rtscts_dur(wlc, use_cts, - rts_rspec_fallback, - rspec_fallback, - rts_fbr_preamble_type, - fbr_preamble_type, - ampdu_len, true); - txh->RTSDurFallback = cpu_to_le16(durid); - /* set TxFesTimeNormal */ - txh->TxFesTimeNormal = rts->duration; - /* set fallback rate version of TxFesTimeNormal */ - txh->TxFesTimeFallback = txh->RTSDurFallback; - } - - /* set flag and plcp for fallback rate */ - if (fbr) { - mch |= TXC_AMPDU_FBR; - txh->MacTxControlHigh = cpu_to_le16(mch); - BRCMS_SET_MIMO_PLCP_AMPDU(plcp); - BRCMS_SET_MIMO_PLCP_AMPDU(txh->FragPLCPFallback); - } - - BCMMSG(wlc->wiphy, "wl%d: count %d ampdu_len %d\n", - wlc->pub->unit, count, ampdu_len); - - /* inform rate_sel if it this is a rate probe pkt */ - frameid = le16_to_cpu(txh->TxFrameID); - if (frameid & TXFID_RATE_PROBE_MASK) - wiphy_err(wiphy, "%s: XXX what to do with " - "TXFID_RATE_PROBE_MASK!?\n", __func__); - - for (i = 0; i < count; i++) - brcms_c_txfifo(wlc, fifo, pkt[i], i == (count - 1), - ampdu->txpkt_weight); + preamble_type, + session->ampdu_len, true); + rts->duration = cpu_to_le16(durid); + durid = brcms_c_compute_rtscts_dur(wlc, use_cts, + rts_rspec_fallback, + rspec_fallback, + rts_fbr_preamble_type, + fbr_preamble_type, + session->ampdu_len, true); + txh->RTSDurFallback = cpu_to_le16(durid); + /* set TxFesTimeNormal */ + txh->TxFesTimeNormal = rts->duration; + /* set fallback rate version of TxFesTimeNormal */ + txh->TxFesTimeFallback = txh->RTSDurFallback; + } + /* set flag and plcp for fallback rate */ + if (fbr) { + mch |= TXC_AMPDU_FBR; + txh->MacTxControlHigh = cpu_to_le16(mch); + BRCMS_SET_MIMO_PLCP_AMPDU(plcp); + BRCMS_SET_MIMO_PLCP_AMPDU(txh->FragPLCPFallback); } - /* endif (count) */ - return err; + + brcms_dbg_ht(wlc->hw->d11core, "wl%d: count %d ampdu_len %d\n", + wlc->pub->unit, skb_queue_len(&session->skb_list), + session->ampdu_len); } static void @@ -909,7 +855,6 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb, u8 antselid = 0; u8 retry_limit, rr_retry_limit; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(p); - struct wiphy *wiphy = wlc->wiphy; #ifdef DEBUG u8 hole[AMPDU_MAX_MPDU]; @@ -955,13 +900,14 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb, if (supr_status) { update_rate = false; if (supr_status == TX_STATUS_SUPR_BADCH) { - wiphy_err(wiphy, + brcms_err(wlc->hw->d11core, "%s: Pkt tx suppressed, illegal channel possibly %d\n", __func__, CHSPEC_CHANNEL( wlc->default_bss->chanspec)); } else { if (supr_status != TX_STATUS_SUPR_FRAG) - wiphy_err(wiphy, "%s: supr_status 0x%x\n", + brcms_err(wlc->hw->d11core, + "%s: supr_status 0x%x\n", __func__, supr_status); } /* no need to retry for badch; will fail again */ @@ -977,20 +923,14 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb, * if there were underflows, but pre-loading * is not active, notify rate adaptation. */ - if (brcms_c_ffpld_check_txfunfl(wlc, - prio2fifo[tid]) > 0) + if (brcms_c_ffpld_check_txfunfl(wlc, queue) > 0) tx_error = true; } } else if (txs->phyerr) { update_rate = false; - wiphy_err(wiphy, "%s: ampdu tx phy error (0x%x)\n", + brcms_err(wlc->hw->d11core, + "%s: ampdu tx phy error (0x%x)\n", __func__, txs->phyerr); - - if (brcm_msg_level & LOG_ERROR_VAL) { - brcmu_prpkt("txpkt (AMPDU)", p); - brcms_c_print_txdesc((struct d11txh *) p->data); - } - brcms_c_print_txstatus(txs); } } @@ -1003,6 +943,8 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb, h = (struct ieee80211_hdr *)(plcp + D11_PHY_HDR_LEN); seq = le16_to_cpu(h->seq_ctrl) >> SEQNUM_SHIFT; + trace_brcms_txdesc(&wlc->hw->d11core->dev, txh, sizeof(*txh)); + if (tot_mpdu == 0) { mcs = plcp[0] & MIMO_PLCP_MCS_MASK; mimoantsel = le16_to_cpu(txh->ABI_MimoAntSel); @@ -1012,10 +954,10 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb, ack_recd = false; if (ba_recd) { bindex = MODSUB_POW2(seq, start_seq, SEQNUM_MAX); - BCMMSG(wiphy, - "tid %d seq %d, start_seq %d, bindex %d set %d, index %d\n", - tid, seq, start_seq, bindex, - isset(bitmap, bindex), index); + brcms_dbg_ht(wlc->hw->d11core, + "tid %d seq %d, start_seq %d, bindex %d set %d, index %d\n", + tid, seq, start_seq, bindex, + isset(bitmap, bindex), index); /* if acked then clear bit and free packet */ if ((bindex < AMPDU_TX_BA_MAX_WSIZE) && isset(bitmap, bindex)) { @@ -1046,14 +988,16 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb, /* either retransmit or send bar if ack not recd */ if (!ack_recd) { if (retry && (ini->txretry[index] < (int)retry_limit)) { + int ret; ini->txretry[index]++; ini->tx_in_transit--; + ret = brcms_c_txfifo(wlc, queue, p); /* - * Use high prededence for retransmit to - * give some punch + * We shouldn't be out of space in the DMA + * ring here since we're reinserting a frame + * that was just pulled out. */ - brcms_c_txq_enq(wlc, scb, p, - BRCMS_PRIO_TO_HI_PREC(tid)); + WARN_ONCE(ret, "queue %d out of txds\n", queue); } else { /* Retry timeout */ ini->tx_in_transit--; @@ -1064,9 +1008,9 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb, IEEE80211_TX_STAT_AMPDU_NO_BACK; skb_pull(p, D11_PHY_HDR_LEN); skb_pull(p, D11_TXH_LEN); - BCMMSG(wiphy, - "BA Timeout, seq %d, in_transit %d\n", - seq, ini->tx_in_transit); + brcms_dbg_ht(wlc->hw->d11core, + "BA Timeout, seq %d, in_transit %d\n", + seq, ini->tx_in_transit); ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw, p); } @@ -1080,12 +1024,9 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb, p = dma_getnexttxp(wlc->hw->di[queue], DMA_RANGE_TRANSMITTED); } - brcms_c_send_q(wlc); /* update rate state */ antselid = brcms_c_antsel_antsel2id(wlc->asi, mimoantsel); - - brcms_c_txfifo_complete(wlc, queue, ampdu->txpkt_weight); } void @@ -1133,6 +1074,8 @@ brcms_c_ampdu_dotxstatus(struct ampdu_info *ampdu, struct scb *scb, while (p) { tx_info = IEEE80211_SKB_CB(p); txh = (struct d11txh *) p->data; + trace_brcms_txdesc(&wlc->hw->d11core->dev, txh, + sizeof(*txh)); mcl = le16_to_cpu(txh->MacTxControlLow); brcmu_pkt_buf_free_skb(p); /* break out if last packet of ampdu */ @@ -1142,7 +1085,6 @@ brcms_c_ampdu_dotxstatus(struct ampdu_info *ampdu, struct scb *scb, p = dma_getnexttxp(wlc->hw->di[queue], DMA_RANGE_TRANSMITTED); } - brcms_c_txfifo_complete(wlc, queue, ampdu->txpkt_weight); } } @@ -1182,23 +1124,6 @@ void brcms_c_ampdu_shm_upd(struct ampdu_info *ampdu) } /* - * callback function that helps flushing ampdu packets from a priority queue - */ -static bool cb_del_ampdu_pkt(struct sk_buff *mpdu, void *arg_a) -{ - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(mpdu); - struct cb_del_ampdu_pars *ampdu_pars = - (struct cb_del_ampdu_pars *)arg_a; - bool rc; - - rc = tx_info->flags & IEEE80211_TX_CTL_AMPDU ? true : false; - rc = rc && (tx_info->rate_driver_data[0] == NULL || ampdu_pars->sta == NULL || - tx_info->rate_driver_data[0] == ampdu_pars->sta); - rc = rc && ((u8)(mpdu->priority) == ampdu_pars->tid); - return rc; -} - -/* * callback function that helps invalidating ampdu packets in a DMA queue */ static void dma_cb_fn_ampdu(void *txi, void *arg_a) @@ -1218,15 +1143,5 @@ static void dma_cb_fn_ampdu(void *txi, void *arg_a) void brcms_c_ampdu_flush(struct brcms_c_info *wlc, struct ieee80211_sta *sta, u16 tid) { - struct brcms_txq_info *qi = wlc->pkt_queue; - struct pktq *pq = &qi->q; - int prec; - struct cb_del_ampdu_pars ampdu_pars; - - ampdu_pars.sta = sta; - ampdu_pars.tid = tid; - for (prec = 0; prec < pq->num_prec; prec++) - brcmu_pktq_pflush(pq, prec, true, cb_del_ampdu_pkt, - (void *)&du_pars); brcms_c_inval_dma_pkts(wlc->hw, sta, dma_cb_fn_ampdu); } diff --git a/drivers/net/wireless/brcm80211/brcmsmac/ampdu.h b/drivers/net/wireless/brcm80211/brcmsmac/ampdu.h index 421f4ba..73d01e5 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/ampdu.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/ampdu.h @@ -17,11 +17,34 @@ #ifndef _BRCM_AMPDU_H_ #define _BRCM_AMPDU_H_ +/* + * Data structure representing an in-progress session for accumulating + * frames for AMPDU. + * + * wlc: pointer to common driver data + * skb_list: queue of skb's for AMPDU + * max_ampdu_len: maximum length for this AMPDU + * max_ampdu_frames: maximum number of frames for this AMPDU + * ampdu_len: total number of bytes accumulated for this AMPDU + * dma_len: DMA length of this AMPDU + */ +struct brcms_ampdu_session { + struct brcms_c_info *wlc; + struct sk_buff_head skb_list; + unsigned max_ampdu_len; + u16 max_ampdu_frames; + u16 ampdu_len; + u16 dma_len; +}; + +extern void brcms_c_ampdu_reset_session(struct brcms_ampdu_session *session, + struct brcms_c_info *wlc); +extern int brcms_c_ampdu_add_frame(struct brcms_ampdu_session *session, + struct sk_buff *p); +extern void brcms_c_ampdu_finalize(struct brcms_ampdu_session *session); + extern struct ampdu_info *brcms_c_ampdu_attach(struct brcms_c_info *wlc); extern void brcms_c_ampdu_detach(struct ampdu_info *ampdu); -extern int brcms_c_sendampdu(struct ampdu_info *ampdu, - struct brcms_txq_info *qi, - struct sk_buff **aggp, int prec); extern void brcms_c_ampdu_dotxstatus(struct ampdu_info *ampdu, struct scb *scb, struct sk_buff *p, struct tx_status *txs); extern void brcms_c_ampdu_macaddr_upd(struct brcms_c_info *wlc); diff --git a/drivers/net/wireless/brcm80211/brcmsmac/antsel.c b/drivers/net/wireless/brcm80211/brcmsmac/antsel.c index 55e12c3..54c6169 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/antsel.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/antsel.c @@ -21,6 +21,7 @@ #include "main.h" #include "phy_shim.h" #include "antsel.h" +#include "debug.h" #define ANT_SELCFG_AUTO 0x80 /* bit indicates antenna sel AUTO */ #define ANT_SELCFG_MASK 0x33 /* antenna configuration mask */ @@ -137,7 +138,8 @@ struct antsel_info *brcms_c_antsel_attach(struct brcms_c_info *wlc) asi->antsel_avail = false; } else { asi->antsel_avail = false; - wiphy_err(wlc->wiphy, "antsel_attach: 2o3 " + brcms_err(wlc->hw->d11core, + "antsel_attach: 2o3 " "board cfg invalid\n"); } diff --git a/drivers/net/wireless/brcm80211/brcmsmac/brcms_trace_events.h b/drivers/net/wireless/brcm80211/brcmsmac/brcms_trace_events.h index 27dd73e..871781e 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/brcms_trace_events.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/brcms_trace_events.h @@ -14,22 +14,29 @@ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#undef TRACE_SYSTEM -#define TRACE_SYSTEM brcmsmac - #if !defined(__TRACE_BRCMSMAC_H) || defined(TRACE_HEADER_MULTI_READ) #define __TRACE_BRCMSMAC_H +#include <linux/types.h> +#include <linux/device.h> #include <linux/tracepoint.h> #include "mac80211_if.h" -#ifndef CONFIG_BRCMDBG +#ifndef CONFIG_BRCM_TRACING #undef TRACE_EVENT #define TRACE_EVENT(name, proto, ...) \ static inline void trace_ ## name(proto) {} +#undef DECLARE_EVENT_CLASS +#define DECLARE_EVENT_CLASS(...) +#undef DEFINE_EVENT +#define DEFINE_EVENT(evt_class, name, proto, ...) \ +static inline void trace_ ## name(proto) {} #endif +#undef TRACE_SYSTEM +#define TRACE_SYSTEM brcmsmac + /* * We define a tracepoint, its arguments, its printk format and its * 'fast binary record' layout. @@ -78,9 +85,165 @@ TRACE_EVENT(brcms_dpc, ) ); +TRACE_EVENT(brcms_macintstatus, + TP_PROTO(const struct device *dev, int in_isr, u32 macintstatus, + u32 mask), + TP_ARGS(dev, in_isr, macintstatus, mask), + TP_STRUCT__entry( + __string(dev, dev_name(dev)) + __field(int, in_isr) + __field(u32, macintstatus) + __field(u32, mask) + ), + TP_fast_assign( + __assign_str(dev, dev_name(dev)); + __entry->in_isr = in_isr; + __entry->macintstatus = macintstatus; + __entry->mask = mask; + ), + TP_printk("[%s] in_isr=%d macintstatus=%#x mask=%#x", __get_str(dev), + __entry->in_isr, __entry->macintstatus, __entry->mask) +); + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM brcmsmac_tx + +TRACE_EVENT(brcms_txdesc, + TP_PROTO(const struct device *dev, + void *txh, size_t txh_len), + TP_ARGS(dev, txh, txh_len), + TP_STRUCT__entry( + __string(dev, dev_name(dev)) + __dynamic_array(u8, txh, txh_len) + ), + TP_fast_assign( + __assign_str(dev, dev_name(dev)); + memcpy(__get_dynamic_array(txh), txh, txh_len); + ), + TP_printk("[%s] txdesc", __get_str(dev)) +); + +TRACE_EVENT(brcms_txstatus, + TP_PROTO(const struct device *dev, u16 framelen, u16 frameid, + u16 status, u16 lasttxtime, u16 sequence, u16 phyerr, + u16 ackphyrxsh), + TP_ARGS(dev, framelen, frameid, status, lasttxtime, sequence, phyerr, + ackphyrxsh), + TP_STRUCT__entry( + __string(dev, dev_name(dev)) + __field(u16, framelen) + __field(u16, frameid) + __field(u16, status) + __field(u16, lasttxtime) + __field(u16, sequence) + __field(u16, phyerr) + __field(u16, ackphyrxsh) + ), + TP_fast_assign( + __assign_str(dev, dev_name(dev)); + __entry->framelen = framelen; + __entry->frameid = frameid; + __entry->status = status; + __entry->lasttxtime = lasttxtime; + __entry->sequence = sequence; + __entry->phyerr = phyerr; + __entry->ackphyrxsh = ackphyrxsh; + ), + TP_printk("[%s] FrameId %#04x TxStatus %#04x LastTxTime %#04x " + "Seq %#04x PHYTxStatus %#04x RxAck %#04x", + __get_str(dev), __entry->frameid, __entry->status, + __entry->lasttxtime, __entry->sequence, __entry->phyerr, + __entry->ackphyrxsh) +); + +TRACE_EVENT(brcms_ampdu_session, + TP_PROTO(const struct device *dev, unsigned max_ampdu_len, + u16 max_ampdu_frames, u16 ampdu_len, u16 ampdu_frames, + u16 dma_len), + TP_ARGS(dev, max_ampdu_len, max_ampdu_frames, ampdu_len, ampdu_frames, + dma_len), + TP_STRUCT__entry( + __string(dev, dev_name(dev)) + __field(unsigned, max_ampdu_len) + __field(u16, max_ampdu_frames) + __field(u16, ampdu_len) + __field(u16, ampdu_frames) + __field(u16, dma_len) + ), + TP_fast_assign( + __assign_str(dev, dev_name(dev)); + __entry->max_ampdu_len = max_ampdu_len; + __entry->max_ampdu_frames = max_ampdu_frames; + __entry->ampdu_len = ampdu_len; + __entry->ampdu_frames = ampdu_frames; + __entry->dma_len = dma_len; + ), + TP_printk("[%s] ampdu session max_len=%u max_frames=%u len=%u frames=%u dma_len=%u", + __get_str(dev), __entry->max_ampdu_len, + __entry->max_ampdu_frames, __entry->ampdu_len, + __entry->ampdu_frames, __entry->dma_len) +); + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM brcmsmac_msg + +#define MAX_MSG_LEN 100 + +DECLARE_EVENT_CLASS(brcms_msg_event, + TP_PROTO(struct va_format *vaf), + TP_ARGS(vaf), + TP_STRUCT__entry( + __dynamic_array(char, msg, MAX_MSG_LEN) + ), + TP_fast_assign( + WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg), + MAX_MSG_LEN, vaf->fmt, + *vaf->va) >= MAX_MSG_LEN); + ), + TP_printk("%s", __get_str(msg)) +); + +DEFINE_EVENT(brcms_msg_event, brcms_info, + TP_PROTO(struct va_format *vaf), + TP_ARGS(vaf) +); + +DEFINE_EVENT(brcms_msg_event, brcms_warn, + TP_PROTO(struct va_format *vaf), + TP_ARGS(vaf) +); + +DEFINE_EVENT(brcms_msg_event, brcms_err, + TP_PROTO(struct va_format *vaf), + TP_ARGS(vaf) +); + +DEFINE_EVENT(brcms_msg_event, brcms_crit, + TP_PROTO(struct va_format *vaf), + TP_ARGS(vaf) +); + +TRACE_EVENT(brcms_dbg, + TP_PROTO(u32 level, const char *func, struct va_format *vaf), + TP_ARGS(level, func, vaf), + TP_STRUCT__entry( + __field(u32, level) + __string(func, func) + __dynamic_array(char, msg, MAX_MSG_LEN) + ), + TP_fast_assign( + __entry->level = level; + __assign_str(func, func); + WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg), + MAX_MSG_LEN, vaf->fmt, + *vaf->va) >= MAX_MSG_LEN); + ), + TP_printk("%s: %s", __get_str(func), __get_str(msg)) +); + #endif /* __TRACE_BRCMSMAC_H */ -#ifdef CONFIG_BRCMDBG +#ifdef CONFIG_BRCM_TRACING #undef TRACE_INCLUDE_PATH #define TRACE_INCLUDE_PATH . @@ -89,4 +252,4 @@ TRACE_EVENT(brcms_dpc, #include <trace/define_trace.h> -#endif /* CONFIG_BRCMDBG */ +#endif /* CONFIG_BRCM_TRACING */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/channel.c b/drivers/net/wireless/brcm80211/brcmsmac/channel.c index 64a48f0..a90b722 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/channel.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/channel.c @@ -26,6 +26,7 @@ #include "stf.h" #include "channel.h" #include "mac80211_if.h" +#include "debug.h" /* QDB() macro takes a dB value and converts to a quarter dB value */ #define QDB(n) ((n) * BRCMS_TXPWR_DB_FACTOR) @@ -336,8 +337,6 @@ struct brcms_cm_info *brcms_c_channel_mgr_attach(struct brcms_c_info *wlc) const char *ccode = sprom->alpha2; int ccode_len = sizeof(sprom->alpha2); - BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit); - wlc_cm = kzalloc(sizeof(struct brcms_cm_info), GFP_ATOMIC); if (wlc_cm == NULL) return NULL; @@ -615,8 +614,8 @@ brcms_c_valid_chanspec_ext(struct brcms_cm_info *wlc_cm, u16 chspec) /* check the chanspec */ if (brcms_c_chspec_malformed(chspec)) { - wiphy_err(wlc->wiphy, "wl%d: malformed chanspec 0x%x\n", - wlc->pub->unit, chspec); + brcms_err(wlc->hw->d11core, "wl%d: malformed chanspec 0x%x\n", + wlc->pub->unit, chspec); return false; } @@ -738,7 +737,8 @@ static int brcms_reg_notifier(struct wiphy *wiphy, mboolclr(wlc->pub->radio_disabled, WL_RADIO_COUNTRY_DISABLE); } else { mboolset(wlc->pub->radio_disabled, WL_RADIO_COUNTRY_DISABLE); - wiphy_err(wlc->wiphy, "wl%d: %s: no valid channel for \"%s\"\n", + brcms_err(wlc->hw->d11core, + "wl%d: %s: no valid channel for \"%s\"\n", wlc->pub->unit, __func__, request->alpha2); } diff --git a/drivers/net/wireless/brcm80211/brcmsmac/debug.c b/drivers/net/wireless/brcm80211/brcmsmac/debug.c new file mode 100644 index 0000000..be84791 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmsmac/debug.c @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2012 Broadcom Corporation + * Copyright (c) 2012 Canonical Ltd. + * + * 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. + */ +#include <linux/debugfs.h> +#include <linux/if_ether.h> +#include <linux/if.h> +#include <linux/net.h> +#include <linux/netdevice.h> +#include <linux/ieee80211.h> +#include <linux/module.h> +#include <linux/netdevice.h> +#include <net/mac80211.h> + +#include <defs.h> +#include <brcmu_wifi.h> +#include <brcmu_utils.h> +#include "types.h" +#include "main.h" +#include "debug.h" +#include "brcms_trace_events.h" + +static struct dentry *root_folder; + +void brcms_debugfs_init(void) +{ + root_folder = debugfs_create_dir(KBUILD_MODNAME, NULL); + if (IS_ERR(root_folder)) + root_folder = NULL; +} + +void brcms_debugfs_exit(void) +{ + if (!root_folder) + return; + + debugfs_remove_recursive(root_folder); + root_folder = NULL; +} + +int brcms_debugfs_attach(struct brcms_pub *drvr) +{ + if (!root_folder) + return -ENODEV; + + drvr->dbgfs_dir = debugfs_create_dir( + dev_name(&drvr->wlc->hw->d11core->dev), root_folder); + return PTR_RET(drvr->dbgfs_dir); +} + +void brcms_debugfs_detach(struct brcms_pub *drvr) +{ + if (!IS_ERR_OR_NULL(drvr->dbgfs_dir)) + debugfs_remove_recursive(drvr->dbgfs_dir); +} + +struct dentry *brcms_debugfs_get_devdir(struct brcms_pub *drvr) +{ + return drvr->dbgfs_dir; +} + +static +ssize_t brcms_debugfs_hardware_read(struct file *f, char __user *data, + size_t count, loff_t *ppos) +{ + char buf[128]; + int res; + struct brcms_pub *drvr = f->private_data; + + /* only allow read from start */ + if (*ppos > 0) + return 0; + + res = scnprintf(buf, sizeof(buf), + "board vendor: %x\n" + "board type: %x\n" + "board revision: %x\n" + "board flags: %x\n" + "board flags2: %x\n" + "firmware revision: %x\n", + drvr->wlc->hw->d11core->bus->boardinfo.vendor, + drvr->wlc->hw->d11core->bus->boardinfo.type, + drvr->wlc->hw->boardrev, + drvr->wlc->hw->boardflags, + drvr->wlc->hw->boardflags2, + drvr->wlc->ucode_rev + ); + + return simple_read_from_buffer(data, count, ppos, buf, res); +} + +static const struct file_operations brcms_debugfs_hardware_ops = { + .owner = THIS_MODULE, + .open = simple_open, + .read = brcms_debugfs_hardware_read +}; + +void brcms_debugfs_create_files(struct brcms_pub *drvr) +{ + struct dentry *dentry = drvr->dbgfs_dir; + + if (!IS_ERR_OR_NULL(dentry)) + debugfs_create_file("hardware", S_IRUGO, dentry, + drvr, &brcms_debugfs_hardware_ops); +} + +#define __brcms_fn(fn) \ +void __brcms_ ##fn(struct device *dev, const char *fmt, ...) \ +{ \ + struct va_format vaf = { \ + .fmt = fmt, \ + }; \ + va_list args; \ + \ + va_start(args, fmt); \ + vaf.va = &args; \ + dev_ ##fn(dev, "%pV", &vaf); \ + trace_brcms_ ##fn(&vaf); \ + va_end(args); \ +} + +__brcms_fn(info) +__brcms_fn(warn) +__brcms_fn(err) +__brcms_fn(crit) + +#if defined(CONFIG_BRCMDBG) || defined(CONFIG_BRCM_TRACING) +void __brcms_dbg(struct device *dev, u32 level, const char *func, + const char *fmt, ...) +{ + struct va_format vaf = { + .fmt = fmt, + }; + va_list args; + + va_start(args, fmt); + vaf.va = &args; +#ifdef CONFIG_BRCMDBG + if ((brcm_msg_level & level) && net_ratelimit()) + dev_err(dev, "%s %pV", func, &vaf); +#endif + trace_brcms_dbg(level, func, &vaf); + va_end(args); +} +#endif diff --git a/drivers/net/wireless/brcm80211/brcmsmac/debug.h b/drivers/net/wireless/brcm80211/brcmsmac/debug.h new file mode 100644 index 0000000..796836b --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmsmac/debug.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2012 Broadcom Corporation + * + * 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 _BRCMS_DEBUG_H_ +#define _BRCMS_DEBUG_H_ + +#include <linux/device.h> +#include <linux/bcma/bcma.h> +#include <net/cfg80211.h> +#include <net/mac80211.h> +#include "main.h" +#include "mac80211_if.h" + +__printf(2, 3) +void __brcms_info(struct device *dev, const char *fmt, ...); +__printf(2, 3) +void __brcms_warn(struct device *dev, const char *fmt, ...); +__printf(2, 3) +void __brcms_err(struct device *dev, const char *fmt, ...); +__printf(2, 3) +void __brcms_crit(struct device *dev, const char *fmt, ...); + +#if defined(CONFIG_BRCMDBG) || defined(CONFIG_BRCM_TRACING) +__printf(4, 5) +void __brcms_dbg(struct device *dev, u32 level, const char *func, + const char *fmt, ...); +#else +static inline __printf(4, 5) +void __brcms_dbg(struct device *dev, u32 level, const char *func, + const char *fmt, ...) +{ +} +#endif + +/* + * Debug macros cannot be used when wlc is uninitialized. Generally + * this means any code that could run before brcms_c_attach() has + * returned successfully probably shouldn't use the following macros. + */ + +#define brcms_dbg(core, l, f, a...) __brcms_dbg(&(core)->dev, l, __func__, f, ##a) +#define brcms_info(core, f, a...) __brcms_info(&(core)->dev, f, ##a) +#define brcms_warn(core, f, a...) __brcms_warn(&(core)->dev, f, ##a) +#define brcms_err(core, f, a...) __brcms_err(&(core)->dev, f, ##a) +#define brcms_crit(core, f, a...) __brcms_crit(&(core)->dev, f, ##a) + +#define brcms_dbg_info(core, f, a...) brcms_dbg(core, BRCM_DL_INFO, f, ##a) +#define brcms_dbg_mac80211(core, f, a...) brcms_dbg(core, BRCM_DL_MAC80211, f, ##a) +#define brcms_dbg_rx(core, f, a...) brcms_dbg(core, BRCM_DL_RX, f, ##a) +#define brcms_dbg_tx(core, f, a...) brcms_dbg(core, BRCM_DL_TX, f, ##a) +#define brcms_dbg_int(core, f, a...) brcms_dbg(core, BRCM_DL_INT, f, ##a) +#define brcms_dbg_dma(core, f, a...) brcms_dbg(core, BRCM_DL_DMA, f, ##a) +#define brcms_dbg_ht(core, f, a...) brcms_dbg(core, BRCM_DL_HT, f, ##a) + +struct brcms_pub; +void brcms_debugfs_init(void); +void brcms_debugfs_exit(void); +int brcms_debugfs_attach(struct brcms_pub *drvr); +void brcms_debugfs_detach(struct brcms_pub *drvr); +struct dentry *brcms_debugfs_get_devdir(struct brcms_pub *drvr); +void brcms_debugfs_create_files(struct brcms_pub *drvr); + +#endif /* _BRCMS_DEBUG_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/dma.c b/drivers/net/wireless/brcm80211/brcmsmac/dma.c index 5e53305..1860c57 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/dma.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/dma.c @@ -14,17 +14,22 @@ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - #include <linux/slab.h> #include <linux/delay.h> #include <linux/pci.h> +#include <net/cfg80211.h> +#include <net/mac80211.h> #include <brcmu_utils.h> #include <aiutils.h> #include "types.h" +#include "main.h" #include "dma.h" #include "soc.h" +#include "scb.h" +#include "ampdu.h" +#include "debug.h" +#include "brcms_trace_events.h" /* * dma register field offset calculation @@ -176,28 +181,6 @@ #define BCMEXTRAHDROOM 172 -/* debug/trace */ -#ifdef DEBUG -#define DMA_ERROR(fmt, ...) \ -do { \ - if (*di->msg_level & 1) \ - pr_debug("%s: " fmt, __func__, ##__VA_ARGS__); \ -} while (0) -#define DMA_TRACE(fmt, ...) \ -do { \ - if (*di->msg_level & 2) \ - pr_debug("%s: " fmt, __func__, ##__VA_ARGS__); \ -} while (0) -#else -#define DMA_ERROR(fmt, ...) \ - no_printk(fmt, ##__VA_ARGS__) -#define DMA_TRACE(fmt, ...) \ - no_printk(fmt, ##__VA_ARGS__) -#endif /* DEBUG */ - -#define DMA_NONE(fmt, ...) \ - no_printk(fmt, ##__VA_ARGS__) - #define MAXNAMEL 8 /* 8 char names */ /* macros to convert between byte offsets and indexes */ @@ -224,12 +207,14 @@ struct dma64desc { /* dma engine software state */ struct dma_info { struct dma_pub dma; /* exported structure */ - uint *msg_level; /* message level pointer */ char name[MAXNAMEL]; /* callers name for diag msgs */ struct bcma_device *core; struct device *dmadev; + /* session information for AMPDU */ + struct brcms_ampdu_session ampdu_session; + bool dma64; /* this dma engine is operating in 64-bit mode */ bool addrext; /* this dma engine supports DmaExtendedAddrChanges */ @@ -298,12 +283,6 @@ struct dma_info { bool aligndesc_4k; }; -/* - * default dma message level (if input msg_level - * pointer is null in dma_attach()) - */ -static uint dma_msg_level; - /* Check for odd number of 1's */ static u32 parity32(__le32 data) { @@ -353,7 +332,7 @@ static uint prevtxd(struct dma_info *di, uint i) static uint nextrxd(struct dma_info *di, uint i) { - return txd(di, i + 1); + return rxd(di, i + 1); } static uint ntxdactive(struct dma_info *di, uint h, uint t) @@ -370,10 +349,8 @@ static uint _dma_ctrlflags(struct dma_info *di, uint mask, uint flags) { uint dmactrlflags; - if (di == NULL) { - DMA_ERROR("NULL dma handle\n"); + if (di == NULL) return 0; - } dmactrlflags = di->dma.dmactrlflags; dmactrlflags &= ~mask; @@ -423,13 +400,15 @@ static bool _dma_isaddrext(struct dma_info *di) /* not all tx or rx channel are available */ if (di->d64txregbase != 0) { if (!_dma64_addrext(di, DMA64TXREGOFFS(di, control))) - DMA_ERROR("%s: DMA64 tx doesn't have AE set\n", - di->name); + brcms_dbg_dma(di->core, + "%s: DMA64 tx doesn't have AE set\n", + di->name); return true; } else if (di->d64rxregbase != 0) { if (!_dma64_addrext(di, DMA64RXREGOFFS(di, control))) - DMA_ERROR("%s: DMA64 rx doesn't have AE set\n", - di->name); + brcms_dbg_dma(di->core, + "%s: DMA64 rx doesn't have AE set\n", + di->name); return true; } @@ -530,8 +509,9 @@ static bool dma64_alloc(struct dma_info *di, uint direction) va = dma_ringalloc(di, D64RINGALIGN, size, &align_bits, &alloced, &di->txdpaorig); if (va == NULL) { - DMA_ERROR("%s: DMA_ALLOC_CONSISTENT(ntxd) failed\n", - di->name); + brcms_dbg_dma(di->core, + "%s: DMA_ALLOC_CONSISTENT(ntxd) failed\n", + di->name); return false; } align = (1 << align_bits); @@ -544,8 +524,9 @@ static bool dma64_alloc(struct dma_info *di, uint direction) va = dma_ringalloc(di, D64RINGALIGN, size, &align_bits, &alloced, &di->rxdpaorig); if (va == NULL) { - DMA_ERROR("%s: DMA_ALLOC_CONSISTENT(nrxd) failed\n", - di->name); + brcms_dbg_dma(di->core, + "%s: DMA_ALLOC_CONSISTENT(nrxd) failed\n", + di->name); return false; } align = (1 << align_bits); @@ -564,12 +545,13 @@ static bool _dma_alloc(struct dma_info *di, uint direction) return dma64_alloc(di, direction); } -struct dma_pub *dma_attach(char *name, struct si_pub *sih, - struct bcma_device *core, +struct dma_pub *dma_attach(char *name, struct brcms_c_info *wlc, uint txregbase, uint rxregbase, uint ntxd, uint nrxd, uint rxbufsize, int rxextheadroom, - uint nrxpost, uint rxoffset, uint *msg_level) + uint nrxpost, uint rxoffset) { + struct si_pub *sih = wlc->hw->sih; + struct bcma_device *core = wlc->hw->d11core; struct dma_info *di; u8 rev = core->id.rev; uint size; @@ -580,9 +562,6 @@ struct dma_pub *dma_attach(char *name, struct si_pub *sih, if (di == NULL) return NULL; - di->msg_level = msg_level ? msg_level : &dma_msg_level; - - di->dma64 = ((bcma_aread32(core, BCMA_IOST) & SISF_DMA64) == SISF_DMA64); @@ -598,11 +577,11 @@ struct dma_pub *dma_attach(char *name, struct si_pub *sih, */ _dma_ctrlflags(di, DMA_CTRL_ROC | DMA_CTRL_PEN, 0); - DMA_TRACE("%s: %s flags 0x%x ntxd %d nrxd %d " - "rxbufsize %d rxextheadroom %d nrxpost %d rxoffset %d " - "txregbase %u rxregbase %u\n", name, "DMA64", - di->dma.dmactrlflags, ntxd, nrxd, rxbufsize, - rxextheadroom, nrxpost, rxoffset, txregbase, rxregbase); + brcms_dbg_dma(di->core, "%s: %s flags 0x%x ntxd %d nrxd %d " + "rxbufsize %d rxextheadroom %d nrxpost %d rxoffset %d " + "txregbase %u rxregbase %u\n", name, "DMA64", + di->dma.dmactrlflags, ntxd, nrxd, rxbufsize, + rxextheadroom, nrxpost, rxoffset, txregbase, rxregbase); /* make a private copy of our callers name */ strncpy(di->name, name, MAXNAMEL); @@ -664,8 +643,8 @@ struct dma_pub *dma_attach(char *name, struct si_pub *sih, di->dmadesc_align = 4; /* 16 byte alignment */ } - DMA_NONE("DMA descriptor align_needed %d, align %d\n", - di->aligndesc_4k, di->dmadesc_align); + brcms_dbg_dma(di->core, "DMA descriptor align_needed %d, align %d\n", + di->aligndesc_4k, di->dmadesc_align); /* allocate tx packet pointer vector */ if (ntxd) { @@ -703,21 +682,27 @@ struct dma_pub *dma_attach(char *name, struct si_pub *sih, if ((di->ddoffsetlow != 0) && !di->addrext) { if (di->txdpa > SI_PCI_DMA_SZ) { - DMA_ERROR("%s: txdpa 0x%x: addrext not supported\n", - di->name, (u32)di->txdpa); + brcms_dbg_dma(di->core, + "%s: txdpa 0x%x: addrext not supported\n", + di->name, (u32)di->txdpa); goto fail; } if (di->rxdpa > SI_PCI_DMA_SZ) { - DMA_ERROR("%s: rxdpa 0x%x: addrext not supported\n", - di->name, (u32)di->rxdpa); + brcms_dbg_dma(di->core, + "%s: rxdpa 0x%x: addrext not supported\n", + di->name, (u32)di->rxdpa); goto fail; } } - DMA_TRACE("ddoffsetlow 0x%x ddoffsethigh 0x%x dataoffsetlow 0x%x dataoffsethigh 0x%x addrext %d\n", - di->ddoffsetlow, di->ddoffsethigh, - di->dataoffsetlow, di->dataoffsethigh, - di->addrext); + /* Initialize AMPDU session */ + brcms_c_ampdu_reset_session(&di->ampdu_session, wlc); + + brcms_dbg_dma(di->core, + "ddoffsetlow 0x%x ddoffsethigh 0x%x dataoffsetlow 0x%x dataoffsethigh 0x%x addrext %d\n", + di->ddoffsetlow, di->ddoffsethigh, + di->dataoffsetlow, di->dataoffsethigh, + di->addrext); return (struct dma_pub *) di; @@ -763,7 +748,7 @@ void dma_detach(struct dma_pub *pub) { struct dma_info *di = (struct dma_info *)pub; - DMA_TRACE("%s:\n", di->name); + brcms_dbg_dma(di->core, "%s:\n", di->name); /* free dma descriptor rings */ if (di->txd64) @@ -839,7 +824,7 @@ static void _dma_rxenable(struct dma_info *di) uint dmactrlflags = di->dma.dmactrlflags; u32 control; - DMA_TRACE("%s:\n", di->name); + brcms_dbg_dma(di->core, "%s:\n", di->name); control = D64_RC_RE | (bcma_read32(di->core, DMA64RXREGOFFS(di, control)) & @@ -859,7 +844,7 @@ void dma_rxinit(struct dma_pub *pub) { struct dma_info *di = (struct dma_info *)pub; - DMA_TRACE("%s:\n", di->name); + brcms_dbg_dma(di->core, "%s:\n", di->name); if (di->nrxd == 0) return; @@ -954,7 +939,7 @@ int dma_rx(struct dma_pub *pub, struct sk_buff_head *skb_list) return 0; len = le16_to_cpu(*(__le16 *) (p->data)); - DMA_TRACE("%s: dma_rx len %d\n", di->name, len); + brcms_dbg_dma(di->core, "%s: dma_rx len %d\n", di->name, len); dma_spin_for_len(len, p); /* set actual length */ @@ -981,14 +966,15 @@ int dma_rx(struct dma_pub *pub, struct sk_buff_head *skb_list) DMA64RXREGOFFS(di, status0)) & D64_RS0_CD_MASK) - di->rcvptrbase) & D64_RS0_CD_MASK, struct dma64desc); - DMA_ERROR("rxin %d rxout %d, hw_curr %d\n", - di->rxin, di->rxout, cur); + brcms_dbg_dma(di->core, + "rxin %d rxout %d, hw_curr %d\n", + di->rxin, di->rxout, cur); } #endif /* DEBUG */ if ((di->dma.dmactrlflags & DMA_CTRL_RXMULTI) == 0) { - DMA_ERROR("%s: bad frame length (%d)\n", - di->name, len); + brcms_dbg_dma(di->core, "%s: bad frame length (%d)\n", + di->name, len); skb_queue_walk_safe(&dma_frames, p, next) { skb_unlink(p, &dma_frames); brcmu_pkt_buf_free_skb(p); @@ -1005,7 +991,7 @@ int dma_rx(struct dma_pub *pub, struct sk_buff_head *skb_list) static bool dma64_rxidle(struct dma_info *di) { - DMA_TRACE("%s:\n", di->name); + brcms_dbg_dma(di->core, "%s:\n", di->name); if (di->nrxd == 0) return true; @@ -1016,6 +1002,17 @@ static bool dma64_rxidle(struct dma_info *di) D64_RS0_CD_MASK)); } +static bool dma64_txidle(struct dma_info *di) +{ + if (di->ntxd == 0) + return true; + + return ((bcma_read32(di->core, + DMA64TXREGOFFS(di, status0)) & D64_XS0_CD_MASK) == + (bcma_read32(di->core, DMA64TXREGOFFS(di, ptr)) & + D64_XS0_CD_MASK)); +} + /* * post receive buffers * return false is refill failed completely and ring is empty this will stall @@ -1047,7 +1044,7 @@ bool dma_rxfill(struct dma_pub *pub) n = di->nrxpost - nrxdactive(di, rxin, rxout); - DMA_TRACE("%s: post %d\n", di->name, n); + brcms_dbg_dma(di->core, "%s: post %d\n", di->name, n); if (di->rxbufsize > BCMEXTRAHDROOM) extra_offset = di->rxextrahdrroom; @@ -1060,9 +1057,11 @@ bool dma_rxfill(struct dma_pub *pub) p = brcmu_pkt_buf_get_skb(di->rxbufsize + extra_offset); if (p == NULL) { - DMA_ERROR("%s: out of rxbufs\n", di->name); + brcms_dbg_dma(di->core, "%s: out of rxbufs\n", + di->name); if (i == 0 && dma64_rxidle(di)) { - DMA_ERROR("%s: ring is empty !\n", di->name); + brcms_dbg_dma(di->core, "%s: ring is empty !\n", + di->name); ring_empty = true; } di->dma.rxnobuf++; @@ -1107,7 +1106,7 @@ void dma_rxreclaim(struct dma_pub *pub) struct dma_info *di = (struct dma_info *)pub; struct sk_buff *p; - DMA_TRACE("%s:\n", di->name); + brcms_dbg_dma(di->core, "%s:\n", di->name); while ((p = _dma_getnextrxp(di, true))) brcmu_pkt_buf_free_skb(p); @@ -1138,7 +1137,7 @@ void dma_txinit(struct dma_pub *pub) struct dma_info *di = (struct dma_info *)pub; u32 control = D64_XC_XE; - DMA_TRACE("%s:\n", di->name); + brcms_dbg_dma(di->core, "%s:\n", di->name); if (di->ntxd == 0) return; @@ -1170,7 +1169,7 @@ void dma_txsuspend(struct dma_pub *pub) { struct dma_info *di = (struct dma_info *)pub; - DMA_TRACE("%s:\n", di->name); + brcms_dbg_dma(di->core, "%s:\n", di->name); if (di->ntxd == 0) return; @@ -1182,7 +1181,7 @@ void dma_txresume(struct dma_pub *pub) { struct dma_info *di = (struct dma_info *)pub; - DMA_TRACE("%s:\n", di->name); + brcms_dbg_dma(di->core, "%s:\n", di->name); if (di->ntxd == 0) return; @@ -1205,11 +1204,11 @@ void dma_txreclaim(struct dma_pub *pub, enum txd_range range) struct dma_info *di = (struct dma_info *)pub; struct sk_buff *p; - DMA_TRACE("%s: %s\n", - di->name, - range == DMA_RANGE_ALL ? "all" : - range == DMA_RANGE_TRANSMITTED ? "transmitted" : - "transferred"); + brcms_dbg_dma(di->core, "%s: %s\n", + di->name, + range == DMA_RANGE_ALL ? "all" : + range == DMA_RANGE_TRANSMITTED ? "transmitted" : + "transferred"); if (di->txin == di->txout) return; @@ -1264,39 +1263,25 @@ bool dma_rxreset(struct dma_pub *pub) return status == D64_RS0_RS_DISABLED; } -/* - * !! tx entry routine - * WARNING: call must check the return value for error. - * the error(toss frames) could be fatal and cause many subsequent hard - * to debug problems - */ -int dma_txfast(struct dma_pub *pub, struct sk_buff *p, bool commit) +static void dma_txenq(struct dma_info *di, struct sk_buff *p) { - struct dma_info *di = (struct dma_info *)pub; unsigned char *data; uint len; u16 txout; u32 flags = 0; dma_addr_t pa; - DMA_TRACE("%s:\n", di->name); - txout = di->txout; + if (WARN_ON(nexttxd(di, txout) == di->txin)) + return; + /* * obtain and initialize transmit descriptor entry. */ data = p->data; len = p->len; - /* no use to transmit a zero length packet */ - if (len == 0) - return 0; - - /* return nonzero if out of tx descriptors */ - if (nexttxd(di, txout) == di->txin) - goto outoftxd; - /* get physical address of buffer start */ pa = dma_map_single(di->dmadev, data, len, DMA_TO_DEVICE); @@ -1318,23 +1303,147 @@ int dma_txfast(struct dma_pub *pub, struct sk_buff *p, bool commit) /* bump the tx descriptor index */ di->txout = txout; +} - /* kick the chip */ - if (commit) - bcma_write32(di->core, DMA64TXREGOFFS(di, ptr), - di->xmtptrbase + I2B(txout, struct dma64desc)); +static void ampdu_finalize(struct dma_info *di) +{ + struct brcms_ampdu_session *session = &di->ampdu_session; + struct sk_buff *p; + + trace_brcms_ampdu_session(&session->wlc->hw->d11core->dev, + session->max_ampdu_len, + session->max_ampdu_frames, + session->ampdu_len, + skb_queue_len(&session->skb_list), + session->dma_len); + + if (WARN_ON(skb_queue_empty(&session->skb_list))) + return; + + brcms_c_ampdu_finalize(session); + + while (!skb_queue_empty(&session->skb_list)) { + p = skb_dequeue(&session->skb_list); + dma_txenq(di, p); + } + + bcma_write32(di->core, DMA64TXREGOFFS(di, ptr), + di->xmtptrbase + I2B(di->txout, struct dma64desc)); + brcms_c_ampdu_reset_session(session, session->wlc); +} + +static void prep_ampdu_frame(struct dma_info *di, struct sk_buff *p) +{ + struct brcms_ampdu_session *session = &di->ampdu_session; + int ret; + + ret = brcms_c_ampdu_add_frame(session, p); + if (ret == -ENOSPC) { + /* + * AMPDU cannot accomodate this frame. Close out the in- + * progress AMPDU session and start a new one. + */ + ampdu_finalize(di); + ret = brcms_c_ampdu_add_frame(session, p); + } + + WARN_ON(ret); +} + +/* Update count of available tx descriptors based on current DMA state */ +static void dma_update_txavail(struct dma_info *di) +{ + /* + * Available space is number of descriptors less the number of + * active descriptors and the number of queued AMPDU frames. + */ + di->dma.txavail = di->ntxd - ntxdactive(di, di->txin, di->txout) - + skb_queue_len(&di->ampdu_session.skb_list) - 1; +} + +/* + * !! tx entry routine + * WARNING: call must check the return value for error. + * the error(toss frames) could be fatal and cause many subsequent hard + * to debug problems + */ +int dma_txfast(struct brcms_c_info *wlc, struct dma_pub *pub, + struct sk_buff *p) +{ + struct dma_info *di = (struct dma_info *)pub; + struct brcms_ampdu_session *session = &di->ampdu_session; + struct ieee80211_tx_info *tx_info; + bool is_ampdu; + + /* no use to transmit a zero length packet */ + if (p->len == 0) + return 0; + + /* return nonzero if out of tx descriptors */ + if (di->dma.txavail == 0 || nexttxd(di, di->txout) == di->txin) + goto outoftxd; + + tx_info = IEEE80211_SKB_CB(p); + is_ampdu = tx_info->flags & IEEE80211_TX_CTL_AMPDU; + if (is_ampdu) + prep_ampdu_frame(di, p); + else + dma_txenq(di, p); /* tx flow control */ - di->dma.txavail = di->ntxd - ntxdactive(di, di->txin, di->txout) - 1; + dma_update_txavail(di); + + /* kick the chip */ + if (is_ampdu) { + /* + * Start sending data if we've got a full AMPDU, there's + * no more space in the DMA ring, or the ring isn't + * currently transmitting. + */ + if (skb_queue_len(&session->skb_list) == session->max_ampdu_frames || + di->dma.txavail == 0 || dma64_txidle(di)) + ampdu_finalize(di); + } else { + bcma_write32(di->core, DMA64TXREGOFFS(di, ptr), + di->xmtptrbase + I2B(di->txout, struct dma64desc)); + } return 0; outoftxd: - DMA_ERROR("%s: out of txds !!!\n", di->name); + brcms_dbg_dma(di->core, "%s: out of txds !!!\n", di->name); brcmu_pkt_buf_free_skb(p); di->dma.txavail = 0; di->dma.txnobuf++; - return -1; + return -ENOSPC; +} + +void dma_txflush(struct dma_pub *pub) +{ + struct dma_info *di = (struct dma_info *)pub; + struct brcms_ampdu_session *session = &di->ampdu_session; + + if (!skb_queue_empty(&session->skb_list)) + ampdu_finalize(di); +} + +int dma_txpending(struct dma_pub *pub) +{ + struct dma_info *di = (struct dma_info *)pub; + return ntxdactive(di, di->txin, di->txout); +} + +/* + * If we have an active AMPDU session and are not transmitting, + * this function will force tx to start. + */ +void dma_kick_tx(struct dma_pub *pub) +{ + struct dma_info *di = (struct dma_info *)pub; + struct brcms_ampdu_session *session = &di->ampdu_session; + + if (!skb_queue_empty(&session->skb_list) && dma64_txidle(di)) + ampdu_finalize(di); } /* @@ -1354,11 +1463,11 @@ struct sk_buff *dma_getnexttxp(struct dma_pub *pub, enum txd_range range) u16 active_desc; struct sk_buff *txp; - DMA_TRACE("%s: %s\n", - di->name, - range == DMA_RANGE_ALL ? "all" : - range == DMA_RANGE_TRANSMITTED ? "transmitted" : - "transferred"); + brcms_dbg_dma(di->core, "%s: %s\n", + di->name, + range == DMA_RANGE_ALL ? "all" : + range == DMA_RANGE_TRANSMITTED ? "transmitted" : + "transferred"); if (di->ntxd == 0) return NULL; @@ -1412,13 +1521,13 @@ struct sk_buff *dma_getnexttxp(struct dma_pub *pub, enum txd_range range) di->txin = i; /* tx flow control */ - di->dma.txavail = di->ntxd - ntxdactive(di, di->txin, di->txout) - 1; + dma_update_txavail(di); return txp; bogus: - DMA_NONE("bogus curr: start %d end %d txout %d\n", - start, end, di->txout); + brcms_dbg_dma(di->core, "bogus curr: start %d end %d txout %d\n", + start, end, di->txout); return NULL; } diff --git a/drivers/net/wireless/brcm80211/brcmsmac/dma.h b/drivers/net/wireless/brcm80211/brcmsmac/dma.h index cc269ee..ff5b80b 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/dma.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/dma.h @@ -74,12 +74,11 @@ struct dma_pub { uint txnobuf; /* tx out of dma descriptors */ }; -extern struct dma_pub *dma_attach(char *name, struct si_pub *sih, - struct bcma_device *d11core, +extern struct dma_pub *dma_attach(char *name, struct brcms_c_info *wlc, uint txregbase, uint rxregbase, uint ntxd, uint nrxd, uint rxbufsize, int rxextheadroom, - uint nrxpost, uint rxoffset, uint *msg_level); + uint nrxpost, uint rxoffset); void dma_rxinit(struct dma_pub *pub); int dma_rx(struct dma_pub *pub, struct sk_buff_head *skb_list); @@ -87,7 +86,11 @@ bool dma_rxfill(struct dma_pub *pub); bool dma_rxreset(struct dma_pub *pub); bool dma_txreset(struct dma_pub *pub); void dma_txinit(struct dma_pub *pub); -int dma_txfast(struct dma_pub *pub, struct sk_buff *p0, bool commit); +int dma_txfast(struct brcms_c_info *wlc, struct dma_pub *pub, + struct sk_buff *p0); +void dma_txflush(struct dma_pub *pub); +int dma_txpending(struct dma_pub *pub); +void dma_kick_tx(struct dma_pub *pub); void dma_txsuspend(struct dma_pub *pub); bool dma_txsuspended(struct dma_pub *pub); void dma_txresume(struct dma_pub *pub); diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c index a744ea5..85dbaf8 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c @@ -33,6 +33,7 @@ #include "ucode_loader.h" #include "mac80211_if.h" #include "main.h" +#include "debug.h" #define N_TX_QUEUES 4 /* #tx queues on mac80211<->driver interface */ @@ -98,10 +99,14 @@ static struct bcma_device_id brcms_coreid_table[] = { }; MODULE_DEVICE_TABLE(bcma, brcms_coreid_table); -#ifdef DEBUG -static int msglevel = 0xdeadbeef; -module_param(msglevel, int, 0); -#endif /* DEBUG */ +#if defined(CONFIG_BRCMDBG) +/* + * Module parameter for setting the debug message level. Available + * flags are specified by the BRCM_DL_* macros in + * drivers/net/wireless/brcm80211/include/defs.h. + */ +module_param_named(debug, brcm_msg_level, uint, S_IRUGO | S_IWUSR); +#endif static struct ieee80211_channel brcms_2ghz_chantable[] = { CHAN2GHZ(1, 2412, IEEE80211_CHAN_NO_HT40MINUS), @@ -276,12 +281,12 @@ static void brcms_ops_tx(struct ieee80211_hw *hw, spin_lock_bh(&wl->lock); if (!wl->pub->up) { - wiphy_err(wl->wiphy, "ops->tx called while down\n"); + brcms_err(wl->wlc->hw->d11core, "ops->tx called while down\n"); kfree_skb(skb); goto done; } - brcms_c_sendpkt_mac80211(wl->wlc, skb, hw); - tx_info->rate_driver_data[0] = control->sta; + if (brcms_c_sendpkt_mac80211(wl->wlc, skb, hw)) + tx_info->rate_driver_data[0] = control->sta; done: spin_unlock_bh(&wl->lock); } @@ -313,8 +318,8 @@ static int brcms_ops_start(struct ieee80211_hw *hw) spin_unlock_bh(&wl->lock); if (err != 0) - wiphy_err(hw->wiphy, "%s: brcms_up() returned %d\n", __func__, - err); + brcms_err(wl->wlc->hw->d11core, "%s: brcms_up() returned %d\n", + __func__, err); return err; } @@ -332,7 +337,7 @@ static void brcms_ops_stop(struct ieee80211_hw *hw) status = brcms_c_chipmatch(wl->wlc->hw->d11core); spin_unlock_bh(&wl->lock); if (!status) { - wiphy_err(wl->wiphy, + brcms_err(wl->wlc->hw->d11core, "wl: brcms_ops_stop: chipmatch failed\n"); return; } @@ -350,8 +355,9 @@ brcms_ops_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) /* Just STA for now */ if (vif->type != NL80211_IFTYPE_STATION) { - wiphy_err(hw->wiphy, "%s: Attempt to add type %d, only" - " STA for now\n", __func__, vif->type); + brcms_err(wl->wlc->hw->d11core, + "%s: Attempt to add type %d, only STA for now\n", + __func__, vif->type); return -EOPNOTSUPP; } @@ -370,9 +376,9 @@ static int brcms_ops_config(struct ieee80211_hw *hw, u32 changed) { struct ieee80211_conf *conf = &hw->conf; struct brcms_info *wl = hw->priv; + struct bcma_device *core = wl->wlc->hw->d11core; int err = 0; int new_int; - struct wiphy *wiphy = hw->wiphy; spin_lock_bh(&wl->lock); if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) { @@ -380,25 +386,26 @@ static int brcms_ops_config(struct ieee80211_hw *hw, u32 changed) conf->listen_interval); } if (changed & IEEE80211_CONF_CHANGE_MONITOR) - wiphy_dbg(wiphy, "%s: change monitor mode: %s\n", - __func__, conf->flags & IEEE80211_CONF_MONITOR ? - "true" : "false"); + brcms_dbg_info(core, "%s: change monitor mode: %s\n", + __func__, conf->flags & IEEE80211_CONF_MONITOR ? + "true" : "false"); if (changed & IEEE80211_CONF_CHANGE_PS) - wiphy_err(wiphy, "%s: change power-save mode: %s (implement)\n", + brcms_err(core, "%s: change power-save mode: %s (implement)\n", __func__, conf->flags & IEEE80211_CONF_PS ? "true" : "false"); if (changed & IEEE80211_CONF_CHANGE_POWER) { err = brcms_c_set_tx_power(wl->wlc, conf->power_level); if (err < 0) { - wiphy_err(wiphy, "%s: Error setting power_level\n", + brcms_err(core, "%s: Error setting power_level\n", __func__); goto config_out; } new_int = brcms_c_get_tx_power(wl->wlc); if (new_int != conf->power_level) - wiphy_err(wiphy, "%s: Power level req != actual, %d %d" - "\n", __func__, conf->power_level, + brcms_err(core, + "%s: Power level req != actual, %d %d\n", + __func__, conf->power_level, new_int); } if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { @@ -425,13 +432,13 @@ brcms_ops_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_bss_conf *info, u32 changed) { struct brcms_info *wl = hw->priv; - struct wiphy *wiphy = hw->wiphy; + struct bcma_device *core = wl->wlc->hw->d11core; if (changed & BSS_CHANGED_ASSOC) { /* association status changed (associated/disassociated) * also implies a change in the AID. */ - wiphy_err(wiphy, "%s: %s: %sassociated\n", KBUILD_MODNAME, + brcms_err(core, "%s: %s: %sassociated\n", KBUILD_MODNAME, __func__, info->assoc ? "" : "dis"); spin_lock_bh(&wl->lock); brcms_c_associate_upd(wl->wlc, info->assoc); @@ -491,7 +498,7 @@ brcms_ops_bss_info_changed(struct ieee80211_hw *hw, error = brcms_c_set_rateset(wl->wlc, &rs); spin_unlock_bh(&wl->lock); if (error) - wiphy_err(wiphy, "changing basic rates failed: %d\n", + brcms_err(core, "changing basic rates failed: %d\n", error); } if (changed & BSS_CHANGED_BEACON_INT) { @@ -508,30 +515,30 @@ brcms_ops_bss_info_changed(struct ieee80211_hw *hw, } if (changed & BSS_CHANGED_BEACON) /* Beacon data changed, retrieve new beacon (beaconing modes) */ - wiphy_err(wiphy, "%s: beacon changed\n", __func__); + brcms_err(core, "%s: beacon changed\n", __func__); if (changed & BSS_CHANGED_BEACON_ENABLED) { /* Beaconing should be enabled/disabled (beaconing modes) */ - wiphy_err(wiphy, "%s: Beacon enabled: %s\n", __func__, + brcms_err(core, "%s: Beacon enabled: %s\n", __func__, info->enable_beacon ? "true" : "false"); } if (changed & BSS_CHANGED_CQM) { /* Connection quality monitor config changed */ - wiphy_err(wiphy, "%s: cqm change: threshold %d, hys %d " + brcms_err(core, "%s: cqm change: threshold %d, hys %d " " (implement)\n", __func__, info->cqm_rssi_thold, info->cqm_rssi_hyst); } if (changed & BSS_CHANGED_IBSS) { /* IBSS join status changed */ - wiphy_err(wiphy, "%s: IBSS joined: %s (implement)\n", __func__, - info->ibss_joined ? "true" : "false"); + brcms_err(core, "%s: IBSS joined: %s (implement)\n", + __func__, info->ibss_joined ? "true" : "false"); } if (changed & BSS_CHANGED_ARP_FILTER) { /* Hardware ARP filter address list or state changed */ - wiphy_err(wiphy, "%s: arp filtering: enabled %s, count %d" + brcms_err(core, "%s: arp filtering: enabled %s, count %d" " (implement)\n", __func__, info->arp_filter_enabled ? "true" : "false", info->arp_addr_cnt); } @@ -541,8 +548,8 @@ brcms_ops_bss_info_changed(struct ieee80211_hw *hw, * QoS for this association was enabled/disabled. * Note that it is only ever disabled for station mode. */ - wiphy_err(wiphy, "%s: qos enabled: %s (implement)\n", __func__, - info->qos ? "true" : "false"); + brcms_err(core, "%s: qos enabled: %s (implement)\n", + __func__, info->qos ? "true" : "false"); } return; } @@ -553,25 +560,25 @@ brcms_ops_configure_filter(struct ieee80211_hw *hw, unsigned int *total_flags, u64 multicast) { struct brcms_info *wl = hw->priv; - struct wiphy *wiphy = hw->wiphy; + struct bcma_device *core = wl->wlc->hw->d11core; changed_flags &= MAC_FILTERS; *total_flags &= MAC_FILTERS; if (changed_flags & FIF_PROMISC_IN_BSS) - wiphy_dbg(wiphy, "FIF_PROMISC_IN_BSS\n"); + brcms_dbg_info(core, "FIF_PROMISC_IN_BSS\n"); if (changed_flags & FIF_ALLMULTI) - wiphy_dbg(wiphy, "FIF_ALLMULTI\n"); + brcms_dbg_info(core, "FIF_ALLMULTI\n"); if (changed_flags & FIF_FCSFAIL) - wiphy_dbg(wiphy, "FIF_FCSFAIL\n"); + brcms_dbg_info(core, "FIF_FCSFAIL\n"); if (changed_flags & FIF_CONTROL) - wiphy_dbg(wiphy, "FIF_CONTROL\n"); + brcms_dbg_info(core, "FIF_CONTROL\n"); if (changed_flags & FIF_OTHER_BSS) - wiphy_dbg(wiphy, "FIF_OTHER_BSS\n"); + brcms_dbg_info(core, "FIF_OTHER_BSS\n"); if (changed_flags & FIF_PSPOLL) - wiphy_dbg(wiphy, "FIF_PSPOLL\n"); + brcms_dbg_info(core, "FIF_PSPOLL\n"); if (changed_flags & FIF_BCN_PRBRESP_PROMISC) - wiphy_dbg(wiphy, "FIF_BCN_PRBRESP_PROMISC\n"); + brcms_dbg_info(core, "FIF_BCN_PRBRESP_PROMISC\n"); spin_lock_bh(&wl->lock); brcms_c_mac_promisc(wl->wlc, *total_flags); @@ -653,8 +660,8 @@ brcms_ops_ampdu_action(struct ieee80211_hw *hw, status = brcms_c_aggregatable(wl->wlc, tid); spin_unlock_bh(&wl->lock); if (!status) { - wiphy_err(wl->wiphy, "START: tid %d is not agg\'able\n", - tid); + brcms_err(wl->wlc->hw->d11core, + "START: tid %d is not agg\'able\n", tid); return -EINVAL; } ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); @@ -681,8 +688,8 @@ brcms_ops_ampdu_action(struct ieee80211_hw *hw, /* Power save wakeup */ break; default: - wiphy_err(wl->wiphy, "%s: Invalid command, ignoring\n", - __func__); + brcms_err(wl->wlc->hw->d11core, + "%s: Invalid command, ignoring\n", __func__); } return 0; @@ -839,8 +846,10 @@ static void brcms_free(struct brcms_info *wl) /* kill dpc */ tasklet_kill(&wl->tasklet); - if (wl->pub) + if (wl->pub) { + brcms_debugfs_detach(wl->pub); brcms_c_module_unregister(wl->pub, "linux", wl); + } /* free common resources */ if (wl->wlc) { @@ -889,27 +898,22 @@ static void brcms_remove(struct bcma_device *pdev) static irqreturn_t brcms_isr(int irq, void *dev_id) { struct brcms_info *wl; - bool ours, wantdpc; + irqreturn_t ret = IRQ_NONE; wl = (struct brcms_info *) dev_id; spin_lock(&wl->isr_lock); /* call common first level interrupt handler */ - ours = brcms_c_isr(wl->wlc, &wantdpc); - if (ours) { - /* if more to do... */ - if (wantdpc) { - - /* ...and call the second level interrupt handler */ - /* schedule dpc */ - tasklet_schedule(&wl->tasklet); - } + if (brcms_c_isr(wl->wlc)) { + /* schedule second level handler */ + tasklet_schedule(&wl->tasklet); + ret = IRQ_HANDLED; } spin_unlock(&wl->isr_lock); - return IRQ_RETVAL(ours); + return ret; } /* @@ -1075,6 +1079,8 @@ static struct brcms_info *brcms_attach(struct bcma_device *pdev) regulatory_hint(wl->wiphy, wl->pub->srom_ccode)) wiphy_err(wl->wiphy, "%s: regulatory hint failed\n", __func__); + brcms_debugfs_attach(wl->pub); + brcms_debugfs_create_files(wl->pub); n_adapters_found++; return wl; @@ -1144,14 +1150,13 @@ static int brcms_suspend(struct bcma_device *pdev) wl->pub->hw_up = false; spin_unlock_bh(&wl->lock); - pr_debug("brcms_suspend ok\n"); + brcms_dbg_info(wl->wlc->hw->d11core, "brcms_suspend ok\n"); return 0; } static int brcms_resume(struct bcma_device *pdev) { - pr_debug("brcms_resume ok\n"); return 0; } @@ -1184,10 +1189,7 @@ static DECLARE_WORK(brcms_driver_work, brcms_driver_init); static int __init brcms_module_init(void) { -#ifdef DEBUG - if (msglevel != 0xdeadbeef) - brcm_msg_level = msglevel; -#endif + brcms_debugfs_init(); if (!schedule_work(&brcms_driver_work)) return -EBUSY; @@ -1205,6 +1207,7 @@ static void __exit brcms_module_exit(void) { cancel_work_sync(&brcms_driver_work); bcma_driver_unregister(&brcms_bcma_driver); + brcms_debugfs_exit(); } module_init(brcms_module_init); @@ -1216,7 +1219,7 @@ module_exit(brcms_module_exit); void brcms_txflowcontrol(struct brcms_info *wl, struct brcms_if *wlif, bool state, int prio) { - wiphy_err(wl->wiphy, "Shouldn't be here %s\n", __func__); + brcms_err(wl->wlc->hw->d11core, "Shouldn't be here %s\n", __func__); } /* @@ -1224,7 +1227,8 @@ void brcms_txflowcontrol(struct brcms_info *wl, struct brcms_if *wlif, */ void brcms_init(struct brcms_info *wl) { - BCMMSG(wl->pub->ieee_hw->wiphy, "wl%d\n", wl->pub->unit); + brcms_dbg_info(wl->wlc->hw->d11core, "Initializing wl%d\n", + wl->pub->unit); brcms_reset(wl); brcms_c_init(wl->wlc, wl->mute_tx); } @@ -1234,7 +1238,7 @@ void brcms_init(struct brcms_info *wl) */ uint brcms_reset(struct brcms_info *wl) { - BCMMSG(wl->pub->ieee_hw->wiphy, "wl%d\n", wl->pub->unit); + brcms_dbg_info(wl->wlc->hw->d11core, "Resetting wl%d\n", wl->pub->unit); brcms_c_reset(wl->wlc); /* dpc will not be rescheduled */ @@ -1248,7 +1252,7 @@ uint brcms_reset(struct brcms_info *wl) void brcms_fatal_error(struct brcms_info *wl) { - wiphy_err(wl->wlc->wiphy, "wl%d: fatal error, reinitializing\n", + brcms_err(wl->wlc->hw->d11core, "wl%d: fatal error, reinitializing\n", wl->wlc->pub->unit); brcms_reset(wl); ieee80211_restart_hw(wl->pub->ieee_hw); @@ -1396,8 +1400,9 @@ void brcms_add_timer(struct brcms_timer *t, uint ms, int periodic) #ifdef DEBUG if (t->set) - wiphy_err(hw->wiphy, "%s: Already set. Name: %s, per %d\n", - __func__, t->name, periodic); + brcms_dbg_info(t->wl->wlc->hw->d11core, + "%s: Already set. Name: %s, per %d\n", + __func__, t->name, periodic); #endif t->ms = ms; t->periodic = (bool) periodic; @@ -1486,8 +1491,8 @@ int brcms_ucode_init_buf(struct brcms_info *wl, void **pbuf, u32 idx) } } } - wiphy_err(wl->wiphy, "ERROR: ucode buf tag:%d can not be found!\n", - idx); + brcms_err(wl->wlc->hw->d11core, + "ERROR: ucode buf tag:%d can not be found!\n", idx); *pbuf = NULL; fail: return -ENODATA; @@ -1510,7 +1515,7 @@ int brcms_ucode_init_uint(struct brcms_info *wl, size_t *n_bytes, u32 idx) pdata = wl->fw.fw_bin[i]->data + le32_to_cpu(hdr->offset); if (le32_to_cpu(hdr->len) != 4) { - wiphy_err(wl->wiphy, + brcms_err(wl->wlc->hw->d11core, "ERROR: fw hdr len\n"); return -ENOMSG; } @@ -1519,7 +1524,8 @@ int brcms_ucode_init_uint(struct brcms_info *wl, size_t *n_bytes, u32 idx) } } } - wiphy_err(wl->wiphy, "ERROR: ucode tag:%d can not be found!\n", idx); + brcms_err(wl->wlc->hw->d11core, + "ERROR: ucode tag:%d can not be found!\n", idx); return -ENOMSG; } @@ -1560,8 +1566,8 @@ int brcms_check_firmwares(struct brcms_info *wl) sizeof(struct firmware_hdr)); rc = -EBADF; } else if (fw->size < MIN_FW_SIZE || fw->size > MAX_FW_SIZE) { - wiphy_err(wl->wiphy, "%s: out of bounds fw file size " - "%zu\n", __func__, fw->size); + wiphy_err(wl->wiphy, "%s: out of bounds fw file size %zu\n", + __func__, fw->size); rc = -EBADF; } else { /* check if ucode section overruns firmware image */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.c b/drivers/net/wireless/brcm80211/brcmsmac/main.c index 565c15a..8fce687 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/main.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c @@ -34,12 +34,9 @@ #include "ucode_loader.h" #include "main.h" #include "soc.h" - -/* - * Indication for txflowcontrol that all priority bits in - * TXQ_STOP_FOR_PRIOFC_MASK are to be considered. - */ -#define ALLPRIO -1 +#include "dma.h" +#include "debug.h" +#include "brcms_trace_events.h" /* watchdog timer, in unit of ms */ #define TIMER_INTERVAL_WATCHDOG 1000 @@ -126,21 +123,6 @@ #define BRCMS_TEMPSENSE_PERIOD 10 /* 10 second timeout */ -/* precedences numbers for wlc queues. These are twice as may levels as - * 802.1D priorities. - * Odd numbers are used for HI priority traffic at same precedence levels - * These constants are used ONLY by wlc_prio2prec_map. Do not use them - * elsewhere. - */ -#define _BRCMS_PREC_NONE 0 /* None = - */ -#define _BRCMS_PREC_BK 2 /* BK - Background */ -#define _BRCMS_PREC_BE 4 /* BE - Best-effort */ -#define _BRCMS_PREC_EE 6 /* EE - Excellent-effort */ -#define _BRCMS_PREC_CL 8 /* CL - Controlled Load */ -#define _BRCMS_PREC_VI 10 /* Vi - Video */ -#define _BRCMS_PREC_VO 12 /* Vo - Voice */ -#define _BRCMS_PREC_NC 14 /* NC - Network Control */ - /* synthpu_dly times in us */ #define SYNTHPU_DLY_APHY_US 3700 #define SYNTHPU_DLY_BPHY_US 1050 @@ -237,17 +219,17 @@ #define MAX_DMA_SEGS 4 -/* Max # of entries in Tx FIFO based on 4kb page size */ -#define NTXD 256 +/* # of entries in Tx FIFO */ +#define NTXD 64 /* Max # of entries in Rx FIFO based on 4kb page size */ #define NRXD 256 +/* Amount of headroom to leave in Tx FIFO */ +#define TX_HEADROOM 4 + /* try to keep this # rbufs posted to the chip */ #define NRXBUFPOST 32 -/* data msg txq hiwat mark */ -#define BRCMS_DATAHIWAT 50 - /* max # frames to process in brcms_c_recv() */ #define RXBND 8 /* max # tx status to process in wlc_txstatus() */ @@ -283,24 +265,8 @@ struct edcf_acparam { u16 TXOP; } __packed; -const u8 prio2fifo[NUMPRIO] = { - TX_AC_BE_FIFO, /* 0 BE AC_BE Best Effort */ - TX_AC_BK_FIFO, /* 1 BK AC_BK Background */ - TX_AC_BK_FIFO, /* 2 -- AC_BK Background */ - TX_AC_BE_FIFO, /* 3 EE AC_BE Best Effort */ - TX_AC_VI_FIFO, /* 4 CL AC_VI Video */ - TX_AC_VI_FIFO, /* 5 VI AC_VI Video */ - TX_AC_VO_FIFO, /* 6 VO AC_VO Voice */ - TX_AC_VO_FIFO /* 7 NC AC_VO Voice */ -}; - /* debug/trace */ -uint brcm_msg_level = -#if defined(DEBUG) - LOG_ERROR_VAL; -#else - 0; -#endif /* DEBUG */ +uint brcm_msg_level; /* TX FIFO number to WME/802.1E Access Category */ static const u8 wme_fifo2ac[] = { @@ -320,18 +286,6 @@ static const u8 wme_ac2fifo[] = { TX_AC_BK_FIFO }; -/* 802.1D Priority to precedence queue mapping */ -const u8 wlc_prio2prec_map[] = { - _BRCMS_PREC_BE, /* 0 BE - Best-effort */ - _BRCMS_PREC_BK, /* 1 BK - Background */ - _BRCMS_PREC_NONE, /* 2 None = - */ - _BRCMS_PREC_EE, /* 3 EE - Excellent-effort */ - _BRCMS_PREC_CL, /* 4 CL - Controlled Load */ - _BRCMS_PREC_VI, /* 5 Vi - Video */ - _BRCMS_PREC_VO, /* 6 Vo - Voice */ - _BRCMS_PREC_NC, /* 7 NC - Network Control */ -}; - static const u16 xmtfifo_sz[][NFIFO] = { /* corerev 17: 5120, 49152, 49152, 5376, 4352, 1280 */ {20, 192, 192, 21, 17, 5}, @@ -371,6 +325,36 @@ static const char fifo_names[6][0]; static struct brcms_c_info *wlc_info_dbg = (struct brcms_c_info *) (NULL); #endif +/* Mapping of ieee80211 AC numbers to tx fifos */ +static const u8 ac_to_fifo_mapping[IEEE80211_NUM_ACS] = { + [IEEE80211_AC_VO] = TX_AC_VO_FIFO, + [IEEE80211_AC_VI] = TX_AC_VI_FIFO, + [IEEE80211_AC_BE] = TX_AC_BE_FIFO, + [IEEE80211_AC_BK] = TX_AC_BK_FIFO, +}; + +/* Mapping of tx fifos to ieee80211 AC numbers */ +static const u8 fifo_to_ac_mapping[IEEE80211_NUM_ACS] = { + [TX_AC_BK_FIFO] = IEEE80211_AC_BK, + [TX_AC_BE_FIFO] = IEEE80211_AC_BE, + [TX_AC_VI_FIFO] = IEEE80211_AC_VI, + [TX_AC_VO_FIFO] = IEEE80211_AC_VO, +}; + +static u8 brcms_ac_to_fifo(u8 ac) +{ + if (ac >= ARRAY_SIZE(ac_to_fifo_mapping)) + return TX_AC_BE_FIFO; + return ac_to_fifo_mapping[ac]; +} + +static u8 brcms_fifo_to_ac(u8 fifo) +{ + if (fifo >= ARRAY_SIZE(fifo_to_ac_mapping)) + return IEEE80211_AC_BE; + return fifo_to_ac_mapping[fifo]; +} + /* Find basic rate for a given rate */ static u8 brcms_basic_rate(struct brcms_c_info *wlc, u32 rspec) { @@ -415,10 +399,15 @@ static bool brcms_deviceremoved(struct brcms_c_info *wlc) } /* sum the individual fifo tx pending packet counts */ -static s16 brcms_txpktpendtot(struct brcms_c_info *wlc) +static int brcms_txpktpendtot(struct brcms_c_info *wlc) { - return wlc->core->txpktpend[0] + wlc->core->txpktpend[1] + - wlc->core->txpktpend[2] + wlc->core->txpktpend[3]; + int i; + int pending = 0; + + for (i = 0; i < ARRAY_SIZE(wlc->hw->di); i++) + if (wlc->hw->di[i]) + pending += dma_txpending(wlc->hw->di[i]); + return pending; } static bool brcms_is_mband_unlocked(struct brcms_c_info *wlc) @@ -626,14 +615,11 @@ static uint brcms_c_calc_frame_time(struct brcms_c_info *wlc, u32 ratespec, uint rate = rspec2rate(ratespec); if (rate == 0) { - wiphy_err(wlc->wiphy, "wl%d: WAR: using rate of 1 mbps\n", + brcms_err(wlc->hw->d11core, "wl%d: WAR: using rate of 1 mbps\n", wlc->pub->unit); rate = BRCM_RATE_1M; } - BCMMSG(wlc->wiphy, "wl%d: rspec 0x%x, preamble_type %d, len%d\n", - wlc->pub->unit, ratespec, preamble_type, mac_len); - if (is_mcs_rate(ratespec)) { uint mcs = ratespec & RSPEC_RATE_MASK; int tot_streams = mcs_2_txstreams(mcs) + rspec_stc(ratespec); @@ -696,7 +682,7 @@ static void brcms_c_write_inits(struct brcms_hardware *wlc_hw, u16 size; u32 value; - BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); + brcms_dbg_info(wlc_hw->d11core, "wl%d\n", wlc_hw->unit); for (i = 0; inits[i].addr != cpu_to_le16(0xffff); i++) { size = le16_to_cpu(inits[i].size); @@ -725,7 +711,6 @@ static void brcms_c_write_mhf(struct brcms_hardware *wlc_hw, u16 *mhfs) static void brcms_c_ucode_bsinit(struct brcms_hardware *wlc_hw) { - struct wiphy *wiphy = wlc_hw->wlc->wiphy; struct brcms_ucode *ucode = &wlc_hw->wlc->wl->ucode; /* init microcode host flags */ @@ -736,8 +721,9 @@ static void brcms_c_ucode_bsinit(struct brcms_hardware *wlc_hw) if (BRCMS_ISNPHY(wlc_hw->band)) brcms_c_write_inits(wlc_hw, ucode->d11n0bsinitvals16); else - wiphy_err(wiphy, "%s: wl%d: unsupported phy in corerev" - " %d\n", __func__, wlc_hw->unit, + brcms_err(wlc_hw->d11core, + "%s: wl%d: unsupported phy in corerev %d\n", + __func__, wlc_hw->unit, wlc_hw->corerev); } else { if (D11REV_IS(wlc_hw->corerev, 24)) { @@ -745,12 +731,14 @@ static void brcms_c_ucode_bsinit(struct brcms_hardware *wlc_hw) brcms_c_write_inits(wlc_hw, ucode->d11lcn0bsinitvals24); else - wiphy_err(wiphy, "%s: wl%d: unsupported phy in" - " core rev %d\n", __func__, - wlc_hw->unit, wlc_hw->corerev); + brcms_err(wlc_hw->d11core, + "%s: wl%d: unsupported phy in core rev %d\n", + __func__, wlc_hw->unit, + wlc_hw->corerev); } else { - wiphy_err(wiphy, "%s: wl%d: unsupported corerev %d\n", - __func__, wlc_hw->unit, wlc_hw->corerev); + brcms_err(wlc_hw->d11core, + "%s: wl%d: unsupported corerev %d\n", + __func__, wlc_hw->unit, wlc_hw->corerev); } } } @@ -765,7 +753,7 @@ static void brcms_b_core_ioctl(struct brcms_hardware *wlc_hw, u32 m, u32 v) static void brcms_b_core_phy_clk(struct brcms_hardware *wlc_hw, bool clk) { - BCMMSG(wlc_hw->wlc->wiphy, "wl%d: clk %d\n", wlc_hw->unit, clk); + brcms_dbg_info(wlc_hw->d11core, "wl%d: clk %d\n", wlc_hw->unit, clk); wlc_hw->phyclk = clk; @@ -790,8 +778,8 @@ static void brcms_b_core_phy_clk(struct brcms_hardware *wlc_hw, bool clk) /* low-level band switch utility routine */ static void brcms_c_setxband(struct brcms_hardware *wlc_hw, uint bandunit) { - BCMMSG(wlc_hw->wlc->wiphy, "wl%d: bandunit %d\n", wlc_hw->unit, - bandunit); + brcms_dbg_mac80211(wlc_hw->d11core, "wl%d: bandunit %d\n", wlc_hw->unit, + bandunit); wlc_hw->band = wlc_hw->bandstate[bandunit]; @@ -819,7 +807,7 @@ static u32 brcms_c_setband_inact(struct brcms_c_info *wlc, uint bandunit) u32 macintmask; u32 macctrl; - BCMMSG(wlc->wiphy, "wl%d\n", wlc_hw->unit); + brcms_dbg_mac80211(wlc_hw->d11core, "wl%d\n", wlc_hw->unit); macctrl = bcma_read32(wlc_hw->d11core, D11REGOFFS(maccontrol)); WARN_ON((macctrl & MCTL_EN_MAC) != 0); @@ -841,9 +829,10 @@ static u32 brcms_c_setband_inact(struct brcms_c_info *wlc, uint bandunit) static bool brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs) { - struct sk_buff *p; - uint queue; - struct d11txh *txh; + struct sk_buff *p = NULL; + uint queue = NFIFO; + struct dma_pub *dma = NULL; + struct d11txh *txh = NULL; struct scb *scb = NULL; bool free_pdu; int tx_rts, tx_frame_count, tx_rts_count; @@ -854,6 +843,11 @@ brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs) struct ieee80211_tx_info *tx_info; struct ieee80211_tx_rate *txrate; int i; + bool fatal = true; + + trace_brcms_txstatus(&wlc->hw->d11core->dev, txs->framelen, + txs->frameid, txs->status, txs->lasttxtime, + txs->sequence, txs->phyerr, txs->ackphyrxsh); /* discard intermediate indications for ucode with one legitimate case: * e.g. if "useRTS" is set. ucode did a successful rts/cts exchange, @@ -862,34 +856,36 @@ brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs) */ if (!(txs->status & TX_STATUS_AMPDU) && (txs->status & TX_STATUS_INTERMEDIATE)) { - BCMMSG(wlc->wiphy, "INTERMEDIATE but not AMPDU\n"); - return false; + brcms_dbg_tx(wlc->hw->d11core, "INTERMEDIATE but not AMPDU\n"); + fatal = false; + goto out; } queue = txs->frameid & TXFID_QUEUE_MASK; if (queue >= NFIFO) { - p = NULL; - goto fatal; + brcms_err(wlc->hw->d11core, "queue %u >= NFIFO\n", queue); + goto out; } + dma = wlc->hw->di[queue]; + p = dma_getnexttxp(wlc->hw->di[queue], DMA_RANGE_TRANSMITTED); - if (p == NULL) - goto fatal; + if (p == NULL) { + brcms_err(wlc->hw->d11core, "dma_getnexttxp returned null!\n"); + goto out; + } txh = (struct d11txh *) (p->data); mcl = le16_to_cpu(txh->MacTxControlLow); - if (txs->phyerr) { - if (brcm_msg_level & LOG_ERROR_VAL) { - wiphy_err(wlc->wiphy, "phyerr 0x%x, rate 0x%x\n", - txs->phyerr, txh->MainRates); - brcms_c_print_txdesc(txh); - } - brcms_c_print_txstatus(txs); - } + if (txs->phyerr) + brcms_err(wlc->hw->d11core, "phyerr 0x%x, rate 0x%x\n", + txs->phyerr, txh->MainRates); - if (txs->frameid != le16_to_cpu(txh->TxFrameID)) - goto fatal; + if (txs->frameid != le16_to_cpu(txh->TxFrameID)) { + brcms_err(wlc->hw->d11core, "frameid != txh->TxFrameID\n"); + goto out; + } tx_info = IEEE80211_SKB_CB(p); h = (struct ieee80211_hdr *)((u8 *) (txh + 1) + D11_PHY_HDR_LEN); @@ -898,14 +894,24 @@ brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs) if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { brcms_c_ampdu_dotxstatus(wlc->ampdu, scb, p, txs); - return false; + fatal = false; + goto out; } + /* + * brcms_c_ampdu_dotxstatus() will trace tx descriptors for AMPDU + * frames; this traces them for the rest. + */ + trace_brcms_txdesc(&wlc->hw->d11core->dev, txh, sizeof(*txh)); + supr_status = txs->status & TX_STATUS_SUPR_MASK; - if (supr_status == TX_STATUS_SUPR_BADCH) - BCMMSG(wlc->wiphy, - "%s: Pkt tx suppressed, possibly channel %d\n", - __func__, CHSPEC_CHANNEL(wlc->default_bss->chanspec)); + if (supr_status == TX_STATUS_SUPR_BADCH) { + unsigned xfts = le16_to_cpu(txh->XtraFrameTypes); + brcms_dbg_tx(wlc->hw->d11core, + "Pkt tx suppressed, dest chan %u, current %d\n", + (xfts >> XFTS_CHANNEL_SHIFT) & 0xff, + CHSPEC_CHANNEL(wlc->default_bss->chanspec)); + } tx_rts = le16_to_cpu(txh->MacTxControlLow) & TXC_SENDRTS; tx_frame_count = @@ -916,7 +922,7 @@ brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs) lastframe = !ieee80211_has_morefrags(h->frame_control); if (!lastframe) { - wiphy_err(wlc->wiphy, "Not last frame!\n"); + brcms_err(wlc->hw->d11core, "Not last frame!\n"); } else { /* * Set information to be consumed by Minstrel ht. @@ -982,26 +988,37 @@ brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs) totlen = p->len; free_pdu = true; - brcms_c_txfifo_complete(wlc, queue, 1); - if (lastframe) { /* remove PLCP & Broadcom tx descriptor header */ skb_pull(p, D11_PHY_HDR_LEN); skb_pull(p, D11_TXH_LEN); ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw, p); } else { - wiphy_err(wlc->wiphy, "%s: Not last frame => not calling " - "tx_status\n", __func__); + brcms_err(wlc->hw->d11core, + "%s: Not last frame => not calling tx_status\n", + __func__); } - return false; + fatal = false; - fatal: - if (p) - brcmu_pkt_buf_free_skb(p); + out: + if (fatal) { + if (txh) + trace_brcms_txdesc(&wlc->hw->d11core->dev, txh, + sizeof(*txh)); + if (p) + brcmu_pkt_buf_free_skb(p); + } - return true; + if (dma && queue < NFIFO) { + u16 ac_queue = brcms_fifo_to_ac(queue); + if (dma->txavail > TX_HEADROOM && queue < TX_BCMC_FIFO && + ieee80211_queue_stopped(wlc->pub->ieee_hw, ac_queue)) + ieee80211_wake_queue(wlc->pub->ieee_hw, ac_queue); + dma_kick_tx(dma); + } + return fatal; } /* process tx completion events in BMAC @@ -1011,7 +1028,6 @@ static bool brcms_b_txstatus(struct brcms_hardware *wlc_hw, bool bound, bool *fatal) { bool morepending = false; - struct brcms_c_info *wlc = wlc_hw->wlc; struct bcma_device *core; struct tx_status txstatus, *txs; u32 s1, s2; @@ -1022,19 +1038,23 @@ brcms_b_txstatus(struct brcms_hardware *wlc_hw, bool bound, bool *fatal) */ uint max_tx_num = bound ? TXSBND : -1; - BCMMSG(wlc->wiphy, "wl%d\n", wlc_hw->unit); - txs = &txstatus; core = wlc_hw->d11core; *fatal = false; s1 = bcma_read32(core, D11REGOFFS(frmtxstatus)); while (!(*fatal) && (s1 & TXS_V)) { + /* !give others some time to run! */ + if (n >= max_tx_num) { + morepending = true; + break; + } if (s1 == 0xffffffff) { - wiphy_err(wlc->wiphy, "wl%d: %s: dead chip\n", - wlc_hw->unit, __func__); - return morepending; + brcms_err(core, "wl%d: %s: dead chip\n", wlc_hw->unit, + __func__); + *fatal = true; + return false; } s2 = bcma_read32(core, D11REGOFFS(frmtxstatus2)); @@ -1046,20 +1066,12 @@ brcms_b_txstatus(struct brcms_hardware *wlc_hw, bool bound, bool *fatal) *fatal = brcms_c_dotxstatus(wlc_hw->wlc, txs); - /* !give others some time to run! */ - if (++n >= max_tx_num) - break; s1 = bcma_read32(core, D11REGOFFS(frmtxstatus)); + n++; } if (*fatal) - return 0; - - if (n >= max_tx_num) - morepending = true; - - if (!pktq_empty(&wlc->pkt_queue->q)) - brcms_c_send_q(wlc); + return false; return morepending; } @@ -1112,7 +1124,6 @@ static bool brcms_b_attach_dmapio(struct brcms_c_info *wlc, uint j, bool wme) u16 pio_mhf2 = 0; struct brcms_hardware *wlc_hw = wlc->hw; uint unit = wlc_hw->unit; - struct wiphy *wiphy = wlc->wiphy; /* name and offsets for dma_attach */ snprintf(name, sizeof(name), "wl%d", unit); @@ -1125,12 +1136,12 @@ static bool brcms_b_attach_dmapio(struct brcms_c_info *wlc, uint j, bool wme) * TX: TX_AC_BK_FIFO (TX AC Background data packets) * RX: RX_FIFO (RX data packets) */ - wlc_hw->di[0] = dma_attach(name, wlc_hw->sih, wlc_hw->d11core, + wlc_hw->di[0] = dma_attach(name, wlc, (wme ? dmareg(DMA_TX, 0) : 0), dmareg(DMA_RX, 0), (wme ? NTXD : 0), NRXD, RXBUFSZ, -1, NRXBUFPOST, - BRCMS_HWRXOFF, &brcm_msg_level); + BRCMS_HWRXOFF); dma_attach_err |= (NULL == wlc_hw->di[0]); /* @@ -1139,10 +1150,9 @@ static bool brcms_b_attach_dmapio(struct brcms_c_info *wlc, uint j, bool wme) * (legacy) TX_DATA_FIFO (TX data packets) * RX: UNUSED */ - wlc_hw->di[1] = dma_attach(name, wlc_hw->sih, wlc_hw->d11core, + wlc_hw->di[1] = dma_attach(name, wlc, dmareg(DMA_TX, 1), 0, - NTXD, 0, 0, -1, 0, 0, - &brcm_msg_level); + NTXD, 0, 0, -1, 0, 0); dma_attach_err |= (NULL == wlc_hw->di[1]); /* @@ -1150,26 +1160,26 @@ static bool brcms_b_attach_dmapio(struct brcms_c_info *wlc, uint j, bool wme) * TX: TX_AC_VI_FIFO (TX AC Video data packets) * RX: UNUSED */ - wlc_hw->di[2] = dma_attach(name, wlc_hw->sih, wlc_hw->d11core, + wlc_hw->di[2] = dma_attach(name, wlc, dmareg(DMA_TX, 2), 0, - NTXD, 0, 0, -1, 0, 0, - &brcm_msg_level); + NTXD, 0, 0, -1, 0, 0); dma_attach_err |= (NULL == wlc_hw->di[2]); /* * FIFO 3 * TX: TX_AC_VO_FIFO (TX AC Voice data packets) * (legacy) TX_CTL_FIFO (TX control & mgmt packets) */ - wlc_hw->di[3] = dma_attach(name, wlc_hw->sih, wlc_hw->d11core, + wlc_hw->di[3] = dma_attach(name, wlc, dmareg(DMA_TX, 3), 0, NTXD, 0, 0, -1, - 0, 0, &brcm_msg_level); + 0, 0); dma_attach_err |= (NULL == wlc_hw->di[3]); /* Cleaner to leave this as if with AP defined */ if (dma_attach_err) { - wiphy_err(wiphy, "wl%d: wlc_attach: dma_attach failed" - "\n", unit); + brcms_err(wlc_hw->d11core, + "wl%d: wlc_attach: dma_attach failed\n", + unit); return false; } @@ -1503,8 +1513,7 @@ brcms_b_set_addrmatch(struct brcms_hardware *wlc_hw, int match_reg_offset, u16 mac_m; u16 mac_h; - BCMMSG(wlc_hw->wlc->wiphy, "wl%d: brcms_b_set_addrmatch\n", - wlc_hw->unit); + brcms_dbg_rx(core, "wl%d: brcms_b_set_addrmatch\n", wlc_hw->unit); mac_l = addr[0] | (addr[1] << 8); mac_m = addr[2] | (addr[3] << 8); @@ -1527,7 +1536,7 @@ brcms_b_write_template_ram(struct brcms_hardware *wlc_hw, int offset, int len, __le32 word_le; __be32 word_be; bool be_bit; - BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); + brcms_dbg_info(core, "wl%d\n", wlc_hw->unit); bcma_write32(core, D11REGOFFS(tplatewrptr), offset); @@ -1700,8 +1709,8 @@ static void brcms_b_bsinit(struct brcms_c_info *wlc, u16 chanspec) { struct brcms_hardware *wlc_hw = wlc->hw; - BCMMSG(wlc->wiphy, "wl%d: bandunit %d\n", wlc_hw->unit, - wlc_hw->band->bandunit); + brcms_dbg_mac80211(wlc_hw->d11core, "wl%d: bandunit %d\n", wlc_hw->unit, + wlc_hw->band->bandunit); brcms_c_ucode_bsinit(wlc_hw); @@ -1736,8 +1745,6 @@ static void brcms_b_bsinit(struct brcms_c_info *wlc, u16 chanspec) /* Perform a soft reset of the PHY PLL */ void brcms_b_core_phypll_reset(struct brcms_hardware *wlc_hw) { - BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); - ai_cc_reg(wlc_hw->sih, offsetof(struct chipcregs, chipcontrol_addr), ~0, 0); udelay(1); @@ -1782,7 +1789,7 @@ void brcms_b_phy_reset(struct brcms_hardware *wlc_hw) u32 phy_bw_clkbits; bool phy_in_reset = false; - BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); + brcms_dbg_info(wlc_hw->d11core, "wl%d: reset phy\n", wlc_hw->unit); if (pih == NULL) return; @@ -1916,7 +1923,7 @@ static void brcms_c_get_macaddr(struct brcms_hardware *wlc_hw, u8 etheraddr[ETH_ /* power both the pll and external oscillator on/off */ static void brcms_b_xtal(struct brcms_hardware *wlc_hw, bool want) { - BCMMSG(wlc_hw->wlc->wiphy, "wl%d: want %d\n", wlc_hw->unit, want); + brcms_dbg_info(wlc_hw->d11core, "wl%d: want %d\n", wlc_hw->unit, want); /* * dont power down if plldown is false or @@ -2005,7 +2012,7 @@ void brcms_b_corereset(struct brcms_hardware *wlc_hw, u32 flags) if (flags == BRCMS_USE_COREFLAGS) flags = (wlc_hw->band->pi ? wlc_hw->band->core_flags : 0); - BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); + brcms_dbg_info(wlc_hw->d11core, "wl%d: core reset\n", wlc_hw->unit); /* request FAST clock if not on */ fastclk = wlc_hw->forcefastclk; @@ -2016,13 +2023,13 @@ void brcms_b_corereset(struct brcms_hardware *wlc_hw, u32 flags) if (bcma_core_is_enabled(wlc_hw->d11core)) { for (i = 0; i < NFIFO; i++) if ((wlc_hw->di[i]) && (!dma_txreset(wlc_hw->di[i]))) - wiphy_err(wlc_hw->wlc->wiphy, "wl%d: %s: " + brcms_err(wlc_hw->d11core, "wl%d: %s: " "dma_txreset[%d]: cannot stop dma\n", wlc_hw->unit, __func__, i); if ((wlc_hw->di[RX_FIFO]) && (!wlc_dma_rxreset(wlc_hw, RX_FIFO))) - wiphy_err(wlc_hw->wlc->wiphy, "wl%d: %s: dma_rxreset" + brcms_err(wlc_hw->d11core, "wl%d: %s: dma_rxreset" "[%d]: cannot stop dma\n", wlc_hw->unit, __func__, RX_FIFO); } @@ -2235,7 +2242,7 @@ static void brcms_ucode_write(struct brcms_hardware *wlc_hw, uint i; uint count; - BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); + brcms_dbg_info(wlc_hw->d11core, "wl%d\n", wlc_hw->unit); count = (nbytes / sizeof(u32)); @@ -2263,8 +2270,8 @@ static void brcms_ucode_download(struct brcms_hardware *wlc_hw) ucode->bcm43xx_16_mimosz); wlc_hw->ucode_loaded = true; } else - wiphy_err(wlc->wiphy, "%s: wl%d: unsupported phy in " - "corerev %d\n", + brcms_err(wlc_hw->d11core, + "%s: wl%d: unsupported phy in corerev %d\n", __func__, wlc_hw->unit, wlc_hw->corerev); } else if (D11REV_IS(wlc_hw->corerev, 24)) { if (BRCMS_ISLCNPHY(wlc_hw->band)) { @@ -2272,8 +2279,8 @@ static void brcms_ucode_download(struct brcms_hardware *wlc_hw) ucode->bcm43xx_24_lcnsz); wlc_hw->ucode_loaded = true; } else { - wiphy_err(wlc->wiphy, "%s: wl%d: unsupported phy in " - "corerev %d\n", + brcms_err(wlc_hw->d11core, + "%s: wl%d: unsupported phy in corerev %d\n", __func__, wlc_hw->unit, wlc_hw->corerev); } } @@ -2310,7 +2317,6 @@ static void brcms_b_fifoerrors(struct brcms_hardware *wlc_hw) uint unit; uint intstatus, idx; struct bcma_device *core = wlc_hw->d11core; - struct wiphy *wiphy = wlc_hw->wlc->wiphy; unit = wlc_hw->unit; @@ -2323,39 +2329,39 @@ static void brcms_b_fifoerrors(struct brcms_hardware *wlc_hw) if (!intstatus) continue; - BCMMSG(wlc_hw->wlc->wiphy, "wl%d: intstatus%d 0x%x\n", - unit, idx, intstatus); + brcms_dbg_int(core, "wl%d: intstatus%d 0x%x\n", + unit, idx, intstatus); if (intstatus & I_RO) { - wiphy_err(wiphy, "wl%d: fifo %d: receive fifo " + brcms_err(core, "wl%d: fifo %d: receive fifo " "overflow\n", unit, idx); fatal = true; } if (intstatus & I_PC) { - wiphy_err(wiphy, "wl%d: fifo %d: descriptor error\n", - unit, idx); + brcms_err(core, "wl%d: fifo %d: descriptor error\n", + unit, idx); fatal = true; } if (intstatus & I_PD) { - wiphy_err(wiphy, "wl%d: fifo %d: data error\n", unit, + brcms_err(core, "wl%d: fifo %d: data error\n", unit, idx); fatal = true; } if (intstatus & I_DE) { - wiphy_err(wiphy, "wl%d: fifo %d: descriptor protocol " + brcms_err(core, "wl%d: fifo %d: descriptor protocol " "error\n", unit, idx); fatal = true; } if (intstatus & I_RU) - wiphy_err(wiphy, "wl%d: fifo %d: receive descriptor " + brcms_err(core, "wl%d: fifo %d: receive descriptor " "underflow\n", idx, unit); if (intstatus & I_XU) { - wiphy_err(wiphy, "wl%d: fifo %d: transmit fifo " + brcms_err(core, "wl%d: fifo %d: transmit fifo " "underflow\n", idx, unit); fatal = true; } @@ -2516,13 +2522,13 @@ static inline u32 wlc_intstatus(struct brcms_c_info *wlc, bool in_isr) { struct brcms_hardware *wlc_hw = wlc->hw; struct bcma_device *core = wlc_hw->d11core; - u32 macintstatus; + u32 macintstatus, mask; /* macintstatus includes a DMA interrupt summary bit */ macintstatus = bcma_read32(core, D11REGOFFS(macintstatus)); + mask = in_isr ? wlc->macintmask : wlc->defmacintmask; - BCMMSG(wlc->wiphy, "wl%d: macintstatus: 0x%x\n", wlc_hw->unit, - macintstatus); + trace_brcms_macintstatus(&core->dev, in_isr, macintstatus, mask); /* detect cardbus removed, in power down(suspend) and in reset */ if (brcms_deviceremoved(wlc)) @@ -2535,16 +2541,12 @@ static inline u32 wlc_intstatus(struct brcms_c_info *wlc, bool in_isr) return 0; /* defer unsolicited interrupts */ - macintstatus &= (in_isr ? wlc->macintmask : wlc->defmacintmask); + macintstatus &= mask; /* if not for us */ if (macintstatus == 0) return 0; - /* interrupts are already turned off for CFE build - * Caution: For CFE Turning off the interrupts again has some undesired - * consequences - */ /* turn off the interrupts */ bcma_write32(core, D11REGOFFS(macintmask), 0); (void)bcma_read32(core, D11REGOFFS(macintmask)); @@ -2587,33 +2589,31 @@ bool brcms_c_intrsupd(struct brcms_c_info *wlc) /* * First-level interrupt processing. - * Return true if this was our interrupt, false otherwise. - * *wantdpc will be set to true if further brcms_c_dpc() processing is required, + * Return true if this was our interrupt + * and if further brcms_c_dpc() processing is required, * false otherwise. */ -bool brcms_c_isr(struct brcms_c_info *wlc, bool *wantdpc) +bool brcms_c_isr(struct brcms_c_info *wlc) { struct brcms_hardware *wlc_hw = wlc->hw; u32 macintstatus; - *wantdpc = false; - if (!wlc_hw->up || !wlc->macintmask) return false; /* read and clear macintstatus and intstatus registers */ macintstatus = wlc_intstatus(wlc, true); - if (macintstatus == 0xffffffff) - wiphy_err(wlc->wiphy, "DEVICEREMOVED detected in the ISR code" - " path\n"); + if (macintstatus == 0xffffffff) { + brcms_err(wlc_hw->d11core, + "DEVICEREMOVED detected in the ISR code path\n"); + return false; + } /* it is not for us */ if (macintstatus == 0) return false; - *wantdpc = true; - /* save interrupt status bits */ wlc->macintstatus = macintstatus; @@ -2626,10 +2626,9 @@ void brcms_c_suspend_mac_and_wait(struct brcms_c_info *wlc) struct brcms_hardware *wlc_hw = wlc->hw; struct bcma_device *core = wlc_hw->d11core; u32 mc, mi; - struct wiphy *wiphy = wlc->wiphy; - BCMMSG(wlc->wiphy, "wl%d: bandunit %d\n", wlc_hw->unit, - wlc_hw->band->bandunit); + brcms_dbg_mac80211(core, "wl%d: bandunit %d\n", wlc_hw->unit, + wlc_hw->band->bandunit); /* * Track overlapping suspend requests @@ -2644,7 +2643,7 @@ void brcms_c_suspend_mac_and_wait(struct brcms_c_info *wlc) mc = bcma_read32(core, D11REGOFFS(maccontrol)); if (mc == 0xffffffff) { - wiphy_err(wiphy, "wl%d: %s: dead chip\n", wlc_hw->unit, + brcms_err(core, "wl%d: %s: dead chip\n", wlc_hw->unit, __func__); brcms_down(wlc->wl); return; @@ -2655,7 +2654,7 @@ void brcms_c_suspend_mac_and_wait(struct brcms_c_info *wlc) mi = bcma_read32(core, D11REGOFFS(macintstatus)); if (mi == 0xffffffff) { - wiphy_err(wiphy, "wl%d: %s: dead chip\n", wlc_hw->unit, + brcms_err(core, "wl%d: %s: dead chip\n", wlc_hw->unit, __func__); brcms_down(wlc->wl); return; @@ -2668,10 +2667,10 @@ void brcms_c_suspend_mac_and_wait(struct brcms_c_info *wlc) BRCMS_MAX_MAC_SUSPEND); if (!(bcma_read32(core, D11REGOFFS(macintstatus)) & MI_MACSSPNDD)) { - wiphy_err(wiphy, "wl%d: wlc_suspend_mac_and_wait: waited %d uS" + brcms_err(core, "wl%d: wlc_suspend_mac_and_wait: waited %d uS" " and MI_MACSSPNDD is still not on.\n", wlc_hw->unit, BRCMS_MAX_MAC_SUSPEND); - wiphy_err(wiphy, "wl%d: psmdebug 0x%08x, phydebug 0x%08x, " + brcms_err(core, "wl%d: psmdebug 0x%08x, phydebug 0x%08x, " "psm_brc 0x%04x\n", wlc_hw->unit, bcma_read32(core, D11REGOFFS(psmdebug)), bcma_read32(core, D11REGOFFS(phydebug)), @@ -2680,7 +2679,7 @@ void brcms_c_suspend_mac_and_wait(struct brcms_c_info *wlc) mc = bcma_read32(core, D11REGOFFS(maccontrol)); if (mc == 0xffffffff) { - wiphy_err(wiphy, "wl%d: %s: dead chip\n", wlc_hw->unit, + brcms_err(core, "wl%d: %s: dead chip\n", wlc_hw->unit, __func__); brcms_down(wlc->wl); return; @@ -2696,8 +2695,8 @@ void brcms_c_enable_mac(struct brcms_c_info *wlc) struct bcma_device *core = wlc_hw->d11core; u32 mc, mi; - BCMMSG(wlc->wiphy, "wl%d: bandunit %d\n", wlc_hw->unit, - wlc->band->bandunit); + brcms_dbg_mac80211(core, "wl%d: bandunit %d\n", wlc_hw->unit, + wlc->band->bandunit); /* * Track overlapping suspend requests @@ -2740,8 +2739,6 @@ static bool brcms_b_validate_chip_access(struct brcms_hardware *wlc_hw) u32 w, val; struct wiphy *wiphy = wlc_hw->wlc->wiphy; - BCMMSG(wiphy, "wl%d\n", wlc_hw->unit); - /* Validate dchip register access */ bcma_write32(core, D11REGOFFS(objaddr), OBJADDR_SHM_SEL | 0); @@ -2802,7 +2799,7 @@ void brcms_b_core_phypll_ctl(struct brcms_hardware *wlc_hw, bool on) struct bcma_device *core = wlc_hw->d11core; u32 tmp; - BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); + brcms_dbg_info(core, "wl%d\n", wlc_hw->unit); tmp = 0; @@ -2818,8 +2815,8 @@ void brcms_b_core_phypll_ctl(struct brcms_hardware *wlc_hw, bool on) tmp = bcma_read32(core, D11REGOFFS(clk_ctl_st)); if ((tmp & CCS_ERSRC_AVAIL_HT) != CCS_ERSRC_AVAIL_HT) - wiphy_err(wlc_hw->wlc->wiphy, "%s: turn on PHY" - " PLL failed\n", __func__); + brcms_err(core, "%s: turn on PHY PLL failed\n", + __func__); } else { bcma_set32(core, D11REGOFFS(clk_ctl_st), tmp | CCS_ERSRC_REQ_D11PLL | @@ -2835,8 +2832,8 @@ void brcms_b_core_phypll_ctl(struct brcms_hardware *wlc_hw, bool on) (CCS_ERSRC_AVAIL_D11PLL | CCS_ERSRC_AVAIL_PHYPLL)) != (CCS_ERSRC_AVAIL_D11PLL | CCS_ERSRC_AVAIL_PHYPLL)) - wiphy_err(wlc_hw->wlc->wiphy, "%s: turn on " - "PHY PLL failed\n", __func__); + brcms_err(core, "%s: turn on PHY PLL failed\n", + __func__); } } else { /* @@ -2854,7 +2851,7 @@ static void brcms_c_coredisable(struct brcms_hardware *wlc_hw) { bool dev_gone; - BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); + brcms_dbg_info(wlc_hw->d11core, "wl%d: disable core\n", wlc_hw->unit); dev_gone = brcms_deviceremoved(wlc_hw->wlc); @@ -2884,12 +2881,14 @@ static void brcms_c_flushqueues(struct brcms_c_info *wlc) uint i; /* free any posted tx packets */ - for (i = 0; i < NFIFO; i++) + for (i = 0; i < NFIFO; i++) { if (wlc_hw->di[i]) { dma_txreclaim(wlc_hw->di[i], DMA_RANGE_ALL); - wlc->core->txpktpend[i] = 0; - BCMMSG(wlc->wiphy, "pktpend fifo %d clrd\n", i); + if (i < TX_BCMC_FIFO) + ieee80211_wake_queue(wlc->pub->ieee_hw, + brcms_fifo_to_ac(i)); } + } /* free any posted rx packets */ dma_rxreclaim(wlc_hw->di[RX_FIFO]); @@ -3109,7 +3108,7 @@ static void brcms_c_statsupd(struct brcms_c_info *wlc) /* check for rx fifo 0 overflow */ delta = (u16) (wlc->core->macstat_snapshot->rxf0ovfl - rxf0ovfl); if (delta) - wiphy_err(wlc->wiphy, "wl%d: %u rx fifo 0 overflows!\n", + brcms_err(wlc->hw->d11core, "wl%d: %u rx fifo 0 overflows!\n", wlc->pub->unit, delta); /* check for tx fifo underflows */ @@ -3118,8 +3117,9 @@ static void brcms_c_statsupd(struct brcms_c_info *wlc) (u16) (wlc->core->macstat_snapshot->txfunfl[i] - txfunfl[i]); if (delta) - wiphy_err(wlc->wiphy, "wl%d: %u tx fifo %d underflows!" - "\n", wlc->pub->unit, delta, i); + brcms_err(wlc->hw->d11core, + "wl%d: %u tx fifo %d underflows!\n", + wlc->pub->unit, delta, i); } #endif /* DEBUG */ @@ -3132,8 +3132,6 @@ static void brcms_c_statsupd(struct brcms_c_info *wlc) static void brcms_b_reset(struct brcms_hardware *wlc_hw) { - BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); - /* reset the core */ if (!brcms_deviceremoved(wlc_hw->wlc)) brcms_b_corereset(wlc_hw, BRCMS_USE_COREFLAGS); @@ -3144,7 +3142,7 @@ static void brcms_b_reset(struct brcms_hardware *wlc_hw) void brcms_c_reset(struct brcms_c_info *wlc) { - BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit); + brcms_dbg_info(wlc->hw->d11core, "wl%d\n", wlc->pub->unit); /* slurp up hw mac counters before core reset */ brcms_c_statsupd(wlc); @@ -3189,10 +3187,9 @@ static void brcms_b_coreinit(struct brcms_c_info *wlc) bool fifosz_fixup = false; int err = 0; u16 buf[NFIFO]; - struct wiphy *wiphy = wlc->wiphy; struct brcms_ucode *ucode = &wlc_hw->wlc->wl->ucode; - BCMMSG(wlc->wiphy, "wl%d\n", wlc_hw->unit); + brcms_dbg_info(core, "wl%d: core init\n", wlc_hw->unit); /* reset PSM */ brcms_b_mctrl(wlc_hw, ~0, (MCTL_IHR_EN | MCTL_PSM_JMP_0 | MCTL_WAKE)); @@ -3212,7 +3209,7 @@ static void brcms_b_coreinit(struct brcms_c_info *wlc) SPINWAIT(((bcma_read32(core, D11REGOFFS(macintstatus)) & MI_MACSSPNDD) == 0), 1000 * 1000); if ((bcma_read32(core, D11REGOFFS(macintstatus)) & MI_MACSSPNDD) == 0) - wiphy_err(wiphy, "wl%d: wlc_coreinit: ucode did not self-" + brcms_err(core, "wl%d: wlc_coreinit: ucode did not self-" "suspend!\n", wlc_hw->unit); brcms_c_gpio_init(wlc); @@ -3223,18 +3220,18 @@ static void brcms_b_coreinit(struct brcms_c_info *wlc) if (BRCMS_ISNPHY(wlc_hw->band)) brcms_c_write_inits(wlc_hw, ucode->d11n0initvals16); else - wiphy_err(wiphy, "%s: wl%d: unsupported phy in corerev" + brcms_err(core, "%s: wl%d: unsupported phy in corerev" " %d\n", __func__, wlc_hw->unit, wlc_hw->corerev); } else if (D11REV_IS(wlc_hw->corerev, 24)) { if (BRCMS_ISLCNPHY(wlc_hw->band)) brcms_c_write_inits(wlc_hw, ucode->d11lcn0initvals24); else - wiphy_err(wiphy, "%s: wl%d: unsupported phy in corerev" + brcms_err(core, "%s: wl%d: unsupported phy in corerev" " %d\n", __func__, wlc_hw->unit, wlc_hw->corerev); } else { - wiphy_err(wiphy, "%s: wl%d: unsupported corerev %d\n", + brcms_err(core, "%s: wl%d: unsupported corerev %d\n", __func__, wlc_hw->unit, wlc_hw->corerev); } @@ -3276,7 +3273,7 @@ static void brcms_b_coreinit(struct brcms_c_info *wlc) err = -1; } if (err != 0) - wiphy_err(wiphy, "wlc_coreinit: txfifo mismatch: ucode size %d" + brcms_err(core, "wlc_coreinit: txfifo mismatch: ucode size %d" " driver size %d index %d\n", buf[i], wlc_hw->xmtfifo_sz[i], i); @@ -3359,8 +3356,6 @@ static brcms_b_init(struct brcms_hardware *wlc_hw, u16 chanspec) { bool fastclk; struct brcms_c_info *wlc = wlc_hw->wlc; - BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); - /* request FAST clock if not on */ fastclk = wlc_hw->forcefastclk; if (!fastclk) @@ -3453,7 +3448,7 @@ static void brcms_c_rate_lookup_init(struct brcms_c_info *wlc, rate = (rateset->rates[i] & BRCMS_RATE_MASK); if (rate > BRCM_MAXRATE) { - wiphy_err(wlc->wiphy, "brcms_c_rate_lookup_init: " + brcms_err(wlc->hw->d11core, "brcms_c_rate_lookup_init: " "invalid rate 0x%X in rate set\n", rateset->rates[i]); continue; @@ -3529,7 +3524,6 @@ static void brcms_c_bandinit_ordered(struct brcms_c_info *wlc, uint parkband; uint i, band_order[2]; - BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit); /* * We might have been bandlocked during down and the chip * power-cycled (hibernate). Figure out the right band to park on @@ -3710,8 +3704,8 @@ static void brcms_c_set_ratetable(struct brcms_c_info *wlc) /* band-specific init */ static void brcms_c_bsinit(struct brcms_c_info *wlc) { - BCMMSG(wlc->wiphy, "wl%d: bandunit %d\n", - wlc->pub->unit, wlc->band->bandunit); + brcms_dbg_info(wlc->hw->d11core, "wl%d: bandunit %d\n", + wlc->pub->unit, wlc->band->bandunit); /* write ucode ACK/CTS rate table */ brcms_c_set_ratetable(wlc); @@ -3734,7 +3728,8 @@ brcms_c_duty_cycle_set(struct brcms_c_info *wlc, int duty_cycle, bool isOFDM, isOFDM ? M_TX_IDLE_BUSY_RATIO_X_16_OFDM : M_TX_IDLE_BUSY_RATIO_X_16_CCK; if (duty_cycle > 100 || duty_cycle < 0) { - wiphy_err(wlc->wiphy, "wl%d: duty cycle value off limit\n", + brcms_err(wlc->hw->d11core, + "wl%d: duty cycle value off limit\n", wlc->pub->unit); return -EINVAL; } @@ -3752,40 +3747,6 @@ brcms_c_duty_cycle_set(struct brcms_c_info *wlc, int duty_cycle, bool isOFDM, return 0; } -/* - * Initialize the base precedence map for dequeueing - * from txq based on WME settings - */ -static void brcms_c_tx_prec_map_init(struct brcms_c_info *wlc) -{ - wlc->tx_prec_map = BRCMS_PREC_BMP_ALL; - memset(wlc->fifo2prec_map, 0, NFIFO * sizeof(u16)); - - wlc->fifo2prec_map[TX_AC_BK_FIFO] = BRCMS_PREC_BMP_AC_BK; - wlc->fifo2prec_map[TX_AC_BE_FIFO] = BRCMS_PREC_BMP_AC_BE; - wlc->fifo2prec_map[TX_AC_VI_FIFO] = BRCMS_PREC_BMP_AC_VI; - wlc->fifo2prec_map[TX_AC_VO_FIFO] = BRCMS_PREC_BMP_AC_VO; -} - -static void -brcms_c_txflowcontrol_signal(struct brcms_c_info *wlc, - struct brcms_txq_info *qi, bool on, int prio) -{ - /* transmit flowcontrol is not yet implemented */ -} - -static void brcms_c_txflowcontrol_reset(struct brcms_c_info *wlc) -{ - struct brcms_txq_info *qi; - - for (qi = wlc->tx_queues; qi != NULL; qi = qi->next) { - if (qi->stopped) { - brcms_c_txflowcontrol_signal(wlc, qi, OFF, ALLPRIO); - qi->stopped = 0; - } - } -} - /* push sw hps and wake state through hardware */ static void brcms_c_set_ps_ctrl(struct brcms_c_info *wlc) { @@ -3795,7 +3756,8 @@ static void brcms_c_set_ps_ctrl(struct brcms_c_info *wlc) hps = brcms_c_ps_allowed(wlc); - BCMMSG(wlc->wiphy, "wl%d: hps %d\n", wlc->pub->unit, hps); + brcms_dbg_mac80211(wlc->hw->d11core, "wl%d: hps %d\n", wlc->pub->unit, + hps); v1 = bcma_read32(wlc->hw->d11core, D11REGOFFS(maccontrol)); v2 = MCTL_WAKE; @@ -3881,7 +3843,8 @@ brcms_b_set_chanspec(struct brcms_hardware *wlc_hw, u16 chanspec, { uint bandunit; - BCMMSG(wlc_hw->wlc->wiphy, "wl%d: 0x%x\n", wlc_hw->unit, chanspec); + brcms_dbg_mac80211(wlc_hw->d11core, "wl%d: 0x%x\n", wlc_hw->unit, + chanspec); wlc_hw->chanspec = chanspec; @@ -3942,7 +3905,7 @@ static void brcms_c_set_chanspec(struct brcms_c_info *wlc, u16 chanspec) u16 old_chanspec = wlc->chanspec; if (!brcms_c_valid_chanspec_db(wlc->cmi, chanspec)) { - wiphy_err(wlc->wiphy, "wl%d: %s: Bad channel %d\n", + brcms_err(wlc->hw->d11core, "wl%d: %s: Bad channel %d\n", wlc->pub->unit, __func__, CHSPEC_CHANNEL(chanspec)); return; } @@ -3953,8 +3916,8 @@ static void brcms_c_set_chanspec(struct brcms_c_info *wlc, u16 chanspec) if (wlc->band->bandunit != bandunit || wlc->bandinit_pending) { switchband = true; if (wlc->bandlocked) { - wiphy_err(wlc->wiphy, "wl%d: %s: chspec %d " - "band is locked!\n", + brcms_err(wlc->hw->d11core, + "wl%d: %s: chspec %d band is locked!\n", wlc->pub->unit, __func__, CHSPEC_CHANNEL(chanspec)); return; @@ -4018,6 +3981,10 @@ void brcms_c_beacon_phytxctl_txant_upd(struct brcms_c_info *wlc, */ void brcms_c_protection_upd(struct brcms_c_info *wlc, uint idx, int val) { + /* + * Cannot use brcms_dbg_* here because this function is called + * before wlc is sufficiently initialized. + */ BCMMSG(wlc->wiphy, "idx %d, val %d\n", idx, val); switch (idx) { @@ -4090,8 +4057,8 @@ void brcms_c_wme_setparams(struct brcms_c_info *wlc, u16 aci, /* Only apply params if the core is out of reset and has clocks */ if (!wlc->clk) { - wiphy_err(wlc->wiphy, "wl%d: %s : no-clock\n", wlc->pub->unit, - __func__); + brcms_err(wlc->hw->d11core, "wl%d: %s : no-clock\n", + wlc->pub->unit, __func__); return; } @@ -4109,7 +4076,7 @@ void brcms_c_wme_setparams(struct brcms_c_info *wlc, u16 aci, if (acp_shm.aifs < EDCF_AIFSN_MIN || acp_shm.aifs > EDCF_AIFSN_MAX) { - wiphy_err(wlc->wiphy, "wl%d: edcf_setparams: bad " + brcms_err(wlc->hw->d11core, "wl%d: edcf_setparams: bad " "aifs %d\n", wlc->pub->unit, acp_shm.aifs); } else { acp_shm.cwmin = params->cw_min; @@ -4224,8 +4191,8 @@ static void brcms_c_radio_timer(void *arg) struct brcms_c_info *wlc = (struct brcms_c_info *) arg; if (brcms_deviceremoved(wlc)) { - wiphy_err(wlc->wiphy, "wl%d: %s: dead chip\n", wlc->pub->unit, - __func__); + brcms_err(wlc->hw->d11core, "wl%d: %s: dead chip\n", + wlc->pub->unit, __func__); brcms_down(wlc->wl); return; } @@ -4238,8 +4205,6 @@ static void brcms_b_watchdog(struct brcms_c_info *wlc) { struct brcms_hardware *wlc_hw = wlc->hw; - BCMMSG(wlc->wiphy, "wl%d\n", wlc_hw->unit); - if (!wlc_hw->up) return; @@ -4258,14 +4223,14 @@ static void brcms_b_watchdog(struct brcms_c_info *wlc) /* common watchdog code */ static void brcms_c_watchdog(struct brcms_c_info *wlc) { - BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit); + brcms_dbg_info(wlc->hw->d11core, "wl%d\n", wlc->pub->unit); if (!wlc->pub->up) return; if (brcms_deviceremoved(wlc)) { - wiphy_err(wlc->wiphy, "wl%d: %s: dead chip\n", wlc->pub->unit, - __func__); + brcms_err(wlc->hw->d11core, "wl%d: %s: dead chip\n", + wlc->pub->unit, __func__); brcms_down(wlc->wl); return; } @@ -4437,13 +4402,13 @@ static int brcms_b_attach(struct brcms_c_info *wlc, struct bcma_device *core, struct ssb_sprom *sprom = &core->bus->sprom; if (core->bus->hosttype == BCMA_HOSTTYPE_PCI) - BCMMSG(wlc->wiphy, "wl%d: vendor 0x%x device 0x%x\n", unit, - pcidev->vendor, - pcidev->device); + brcms_dbg_info(core, "wl%d: vendor 0x%x device 0x%x\n", unit, + pcidev->vendor, + pcidev->device); else - BCMMSG(wlc->wiphy, "wl%d: vendor 0x%x device 0x%x\n", unit, - core->bus->boardinfo.vendor, - core->bus->boardinfo.type); + brcms_dbg_info(core, "wl%d: vendor 0x%x device 0x%x\n", unit, + core->bus->boardinfo.vendor, + core->bus->boardinfo.type); wme = true; @@ -4715,8 +4680,9 @@ static int brcms_b_attach(struct brcms_c_info *wlc, struct bcma_device *core, goto fail; } - BCMMSG(wlc->wiphy, "deviceid 0x%x nbands %d board 0x%x\n", - wlc_hw->deviceid, wlc_hw->_nbands, ai_get_boardtype(wlc_hw->sih)); + brcms_dbg_info(wlc_hw->d11core, "deviceid 0x%x nbands %d board 0x%x\n", + wlc_hw->deviceid, wlc_hw->_nbands, + ai_get_boardtype(wlc_hw->sih)); return err; @@ -4836,56 +4802,6 @@ static void brcms_c_bss_default_init(struct brcms_c_info *wlc) bi->flags |= BRCMS_BSS_HT; } -static struct brcms_txq_info *brcms_c_txq_alloc(struct brcms_c_info *wlc) -{ - struct brcms_txq_info *qi, *p; - - qi = kzalloc(sizeof(struct brcms_txq_info), GFP_ATOMIC); - if (qi != NULL) { - /* - * Have enough room for control packets along with HI watermark - * Also, add room to txq for total psq packets if all the SCBs - * leave PS mode. The watermark for flowcontrol to OS packets - * will remain the same - */ - brcmu_pktq_init(&qi->q, BRCMS_PREC_COUNT, - 2 * BRCMS_DATAHIWAT + PKTQ_LEN_DEFAULT); - - /* add this queue to the the global list */ - p = wlc->tx_queues; - if (p == NULL) { - wlc->tx_queues = qi; - } else { - while (p->next != NULL) - p = p->next; - p->next = qi; - } - } - return qi; -} - -static void brcms_c_txq_free(struct brcms_c_info *wlc, - struct brcms_txq_info *qi) -{ - struct brcms_txq_info *p; - - if (qi == NULL) - return; - - /* remove the queue from the linked list */ - p = wlc->tx_queues; - if (p == qi) - wlc->tx_queues = p->next; - else { - while (p != NULL && p->next != qi) - p = p->next; - if (p != NULL) - p->next = p->next->next; - } - - kfree(qi); -} - static void brcms_c_update_mimo_band_bwcap(struct brcms_c_info *wlc, u8 bwcap) { uint i; @@ -4991,8 +4907,6 @@ uint brcms_c_detach(struct brcms_c_info *wlc) if (wlc == NULL) return 0; - BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit); - callbacks += brcms_b_detach(wlc); /* delete software timers */ @@ -5005,10 +4919,6 @@ uint brcms_c_detach(struct brcms_c_info *wlc) brcms_c_detach_module(wlc); - - while (wlc->tx_queues != NULL) - brcms_c_txq_free(wlc, wlc->tx_queues); - brcms_c_detach_mfree(wlc); return callbacks; } @@ -5026,7 +4936,7 @@ static void brcms_b_hw_up(struct brcms_hardware *wlc_hw) if (wlc_hw->wlc->pub->hw_up) return; - BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); + brcms_dbg_info(wlc_hw->d11core, "wl%d\n", wlc_hw->unit); /* * Enable pll and xtal, initialize the power control registers, @@ -5063,7 +4973,7 @@ static void brcms_b_hw_up(struct brcms_hardware *wlc_hw) static int brcms_b_up_prep(struct brcms_hardware *wlc_hw) { - BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); + brcms_dbg_info(wlc_hw->d11core, "wl%d\n", wlc_hw->unit); /* * Enable pll and xtal, initialize the power control registers, @@ -5102,8 +5012,6 @@ static int brcms_b_up_prep(struct brcms_hardware *wlc_hw) static int brcms_b_up_finish(struct brcms_hardware *wlc_hw) { - BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); - wlc_hw->up = true; wlc_phy_hw_state_upd(wlc_hw->band->pi, true); @@ -5135,7 +5043,7 @@ int brcms_c_up(struct brcms_c_info *wlc) { struct ieee80211_channel *ch; - BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit); + brcms_dbg_info(wlc->hw->d11core, "wl%d\n", wlc->pub->unit); /* HW is turned off so don't try to access it */ if (wlc->pub->hw_off || brcms_deviceremoved(wlc)) @@ -5176,8 +5084,8 @@ int brcms_c_up(struct brcms_c_info *wlc) WL_RADIO_HW_DISABLE); if (bsscfg->enable && bsscfg->BSS) - wiphy_err(wlc->wiphy, "wl%d: up" - ": rfdisable -> " + brcms_err(wlc->hw->d11core, + "wl%d: up: rfdisable -> " "bsscfg_disable()\n", wlc->pub->unit); } @@ -5237,8 +5145,6 @@ static int brcms_b_bmac_down_prep(struct brcms_hardware *wlc_hw) bool dev_gone; uint callbacks = 0; - BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); - if (!wlc_hw->up) return callbacks; @@ -5265,8 +5171,6 @@ static int brcms_b_down_finish(struct brcms_hardware *wlc_hw) uint callbacks = 0; bool dev_gone; - BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); - if (!wlc_hw->up) return callbacks; @@ -5314,14 +5218,14 @@ uint brcms_c_down(struct brcms_c_info *wlc) uint callbacks = 0; int i; bool dev_gone = false; - struct brcms_txq_info *qi; - BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit); + brcms_dbg_info(wlc->hw->d11core, "wl%d\n", wlc->pub->unit); /* check if we are already in the going down path */ if (wlc->going_down) { - wiphy_err(wlc->wiphy, "wl%d: %s: Driver going down so return" - "\n", wlc->pub->unit, __func__); + brcms_err(wlc->hw->d11core, + "wl%d: %s: Driver going down so return\n", + wlc->pub->unit, __func__); return 0; } if (!wlc->pub->up) @@ -5353,13 +5257,6 @@ uint brcms_c_down(struct brcms_c_info *wlc) wlc_phy_mute_upd(wlc->band->pi, false, PHY_MUTE_ALL); - /* clear txq flow control */ - brcms_c_txflowcontrol_reset(wlc); - - /* flush tx queues */ - for (qi = wlc->tx_queues; qi != NULL; qi = qi->next) - brcmu_pktq_flush(&qi->q, true, NULL, NULL); - callbacks += brcms_b_down_finish(wlc->hw); /* brcms_b_down_finish has done brcms_c_coredisable(). so clk is off */ @@ -5441,7 +5338,7 @@ int brcms_c_set_gmode(struct brcms_c_info *wlc, u8 gmode, bool config) default: /* Error */ - wiphy_err(wlc->wiphy, "wl%d: %s: invalid gmode %d\n", + brcms_err(wlc->hw->d11core, "wl%d: %s: invalid gmode %d\n", wlc->pub->unit, __func__, gmode); return -ENOTSUPP; } @@ -5745,45 +5642,6 @@ int brcms_c_module_unregister(struct brcms_pub *pub, const char *name, return -ENODATA; } -void brcms_c_print_txstatus(struct tx_status *txs) -{ - pr_debug("\ntxpkt (MPDU) Complete\n"); - - pr_debug("FrameID: %04x TxStatus: %04x\n", txs->frameid, txs->status); - - pr_debug("[15:12] %d frame attempts\n", - (txs->status & TX_STATUS_FRM_RTX_MASK) >> - TX_STATUS_FRM_RTX_SHIFT); - pr_debug(" [11:8] %d rts attempts\n", - (txs->status & TX_STATUS_RTS_RTX_MASK) >> - TX_STATUS_RTS_RTX_SHIFT); - pr_debug(" [7] %d PM mode indicated\n", - txs->status & TX_STATUS_PMINDCTD ? 1 : 0); - pr_debug(" [6] %d intermediate status\n", - txs->status & TX_STATUS_INTERMEDIATE ? 1 : 0); - pr_debug(" [5] %d AMPDU\n", - txs->status & TX_STATUS_AMPDU ? 1 : 0); - pr_debug(" [4:2] %d Frame Suppressed Reason (%s)\n", - (txs->status & TX_STATUS_SUPR_MASK) >> TX_STATUS_SUPR_SHIFT, - (const char *[]) { - "None", - "PMQ Entry", - "Flush request", - "Previous frag failure", - "Channel mismatch", - "Lifetime Expiry", - "Underflow" - } [(txs->status & TX_STATUS_SUPR_MASK) >> - TX_STATUS_SUPR_SHIFT]); - pr_debug(" [1] %d acked\n", - txs->status & TX_STATUS_ACK_RCV ? 1 : 0); - - pr_debug("LastTxTime: %04x Seq: %04x PHYTxStatus: %04x RxAckRSSI: %04x RxAckSQ: %04x\n", - txs->lasttxtime, txs->sequence, txs->phyerr, - (txs->ackphyrxsh & PRXS1_JSSI_MASK) >> PRXS1_JSSI_SHIFT, - (txs->ackphyrxsh & PRXS1_SQ_MASK) >> PRXS1_SQ_SHIFT); -} - static bool brcms_c_chipmatch_pci(struct bcma_device *core) { struct pci_dev *pcidev = core->bus->host_pci; @@ -5832,184 +5690,6 @@ bool brcms_c_chipmatch(struct bcma_device *core) } } -#if defined(DEBUG) -void brcms_c_print_txdesc(struct d11txh *txh) -{ - u16 mtcl = le16_to_cpu(txh->MacTxControlLow); - u16 mtch = le16_to_cpu(txh->MacTxControlHigh); - u16 mfc = le16_to_cpu(txh->MacFrameControl); - u16 tfest = le16_to_cpu(txh->TxFesTimeNormal); - u16 ptcw = le16_to_cpu(txh->PhyTxControlWord); - u16 ptcw_1 = le16_to_cpu(txh->PhyTxControlWord_1); - u16 ptcw_1_Fbr = le16_to_cpu(txh->PhyTxControlWord_1_Fbr); - u16 ptcw_1_Rts = le16_to_cpu(txh->PhyTxControlWord_1_Rts); - u16 ptcw_1_FbrRts = le16_to_cpu(txh->PhyTxControlWord_1_FbrRts); - u16 mainrates = le16_to_cpu(txh->MainRates); - u16 xtraft = le16_to_cpu(txh->XtraFrameTypes); - u8 *iv = txh->IV; - u8 *ra = txh->TxFrameRA; - u16 tfestfb = le16_to_cpu(txh->TxFesTimeFallback); - u8 *rtspfb = txh->RTSPLCPFallback; - u16 rtsdfb = le16_to_cpu(txh->RTSDurFallback); - u8 *fragpfb = txh->FragPLCPFallback; - u16 fragdfb = le16_to_cpu(txh->FragDurFallback); - u16 mmodelen = le16_to_cpu(txh->MModeLen); - u16 mmodefbrlen = le16_to_cpu(txh->MModeFbrLen); - u16 tfid = le16_to_cpu(txh->TxFrameID); - u16 txs = le16_to_cpu(txh->TxStatus); - u16 mnmpdu = le16_to_cpu(txh->MaxNMpdus); - u16 mabyte = le16_to_cpu(txh->MaxABytes_MRT); - u16 mabyte_f = le16_to_cpu(txh->MaxABytes_FBR); - u16 mmbyte = le16_to_cpu(txh->MinMBytes); - - u8 *rtsph = txh->RTSPhyHeader; - struct ieee80211_rts rts = txh->rts_frame; - - /* add plcp header along with txh descriptor */ - brcmu_dbg_hex_dump(txh, sizeof(struct d11txh) + 48, - "Raw TxDesc + plcp header:\n"); - - pr_debug("TxCtlLow: %04x ", mtcl); - pr_debug("TxCtlHigh: %04x ", mtch); - pr_debug("FC: %04x ", mfc); - pr_debug("FES Time: %04x\n", tfest); - pr_debug("PhyCtl: %04x%s ", ptcw, - (ptcw & PHY_TXC_SHORT_HDR) ? " short" : ""); - pr_debug("PhyCtl_1: %04x ", ptcw_1); - pr_debug("PhyCtl_1_Fbr: %04x\n", ptcw_1_Fbr); - pr_debug("PhyCtl_1_Rts: %04x ", ptcw_1_Rts); - pr_debug("PhyCtl_1_Fbr_Rts: %04x\n", ptcw_1_FbrRts); - pr_debug("MainRates: %04x ", mainrates); - pr_debug("XtraFrameTypes: %04x ", xtraft); - pr_debug("\n"); - - print_hex_dump_bytes("SecIV:", DUMP_PREFIX_OFFSET, iv, sizeof(txh->IV)); - print_hex_dump_bytes("RA:", DUMP_PREFIX_OFFSET, - ra, sizeof(txh->TxFrameRA)); - - pr_debug("Fb FES Time: %04x ", tfestfb); - print_hex_dump_bytes("Fb RTS PLCP:", DUMP_PREFIX_OFFSET, - rtspfb, sizeof(txh->RTSPLCPFallback)); - pr_debug("RTS DUR: %04x ", rtsdfb); - print_hex_dump_bytes("PLCP:", DUMP_PREFIX_OFFSET, - fragpfb, sizeof(txh->FragPLCPFallback)); - pr_debug("DUR: %04x", fragdfb); - pr_debug("\n"); - - pr_debug("MModeLen: %04x ", mmodelen); - pr_debug("MModeFbrLen: %04x\n", mmodefbrlen); - - pr_debug("FrameID: %04x\n", tfid); - pr_debug("TxStatus: %04x\n", txs); - - pr_debug("MaxNumMpdu: %04x\n", mnmpdu); - pr_debug("MaxAggbyte: %04x\n", mabyte); - pr_debug("MaxAggbyte_fb: %04x\n", mabyte_f); - pr_debug("MinByte: %04x\n", mmbyte); - - print_hex_dump_bytes("RTS PLCP:", DUMP_PREFIX_OFFSET, - rtsph, sizeof(txh->RTSPhyHeader)); - print_hex_dump_bytes("RTS Frame:", DUMP_PREFIX_OFFSET, - (u8 *)&rts, sizeof(txh->rts_frame)); - pr_debug("\n"); -} -#endif /* defined(DEBUG) */ - -#if defined(DEBUG) -static int -brcms_c_format_flags(const struct brcms_c_bit_desc *bd, u32 flags, char *buf, - int len) -{ - int i; - char *p = buf; - char hexstr[16]; - int slen = 0, nlen = 0; - u32 bit; - const char *name; - - if (len < 2 || !buf) - return 0; - - buf[0] = '\0'; - - for (i = 0; flags != 0; i++) { - bit = bd[i].bit; - name = bd[i].name; - if (bit == 0 && flags != 0) { - /* print any unnamed bits */ - snprintf(hexstr, 16, "0x%X", flags); - name = hexstr; - flags = 0; /* exit loop */ - } else if ((flags & bit) == 0) - continue; - flags &= ~bit; - nlen = strlen(name); - slen += nlen; - /* count btwn flag space */ - if (flags != 0) - slen += 1; - /* need NULL char as well */ - if (len <= slen) - break; - /* copy NULL char but don't count it */ - strncpy(p, name, nlen + 1); - p += nlen; - /* copy btwn flag space and NULL char */ - if (flags != 0) - p += snprintf(p, 2, " "); - len -= slen; - } - - /* indicate the str was too short */ - if (flags != 0) { - if (len < 2) - p -= 2 - len; /* overwrite last char */ - p += snprintf(p, 2, ">"); - } - - return (int)(p - buf); -} -#endif /* defined(DEBUG) */ - -#if defined(DEBUG) -void brcms_c_print_rxh(struct d11rxhdr *rxh) -{ - u16 len = rxh->RxFrameSize; - u16 phystatus_0 = rxh->PhyRxStatus_0; - u16 phystatus_1 = rxh->PhyRxStatus_1; - u16 phystatus_2 = rxh->PhyRxStatus_2; - u16 phystatus_3 = rxh->PhyRxStatus_3; - u16 macstatus1 = rxh->RxStatus1; - u16 macstatus2 = rxh->RxStatus2; - char flagstr[64]; - char lenbuf[20]; - static const struct brcms_c_bit_desc macstat_flags[] = { - {RXS_FCSERR, "FCSErr"}, - {RXS_RESPFRAMETX, "Reply"}, - {RXS_PBPRES, "PADDING"}, - {RXS_DECATMPT, "DeCr"}, - {RXS_DECERR, "DeCrErr"}, - {RXS_BCNSENT, "Bcn"}, - {0, NULL} - }; - - brcmu_dbg_hex_dump(rxh, sizeof(struct d11rxhdr), "Raw RxDesc:\n"); - - brcms_c_format_flags(macstat_flags, macstatus1, flagstr, 64); - - snprintf(lenbuf, sizeof(lenbuf), "0x%x", len); - - pr_debug("RxFrameSize: %6s (%d)%s\n", lenbuf, len, - (rxh->PhyRxStatus_0 & PRXS0_SHORTH) ? " short preamble" : ""); - pr_debug("RxPHYStatus: %04x %04x %04x %04x\n", - phystatus_0, phystatus_1, phystatus_2, phystatus_3); - pr_debug("RxMACStatus: %x %s\n", macstatus1, flagstr); - pr_debug("RXMACaggtype: %x\n", - (macstatus2 & RXS_AGGTYPE_MASK)); - pr_debug("RxTSFTime: %04x\n", rxh->RxTSFTime); -} -#endif /* defined(DEBUG) */ - u16 brcms_b_rate_shm_offset(struct brcms_hardware *wlc_hw, u8 rate) { u16 table_ptr; @@ -6033,86 +5713,6 @@ u16 brcms_b_rate_shm_offset(struct brcms_hardware *wlc_hw, u8 rate) return 2 * brcms_b_read_shm(wlc_hw, table_ptr + (index * 2)); } -static bool -brcms_c_prec_enq_head(struct brcms_c_info *wlc, struct pktq *q, - struct sk_buff *pkt, int prec, bool head) -{ - struct sk_buff *p; - int eprec = -1; /* precedence to evict from */ - - /* Determine precedence from which to evict packet, if any */ - if (pktq_pfull(q, prec)) - eprec = prec; - else if (pktq_full(q)) { - p = brcmu_pktq_peek_tail(q, &eprec); - if (eprec > prec) { - wiphy_err(wlc->wiphy, "%s: Failing: eprec %d > prec %d" - "\n", __func__, eprec, prec); - return false; - } - } - - /* Evict if needed */ - if (eprec >= 0) { - bool discard_oldest; - - discard_oldest = ac_bitmap_tst(0, eprec); - - /* Refuse newer packet unless configured to discard oldest */ - if (eprec == prec && !discard_oldest) { - wiphy_err(wlc->wiphy, "%s: No where to go, prec == %d" - "\n", __func__, prec); - return false; - } - - /* Evict packet according to discard policy */ - p = discard_oldest ? brcmu_pktq_pdeq(q, eprec) : - brcmu_pktq_pdeq_tail(q, eprec); - brcmu_pkt_buf_free_skb(p); - } - - /* Enqueue */ - if (head) - p = brcmu_pktq_penq_head(q, prec, pkt); - else - p = brcmu_pktq_penq(q, prec, pkt); - - return true; -} - -/* - * Attempts to queue a packet onto a multiple-precedence queue, - * if necessary evicting a lower precedence packet from the queue. - * - * 'prec' is the precedence number that has already been mapped - * from the packet priority. - * - * Returns true if packet consumed (queued), false if not. - */ -static bool brcms_c_prec_enq(struct brcms_c_info *wlc, struct pktq *q, - struct sk_buff *pkt, int prec) -{ - return brcms_c_prec_enq_head(wlc, q, pkt, prec, false); -} - -void brcms_c_txq_enq(struct brcms_c_info *wlc, struct scb *scb, - struct sk_buff *sdu, uint prec) -{ - struct brcms_txq_info *qi = wlc->pkt_queue; /* Check me */ - struct pktq *q = &qi->q; - int prio; - - prio = sdu->priority; - - if (!brcms_c_prec_enq(wlc, q, sdu, prec)) { - /* - * we might hit this condtion in case - * packet flooding from mac80211 stack - */ - brcmu_pkt_buf_free_skb(sdu); - } -} - /* * bcmc_fid_generate: * Generate frame ID for a BCMC packet. The frag field is not used @@ -6140,8 +5740,6 @@ brcms_c_calc_ack_time(struct brcms_c_info *wlc, u32 rspec, { uint dur = 0; - BCMMSG(wlc->wiphy, "wl%d: rspec 0x%x, preamble_type %d\n", - wlc->pub->unit, rspec, preamble_type); /* * Spec 9.6: ack rate is the highest rate in BSSBasicRateSet that * is less than or equal to the rate of the immediately previous @@ -6159,8 +5757,6 @@ static uint brcms_c_calc_cts_time(struct brcms_c_info *wlc, u32 rspec, u8 preamble_type) { - BCMMSG(wlc->wiphy, "wl%d: ratespec 0x%x, preamble_type %d\n", - wlc->pub->unit, rspec, preamble_type); return brcms_c_calc_ack_time(wlc, rspec, preamble_type); } @@ -6168,8 +5764,6 @@ static uint brcms_c_calc_ba_time(struct brcms_c_info *wlc, u32 rspec, u8 preamble_type) { - BCMMSG(wlc->wiphy, "wl%d: rspec 0x%x, " - "preamble_type %d\n", wlc->pub->unit, rspec, preamble_type); /* * Spec 9.6: ack rate is the highest rate in BSSBasicRateSet that * is less than or equal to the rate of the immediately previous @@ -6223,9 +5817,6 @@ brcms_c_calc_frame_len(struct brcms_c_info *wlc, u32 ratespec, uint nsyms, mac_len, Ndps, kNdps; uint rate = rspec2rate(ratespec); - BCMMSG(wlc->wiphy, "wl%d: rspec 0x%x, preamble_type %d, dur %d\n", - wlc->pub->unit, ratespec, preamble_type, dur); - if (is_mcs_rate(ratespec)) { uint mcs = ratespec & RSPEC_RATE_MASK; int tot_streams = mcs_2_txstreams(mcs) + rspec_stc(ratespec); @@ -6292,7 +5883,7 @@ static bool brcms_c_valid_rate(struct brcms_c_info *wlc, u32 rspec, int band, return true; error: if (verbose) - wiphy_err(wlc->wiphy, "wl%d: valid_rate: rate spec 0x%x " + brcms_err(wlc->hw->d11core, "wl%d: valid_rate: rate spec 0x%x " "not in hw_rateset\n", wlc->pub->unit, rspec); return false; @@ -6302,6 +5893,7 @@ static u32 mac80211_wlc_set_nrate(struct brcms_c_info *wlc, struct brcms_band *cur_band, u32 int_val) { + struct bcma_device *core = wlc->hw->d11core; u8 stf = (int_val & NRATE_STF_MASK) >> NRATE_STF_SHIFT; u8 rate = int_val & NRATE_RATE_MASK; u32 rspec; @@ -6318,7 +5910,7 @@ mac80211_wlc_set_nrate(struct brcms_c_info *wlc, struct brcms_band *cur_band, if ((wlc->pub->_n_enab & SUPPORT_11N) && ismcs) { /* mcs only allowed when nmode */ if (stf > PHY_TXC1_MODE_SDM) { - wiphy_err(wlc->wiphy, "wl%d: %s: Invalid stf\n", + brcms_err(core, "wl%d: %s: Invalid stf\n", wlc->pub->unit, __func__); bcmerror = -EINVAL; goto done; @@ -6329,8 +5921,8 @@ mac80211_wlc_set_nrate(struct brcms_c_info *wlc, struct brcms_band *cur_band, if (!CHSPEC_IS40(wlc->home_chanspec) || ((stf != PHY_TXC1_MODE_SISO) && (stf != PHY_TXC1_MODE_CDD))) { - wiphy_err(wlc->wiphy, "wl%d: %s: Invalid mcs " - "32\n", wlc->pub->unit, __func__); + brcms_err(core, "wl%d: %s: Invalid mcs 32\n", + wlc->pub->unit, __func__); bcmerror = -EINVAL; goto done; } @@ -6338,9 +5930,9 @@ mac80211_wlc_set_nrate(struct brcms_c_info *wlc, struct brcms_band *cur_band, } else if (rate > HIGHEST_SINGLE_STREAM_MCS) { /* mcs > 7 must use stf SDM */ if (stf != PHY_TXC1_MODE_SDM) { - BCMMSG(wlc->wiphy, "wl%d: enabling " - "SDM mode for mcs %d\n", - wlc->pub->unit, rate); + brcms_dbg_mac80211(core, "wl%d: enabling " + "SDM mode for mcs %d\n", + wlc->pub->unit, rate); stf = PHY_TXC1_MODE_SDM; } } else { @@ -6351,15 +5943,15 @@ mac80211_wlc_set_nrate(struct brcms_c_info *wlc, struct brcms_band *cur_band, if ((stf > PHY_TXC1_MODE_STBC) || (!BRCMS_STBC_CAP_PHY(wlc) && (stf == PHY_TXC1_MODE_STBC))) { - wiphy_err(wlc->wiphy, "wl%d: %s: Invalid STBC" - "\n", wlc->pub->unit, __func__); + brcms_err(core, "wl%d: %s: Invalid STBC\n", + wlc->pub->unit, __func__); bcmerror = -EINVAL; goto done; } } } else if (is_ofdm_rate(rate)) { if ((stf != PHY_TXC1_MODE_CDD) && (stf != PHY_TXC1_MODE_SISO)) { - wiphy_err(wlc->wiphy, "wl%d: %s: Invalid OFDM\n", + brcms_err(core, "wl%d: %s: Invalid OFDM\n", wlc->pub->unit, __func__); bcmerror = -EINVAL; goto done; @@ -6367,20 +5959,20 @@ mac80211_wlc_set_nrate(struct brcms_c_info *wlc, struct brcms_band *cur_band, } else if (is_cck_rate(rate)) { if ((cur_band->bandtype != BRCM_BAND_2G) || (stf != PHY_TXC1_MODE_SISO)) { - wiphy_err(wlc->wiphy, "wl%d: %s: Invalid CCK\n", + brcms_err(core, "wl%d: %s: Invalid CCK\n", wlc->pub->unit, __func__); bcmerror = -EINVAL; goto done; } } else { - wiphy_err(wlc->wiphy, "wl%d: %s: Unknown rate type\n", + brcms_err(core, "wl%d: %s: Unknown rate type\n", wlc->pub->unit, __func__); bcmerror = -EINVAL; goto done; } /* make sure multiple antennae are available for non-siso rates */ if ((stf != PHY_TXC1_MODE_SISO) && (wlc->stf->txstreams == 1)) { - wiphy_err(wlc->wiphy, "wl%d: %s: SISO antenna but !SISO " + brcms_err(core, "wl%d: %s: SISO antenna but !SISO " "request\n", wlc->pub->unit, __func__); bcmerror = -EINVAL; goto done; @@ -6449,7 +6041,7 @@ static void brcms_c_cck_plcp_set(struct brcms_c_info *wlc, int rate_500, break; default: - wiphy_err(wlc->wiphy, + brcms_err(wlc->hw->d11core, "brcms_c_cck_plcp_set: unsupported rate %d\n", rate_500); rate_500 = BRCM_RATE_1M; @@ -6582,7 +6174,7 @@ static u16 brcms_c_phytxctl1_calc(struct brcms_c_info *wlc, u32 rspec) bw = rspec_get_bw(rspec); /* 10Mhz is not supported yet */ if (bw < PHY_TXC1_BW_20MHZ) { - wiphy_err(wlc->wiphy, "phytxctl1_calc: bw %d is " + brcms_err(wlc->hw->d11core, "phytxctl1_calc: bw %d is " "not supported yet, set to 20L\n", bw); bw = PHY_TXC1_BW_20MHZ; } @@ -6609,7 +6201,7 @@ static u16 brcms_c_phytxctl1_calc(struct brcms_c_info *wlc, u32 rspec) /* get the phyctl byte from rate phycfg table */ phycfg = brcms_c_rate_legacy_phyctl(rspec2rate(rspec)); if (phycfg == -1) { - wiphy_err(wlc->wiphy, "phytxctl1_calc: wrong " + brcms_err(wlc->hw->d11core, "phytxctl1_calc: wrong " "legacy OFDM/CCK rate\n"); phycfg = 0; } @@ -6689,8 +6281,9 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw, if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { /* non-AP STA should never use BCMC queue */ if (queue == TX_BCMC_FIFO) { - wiphy_err(wlc->wiphy, "wl%d: %s: ASSERT queue == " - "TX_BCMC!\n", wlc->pub->unit, __func__); + brcms_err(wlc->hw->d11core, + "wl%d: %s: ASSERT queue == TX_BCMC!\n", + wlc->pub->unit, __func__); frameid = bcmc_fid_generate(wlc, NULL, txh); } else { /* Increment the counter for first fragment */ @@ -6860,7 +6453,8 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw, if ((txrate[k]->flags & IEEE80211_TX_RC_MCS) && (!is_mcs_rate(rspec[k]))) { - wiphy_err(wlc->wiphy, "wl%d: %s: IEEE80211_TX_" + brcms_err(wlc->hw->d11core, + "wl%d: %s: IEEE80211_TX_" "RC_MCS != is_mcs_rate(rspec)\n", wlc->pub->unit, __func__); } @@ -7254,14 +6848,16 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw, wlc->fragthresh[queue] = (u16) newfragthresh; } else { - wiphy_err(wlc->wiphy, "wl%d: %s txop invalid " + brcms_err(wlc->hw->d11core, + "wl%d: %s txop invalid " "for rate %d\n", wlc->pub->unit, fifo_names[queue], rspec2rate(rspec[0])); } if (dur > wlc->edcf_txop[ac]) - wiphy_err(wlc->wiphy, "wl%d: %s: %s txop " + brcms_err(wlc->hw->d11core, + "wl%d: %s: %s txop " "exceeded phylen %d/%d dur %d/%d\n", wlc->pub->unit, __func__, fifo_names[queue], @@ -7273,79 +6869,33 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw, return 0; } -void brcms_c_sendpkt_mac80211(struct brcms_c_info *wlc, struct sk_buff *sdu, - struct ieee80211_hw *hw) +static int brcms_c_tx(struct brcms_c_info *wlc, struct sk_buff *skb) { - u8 prio; - uint fifo; - struct scb *scb = &wlc->pri_scb; - struct ieee80211_hdr *d11_header = (struct ieee80211_hdr *)(sdu->data); - - /* - * 802.11 standard requires management traffic - * to go at highest priority - */ - prio = ieee80211_is_data(d11_header->frame_control) ? sdu->priority : - MAXPRIO; - fifo = prio2fifo[prio]; - if (brcms_c_d11hdrs_mac80211(wlc, hw, sdu, scb, 0, 1, fifo, 0)) - return; - brcms_c_txq_enq(wlc, scb, sdu, BRCMS_PRIO_TO_PREC(prio)); - brcms_c_send_q(wlc); -} - -void brcms_c_send_q(struct brcms_c_info *wlc) -{ - struct sk_buff *pkt[DOT11_MAXNUMFRAGS]; - int prec; - u16 prec_map; - int err = 0, i, count; - uint fifo; - struct brcms_txq_info *qi = wlc->pkt_queue; - struct pktq *q = &qi->q; - struct ieee80211_tx_info *tx_info; + struct dma_pub *dma; + int fifo, ret = -ENOSPC; + struct d11txh *txh; + u16 frameid = INVALIDFID; - prec_map = wlc->tx_prec_map; + fifo = brcms_ac_to_fifo(skb_get_queue_mapping(skb)); + dma = wlc->hw->di[fifo]; + txh = (struct d11txh *)(skb->data); - /* Send all the enq'd pkts that we can. - * Dequeue packets with precedence with empty HW fifo only - */ - while (prec_map && (pkt[0] = brcmu_pktq_mdeq(q, prec_map, &prec))) { - tx_info = IEEE80211_SKB_CB(pkt[0]); - if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { - err = brcms_c_sendampdu(wlc->ampdu, qi, pkt, prec); - } else { - count = 1; - err = brcms_c_prep_pdu(wlc, pkt[0], &fifo); - if (!err) { - for (i = 0; i < count; i++) - brcms_c_txfifo(wlc, fifo, pkt[i], true, - 1); - } - } - - if (err == -EBUSY) { - brcmu_pktq_penq_head(q, prec, pkt[0]); - /* - * If send failed due to any other reason than a - * change in HW FIFO condition, quit. Otherwise, - * read the new prec_map! - */ - if (prec_map == wlc->tx_prec_map) - break; - prec_map = wlc->tx_prec_map; - } + if (dma->txavail == 0) { + /* + * We sometimes get a frame from mac80211 after stopping + * the queues. This only ever seems to be a single frame + * and is seems likely to be a race. TX_HEADROOM should + * ensure that we have enough space to handle these stray + * packets, so warn if there isn't. If we're out of space + * in the tx ring and the tx queue isn't stopped then + * we've really got a bug; warn loudly if that happens. + */ + brcms_warn(wlc->hw->d11core, + "Received frame for tx with no space in DMA ring\n"); + WARN_ON(!ieee80211_queue_stopped(wlc->pub->ieee_hw, + skb_get_queue_mapping(skb))); + return -ENOSPC; } -} - -void -brcms_c_txfifo(struct brcms_c_info *wlc, uint fifo, struct sk_buff *p, - bool commit, s8 txpktpend) -{ - u16 frameid = INVALIDFID; - struct d11txh *txh; - - txh = (struct d11txh *) (p->data); /* When a BC/MC frame is being committed to the BCMC fifo * via DMA (NOT PIO), update ucode or BSS info as appropriate. @@ -7353,16 +6903,6 @@ brcms_c_txfifo(struct brcms_c_info *wlc, uint fifo, struct sk_buff *p, if (fifo == TX_BCMC_FIFO) frameid = le16_to_cpu(txh->TxFrameID); - /* - * Bump up pending count for if not using rpc. If rpc is - * used, this will be handled in brcms_b_txfifo() - */ - if (commit) { - wlc->core->txpktpend[fifo] += txpktpend; - BCMMSG(wlc->wiphy, "pktpend inc %d to %d\n", - txpktpend, wlc->core->txpktpend[fifo]); - } - /* Commit BCMC sequence number in the SHM frame ID location */ if (frameid != INVALIDFID) { /* @@ -7372,8 +6912,55 @@ brcms_c_txfifo(struct brcms_c_info *wlc, uint fifo, struct sk_buff *p, brcms_b_write_shm(wlc->hw, M_BCMC_FID, frameid); } - if (dma_txfast(wlc->hw->di[fifo], p, commit) < 0) + ret = brcms_c_txfifo(wlc, fifo, skb); + /* + * The only reason for brcms_c_txfifo to fail is because + * there weren't any DMA descriptors, but we've already + * checked for that. So if it does fail yell loudly. + */ + WARN_ON_ONCE(ret); + + return ret; +} + +bool brcms_c_sendpkt_mac80211(struct brcms_c_info *wlc, struct sk_buff *sdu, + struct ieee80211_hw *hw) +{ + uint fifo; + struct scb *scb = &wlc->pri_scb; + + fifo = brcms_ac_to_fifo(skb_get_queue_mapping(sdu)); + brcms_c_d11hdrs_mac80211(wlc, hw, sdu, scb, 0, 1, fifo, 0); + if (!brcms_c_tx(wlc, sdu)) + return true; + + /* packet discarded */ + dev_kfree_skb_any(sdu); + return false; +} + +int +brcms_c_txfifo(struct brcms_c_info *wlc, uint fifo, struct sk_buff *p) +{ + struct dma_pub *dma = wlc->hw->di[fifo]; + int ret; + u16 queue; + + ret = dma_txfast(wlc, dma, p); + if (ret < 0) wiphy_err(wlc->wiphy, "txfifo: fatal, toss frames !!!\n"); + + /* + * Stop queue if DMA ring is full. Reserve some free descriptors, + * as we sometimes receive a frame from mac80211 after the queues + * are stopped. + */ + queue = skb_get_queue_mapping(p); + if (dma->txavail <= TX_HEADROOM && fifo < TX_BCMC_FIFO && + !ieee80211_queue_stopped(wlc->pub->ieee_hw, queue)) + ieee80211_stop_queue(wlc->pub->ieee_hw, queue); + + return ret; } u32 @@ -7423,19 +7010,6 @@ brcms_c_rspec_to_rts_rspec(struct brcms_c_info *wlc, u32 rspec, return rts_rspec; } -void -brcms_c_txfifo_complete(struct brcms_c_info *wlc, uint fifo, s8 txpktpend) -{ - wlc->core->txpktpend[fifo] -= txpktpend; - BCMMSG(wlc->wiphy, "pktpend dec %d to %d\n", txpktpend, - wlc->core->txpktpend[fifo]); - - /* There is more room; mark precedences related to this FIFO sendable */ - wlc->tx_prec_map |= wlc->fifo2prec_map[fifo]; - - /* figure out which bsscfg is being worked on... */ -} - /* Update beacon listen interval in shared memory */ static void brcms_c_bcn_li_upd(struct brcms_c_info *wlc) { @@ -7508,7 +7082,7 @@ prep_mac80211_status(struct brcms_c_info *wlc, struct d11rxhdr *rxh, /* fill in TSF and flag its presence */ rx_status->mactime = brcms_c_recover_tsf64(wlc, rxh); - rx_status->flag |= RX_FLAG_MACTIME_MPDU; + rx_status->flag |= RX_FLAG_MACTIME_START; channel = BRCMS_CHAN_CHANNEL(rxh->RxChan); @@ -7571,7 +7145,8 @@ prep_mac80211_status(struct brcms_c_info *wlc, struct d11rxhdr *rxh, rx_status->rate_idx = 11; break; default: - wiphy_err(wlc->wiphy, "%s: Unknown rate\n", __func__); + brcms_err(wlc->hw->d11core, + "%s: Unknown rate\n", __func__); } /* @@ -7590,7 +7165,7 @@ prep_mac80211_status(struct brcms_c_info *wlc, struct d11rxhdr *rxh, } else if (is_ofdm_rate(rspec)) { rx_status->flag |= RX_FLAG_SHORTPRE; } else { - wiphy_err(wlc->wiphy, "%s: Unknown modulation\n", + brcms_err(wlc->hw->d11core, "%s: Unknown modulation\n", __func__); } } @@ -7600,12 +7175,12 @@ prep_mac80211_status(struct brcms_c_info *wlc, struct d11rxhdr *rxh, if (rxh->RxStatus1 & RXS_DECERR) { rx_status->flag |= RX_FLAG_FAILED_PLCP_CRC; - wiphy_err(wlc->wiphy, "%s: RX_FLAG_FAILED_PLCP_CRC\n", + brcms_err(wlc->hw->d11core, "%s: RX_FLAG_FAILED_PLCP_CRC\n", __func__); } if (rxh->RxStatus1 & RXS_FCSERR) { rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; - wiphy_err(wlc->wiphy, "%s: RX_FLAG_FAILED_FCS_CRC\n", + brcms_err(wlc->hw->d11core, "%s: RX_FLAG_FAILED_FCS_CRC\n", __func__); } } @@ -7649,9 +7224,6 @@ brcms_c_calc_lsig_len(struct brcms_c_info *wlc, u32 ratespec, { uint nsyms, len = 0, kNdps; - BCMMSG(wlc->wiphy, "wl%d: rate %d, len%d\n", - wlc->pub->unit, rspec2rate(ratespec), mac_len); - if (is_mcs_rate(ratespec)) { uint mcs = ratespec & RSPEC_RATE_MASK; int tot_streams = (mcs_2_txstreams(mcs) + 1) + @@ -7883,35 +7455,6 @@ void brcms_c_update_probe_resp(struct brcms_c_info *wlc, bool suspend) brcms_c_bss_update_probe_resp(wlc, bsscfg, suspend); } -/* prepares pdu for transmission. returns BCM error codes */ -int brcms_c_prep_pdu(struct brcms_c_info *wlc, struct sk_buff *pdu, uint *fifop) -{ - uint fifo; - struct d11txh *txh; - struct ieee80211_hdr *h; - struct scb *scb; - - txh = (struct d11txh *) (pdu->data); - h = (struct ieee80211_hdr *)((u8 *) (txh + 1) + D11_PHY_HDR_LEN); - - /* get the pkt queue info. This was put at brcms_c_sendctl or - * brcms_c_send for PDU */ - fifo = le16_to_cpu(txh->TxFrameID) & TXFID_QUEUE_MASK; - - scb = NULL; - - *fifop = fifo; - - /* return if insufficient dma resources */ - if (*wlc->core->txavail[fifo] < MAX_DMA_SEGS) { - /* Mark precedences related to this FIFO, unsendable */ - /* A fifo is full. Clear precedences related to that FIFO */ - wlc->tx_prec_map &= ~(wlc->fifo2prec_map[fifo]); - return -EBUSY; - } - return 0; -} - int brcms_b_xmtfifo_sz_get(struct brcms_hardware *wlc_hw, uint fifo, uint *blocks) { @@ -7977,13 +7520,15 @@ int brcms_c_get_curband(struct brcms_c_info *wlc) void brcms_c_wait_for_tx_completion(struct brcms_c_info *wlc, bool drop) { int timeout = 20; + int i; - /* flush packet queue when requested */ - if (drop) - brcmu_pktq_flush(&wlc->pkt_queue->q, false, NULL, NULL); + /* Kick DMA to send any pending AMPDU */ + for (i = 0; i < ARRAY_SIZE(wlc->hw->di); i++) + if (wlc->hw->di[i]) + dma_txflush(wlc->hw->di[i]); /* wait for queue and DMA fifos to run dry */ - while (!pktq_empty(&wlc->pkt_queue->q) || brcms_txpktpendtot(wlc) > 0) { + while (brcms_txpktpendtot(wlc) > 0) { brcms_msleep(wlc->wl, 1); if (--timeout == 0) @@ -8032,8 +7577,6 @@ static void brcms_c_recv(struct brcms_c_info *wlc, struct sk_buff *p) uint len; bool is_amsdu; - BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit); - /* frame starts with rxhdr */ rxh = (struct d11rxhdr *) (p->data); @@ -8043,8 +7586,9 @@ static void brcms_c_recv(struct brcms_c_info *wlc, struct sk_buff *p) /* MAC inserts 2 pad bytes for a4 headers or QoS or A-MSDU subframes */ if (rxh->RxStatus1 & RXS_PBPRES) { if (p->len < 2) { - wiphy_err(wlc->wiphy, "wl%d: recv: rcvd runt of " - "len %d\n", wlc->pub->unit, p->len); + brcms_err(wlc->hw->d11core, + "wl%d: recv: rcvd runt of len %d\n", + wlc->pub->unit, p->len); goto toss; } skb_pull(p, 2); @@ -8088,17 +7632,19 @@ brcms_b_recv(struct brcms_hardware *wlc_hw, uint fifo, bool bound) uint n = 0; uint bound_limit = bound ? RXBND : -1; + bool morepending; - BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); skb_queue_head_init(&recv_frames); /* gather received frames */ - while (dma_rx(wlc_hw->di[fifo], &recv_frames)) { - + do { /* !give others some time to run! */ - if (++n >= bound_limit) + if (n >= bound_limit) break; - } + + morepending = dma_rx(wlc_hw->di[fifo], &recv_frames); + n++; + } while (morepending); /* post more rbufs */ dma_rxfill(wlc_hw->di[fifo]); @@ -8128,7 +7674,7 @@ brcms_b_recv(struct brcms_hardware *wlc_hw, uint fifo, bool bound) brcms_c_recv(wlc_hw->wlc, p); } - return n >= bound_limit; + return morepending; } /* second-level interrupt processing @@ -8140,10 +7686,9 @@ bool brcms_c_dpc(struct brcms_c_info *wlc, bool bounded) u32 macintstatus; struct brcms_hardware *wlc_hw = wlc->hw; struct bcma_device *core = wlc_hw->d11core; - struct wiphy *wiphy = wlc->wiphy; if (brcms_deviceremoved(wlc)) { - wiphy_err(wiphy, "wl%d: %s: dead chip\n", wlc_hw->unit, + brcms_err(core, "wl%d: %s: dead chip\n", wlc_hw->unit, __func__); brcms_down(wlc->wl); return false; @@ -8153,8 +7698,8 @@ bool brcms_c_dpc(struct brcms_c_info *wlc, bool bounded) macintstatus = wlc->macintstatus; wlc->macintstatus = 0; - BCMMSG(wlc->wiphy, "wl%d: macintstatus 0x%x\n", - wlc_hw->unit, macintstatus); + brcms_dbg_int(core, "wl%d: macintstatus 0x%x\n", + wlc_hw->unit, macintstatus); WARN_ON(macintstatus & MI_PRQ); /* PRQ Interrupt in non-MBSS */ @@ -8164,7 +7709,7 @@ bool brcms_c_dpc(struct brcms_c_info *wlc, bool bounded) if (brcms_b_txstatus(wlc->hw, bounded, &fatal)) wlc->macintstatus |= MI_TFS; if (fatal) { - wiphy_err(wiphy, "MI_TFS: fatal\n"); + brcms_err(core, "MI_TFS: fatal\n"); goto fatal; } } @@ -8174,7 +7719,7 @@ bool brcms_c_dpc(struct brcms_c_info *wlc, bool bounded) /* ATIM window end */ if (macintstatus & MI_ATIMWINEND) { - BCMMSG(wlc->wiphy, "end of ATIM window\n"); + brcms_dbg_info(core, "end of ATIM window\n"); bcma_set32(core, D11REGOFFS(maccommand), wlc->qvalid); wlc->qvalid = 0; } @@ -8192,7 +7737,7 @@ bool brcms_c_dpc(struct brcms_c_info *wlc, bool bounded) wlc_phy_noise_sample_intr(wlc_hw->band->pi); if (macintstatus & MI_GP0) { - wiphy_err(wiphy, "wl%d: PSM microcode watchdog fired at %d " + brcms_err(core, "wl%d: PSM microcode watchdog fired at %d " "(seconds). Resetting.\n", wlc_hw->unit, wlc_hw->now); printk_once("%s : PSM Watchdog, chipid 0x%x, chiprev 0x%x\n", @@ -8206,15 +7751,11 @@ bool brcms_c_dpc(struct brcms_c_info *wlc, bool bounded) bcma_write32(core, D11REGOFFS(gptimer), 0); if (macintstatus & MI_RFDISABLE) { - BCMMSG(wlc->wiphy, "wl%d: BMAC Detected a change on the" - " RF Disable Input\n", wlc_hw->unit); + brcms_dbg_info(core, "wl%d: BMAC Detected a change on the" + " RF Disable Input\n", wlc_hw->unit); brcms_rfkill_set_hw_state(wlc->wl); } - /* send any enq'd tx packets. Just makes sure to jump start tx */ - if (!pktq_empty(&wlc->pkt_queue->q)) - brcms_c_send_q(wlc); - /* it isn't done and needs to be resched if macintstatus is non-zero */ return wlc->macintstatus != 0; @@ -8229,7 +7770,7 @@ void brcms_c_init(struct brcms_c_info *wlc, bool mute_tx) struct ieee80211_channel *ch = wlc->pub->ieee_hw->conf.channel; u16 chanspec; - BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit); + brcms_dbg_info(core, "wl%d\n", wlc->pub->unit); chanspec = ch20mhz_chspec(ch->hw_value); @@ -8286,9 +7827,6 @@ void brcms_c_init(struct brcms_c_info *wlc, bool mute_tx) bcma_set16(core, D11REGOFFS(ifs_ctl), IFS_USEEDCF); brcms_c_edcf_setparams(wlc, false); - /* Init precedence maps for empty FIFOs */ - brcms_c_tx_prec_map_init(wlc); - /* read the ucode version if we have not yet done so */ if (wlc->ucode_rev == 0) { wlc->ucode_rev = @@ -8303,9 +7841,6 @@ void brcms_c_init(struct brcms_c_info *wlc, bool mute_tx) if (mute_tx) brcms_b_mute(wlc->hw, true); - /* clear tx flow control */ - brcms_c_txflowcontrol_reset(wlc); - /* enable the RF Disable Delay timer */ bcma_write32(core, D11REGOFFS(rfdisabledly), RFDISABLE_DEFAULT); @@ -8464,15 +7999,6 @@ brcms_c_attach(struct brcms_info *wl, struct bcma_device *core, uint unit, * Complete the wlc default state initializations.. */ - /* allocate our initial queue */ - wlc->pkt_queue = brcms_c_txq_alloc(wlc); - if (wlc->pkt_queue == NULL) { - wiphy_err(wl->wiphy, "wl%d: %s: failed to malloc tx queue\n", - unit, __func__); - err = 100; - goto fail; - } - wlc->bsscfg->wlc = wlc; wlc->mimoft = FT_HT; diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.h b/drivers/net/wireless/brcm80211/brcmsmac/main.h index 8debc74..fb44774 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/main.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/main.h @@ -101,9 +101,6 @@ #define DATA_BLOCK_TX_SUPR (1 << 4) -/* 802.1D Priority to TX FIFO number for wme */ -extern const u8 prio2fifo[]; - /* Ucode MCTL_WAKE override bits */ #define BRCMS_WAKE_OVERRIDE_CLKCTL 0x01 #define BRCMS_WAKE_OVERRIDE_PHYREG 0x02 @@ -242,7 +239,6 @@ struct brcms_core { /* fifo */ uint *txavail[NFIFO]; /* # tx descriptors available */ - s16 txpktpend[NFIFO]; /* tx admission control */ struct macstat *macstat_snapshot; /* mac hw prev read values */ }; @@ -382,19 +378,6 @@ struct brcms_hardware { */ }; -/* TX Queue information - * - * Each flow of traffic out of the device has a TX Queue with independent - * flow control. Several interfaces may be associated with a single TX Queue - * if they belong to the same flow of traffic from the device. For multi-channel - * operation there are independent TX Queues for each channel. - */ -struct brcms_txq_info { - struct brcms_txq_info *next; - struct pktq q; - uint stopped; /* tx flow control bits */ -}; - /* * Principal common driver data structure. * @@ -435,11 +418,8 @@ struct brcms_txq_info { * WDlast: last time wlc_watchdog() was called. * edcf_txop[IEEE80211_NUM_ACS]: current txop for each ac. * wme_retries: per-AC retry limits. - * tx_prec_map: Precedence map based on HW FIFO space. - * fifo2prec_map[NFIFO]: pointer to fifo2_prec map based on WME. * bsscfg: set of BSS configurations, idx 0 is default and always valid. * cfg: the primary bsscfg (can be AP or STA). - * tx_queues: common TX Queue list. * modulecb: * mimoft: SIGN or 11N. * cck_40txbw: 11N, cck tx b/w override when in 40MHZ mode. @@ -469,7 +449,6 @@ struct brcms_txq_info { * tempsense_lasttime; * tx_duty_cycle_ofdm: maximum allowed duty cycle for OFDM. * tx_duty_cycle_cck: maximum allowed duty cycle for CCK. - * pkt_queue: txq for transmit packets. * wiphy: * pri_scb: primary Station Control Block */ @@ -533,14 +512,9 @@ struct brcms_c_info { u16 edcf_txop[IEEE80211_NUM_ACS]; u16 wme_retries[IEEE80211_NUM_ACS]; - u16 tx_prec_map; - u16 fifo2prec_map[NFIFO]; struct brcms_bss_cfg *bsscfg; - /* tx queue */ - struct brcms_txq_info *tx_queues; - struct modulecb *modulecb; u8 mimoft; @@ -585,7 +559,6 @@ struct brcms_c_info { u16 tx_duty_cycle_ofdm; u16 tx_duty_cycle_cck; - struct brcms_txq_info *pkt_queue; struct wiphy *wiphy; struct scb pri_scb; }; @@ -637,30 +610,13 @@ struct brcms_bss_cfg { struct brcms_bss_info *current_bss; }; -extern void brcms_c_txfifo(struct brcms_c_info *wlc, uint fifo, - struct sk_buff *p, - bool commit, s8 txpktpend); -extern void brcms_c_txfifo_complete(struct brcms_c_info *wlc, uint fifo, - s8 txpktpend); -extern void brcms_c_txq_enq(struct brcms_c_info *wlc, struct scb *scb, - struct sk_buff *sdu, uint prec); -extern void brcms_c_print_txstatus(struct tx_status *txs); +extern int brcms_c_txfifo(struct brcms_c_info *wlc, uint fifo, + struct sk_buff *p); extern int brcms_b_xmtfifo_sz_get(struct brcms_hardware *wlc_hw, uint fifo, uint *blocks); -#if defined(DEBUG) -extern void brcms_c_print_txdesc(struct d11txh *txh); -#else -static inline void brcms_c_print_txdesc(struct d11txh *txh) -{ -} -#endif - extern int brcms_c_set_gmode(struct brcms_c_info *wlc, u8 gmode, bool config); extern void brcms_c_mac_promisc(struct brcms_c_info *wlc, uint filter_flags); -extern void brcms_c_send_q(struct brcms_c_info *wlc); -extern int brcms_c_prep_pdu(struct brcms_c_info *wlc, struct sk_buff *pdu, - uint *fifo); extern u16 brcms_c_calc_lsig_len(struct brcms_c_info *wlc, u32 ratespec, uint mac_len); extern u32 brcms_c_rspec_to_rts_rspec(struct brcms_c_info *wlc, diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c index abfd788..606b534 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c @@ -1137,8 +1137,9 @@ wlc_lcnphy_set_rx_gain_by_distribution(struct brcms_phy *pi, gain0_15 = ((biq1 & 0xf) << 12) | ((tia & 0xf) << 8) | ((lna2 & 0x3) << 6) | - ((lna2 & - 0x3) << 4) | ((lna1 & 0x3) << 2) | ((lna1 & 0x3) << 0); + ((lna2 & 0x3) << 4) | + ((lna1 & 0x3) << 2) | + ((lna1 & 0x3) << 0); mod_phy_reg(pi, 0x4b6, (0xffff << 0), gain0_15 << 0); mod_phy_reg(pi, 0x4b7, (0xf << 0), gain16_19 << 0); @@ -1156,6 +1157,8 @@ wlc_lcnphy_set_rx_gain_by_distribution(struct brcms_phy *pi, } mod_phy_reg(pi, 0x44d, (0x1 << 0), (!trsw) << 0); + mod_phy_reg(pi, 0x4b1, (0x3 << 11), lna1 << 11); + mod_phy_reg(pi, 0x4e6, (0x3 << 3), lna1 << 3); } @@ -1328,6 +1331,43 @@ static u32 wlc_lcnphy_measure_digital_power(struct brcms_phy *pi, u16 nsamples) return (iq_est.i_pwr + iq_est.q_pwr) / nsamples; } +static bool wlc_lcnphy_rx_iq_cal_gain(struct brcms_phy *pi, u16 biq1_gain, + u16 tia_gain, u16 lna2_gain) +{ + u32 i_thresh_l, q_thresh_l; + u32 i_thresh_h, q_thresh_h; + struct lcnphy_iq_est iq_est_h, iq_est_l; + + wlc_lcnphy_set_rx_gain_by_distribution(pi, 0, 0, 0, biq1_gain, tia_gain, + lna2_gain, 0); + + wlc_lcnphy_rx_gain_override_enable(pi, true); + wlc_lcnphy_start_tx_tone(pi, 2000, (40 >> 1), 0); + usleep_range(500, 500); + write_radio_reg(pi, RADIO_2064_REG112, 0); + if (!wlc_lcnphy_rx_iq_est(pi, 1024, 32, &iq_est_l)) + return false; + + wlc_lcnphy_start_tx_tone(pi, 2000, 40, 0); + usleep_range(500, 500); + write_radio_reg(pi, RADIO_2064_REG112, 0); + if (!wlc_lcnphy_rx_iq_est(pi, 1024, 32, &iq_est_h)) + return false; + + i_thresh_l = (iq_est_l.i_pwr << 1); + i_thresh_h = (iq_est_l.i_pwr << 2) + iq_est_l.i_pwr; + + q_thresh_l = (iq_est_l.q_pwr << 1); + q_thresh_h = (iq_est_l.q_pwr << 2) + iq_est_l.q_pwr; + if ((iq_est_h.i_pwr > i_thresh_l) && + (iq_est_h.i_pwr < i_thresh_h) && + (iq_est_h.q_pwr > q_thresh_l) && + (iq_est_h.q_pwr < q_thresh_h)) + return true; + + return false; +} + static bool wlc_lcnphy_rx_iq_cal(struct brcms_phy *pi, const struct lcnphy_rx_iqcomp *iqcomp, @@ -1342,8 +1382,8 @@ wlc_lcnphy_rx_iq_cal(struct brcms_phy *pi, RFOverrideVal0_old, rfoverride2_old, rfoverride2val_old, rfoverride3_old, rfoverride3val_old, rfoverride4_old, rfoverride4val_old, afectrlovr_old, afectrlovrval_old; - int tia_gain; - u32 received_power, rx_pwr_threshold; + int tia_gain, lna2_gain, biq1_gain; + bool set_gain; u16 old_sslpnCalibClkEnCtrl, old_sslpnRxFeClkEnCtrl; u16 values_to_save[11]; s16 *ptr; @@ -1368,126 +1408,134 @@ wlc_lcnphy_rx_iq_cal(struct brcms_phy *pi, goto cal_done; } - if (module == 1) { + WARN_ON(module != 1); + tx_pwr_ctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi); + wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF); - tx_pwr_ctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi); - wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF); + for (i = 0; i < 11; i++) + values_to_save[i] = + read_radio_reg(pi, rxiq_cal_rf_reg[i]); + Core1TxControl_old = read_phy_reg(pi, 0x631); + + or_phy_reg(pi, 0x631, 0x0015); + + RFOverride0_old = read_phy_reg(pi, 0x44c); + RFOverrideVal0_old = read_phy_reg(pi, 0x44d); + rfoverride2_old = read_phy_reg(pi, 0x4b0); + rfoverride2val_old = read_phy_reg(pi, 0x4b1); + rfoverride3_old = read_phy_reg(pi, 0x4f9); + rfoverride3val_old = read_phy_reg(pi, 0x4fa); + rfoverride4_old = read_phy_reg(pi, 0x938); + rfoverride4val_old = read_phy_reg(pi, 0x939); + afectrlovr_old = read_phy_reg(pi, 0x43b); + afectrlovrval_old = read_phy_reg(pi, 0x43c); + old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da); + old_sslpnRxFeClkEnCtrl = read_phy_reg(pi, 0x6db); - for (i = 0; i < 11; i++) - values_to_save[i] = - read_radio_reg(pi, rxiq_cal_rf_reg[i]); - Core1TxControl_old = read_phy_reg(pi, 0x631); - - or_phy_reg(pi, 0x631, 0x0015); - - RFOverride0_old = read_phy_reg(pi, 0x44c); - RFOverrideVal0_old = read_phy_reg(pi, 0x44d); - rfoverride2_old = read_phy_reg(pi, 0x4b0); - rfoverride2val_old = read_phy_reg(pi, 0x4b1); - rfoverride3_old = read_phy_reg(pi, 0x4f9); - rfoverride3val_old = read_phy_reg(pi, 0x4fa); - rfoverride4_old = read_phy_reg(pi, 0x938); - rfoverride4val_old = read_phy_reg(pi, 0x939); - afectrlovr_old = read_phy_reg(pi, 0x43b); - afectrlovrval_old = read_phy_reg(pi, 0x43c); - old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da); - old_sslpnRxFeClkEnCtrl = read_phy_reg(pi, 0x6db); - - tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi); - if (tx_gain_override_old) { - wlc_lcnphy_get_tx_gain(pi, &old_gains); - tx_gain_index_old = pi_lcn->lcnphy_current_index; - } + tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi); + if (tx_gain_override_old) { + wlc_lcnphy_get_tx_gain(pi, &old_gains); + tx_gain_index_old = pi_lcn->lcnphy_current_index; + } - wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_idx); + wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_idx); - mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0); - mod_phy_reg(pi, 0x4fa, (0x1 << 0), 0 << 0); + mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0); + mod_phy_reg(pi, 0x4fa, (0x1 << 0), 0 << 0); - mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1); - mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1); + mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1); + mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1); - write_radio_reg(pi, RADIO_2064_REG116, 0x06); - write_radio_reg(pi, RADIO_2064_REG12C, 0x07); - write_radio_reg(pi, RADIO_2064_REG06A, 0xd3); - write_radio_reg(pi, RADIO_2064_REG098, 0x03); - write_radio_reg(pi, RADIO_2064_REG00B, 0x7); - mod_radio_reg(pi, RADIO_2064_REG113, 1 << 4, 1 << 4); - write_radio_reg(pi, RADIO_2064_REG01D, 0x01); - write_radio_reg(pi, RADIO_2064_REG114, 0x01); - write_radio_reg(pi, RADIO_2064_REG02E, 0x10); - write_radio_reg(pi, RADIO_2064_REG12A, 0x08); - - mod_phy_reg(pi, 0x938, (0x1 << 0), 1 << 0); - mod_phy_reg(pi, 0x939, (0x1 << 0), 0 << 0); - mod_phy_reg(pi, 0x938, (0x1 << 1), 1 << 1); - mod_phy_reg(pi, 0x939, (0x1 << 1), 1 << 1); - mod_phy_reg(pi, 0x938, (0x1 << 2), 1 << 2); - mod_phy_reg(pi, 0x939, (0x1 << 2), 1 << 2); - mod_phy_reg(pi, 0x938, (0x1 << 3), 1 << 3); - mod_phy_reg(pi, 0x939, (0x1 << 3), 1 << 3); - mod_phy_reg(pi, 0x938, (0x1 << 5), 1 << 5); - mod_phy_reg(pi, 0x939, (0x1 << 5), 0 << 5); - - mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0); - mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0); - - wlc_lcnphy_start_tx_tone(pi, 2000, 120, 0); - write_phy_reg(pi, 0x6da, 0xffff); - or_phy_reg(pi, 0x6db, 0x3); - wlc_lcnphy_set_trsw_override(pi, tx_switch, rx_switch); - wlc_lcnphy_rx_gain_override_enable(pi, true); - - tia_gain = 8; - rx_pwr_threshold = 950; - while (tia_gain > 0) { - tia_gain -= 1; - wlc_lcnphy_set_rx_gain_by_distribution(pi, - 0, 0, 2, 2, - (u16) - tia_gain, 1, 0); - udelay(500); + write_radio_reg(pi, RADIO_2064_REG116, 0x06); + write_radio_reg(pi, RADIO_2064_REG12C, 0x07); + write_radio_reg(pi, RADIO_2064_REG06A, 0xd3); + write_radio_reg(pi, RADIO_2064_REG098, 0x03); + write_radio_reg(pi, RADIO_2064_REG00B, 0x7); + mod_radio_reg(pi, RADIO_2064_REG113, 1 << 4, 1 << 4); + write_radio_reg(pi, RADIO_2064_REG01D, 0x01); + write_radio_reg(pi, RADIO_2064_REG114, 0x01); + write_radio_reg(pi, RADIO_2064_REG02E, 0x10); + write_radio_reg(pi, RADIO_2064_REG12A, 0x08); + + mod_phy_reg(pi, 0x938, (0x1 << 0), 1 << 0); + mod_phy_reg(pi, 0x939, (0x1 << 0), 0 << 0); + mod_phy_reg(pi, 0x938, (0x1 << 1), 1 << 1); + mod_phy_reg(pi, 0x939, (0x1 << 1), 1 << 1); + mod_phy_reg(pi, 0x938, (0x1 << 2), 1 << 2); + mod_phy_reg(pi, 0x939, (0x1 << 2), 1 << 2); + mod_phy_reg(pi, 0x938, (0x1 << 3), 1 << 3); + mod_phy_reg(pi, 0x939, (0x1 << 3), 1 << 3); + mod_phy_reg(pi, 0x938, (0x1 << 5), 1 << 5); + mod_phy_reg(pi, 0x939, (0x1 << 5), 0 << 5); - received_power = - wlc_lcnphy_measure_digital_power(pi, 2000); - if (received_power < rx_pwr_threshold) - break; + mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0); + mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0); + + write_phy_reg(pi, 0x6da, 0xffff); + or_phy_reg(pi, 0x6db, 0x3); + + wlc_lcnphy_set_trsw_override(pi, tx_switch, rx_switch); + set_gain = false; + + lna2_gain = 3; + while ((lna2_gain >= 0) && !set_gain) { + tia_gain = 4; + + while ((tia_gain >= 0) && !set_gain) { + biq1_gain = 6; + + while ((biq1_gain >= 0) && !set_gain) { + set_gain = wlc_lcnphy_rx_iq_cal_gain(pi, + (u16) + biq1_gain, + (u16) + tia_gain, + (u16) + lna2_gain); + biq1_gain -= 1; + } + tia_gain -= 1; } - result = wlc_lcnphy_calc_rx_iq_comp(pi, 0xffff); + lna2_gain -= 1; + } - wlc_lcnphy_stop_tx_tone(pi); + if (set_gain) + result = wlc_lcnphy_calc_rx_iq_comp(pi, 1024); + else + result = false; - write_phy_reg(pi, 0x631, Core1TxControl_old); + wlc_lcnphy_stop_tx_tone(pi); - write_phy_reg(pi, 0x44c, RFOverrideVal0_old); - write_phy_reg(pi, 0x44d, RFOverrideVal0_old); - write_phy_reg(pi, 0x4b0, rfoverride2_old); - write_phy_reg(pi, 0x4b1, rfoverride2val_old); - write_phy_reg(pi, 0x4f9, rfoverride3_old); - write_phy_reg(pi, 0x4fa, rfoverride3val_old); - write_phy_reg(pi, 0x938, rfoverride4_old); - write_phy_reg(pi, 0x939, rfoverride4val_old); - write_phy_reg(pi, 0x43b, afectrlovr_old); - write_phy_reg(pi, 0x43c, afectrlovrval_old); - write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl); - write_phy_reg(pi, 0x6db, old_sslpnRxFeClkEnCtrl); + write_phy_reg(pi, 0x631, Core1TxControl_old); + + write_phy_reg(pi, 0x44c, RFOverrideVal0_old); + write_phy_reg(pi, 0x44d, RFOverrideVal0_old); + write_phy_reg(pi, 0x4b0, rfoverride2_old); + write_phy_reg(pi, 0x4b1, rfoverride2val_old); + write_phy_reg(pi, 0x4f9, rfoverride3_old); + write_phy_reg(pi, 0x4fa, rfoverride3val_old); + write_phy_reg(pi, 0x938, rfoverride4_old); + write_phy_reg(pi, 0x939, rfoverride4val_old); + write_phy_reg(pi, 0x43b, afectrlovr_old); + write_phy_reg(pi, 0x43c, afectrlovrval_old); + write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl); + write_phy_reg(pi, 0x6db, old_sslpnRxFeClkEnCtrl); - wlc_lcnphy_clear_trsw_override(pi); + wlc_lcnphy_clear_trsw_override(pi); - mod_phy_reg(pi, 0x44c, (0x1 << 2), 0 << 2); + mod_phy_reg(pi, 0x44c, (0x1 << 2), 0 << 2); - for (i = 0; i < 11; i++) - write_radio_reg(pi, rxiq_cal_rf_reg[i], - values_to_save[i]); + for (i = 0; i < 11; i++) + write_radio_reg(pi, rxiq_cal_rf_reg[i], + values_to_save[i]); - if (tx_gain_override_old) - wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_index_old); - else - wlc_lcnphy_disable_tx_gain_override(pi); + if (tx_gain_override_old) + wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_index_old); + else + wlc_lcnphy_disable_tx_gain_override(pi); - wlc_lcnphy_set_tx_pwr_ctrl(pi, tx_pwr_ctrl); - wlc_lcnphy_rx_gain_override_enable(pi, false); - } + wlc_lcnphy_set_tx_pwr_ctrl(pi, tx_pwr_ctrl); + wlc_lcnphy_rx_gain_override_enable(pi, false); cal_done: kfree(ptr); @@ -1781,6 +1829,17 @@ wlc_lcnphy_radio_2064_channel_tune_4313(struct brcms_phy *pi, u8 channel) write_radio_reg(pi, RADIO_2064_REG038, 3); write_radio_reg(pi, RADIO_2064_REG091, 7); } + + if (!(pi->sh->boardflags & BFL_FEM)) { + u8 reg038[14] = {0xd, 0xe, 0xd, 0xd, 0xd, 0xc, + 0xa, 0xb, 0xb, 0x3, 0x3, 0x2, 0x0, 0x0}; + + write_radio_reg(pi, RADIO_2064_REG02A, 0xf); + write_radio_reg(pi, RADIO_2064_REG091, 0x3); + write_radio_reg(pi, RADIO_2064_REG038, 0x3); + + write_radio_reg(pi, RADIO_2064_REG038, reg038[channel - 1]); + } } static int @@ -1860,41 +1919,6 @@ wlc_lcnphy_load_tx_iir_filter(struct brcms_phy *pi, bool is_ofdm, s16 filt_type) return (filt_index != -1) ? 0 : -1; } -void wlc_phy_chanspec_set_lcnphy(struct brcms_phy *pi, u16 chanspec) -{ - u8 channel = CHSPEC_CHANNEL(chanspec); - - wlc_phy_chanspec_radio_set((struct brcms_phy_pub *) pi, chanspec); - - wlc_lcnphy_set_chanspec_tweaks(pi, pi->radio_chanspec); - - or_phy_reg(pi, 0x44a, 0x44); - write_phy_reg(pi, 0x44a, 0x80); - - wlc_lcnphy_radio_2064_channel_tune_4313(pi, channel); - udelay(1000); - - wlc_lcnphy_toggle_afe_pwdn(pi); - - write_phy_reg(pi, 0x657, lcnphy_sfo_cfg[channel - 1].ptcentreTs20); - write_phy_reg(pi, 0x658, lcnphy_sfo_cfg[channel - 1].ptcentreFactor); - - if (CHSPEC_CHANNEL(pi->radio_chanspec) == 14) { - mod_phy_reg(pi, 0x448, (0x3 << 8), (2) << 8); - - wlc_lcnphy_load_tx_iir_filter(pi, false, 3); - } else { - mod_phy_reg(pi, 0x448, (0x3 << 8), (1) << 8); - - wlc_lcnphy_load_tx_iir_filter(pi, false, 2); - } - - wlc_lcnphy_load_tx_iir_filter(pi, true, 0); - - mod_phy_reg(pi, 0x4eb, (0x7 << 3), (1) << 3); - -} - static u16 wlc_lcnphy_get_pa_gain(struct brcms_phy *pi) { u16 pa_gain; @@ -1936,6 +1960,21 @@ static void wlc_lcnphy_set_tx_gain(struct brcms_phy *pi, wlc_lcnphy_enable_tx_gain_override(pi); } +static u8 wlc_lcnphy_get_bbmult(struct brcms_phy *pi) +{ + u16 m0m1; + struct phytbl_info tab; + + tab.tbl_ptr = &m0m1; + tab.tbl_len = 1; + tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL; + tab.tbl_offset = 87; + tab.tbl_width = 16; + wlc_lcnphy_read_table(pi, &tab); + + return (u8) ((m0m1 & 0xff00) >> 8); +} + static void wlc_lcnphy_set_bbmult(struct brcms_phy *pi, u8 m0) { u16 m0m1 = (u16) m0 << 8; @@ -1995,6 +2034,16 @@ wlc_lcnphy_set_tssi_mux(struct brcms_phy *pi, enum lcnphy_tssi_mode pos) } else { mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0x1); mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 0x8); + mod_radio_reg(pi, RADIO_2064_REG028, 0x1, 0x0); + mod_radio_reg(pi, RADIO_2064_REG11A, 0x4, 1<<2); + mod_radio_reg(pi, RADIO_2064_REG036, 0x10, 0x0); + mod_radio_reg(pi, RADIO_2064_REG11A, 0x10, 1<<4); + mod_radio_reg(pi, RADIO_2064_REG036, 0x3, 0x0); + mod_radio_reg(pi, RADIO_2064_REG035, 0xff, 0x77); + mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, 0xe<<1); + mod_radio_reg(pi, RADIO_2064_REG112, 0x80, 1<<7); + mod_radio_reg(pi, RADIO_2064_REG005, 0x7, 1<<1); + mod_radio_reg(pi, RADIO_2064_REG029, 0xf0, 0<<4); } } else { mod_phy_reg(pi, 0x4d9, (0x1 << 2), (0x1) << 2); @@ -2081,12 +2130,14 @@ static void wlc_lcnphy_pwrctrl_rssiparams(struct brcms_phy *pi) (auxpga_vmid_temp << 0) | (auxpga_gain_temp << 12)); mod_radio_reg(pi, RADIO_2064_REG082, (1 << 5), (1 << 5)); + mod_radio_reg(pi, RADIO_2064_REG07C, (1 << 0), (1 << 0)); } static void wlc_lcnphy_tssi_setup(struct brcms_phy *pi) { struct phytbl_info tab; u32 rfseq, ind; + u8 tssi_sel; tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL; tab.tbl_width = 32; @@ -2108,7 +2159,13 @@ static void wlc_lcnphy_tssi_setup(struct brcms_phy *pi) mod_phy_reg(pi, 0x503, (0x1 << 4), (1) << 4); - wlc_lcnphy_set_tssi_mux(pi, LCNPHY_TSSI_EXT); + if (pi->sh->boardflags & BFL_FEM) { + tssi_sel = 0x1; + wlc_lcnphy_set_tssi_mux(pi, LCNPHY_TSSI_EXT); + } else { + tssi_sel = 0xe; + wlc_lcnphy_set_tssi_mux(pi, LCNPHY_TSSI_POST_PA); + } mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0) << 14); mod_phy_reg(pi, 0x4a4, (0x1 << 15), (1) << 15); @@ -2144,9 +2201,10 @@ static void wlc_lcnphy_tssi_setup(struct brcms_phy *pi) mod_phy_reg(pi, 0x49a, (0x1ff << 0), (0xff) << 0); if (LCNREV_IS(pi->pubpi.phy_rev, 2)) { - mod_radio_reg(pi, RADIO_2064_REG028, 0xf, 0xe); + mod_radio_reg(pi, RADIO_2064_REG028, 0xf, tssi_sel); mod_radio_reg(pi, RADIO_2064_REG086, 0x4, 0x4); } else { + mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, tssi_sel << 1); mod_radio_reg(pi, RADIO_2064_REG03A, 0x1, 1); mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 1 << 3); } @@ -2193,6 +2251,10 @@ static void wlc_lcnphy_tssi_setup(struct brcms_phy *pi) mod_phy_reg(pi, 0x4d7, (0xf << 8), (0) << 8); + mod_radio_reg(pi, RADIO_2064_REG035, 0xff, 0x0); + mod_radio_reg(pi, RADIO_2064_REG036, 0x3, 0x0); + mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 0x8); + wlc_lcnphy_pwrctrl_rssiparams(pi); } @@ -2811,6 +2873,8 @@ static void wlc_lcnphy_idle_tssi_est(struct brcms_phy_pub *ppi) read_radio_reg(pi, RADIO_2064_REG007) & 1; u16 SAVE_jtag_auxpga = read_radio_reg(pi, RADIO_2064_REG0FF) & 0x10; u16 SAVE_iqadc_aux_en = read_radio_reg(pi, RADIO_2064_REG11F) & 4; + u8 SAVE_bbmult = wlc_lcnphy_get_bbmult(pi); + idleTssi = read_phy_reg(pi, 0x4ab); suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) & MCTL_EN_MAC)); @@ -2828,6 +2892,12 @@ static void wlc_lcnphy_idle_tssi_est(struct brcms_phy_pub *ppi) mod_radio_reg(pi, RADIO_2064_REG0FF, 0x10, 1 << 4); mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 1 << 2); wlc_lcnphy_tssi_setup(pi); + + mod_phy_reg(pi, 0x4d7, (0x1 << 0), (1 << 0)); + mod_phy_reg(pi, 0x4d7, (0x1 << 6), (1 << 6)); + + wlc_lcnphy_set_bbmult(pi, 0x0); + wlc_phy_do_dummy_tx(pi, true, OFF); idleTssi = ((read_phy_reg(pi, 0x4ab) & (0x1ff << 0)) >> 0); @@ -2849,6 +2919,7 @@ static void wlc_lcnphy_idle_tssi_est(struct brcms_phy_pub *ppi) mod_phy_reg(pi, 0x44c, (0x1 << 12), (0) << 12); + wlc_lcnphy_set_bbmult(pi, SAVE_bbmult); wlc_lcnphy_set_tx_gain_override(pi, tx_gain_override_old); wlc_lcnphy_set_tx_gain(pi, &old_gains); wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl); @@ -3062,6 +3133,11 @@ static void wlc_lcnphy_tx_pwr_ctrl_init(struct brcms_phy_pub *ppi) wlc_lcnphy_write_table(pi, &tab); tab.tbl_offset++; } + mod_phy_reg(pi, 0x4d0, (0x1 << 0), (0) << 0); + mod_phy_reg(pi, 0x4d3, (0xff << 0), (0) << 0); + mod_phy_reg(pi, 0x4d3, (0xff << 8), (0) << 8); + mod_phy_reg(pi, 0x4d0, (0x1 << 4), (0) << 4); + mod_phy_reg(pi, 0x4d0, (0x1 << 2), (0) << 2); mod_phy_reg(pi, 0x410, (0x1 << 7), (0) << 7); @@ -3075,21 +3151,6 @@ static void wlc_lcnphy_tx_pwr_ctrl_init(struct brcms_phy_pub *ppi) wlapi_enable_mac(pi->sh->physhim); } -static u8 wlc_lcnphy_get_bbmult(struct brcms_phy *pi) -{ - u16 m0m1; - struct phytbl_info tab; - - tab.tbl_ptr = &m0m1; - tab.tbl_len = 1; - tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL; - tab.tbl_offset = 87; - tab.tbl_width = 16; - wlc_lcnphy_read_table(pi, &tab); - - return (u8) ((m0m1 & 0xff00) >> 8); -} - static void wlc_lcnphy_set_pa_gain(struct brcms_phy *pi, u16 gain) { mod_phy_reg(pi, 0x4fb, @@ -3878,7 +3939,6 @@ static void wlc_lcnphy_txpwrtbl_iqlo_cal(struct brcms_phy *pi) target_gains.pad_gain = 21; target_gains.dac_gain = 0; wlc_lcnphy_set_tx_gain(pi, &target_gains); - wlc_lcnphy_set_tx_pwr_by_index(pi, 16); if (LCNREV_IS(pi->pubpi.phy_rev, 1) || pi_lcn->lcnphy_hw_iqcal_en) { @@ -3889,6 +3949,7 @@ static void wlc_lcnphy_txpwrtbl_iqlo_cal(struct brcms_phy *pi) lcnphy_recal ? LCNPHY_CAL_RECAL : LCNPHY_CAL_FULL), false); } else { + wlc_lcnphy_set_tx_pwr_by_index(pi, 16); wlc_lcnphy_tx_iqlo_soft_cal_full(pi); } @@ -4313,17 +4374,22 @@ wlc_lcnphy_load_tx_gain_table(struct brcms_phy *pi, if (CHSPEC_IS5G(pi->radio_chanspec)) pa_gain = 0x70; else - pa_gain = 0x70; + pa_gain = 0x60; if (pi->sh->boardflags & BFL_FEM) pa_gain = 0x10; + tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL; tab.tbl_width = 32; tab.tbl_len = 1; tab.tbl_ptr = &val; for (j = 0; j < 128; j++) { - gm_gain = gain_table[j].gm; + if (pi->sh->boardflags & BFL_FEM) + gm_gain = gain_table[j].gm; + else + gm_gain = 15; + val = (((u32) pa_gain << 24) | (gain_table[j].pad << 16) | (gain_table[j].pga << 8) | gm_gain); @@ -4534,7 +4600,10 @@ static void wlc_radio_2064_init(struct brcms_phy *pi) write_phy_reg(pi, 0x4ea, 0x4688); - mod_phy_reg(pi, 0x4eb, (0x7 << 0), 2 << 0); + if (pi->sh->boardflags & BFL_FEM) + mod_phy_reg(pi, 0x4eb, (0x7 << 0), 2 << 0); + else + mod_phy_reg(pi, 0x4eb, (0x7 << 0), 3 << 0); mod_phy_reg(pi, 0x4eb, (0x7 << 6), 0 << 6); @@ -4545,6 +4614,13 @@ static void wlc_radio_2064_init(struct brcms_phy *pi) wlc_lcnphy_rcal(pi); wlc_lcnphy_rc_cal(pi); + + if (!(pi->sh->boardflags & BFL_FEM)) { + write_radio_reg(pi, RADIO_2064_REG032, 0x6f); + write_radio_reg(pi, RADIO_2064_REG033, 0x19); + write_radio_reg(pi, RADIO_2064_REG039, 0xe); + } + } static void wlc_lcnphy_radio_init(struct brcms_phy *pi) @@ -4574,22 +4650,20 @@ static void wlc_lcnphy_tbl_init(struct brcms_phy *pi) wlc_lcnphy_write_table(pi, &tab); } - tab.tbl_id = LCNPHY_TBL_ID_RFSEQ; - tab.tbl_width = 16; - tab.tbl_ptr = &val; - tab.tbl_len = 1; - - val = 114; - tab.tbl_offset = 0; - wlc_lcnphy_write_table(pi, &tab); + if (!(pi->sh->boardflags & BFL_FEM)) { + tab.tbl_id = LCNPHY_TBL_ID_RFSEQ; + tab.tbl_width = 16; + tab.tbl_ptr = &val; + tab.tbl_len = 1; - val = 130; - tab.tbl_offset = 1; - wlc_lcnphy_write_table(pi, &tab); + val = 150; + tab.tbl_offset = 0; + wlc_lcnphy_write_table(pi, &tab); - val = 6; - tab.tbl_offset = 8; - wlc_lcnphy_write_table(pi, &tab); + val = 220; + tab.tbl_offset = 1; + wlc_lcnphy_write_table(pi, &tab); + } if (CHSPEC_IS2G(pi->radio_chanspec)) { if (pi->sh->boardflags & BFL_FEM) @@ -4946,6 +5020,44 @@ void wlc_phy_txpower_recalc_target_lcnphy(struct brcms_phy *pi) } } +void wlc_phy_chanspec_set_lcnphy(struct brcms_phy *pi, u16 chanspec) +{ + u8 channel = CHSPEC_CHANNEL(chanspec); + + wlc_phy_chanspec_radio_set((struct brcms_phy_pub *)pi, chanspec); + + wlc_lcnphy_set_chanspec_tweaks(pi, pi->radio_chanspec); + + or_phy_reg(pi, 0x44a, 0x44); + write_phy_reg(pi, 0x44a, 0x80); + + wlc_lcnphy_radio_2064_channel_tune_4313(pi, channel); + udelay(1000); + + wlc_lcnphy_toggle_afe_pwdn(pi); + + write_phy_reg(pi, 0x657, lcnphy_sfo_cfg[channel - 1].ptcentreTs20); + write_phy_reg(pi, 0x658, lcnphy_sfo_cfg[channel - 1].ptcentreFactor); + + if (CHSPEC_CHANNEL(pi->radio_chanspec) == 14) { + mod_phy_reg(pi, 0x448, (0x3 << 8), (2) << 8); + + wlc_lcnphy_load_tx_iir_filter(pi, false, 3); + } else { + mod_phy_reg(pi, 0x448, (0x3 << 8), (1) << 8); + + wlc_lcnphy_load_tx_iir_filter(pi, false, 2); + } + + if (pi->sh->boardflags & BFL_FEM) + wlc_lcnphy_load_tx_iir_filter(pi, true, 0); + else + wlc_lcnphy_load_tx_iir_filter(pi, true, 3); + + mod_phy_reg(pi, 0x4eb, (0x7 << 3), (1) << 3); + wlc_lcnphy_tssi_setup(pi); +} + void wlc_phy_detach_lcnphy(struct brcms_phy *pi) { kfree(pi->u.pi_lcnphy); @@ -4982,8 +5094,7 @@ bool wlc_phy_attach_lcnphy(struct brcms_phy *pi) if (!wlc_phy_txpwr_srom_read_lcnphy(pi)) return false; - if ((pi->sh->boardflags & BFL_FEM) && - (LCNREV_IS(pi->pubpi.phy_rev, 1))) { + if (LCNREV_IS(pi->pubpi.phy_rev, 1)) { if (pi_lcn->lcnphy_tempsense_option == 3) { pi->hwpwrctrl = true; pi->hwpwrctrl_capable = true; diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c index 622c01c..b7e95ac 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c @@ -1992,70 +1992,70 @@ static const u16 dot11lcn_sw_ctrl_tbl_4313_epa_rev0[] = { }; static const u16 dot11lcn_sw_ctrl_tbl_4313_rev0[] = { - 0x000a, 0x0009, - 0x0006, - 0x0005, 0x000a, - 0x0009, - 0x0006, 0x0005, - 0x000a, - 0x0009, 0x0006, - 0x0005, - 0x000a, 0x0009, - 0x0006, - 0x0005, 0x000a, - 0x0009, - 0x0006, 0x0005, - 0x000a, - 0x0009, 0x0006, - 0x0005, - 0x000a, 0x0009, - 0x0006, - 0x0005, 0x000a, - 0x0009, - 0x0006, 0x0005, - 0x000a, - 0x0009, 0x0006, - 0x0005, - 0x000a, 0x0009, - 0x0006, - 0x0005, 0x000a, - 0x0009, - 0x0006, 0x0005, - 0x000a, - 0x0009, 0x0006, - 0x0005, + 0x0009, 0x000a, + 0x0005, + 0x0006, 0x0009, + 0x000a, + 0x0005, 0x0006, + 0x0009, + 0x000a, 0x0005, + 0x0006, + 0x0009, 0x000a, + 0x0005, + 0x0006, 0x0009, + 0x000a, + 0x0005, 0x0006, + 0x0009, + 0x000a, 0x0005, + 0x0006, + 0x0009, 0x000a, + 0x0005, + 0x0006, 0x0009, + 0x000a, + 0x0005, 0x0006, + 0x0009, + 0x000a, 0x0005, + 0x0006, + 0x0009, 0x000a, + 0x0005, + 0x0006, 0x0009, + 0x000a, + 0x0005, 0x0006, + 0x0009, + 0x000a, 0x0005, + 0x0006, }; static const u16 dot11lcn_sw_ctrl_tbl_rev0[] = { diff --git a/drivers/net/wireless/brcm80211/brcmsmac/pub.h b/drivers/net/wireless/brcm80211/brcmsmac/pub.h index 5855f4f..4fb2834 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/pub.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/pub.h @@ -176,6 +176,7 @@ struct brcms_pub { bool phy_11ncapable; /* the PHY/HW is capable of 802.11N */ struct wl_cnt *_cnt; /* low-level counters in driver */ + struct dentry *dbgfs_dir; }; enum wlc_par_id { @@ -200,43 +201,6 @@ enum wlc_par_id { /* WL11N Support */ #define AMPDU_AGG_HOST 1 -/* pri is priority encoded in the packet. This maps the Packet priority to - * enqueue precedence as defined in wlc_prec_map - */ -extern const u8 wlc_prio2prec_map[]; -#define BRCMS_PRIO_TO_PREC(pri) wlc_prio2prec_map[(pri) & 7] - -#define BRCMS_PREC_COUNT 16 /* Max precedence level implemented */ - -/* Mask to describe all precedence levels */ -#define BRCMS_PREC_BMP_ALL MAXBITVAL(BRCMS_PREC_COUNT) - -/* - * This maps priority to one precedence higher - Used by PS-Poll response - * packets to simulate enqueue-at-head operation, but still maintain the - * order on the queue - */ -#define BRCMS_PRIO_TO_HI_PREC(pri) min(BRCMS_PRIO_TO_PREC(pri) + 1,\ - BRCMS_PREC_COUNT - 1) - -/* Define a bitmap of precedences comprised by each AC */ -#define BRCMS_PREC_BMP_AC_BE (NBITVAL(BRCMS_PRIO_TO_PREC(PRIO_8021D_BE)) | \ - NBITVAL(BRCMS_PRIO_TO_HI_PREC(PRIO_8021D_BE)) | \ - NBITVAL(BRCMS_PRIO_TO_PREC(PRIO_8021D_EE)) | \ - NBITVAL(BRCMS_PRIO_TO_HI_PREC(PRIO_8021D_EE))) -#define BRCMS_PREC_BMP_AC_BK (NBITVAL(BRCMS_PRIO_TO_PREC(PRIO_8021D_BK)) | \ - NBITVAL(BRCMS_PRIO_TO_HI_PREC(PRIO_8021D_BK)) | \ - NBITVAL(BRCMS_PRIO_TO_PREC(PRIO_8021D_NONE)) | \ - NBITVAL(BRCMS_PRIO_TO_HI_PREC(PRIO_8021D_NONE))) -#define BRCMS_PREC_BMP_AC_VI (NBITVAL(BRCMS_PRIO_TO_PREC(PRIO_8021D_CL)) | \ - NBITVAL(BRCMS_PRIO_TO_HI_PREC(PRIO_8021D_CL)) | \ - NBITVAL(BRCMS_PRIO_TO_PREC(PRIO_8021D_VI)) | \ - NBITVAL(BRCMS_PRIO_TO_HI_PREC(PRIO_8021D_VI))) -#define BRCMS_PREC_BMP_AC_VO (NBITVAL(BRCMS_PRIO_TO_PREC(PRIO_8021D_VO)) | \ - NBITVAL(BRCMS_PRIO_TO_HI_PREC(PRIO_8021D_VO)) | \ - NBITVAL(BRCMS_PRIO_TO_PREC(PRIO_8021D_NC)) | \ - NBITVAL(BRCMS_PRIO_TO_HI_PREC(PRIO_8021D_NC))) - /* network protection config */ #define BRCMS_PROT_G_SPEC 1 /* SPEC g protection */ #define BRCMS_PROT_G_OVR 2 /* SPEC g prot override */ @@ -319,9 +283,9 @@ extern void brcms_c_intrson(struct brcms_c_info *wlc); extern u32 brcms_c_intrsoff(struct brcms_c_info *wlc); extern void brcms_c_intrsrestore(struct brcms_c_info *wlc, u32 macintmask); extern bool brcms_c_intrsupd(struct brcms_c_info *wlc); -extern bool brcms_c_isr(struct brcms_c_info *wlc, bool *wantdpc); +extern bool brcms_c_isr(struct brcms_c_info *wlc); extern bool brcms_c_dpc(struct brcms_c_info *wlc, bool bounded); -extern void brcms_c_sendpkt_mac80211(struct brcms_c_info *wlc, +extern bool brcms_c_sendpkt_mac80211(struct brcms_c_info *wlc, struct sk_buff *sdu, struct ieee80211_hw *hw); extern bool brcms_c_aggregatable(struct brcms_c_info *wlc, u8 tid); diff --git a/drivers/net/wireless/brcm80211/brcmsmac/stf.c b/drivers/net/wireless/brcm80211/brcmsmac/stf.c index ed1d1aa..dd91627 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/stf.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/stf.c @@ -23,6 +23,7 @@ #include "channel.h" #include "main.h" #include "stf.h" +#include "debug.h" #define MIN_SPATIAL_EXPANSION 0 #define MAX_SPATIAL_EXPANSION 1 @@ -160,8 +161,8 @@ bool brcms_c_stf_stbc_rx_set(struct brcms_c_info *wlc, s32 int_val) static int brcms_c_stf_txcore_set(struct brcms_c_info *wlc, u8 Nsts, u8 core_mask) { - BCMMSG(wlc->wiphy, "wl%d: Nsts %d core_mask %x\n", - wlc->pub->unit, Nsts, core_mask); + brcms_dbg_ht(wlc->hw->d11core, "wl%d: Nsts %d core_mask %x\n", + wlc->pub->unit, Nsts, core_mask); if (hweight8(core_mask) > wlc->stf->txstreams) core_mask = 0; @@ -194,7 +195,8 @@ static int brcms_c_stf_spatial_policy_set(struct brcms_c_info *wlc, int val) int i; u8 core_mask = 0; - BCMMSG(wlc->wiphy, "wl%d: val %x\n", wlc->pub->unit, val); + brcms_dbg_ht(wlc->hw->d11core, "wl%d: val %x\n", wlc->pub->unit, + val); wlc->stf->spatial_policy = (s8) val; for (i = 1; i <= MAX_STREAMS_SUPPORTED; i++) { diff --git a/drivers/net/wireless/brcm80211/brcmsmac/types.h b/drivers/net/wireless/brcm80211/brcmsmac/types.h index e11ae83..ae1f3ad 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/types.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/types.h @@ -246,7 +246,7 @@ #define BCMMSG(dev, fmt, args...) \ do { \ - if (brcm_msg_level & LOG_TRACE_VAL) \ + if (brcm_msg_level & BRCM_DL_INFO) \ wiphy_err(dev, "%s: " fmt, __func__, ##args); \ } while (0) @@ -281,7 +281,6 @@ struct ieee80211_tx_queue_params; struct brcms_info; struct brcms_c_info; struct brcms_hardware; -struct brcms_txq_info; struct brcms_band; struct dma_pub; struct si_pub; diff --git a/drivers/net/wireless/brcm80211/include/defs.h b/drivers/net/wireless/brcm80211/include/defs.h index f0d8c04..fb7cbcf 100644 --- a/drivers/net/wireless/brcm80211/include/defs.h +++ b/drivers/net/wireless/brcm80211/include/defs.h @@ -78,9 +78,14 @@ #define PM_OFF 0 #define PM_MAX 1 -/* Message levels */ -#define LOG_ERROR_VAL 0x00000001 -#define LOG_TRACE_VAL 0x00000002 +/* Debug levels */ +#define BRCM_DL_INFO 0x00000001 +#define BRCM_DL_MAC80211 0x00000002 +#define BRCM_DL_RX 0x00000004 +#define BRCM_DL_TX 0x00000008 +#define BRCM_DL_INT 0x00000010 +#define BRCM_DL_DMA 0x00000020 +#define BRCM_DL_HT 0x00000040 #define PM_OFF 0 #define PM_MAX 1 diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c index fea96b5..482f505 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/ipw2x00/ipw2200.c @@ -11269,10 +11269,31 @@ static const struct libipw_geo ipw_geos[] = { } }; +static void ipw_set_geo(struct ipw_priv *priv) +{ + int j; + + for (j = 0; j < ARRAY_SIZE(ipw_geos); j++) { + if (!memcmp(&priv->eeprom[EEPROM_COUNTRY_CODE], + ipw_geos[j].name, 3)) + break; + } + + if (j == ARRAY_SIZE(ipw_geos)) { + IPW_WARNING("SKU [%c%c%c] not recognized.\n", + priv->eeprom[EEPROM_COUNTRY_CODE + 0], + priv->eeprom[EEPROM_COUNTRY_CODE + 1], + priv->eeprom[EEPROM_COUNTRY_CODE + 2]); + j = 0; + } + + libipw_set_geo(priv->ieee, &ipw_geos[j]); +} + #define MAX_HW_RESTARTS 5 static int ipw_up(struct ipw_priv *priv) { - int rc, i, j; + int rc, i; /* Age scan list entries found before suspend */ if (priv->suspend_time) { @@ -11310,19 +11331,7 @@ static int ipw_up(struct ipw_priv *priv) memcpy(priv->net_dev->dev_addr, priv->mac_addr, ETH_ALEN); memcpy(priv->net_dev->perm_addr, priv->mac_addr, ETH_ALEN); - for (j = 0; j < ARRAY_SIZE(ipw_geos); j++) { - if (!memcmp(&priv->eeprom[EEPROM_COUNTRY_CODE], - ipw_geos[j].name, 3)) - break; - } - if (j == ARRAY_SIZE(ipw_geos)) { - IPW_WARNING("SKU [%c%c%c] not recognized.\n", - priv->eeprom[EEPROM_COUNTRY_CODE + 0], - priv->eeprom[EEPROM_COUNTRY_CODE + 1], - priv->eeprom[EEPROM_COUNTRY_CODE + 2]); - j = 0; - } - libipw_set_geo(priv->ieee, &ipw_geos[j]); + ipw_set_geo(priv); if (priv->status & STATUS_RF_KILL_SW) { IPW_WARNING("Radio disabled by module parameter.\n"); diff --git a/drivers/net/wireless/iwlegacy/3945.c b/drivers/net/wireless/iwlegacy/3945.c index 87e5398..e0b9d7f 100644 --- a/drivers/net/wireless/iwlegacy/3945.c +++ b/drivers/net/wireless/iwlegacy/3945.c @@ -516,7 +516,7 @@ static void il3945_hdl_rx(struct il_priv *il, struct il_rx_buf *rxb) { struct ieee80211_hdr *header; - struct ieee80211_rx_status rx_status; + struct ieee80211_rx_status rx_status = {}; struct il_rx_pkt *pkt = rxb_addr(rxb); struct il3945_rx_frame_stats *rx_stats = IL_RX_STATS(pkt); struct il3945_rx_frame_hdr *rx_hdr = IL_RX_HDR(pkt); diff --git a/drivers/net/wireless/iwlegacy/4965-mac.c b/drivers/net/wireless/iwlegacy/4965-mac.c index eac4dc8..07ffa57 100644 --- a/drivers/net/wireless/iwlegacy/4965-mac.c +++ b/drivers/net/wireless/iwlegacy/4965-mac.c @@ -613,7 +613,7 @@ void il4965_hdl_rx(struct il_priv *il, struct il_rx_buf *rxb) { struct ieee80211_hdr *header; - struct ieee80211_rx_status rx_status; + struct ieee80211_rx_status rx_status = {}; struct il_rx_pkt *pkt = rxb_addr(rxb); struct il_rx_phy_res *phy_res; __le32 rx_pkt_status; @@ -686,7 +686,7 @@ il4965_hdl_rx(struct il_priv *il, struct il_rx_buf *rxb) /* TSF isn't reliable. In order to allow smooth user experience, * this W/A doesn't propagate it to the mac80211 */ - /*rx_status.flag |= RX_FLAG_MACTIME_MPDU; */ + /*rx_status.flag |= RX_FLAG_MACTIME_START; */ il->ucode_beacon_time = le32_to_cpu(phy_res->beacon_time_stamp); diff --git a/drivers/net/wireless/iwlwifi/dvm/dev.h b/drivers/net/wireless/iwlwifi/dvm/dev.h index 8141f91..29c571a 100644 --- a/drivers/net/wireless/iwlwifi/dvm/dev.h +++ b/drivers/net/wireless/iwlwifi/dvm/dev.h @@ -789,7 +789,6 @@ struct iwl_priv { /* remain-on-channel offload support */ struct ieee80211_channel *hw_roc_channel; struct delayed_work hw_roc_disable_work; - enum nl80211_channel_type hw_roc_chantype; int hw_roc_duration; bool hw_roc_setup, hw_roc_start_notified; diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c index cb443d5..fb959b0 100644 --- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c @@ -168,8 +168,13 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv, hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS | IEEE80211_HW_SUPPORTS_STATIC_SMPS; - /* enable 11w if the uCode advertise */ - if (capa->flags & IWL_UCODE_TLV_FLAGS_MFP) + /* + * Enable 11w if advertised by firmware and software crypto + * is not enabled (as the firmware will interpret some mgmt + * packets, so enabling it with software crypto isn't safe) + */ + if (priv->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_MFP && + !iwlwifi_mod_params.sw_crypto) hw->flags |= IEEE80211_HW_MFP_CAPABLE; hw->sta_data_size = sizeof(struct iwl_station_priv); @@ -519,7 +524,7 @@ static void iwlagn_mac_tx(struct ieee80211_hw *hw, ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate); if (iwlagn_tx_skb(priv, control->sta, skb)) - dev_kfree_skb_any(skb); + ieee80211_free_txskb(hw, skb); } static void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw, @@ -1030,8 +1035,8 @@ done: } static int iwlagn_mac_remain_on_channel(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, struct ieee80211_channel *channel, - enum nl80211_channel_type channel_type, int duration) { struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); @@ -1063,7 +1068,6 @@ static int iwlagn_mac_remain_on_channel(struct ieee80211_hw *hw, } priv->hw_roc_channel = channel; - priv->hw_roc_chantype = channel_type; /* convert from ms to TU */ priv->hw_roc_duration = DIV_ROUND_UP(1000 * duration, 1024); priv->hw_roc_start_notified = false; @@ -1352,6 +1356,20 @@ static int iwlagn_mac_add_interface(struct ieee80211_hw *hw, vif_priv->ctx = ctx; ctx->vif = vif; + /* + * In SNIFFER device type, the firmware reports the FCS to + * the host, rather than snipping it off. Unfortunately, + * mac80211 doesn't (yet) provide a per-packet flag for + * this, so that we have to set the hardware flag based + * on the interfaces added. As the monitor interface can + * only be present by itself, and will be removed before + * other interfaces are added, this is safe. + */ + if (vif->type == NL80211_IFTYPE_MONITOR) + priv->hw->flags |= IEEE80211_HW_RX_INCLUDES_FCS; + else + priv->hw->flags &= ~IEEE80211_HW_RX_INCLUDES_FCS; + err = iwl_setup_interface(priv, ctx); if (!err || reset) goto out; diff --git a/drivers/net/wireless/iwlwifi/dvm/main.c b/drivers/net/wireless/iwlwifi/dvm/main.c index 03cbfa7..e3a07c9 100644 --- a/drivers/net/wireless/iwlwifi/dvm/main.c +++ b/drivers/net/wireless/iwlwifi/dvm/main.c @@ -1191,8 +1191,6 @@ static void iwl_option_config(struct iwl_priv *priv) static int iwl_eeprom_init_hw_params(struct iwl_priv *priv) { - priv->eeprom_data->sku = priv->eeprom_data->sku; - if (priv->eeprom_data->sku & EEPROM_SKU_CAP_11N_ENABLE && !priv->cfg->ht_params) { IWL_ERR(priv, "Invalid 11n configuration\n"); @@ -2107,7 +2105,7 @@ static void iwl_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb) info = IEEE80211_SKB_CB(skb); iwl_trans_free_tx_cmd(priv->trans, info->driver_data[1]); - dev_kfree_skb_any(skb); + ieee80211_free_txskb(priv->hw, skb); } static void iwl_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state) diff --git a/drivers/net/wireless/iwlwifi/dvm/rx.c b/drivers/net/wireless/iwlwifi/dvm/rx.c index 9a8d502..cac4f37 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rx.c +++ b/drivers/net/wireless/iwlwifi/dvm/rx.c @@ -899,7 +899,7 @@ static int iwlagn_rx_reply_rx(struct iwl_priv *priv, struct iwl_device_cmd *cmd) { struct ieee80211_hdr *header; - struct ieee80211_rx_status rx_status; + struct ieee80211_rx_status rx_status = {}; struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_rx_phy_res *phy_res; __le32 rx_pkt_status; @@ -949,7 +949,7 @@ static int iwlagn_rx_reply_rx(struct iwl_priv *priv, /* TSF isn't reliable. In order to allow smooth user experience, * this W/A doesn't propagate it to the mac80211 */ - /*rx_status.flag |= RX_FLAG_MACTIME_MPDU;*/ + /*rx_status.flag |= RX_FLAG_MACTIME_START;*/ priv->ucode_beacon_time = le32_to_cpu(phy_res->beacon_time_stamp); diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h index 87f465a..196266a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/iwlwifi/iwl-config.h @@ -150,7 +150,7 @@ enum iwl_led_mode { struct iwl_base_params { int eeprom_size; int num_of_queues; /* def: HW dependent */ - /* for iwl_apm_init() */ + /* for iwl_pcie_apm_init() */ u32 pll_cfg_val; const u16 max_ll_items; diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h index 8060466..ec48563 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/iwlwifi/iwl-fh.h @@ -267,7 +267,7 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(unsigned int chnl) #define FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS (20) #define FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS (4) -#define RX_RB_TIMEOUT (0x10) +#define RX_RB_TIMEOUT (0x11) #define FH_RCSR_RX_CONFIG_CHNL_EN_PAUSE_VAL (0x00000000) #define FH_RCSR_RX_CONFIG_CHNL_EN_PAUSE_EOF_VAL (0x40000000) diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c index 2a46753..956fe6c 100644 --- a/drivers/net/wireless/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/iwlwifi/pcie/drv.c @@ -69,7 +69,6 @@ #include "iwl-trans.h" #include "iwl-drv.h" -#include "iwl-trans.h" #include "cfg.h" #include "internal.h" diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h index 1f065c6..d91d2e8 100644 --- a/drivers/net/wireless/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/iwlwifi/pcie/internal.h @@ -73,7 +73,7 @@ struct isr_statistics { }; /** - * struct iwl_rx_queue - Rx queue + * struct iwl_rxq - Rx queue * @bd: driver's pointer to buffer of receive buffer descriptors (rbd) * @bd_dma: bus address of buffer of receive buffer descriptors (rbd) * @pool: @@ -91,7 +91,7 @@ struct isr_statistics { * * NOTE: rx_free and rx_used are used as a FIFO for iwl_rx_mem_buffers */ -struct iwl_rx_queue { +struct iwl_rxq { __le32 *bd; dma_addr_t bd_dma; struct iwl_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS]; @@ -157,8 +157,8 @@ struct iwl_cmd_meta { * 32 since we don't need so many commands pending. Since the HW * still uses 256 BDs for DMA though, n_bd stays 256. As a result, * the software buffers (in the variables @meta, @txb in struct - * iwl_tx_queue) only have 32 entries, while the HW buffers (@tfds - * in the same struct) have 256. + * iwl_txq) only have 32 entries, while the HW buffers (@tfds in + * the same struct) have 256. * This means that we end up with the following: * HW entries: | 0 | ... | N * 32 | ... | N * 32 + 31 | ... | 255 | * SW entries: | 0 | ... | 31 | @@ -182,7 +182,7 @@ struct iwl_queue { #define TFD_TX_CMD_SLOTS 256 #define TFD_CMD_SLOTS 32 -struct iwl_pcie_tx_queue_entry { +struct iwl_pcie_txq_entry { struct iwl_device_cmd *cmd; struct iwl_device_cmd *copy_cmd; struct sk_buff *skb; @@ -192,7 +192,7 @@ struct iwl_pcie_tx_queue_entry { }; /** - * struct iwl_tx_queue - Tx Queue for DMA + * struct iwl_txq - Tx Queue for DMA * @q: generic Rx/Tx queue descriptor * @tfds: transmit frame descriptors (DMA memory) * @entries: transmit entries (driver state) @@ -205,10 +205,10 @@ struct iwl_pcie_tx_queue_entry { * A Tx queue consists of circular buffer of BDs (a.k.a. TFDs, transmit frame * descriptors) and required locking structures. */ -struct iwl_tx_queue { +struct iwl_txq { struct iwl_queue q; struct iwl_tfd *tfds; - struct iwl_pcie_tx_queue_entry *entries; + struct iwl_pcie_txq_entry *entries; spinlock_t lock; struct timer_list stuck_timer; struct iwl_trans_pcie *trans_pcie; @@ -238,7 +238,7 @@ struct iwl_tx_queue { * @wd_timeout: queue watchdog timeout (jiffies) */ struct iwl_trans_pcie { - struct iwl_rx_queue rxq; + struct iwl_rxq rxq; struct work_struct rx_replenish; struct iwl_trans *trans; struct iwl_drv *drv; @@ -260,7 +260,7 @@ struct iwl_trans_pcie { struct iwl_dma_ptr scd_bc_tbls; struct iwl_dma_ptr kw; - struct iwl_tx_queue *txq; + struct iwl_txq *txq; unsigned long queue_used[BITS_TO_LONGS(IWL_MAX_HW_QUEUES)]; unsigned long queue_stopped[BITS_TO_LONGS(IWL_MAX_HW_QUEUES)]; @@ -287,10 +287,16 @@ struct iwl_trans_pcie { unsigned long wd_timeout; }; -/***************************************************** -* DRIVER STATUS FUNCTIONS -******************************************************/ -enum { +/** + * enum iwl_pcie_status: status of the PCIe transport + * @STATUS_HCMD_ACTIVE: a SYNC command is being processed + * @STATUS_DEVICE_ENABLED: APM is enabled + * @STATUS_TPOWER_PMI: the device might be asleep (need to wake it up) + * @STATUS_INT_ENABLED: interrupts are enabled + * @STATUS_RFKILL: the HW RFkill switch is in KILL position + * @STATUS_FW_ERROR: the fw is in error state + */ +enum iwl_pcie_status { STATUS_HCMD_ACTIVE, STATUS_DEVICE_ENABLED, STATUS_TPOWER_PMI, @@ -309,6 +315,10 @@ iwl_trans_pcie_get_trans(struct iwl_trans_pcie *trans_pcie) trans_specific); } +/* + * Convention: trans API functions: iwl_trans_pcie_XXX + * Other functions: iwl_pcie_XXX + */ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, const struct pci_device_id *ent, const struct iwl_cfg *cfg); @@ -317,51 +327,43 @@ void iwl_trans_pcie_free(struct iwl_trans *trans); /***************************************************** * RX ******************************************************/ -void iwl_bg_rx_replenish(struct work_struct *data); -void iwl_irq_tasklet(struct iwl_trans *trans); -void iwl_rx_replenish(struct iwl_trans *trans); -void iwl_rx_queue_update_write_ptr(struct iwl_trans *trans, - struct iwl_rx_queue *q); +int iwl_pcie_rx_init(struct iwl_trans *trans); +void iwl_pcie_tasklet(struct iwl_trans *trans); +int iwl_pcie_rx_stop(struct iwl_trans *trans); +void iwl_pcie_rx_free(struct iwl_trans *trans); /***************************************************** -* ICT +* ICT - interrupt handling ******************************************************/ -void iwl_reset_ict(struct iwl_trans *trans); -void iwl_disable_ict(struct iwl_trans *trans); -int iwl_alloc_isr_ict(struct iwl_trans *trans); -void iwl_free_isr_ict(struct iwl_trans *trans); -irqreturn_t iwl_isr_ict(int irq, void *data); +irqreturn_t iwl_pcie_isr_ict(int irq, void *data); +int iwl_pcie_alloc_ict(struct iwl_trans *trans); +void iwl_pcie_free_ict(struct iwl_trans *trans); +void iwl_pcie_reset_ict(struct iwl_trans *trans); +void iwl_pcie_disable_ict(struct iwl_trans *trans); /***************************************************** * TX / HCMD ******************************************************/ -void iwl_txq_update_write_ptr(struct iwl_trans *trans, - struct iwl_tx_queue *txq); -int iwlagn_txq_attach_buf_to_tfd(struct iwl_trans *trans, - struct iwl_tx_queue *txq, - dma_addr_t addr, u16 len, u8 reset); -int iwl_queue_init(struct iwl_queue *q, int count, int slots_num, u32 id); -int iwl_trans_pcie_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd); -void iwl_tx_cmd_complete(struct iwl_trans *trans, - struct iwl_rx_cmd_buffer *rxb, int handler_status); -void iwl_trans_txq_update_byte_cnt_tbl(struct iwl_trans *trans, - struct iwl_tx_queue *txq, - u16 byte_cnt); +int iwl_pcie_tx_init(struct iwl_trans *trans); +void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr); +int iwl_pcie_tx_stop(struct iwl_trans *trans); +void iwl_pcie_tx_free(struct iwl_trans *trans); void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, int fifo, int sta_id, int tid, int frame_limit, u16 ssn); void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int queue); -void iwl_txq_free_tfd(struct iwl_trans *trans, struct iwl_tx_queue *txq, - enum dma_data_direction dma_dir); -int iwl_tx_queue_reclaim(struct iwl_trans *trans, int txq_id, int index, - struct sk_buff_head *skbs); -void iwl_tx_queue_unmap(struct iwl_trans *trans, int txq_id); -int iwl_queue_space(const struct iwl_queue *q); - +int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, + struct iwl_device_cmd *dev_cmd, int txq_id); +void iwl_pcie_txq_inc_wr_ptr(struct iwl_trans *trans, struct iwl_txq *txq); +int iwl_trans_pcie_send_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd); +void iwl_pcie_hcmd_complete(struct iwl_trans *trans, + struct iwl_rx_cmd_buffer *rxb, int handler_status); +void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, + struct sk_buff_head *skbs); /***************************************************** * Error handling ******************************************************/ -int iwl_dump_fh(struct iwl_trans *trans, char **buf); -void iwl_dump_csr(struct iwl_trans *trans); +int iwl_pcie_dump_fh(struct iwl_trans *trans, char **buf); +void iwl_pcie_dump_csr(struct iwl_trans *trans); /***************************************************** * Helpers @@ -397,7 +399,7 @@ static inline void iwl_enable_rfkill_int(struct iwl_trans *trans) } static inline void iwl_wake_queue(struct iwl_trans *trans, - struct iwl_tx_queue *txq) + struct iwl_txq *txq) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); @@ -408,7 +410,7 @@ static inline void iwl_wake_queue(struct iwl_trans *trans, } static inline void iwl_stop_queue(struct iwl_trans *trans, - struct iwl_tx_queue *txq) + struct iwl_txq *txq) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); @@ -420,7 +422,7 @@ static inline void iwl_stop_queue(struct iwl_trans *trans, txq->q.id); } -static inline int iwl_queue_used(const struct iwl_queue *q, int i) +static inline bool iwl_queue_used(const struct iwl_queue *q, int i) { return q->write_ptr >= q->read_ptr ? (i >= q->read_ptr && i < q->write_ptr) : @@ -432,8 +434,8 @@ static inline u8 get_cmd_index(struct iwl_queue *q, u32 index) return index & (q->n_window - 1); } -static inline const char * -trans_pcie_get_cmd_string(struct iwl_trans_pcie *trans_pcie, u8 cmd) +static inline const char *get_cmd_string(struct iwl_trans_pcie *trans_pcie, + u8 cmd) { if (!trans_pcie->command_names || !trans_pcie->command_names[cmd]) return "UNKNOWN"; diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c index 11a93ed..bb32510 100644 --- a/drivers/net/wireless/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/iwlwifi/pcie/rx.c @@ -76,7 +76,7 @@ * + A list of pre-allocated SKBs is stored in iwl->rxq->rx_free. When * iwl->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled * to replenish the iwl->rxq->rx_free. - * + In iwl_rx_replenish (scheduled) if 'processed' != 'read' then the + * + In iwl_pcie_rx_replenish (scheduled) if 'processed' != 'read' then the * iwl->rxq is replenished and the READ INDEX is updated (updating the * 'processed' and 'read' driver indexes as well) * + A received packet is processed and handed to the kernel network stack, @@ -89,28 +89,28 @@ * * Driver sequence: * - * iwl_rx_queue_alloc() Allocates rx_free - * iwl_rx_replenish() Replenishes rx_free list from rx_used, and calls - * iwl_rx_queue_restock - * iwl_rx_queue_restock() Moves available buffers from rx_free into Rx + * iwl_rxq_alloc() Allocates rx_free + * iwl_pcie_rx_replenish() Replenishes rx_free list from rx_used, and calls + * iwl_pcie_rxq_restock + * iwl_pcie_rxq_restock() Moves available buffers from rx_free into Rx * queue, updates firmware pointers, and updates * the WRITE index. If insufficient rx_free buffers - * are available, schedules iwl_rx_replenish + * are available, schedules iwl_pcie_rx_replenish * * -- enable interrupts -- - * ISR - iwl_rx() Detach iwl_rx_mem_buffers from pool up to the + * ISR - iwl_rx() Detach iwl_rx_mem_buffers from pool up to the * READ INDEX, detaching the SKB from the pool. * Moves the packet buffer from queue to rx_used. - * Calls iwl_rx_queue_restock to refill any empty + * Calls iwl_pcie_rxq_restock to refill any empty * slots. * ... * */ -/** - * iwl_rx_queue_space - Return number of free slots available in queue. +/* + * iwl_rxq_space - Return number of free slots available in queue. */ -static int iwl_rx_queue_space(const struct iwl_rx_queue *q) +static int iwl_rxq_space(const struct iwl_rxq *q) { int s = q->read - q->write; if (s <= 0) @@ -122,11 +122,28 @@ static int iwl_rx_queue_space(const struct iwl_rx_queue *q) return s; } -/** - * iwl_rx_queue_update_write_ptr - Update the write pointer for the RX queue +/* + * iwl_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer ptr + */ +static inline __le32 iwl_pcie_dma_addr2rbd_ptr(dma_addr_t dma_addr) +{ + return cpu_to_le32((u32)(dma_addr >> 8)); +} + +/* + * iwl_pcie_rx_stop - stops the Rx DMA + */ +int iwl_pcie_rx_stop(struct iwl_trans *trans) +{ + iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); + return iwl_poll_direct_bit(trans, FH_MEM_RSSR_RX_STATUS_REG, + FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, 1000); +} + +/* + * iwl_pcie_rxq_inc_wr_ptr - Update the write pointer for the RX queue */ -void iwl_rx_queue_update_write_ptr(struct iwl_trans *trans, - struct iwl_rx_queue *q) +static void iwl_pcie_rxq_inc_wr_ptr(struct iwl_trans *trans, struct iwl_rxq *q) { unsigned long flags; u32 reg; @@ -176,16 +193,8 @@ void iwl_rx_queue_update_write_ptr(struct iwl_trans *trans, spin_unlock_irqrestore(&q->lock, flags); } -/** - * iwl_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer ptr - */ -static inline __le32 iwl_dma_addr2rbd_ptr(dma_addr_t dma_addr) -{ - return cpu_to_le32((u32)(dma_addr >> 8)); -} - -/** - * iwl_rx_queue_restock - refill RX queue from pre-allocated pool +/* + * iwl_pcie_rxq_restock - refill RX queue from pre-allocated pool * * If there are slots in the RX queue that need to be restocked, * and we have free pre-allocated buffers, fill the ranks as much @@ -195,10 +204,10 @@ static inline __le32 iwl_dma_addr2rbd_ptr(dma_addr_t dma_addr) * also updates the memory address in the firmware to reference the new * target buffer. */ -static void iwl_rx_queue_restock(struct iwl_trans *trans) +static void iwl_pcie_rxq_restock(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_rx_queue *rxq = &trans_pcie->rxq; + struct iwl_rxq *rxq = &trans_pcie->rxq; struct iwl_rx_mem_buffer *rxb; unsigned long flags; @@ -214,7 +223,7 @@ static void iwl_rx_queue_restock(struct iwl_trans *trans) return; spin_lock_irqsave(&rxq->lock, flags); - while ((iwl_rx_queue_space(rxq) > 0) && (rxq->free_count)) { + while ((iwl_rxq_space(rxq) > 0) && (rxq->free_count)) { /* The overwritten rxb must be a used one */ rxb = rxq->queue[rxq->write]; BUG_ON(rxb && rxb->page); @@ -225,7 +234,7 @@ static void iwl_rx_queue_restock(struct iwl_trans *trans) list_del(&rxb->list); /* Point to Rx buffer via next RBD in circular buffer */ - rxq->bd[rxq->write] = iwl_dma_addr2rbd_ptr(rxb->page_dma); + rxq->bd[rxq->write] = iwl_pcie_dma_addr2rbd_ptr(rxb->page_dma); rxq->queue[rxq->write] = rxb; rxq->write = (rxq->write + 1) & RX_QUEUE_MASK; rxq->free_count--; @@ -242,23 +251,23 @@ static void iwl_rx_queue_restock(struct iwl_trans *trans) spin_lock_irqsave(&rxq->lock, flags); rxq->need_update = 1; spin_unlock_irqrestore(&rxq->lock, flags); - iwl_rx_queue_update_write_ptr(trans, rxq); + iwl_pcie_rxq_inc_wr_ptr(trans, rxq); } } /* - * iwl_rx_allocate - allocate a page for each used RBD + * iwl_pcie_rxq_alloc_rbs - allocate a page for each used RBD * * A used RBD is an Rx buffer that has been given to the stack. To use it again * a page must be allocated and the RBD must point to the page. This function * doesn't change the HW pointer but handles the list of pages that is used by - * iwl_rx_queue_restock. The latter function will update the HW to use the newly + * iwl_pcie_rxq_restock. The latter function will update the HW to use the newly * allocated buffers. */ -static void iwl_rx_allocate(struct iwl_trans *trans, gfp_t priority) +static void iwl_pcie_rxq_alloc_rbs(struct iwl_trans *trans, gfp_t priority) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_rx_queue *rxq = &trans_pcie->rxq; + struct iwl_rxq *rxq = &trans_pcie->rxq; struct iwl_rx_mem_buffer *rxb; struct page *page; unsigned long flags; @@ -318,6 +327,14 @@ static void iwl_rx_allocate(struct iwl_trans *trans, gfp_t priority) dma_map_page(trans->dev, page, 0, PAGE_SIZE << trans_pcie->rx_page_order, DMA_FROM_DEVICE); + if (dma_mapping_error(trans->dev, rxb->page_dma)) { + rxb->page = NULL; + spin_lock_irqsave(&rxq->lock, flags); + list_add(&rxb->list, &rxq->rx_used); + spin_unlock_irqrestore(&rxq->lock, flags); + __free_pages(page, trans_pcie->rx_page_order); + return; + } /* dma address must be no more than 36 bits */ BUG_ON(rxb->page_dma & ~DMA_BIT_MASK(36)); /* and also 256 byte aligned! */ @@ -332,47 +349,227 @@ static void iwl_rx_allocate(struct iwl_trans *trans, gfp_t priority) } } +static void iwl_pcie_rxq_free_rbs(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_rxq *rxq = &trans_pcie->rxq; + int i; + + /* Fill the rx_used queue with _all_ of the Rx buffers */ + for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) { + /* In the reset function, these buffers may have been allocated + * to an SKB, so we need to unmap and free potential storage */ + if (rxq->pool[i].page != NULL) { + dma_unmap_page(trans->dev, rxq->pool[i].page_dma, + PAGE_SIZE << trans_pcie->rx_page_order, + DMA_FROM_DEVICE); + __free_pages(rxq->pool[i].page, + trans_pcie->rx_page_order); + rxq->pool[i].page = NULL; + } + list_add_tail(&rxq->pool[i].list, &rxq->rx_used); + } +} + /* - * iwl_rx_replenish - Move all used buffers from rx_used to rx_free + * iwl_pcie_rx_replenish - Move all used buffers from rx_used to rx_free * * When moving to rx_free an page is allocated for the slot. * - * Also restock the Rx queue via iwl_rx_queue_restock. + * Also restock the Rx queue via iwl_pcie_rxq_restock. * This is called as a scheduled work item (except for during initialization) */ -void iwl_rx_replenish(struct iwl_trans *trans) +static void iwl_pcie_rx_replenish(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); unsigned long flags; - iwl_rx_allocate(trans, GFP_KERNEL); + iwl_pcie_rxq_alloc_rbs(trans, GFP_KERNEL); spin_lock_irqsave(&trans_pcie->irq_lock, flags); - iwl_rx_queue_restock(trans); + iwl_pcie_rxq_restock(trans); spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); } -static void iwl_rx_replenish_now(struct iwl_trans *trans) +static void iwl_pcie_rx_replenish_now(struct iwl_trans *trans) { - iwl_rx_allocate(trans, GFP_ATOMIC); + iwl_pcie_rxq_alloc_rbs(trans, GFP_ATOMIC); - iwl_rx_queue_restock(trans); + iwl_pcie_rxq_restock(trans); } -void iwl_bg_rx_replenish(struct work_struct *data) +static void iwl_pcie_rx_replenish_work(struct work_struct *data) { struct iwl_trans_pcie *trans_pcie = container_of(data, struct iwl_trans_pcie, rx_replenish); - iwl_rx_replenish(trans_pcie->trans); + iwl_pcie_rx_replenish(trans_pcie->trans); +} + +static int iwl_pcie_rx_alloc(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_rxq *rxq = &trans_pcie->rxq; + struct device *dev = trans->dev; + + memset(&trans_pcie->rxq, 0, sizeof(trans_pcie->rxq)); + + spin_lock_init(&rxq->lock); + + if (WARN_ON(rxq->bd || rxq->rb_stts)) + return -EINVAL; + + /* Allocate the circular buffer of Read Buffer Descriptors (RBDs) */ + rxq->bd = dma_zalloc_coherent(dev, sizeof(__le32) * RX_QUEUE_SIZE, + &rxq->bd_dma, GFP_KERNEL); + if (!rxq->bd) + goto err_bd; + + /*Allocate the driver's pointer to receive buffer status */ + rxq->rb_stts = dma_zalloc_coherent(dev, sizeof(*rxq->rb_stts), + &rxq->rb_stts_dma, GFP_KERNEL); + if (!rxq->rb_stts) + goto err_rb_stts; + + return 0; + +err_rb_stts: + dma_free_coherent(dev, sizeof(__le32) * RX_QUEUE_SIZE, + rxq->bd, rxq->bd_dma); + memset(&rxq->bd_dma, 0, sizeof(rxq->bd_dma)); + rxq->bd = NULL; +err_bd: + return -ENOMEM; } -static void iwl_rx_handle_rxbuf(struct iwl_trans *trans, +static void iwl_pcie_rx_hw_init(struct iwl_trans *trans, struct iwl_rxq *rxq) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + u32 rb_size; + const u32 rfdnlog = RX_QUEUE_SIZE_LOG; /* 256 RBDs */ + + if (trans_pcie->rx_buf_size_8k) + rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K; + else + rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K; + + /* Stop Rx DMA */ + iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); + + /* Reset driver's Rx queue write index */ + iwl_write_direct32(trans, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0); + + /* Tell device where to find RBD circular buffer in DRAM */ + iwl_write_direct32(trans, FH_RSCSR_CHNL0_RBDCB_BASE_REG, + (u32)(rxq->bd_dma >> 8)); + + /* Tell device where in DRAM to update its Rx status */ + iwl_write_direct32(trans, FH_RSCSR_CHNL0_STTS_WPTR_REG, + rxq->rb_stts_dma >> 4); + + /* Enable Rx DMA + * FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY is set because of HW bug in + * the credit mechanism in 5000 HW RX FIFO + * Direct rx interrupts to hosts + * Rx buffer size 4 or 8k + * RB timeout 0x10 + * 256 RBDs + */ + iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_CONFIG_REG, + FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL | + FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY | + FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL | + rb_size| + (RX_RB_TIMEOUT << FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS)| + (rfdnlog << FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS)); + + /* Set interrupt coalescing timer to default (2048 usecs) */ + iwl_write8(trans, CSR_INT_COALESCING, IWL_HOST_INT_TIMEOUT_DEF); +} + +int iwl_pcie_rx_init(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_rxq *rxq = &trans_pcie->rxq; + + int i, err; + unsigned long flags; + + if (!rxq->bd) { + err = iwl_pcie_rx_alloc(trans); + if (err) + return err; + } + + spin_lock_irqsave(&rxq->lock, flags); + INIT_LIST_HEAD(&rxq->rx_free); + INIT_LIST_HEAD(&rxq->rx_used); + + INIT_WORK(&trans_pcie->rx_replenish, + iwl_pcie_rx_replenish_work); + + iwl_pcie_rxq_free_rbs(trans); + + for (i = 0; i < RX_QUEUE_SIZE; i++) + rxq->queue[i] = NULL; + + /* Set us so that we have processed and used all buffers, but have + * not restocked the Rx queue with fresh buffers */ + rxq->read = rxq->write = 0; + rxq->write_actual = 0; + rxq->free_count = 0; + spin_unlock_irqrestore(&rxq->lock, flags); + + iwl_pcie_rx_replenish(trans); + + iwl_pcie_rx_hw_init(trans, rxq); + + spin_lock_irqsave(&trans_pcie->irq_lock, flags); + rxq->need_update = 1; + iwl_pcie_rxq_inc_wr_ptr(trans, rxq); + spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); + + return 0; +} + +void iwl_pcie_rx_free(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_rxq *rxq = &trans_pcie->rxq; + unsigned long flags; + + /*if rxq->bd is NULL, it means that nothing has been allocated, + * exit now */ + if (!rxq->bd) { + IWL_DEBUG_INFO(trans, "Free NULL rx context\n"); + return; + } + + spin_lock_irqsave(&rxq->lock, flags); + iwl_pcie_rxq_free_rbs(trans); + spin_unlock_irqrestore(&rxq->lock, flags); + + dma_free_coherent(trans->dev, sizeof(__le32) * RX_QUEUE_SIZE, + rxq->bd, rxq->bd_dma); + memset(&rxq->bd_dma, 0, sizeof(rxq->bd_dma)); + rxq->bd = NULL; + + if (rxq->rb_stts) + dma_free_coherent(trans->dev, + sizeof(struct iwl_rb_status), + rxq->rb_stts, rxq->rb_stts_dma); + else + IWL_DEBUG_INFO(trans, "Free rxq->rb_stts which is NULL\n"); + memset(&rxq->rb_stts_dma, 0, sizeof(rxq->rb_stts_dma)); + rxq->rb_stts = NULL; +} + +static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans, struct iwl_rx_mem_buffer *rxb) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_rx_queue *rxq = &trans_pcie->rxq; - struct iwl_tx_queue *txq = &trans_pcie->txq[trans_pcie->cmd_queue]; + struct iwl_rxq *rxq = &trans_pcie->rxq; + struct iwl_txq *txq = &trans_pcie->txq[trans_pcie->cmd_queue]; unsigned long flags; bool page_stolen = false; int max_len = PAGE_SIZE << trans_pcie->rx_page_order; @@ -402,8 +599,7 @@ static void iwl_rx_handle_rxbuf(struct iwl_trans *trans, break; IWL_DEBUG_RX(trans, "cmd at offset %d: %s (0x%.2x)\n", - rxcb._offset, - trans_pcie_get_cmd_string(trans_pcie, pkt->hdr.cmd), + rxcb._offset, get_cmd_string(trans_pcie, pkt->hdr.cmd), pkt->hdr.cmd); len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; @@ -435,7 +631,7 @@ static void iwl_rx_handle_rxbuf(struct iwl_trans *trans, cmd_index = get_cmd_index(&txq->q, index); if (reclaim) { - struct iwl_pcie_tx_queue_entry *ent; + struct iwl_pcie_txq_entry *ent; ent = &txq->entries[cmd_index]; cmd = ent->copy_cmd; WARN_ON_ONCE(!cmd && ent->meta.flags & CMD_WANT_HCMD); @@ -465,7 +661,7 @@ static void iwl_rx_handle_rxbuf(struct iwl_trans *trans, * iwl_trans_send_cmd() * as we reclaim the driver command queue */ if (!rxcb._page_stolen) - iwl_tx_cmd_complete(trans, &rxcb, err); + iwl_pcie_hcmd_complete(trans, &rxcb, err); else IWL_WARN(trans, "Claim null rxb?\n"); } @@ -489,24 +685,31 @@ static void iwl_rx_handle_rxbuf(struct iwl_trans *trans, dma_map_page(trans->dev, rxb->page, 0, PAGE_SIZE << trans_pcie->rx_page_order, DMA_FROM_DEVICE); - list_add_tail(&rxb->list, &rxq->rx_free); - rxq->free_count++; + if (dma_mapping_error(trans->dev, rxb->page_dma)) { + /* + * free the page(s) as well to not break + * the invariant that the items on the used + * list have no page(s) + */ + __free_pages(rxb->page, trans_pcie->rx_page_order); + rxb->page = NULL; + list_add_tail(&rxb->list, &rxq->rx_used); + } else { + list_add_tail(&rxb->list, &rxq->rx_free); + rxq->free_count++; + } } else list_add_tail(&rxb->list, &rxq->rx_used); spin_unlock_irqrestore(&rxq->lock, flags); } -/** - * iwl_rx_handle - Main entry function for receiving responses from uCode - * - * Uses the priv->rx_handlers callback function array to invoke - * the appropriate handlers, including command responses, - * frame-received notifications, and other notifications. +/* + * iwl_pcie_rx_handle - Main entry function for receiving responses from fw */ -static void iwl_rx_handle(struct iwl_trans *trans) +static void iwl_pcie_rx_handle(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_rx_queue *rxq = &trans_pcie->rxq; + struct iwl_rxq *rxq = &trans_pcie->rxq; u32 r, i; u8 fill_rx = 0; u32 count = 8; @@ -537,7 +740,7 @@ static void iwl_rx_handle(struct iwl_trans *trans) IWL_DEBUG_RX(trans, "rxbuf: HW = %d, SW = %d (%p)\n", r, i, rxb); - iwl_rx_handle_rxbuf(trans, rxb); + iwl_pcie_rx_handle_rb(trans, rxb); i = (i + 1) & RX_QUEUE_MASK; /* If there are a lot of unused frames, @@ -546,7 +749,7 @@ static void iwl_rx_handle(struct iwl_trans *trans) count++; if (count >= 8) { rxq->read = i; - iwl_rx_replenish_now(trans); + iwl_pcie_rx_replenish_now(trans); count = 0; } } @@ -555,15 +758,15 @@ static void iwl_rx_handle(struct iwl_trans *trans) /* Backtrack one entry */ rxq->read = i; if (fill_rx) - iwl_rx_replenish_now(trans); + iwl_pcie_rx_replenish_now(trans); else - iwl_rx_queue_restock(trans); + iwl_pcie_rxq_restock(trans); } -/** - * iwl_irq_handle_error - called for HW or SW error interrupt from card +/* + * iwl_pcie_irq_handle_error - called for HW or SW error interrupt from card */ -static void iwl_irq_handle_error(struct iwl_trans *trans) +static void iwl_pcie_irq_handle_error(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); @@ -579,8 +782,8 @@ static void iwl_irq_handle_error(struct iwl_trans *trans) return; } - iwl_dump_csr(trans); - iwl_dump_fh(trans, NULL); + iwl_pcie_dump_csr(trans); + iwl_pcie_dump_fh(trans, NULL); set_bit(STATUS_FW_ERROR, &trans_pcie->status); clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status); @@ -589,8 +792,7 @@ static void iwl_irq_handle_error(struct iwl_trans *trans) iwl_op_mode_nic_error(trans->op_mode); } -/* tasklet for iwlagn interrupt */ -void iwl_irq_tasklet(struct iwl_trans *trans) +void iwl_pcie_tasklet(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct isr_statistics *isr_stats = &trans_pcie->isr_stats; @@ -642,7 +844,7 @@ void iwl_irq_tasklet(struct iwl_trans *trans) iwl_disable_interrupts(trans); isr_stats->hw++; - iwl_irq_handle_error(trans); + iwl_pcie_irq_handle_error(trans); handled |= CSR_INT_BIT_HW_ERR; @@ -705,17 +907,16 @@ void iwl_irq_tasklet(struct iwl_trans *trans) IWL_ERR(trans, "Microcode SW error detected. " " Restarting 0x%X.\n", inta); isr_stats->sw++; - iwl_irq_handle_error(trans); + iwl_pcie_irq_handle_error(trans); handled |= CSR_INT_BIT_SW_ERR; } /* uCode wakes up after power-down sleep */ if (inta & CSR_INT_BIT_WAKEUP) { IWL_DEBUG_ISR(trans, "Wakeup interrupt\n"); - iwl_rx_queue_update_write_ptr(trans, &trans_pcie->rxq); + iwl_pcie_rxq_inc_wr_ptr(trans, &trans_pcie->rxq); for (i = 0; i < trans->cfg->base_params->num_of_queues; i++) - iwl_txq_update_write_ptr(trans, - &trans_pcie->txq[i]); + iwl_pcie_txq_inc_wr_ptr(trans, &trans_pcie->txq[i]); isr_stats->wakeup++; @@ -753,7 +954,7 @@ void iwl_irq_tasklet(struct iwl_trans *trans) iwl_write8(trans, CSR_INT_PERIODIC_REG, CSR_INT_PERIODIC_DIS); - iwl_rx_handle(trans); + iwl_pcie_rx_handle(trans); /* * Enable periodic interrupt in 8 msec only if we received @@ -811,7 +1012,7 @@ void iwl_irq_tasklet(struct iwl_trans *trans) #define ICT_COUNT (ICT_SIZE / sizeof(u32)) /* Free dram table */ -void iwl_free_isr_ict(struct iwl_trans *trans) +void iwl_pcie_free_ict(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); @@ -824,13 +1025,12 @@ void iwl_free_isr_ict(struct iwl_trans *trans) } } - /* * allocate dram shared table, it is an aligned memory * block of ICT_SIZE. * also reset all data related to ICT table interrupt. */ -int iwl_alloc_isr_ict(struct iwl_trans *trans) +int iwl_pcie_alloc_ict(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); @@ -843,7 +1043,7 @@ int iwl_alloc_isr_ict(struct iwl_trans *trans) /* just an API sanity check ... it is guaranteed to be aligned */ if (WARN_ON(trans_pcie->ict_tbl_dma & (ICT_SIZE - 1))) { - iwl_free_isr_ict(trans); + iwl_pcie_free_ict(trans); return -EINVAL; } @@ -864,7 +1064,7 @@ int iwl_alloc_isr_ict(struct iwl_trans *trans) /* Device is going up inform it about using ICT interrupt table, * also we need to tell the driver to start using ICT interrupt. */ -void iwl_reset_ict(struct iwl_trans *trans) +void iwl_pcie_reset_ict(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); u32 val; @@ -894,7 +1094,7 @@ void iwl_reset_ict(struct iwl_trans *trans) } /* Device is going down disable ict interrupt usage */ -void iwl_disable_ict(struct iwl_trans *trans) +void iwl_pcie_disable_ict(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); unsigned long flags; @@ -905,7 +1105,7 @@ void iwl_disable_ict(struct iwl_trans *trans) } /* legacy (non-ICT) ISR. Assumes that trans_pcie->irq_lock is held */ -static irqreturn_t iwl_isr(int irq, void *data) +static irqreturn_t iwl_pcie_isr(int irq, void *data) { struct iwl_trans *trans = data; struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); @@ -952,7 +1152,7 @@ static irqreturn_t iwl_isr(int irq, void *data) #endif trans_pcie->inta |= inta; - /* iwl_irq_tasklet() will service interrupts and re-enable them */ + /* iwl_pcie_tasklet() will service interrupts and re-enable them */ if (likely(inta)) tasklet_schedule(&trans_pcie->irq_tasklet); else if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) && @@ -977,7 +1177,7 @@ none: * the interrupt we need to service, driver will set the entries back to 0 and * set index. */ -irqreturn_t iwl_isr_ict(int irq, void *data) +irqreturn_t iwl_pcie_isr_ict(int irq, void *data) { struct iwl_trans *trans = data; struct iwl_trans_pcie *trans_pcie; @@ -997,14 +1197,13 @@ irqreturn_t iwl_isr_ict(int irq, void *data) * use legacy interrupt. */ if (unlikely(!trans_pcie->use_ict)) { - irqreturn_t ret = iwl_isr(irq, data); + irqreturn_t ret = iwl_pcie_isr(irq, data); spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); return ret; } trace_iwlwifi_dev_irq(trans->dev); - /* Disable (but don't clear!) interrupts here to avoid * back-to-back ISRs and sporadic interrupts from our NIC. * If we have something to service, the tasklet will re-enable ints. @@ -1013,7 +1212,6 @@ irqreturn_t iwl_isr_ict(int irq, void *data) inta_mask = iwl_read32(trans, CSR_INT_MASK); /* just for debug */ iwl_write32(trans, CSR_INT_MASK, 0x00000000); - /* Ignore interrupt if there's nothing in NIC to service. * This may be due to IRQ shared with another device, * or due to sporadic interrupts thrown from our NIC. */ @@ -1062,7 +1260,7 @@ irqreturn_t iwl_isr_ict(int irq, void *data) inta &= trans_pcie->inta_mask; trans_pcie->inta |= inta; - /* iwl_irq_tasklet() will service interrupts and re-enable them */ + /* iwl_pcie_tasklet() will service interrupts and re-enable them */ if (likely(inta)) tasklet_schedule(&trans_pcie->irq_tasklet); else if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) && diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index f21bf66..f6c21e7 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -74,585 +74,8 @@ #include "iwl-prph.h" #include "iwl-agn-hw.h" #include "internal.h" -/* FIXME: need to abstract out TX command (once we know what it looks like) */ -#include "dvm/commands.h" -#define SCD_QUEUECHAIN_SEL_ALL(trans, trans_pcie) \ - (((1<<trans->cfg->base_params->num_of_queues) - 1) &\ - (~(1<<(trans_pcie)->cmd_queue))) - -static int iwl_trans_rx_alloc(struct iwl_trans *trans) -{ - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_rx_queue *rxq = &trans_pcie->rxq; - struct device *dev = trans->dev; - - memset(&trans_pcie->rxq, 0, sizeof(trans_pcie->rxq)); - - spin_lock_init(&rxq->lock); - - if (WARN_ON(rxq->bd || rxq->rb_stts)) - return -EINVAL; - - /* Allocate the circular buffer of Read Buffer Descriptors (RBDs) */ - rxq->bd = dma_zalloc_coherent(dev, sizeof(__le32) * RX_QUEUE_SIZE, - &rxq->bd_dma, GFP_KERNEL); - if (!rxq->bd) - goto err_bd; - - /*Allocate the driver's pointer to receive buffer status */ - rxq->rb_stts = dma_zalloc_coherent(dev, sizeof(*rxq->rb_stts), - &rxq->rb_stts_dma, GFP_KERNEL); - if (!rxq->rb_stts) - goto err_rb_stts; - - return 0; - -err_rb_stts: - dma_free_coherent(dev, sizeof(__le32) * RX_QUEUE_SIZE, - rxq->bd, rxq->bd_dma); - memset(&rxq->bd_dma, 0, sizeof(rxq->bd_dma)); - rxq->bd = NULL; -err_bd: - return -ENOMEM; -} - -static void iwl_trans_rxq_free_rx_bufs(struct iwl_trans *trans) -{ - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_rx_queue *rxq = &trans_pcie->rxq; - int i; - - /* Fill the rx_used queue with _all_ of the Rx buffers */ - for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) { - /* In the reset function, these buffers may have been allocated - * to an SKB, so we need to unmap and free potential storage */ - if (rxq->pool[i].page != NULL) { - dma_unmap_page(trans->dev, rxq->pool[i].page_dma, - PAGE_SIZE << trans_pcie->rx_page_order, - DMA_FROM_DEVICE); - __free_pages(rxq->pool[i].page, - trans_pcie->rx_page_order); - rxq->pool[i].page = NULL; - } - list_add_tail(&rxq->pool[i].list, &rxq->rx_used); - } -} - -static void iwl_trans_rx_hw_init(struct iwl_trans *trans, - struct iwl_rx_queue *rxq) -{ - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - u32 rb_size; - const u32 rfdnlog = RX_QUEUE_SIZE_LOG; /* 256 RBDs */ - u32 rb_timeout = RX_RB_TIMEOUT; /* FIXME: RX_RB_TIMEOUT for all devices? */ - - if (trans_pcie->rx_buf_size_8k) - rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K; - else - rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K; - - /* Stop Rx DMA */ - iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); - - /* Reset driver's Rx queue write index */ - iwl_write_direct32(trans, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0); - - /* Tell device where to find RBD circular buffer in DRAM */ - iwl_write_direct32(trans, FH_RSCSR_CHNL0_RBDCB_BASE_REG, - (u32)(rxq->bd_dma >> 8)); - - /* Tell device where in DRAM to update its Rx status */ - iwl_write_direct32(trans, FH_RSCSR_CHNL0_STTS_WPTR_REG, - rxq->rb_stts_dma >> 4); - - /* Enable Rx DMA - * FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY is set because of HW bug in - * the credit mechanism in 5000 HW RX FIFO - * Direct rx interrupts to hosts - * Rx buffer size 4 or 8k - * RB timeout 0x10 - * 256 RBDs - */ - iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_CONFIG_REG, - FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL | - FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY | - FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL | - rb_size| - (rb_timeout << FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS)| - (rfdnlog << FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS)); - - /* Set interrupt coalescing timer to default (2048 usecs) */ - iwl_write8(trans, CSR_INT_COALESCING, IWL_HOST_INT_TIMEOUT_DEF); -} - -static int iwl_rx_init(struct iwl_trans *trans) -{ - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_rx_queue *rxq = &trans_pcie->rxq; - - int i, err; - unsigned long flags; - - if (!rxq->bd) { - err = iwl_trans_rx_alloc(trans); - if (err) - return err; - } - - spin_lock_irqsave(&rxq->lock, flags); - INIT_LIST_HEAD(&rxq->rx_free); - INIT_LIST_HEAD(&rxq->rx_used); - - iwl_trans_rxq_free_rx_bufs(trans); - - for (i = 0; i < RX_QUEUE_SIZE; i++) - rxq->queue[i] = NULL; - - /* Set us so that we have processed and used all buffers, but have - * not restocked the Rx queue with fresh buffers */ - rxq->read = rxq->write = 0; - rxq->write_actual = 0; - rxq->free_count = 0; - spin_unlock_irqrestore(&rxq->lock, flags); - - iwl_rx_replenish(trans); - - iwl_trans_rx_hw_init(trans, rxq); - - spin_lock_irqsave(&trans_pcie->irq_lock, flags); - rxq->need_update = 1; - iwl_rx_queue_update_write_ptr(trans, rxq); - spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); - - return 0; -} - -static void iwl_trans_pcie_rx_free(struct iwl_trans *trans) -{ - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_rx_queue *rxq = &trans_pcie->rxq; - unsigned long flags; - - /*if rxq->bd is NULL, it means that nothing has been allocated, - * exit now */ - if (!rxq->bd) { - IWL_DEBUG_INFO(trans, "Free NULL rx context\n"); - return; - } - - spin_lock_irqsave(&rxq->lock, flags); - iwl_trans_rxq_free_rx_bufs(trans); - spin_unlock_irqrestore(&rxq->lock, flags); - - dma_free_coherent(trans->dev, sizeof(__le32) * RX_QUEUE_SIZE, - rxq->bd, rxq->bd_dma); - memset(&rxq->bd_dma, 0, sizeof(rxq->bd_dma)); - rxq->bd = NULL; - - if (rxq->rb_stts) - dma_free_coherent(trans->dev, - sizeof(struct iwl_rb_status), - rxq->rb_stts, rxq->rb_stts_dma); - else - IWL_DEBUG_INFO(trans, "Free rxq->rb_stts which is NULL\n"); - memset(&rxq->rb_stts_dma, 0, sizeof(rxq->rb_stts_dma)); - rxq->rb_stts = NULL; -} - -static int iwl_trans_rx_stop(struct iwl_trans *trans) -{ - - /* stop Rx DMA */ - iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); - return iwl_poll_direct_bit(trans, FH_MEM_RSSR_RX_STATUS_REG, - FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, 1000); -} - -static int iwlagn_alloc_dma_ptr(struct iwl_trans *trans, - struct iwl_dma_ptr *ptr, size_t size) -{ - if (WARN_ON(ptr->addr)) - return -EINVAL; - - ptr->addr = dma_alloc_coherent(trans->dev, size, - &ptr->dma, GFP_KERNEL); - if (!ptr->addr) - return -ENOMEM; - ptr->size = size; - return 0; -} - -static void iwlagn_free_dma_ptr(struct iwl_trans *trans, - struct iwl_dma_ptr *ptr) -{ - if (unlikely(!ptr->addr)) - return; - - dma_free_coherent(trans->dev, ptr->size, ptr->addr, ptr->dma); - memset(ptr, 0, sizeof(*ptr)); -} - -static void iwl_trans_pcie_queue_stuck_timer(unsigned long data) -{ - struct iwl_tx_queue *txq = (void *)data; - struct iwl_queue *q = &txq->q; - struct iwl_trans_pcie *trans_pcie = txq->trans_pcie; - struct iwl_trans *trans = iwl_trans_pcie_get_trans(trans_pcie); - u32 scd_sram_addr = trans_pcie->scd_base_addr + - SCD_TX_STTS_QUEUE_OFFSET(txq->q.id); - u8 buf[16]; - int i; - - spin_lock(&txq->lock); - /* check if triggered erroneously */ - if (txq->q.read_ptr == txq->q.write_ptr) { - spin_unlock(&txq->lock); - return; - } - spin_unlock(&txq->lock); - - IWL_ERR(trans, "Queue %d stuck for %u ms.\n", txq->q.id, - jiffies_to_msecs(trans_pcie->wd_timeout)); - IWL_ERR(trans, "Current SW read_ptr %d write_ptr %d\n", - txq->q.read_ptr, txq->q.write_ptr); - - iwl_read_targ_mem_bytes(trans, scd_sram_addr, buf, sizeof(buf)); - - iwl_print_hex_error(trans, buf, sizeof(buf)); - - for (i = 0; i < FH_TCSR_CHNL_NUM; i++) - IWL_ERR(trans, "FH TRBs(%d) = 0x%08x\n", i, - iwl_read_direct32(trans, FH_TX_TRB_REG(i))); - - for (i = 0; i < trans->cfg->base_params->num_of_queues; i++) { - u32 status = iwl_read_prph(trans, SCD_QUEUE_STATUS_BITS(i)); - u8 fifo = (status >> SCD_QUEUE_STTS_REG_POS_TXF) & 0x7; - bool active = !!(status & BIT(SCD_QUEUE_STTS_REG_POS_ACTIVE)); - u32 tbl_dw = - iwl_read_targ_mem(trans, - trans_pcie->scd_base_addr + - SCD_TRANS_TBL_OFFSET_QUEUE(i)); - - if (i & 0x1) - tbl_dw = (tbl_dw & 0xFFFF0000) >> 16; - else - tbl_dw = tbl_dw & 0x0000FFFF; - - IWL_ERR(trans, - "Q %d is %sactive and mapped to fifo %d ra_tid 0x%04x [%d,%d]\n", - i, active ? "" : "in", fifo, tbl_dw, - iwl_read_prph(trans, - SCD_QUEUE_RDPTR(i)) & (txq->q.n_bd - 1), - iwl_read_prph(trans, SCD_QUEUE_WRPTR(i))); - } - - for (i = q->read_ptr; i != q->write_ptr; - i = iwl_queue_inc_wrap(i, q->n_bd)) { - struct iwl_tx_cmd *tx_cmd = - (struct iwl_tx_cmd *)txq->entries[i].cmd->payload; - IWL_ERR(trans, "scratch %d = 0x%08x\n", i, - get_unaligned_le32(&tx_cmd->scratch)); - } - - iwl_op_mode_nic_error(trans->op_mode); -} - -static int iwl_trans_txq_alloc(struct iwl_trans *trans, - struct iwl_tx_queue *txq, int slots_num, - u32 txq_id) -{ - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - size_t tfd_sz = sizeof(struct iwl_tfd) * TFD_QUEUE_SIZE_MAX; - int i; - - if (WARN_ON(txq->entries || txq->tfds)) - return -EINVAL; - - setup_timer(&txq->stuck_timer, iwl_trans_pcie_queue_stuck_timer, - (unsigned long)txq); - txq->trans_pcie = trans_pcie; - - txq->q.n_window = slots_num; - - txq->entries = kcalloc(slots_num, - sizeof(struct iwl_pcie_tx_queue_entry), - GFP_KERNEL); - - if (!txq->entries) - goto error; - - if (txq_id == trans_pcie->cmd_queue) - for (i = 0; i < slots_num; i++) { - txq->entries[i].cmd = - kmalloc(sizeof(struct iwl_device_cmd), - GFP_KERNEL); - if (!txq->entries[i].cmd) - goto error; - } - - /* Circular buffer of transmit frame descriptors (TFDs), - * shared with device */ - txq->tfds = dma_alloc_coherent(trans->dev, tfd_sz, - &txq->q.dma_addr, GFP_KERNEL); - if (!txq->tfds) { - IWL_ERR(trans, "dma_alloc_coherent(%zd) failed\n", tfd_sz); - goto error; - } - txq->q.id = txq_id; - - return 0; -error: - if (txq->entries && txq_id == trans_pcie->cmd_queue) - for (i = 0; i < slots_num; i++) - kfree(txq->entries[i].cmd); - kfree(txq->entries); - txq->entries = NULL; - - return -ENOMEM; - -} - -static int iwl_trans_txq_init(struct iwl_trans *trans, struct iwl_tx_queue *txq, - int slots_num, u32 txq_id) -{ - int ret; - - txq->need_update = 0; - - /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise - * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */ - BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1)); - - /* Initialize queue's high/low-water marks, and head/tail indexes */ - ret = iwl_queue_init(&txq->q, TFD_QUEUE_SIZE_MAX, slots_num, - txq_id); - if (ret) - return ret; - - spin_lock_init(&txq->lock); - - /* - * Tell nic where to find circular buffer of Tx Frame Descriptors for - * given Tx queue, and enable the DMA channel used for that queue. - * Circular buffer (TFD queue in DRAM) physical base address */ - iwl_write_direct32(trans, FH_MEM_CBBC_QUEUE(txq_id), - txq->q.dma_addr >> 8); - - return 0; -} - -/* - * iwl_tx_queue_unmap - Unmap any remaining DMA mappings and free skb's - */ -void iwl_tx_queue_unmap(struct iwl_trans *trans, int txq_id) -{ - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id]; - struct iwl_queue *q = &txq->q; - enum dma_data_direction dma_dir; - - if (!q->n_bd) - return; - - /* In the command queue, all the TBs are mapped as BIDI - * so unmap them as such. - */ - if (txq_id == trans_pcie->cmd_queue) - dma_dir = DMA_BIDIRECTIONAL; - else - dma_dir = DMA_TO_DEVICE; - - spin_lock_bh(&txq->lock); - while (q->write_ptr != q->read_ptr) { - iwl_txq_free_tfd(trans, txq, dma_dir); - q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd); - } - spin_unlock_bh(&txq->lock); -} - -/** - * iwl_tx_queue_free - Deallocate DMA queue. - * @txq: Transmit queue to deallocate. - * - * Empty queue by removing and destroying all BD's. - * Free all buffers. - * 0-fill, but do not free "txq" descriptor structure. - */ -static void iwl_tx_queue_free(struct iwl_trans *trans, int txq_id) -{ - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id]; - struct device *dev = trans->dev; - int i; - - if (WARN_ON(!txq)) - return; - - iwl_tx_queue_unmap(trans, txq_id); - - /* De-alloc array of command/tx buffers */ - if (txq_id == trans_pcie->cmd_queue) - for (i = 0; i < txq->q.n_window; i++) { - kfree(txq->entries[i].cmd); - kfree(txq->entries[i].copy_cmd); - kfree(txq->entries[i].free_buf); - } - - /* De-alloc circular buffer of TFDs */ - if (txq->q.n_bd) { - dma_free_coherent(dev, sizeof(struct iwl_tfd) * - txq->q.n_bd, txq->tfds, txq->q.dma_addr); - memset(&txq->q.dma_addr, 0, sizeof(txq->q.dma_addr)); - } - - kfree(txq->entries); - txq->entries = NULL; - - del_timer_sync(&txq->stuck_timer); - - /* 0-fill queue descriptor structure */ - memset(txq, 0, sizeof(*txq)); -} - -/** - * iwl_trans_tx_free - Free TXQ Context - * - * Destroy all TX DMA queues and structures - */ -static void iwl_trans_pcie_tx_free(struct iwl_trans *trans) -{ - int txq_id; - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - - /* Tx queues */ - if (trans_pcie->txq) { - for (txq_id = 0; - txq_id < trans->cfg->base_params->num_of_queues; txq_id++) - iwl_tx_queue_free(trans, txq_id); - } - - kfree(trans_pcie->txq); - trans_pcie->txq = NULL; - - iwlagn_free_dma_ptr(trans, &trans_pcie->kw); - - iwlagn_free_dma_ptr(trans, &trans_pcie->scd_bc_tbls); -} - -/** - * iwl_trans_tx_alloc - allocate TX context - * Allocate all Tx DMA structures and initialize them - * - * @param priv - * @return error code - */ -static int iwl_trans_tx_alloc(struct iwl_trans *trans) -{ - int ret; - int txq_id, slots_num; - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - - u16 scd_bc_tbls_size = trans->cfg->base_params->num_of_queues * - sizeof(struct iwlagn_scd_bc_tbl); - - /*It is not allowed to alloc twice, so warn when this happens. - * We cannot rely on the previous allocation, so free and fail */ - if (WARN_ON(trans_pcie->txq)) { - ret = -EINVAL; - goto error; - } - - ret = iwlagn_alloc_dma_ptr(trans, &trans_pcie->scd_bc_tbls, - scd_bc_tbls_size); - if (ret) { - IWL_ERR(trans, "Scheduler BC Table allocation failed\n"); - goto error; - } - - /* Alloc keep-warm buffer */ - ret = iwlagn_alloc_dma_ptr(trans, &trans_pcie->kw, IWL_KW_SIZE); - if (ret) { - IWL_ERR(trans, "Keep Warm allocation failed\n"); - goto error; - } - - trans_pcie->txq = kcalloc(trans->cfg->base_params->num_of_queues, - sizeof(struct iwl_tx_queue), GFP_KERNEL); - if (!trans_pcie->txq) { - IWL_ERR(trans, "Not enough memory for txq\n"); - ret = ENOMEM; - goto error; - } - - /* Alloc and init all Tx queues, including the command queue (#4/#9) */ - for (txq_id = 0; txq_id < trans->cfg->base_params->num_of_queues; - txq_id++) { - slots_num = (txq_id == trans_pcie->cmd_queue) ? - TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; - ret = iwl_trans_txq_alloc(trans, &trans_pcie->txq[txq_id], - slots_num, txq_id); - if (ret) { - IWL_ERR(trans, "Tx %d queue alloc failed\n", txq_id); - goto error; - } - } - - return 0; - -error: - iwl_trans_pcie_tx_free(trans); - - return ret; -} -static int iwl_tx_init(struct iwl_trans *trans) -{ - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - int ret; - int txq_id, slots_num; - unsigned long flags; - bool alloc = false; - - if (!trans_pcie->txq) { - ret = iwl_trans_tx_alloc(trans); - if (ret) - goto error; - alloc = true; - } - - spin_lock_irqsave(&trans_pcie->irq_lock, flags); - - /* Turn off all Tx DMA fifos */ - iwl_write_prph(trans, SCD_TXFACT, 0); - - /* Tell NIC where to find the "keep warm" buffer */ - iwl_write_direct32(trans, FH_KW_MEM_ADDR_REG, - trans_pcie->kw.dma >> 4); - - spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); - - /* Alloc and init all Tx queues, including the command queue (#4/#9) */ - for (txq_id = 0; txq_id < trans->cfg->base_params->num_of_queues; - txq_id++) { - slots_num = (txq_id == trans_pcie->cmd_queue) ? - TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; - ret = iwl_trans_txq_init(trans, &trans_pcie->txq[txq_id], - slots_num, txq_id); - if (ret) { - IWL_ERR(trans, "Tx %d queue init failed\n", txq_id); - goto error; - } - } - - return 0; -error: - /*Upon error, free only if we allocated something */ - if (alloc) - iwl_trans_pcie_tx_free(trans); - return ret; -} - -static void iwl_set_pwr_vmain(struct iwl_trans *trans) +static void iwl_pcie_set_pwr_vmain(struct iwl_trans *trans) { /* * (for documentation purposes) @@ -674,18 +97,11 @@ static void iwl_set_pwr_vmain(struct iwl_trans *trans) #define PCI_CFG_LINK_CTRL_VAL_L0S_EN 0x01 #define PCI_CFG_LINK_CTRL_VAL_L1_EN 0x02 -static u16 iwl_pciexp_link_ctrl(struct iwl_trans *trans) +static void iwl_pcie_apm_config(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - u16 pci_lnk_ctl; + u16 lctl; - pcie_capability_read_word(trans_pcie->pci_dev, PCI_EXP_LNKCTL, - &pci_lnk_ctl); - return pci_lnk_ctl; -} - -static void iwl_apm_config(struct iwl_trans *trans) -{ /* * HW bug W/A for instability in PCIe bus L0S->L1 transition. * Check if BIOS (or OS) enabled L1-ASPM on this device. @@ -694,7 +110,7 @@ static void iwl_apm_config(struct iwl_trans *trans) * If not (unlikely), enable L0S, so there is at least some * power savings, even without L1. */ - u16 lctl = iwl_pciexp_link_ctrl(trans); + pcie_capability_read_word(trans_pcie->pci_dev, PCI_EXP_LNKCTL, &lctl); if ((lctl & PCI_CFG_LINK_CTRL_VAL_L1_EN) == PCI_CFG_LINK_CTRL_VAL_L1_EN) { @@ -711,10 +127,10 @@ static void iwl_apm_config(struct iwl_trans *trans) /* * Start up NIC's basic functionality after it has been reset - * (e.g. after platform boot, or shutdown via iwl_apm_stop()) + * (e.g. after platform boot, or shutdown via iwl_pcie_apm_stop()) * NOTE: This does not load uCode nor start the embedded processor */ -static int iwl_apm_init(struct iwl_trans *trans) +static int iwl_pcie_apm_init(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); int ret = 0; @@ -746,7 +162,7 @@ static int iwl_apm_init(struct iwl_trans *trans) iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A); - iwl_apm_config(trans); + iwl_pcie_apm_config(trans); /* Configure analog phase-lock-loop before activating to D0A */ if (trans->cfg->base_params->pll_cfg_val) @@ -792,7 +208,7 @@ out: return ret; } -static int iwl_apm_stop_master(struct iwl_trans *trans) +static int iwl_pcie_apm_stop_master(struct iwl_trans *trans) { int ret = 0; @@ -810,7 +226,7 @@ static int iwl_apm_stop_master(struct iwl_trans *trans) return ret; } -static void iwl_apm_stop(struct iwl_trans *trans) +static void iwl_pcie_apm_stop(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); IWL_DEBUG_INFO(trans, "Stop card, put in low power state\n"); @@ -818,7 +234,7 @@ static void iwl_apm_stop(struct iwl_trans *trans) clear_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status); /* Stop device's DMA activity */ - iwl_apm_stop_master(trans); + iwl_pcie_apm_stop_master(trans); /* Reset the entire device */ iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); @@ -833,29 +249,29 @@ static void iwl_apm_stop(struct iwl_trans *trans) CSR_GP_CNTRL_REG_FLAG_INIT_DONE); } -static int iwl_nic_init(struct iwl_trans *trans) +static int iwl_pcie_nic_init(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); unsigned long flags; /* nic_init */ spin_lock_irqsave(&trans_pcie->irq_lock, flags); - iwl_apm_init(trans); + iwl_pcie_apm_init(trans); /* Set interrupt coalescing calibration timer to default (512 usecs) */ iwl_write8(trans, CSR_INT_COALESCING, IWL_HOST_INT_CALIB_TIMEOUT_DEF); spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); - iwl_set_pwr_vmain(trans); + iwl_pcie_set_pwr_vmain(trans); iwl_op_mode_nic_config(trans->op_mode); /* Allocate the RX queue, or reset if it is already allocated */ - iwl_rx_init(trans); + iwl_pcie_rx_init(trans); /* Allocate or reset and init all Tx and Command queues */ - if (iwl_tx_init(trans)) + if (iwl_pcie_tx_init(trans)) return -ENOMEM; if (trans->cfg->base_params->shadow_reg_enable) { @@ -870,7 +286,7 @@ static int iwl_nic_init(struct iwl_trans *trans) #define HW_READY_TIMEOUT (50) /* Note: returns poll_bit return value, which is >= 0 if success */ -static int iwl_set_hw_ready(struct iwl_trans *trans) +static int iwl_pcie_set_hw_ready(struct iwl_trans *trans) { int ret; @@ -888,14 +304,14 @@ static int iwl_set_hw_ready(struct iwl_trans *trans) } /* Note: returns standard 0/-ERROR code */ -static int iwl_prepare_card_hw(struct iwl_trans *trans) +static int iwl_pcie_prepare_card_hw(struct iwl_trans *trans) { int ret; int t = 0; IWL_DEBUG_INFO(trans, "iwl_trans_prepare_card_hw enter\n"); - ret = iwl_set_hw_ready(trans); + ret = iwl_pcie_set_hw_ready(trans); /* If the card is ready, exit 0 */ if (ret >= 0) return 0; @@ -905,7 +321,7 @@ static int iwl_prepare_card_hw(struct iwl_trans *trans) CSR_HW_IF_CONFIG_REG_PREPARE); do { - ret = iwl_set_hw_ready(trans); + ret = iwl_pcie_set_hw_ready(trans); if (ret >= 0) return 0; @@ -919,7 +335,7 @@ static int iwl_prepare_card_hw(struct iwl_trans *trans) /* * ucode */ -static int iwl_load_firmware_chunk(struct iwl_trans *trans, u32 dst_addr, +static int iwl_pcie_load_firmware_chunk(struct iwl_trans *trans, u32 dst_addr, dma_addr_t phy_addr, u32 byte_cnt) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); @@ -966,7 +382,7 @@ static int iwl_load_firmware_chunk(struct iwl_trans *trans, u32 dst_addr, return 0; } -static int iwl_load_section(struct iwl_trans *trans, u8 section_num, +static int iwl_pcie_load_section(struct iwl_trans *trans, u8 section_num, const struct fw_desc *section) { u8 *v_addr; @@ -987,8 +403,9 @@ static int iwl_load_section(struct iwl_trans *trans, u8 section_num, copy_size = min_t(u32, PAGE_SIZE, section->len - offset); memcpy(v_addr, (u8 *)section->data + offset, copy_size); - ret = iwl_load_firmware_chunk(trans, section->offset + offset, - p_addr, copy_size); + ret = iwl_pcie_load_firmware_chunk(trans, + section->offset + offset, + p_addr, copy_size); if (ret) { IWL_ERR(trans, "Could not load the [%d] uCode section\n", @@ -1001,7 +418,7 @@ static int iwl_load_section(struct iwl_trans *trans, u8 section_num, return ret; } -static int iwl_load_given_ucode(struct iwl_trans *trans, +static int iwl_pcie_load_given_ucode(struct iwl_trans *trans, const struct fw_img *image) { int i, ret = 0; @@ -1010,7 +427,7 @@ static int iwl_load_given_ucode(struct iwl_trans *trans, if (!image->sec[i].data) break; - ret = iwl_load_section(trans, i, &image->sec[i]); + ret = iwl_pcie_load_section(trans, i, &image->sec[i]); if (ret) return ret; } @@ -1029,7 +446,7 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans, bool hw_rfkill; /* This may fail if AMT took ownership of the device */ - if (iwl_prepare_card_hw(trans)) { + if (iwl_pcie_prepare_card_hw(trans)) { IWL_WARN(trans, "Exit HW not ready\n"); return -EIO; } @@ -1046,7 +463,7 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans, iwl_write32(trans, CSR_INT, 0xFFFFFFFF); - ret = iwl_nic_init(trans); + ret = iwl_pcie_nic_init(trans); if (ret) { IWL_ERR(trans, "Unable to init nic\n"); return ret; @@ -1066,129 +483,13 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans, iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); /* Load the given image to the HW */ - return iwl_load_given_ucode(trans, fw); -} - -/* - * Activate/Deactivate Tx DMA/FIFO channels according tx fifos mask - */ -static void iwl_trans_txq_set_sched(struct iwl_trans *trans, u32 mask) -{ - struct iwl_trans_pcie __maybe_unused *trans_pcie = - IWL_TRANS_GET_PCIE_TRANS(trans); - - iwl_write_prph(trans, SCD_TXFACT, mask); -} - -static void iwl_tx_start(struct iwl_trans *trans, u32 scd_base_addr) -{ - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - u32 a; - int chan; - u32 reg_val; - - /* make sure all queue are not stopped/used */ - memset(trans_pcie->queue_stopped, 0, sizeof(trans_pcie->queue_stopped)); - memset(trans_pcie->queue_used, 0, sizeof(trans_pcie->queue_used)); - - trans_pcie->scd_base_addr = - iwl_read_prph(trans, SCD_SRAM_BASE_ADDR); - - WARN_ON(scd_base_addr != 0 && - scd_base_addr != trans_pcie->scd_base_addr); - - a = trans_pcie->scd_base_addr + SCD_CONTEXT_MEM_LOWER_BOUND; - /* reset conext data memory */ - for (; a < trans_pcie->scd_base_addr + SCD_CONTEXT_MEM_UPPER_BOUND; - a += 4) - iwl_write_targ_mem(trans, a, 0); - /* reset tx status memory */ - for (; a < trans_pcie->scd_base_addr + SCD_TX_STTS_MEM_UPPER_BOUND; - a += 4) - iwl_write_targ_mem(trans, a, 0); - for (; a < trans_pcie->scd_base_addr + - SCD_TRANS_TBL_OFFSET_QUEUE( - trans->cfg->base_params->num_of_queues); - a += 4) - iwl_write_targ_mem(trans, a, 0); - - iwl_write_prph(trans, SCD_DRAM_BASE_ADDR, - trans_pcie->scd_bc_tbls.dma >> 10); - - /* The chain extension of the SCD doesn't work well. This feature is - * enabled by default by the HW, so we need to disable it manually. - */ - iwl_write_prph(trans, SCD_CHAINEXT_EN, 0); - - iwl_trans_ac_txq_enable(trans, trans_pcie->cmd_queue, - trans_pcie->cmd_fifo); - - /* Activate all Tx DMA/FIFO channels */ - iwl_trans_txq_set_sched(trans, IWL_MASK(0, 7)); - - /* Enable DMA channel */ - for (chan = 0; chan < FH_TCSR_CHNL_NUM ; chan++) - iwl_write_direct32(trans, FH_TCSR_CHNL_TX_CONFIG_REG(chan), - FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | - FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE); - - /* Update FH chicken bits */ - reg_val = iwl_read_direct32(trans, FH_TX_CHICKEN_BITS_REG); - iwl_write_direct32(trans, FH_TX_CHICKEN_BITS_REG, - reg_val | FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN); - - /* Enable L1-Active */ - iwl_clear_bits_prph(trans, APMG_PCIDEV_STT_REG, - APMG_PCIDEV_STT_VAL_L1_ACT_DIS); + return iwl_pcie_load_given_ucode(trans, fw); } static void iwl_trans_pcie_fw_alive(struct iwl_trans *trans, u32 scd_addr) { - iwl_reset_ict(trans); - iwl_tx_start(trans, scd_addr); -} - -/** - * iwlagn_txq_ctx_stop - Stop all Tx DMA channels - */ -static int iwl_trans_tx_stop(struct iwl_trans *trans) -{ - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - int ch, txq_id, ret; - unsigned long flags; - - /* Turn off all Tx DMA fifos */ - spin_lock_irqsave(&trans_pcie->irq_lock, flags); - - iwl_trans_txq_set_sched(trans, 0); - - /* Stop each Tx DMA channel, and wait for it to be idle */ - for (ch = 0; ch < FH_TCSR_CHNL_NUM; ch++) { - iwl_write_direct32(trans, - FH_TCSR_CHNL_TX_CONFIG_REG(ch), 0x0); - ret = iwl_poll_direct_bit(trans, FH_TSSR_TX_STATUS_REG, - FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch), 1000); - if (ret < 0) - IWL_ERR(trans, - "Failing on timeout while stopping DMA channel %d [0x%08x]\n", - ch, - iwl_read_direct32(trans, - FH_TSSR_TX_STATUS_REG)); - } - spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); - - if (!trans_pcie->txq) { - IWL_WARN(trans, - "Stopping tx queues that aren't allocated...\n"); - return 0; - } - - /* Unmap DMA from host system and free skb's */ - for (txq_id = 0; txq_id < trans->cfg->base_params->num_of_queues; - txq_id++) - iwl_tx_queue_unmap(trans, txq_id); - - return 0; + iwl_pcie_reset_ict(trans); + iwl_pcie_tx_start(trans, scd_addr); } static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) @@ -1202,7 +503,7 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); /* device going down, Stop using ICT table */ - iwl_disable_ict(trans); + iwl_pcie_disable_ict(trans); /* * If a HW restart happens during firmware loading, @@ -1212,8 +513,8 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) * already dead. */ if (test_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status)) { - iwl_trans_tx_stop(trans); - iwl_trans_rx_stop(trans); + iwl_pcie_tx_stop(trans); + iwl_pcie_rx_stop(trans); /* Power-down device's busmaster DMA clocks */ iwl_write_prph(trans, APMG_CLK_DIS_REG, @@ -1226,7 +527,7 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); /* Stop the device, and put it in low power state */ - iwl_apm_stop(trans); + iwl_pcie_apm_stop(trans); /* Upon stop, the APM issues an interrupt if HW RF kill is set. * Clean again the interrupt here @@ -1265,171 +566,6 @@ static void iwl_trans_pcie_wowlan_suspend(struct iwl_trans *trans) CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); } -static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, - struct iwl_device_cmd *dev_cmd, int txq_id) -{ - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct iwl_tx_cmd *tx_cmd = (struct iwl_tx_cmd *) dev_cmd->payload; - struct iwl_cmd_meta *out_meta; - struct iwl_tx_queue *txq; - struct iwl_queue *q; - dma_addr_t phys_addr = 0; - dma_addr_t txcmd_phys; - dma_addr_t scratch_phys; - u16 len, firstlen, secondlen; - u8 wait_write_ptr = 0; - __le16 fc = hdr->frame_control; - u8 hdr_len = ieee80211_hdrlen(fc); - u16 __maybe_unused wifi_seq; - - txq = &trans_pcie->txq[txq_id]; - q = &txq->q; - - if (unlikely(!test_bit(txq_id, trans_pcie->queue_used))) { - WARN_ON_ONCE(1); - return -EINVAL; - } - - spin_lock(&txq->lock); - - /* In AGG mode, the index in the ring must correspond to the WiFi - * sequence number. This is a HW requirements to help the SCD to parse - * the BA. - * Check here that the packets are in the right place on the ring. - */ -#ifdef CONFIG_IWLWIFI_DEBUG - wifi_seq = SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)); - WARN_ONCE((iwl_read_prph(trans, SCD_AGGR_SEL) & BIT(txq_id)) && - ((wifi_seq & 0xff) != q->write_ptr), - "Q: %d WiFi Seq %d tfdNum %d", - txq_id, wifi_seq, q->write_ptr); -#endif - - /* Set up driver data for this TFD */ - txq->entries[q->write_ptr].skb = skb; - txq->entries[q->write_ptr].cmd = dev_cmd; - - dev_cmd->hdr.cmd = REPLY_TX; - dev_cmd->hdr.sequence = - cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) | - INDEX_TO_SEQ(q->write_ptr))); - - /* Set up first empty entry in queue's array of Tx/cmd buffers */ - out_meta = &txq->entries[q->write_ptr].meta; - - /* - * Use the first empty entry in this queue's command buffer array - * to contain the Tx command and MAC header concatenated together - * (payload data will be in another buffer). - * Size of this varies, due to varying MAC header length. - * If end is not dword aligned, we'll have 2 extra bytes at the end - * of the MAC header (device reads on dword boundaries). - * We'll tell device about this padding later. - */ - len = sizeof(struct iwl_tx_cmd) + - sizeof(struct iwl_cmd_header) + hdr_len; - firstlen = (len + 3) & ~3; - - /* Tell NIC about any 2-byte padding after MAC header */ - if (firstlen != len) - tx_cmd->tx_flags |= TX_CMD_FLG_MH_PAD_MSK; - - /* Physical address of this Tx command's header (not MAC header!), - * within command buffer array. */ - txcmd_phys = dma_map_single(trans->dev, - &dev_cmd->hdr, firstlen, - DMA_BIDIRECTIONAL); - if (unlikely(dma_mapping_error(trans->dev, txcmd_phys))) - goto out_err; - dma_unmap_addr_set(out_meta, mapping, txcmd_phys); - dma_unmap_len_set(out_meta, len, firstlen); - - if (!ieee80211_has_morefrags(fc)) { - txq->need_update = 1; - } else { - wait_write_ptr = 1; - txq->need_update = 0; - } - - /* Set up TFD's 2nd entry to point directly to remainder of skb, - * if any (802.11 null frames have no payload). */ - secondlen = skb->len - hdr_len; - if (secondlen > 0) { - phys_addr = dma_map_single(trans->dev, skb->data + hdr_len, - secondlen, DMA_TO_DEVICE); - if (unlikely(dma_mapping_error(trans->dev, phys_addr))) { - dma_unmap_single(trans->dev, - dma_unmap_addr(out_meta, mapping), - dma_unmap_len(out_meta, len), - DMA_BIDIRECTIONAL); - goto out_err; - } - } - - /* Attach buffers to TFD */ - iwlagn_txq_attach_buf_to_tfd(trans, txq, txcmd_phys, firstlen, 1); - if (secondlen > 0) - iwlagn_txq_attach_buf_to_tfd(trans, txq, phys_addr, - secondlen, 0); - - scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) + - offsetof(struct iwl_tx_cmd, scratch); - - /* take back ownership of DMA buffer to enable update */ - dma_sync_single_for_cpu(trans->dev, txcmd_phys, firstlen, - DMA_BIDIRECTIONAL); - tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys); - tx_cmd->dram_msb_ptr = iwl_get_dma_hi_addr(scratch_phys); - - IWL_DEBUG_TX(trans, "sequence nr = 0X%x\n", - le16_to_cpu(dev_cmd->hdr.sequence)); - IWL_DEBUG_TX(trans, "tx_flags = 0X%x\n", le32_to_cpu(tx_cmd->tx_flags)); - - /* Set up entry for this TFD in Tx byte-count array */ - iwl_trans_txq_update_byte_cnt_tbl(trans, txq, le16_to_cpu(tx_cmd->len)); - - dma_sync_single_for_device(trans->dev, txcmd_phys, firstlen, - DMA_BIDIRECTIONAL); - - trace_iwlwifi_dev_tx(trans->dev, skb, - &txq->tfds[txq->q.write_ptr], - sizeof(struct iwl_tfd), - &dev_cmd->hdr, firstlen, - skb->data + hdr_len, secondlen); - trace_iwlwifi_dev_tx_data(trans->dev, skb, - skb->data + hdr_len, secondlen); - - /* start timer if queue currently empty */ - if (txq->need_update && q->read_ptr == q->write_ptr && - trans_pcie->wd_timeout) - mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout); - - /* Tell device the write index *just past* this latest filled TFD */ - q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); - iwl_txq_update_write_ptr(trans, txq); - - /* - * At this point the frame is "transmitted" successfully - * and we will get a TX status notification eventually, - * regardless of the value of ret. "ret" only indicates - * whether or not we should update the write pointer. - */ - if (iwl_queue_space(q) < q->high_mark) { - if (wait_write_ptr) { - txq->need_update = 1; - iwl_txq_update_write_ptr(trans, txq); - } else { - iwl_stop_queue(trans, txq); - } - } - spin_unlock(&txq->lock); - return 0; - out_err: - spin_unlock(&txq->lock); - return -1; -} - static int iwl_trans_pcie_start_hw(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); @@ -1440,29 +576,28 @@ static int iwl_trans_pcie_start_hw(struct iwl_trans *trans) if (!trans_pcie->irq_requested) { tasklet_init(&trans_pcie->irq_tasklet, (void (*)(unsigned long)) - iwl_irq_tasklet, (unsigned long)trans); + iwl_pcie_tasklet, (unsigned long)trans); - iwl_alloc_isr_ict(trans); + iwl_pcie_alloc_ict(trans); - err = request_irq(trans_pcie->irq, iwl_isr_ict, IRQF_SHARED, - DRV_NAME, trans); + err = request_irq(trans_pcie->irq, iwl_pcie_isr_ict, + IRQF_SHARED, DRV_NAME, trans); if (err) { IWL_ERR(trans, "Error allocating IRQ %d\n", trans_pcie->irq); goto error; } - INIT_WORK(&trans_pcie->rx_replenish, iwl_bg_rx_replenish); trans_pcie->irq_requested = true; } - err = iwl_prepare_card_hw(trans); + err = iwl_pcie_prepare_card_hw(trans); if (err) { IWL_ERR(trans, "Error while preparing HW: %d\n", err); goto err_free_irq; } - iwl_apm_init(trans); + iwl_pcie_apm_init(trans); /* From now on, the op_mode will be kept updated about RF kill state */ iwl_enable_rfkill_int(trans); @@ -1476,7 +611,7 @@ err_free_irq: trans_pcie->irq_requested = false; free_irq(trans_pcie->irq, trans); error: - iwl_free_isr_ict(trans); + iwl_pcie_free_ict(trans); tasklet_kill(&trans_pcie->irq_tasklet); return err; } @@ -1492,7 +627,7 @@ static void iwl_trans_pcie_stop_hw(struct iwl_trans *trans, iwl_disable_interrupts(trans); spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); - iwl_apm_stop(trans); + iwl_pcie_apm_stop(trans); spin_lock_irqsave(&trans_pcie->irq_lock, flags); iwl_disable_interrupts(trans); @@ -1516,27 +651,6 @@ static void iwl_trans_pcie_stop_hw(struct iwl_trans *trans, } } -static void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, - struct sk_buff_head *skbs) -{ - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id]; - /* n_bd is usually 256 => n_bd - 1 = 0xff */ - int tfd_num = ssn & (txq->q.n_bd - 1); - - spin_lock(&txq->lock); - - if (txq->q.read_ptr != tfd_num) { - IWL_DEBUG_TX_REPLY(trans, "[Q %d] %d -> %d (%d)\n", - txq_id, txq->q.read_ptr, tfd_num, ssn); - iwl_tx_queue_reclaim(trans, txq_id, tfd_num, skbs); - if (iwl_queue_space(&txq->q) > txq->q.low_mark) - iwl_wake_queue(trans, txq); - } - - spin_unlock(&txq->lock); -} - static void iwl_trans_pcie_write8(struct iwl_trans *trans, u32 ofs, u8 val) { writeb(val, IWL_TRANS_GET_PCIE_TRANS(trans)->hw_base + ofs); @@ -1583,12 +697,12 @@ void iwl_trans_pcie_free(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - iwl_trans_pcie_tx_free(trans); - iwl_trans_pcie_rx_free(trans); + iwl_pcie_tx_free(trans); + iwl_pcie_rx_free(trans); if (trans_pcie->irq_requested == true) { free_irq(trans_pcie->irq, trans); - iwl_free_isr_ict(trans); + iwl_pcie_free_ict(trans); } pci_disable_msi(trans_pcie->pci_dev); @@ -1634,10 +748,10 @@ static int iwl_trans_pcie_resume(struct iwl_trans *trans) #define IWL_FLUSH_WAIT_MS 2000 -static int iwl_trans_pcie_wait_tx_queue_empty(struct iwl_trans *trans) +static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_tx_queue *txq; + struct iwl_txq *txq; struct iwl_queue *q; int cnt; unsigned long now = jiffies; @@ -1681,7 +795,7 @@ static const char *get_fh_string(int cmd) #undef IWL_CMD } -int iwl_dump_fh(struct iwl_trans *trans, char **buf) +int iwl_pcie_dump_fh(struct iwl_trans *trans, char **buf) { int i; static const u32 fh_tbl[] = { @@ -1760,7 +874,7 @@ static const char *get_csr_string(int cmd) #undef IWL_CMD } -void iwl_dump_csr(struct iwl_trans *trans) +void iwl_pcie_dump_csr(struct iwl_trans *trans) { int i; static const u32 csr_tbl[] = { @@ -1817,7 +931,6 @@ static ssize_t iwl_dbgfs_##name##_write(struct file *file, \ const char __user *user_buf, \ size_t count, loff_t *ppos); - #define DEBUGFS_READ_FILE_OPS(name) \ DEBUGFS_READ_FUNC(name); \ static const struct file_operations iwl_dbgfs_##name##_ops = { \ @@ -1850,7 +963,7 @@ static ssize_t iwl_dbgfs_tx_queue_read(struct file *file, { struct iwl_trans *trans = file->private_data; struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_tx_queue *txq; + struct iwl_txq *txq; struct iwl_queue *q; char *buf; int pos = 0; @@ -1887,7 +1000,7 @@ static ssize_t iwl_dbgfs_rx_queue_read(struct file *file, { struct iwl_trans *trans = file->private_data; struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_rx_queue *rxq = &trans_pcie->rxq; + struct iwl_rxq *rxq = &trans_pcie->rxq; char buf[256]; int pos = 0; const size_t bufsz = sizeof(buf); @@ -2006,7 +1119,7 @@ static ssize_t iwl_dbgfs_csr_write(struct file *file, if (sscanf(buf, "%d", &csr) != 1) return -EFAULT; - iwl_dump_csr(trans); + iwl_pcie_dump_csr(trans); return count; } @@ -2020,7 +1133,7 @@ static ssize_t iwl_dbgfs_fh_reg_read(struct file *file, int pos = 0; ssize_t ret = -EFAULT; - ret = pos = iwl_dump_fh(trans, &buf); + ret = pos = iwl_pcie_dump_fh(trans, &buf); if (buf) { ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); @@ -2089,7 +1202,7 @@ static const struct iwl_trans_ops trans_ops_pcie = { .wowlan_suspend = iwl_trans_pcie_wowlan_suspend, - .send_cmd = iwl_trans_pcie_send_cmd, + .send_cmd = iwl_trans_pcie_send_hcmd, .tx = iwl_trans_pcie_tx, .reclaim = iwl_trans_pcie_reclaim, @@ -2099,7 +1212,7 @@ static const struct iwl_trans_ops trans_ops_pcie = { .dbgfs_register = iwl_trans_pcie_dbgfs_register, - .wait_tx_queue_empty = iwl_trans_pcie_wait_tx_queue_empty, + .wait_tx_queue_empty = iwl_trans_pcie_wait_txq_empty, #ifdef CONFIG_PM_SLEEP .suspend = iwl_trans_pcie_suspend, @@ -2124,7 +1237,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, trans = kzalloc(sizeof(struct iwl_trans) + sizeof(struct iwl_trans_pcie), GFP_KERNEL); - if (WARN_ON(!trans)) + if (!trans) return NULL; trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); @@ -2180,8 +1293,15 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, pci_write_config_byte(pdev, PCI_CFG_RETRY_TIMEOUT, 0x00); err = pci_enable_msi(pdev); - if (err) + if (err) { dev_err(&pdev->dev, "pci_enable_msi failed(0X%x)\n", err); + /* enable rfkill interrupt: hw bug w/a */ + pci_read_config_word(pdev, PCI_COMMAND, &pci_cmd); + if (pci_cmd & PCI_COMMAND_INTX_DISABLE) { + pci_cmd &= ~PCI_COMMAND_INTX_DISABLE; + pci_write_config_word(pdev, PCI_COMMAND, pci_cmd); + } + } trans->dev = &pdev->dev; trans_pcie->irq = pdev->irq; @@ -2191,14 +1311,6 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, snprintf(trans->hw_id_str, sizeof(trans->hw_id_str), "PCI ID: 0x%04X:0x%04X", pdev->device, pdev->subsystem_device); - /* TODO: Move this away, not needed if not MSI */ - /* enable rfkill interrupt: hw bug w/a */ - pci_read_config_word(pdev, PCI_COMMAND, &pci_cmd); - if (pci_cmd & PCI_COMMAND_INTX_DISABLE) { - pci_cmd &= ~PCI_COMMAND_INTX_DISABLE; - pci_write_config_word(pdev, PCI_COMMAND, pci_cmd); - } - /* Initialize the wait queue for commands */ init_waitqueue_head(&trans_pcie->wait_command_queue); spin_lock_init(&trans->reg_lock); diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index dcc7e125..6c5b867 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -42,12 +42,170 @@ #define IWL_TX_CRC_SIZE 4 #define IWL_TX_DELIMITER_SIZE 4 -/** - * iwl_trans_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array +/*************** DMA-QUEUE-GENERAL-FUNCTIONS ***** + * DMA services + * + * Theory of operation + * + * A Tx or Rx queue resides in host DRAM, and is comprised of a circular buffer + * of buffer descriptors, each of which points to one or more data buffers for + * the device to read from or fill. Driver and device exchange status of each + * queue via "read" and "write" pointers. Driver keeps minimum of 2 empty + * entries in each circular buffer, to protect against confusing empty and full + * queue states. + * + * The device reads or writes the data in the queues via the device's several + * DMA/FIFO channels. Each queue is mapped to a single DMA channel. + * + * For Tx queue, there are low mark and high mark limits. If, after queuing + * the packet for Tx, free space become < low mark, Tx queue stopped. When + * reclaiming packets (on 'tx done IRQ), if free space become > high mark, + * Tx queue resumed. + * + ***************************************************/ +static int iwl_queue_space(const struct iwl_queue *q) +{ + int s = q->read_ptr - q->write_ptr; + + if (q->read_ptr > q->write_ptr) + s -= q->n_bd; + + if (s <= 0) + s += q->n_window; + /* keep some reserve to not confuse empty and full situations */ + s -= 2; + if (s < 0) + s = 0; + return s; +} + +/* + * iwl_queue_init - Initialize queue's high/low-water and read/write indexes + */ +static int iwl_queue_init(struct iwl_queue *q, int count, int slots_num, u32 id) +{ + q->n_bd = count; + q->n_window = slots_num; + q->id = id; + + /* count must be power-of-two size, otherwise iwl_queue_inc_wrap + * and iwl_queue_dec_wrap are broken. */ + if (WARN_ON(!is_power_of_2(count))) + return -EINVAL; + + /* slots_num must be power-of-two size, otherwise + * get_cmd_index is broken. */ + if (WARN_ON(!is_power_of_2(slots_num))) + return -EINVAL; + + q->low_mark = q->n_window / 4; + if (q->low_mark < 4) + q->low_mark = 4; + + q->high_mark = q->n_window / 8; + if (q->high_mark < 2) + q->high_mark = 2; + + q->write_ptr = 0; + q->read_ptr = 0; + + return 0; +} + +static int iwl_pcie_alloc_dma_ptr(struct iwl_trans *trans, + struct iwl_dma_ptr *ptr, size_t size) +{ + if (WARN_ON(ptr->addr)) + return -EINVAL; + + ptr->addr = dma_alloc_coherent(trans->dev, size, + &ptr->dma, GFP_KERNEL); + if (!ptr->addr) + return -ENOMEM; + ptr->size = size; + return 0; +} + +static void iwl_pcie_free_dma_ptr(struct iwl_trans *trans, + struct iwl_dma_ptr *ptr) +{ + if (unlikely(!ptr->addr)) + return; + + dma_free_coherent(trans->dev, ptr->size, ptr->addr, ptr->dma); + memset(ptr, 0, sizeof(*ptr)); +} + +static void iwl_pcie_txq_stuck_timer(unsigned long data) +{ + struct iwl_txq *txq = (void *)data; + struct iwl_queue *q = &txq->q; + struct iwl_trans_pcie *trans_pcie = txq->trans_pcie; + struct iwl_trans *trans = iwl_trans_pcie_get_trans(trans_pcie); + u32 scd_sram_addr = trans_pcie->scd_base_addr + + SCD_TX_STTS_QUEUE_OFFSET(txq->q.id); + u8 buf[16]; + int i; + + spin_lock(&txq->lock); + /* check if triggered erroneously */ + if (txq->q.read_ptr == txq->q.write_ptr) { + spin_unlock(&txq->lock); + return; + } + spin_unlock(&txq->lock); + + IWL_ERR(trans, "Queue %d stuck for %u ms.\n", txq->q.id, + jiffies_to_msecs(trans_pcie->wd_timeout)); + IWL_ERR(trans, "Current SW read_ptr %d write_ptr %d\n", + txq->q.read_ptr, txq->q.write_ptr); + + iwl_read_targ_mem_bytes(trans, scd_sram_addr, buf, sizeof(buf)); + + iwl_print_hex_error(trans, buf, sizeof(buf)); + + for (i = 0; i < FH_TCSR_CHNL_NUM; i++) + IWL_ERR(trans, "FH TRBs(%d) = 0x%08x\n", i, + iwl_read_direct32(trans, FH_TX_TRB_REG(i))); + + for (i = 0; i < trans->cfg->base_params->num_of_queues; i++) { + u32 status = iwl_read_prph(trans, SCD_QUEUE_STATUS_BITS(i)); + u8 fifo = (status >> SCD_QUEUE_STTS_REG_POS_TXF) & 0x7; + bool active = !!(status & BIT(SCD_QUEUE_STTS_REG_POS_ACTIVE)); + u32 tbl_dw = + iwl_read_targ_mem(trans, + trans_pcie->scd_base_addr + + SCD_TRANS_TBL_OFFSET_QUEUE(i)); + + if (i & 0x1) + tbl_dw = (tbl_dw & 0xFFFF0000) >> 16; + else + tbl_dw = tbl_dw & 0x0000FFFF; + + IWL_ERR(trans, + "Q %d is %sactive and mapped to fifo %d ra_tid 0x%04x [%d,%d]\n", + i, active ? "" : "in", fifo, tbl_dw, + iwl_read_prph(trans, + SCD_QUEUE_RDPTR(i)) & (txq->q.n_bd - 1), + iwl_read_prph(trans, SCD_QUEUE_WRPTR(i))); + } + + for (i = q->read_ptr; i != q->write_ptr; + i = iwl_queue_inc_wrap(i, q->n_bd)) { + struct iwl_tx_cmd *tx_cmd = + (struct iwl_tx_cmd *)txq->entries[i].cmd->payload; + IWL_ERR(trans, "scratch %d = 0x%08x\n", i, + get_unaligned_le32(&tx_cmd->scratch)); + } + + iwl_op_mode_nic_error(trans->op_mode); +} + +/* + * iwl_pcie_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array */ -void iwl_trans_txq_update_byte_cnt_tbl(struct iwl_trans *trans, - struct iwl_tx_queue *txq, - u16 byte_cnt) +static void iwl_pcie_txq_update_byte_cnt_tbl(struct iwl_trans *trans, + struct iwl_txq *txq, u16 byte_cnt) { struct iwlagn_scd_bc_tbl *scd_bc_tbl; struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); @@ -88,10 +246,36 @@ void iwl_trans_txq_update_byte_cnt_tbl(struct iwl_trans *trans, tfd_offset[TFD_QUEUE_SIZE_MAX + write_ptr] = bc_ent; } -/** - * iwl_txq_update_write_ptr - Send new write index to hardware +static void iwl_pcie_txq_inval_byte_cnt_tbl(struct iwl_trans *trans, + struct iwl_txq *txq) +{ + struct iwl_trans_pcie *trans_pcie = + IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwlagn_scd_bc_tbl *scd_bc_tbl = trans_pcie->scd_bc_tbls.addr; + int txq_id = txq->q.id; + int read_ptr = txq->q.read_ptr; + u8 sta_id = 0; + __le16 bc_ent; + struct iwl_tx_cmd *tx_cmd = + (void *)txq->entries[txq->q.read_ptr].cmd->payload; + + WARN_ON(read_ptr >= TFD_QUEUE_SIZE_MAX); + + if (txq_id != trans_pcie->cmd_queue) + sta_id = tx_cmd->sta_id; + + bc_ent = cpu_to_le16(1 | (sta_id << 12)); + scd_bc_tbl[txq_id].tfd_offset[read_ptr] = bc_ent; + + if (read_ptr < TFD_QUEUE_SIZE_BC_DUP) + scd_bc_tbl[txq_id]. + tfd_offset[TFD_QUEUE_SIZE_MAX + read_ptr] = bc_ent; +} + +/* + * iwl_pcie_txq_inc_wr_ptr - Send new write index to hardware */ -void iwl_txq_update_write_ptr(struct iwl_trans *trans, struct iwl_tx_queue *txq) +void iwl_pcie_txq_inc_wr_ptr(struct iwl_trans *trans, struct iwl_txq *txq) { u32 reg = 0; int txq_id = txq->q.id; @@ -137,7 +321,7 @@ void iwl_txq_update_write_ptr(struct iwl_trans *trans, struct iwl_tx_queue *txq) txq->need_update = 0; } -static inline dma_addr_t iwl_tfd_tb_get_addr(struct iwl_tfd *tfd, u8 idx) +static inline dma_addr_t iwl_pcie_tfd_tb_get_addr(struct iwl_tfd *tfd, u8 idx) { struct iwl_tfd_tb *tb = &tfd->tbs[idx]; @@ -149,15 +333,15 @@ static inline dma_addr_t iwl_tfd_tb_get_addr(struct iwl_tfd *tfd, u8 idx) return addr; } -static inline u16 iwl_tfd_tb_get_len(struct iwl_tfd *tfd, u8 idx) +static inline u16 iwl_pcie_tfd_tb_get_len(struct iwl_tfd *tfd, u8 idx) { struct iwl_tfd_tb *tb = &tfd->tbs[idx]; return le16_to_cpu(tb->hi_n_len) >> 4; } -static inline void iwl_tfd_set_tb(struct iwl_tfd *tfd, u8 idx, - dma_addr_t addr, u16 len) +static inline void iwl_pcie_tfd_set_tb(struct iwl_tfd *tfd, u8 idx, + dma_addr_t addr, u16 len) { struct iwl_tfd_tb *tb = &tfd->tbs[idx]; u16 hi_n_len = len << 4; @@ -171,19 +355,20 @@ static inline void iwl_tfd_set_tb(struct iwl_tfd *tfd, u8 idx, tfd->num_tbs = idx + 1; } -static inline u8 iwl_tfd_get_num_tbs(struct iwl_tfd *tfd) +static inline u8 iwl_pcie_tfd_get_num_tbs(struct iwl_tfd *tfd) { return tfd->num_tbs & 0x1f; } -static void iwl_unmap_tfd(struct iwl_trans *trans, struct iwl_cmd_meta *meta, - struct iwl_tfd *tfd, enum dma_data_direction dma_dir) +static void iwl_pcie_tfd_unmap(struct iwl_trans *trans, + struct iwl_cmd_meta *meta, struct iwl_tfd *tfd, + enum dma_data_direction dma_dir) { int i; int num_tbs; /* Sanity check on number of chunks */ - num_tbs = iwl_tfd_get_num_tbs(tfd); + num_tbs = iwl_pcie_tfd_get_num_tbs(tfd); if (num_tbs >= IWL_NUM_OF_TBS) { IWL_ERR(trans, "Too many chunks: %i\n", num_tbs); @@ -200,14 +385,14 @@ static void iwl_unmap_tfd(struct iwl_trans *trans, struct iwl_cmd_meta *meta, /* Unmap chunks, if any. */ for (i = 1; i < num_tbs; i++) - dma_unmap_single(trans->dev, iwl_tfd_tb_get_addr(tfd, i), - iwl_tfd_tb_get_len(tfd, i), dma_dir); + dma_unmap_single(trans->dev, iwl_pcie_tfd_tb_get_addr(tfd, i), + iwl_pcie_tfd_tb_get_len(tfd, i), dma_dir); tfd->num_tbs = 0; } -/** - * iwl_txq_free_tfd - Free all chunks referenced by TFD [txq->q.read_ptr] +/* + * iwl_pcie_txq_free_tfd - Free all chunks referenced by TFD [txq->q.read_ptr] * @trans - transport private data * @txq - tx queue * @dma_dir - the direction of the DMA mapping @@ -215,8 +400,8 @@ static void iwl_unmap_tfd(struct iwl_trans *trans, struct iwl_cmd_meta *meta, * Does NOT advance any TFD circular buffer read/write indexes * Does NOT free the TFD itself (which is within circular buffer) */ -void iwl_txq_free_tfd(struct iwl_trans *trans, struct iwl_tx_queue *txq, - enum dma_data_direction dma_dir) +static void iwl_pcie_txq_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq, + enum dma_data_direction dma_dir) { struct iwl_tfd *tfd_tmp = txq->tfds; @@ -227,8 +412,8 @@ void iwl_txq_free_tfd(struct iwl_trans *trans, struct iwl_tx_queue *txq, lockdep_assert_held(&txq->lock); /* We have only q->n_window txq->entries, but we use q->n_bd tfds */ - iwl_unmap_tfd(trans, &txq->entries[idx].meta, &tfd_tmp[rd_ptr], - dma_dir); + iwl_pcie_tfd_unmap(trans, &txq->entries[idx].meta, &tfd_tmp[rd_ptr], + dma_dir); /* free SKB */ if (txq->entries) { @@ -247,10 +432,8 @@ void iwl_txq_free_tfd(struct iwl_trans *trans, struct iwl_tx_queue *txq, } } -int iwlagn_txq_attach_buf_to_tfd(struct iwl_trans *trans, - struct iwl_tx_queue *txq, - dma_addr_t addr, u16 len, - u8 reset) +static int iwl_pcie_txq_build_tfd(struct iwl_trans *trans, struct iwl_txq *txq, + dma_addr_t addr, u16 len, u8 reset) { struct iwl_queue *q; struct iwl_tfd *tfd, *tfd_tmp; @@ -263,7 +446,7 @@ int iwlagn_txq_attach_buf_to_tfd(struct iwl_trans *trans, if (reset) memset(tfd, 0, sizeof(*tfd)); - num_tbs = iwl_tfd_get_num_tbs(tfd); + num_tbs = iwl_pcie_tfd_get_num_tbs(tfd); /* Each TFD can point to a maximum 20 Tx buffers */ if (num_tbs >= IWL_NUM_OF_TBS) { @@ -279,108 +462,534 @@ int iwlagn_txq_attach_buf_to_tfd(struct iwl_trans *trans, IWL_ERR(trans, "Unaligned address = %llx\n", (unsigned long long)addr); - iwl_tfd_set_tb(tfd, num_tbs, addr, len); + iwl_pcie_tfd_set_tb(tfd, num_tbs, addr, len); return 0; } -/*************** DMA-QUEUE-GENERAL-FUNCTIONS ***** - * DMA services - * - * Theory of operation - * - * A Tx or Rx queue resides in host DRAM, and is comprised of a circular buffer - * of buffer descriptors, each of which points to one or more data buffers for - * the device to read from or fill. Driver and device exchange status of each - * queue via "read" and "write" pointers. Driver keeps minimum of 2 empty - * entries in each circular buffer, to protect against confusing empty and full - * queue states. - * - * The device reads or writes the data in the queues via the device's several - * DMA/FIFO channels. Each queue is mapped to a single DMA channel. - * - * For Tx queue, there are low mark and high mark limits. If, after queuing - * the packet for Tx, free space become < low mark, Tx queue stopped. When - * reclaiming packets (on 'tx done IRQ), if free space become > high mark, - * Tx queue resumed. +static int iwl_pcie_txq_alloc(struct iwl_trans *trans, + struct iwl_txq *txq, int slots_num, + u32 txq_id) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + size_t tfd_sz = sizeof(struct iwl_tfd) * TFD_QUEUE_SIZE_MAX; + int i; + + if (WARN_ON(txq->entries || txq->tfds)) + return -EINVAL; + + setup_timer(&txq->stuck_timer, iwl_pcie_txq_stuck_timer, + (unsigned long)txq); + txq->trans_pcie = trans_pcie; + + txq->q.n_window = slots_num; + + txq->entries = kcalloc(slots_num, + sizeof(struct iwl_pcie_txq_entry), + GFP_KERNEL); + + if (!txq->entries) + goto error; + + if (txq_id == trans_pcie->cmd_queue) + for (i = 0; i < slots_num; i++) { + txq->entries[i].cmd = + kmalloc(sizeof(struct iwl_device_cmd), + GFP_KERNEL); + if (!txq->entries[i].cmd) + goto error; + } + + /* Circular buffer of transmit frame descriptors (TFDs), + * shared with device */ + txq->tfds = dma_alloc_coherent(trans->dev, tfd_sz, + &txq->q.dma_addr, GFP_KERNEL); + if (!txq->tfds) { + IWL_ERR(trans, "dma_alloc_coherent(%zd) failed\n", tfd_sz); + goto error; + } + txq->q.id = txq_id; + + return 0; +error: + if (txq->entries && txq_id == trans_pcie->cmd_queue) + for (i = 0; i < slots_num; i++) + kfree(txq->entries[i].cmd); + kfree(txq->entries); + txq->entries = NULL; + + return -ENOMEM; + +} + +static int iwl_pcie_txq_init(struct iwl_trans *trans, struct iwl_txq *txq, + int slots_num, u32 txq_id) +{ + int ret; + + txq->need_update = 0; + + /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise + * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */ + BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1)); + + /* Initialize queue's high/low-water marks, and head/tail indexes */ + ret = iwl_queue_init(&txq->q, TFD_QUEUE_SIZE_MAX, slots_num, + txq_id); + if (ret) + return ret; + + spin_lock_init(&txq->lock); + + /* + * Tell nic where to find circular buffer of Tx Frame Descriptors for + * given Tx queue, and enable the DMA channel used for that queue. + * Circular buffer (TFD queue in DRAM) physical base address */ + iwl_write_direct32(trans, FH_MEM_CBBC_QUEUE(txq_id), + txq->q.dma_addr >> 8); + + return 0; +} + +/* + * iwl_pcie_txq_unmap - Unmap any remaining DMA mappings and free skb's + */ +static void iwl_pcie_txq_unmap(struct iwl_trans *trans, int txq_id) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_txq *txq = &trans_pcie->txq[txq_id]; + struct iwl_queue *q = &txq->q; + enum dma_data_direction dma_dir; + + if (!q->n_bd) + return; + + /* In the command queue, all the TBs are mapped as BIDI + * so unmap them as such. + */ + if (txq_id == trans_pcie->cmd_queue) + dma_dir = DMA_BIDIRECTIONAL; + else + dma_dir = DMA_TO_DEVICE; + + spin_lock_bh(&txq->lock); + while (q->write_ptr != q->read_ptr) { + iwl_pcie_txq_free_tfd(trans, txq, dma_dir); + q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd); + } + spin_unlock_bh(&txq->lock); +} + +/* + * iwl_pcie_txq_free - Deallocate DMA queue. + * @txq: Transmit queue to deallocate. * - ***************************************************/ + * Empty queue by removing and destroying all BD's. + * Free all buffers. + * 0-fill, but do not free "txq" descriptor structure. + */ +static void iwl_pcie_txq_free(struct iwl_trans *trans, int txq_id) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_txq *txq = &trans_pcie->txq[txq_id]; + struct device *dev = trans->dev; + int i; + + if (WARN_ON(!txq)) + return; + + iwl_pcie_txq_unmap(trans, txq_id); + + /* De-alloc array of command/tx buffers */ + if (txq_id == trans_pcie->cmd_queue) + for (i = 0; i < txq->q.n_window; i++) { + kfree(txq->entries[i].cmd); + kfree(txq->entries[i].copy_cmd); + kfree(txq->entries[i].free_buf); + } + + /* De-alloc circular buffer of TFDs */ + if (txq->q.n_bd) { + dma_free_coherent(dev, sizeof(struct iwl_tfd) * + txq->q.n_bd, txq->tfds, txq->q.dma_addr); + memset(&txq->q.dma_addr, 0, sizeof(txq->q.dma_addr)); + } + + kfree(txq->entries); + txq->entries = NULL; -int iwl_queue_space(const struct iwl_queue *q) + del_timer_sync(&txq->stuck_timer); + + /* 0-fill queue descriptor structure */ + memset(txq, 0, sizeof(*txq)); +} + +/* + * Activate/Deactivate Tx DMA/FIFO channels according tx fifos mask + */ +static void iwl_pcie_txq_set_sched(struct iwl_trans *trans, u32 mask) { - int s = q->read_ptr - q->write_ptr; + struct iwl_trans_pcie __maybe_unused *trans_pcie = + IWL_TRANS_GET_PCIE_TRANS(trans); - if (q->read_ptr > q->write_ptr) - s -= q->n_bd; + iwl_write_prph(trans, SCD_TXFACT, mask); +} - if (s <= 0) - s += q->n_window; - /* keep some reserve to not confuse empty and full situations */ - s -= 2; - if (s < 0) - s = 0; - return s; +void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + u32 a; + int chan; + u32 reg_val; + + /* make sure all queue are not stopped/used */ + memset(trans_pcie->queue_stopped, 0, sizeof(trans_pcie->queue_stopped)); + memset(trans_pcie->queue_used, 0, sizeof(trans_pcie->queue_used)); + + trans_pcie->scd_base_addr = + iwl_read_prph(trans, SCD_SRAM_BASE_ADDR); + + WARN_ON(scd_base_addr != 0 && + scd_base_addr != trans_pcie->scd_base_addr); + + a = trans_pcie->scd_base_addr + SCD_CONTEXT_MEM_LOWER_BOUND; + /* reset conext data memory */ + for (; a < trans_pcie->scd_base_addr + SCD_CONTEXT_MEM_UPPER_BOUND; + a += 4) + iwl_write_targ_mem(trans, a, 0); + /* reset tx status memory */ + for (; a < trans_pcie->scd_base_addr + SCD_TX_STTS_MEM_UPPER_BOUND; + a += 4) + iwl_write_targ_mem(trans, a, 0); + for (; a < trans_pcie->scd_base_addr + + SCD_TRANS_TBL_OFFSET_QUEUE( + trans->cfg->base_params->num_of_queues); + a += 4) + iwl_write_targ_mem(trans, a, 0); + + iwl_write_prph(trans, SCD_DRAM_BASE_ADDR, + trans_pcie->scd_bc_tbls.dma >> 10); + + /* The chain extension of the SCD doesn't work well. This feature is + * enabled by default by the HW, so we need to disable it manually. + */ + iwl_write_prph(trans, SCD_CHAINEXT_EN, 0); + + iwl_trans_ac_txq_enable(trans, trans_pcie->cmd_queue, + trans_pcie->cmd_fifo); + + /* Activate all Tx DMA/FIFO channels */ + iwl_pcie_txq_set_sched(trans, IWL_MASK(0, 7)); + + /* Enable DMA channel */ + for (chan = 0; chan < FH_TCSR_CHNL_NUM; chan++) + iwl_write_direct32(trans, FH_TCSR_CHNL_TX_CONFIG_REG(chan), + FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | + FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE); + + /* Update FH chicken bits */ + reg_val = iwl_read_direct32(trans, FH_TX_CHICKEN_BITS_REG); + iwl_write_direct32(trans, FH_TX_CHICKEN_BITS_REG, + reg_val | FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN); + + /* Enable L1-Active */ + iwl_clear_bits_prph(trans, APMG_PCIDEV_STT_REG, + APMG_PCIDEV_STT_VAL_L1_ACT_DIS); } -/** - * iwl_queue_init - Initialize queue's high/low-water and read/write indexes +/* + * iwl_pcie_tx_stop - Stop all Tx DMA channels */ -int iwl_queue_init(struct iwl_queue *q, int count, int slots_num, u32 id) +int iwl_pcie_tx_stop(struct iwl_trans *trans) { - q->n_bd = count; - q->n_window = slots_num; - q->id = id; + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + int ch, txq_id, ret; + unsigned long flags; - /* count must be power-of-two size, otherwise iwl_queue_inc_wrap - * and iwl_queue_dec_wrap are broken. */ - if (WARN_ON(!is_power_of_2(count))) - return -EINVAL; + /* Turn off all Tx DMA fifos */ + spin_lock_irqsave(&trans_pcie->irq_lock, flags); - /* slots_num must be power-of-two size, otherwise - * get_cmd_index is broken. */ - if (WARN_ON(!is_power_of_2(slots_num))) - return -EINVAL; + iwl_pcie_txq_set_sched(trans, 0); - q->low_mark = q->n_window / 4; - if (q->low_mark < 4) - q->low_mark = 4; + /* Stop each Tx DMA channel, and wait for it to be idle */ + for (ch = 0; ch < FH_TCSR_CHNL_NUM; ch++) { + iwl_write_direct32(trans, + FH_TCSR_CHNL_TX_CONFIG_REG(ch), 0x0); + ret = iwl_poll_direct_bit(trans, FH_TSSR_TX_STATUS_REG, + FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch), 1000); + if (ret < 0) + IWL_ERR(trans, + "Failing on timeout while stopping DMA channel %d [0x%08x]\n", + ch, + iwl_read_direct32(trans, + FH_TSSR_TX_STATUS_REG)); + } + spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); - q->high_mark = q->n_window / 8; - if (q->high_mark < 2) - q->high_mark = 2; + if (!trans_pcie->txq) { + IWL_WARN(trans, + "Stopping tx queues that aren't allocated...\n"); + return 0; + } - q->write_ptr = q->read_ptr = 0; + /* Unmap DMA from host system and free skb's */ + for (txq_id = 0; txq_id < trans->cfg->base_params->num_of_queues; + txq_id++) + iwl_pcie_txq_unmap(trans, txq_id); return 0; } -static void iwlagn_txq_inval_byte_cnt_tbl(struct iwl_trans *trans, - struct iwl_tx_queue *txq) +/* + * iwl_trans_tx_free - Free TXQ Context + * + * Destroy all TX DMA queues and structures + */ +void iwl_pcie_tx_free(struct iwl_trans *trans) { - struct iwl_trans_pcie *trans_pcie = - IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwlagn_scd_bc_tbl *scd_bc_tbl = trans_pcie->scd_bc_tbls.addr; - int txq_id = txq->q.id; - int read_ptr = txq->q.read_ptr; - u8 sta_id = 0; - __le16 bc_ent; - struct iwl_tx_cmd *tx_cmd = - (void *)txq->entries[txq->q.read_ptr].cmd->payload; + int txq_id; + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - WARN_ON(read_ptr >= TFD_QUEUE_SIZE_MAX); + /* Tx queues */ + if (trans_pcie->txq) { + for (txq_id = 0; + txq_id < trans->cfg->base_params->num_of_queues; txq_id++) + iwl_pcie_txq_free(trans, txq_id); + } - if (txq_id != trans_pcie->cmd_queue) - sta_id = tx_cmd->sta_id; + kfree(trans_pcie->txq); + trans_pcie->txq = NULL; - bc_ent = cpu_to_le16(1 | (sta_id << 12)); - scd_bc_tbl[txq_id].tfd_offset[read_ptr] = bc_ent; + iwl_pcie_free_dma_ptr(trans, &trans_pcie->kw); - if (read_ptr < TFD_QUEUE_SIZE_BC_DUP) - scd_bc_tbl[txq_id]. - tfd_offset[TFD_QUEUE_SIZE_MAX + read_ptr] = bc_ent; + iwl_pcie_free_dma_ptr(trans, &trans_pcie->scd_bc_tbls); +} + +/* + * iwl_pcie_tx_alloc - allocate TX context + * Allocate all Tx DMA structures and initialize them + */ +static int iwl_pcie_tx_alloc(struct iwl_trans *trans) +{ + int ret; + int txq_id, slots_num; + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + + u16 scd_bc_tbls_size = trans->cfg->base_params->num_of_queues * + sizeof(struct iwlagn_scd_bc_tbl); + + /*It is not allowed to alloc twice, so warn when this happens. + * We cannot rely on the previous allocation, so free and fail */ + if (WARN_ON(trans_pcie->txq)) { + ret = -EINVAL; + goto error; + } + + ret = iwl_pcie_alloc_dma_ptr(trans, &trans_pcie->scd_bc_tbls, + scd_bc_tbls_size); + if (ret) { + IWL_ERR(trans, "Scheduler BC Table allocation failed\n"); + goto error; + } + + /* Alloc keep-warm buffer */ + ret = iwl_pcie_alloc_dma_ptr(trans, &trans_pcie->kw, IWL_KW_SIZE); + if (ret) { + IWL_ERR(trans, "Keep Warm allocation failed\n"); + goto error; + } + + trans_pcie->txq = kcalloc(trans->cfg->base_params->num_of_queues, + sizeof(struct iwl_txq), GFP_KERNEL); + if (!trans_pcie->txq) { + IWL_ERR(trans, "Not enough memory for txq\n"); + ret = ENOMEM; + goto error; + } + + /* Alloc and init all Tx queues, including the command queue (#4/#9) */ + for (txq_id = 0; txq_id < trans->cfg->base_params->num_of_queues; + txq_id++) { + slots_num = (txq_id == trans_pcie->cmd_queue) ? + TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; + ret = iwl_pcie_txq_alloc(trans, &trans_pcie->txq[txq_id], + slots_num, txq_id); + if (ret) { + IWL_ERR(trans, "Tx %d queue alloc failed\n", txq_id); + goto error; + } + } + + return 0; + +error: + iwl_pcie_tx_free(trans); + + return ret; +} +int iwl_pcie_tx_init(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + int ret; + int txq_id, slots_num; + unsigned long flags; + bool alloc = false; + + if (!trans_pcie->txq) { + ret = iwl_pcie_tx_alloc(trans); + if (ret) + goto error; + alloc = true; + } + + spin_lock_irqsave(&trans_pcie->irq_lock, flags); + + /* Turn off all Tx DMA fifos */ + iwl_write_prph(trans, SCD_TXFACT, 0); + + /* Tell NIC where to find the "keep warm" buffer */ + iwl_write_direct32(trans, FH_KW_MEM_ADDR_REG, + trans_pcie->kw.dma >> 4); + + spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); + + /* Alloc and init all Tx queues, including the command queue (#4/#9) */ + for (txq_id = 0; txq_id < trans->cfg->base_params->num_of_queues; + txq_id++) { + slots_num = (txq_id == trans_pcie->cmd_queue) ? + TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; + ret = iwl_pcie_txq_init(trans, &trans_pcie->txq[txq_id], + slots_num, txq_id); + if (ret) { + IWL_ERR(trans, "Tx %d queue init failed\n", txq_id); + goto error; + } + } + + return 0; +error: + /*Upon error, free only if we allocated something */ + if (alloc) + iwl_pcie_tx_free(trans); + return ret; +} + +static inline void iwl_pcie_txq_progress(struct iwl_trans_pcie *trans_pcie, + struct iwl_txq *txq) +{ + if (!trans_pcie->wd_timeout) + return; + + /* + * if empty delete timer, otherwise move timer forward + * since we're making progress on this queue + */ + if (txq->q.read_ptr == txq->q.write_ptr) + del_timer(&txq->stuck_timer); + else + mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout); +} + +/* Frees buffers until index _not_ inclusive */ +void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, + struct sk_buff_head *skbs) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_txq *txq = &trans_pcie->txq[txq_id]; + /* n_bd is usually 256 => n_bd - 1 = 0xff */ + int tfd_num = ssn & (txq->q.n_bd - 1); + struct iwl_queue *q = &txq->q; + int last_to_free; + + /* This function is not meant to release cmd queue*/ + if (WARN_ON(txq_id == trans_pcie->cmd_queue)) + return; + + spin_lock(&txq->lock); + + if (txq->q.read_ptr == tfd_num) + goto out; + + IWL_DEBUG_TX_REPLY(trans, "[Q %d] %d -> %d (%d)\n", + txq_id, txq->q.read_ptr, tfd_num, ssn); + + /*Since we free until index _not_ inclusive, the one before index is + * the last we will free. This one must be used */ + last_to_free = iwl_queue_dec_wrap(tfd_num, q->n_bd); + + if (!iwl_queue_used(q, last_to_free)) { + IWL_ERR(trans, + "%s: Read index for DMA queue txq id (%d), last_to_free %d is out of range [0-%d] %d %d.\n", + __func__, txq_id, last_to_free, q->n_bd, + q->write_ptr, q->read_ptr); + goto out; + } + + if (WARN_ON(!skb_queue_empty(skbs))) + goto out; + + for (; + q->read_ptr != tfd_num; + q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { + + if (WARN_ON_ONCE(txq->entries[txq->q.read_ptr].skb == NULL)) + continue; + + __skb_queue_tail(skbs, txq->entries[txq->q.read_ptr].skb); + + txq->entries[txq->q.read_ptr].skb = NULL; + + iwl_pcie_txq_inval_byte_cnt_tbl(trans, txq); + + iwl_pcie_txq_free_tfd(trans, txq, DMA_TO_DEVICE); + } + + iwl_pcie_txq_progress(trans_pcie, txq); + + if (iwl_queue_space(&txq->q) > txq->q.low_mark) + iwl_wake_queue(trans, txq); +out: + spin_unlock(&txq->lock); } -static int iwl_txq_set_ratid_map(struct iwl_trans *trans, u16 ra_tid, +/* + * iwl_pcie_cmdq_reclaim - Reclaim TX command queue entries already Tx'd + * + * When FW advances 'R' index, all entries between old and new 'R' index + * need to be reclaimed. As result, some free space forms. If there is + * enough free space (> low mark), wake the stack that feeds us. + */ +static void iwl_pcie_cmdq_reclaim(struct iwl_trans *trans, int txq_id, int idx) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_txq *txq = &trans_pcie->txq[txq_id]; + struct iwl_queue *q = &txq->q; + int nfreed = 0; + + lockdep_assert_held(&txq->lock); + + if ((idx >= q->n_bd) || (!iwl_queue_used(q, idx))) { + IWL_ERR(trans, + "%s: Read index for DMA queue txq id (%d), index %d is out of range [0-%d] %d %d.\n", + __func__, txq_id, idx, q->n_bd, + q->write_ptr, q->read_ptr); + return; + } + + for (idx = iwl_queue_inc_wrap(idx, q->n_bd); q->read_ptr != idx; + q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { + + if (nfreed++ > 0) { + IWL_ERR(trans, "HCMD skipped: index (%d) %d %d\n", + idx, q->write_ptr, q->read_ptr); + iwl_op_mode_nic_error(trans->op_mode); + } + } + + iwl_pcie_txq_progress(trans_pcie, txq); +} + +static int iwl_pcie_txq_set_ratid_map(struct iwl_trans *trans, u16 ra_tid, u16 txq_id) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); @@ -405,7 +1014,8 @@ static int iwl_txq_set_ratid_map(struct iwl_trans *trans, u16 ra_tid, return 0; } -static inline void iwl_txq_set_inactive(struct iwl_trans *trans, u16 txq_id) +static inline void iwl_pcie_txq_set_inactive(struct iwl_trans *trans, + u16 txq_id) { /* Simply stop the queue, but don't change any configuration; * the SCD_ACT_EN bit is the write-enable mask for the ACTIVE bit. */ @@ -424,7 +1034,7 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, int fifo, WARN_ONCE(1, "queue %d already used - expect issues", txq_id); /* Stop this Tx queue before configuring it */ - iwl_txq_set_inactive(trans, txq_id); + iwl_pcie_txq_set_inactive(trans, txq_id); /* Set this queue as a chain-building queue unless it is CMD queue */ if (txq_id != trans_pcie->cmd_queue) @@ -435,7 +1045,7 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, int fifo, u16 ra_tid = BUILD_RAxTID(sta_id, tid); /* Map receiver-address / traffic-ID to this queue */ - iwl_txq_set_ratid_map(trans, ra_tid, txq_id); + iwl_pcie_txq_set_ratid_map(trans, ra_tid, txq_id); /* enable aggregations for the queue */ iwl_set_bits_prph(trans, SCD_AGGR_SEL, BIT(txq_id)); @@ -489,20 +1099,20 @@ void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id) return; } - iwl_txq_set_inactive(trans, txq_id); + iwl_pcie_txq_set_inactive(trans, txq_id); _iwl_write_targ_mem_dwords(trans, stts_addr, zero_val, ARRAY_SIZE(zero_val)); - iwl_tx_queue_unmap(trans, txq_id); + iwl_pcie_txq_unmap(trans, txq_id); IWL_DEBUG_TX_QUEUES(trans, "Deactivate queue %d\n", txq_id); } /*************** HOST COMMAND QUEUE FUNCTIONS *****/ -/** - * iwl_enqueue_hcmd - enqueue a uCode command +/* + * iwl_pcie_enqueue_hcmd - enqueue a uCode command * @priv: device private data point * @cmd: a point to the ucode command structure * @@ -510,10 +1120,11 @@ void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id) * failed. On success, it turns the index (> 0) of command in the * command queue. */ -static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) +static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, + struct iwl_host_cmd *cmd) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_tx_queue *txq = &trans_pcie->txq[trans_pcie->cmd_queue]; + struct iwl_txq *txq = &trans_pcie->txq[trans_pcie->cmd_queue]; struct iwl_queue *q = &txq->q; struct iwl_device_cmd *out_cmd; struct iwl_cmd_meta *out_meta; @@ -576,8 +1187,7 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) */ if (WARN(copy_size > TFD_MAX_PAYLOAD_SIZE, "Command %s (%#x) is too large (%d bytes)\n", - trans_pcie_get_cmd_string(trans_pcie, cmd->id), - cmd->id, copy_size)) { + get_cmd_string(trans_pcie, cmd->id), cmd->id, copy_size)) { idx = -EINVAL; goto free_dup_buf; } @@ -640,7 +1250,7 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) IWL_DEBUG_HC(trans, "Sending command %s (#%x), seq: 0x%04X, %d bytes at %d[%d]:%d\n", - trans_pcie_get_cmd_string(trans_pcie, out_cmd->hdr.cmd), + get_cmd_string(trans_pcie, out_cmd->hdr.cmd), out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence), cmd_size, q->write_ptr, idx, trans_pcie->cmd_queue); @@ -654,7 +1264,7 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) dma_unmap_addr_set(out_meta, mapping, phys_addr); dma_unmap_len_set(out_meta, len, copy_size); - iwlagn_txq_attach_buf_to_tfd(trans, txq, phys_addr, copy_size, 1); + iwl_pcie_txq_build_tfd(trans, txq, phys_addr, copy_size, 1); for (i = 0; i < IWL_MAX_CMD_TFDS; i++) { const void *data = cmd->data[i]; @@ -669,15 +1279,14 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) phys_addr = dma_map_single(trans->dev, (void *)data, cmd->len[i], DMA_BIDIRECTIONAL); if (dma_mapping_error(trans->dev, phys_addr)) { - iwl_unmap_tfd(trans, out_meta, - &txq->tfds[q->write_ptr], - DMA_BIDIRECTIONAL); + iwl_pcie_tfd_unmap(trans, out_meta, + &txq->tfds[q->write_ptr], + DMA_BIDIRECTIONAL); idx = -ENOMEM; goto out; } - iwlagn_txq_attach_buf_to_tfd(trans, txq, phys_addr, - cmd->len[i], 0); + iwl_pcie_txq_build_tfd(trans, txq, phys_addr, cmd->len[i], 0); } out_meta->flags = cmd->flags; @@ -696,7 +1305,7 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) /* Increment and update queue's write index */ q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); - iwl_txq_update_write_ptr(trans, txq); + iwl_pcie_txq_inc_wr_ptr(trans, txq); out: spin_unlock_bh(&txq->lock); @@ -706,63 +1315,8 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) return idx; } -static inline void iwl_queue_progress(struct iwl_trans_pcie *trans_pcie, - struct iwl_tx_queue *txq) -{ - if (!trans_pcie->wd_timeout) - return; - - /* - * if empty delete timer, otherwise move timer forward - * since we're making progress on this queue - */ - if (txq->q.read_ptr == txq->q.write_ptr) - del_timer(&txq->stuck_timer); - else - mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout); -} - -/** - * iwl_hcmd_queue_reclaim - Reclaim TX command queue entries already Tx'd - * - * When FW advances 'R' index, all entries between old and new 'R' index - * need to be reclaimed. As result, some free space forms. If there is - * enough free space (> low mark), wake the stack that feeds us. - */ -static void iwl_hcmd_queue_reclaim(struct iwl_trans *trans, int txq_id, - int idx) -{ - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id]; - struct iwl_queue *q = &txq->q; - int nfreed = 0; - - lockdep_assert_held(&txq->lock); - - if ((idx >= q->n_bd) || (iwl_queue_used(q, idx) == 0)) { - IWL_ERR(trans, - "%s: Read index for DMA queue txq id (%d), index %d is out of range [0-%d] %d %d.\n", - __func__, txq_id, idx, q->n_bd, - q->write_ptr, q->read_ptr); - return; - } - - for (idx = iwl_queue_inc_wrap(idx, q->n_bd); q->read_ptr != idx; - q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { - - if (nfreed++ > 0) { - IWL_ERR(trans, "HCMD skipped: index (%d) %d %d\n", - idx, q->write_ptr, q->read_ptr); - iwl_op_mode_nic_error(trans->op_mode); - } - - } - - iwl_queue_progress(trans_pcie, txq); -} - -/** - * iwl_tx_cmd_complete - Pull unused buffers off the queue and reclaim them +/* + * iwl_pcie_hcmd_complete - Pull unused buffers off the queue and reclaim them * @rxb: Rx buffer to reclaim * @handler_status: return value of the handler of the command * (put in setup_rx_handlers) @@ -771,8 +1325,8 @@ static void iwl_hcmd_queue_reclaim(struct iwl_trans *trans, int txq_id, * will be executed. The attached skb (if present) will only be freed * if the callback returns 1 */ -void iwl_tx_cmd_complete(struct iwl_trans *trans, struct iwl_rx_cmd_buffer *rxb, - int handler_status) +void iwl_pcie_hcmd_complete(struct iwl_trans *trans, + struct iwl_rx_cmd_buffer *rxb, int handler_status) { struct iwl_rx_packet *pkt = rxb_addr(rxb); u16 sequence = le16_to_cpu(pkt->hdr.sequence); @@ -782,7 +1336,7 @@ void iwl_tx_cmd_complete(struct iwl_trans *trans, struct iwl_rx_cmd_buffer *rxb, struct iwl_device_cmd *cmd; struct iwl_cmd_meta *meta; struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_tx_queue *txq = &trans_pcie->txq[trans_pcie->cmd_queue]; + struct iwl_txq *txq = &trans_pcie->txq[trans_pcie->cmd_queue]; /* If a Tx command is being handled and it isn't in the actual * command queue then there a command routing bug has been introduced @@ -802,7 +1356,7 @@ void iwl_tx_cmd_complete(struct iwl_trans *trans, struct iwl_rx_cmd_buffer *rxb, cmd = txq->entries[cmd_index].cmd; meta = &txq->entries[cmd_index].meta; - iwl_unmap_tfd(trans, meta, &txq->tfds[index], DMA_BIDIRECTIONAL); + iwl_pcie_tfd_unmap(trans, meta, &txq->tfds[index], DMA_BIDIRECTIONAL); /* Input error checking is done when commands are added to queue. */ if (meta->flags & CMD_WANT_SKB) { @@ -814,19 +1368,17 @@ void iwl_tx_cmd_complete(struct iwl_trans *trans, struct iwl_rx_cmd_buffer *rxb, meta->source->handler_status = handler_status; } - iwl_hcmd_queue_reclaim(trans, txq_id, index); + iwl_pcie_cmdq_reclaim(trans, txq_id, index); if (!(meta->flags & CMD_ASYNC)) { if (!test_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status)) { IWL_WARN(trans, "HCMD_ACTIVE already clear for command %s\n", - trans_pcie_get_cmd_string(trans_pcie, - cmd->hdr.cmd)); + get_cmd_string(trans_pcie, cmd->hdr.cmd)); } clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status); IWL_DEBUG_INFO(trans, "Clearing HCMD_ACTIVE for command %s\n", - trans_pcie_get_cmd_string(trans_pcie, - cmd->hdr.cmd)); + get_cmd_string(trans_pcie, cmd->hdr.cmd)); wake_up(&trans_pcie->wait_command_queue); } @@ -837,7 +1389,8 @@ void iwl_tx_cmd_complete(struct iwl_trans *trans, struct iwl_rx_cmd_buffer *rxb, #define HOST_COMPLETE_TIMEOUT (2 * HZ) -static int iwl_send_cmd_async(struct iwl_trans *trans, struct iwl_host_cmd *cmd) +static int iwl_pcie_send_hcmd_async(struct iwl_trans *trans, + struct iwl_host_cmd *cmd) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); int ret; @@ -846,43 +1399,43 @@ static int iwl_send_cmd_async(struct iwl_trans *trans, struct iwl_host_cmd *cmd) if (WARN_ON(cmd->flags & CMD_WANT_SKB)) return -EINVAL; - - ret = iwl_enqueue_hcmd(trans, cmd); + ret = iwl_pcie_enqueue_hcmd(trans, cmd); if (ret < 0) { IWL_ERR(trans, "Error sending %s: enqueue_hcmd failed: %d\n", - trans_pcie_get_cmd_string(trans_pcie, cmd->id), ret); + get_cmd_string(trans_pcie, cmd->id), ret); return ret; } return 0; } -static int iwl_send_cmd_sync(struct iwl_trans *trans, struct iwl_host_cmd *cmd) +static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans, + struct iwl_host_cmd *cmd) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); int cmd_idx; int ret; IWL_DEBUG_INFO(trans, "Attempting to send sync command %s\n", - trans_pcie_get_cmd_string(trans_pcie, cmd->id)); + get_cmd_string(trans_pcie, cmd->id)); if (WARN_ON(test_and_set_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status))) { IWL_ERR(trans, "Command %s: a command is already active!\n", - trans_pcie_get_cmd_string(trans_pcie, cmd->id)); + get_cmd_string(trans_pcie, cmd->id)); return -EIO; } IWL_DEBUG_INFO(trans, "Setting HCMD_ACTIVE for command %s\n", - trans_pcie_get_cmd_string(trans_pcie, cmd->id)); + get_cmd_string(trans_pcie, cmd->id)); - cmd_idx = iwl_enqueue_hcmd(trans, cmd); + cmd_idx = iwl_pcie_enqueue_hcmd(trans, cmd); if (cmd_idx < 0) { ret = cmd_idx; clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status); IWL_ERR(trans, "Error sending %s: enqueue_hcmd failed: %d\n", - trans_pcie_get_cmd_string(trans_pcie, cmd->id), ret); + get_cmd_string(trans_pcie, cmd->id), ret); return ret; } @@ -892,13 +1445,13 @@ static int iwl_send_cmd_sync(struct iwl_trans *trans, struct iwl_host_cmd *cmd) HOST_COMPLETE_TIMEOUT); if (!ret) { if (test_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status)) { - struct iwl_tx_queue *txq = + struct iwl_txq *txq = &trans_pcie->txq[trans_pcie->cmd_queue]; struct iwl_queue *q = &txq->q; IWL_ERR(trans, "Error sending %s: time out after %dms.\n", - trans_pcie_get_cmd_string(trans_pcie, cmd->id), + get_cmd_string(trans_pcie, cmd->id), jiffies_to_msecs(HOST_COMPLETE_TIMEOUT)); IWL_ERR(trans, @@ -908,8 +1461,7 @@ static int iwl_send_cmd_sync(struct iwl_trans *trans, struct iwl_host_cmd *cmd) clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status); IWL_DEBUG_INFO(trans, "Clearing HCMD_ACTIVE for command %s\n", - trans_pcie_get_cmd_string(trans_pcie, - cmd->id)); + get_cmd_string(trans_pcie, cmd->id)); ret = -ETIMEDOUT; goto cancel; } @@ -917,7 +1469,7 @@ static int iwl_send_cmd_sync(struct iwl_trans *trans, struct iwl_host_cmd *cmd) if (test_bit(STATUS_FW_ERROR, &trans_pcie->status)) { IWL_ERR(trans, "FW error in SYNC CMD %s\n", - trans_pcie_get_cmd_string(trans_pcie, cmd->id)); + get_cmd_string(trans_pcie, cmd->id)); ret = -EIO; goto cancel; } @@ -930,7 +1482,7 @@ static int iwl_send_cmd_sync(struct iwl_trans *trans, struct iwl_host_cmd *cmd) if ((cmd->flags & CMD_WANT_SKB) && !cmd->resp_pkt) { IWL_ERR(trans, "Error: Response NULL in '%s'\n", - trans_pcie_get_cmd_string(trans_pcie, cmd->id)); + get_cmd_string(trans_pcie, cmd->id)); ret = -EIO; goto cancel; } @@ -957,7 +1509,7 @@ cancel: return ret; } -int iwl_trans_pcie_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) +int iwl_trans_pcie_send_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); @@ -968,62 +1520,172 @@ int iwl_trans_pcie_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) return -ERFKILL; if (cmd->flags & CMD_ASYNC) - return iwl_send_cmd_async(trans, cmd); + return iwl_pcie_send_hcmd_async(trans, cmd); /* We still can fail on RFKILL that can be asserted while we wait */ - return iwl_send_cmd_sync(trans, cmd); + return iwl_pcie_send_hcmd_sync(trans, cmd); } -/* Frees buffers until index _not_ inclusive */ -int iwl_tx_queue_reclaim(struct iwl_trans *trans, int txq_id, int index, - struct sk_buff_head *skbs) +int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, + struct iwl_device_cmd *dev_cmd, int txq_id) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id]; - struct iwl_queue *q = &txq->q; - int last_to_free; - int freed = 0; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct iwl_tx_cmd *tx_cmd = (struct iwl_tx_cmd *)dev_cmd->payload; + struct iwl_cmd_meta *out_meta; + struct iwl_txq *txq; + struct iwl_queue *q; + dma_addr_t phys_addr = 0; + dma_addr_t txcmd_phys; + dma_addr_t scratch_phys; + u16 len, firstlen, secondlen; + u8 wait_write_ptr = 0; + __le16 fc = hdr->frame_control; + u8 hdr_len = ieee80211_hdrlen(fc); + u16 __maybe_unused wifi_seq; + + txq = &trans_pcie->txq[txq_id]; + q = &txq->q; - /* This function is not meant to release cmd queue*/ - if (WARN_ON(txq_id == trans_pcie->cmd_queue)) - return 0; + if (unlikely(!test_bit(txq_id, trans_pcie->queue_used))) { + WARN_ON_ONCE(1); + return -EINVAL; + } - lockdep_assert_held(&txq->lock); + spin_lock(&txq->lock); - /*Since we free until index _not_ inclusive, the one before index is - * the last we will free. This one must be used */ - last_to_free = iwl_queue_dec_wrap(index, q->n_bd); + /* In AGG mode, the index in the ring must correspond to the WiFi + * sequence number. This is a HW requirements to help the SCD to parse + * the BA. + * Check here that the packets are in the right place on the ring. + */ +#ifdef CONFIG_IWLWIFI_DEBUG + wifi_seq = SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)); + WARN_ONCE((iwl_read_prph(trans, SCD_AGGR_SEL) & BIT(txq_id)) && + ((wifi_seq & 0xff) != q->write_ptr), + "Q: %d WiFi Seq %d tfdNum %d", + txq_id, wifi_seq, q->write_ptr); +#endif + + /* Set up driver data for this TFD */ + txq->entries[q->write_ptr].skb = skb; + txq->entries[q->write_ptr].cmd = dev_cmd; + + dev_cmd->hdr.cmd = REPLY_TX; + dev_cmd->hdr.sequence = + cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) | + INDEX_TO_SEQ(q->write_ptr))); + + /* Set up first empty entry in queue's array of Tx/cmd buffers */ + out_meta = &txq->entries[q->write_ptr].meta; - if ((index >= q->n_bd) || - (iwl_queue_used(q, last_to_free) == 0)) { - IWL_ERR(trans, - "%s: Read index for DMA queue txq id (%d), last_to_free %d is out of range [0-%d] %d %d.\n", - __func__, txq_id, last_to_free, q->n_bd, - q->write_ptr, q->read_ptr); - return 0; + /* + * Use the first empty entry in this queue's command buffer array + * to contain the Tx command and MAC header concatenated together + * (payload data will be in another buffer). + * Size of this varies, due to varying MAC header length. + * If end is not dword aligned, we'll have 2 extra bytes at the end + * of the MAC header (device reads on dword boundaries). + * We'll tell device about this padding later. + */ + len = sizeof(struct iwl_tx_cmd) + + sizeof(struct iwl_cmd_header) + hdr_len; + firstlen = (len + 3) & ~3; + + /* Tell NIC about any 2-byte padding after MAC header */ + if (firstlen != len) + tx_cmd->tx_flags |= TX_CMD_FLG_MH_PAD_MSK; + + /* Physical address of this Tx command's header (not MAC header!), + * within command buffer array. */ + txcmd_phys = dma_map_single(trans->dev, + &dev_cmd->hdr, firstlen, + DMA_BIDIRECTIONAL); + if (unlikely(dma_mapping_error(trans->dev, txcmd_phys))) + goto out_err; + dma_unmap_addr_set(out_meta, mapping, txcmd_phys); + dma_unmap_len_set(out_meta, len, firstlen); + + if (!ieee80211_has_morefrags(fc)) { + txq->need_update = 1; + } else { + wait_write_ptr = 1; + txq->need_update = 0; } - if (WARN_ON(!skb_queue_empty(skbs))) - return 0; + /* Set up TFD's 2nd entry to point directly to remainder of skb, + * if any (802.11 null frames have no payload). */ + secondlen = skb->len - hdr_len; + if (secondlen > 0) { + phys_addr = dma_map_single(trans->dev, skb->data + hdr_len, + secondlen, DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(trans->dev, phys_addr))) { + dma_unmap_single(trans->dev, + dma_unmap_addr(out_meta, mapping), + dma_unmap_len(out_meta, len), + DMA_BIDIRECTIONAL); + goto out_err; + } + } - for (; - q->read_ptr != index; - q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { + /* Attach buffers to TFD */ + iwl_pcie_txq_build_tfd(trans, txq, txcmd_phys, firstlen, 1); + if (secondlen > 0) + iwl_pcie_txq_build_tfd(trans, txq, phys_addr, secondlen, 0); - if (WARN_ON_ONCE(txq->entries[txq->q.read_ptr].skb == NULL)) - continue; + scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) + + offsetof(struct iwl_tx_cmd, scratch); - __skb_queue_tail(skbs, txq->entries[txq->q.read_ptr].skb); + /* take back ownership of DMA buffer to enable update */ + dma_sync_single_for_cpu(trans->dev, txcmd_phys, firstlen, + DMA_BIDIRECTIONAL); + tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys); + tx_cmd->dram_msb_ptr = iwl_get_dma_hi_addr(scratch_phys); - txq->entries[txq->q.read_ptr].skb = NULL; + IWL_DEBUG_TX(trans, "sequence nr = 0X%x\n", + le16_to_cpu(dev_cmd->hdr.sequence)); + IWL_DEBUG_TX(trans, "tx_flags = 0X%x\n", le32_to_cpu(tx_cmd->tx_flags)); - iwlagn_txq_inval_byte_cnt_tbl(trans, txq); + /* Set up entry for this TFD in Tx byte-count array */ + iwl_pcie_txq_update_byte_cnt_tbl(trans, txq, le16_to_cpu(tx_cmd->len)); - iwl_txq_free_tfd(trans, txq, DMA_TO_DEVICE); - freed++; - } + dma_sync_single_for_device(trans->dev, txcmd_phys, firstlen, + DMA_BIDIRECTIONAL); + + trace_iwlwifi_dev_tx(trans->dev, skb, + &txq->tfds[txq->q.write_ptr], + sizeof(struct iwl_tfd), + &dev_cmd->hdr, firstlen, + skb->data + hdr_len, secondlen); + trace_iwlwifi_dev_tx_data(trans->dev, skb, + skb->data + hdr_len, secondlen); + + /* start timer if queue currently empty */ + if (txq->need_update && q->read_ptr == q->write_ptr && + trans_pcie->wd_timeout) + mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout); - iwl_queue_progress(trans_pcie, txq); + /* Tell device the write index *just past* this latest filled TFD */ + q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); + iwl_pcie_txq_inc_wr_ptr(trans, txq); - return freed; + /* + * At this point the frame is "transmitted" successfully + * and we will get a TX status notification eventually, + * regardless of the value of ret. "ret" only indicates + * whether or not we should update the write pointer. + */ + if (iwl_queue_space(q) < q->high_mark) { + if (wait_write_ptr) { + txq->need_update = 1; + iwl_pcie_txq_inc_wr_ptr(trans, txq); + } else { + iwl_stop_queue(trans, txq); + } + } + spin_unlock(&txq->lock); + return 0; +out_err: + spin_unlock(&txq->lock); + return -1; } diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c index 1c10b54..ec36868 100644 --- a/drivers/net/wireless/libertas/cfg.c +++ b/drivers/net/wireless/libertas/cfg.c @@ -436,19 +436,19 @@ static int lbs_add_wpa_tlv(u8 *tlv, const u8 *ie, u8 ie_len) */ static int lbs_cfg_set_monitor_channel(struct wiphy *wiphy, - struct ieee80211_channel *channel, - enum nl80211_channel_type channel_type) + struct cfg80211_chan_def *chandef) { struct lbs_private *priv = wiphy_priv(wiphy); int ret = -ENOTSUPP; lbs_deb_enter_args(LBS_DEB_CFG80211, "freq %d, type %d", - channel->center_freq, channel_type); + chandef->chan->center_freq, + cfg80211_get_chandef_type(chandef)); - if (channel_type != NL80211_CHAN_NO_HT) + if (cfg80211_get_chandef_type(chandef) != NL80211_CHAN_NO_HT) goto out; - ret = lbs_set_channel(priv, channel->hw_value); + ret = lbs_set_channel(priv, chandef->chan->hw_value); out: lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); @@ -1734,7 +1734,7 @@ static void lbs_join_post(struct lbs_private *priv, /* Fake DS channel IE */ *fake++ = WLAN_EID_DS_PARAMS; *fake++ = 1; - *fake++ = params->channel->hw_value; + *fake++ = params->chandef.chan->hw_value; /* Fake IBSS params IE */ *fake++ = WLAN_EID_IBSS_PARAMS; *fake++ = 2; @@ -1755,7 +1755,7 @@ static void lbs_join_post(struct lbs_private *priv, lbs_deb_hex(LBS_DEB_CFG80211, "IE", fake_ie, fake - fake_ie); bss = cfg80211_inform_bss(priv->wdev->wiphy, - params->channel, + params->chandef.chan, bssid, 0, capability, @@ -1833,7 +1833,7 @@ static int lbs_ibss_join_existing(struct lbs_private *priv, cmd.bss.beaconperiod = cpu_to_le16(params->beacon_interval); cmd.bss.ds.header.id = WLAN_EID_DS_PARAMS; cmd.bss.ds.header.len = 1; - cmd.bss.ds.channel = params->channel->hw_value; + cmd.bss.ds.channel = params->chandef.chan->hw_value; cmd.bss.ibss.header.id = WLAN_EID_IBSS_PARAMS; cmd.bss.ibss.header.len = 2; cmd.bss.ibss.atimwindow = 0; @@ -1942,7 +1942,7 @@ static int lbs_ibss_start_new(struct lbs_private *priv, cmd.ibss.atimwindow = 0; cmd.ds.header.id = WLAN_EID_DS_PARAMS; cmd.ds.header.len = 1; - cmd.ds.channel = params->channel->hw_value; + cmd.ds.channel = params->chandef.chan->hw_value; /* Only v8 and below support setting probe delay */ if (MRVL_FW_MAJOR_REV(priv->fwrelease) <= 8) cmd.probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME); @@ -1987,18 +1987,18 @@ static int lbs_join_ibss(struct wiphy *wiphy, struct net_device *dev, lbs_deb_enter(LBS_DEB_CFG80211); - if (!params->channel) { + if (!params->chandef.chan) { ret = -ENOTSUPP; goto out; } - ret = lbs_set_channel(priv, params->channel->hw_value); + ret = lbs_set_channel(priv, params->chandef.chan->hw_value); if (ret) goto out; /* Search if someone is beaconing. This assumes that the * bss list is populated already */ - bss = cfg80211_get_bss(wiphy, params->channel, params->bssid, + bss = cfg80211_get_bss(wiphy, params->chandef.chan, params->bssid, params->ssid, params->ssid_len, WLAN_CAPABILITY_IBSS, WLAN_CAPABILITY_IBSS); diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index a8ec708..2aa8a1a 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -681,7 +681,7 @@ static void mac80211_hwsim_tx_iter(void *_data, u8 *addr, return; if (!hwsim_chans_compat(data->channel, - rcu_dereference(vif->chanctx_conf)->channel)) + rcu_dereference(vif->chanctx_conf)->def.chan)) return; data->receive = true; @@ -699,7 +699,7 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw, struct ieee80211_rate *txrate = ieee80211_get_tx_rate(hw, info); memset(&rx_status, 0, sizeof(rx_status)); - rx_status.flag |= RX_FLAG_MACTIME_MPDU; + rx_status.flag |= RX_FLAG_MACTIME_START; rx_status.freq = chan->center_freq; rx_status.band = chan->band; rx_status.rate_idx = info->control.rates[0].idx; @@ -751,7 +751,11 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw, continue; } - nskb = skb_copy(skb, GFP_ATOMIC); + /* + * reserve some space for our vendor and the normal + * radiotap header, since we're copying anyway + */ + nskb = skb_copy_expand(skb, 64, 0, GFP_ATOMIC); if (nskb == NULL) continue; @@ -769,6 +773,33 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw, (data->tsf_offset - data2->tsf_offset) + 24 * 8 * 10 / txrate->bitrate); +#if 0 + /* + * Don't enable this code by default as the OUI 00:00:00 + * is registered to Xerox so we shouldn't use it here, it + * might find its way into pcap files. + * Note that this code requires the headroom in the SKB + * that was allocated earlier. + */ + rx_status.vendor_radiotap_oui[0] = 0x00; + rx_status.vendor_radiotap_oui[1] = 0x00; + rx_status.vendor_radiotap_oui[2] = 0x00; + rx_status.vendor_radiotap_subns = 127; + /* + * Radiotap vendor namespaces can (and should) also be + * split into fields by using the standard radiotap + * presence bitmap mechanism. Use just BIT(0) here for + * the presence bitmap. + */ + rx_status.vendor_radiotap_bitmap = BIT(0); + /* We have 8 bytes of (dummy) data */ + rx_status.vendor_radiotap_len = 8; + /* For testing, also require it to be aligned */ + rx_status.vendor_radiotap_align = 8; + /* push the data */ + memcpy(skb_push(nskb, 8), "ABCDEFGH", 8); +#endif + memcpy(IEEE80211_SKB_RXCB(nskb), &rx_status, sizeof(rx_status)); ieee80211_rx_irqsafe(data2->hw, nskb); } @@ -801,7 +832,7 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw, } else { chanctx_conf = rcu_dereference(txi->control.vif->chanctx_conf); if (chanctx_conf) - channel = chanctx_conf->channel; + channel = chanctx_conf->def.chan; else channel = NULL; } @@ -946,7 +977,7 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac, return; mac80211_hwsim_tx_frame(hw, skb, - rcu_dereference(vif->chanctx_conf)->channel); + rcu_dereference(vif->chanctx_conf)->def.chan); } @@ -1076,9 +1107,8 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw, } if (changed & BSS_CHANGED_HT) { - wiphy_debug(hw->wiphy, " HT: op_mode=0x%x, chantype=%s\n", - info->ht_operation_mode, - hwsim_chantypes[info->channel_type]); + wiphy_debug(hw->wiphy, " HT: op_mode=0x%x\n", + info->ht_operation_mode); } if (changed & BSS_CHANGED_BASIC_RATES) { @@ -1337,7 +1367,6 @@ static int mac80211_hwsim_hw_scan(struct ieee80211_hw *hw, struct cfg80211_scan_request *req) { struct mac80211_hwsim_data *hwsim = hw->priv; - int i; mutex_lock(&hwsim->mutex); if (WARN_ON(hwsim->tmp_chan || hwsim->hw_scan_request)) { @@ -1350,11 +1379,6 @@ static int mac80211_hwsim_hw_scan(struct ieee80211_hw *hw, mutex_unlock(&hwsim->mutex); wiphy_debug(hw->wiphy, "hwsim hw_scan request\n"); - for (i = 0; i < req->n_channels; i++) - printk(KERN_DEBUG "hwsim hw_scan freq %d\n", - req->channels[i]->center_freq); - print_hex_dump(KERN_DEBUG, "scan IEs: ", DUMP_PREFIX_OFFSET, - 16, 1, req->ie, req->ie_len, 1); ieee80211_queue_delayed_work(hwsim->hw, &hwsim->hw_scan, 0); @@ -1422,8 +1446,8 @@ static void hw_roc_done(struct work_struct *work) } static int mac80211_hwsim_roc(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type, int duration) { struct mac80211_hwsim_data *hwsim = hw->priv; @@ -1466,16 +1490,20 @@ static int mac80211_hwsim_add_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *ctx) { hwsim_set_chanctx_magic(ctx); - wiphy_debug(hw->wiphy, "add channel context %d MHz/%d\n", - ctx->channel->center_freq, ctx->channel_type); + wiphy_debug(hw->wiphy, + "add channel context control: %d MHz/width: %d/cfreqs:%d/%d MHz\n", + ctx->def.chan->center_freq, ctx->def.width, + ctx->def.center_freq1, ctx->def.center_freq2); return 0; } static void mac80211_hwsim_remove_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *ctx) { - wiphy_debug(hw->wiphy, "remove channel context %d MHz/%d\n", - ctx->channel->center_freq, ctx->channel_type); + wiphy_debug(hw->wiphy, + "remove channel context control: %d MHz/width: %d/cfreqs:%d/%d MHz\n", + ctx->def.chan->center_freq, ctx->def.width, + ctx->def.center_freq1, ctx->def.center_freq2); hwsim_check_chanctx_magic(ctx); hwsim_clear_chanctx_magic(ctx); } @@ -1485,8 +1513,10 @@ static void mac80211_hwsim_change_chanctx(struct ieee80211_hw *hw, u32 changed) { hwsim_check_chanctx_magic(ctx); - wiphy_debug(hw->wiphy, "change channel context %#x (%d MHz/%d)\n", - changed, ctx->channel->center_freq, ctx->channel_type); + wiphy_debug(hw->wiphy, + "change channel context control: %d MHz/width: %d/cfreqs:%d/%d MHz\n", + ctx->def.chan->center_freq, ctx->def.width, + ctx->def.center_freq1, ctx->def.center_freq2); } static int mac80211_hwsim_assign_vif_chanctx(struct ieee80211_hw *hw, @@ -1608,7 +1638,7 @@ static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif) rcu_read_lock(); mac80211_hwsim_tx_frame(data->hw, skb, - rcu_dereference(vif->chanctx_conf)->channel); + rcu_dereference(vif->chanctx_conf)->def.chan); rcu_read_unlock(); } @@ -1640,7 +1670,7 @@ static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac, rcu_read_lock(); mac80211_hwsim_tx_frame(data->hw, skb, - rcu_dereference(vif->chanctx_conf)->channel); + rcu_dereference(vif->chanctx_conf)->def.chan); rcu_read_unlock(); } @@ -2172,6 +2202,34 @@ static int __init init_mac80211_hwsim(void) sband->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; hw->wiphy->bands[band] = sband; + + if (channels == 1) + continue; + + sband->vht_cap.vht_supported = true; + sband->vht_cap.cap = + IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 | + IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ | + IEEE80211_VHT_CAP_RXLDPC | + IEEE80211_VHT_CAP_SHORT_GI_80 | + IEEE80211_VHT_CAP_SHORT_GI_160 | + IEEE80211_VHT_CAP_TXSTBC | + IEEE80211_VHT_CAP_RXSTBC_1 | + IEEE80211_VHT_CAP_RXSTBC_2 | + IEEE80211_VHT_CAP_RXSTBC_3 | + IEEE80211_VHT_CAP_RXSTBC_4 | + IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT; + sband->vht_cap.vht_mcs.rx_mcs_map = + cpu_to_le16(IEEE80211_VHT_MCS_SUPPORT_0_8 << 0 | + IEEE80211_VHT_MCS_SUPPORT_0_8 << 2 | + IEEE80211_VHT_MCS_SUPPORT_0_9 << 4 | + IEEE80211_VHT_MCS_SUPPORT_0_8 << 6 | + IEEE80211_VHT_MCS_SUPPORT_0_8 << 8 | + IEEE80211_VHT_MCS_SUPPORT_0_9 << 10 | + IEEE80211_VHT_MCS_SUPPORT_0_9 << 12 | + IEEE80211_VHT_MCS_SUPPORT_0_8 << 14); + sband->vht_cap.vht_mcs.tx_mcs_map = + sband->vht_cap.vht_mcs.rx_mcs_map; } /* By default all radios are belonging to the first group */ data->group = 1; diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 41be319..a875499 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -180,10 +180,8 @@ mwifiex_form_mgmt_frame(struct sk_buff *skb, const u8 *buf, size_t len) static int mwifiex_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, struct ieee80211_channel *chan, bool offchan, - enum nl80211_channel_type channel_type, - bool channel_type_valid, unsigned int wait, - const u8 *buf, size_t len, bool no_cck, - bool dont_wait_for_ack, u64 *cookie) + unsigned int wait, const u8 *buf, size_t len, + bool no_cck, bool dont_wait_for_ack, u64 *cookie) { struct sk_buff *skb; u16 pkt_len; @@ -253,7 +251,6 @@ static int mwifiex_cfg80211_remain_on_channel(struct wiphy *wiphy, struct wireless_dev *wdev, struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type, unsigned int duration, u64 *cookie) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev); @@ -271,15 +268,14 @@ mwifiex_cfg80211_remain_on_channel(struct wiphy *wiphy, } ret = mwifiex_remain_on_chan_cfg(priv, HostCmd_ACT_GEN_SET, chan, - &channel_type, duration); + duration); if (!ret) { *cookie = random32() | 1; priv->roc_cfg.cookie = *cookie; priv->roc_cfg.chan = *chan; - priv->roc_cfg.chan_type = channel_type; - cfg80211_ready_on_channel(wdev, *cookie, chan, channel_type, + cfg80211_ready_on_channel(wdev, *cookie, chan, duration, GFP_ATOMIC); wiphy_dbg(wiphy, "info: ROC, cookie = 0x%llx\n", *cookie); @@ -302,13 +298,11 @@ mwifiex_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, return -ENOENT; ret = mwifiex_remain_on_chan_cfg(priv, HostCmd_ACT_GEN_REMOVE, - &priv->roc_cfg.chan, - &priv->roc_cfg.chan_type, 0); + &priv->roc_cfg.chan, 0); if (!ret) { cfg80211_remain_on_channel_expired(wdev, cookie, &priv->roc_cfg.chan, - priv->roc_cfg.chan_type, GFP_ATOMIC); memset(&priv->roc_cfg, 0, sizeof(struct mwifiex_roc_cfg)); @@ -1297,21 +1291,23 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy, return -EINVAL; } - bss_cfg->channel = - (u8)ieee80211_frequency_to_channel(params->channel->center_freq); + bss_cfg->channel = ieee80211_frequency_to_channel( + params->chandef.chan->center_freq); /* Set appropriate bands */ - if (params->channel->band == IEEE80211_BAND_2GHZ) { + if (params->chandef.chan->band == IEEE80211_BAND_2GHZ) { bss_cfg->band_cfg = BAND_CONFIG_BG; - if (params->channel_type == NL80211_CHAN_NO_HT) + if (cfg80211_get_chandef_type(¶ms->chandef) == + NL80211_CHAN_NO_HT) config_bands = BAND_B | BAND_G; else config_bands = BAND_B | BAND_G | BAND_GN; } else { bss_cfg->band_cfg = BAND_CONFIG_A; - if (params->channel_type == NL80211_CHAN_NO_HT) + if (cfg80211_get_chandef_type(¶ms->chandef) == + NL80211_CHAN_NO_HT) config_bands = BAND_A; else config_bands = BAND_AN | BAND_A; @@ -1684,7 +1680,7 @@ static int mwifiex_set_ibss_params(struct mwifiex_private *priv, int index = 0, i; u8 config_bands = 0; - if (params->channel->band == IEEE80211_BAND_2GHZ) { + if (params->chandef.chan->band == IEEE80211_BAND_2GHZ) { if (!params->basic_rates) { config_bands = BAND_B | BAND_G; } else { @@ -1709,10 +1705,12 @@ static int mwifiex_set_ibss_params(struct mwifiex_private *priv, } } - if (params->channel_type != NL80211_CHAN_NO_HT) + if (cfg80211_get_chandef_type(¶ms->chandef) != + NL80211_CHAN_NO_HT) config_bands |= BAND_GN; } else { - if (params->channel_type == NL80211_CHAN_NO_HT) + if (cfg80211_get_chandef_type(¶ms->chandef) != + NL80211_CHAN_NO_HT) config_bands = BAND_A; else config_bands = BAND_AN | BAND_A; @@ -1729,9 +1727,10 @@ static int mwifiex_set_ibss_params(struct mwifiex_private *priv, } adapter->sec_chan_offset = - mwifiex_chan_type_to_sec_chan_offset(params->channel_type); - priv->adhoc_channel = - ieee80211_frequency_to_channel(params->channel->center_freq); + mwifiex_chan_type_to_sec_chan_offset( + cfg80211_get_chandef_type(¶ms->chandef)); + priv->adhoc_channel = ieee80211_frequency_to_channel( + params->chandef.chan->center_freq); wiphy_dbg(wiphy, "info: set ibss band %d, chan %d, chan offset %d\n", config_bands, priv->adhoc_channel, adapter->sec_chan_offset); @@ -1765,7 +1764,8 @@ mwifiex_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, ret = mwifiex_cfg80211_assoc(priv, params->ssid_len, params->ssid, params->bssid, priv->bss_mode, - params->channel, NULL, params->privacy); + params->chandef.chan, NULL, + params->privacy); done: if (!ret) { cfg80211_ibss_joined(priv->netdev, priv->cfg_bssid, GFP_KERNEL); @@ -1948,6 +1948,21 @@ mwifiex_setup_ht_caps(struct ieee80211_sta_ht_cap *ht_info, else ht_info->cap &= ~IEEE80211_HT_CAP_TX_STBC; + if (ISSUPP_GREENFIELD(adapter->hw_dot_11n_dev_cap)) + ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD; + else + ht_info->cap &= ~IEEE80211_HT_CAP_GRN_FLD; + + if (ISENABLED_40MHZ_INTOLERANT(adapter->hw_dot_11n_dev_cap)) + ht_info->cap |= IEEE80211_HT_CAP_40MHZ_INTOLERANT; + else + ht_info->cap &= ~IEEE80211_HT_CAP_40MHZ_INTOLERANT; + + if (ISSUPP_RXLDPC(adapter->hw_dot_11n_dev_cap)) + ht_info->cap |= IEEE80211_HT_CAP_LDPC_CODING; + else + ht_info->cap &= ~IEEE80211_HT_CAP_LDPC_CODING; + ht_info->cap &= ~IEEE80211_HT_CAP_MAX_AMSDU; ht_info->cap |= IEEE80211_HT_CAP_SM_PS; diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index c9528b3..5f438e6 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -890,9 +890,6 @@ mwifiex_cmd_timeout_func(unsigned long function_context) return; } cmd_node = adapter->curr_cmd; - if (cmd_node->wait_q_enabled) - adapter->cmd_wait_q.status = -ETIMEDOUT; - if (cmd_node) { adapter->dbg.timeout_cmd_id = adapter->dbg.last_cmd_id[adapter->dbg.last_cmd_index]; @@ -941,6 +938,14 @@ mwifiex_cmd_timeout_func(unsigned long function_context) dev_err(adapter->dev, "ps_mode=%d ps_state=%d\n", adapter->ps_mode, adapter->ps_state); + + if (cmd_node->wait_q_enabled) { + adapter->cmd_wait_q.status = -ETIMEDOUT; + wake_up_interruptible(&adapter->cmd_wait_q.wait); + mwifiex_cancel_pending_ioctl(adapter); + /* reset cmd_sent flag to unblock new commands */ + adapter->cmd_sent = false; + } } if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING) mwifiex_init_fw_complete(adapter); diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index dda588b..4dc8e2e 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -194,6 +194,8 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define ISSUPP_TXSTBC(Dot11nDevCap) (Dot11nDevCap & BIT(25)) #define ISSUPP_RXSTBC(Dot11nDevCap) (Dot11nDevCap & BIT(26)) #define ISSUPP_GREENFIELD(Dot11nDevCap) (Dot11nDevCap & BIT(29)) +#define ISENABLED_40MHZ_INTOLERANT(Dot11nDevCap) (Dot11nDevCap & BIT(8)) +#define ISSUPP_RXLDPC(Dot11nDevCap) (Dot11nDevCap & BIT(22)) /* httxcfg bitmap * 0 reserved diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index db57dd4..1b3cfc8 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -371,7 +371,6 @@ struct wps { struct mwifiex_roc_cfg { u64 cookie; struct ieee80211_channel chan; - enum nl80211_channel_type chan_type; }; struct mwifiex_adapter; @@ -1018,7 +1017,6 @@ int mwifiex_get_ver_ext(struct mwifiex_private *priv); int mwifiex_remain_on_chan_cfg(struct mwifiex_private *priv, u16 action, struct ieee80211_channel *chan, - enum nl80211_channel_type *channel_type, unsigned int duration); int mwifiex_set_bss_role(struct mwifiex_private *priv, u8 bss_role); diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index 4fbbd61..5a1c1d0 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -161,7 +161,6 @@ static int mwifiex_sdio_suspend(struct device *dev) struct sdio_mmc_card *card; struct mwifiex_adapter *adapter; mmc_pm_flag_t pm_flag = 0; - int hs_actived = 0; int i; int ret = 0; @@ -188,12 +187,14 @@ static int mwifiex_sdio_suspend(struct device *dev) adapter = card->adapter; /* Enable the Host Sleep */ - hs_actived = mwifiex_enable_hs(adapter); - if (hs_actived) { - pr_debug("cmd: suspend with MMC_PM_KEEP_POWER\n"); - ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); + if (!mwifiex_enable_hs(adapter)) { + dev_err(adapter->dev, "cmd: failed to suspend\n"); + return -EFAULT; } + dev_dbg(adapter->dev, "cmd: suspend with MMC_PM_KEEP_POWER\n"); + ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); + /* Indicate device suspended */ adapter->is_suspended = true; diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c index 5b0d719..41aafc7 100644 --- a/drivers/net/wireless/mwifiex/sta_event.c +++ b/drivers/net/wireless/mwifiex/sta_event.c @@ -421,7 +421,6 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) cfg80211_remain_on_channel_expired(priv->wdev, priv->roc_cfg.cookie, &priv->roc_cfg.chan, - priv->roc_cfg.chan_type, GFP_ATOMIC); memset(&priv->roc_cfg, 0x00, sizeof(struct mwifiex_roc_cfg)); diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index c8b50c7..95e3ab5 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -161,8 +161,9 @@ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv, int ret; u8 *beacon_ie; struct mwifiex_bss_priv *bss_priv = (void *)bss->priv; + size_t beacon_ie_len = bss->len_information_elements; - beacon_ie = kmemdup(bss->information_elements, bss->len_beacon_ies, + beacon_ie = kmemdup(bss->information_elements, beacon_ie_len, GFP_KERNEL); if (!beacon_ie) { dev_err(priv->adapter->dev, " failed to alloc beacon_ie\n"); @@ -172,7 +173,7 @@ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv, memcpy(bss_desc->mac_address, bss->bssid, ETH_ALEN); bss_desc->rssi = bss->signal; bss_desc->beacon_buf = beacon_ie; - bss_desc->beacon_buf_size = bss->len_beacon_ies; + bss_desc->beacon_buf_size = beacon_ie_len; bss_desc->beacon_period = bss->beacon_interval; bss_desc->cap_info_bitmap = bss->capability; bss_desc->bss_band = bss_priv->band; @@ -461,7 +462,7 @@ int mwifiex_enable_hs(struct mwifiex_adapter *adapter) } if (adapter->hs_activated) { - dev_dbg(adapter->dev, "cmd: HS Already actived\n"); + dev_dbg(adapter->dev, "cmd: HS Already activated\n"); return true; } @@ -1044,7 +1045,6 @@ mwifiex_get_ver_ext(struct mwifiex_private *priv) int mwifiex_remain_on_chan_cfg(struct mwifiex_private *priv, u16 action, struct ieee80211_channel *chan, - enum nl80211_channel_type *ct, unsigned int duration) { struct host_cmd_ds_remain_on_chan roc_cfg; @@ -1054,7 +1054,7 @@ mwifiex_remain_on_chan_cfg(struct mwifiex_private *priv, u16 action, roc_cfg.action = cpu_to_le16(action); if (action == HostCmd_ACT_GEN_SET) { roc_cfg.band_cfg = chan->band; - sc = mwifiex_chan_type_to_sec_chan_offset(*ct); + sc = mwifiex_chan_type_to_sec_chan_offset(NL80211_CHAN_NO_HT); roc_cfg.band_cfg |= (sc << 2); roc_cfg.channel = diff --git a/drivers/net/wireless/mwifiex/usb.c b/drivers/net/wireless/mwifiex/usb.c index bbe1f35..63ac9f2 100644 --- a/drivers/net/wireless/mwifiex/usb.c +++ b/drivers/net/wireless/mwifiex/usb.c @@ -351,7 +351,7 @@ static int mwifiex_usb_probe(struct usb_interface *intf, card->udev = udev; card->intf = intf; - pr_debug("info: bcdUSB=%#x Device Class=%#x SubClass=%#x Protocl=%#x\n", + pr_debug("info: bcdUSB=%#x Device Class=%#x SubClass=%#x Protocol=%#x\n", udev->descriptor.bcdUSB, udev->descriptor.bDeviceClass, udev->descriptor.bDeviceSubClass, udev->descriptor.bDeviceProtocol); diff --git a/drivers/net/wireless/orinoco/cfg.c b/drivers/net/wireless/orinoco/cfg.c index 7b751fb..d01edd2 100644 --- a/drivers/net/wireless/orinoco/cfg.c +++ b/drivers/net/wireless/orinoco/cfg.c @@ -161,24 +161,23 @@ static int orinoco_scan(struct wiphy *wiphy, } static int orinoco_set_monitor_channel(struct wiphy *wiphy, - struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type) + struct cfg80211_chan_def *chandef) { struct orinoco_private *priv = wiphy_priv(wiphy); int err = 0; unsigned long flags; int channel; - if (!chan) + if (!chandef->chan) return -EINVAL; - if (channel_type != NL80211_CHAN_NO_HT) + if (cfg80211_get_chandef_type(chandef) != NL80211_CHAN_NO_HT) return -EINVAL; - if (chan->band != IEEE80211_BAND_2GHZ) + if (chandef->chan->band != IEEE80211_BAND_2GHZ) return -EINVAL; - channel = ieee80211_freq_to_dsss_chan(chan->center_freq); + channel = ieee80211_freq_to_dsss_chan(chandef->chan->center_freq); if ((channel < 1) || (channel > NUM_CHANNELS) || !(priv->channel_mask & (1 << (channel - 1)))) diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c index b439079..810c343 100644 --- a/drivers/net/wireless/p54/p54pci.c +++ b/drivers/net/wireless/p54/p54pci.c @@ -659,7 +659,7 @@ static void __devexit p54p_remove(struct pci_dev *pdev) p54_free_common(dev); } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int p54p_suspend(struct device *device) { struct pci_dev *pdev = to_pci_dev(device); @@ -681,19 +681,12 @@ static int p54p_resume(struct device *device) return pci_set_power_state(pdev, PCI_D0); } -static const struct dev_pm_ops p54pci_pm_ops = { - .suspend = p54p_suspend, - .resume = p54p_resume, - .freeze = p54p_suspend, - .thaw = p54p_resume, - .poweroff = p54p_suspend, - .restore = p54p_resume, -}; +static SIMPLE_DEV_PM_OPS(p54pci_pm_ops, p54p_suspend, p54p_resume); #define P54P_PM_OPS (&p54pci_pm_ops) #else #define P54P_PM_OPS (NULL) -#endif /* CONFIG_PM */ +#endif /* CONFIG_PM_SLEEP */ static struct pci_driver p54p_driver = { .name = "p54pci", diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c index 5861e13..12f0a34 100644 --- a/drivers/net/wireless/p54/txrx.c +++ b/drivers/net/wireless/p54/txrx.c @@ -369,7 +369,11 @@ static int p54_rx_data(struct p54_common *priv, struct sk_buff *skb) rx_status->mactime = ((u64)priv->tsf_high32) << 32 | tsf32; priv->tsf_low32 = tsf32; - rx_status->flag |= RX_FLAG_MACTIME_MPDU; + /* LMAC API Page 10/29 - s_lm_data_in - clock + * "usec accurate timestamp of hardware clock + * at end of frame (before OFDM SIFS EOF padding" + */ + rx_status->flag |= RX_FLAG_MACTIME_END; if (hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN)) header_len += hdr->align[0]; diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 5390af3..abe1d03 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -2293,7 +2293,7 @@ static int rndis_join_ibss(struct wiphy *wiphy, struct net_device *dev, { struct rndis_wlan_private *priv = wiphy_priv(wiphy); struct usbnet *usbdev = priv->usbdev; - struct ieee80211_channel *channel = params->channel; + struct ieee80211_channel *channel = params->chandef.chan; struct ndis_80211_ssid ssid; enum nl80211_auth_type auth_type; int ret, alg, length, chan = -1; diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 3bc206d..c0441a7 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -2449,7 +2449,7 @@ static int rt2800_get_gain_calibration_delta(struct rt2x00_dev *rt2x00dev) /* * Check if temperature compensation is supported. */ - if (tssi_bounds[4] == 0xff) + if (tssi_bounds[4] == 0xff || step == 0xff) return 0; /* diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 67d1679..66b3b17 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -1183,6 +1183,13 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) rt2x00dev->hw->vif_data_size = sizeof(struct rt2x00_intf); /* + * rt2x00 devices can only use the last n bits of the MAC address + * for virtual interfaces. + */ + rt2x00dev->hw->wiphy->addr_mask[ETH_ALEN - 1] = + (rt2x00dev->ops->max_ap_intf - 1); + + /* * Determine which operating modes are supported, all modes * which require beaconing, depend on the availability of * beacon entries. diff --git a/drivers/net/wireless/rtl818x/rtl8180/dev.c b/drivers/net/wireless/rtl818x/rtl8180/dev.c index 021d83e..b4218a5 100644 --- a/drivers/net/wireless/rtl818x/rtl8180/dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180/dev.c @@ -150,7 +150,7 @@ static void rtl8180_handle_rx(struct ieee80211_hw *dev) rx_status.freq = dev->conf.channel->center_freq; rx_status.band = dev->conf.channel->band; rx_status.mactime = le64_to_cpu(entry->tsft); - rx_status.flag |= RX_FLAG_MACTIME_MPDU; + rx_status.flag |= RX_FLAG_MACTIME_START; if (flags & RTL818X_RX_DESC_FLAG_CRC32_ERR) rx_status.flag |= RX_FLAG_FAILED_FCS_CRC; diff --git a/drivers/net/wireless/rtl818x/rtl8187/dev.c b/drivers/net/wireless/rtl818x/rtl8187/dev.c index 7811b63..52e6beb 100644 --- a/drivers/net/wireless/rtl818x/rtl8187/dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187/dev.c @@ -381,7 +381,7 @@ static void rtl8187_rx_cb(struct urb *urb) rx_status.rate_idx = rate; rx_status.freq = dev->conf.channel->center_freq; rx_status.band = dev->conf.channel->band; - rx_status.flag |= RX_FLAG_MACTIME_MPDU; + rx_status.flag |= RX_FLAG_MACTIME_START; if (flags & RTL818X_RX_DESC_FLAG_CRC32_ERR) rx_status.flag |= RX_FLAG_FAILED_FCS_CRC; memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c index f38e30a..086140c 100644 --- a/drivers/net/wireless/rtlwifi/pci.c +++ b/drivers/net/wireless/rtlwifi/pci.c @@ -1982,6 +1982,7 @@ void rtl_pci_disconnect(struct pci_dev *pdev) } EXPORT_SYMBOL(rtl_pci_disconnect); +#ifdef CONFIG_PM_SLEEP /*************************************** kernel pci power state define: PCI_D0 ((pci_power_t __force) 0) @@ -2021,6 +2022,7 @@ int rtl_pci_resume(struct device *dev) return 0; } EXPORT_SYMBOL(rtl_pci_resume); +#endif /* CONFIG_PM_SLEEP */ struct rtl_intf_ops rtl_pci_ops = { .read_efuse_byte = read_efuse_byte, diff --git a/drivers/net/wireless/rtlwifi/pci.h b/drivers/net/wireless/rtlwifi/pci.h index f71b12a..7ea50a3 100644 --- a/drivers/net/wireless/rtlwifi/pci.h +++ b/drivers/net/wireless/rtlwifi/pci.h @@ -239,8 +239,10 @@ extern struct rtl_intf_ops rtl_pci_ops; int __devinit rtl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id); void rtl_pci_disconnect(struct pci_dev *pdev); +#ifdef CONFIG_PM_SLEEP int rtl_pci_suspend(struct device *dev); int rtl_pci_resume(struct device *dev); +#endif /* CONFIG_PM_SLEEP */ static inline u8 pci_read8_sync(struct rtl_priv *rtlpriv, u32 addr) { return readb((u8 __iomem *) rtlpriv->io.pci_mem_start + addr); diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c index 60451ee..49f663b 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c @@ -372,14 +372,7 @@ MODULE_PARM_DESC(swlps, "Set to 1 to use SW control power save (default 0)\n"); MODULE_PARM_DESC(fwlps, "Set to 1 to use FW control power save (default 1)\n"); MODULE_PARM_DESC(debug, "Set debug level (0-5) (default 0)"); -static const struct dev_pm_ops rtlwifi_pm_ops = { - .suspend = rtl_pci_suspend, - .resume = rtl_pci_resume, - .freeze = rtl_pci_suspend, - .thaw = rtl_pci_resume, - .poweroff = rtl_pci_suspend, - .restore = rtl_pci_resume, -}; +static SIMPLE_DEV_PM_OPS(rtlwifi_pm_ops, rtl_pci_suspend, rtl_pci_resume); static struct pci_driver rtl92ce_driver = { .name = KBUILD_MODNAME, diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c index d7e1f0a..1734247 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c @@ -559,7 +559,7 @@ bool rtl92ce_rx_query_desc(struct ieee80211_hw *hw, if (GET_RX_DESC_RXHT(pdesc)) rx_status->flag |= RX_FLAG_HT; - rx_status->flag |= RX_FLAG_MACTIME_MPDU; + rx_status->flag |= RX_FLAG_MACTIME_START; if (stats->decrypted) rx_status->flag |= RX_FLAG_DECRYPTED; diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c index 9970c2b..b7e6607 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c @@ -297,6 +297,7 @@ static struct usb_device_id rtl8192c_usb_ids[] = { /*=== Customer ID ===*/ /****** 8188CU ********/ {RTL_USB_DEVICE(0x050d, 0x1102, rtl92cu_hal_cfg)}, /*Belkin - Edimax*/ + {RTL_USB_DEVICE(0x050d, 0x11f2, rtl92cu_hal_cfg)}, /*Belkin - ISY*/ {RTL_USB_DEVICE(0x06f8, 0xe033, rtl92cu_hal_cfg)}, /*Hercules - Edimax*/ {RTL_USB_DEVICE(0x07b8, 0x8188, rtl92cu_hal_cfg)}, /*Abocom - Abocom*/ {RTL_USB_DEVICE(0x07b8, 0x8189, rtl92cu_hal_cfg)}, /*Funai - Abocom*/ diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c index 6e66f04..b6222ee 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c @@ -334,7 +334,7 @@ bool rtl92cu_rx_query_desc(struct ieee80211_hw *hw, rx_status->flag |= RX_FLAG_40MHZ; if (GET_RX_DESC_RX_HT(pdesc)) rx_status->flag |= RX_FLAG_HT; - rx_status->flag |= RX_FLAG_MACTIME_MPDU; + rx_status->flag |= RX_FLAG_MACTIME_START; if (stats->decrypted) rx_status->flag |= RX_FLAG_DECRYPTED; rx_status->rate_idx = rtlwifi_rate_mapping(hw, diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/sw.c b/drivers/net/wireless/rtlwifi/rtl8192de/sw.c index 480862c..e17f670 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/sw.c @@ -378,14 +378,7 @@ MODULE_PARM_DESC(swlps, "Set to 1 to use SW control power save (default 0)\n"); MODULE_PARM_DESC(fwlps, "Set to 1 to use FW control power save (default 1)\n"); MODULE_PARM_DESC(debug, "Set debug level (0-5) (default 0)"); -static const struct dev_pm_ops rtlwifi_pm_ops = { - .suspend = rtl_pci_suspend, - .resume = rtl_pci_resume, - .freeze = rtl_pci_suspend, - .thaw = rtl_pci_resume, - .poweroff = rtl_pci_suspend, - .restore = rtl_pci_resume, -}; +static SIMPLE_DEV_PM_OPS(rtlwifi_pm_ops, rtl_pci_suspend, rtl_pci_resume); static struct pci_driver rtl92de_driver = { .name = KBUILD_MODNAME, diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/trx.c b/drivers/net/wireless/rtlwifi/rtl8192de/trx.c index 35bb9da..f9f3861 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/trx.c @@ -509,7 +509,7 @@ bool rtl92de_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats, rx_status->flag |= RX_FLAG_40MHZ; if (GET_RX_DESC_RXHT(pdesc)) rx_status->flag |= RX_FLAG_HT; - rx_status->flag |= RX_FLAG_MACTIME_MPDU; + rx_status->flag |= RX_FLAG_MACTIME_START; if (stats->decrypted) rx_status->flag |= RX_FLAG_DECRYPTED; rx_status->rate_idx = rtlwifi_rate_mapping(hw, diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/def.h b/drivers/net/wireless/rtlwifi/rtl8192se/def.h index 20afec6..2d255e0 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/def.h +++ b/drivers/net/wireless/rtlwifi/rtl8192se/def.h @@ -522,8 +522,7 @@ enum fwcmd_iotype { FW_CMD_IQK_ENABLE = 30, }; -/* - * Driver info contain PHY status +/* Driver info contain PHY status * and other variabel size info * PHY Status content as below */ diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/dm.c b/drivers/net/wireless/rtlwifi/rtl8192se/dm.c index bf79a52..e551fe5 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/dm.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/dm.c @@ -465,8 +465,8 @@ static void _rtl92s_dm_initial_gain_sta_beforeconnect(struct ieee80211_hw *hw) digtable->cur_igvalue = digtable->rx_gain_range_min; else - digtable->cur_igvalue = digtable->rssi_val + 10 - - digtable->back_val; + digtable->cur_igvalue = digtable->rssi_val + 10 + - digtable->back_val; if (falsealm_cnt->cnt_all > 10000) digtable->cur_igvalue = @@ -518,7 +518,7 @@ static void _rtl92s_dm_initial_gain_sta_beforeconnect(struct ieee80211_hw *hw) static void _rtl92s_dm_ctrl_initgain_bytwoport(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); - struct dig_t *digtable = &rtlpriv->dm_digtable; + struct dig_t *dig = &rtlpriv->dm_digtable; if (rtlpriv->mac80211.act_scanning) return; @@ -526,17 +526,17 @@ static void _rtl92s_dm_ctrl_initgain_bytwoport(struct ieee80211_hw *hw) /* Decide the current status and if modify initial gain or not */ if (rtlpriv->mac80211.link_state >= MAC80211_LINKED || rtlpriv->mac80211.opmode == NL80211_IFTYPE_ADHOC) - digtable->cur_sta_cstate = DIG_STA_CONNECT; + dig->cur_sta_cstate = DIG_STA_CONNECT; else - digtable->cur_sta_cstate = DIG_STA_DISCONNECT; + dig->cur_sta_cstate = DIG_STA_DISCONNECT; - digtable->rssi_val = rtlpriv->dm.undec_sm_pwdb; + dig->rssi_val = rtlpriv->dm.undec_sm_pwdb; /* Change dig mode to rssi */ - if (digtable->cur_sta_cstate != DIG_STA_DISCONNECT) { - if (digtable->dig_twoport_algorithm == + if (dig->cur_sta_cstate != DIG_STA_DISCONNECT) { + if (dig->dig_twoport_algorithm == DIG_TWO_PORT_ALGO_FALSE_ALARM) { - digtable->dig_twoport_algorithm = DIG_TWO_PORT_ALGO_RSSI; + dig->dig_twoport_algorithm = DIG_TWO_PORT_ALGO_RSSI; rtl92s_phy_set_fw_cmd(hw, FW_CMD_DIG_MODE_SS); } } @@ -544,7 +544,7 @@ static void _rtl92s_dm_ctrl_initgain_bytwoport(struct ieee80211_hw *hw) _rtl92s_dm_false_alarm_counter_statistics(hw); _rtl92s_dm_initial_gain_sta_beforeconnect(hw); - digtable->pre_sta_cstate = digtable->cur_sta_cstate; + dig->pre_sta_cstate = dig->cur_sta_cstate; } static void _rtl92s_dm_ctrl_initgain_byrssi(struct ieee80211_hw *hw) diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/hw.c b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c index 1d72779..28526a7 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c @@ -1089,8 +1089,9 @@ int rtl92se_hw_init(struct ieee80211_hw *hw) return err; } -void rtl92se_set_mac_addr(struct rtl_io *io, const u8 * addr) +void rtl92se_set_mac_addr(struct rtl_io *io, const u8 *addr) { + /* This is a stub. */ } void rtl92se_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid) diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/hw.h b/drivers/net/wireless/rtlwifi/rtl8192se/hw.h index 1886c26..a8e068c 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/hw.h +++ b/drivers/net/wireless/rtlwifi/rtl8192se/hw.h @@ -54,7 +54,7 @@ void rtl92se_disable_interrupt(struct ieee80211_hw *hw); int rtl92se_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type); void rtl92se_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid); -void rtl92se_set_mac_addr(struct rtl_io *io, const u8 * addr); +void rtl92se_set_mac_addr(struct rtl_io *io, const u8 *addr); void rtl92se_set_qos(struct ieee80211_hw *hw, int aci); void rtl92se_set_beacon_related_registers(struct ieee80211_hw *hw); void rtl92se_set_beacon_interval(struct ieee80211_hw *hw); diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/sw.c b/drivers/net/wireless/rtlwifi/rtl8192se/sw.c index ad4b480..45c3443 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/sw.c @@ -50,8 +50,7 @@ static void rtl92s_init_aspm_vars(struct ieee80211_hw *hw) /*close ASPM for AMD defaultly */ rtlpci->const_amdpci_aspm = 0; - /* - * ASPM PS mode. + /* ASPM PS mode. * 0 - Disable ASPM, * 1 - Enable ASPM without Clock Req, * 2 - Enable ASPM with Clock Req, @@ -67,8 +66,7 @@ static void rtl92s_init_aspm_vars(struct ieee80211_hw *hw) /*Setting for PCI-E bridge */ rtlpci->const_hostpci_aspm_setting = 0x02; - /* - * In Hw/Sw Radio Off situation. + /* In Hw/Sw Radio Off situation. * 0 - Default, * 1 - From ASPM setting without low Mac Pwr, * 2 - From ASPM setting with low Mac Pwr, @@ -77,8 +75,7 @@ static void rtl92s_init_aspm_vars(struct ieee80211_hw *hw) */ rtlpci->const_hwsw_rfoff_d3 = 2; - /* - * This setting works for those device with + /* This setting works for those device with * backdoor ASPM setting such as EPHY setting. * 0 - Not support ASPM, * 1 - Support ASPM, @@ -432,14 +429,7 @@ MODULE_PARM_DESC(swlps, "Set to 1 to use SW control power save (default 0)\n"); MODULE_PARM_DESC(fwlps, "Set to 1 to use FW control power save (default 1)\n"); MODULE_PARM_DESC(debug, "Set debug level (0-5) (default 0)"); -static const struct dev_pm_ops rtlwifi_pm_ops = { - .suspend = rtl_pci_suspend, - .resume = rtl_pci_resume, - .freeze = rtl_pci_suspend, - .thaw = rtl_pci_resume, - .poweroff = rtl_pci_suspend, - .restore = rtl_pci_resume, -}; +static SIMPLE_DEV_PM_OPS(rtlwifi_pm_ops, rtl_pci_suspend, rtl_pci_resume); static struct pci_driver rtl92se_driver = { .name = KBUILD_MODNAME, diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c index 1ad51e7..0e9f6eb 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c @@ -553,7 +553,7 @@ bool rtl92se_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats, if (stats->is_ht) rx_status->flag |= RX_FLAG_HT; - rx_status->flag |= RX_FLAG_MACTIME_MPDU; + rx_status->flag |= RX_FLAG_MACTIME_START; /* hw will set stats->decrypted true, if it finds the * frame is open data frame or mgmt frame, diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/sw.c b/drivers/net/wireless/rtlwifi/rtl8723ae/sw.c index 0afdc24..18b0bc5 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/sw.c @@ -367,14 +367,7 @@ MODULE_PARM_DESC(swlps, "Set to 1 to use SW control power save (default 0)\n"); MODULE_PARM_DESC(fwlps, "Set to 1 to use FW control power save (default 1)\n"); MODULE_PARM_DESC(debug, "Set debug level (0-5) (default 0)"); -static const struct dev_pm_ops rtlwifi_pm_ops = { - .suspend = rtl_pci_suspend, - .resume = rtl_pci_resume, - .freeze = rtl_pci_suspend, - .thaw = rtl_pci_resume, - .poweroff = rtl_pci_suspend, - .restore = rtl_pci_resume, -}; +static SIMPLE_DEV_PM_OPS(rtlwifi_pm_ops, rtl_pci_suspend, rtl_pci_resume); static struct pci_driver rtl8723ae_driver = { .name = KBUILD_MODNAME, diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c index 9719d54..87331d8 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c @@ -321,7 +321,7 @@ bool rtl8723ae_rx_query_desc(struct ieee80211_hw *hw, if (status->is_ht) rx_status->flag |= RX_FLAG_HT; - rx_status->flag |= RX_FLAG_MACTIME_MPDU; + rx_status->flag |= RX_FLAG_MACTIME_START; /* hw will set status->decrypted true, if it finds the * frame is open data frame or mgmt frame. diff --git a/drivers/net/wireless/ti/wl1251/rx.c b/drivers/net/wireless/ti/wl1251/rx.c index 6af3526..23289d4 100644 --- a/drivers/net/wireless/ti/wl1251/rx.c +++ b/drivers/net/wireless/ti/wl1251/rx.c @@ -81,7 +81,7 @@ static void wl1251_rx_status(struct wl1251 *wl, status->freq = ieee80211_channel_to_frequency(desc->channel, status->band); - status->flag |= RX_FLAG_MACTIME_MPDU; + status->flag |= RX_FLAG_MACTIME_START; if (desc->flags & RX_DESC_ENCRYPTION_MASK) { status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED; diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 380cf1f..4f1a05b 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -3791,7 +3791,7 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl, /* Handle HT information change */ if ((changed & BSS_CHANGED_HT) && - (bss_conf->channel_type != NL80211_CHAN_NO_HT)) { + (bss_conf->chandef.width != NL80211_CHAN_WIDTH_20_NOHT)) { ret = wl1271_acx_set_ht_information(wl, wlvif, bss_conf->ht_operation_mode); if (ret < 0) { @@ -3905,7 +3905,8 @@ sta_not_found: u32 rates; int ieoffset; wlvif->aid = bss_conf->aid; - wlvif->channel_type = bss_conf->channel_type; + wlvif->channel_type = + cfg80211_get_chandef_type(&bss_conf->chandef); wlvif->beacon_int = bss_conf->beacon_int; do_join = true; set_assoc = true; @@ -4071,7 +4072,7 @@ sta_not_found: /* Handle new association with HT. Do this after join. */ if (sta_exists) { if ((changed & BSS_CHANGED_HT) && - (bss_conf->channel_type != NL80211_CHAN_NO_HT)) { + (bss_conf->chandef.width != NL80211_CHAN_WIDTH_20_NOHT)) { ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap, true, @@ -4098,7 +4099,7 @@ sta_not_found: /* Handle HT information change. Done after join. */ if ((changed & BSS_CHANGED_HT) && - (bss_conf->channel_type != NL80211_CHAN_NO_HT)) { + (bss_conf->chandef.width != NL80211_CHAN_WIDTH_20_NOHT)) { ret = wl1271_acx_set_ht_information(wl, wlvif, bss_conf->ht_operation_mode); if (ret < 0) { diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index 18e279d..ada681b 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c @@ -702,13 +702,14 @@ static void pn533_wq_cmd(struct work_struct *work) cmd = list_first_entry(&dev->cmd_queue, struct pn533_cmd, queue); + list_del(&cmd->queue); + mutex_unlock(&dev->cmd_lock); __pn533_send_cmd_frame_async(dev, cmd->out_frame, cmd->in_frame, cmd->in_frame_len, cmd->cmd_complete, cmd->arg, cmd->flags); - list_del(&cmd->queue); kfree(cmd); } @@ -1680,11 +1681,14 @@ static void pn533_deactivate_target(struct nfc_dev *nfc_dev, static int pn533_in_dep_link_up_complete(struct pn533 *dev, void *arg, u8 *params, int params_len) { - struct pn533_cmd_jump_dep *cmd; struct pn533_cmd_jump_dep_response *resp; struct nfc_target nfc_target; u8 target_gt_len; int rc; + struct pn533_cmd_jump_dep *cmd = (struct pn533_cmd_jump_dep *)arg; + u8 active = cmd->active; + + kfree(arg); if (params_len == -ENOENT) { nfc_dev_dbg(&dev->interface->dev, ""); @@ -1706,7 +1710,6 @@ static int pn533_in_dep_link_up_complete(struct pn533 *dev, void *arg, } resp = (struct pn533_cmd_jump_dep_response *) params; - cmd = (struct pn533_cmd_jump_dep *) arg; rc = resp->status & PN533_CMD_RET_MASK; if (rc != PN533_CMD_RET_SUCCESS) { nfc_dev_err(&dev->interface->dev, @@ -1736,7 +1739,7 @@ static int pn533_in_dep_link_up_complete(struct pn533 *dev, void *arg, if (rc == 0) rc = nfc_dep_link_is_up(dev->nfc_dev, dev->nfc_dev->targets[0].idx, - !cmd->active, NFC_RF_INITIATOR); + !active, NFC_RF_INITIATOR); return 0; } @@ -1821,12 +1824,8 @@ static int pn533_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target, rc = pn533_send_cmd_frame_async(dev, dev->out_frame, dev->in_frame, dev->in_maxlen, pn533_in_dep_link_up_complete, cmd, GFP_KERNEL); - if (rc) - goto out; - - -out: - kfree(cmd); + if (rc < 0) + kfree(cmd); return rc; } @@ -2080,8 +2079,12 @@ error: static int pn533_tm_send_complete(struct pn533 *dev, void *arg, u8 *params, int params_len) { + struct sk_buff *skb_out = arg; + nfc_dev_dbg(&dev->interface->dev, "%s", __func__); + dev_kfree_skb(skb_out); + if (params_len < 0) { nfc_dev_err(&dev->interface->dev, "Error %d when sending data", @@ -2119,7 +2122,7 @@ static int pn533_tm_send(struct nfc_dev *nfc_dev, struct sk_buff *skb) rc = pn533_send_cmd_frame_async(dev, out_frame, dev->in_frame, dev->in_maxlen, pn533_tm_send_complete, - NULL, GFP_KERNEL); + skb, GFP_KERNEL); if (rc) { nfc_dev_err(&dev->interface->dev, "Error %d when trying to send data", rc); diff --git a/drivers/nfc/pn544/i2c.c b/drivers/nfc/pn544/i2c.c index fb430d8..7da9071 100644 --- a/drivers/nfc/pn544/i2c.c +++ b/drivers/nfc/pn544/i2c.c @@ -26,7 +26,7 @@ #include <linux/interrupt.h> #include <linux/delay.h> -#include <linux/nfc/pn544.h> +#include <linux/platform_data/pn544.h> #include <net/nfc/hci.h> #include <net/nfc/llc.h> diff --git a/drivers/ssb/driver_mipscore.c b/drivers/ssb/driver_mipscore.c index b918ba9..5bd05b1 100644 --- a/drivers/ssb/driver_mipscore.c +++ b/drivers/ssb/driver_mipscore.c @@ -178,9 +178,9 @@ static void ssb_mips_serial_init(struct ssb_mipscore *mcore) { struct ssb_bus *bus = mcore->dev->bus; - if (bus->extif.dev) + if (ssb_extif_available(&bus->extif)) mcore->nr_serial_ports = ssb_extif_serial_init(&bus->extif, mcore->serial_ports); - else if (bus->chipco.dev) + else if (ssb_chipco_available(&bus->chipco)) mcore->nr_serial_ports = ssb_chipco_serial_init(&bus->chipco, mcore->serial_ports); else mcore->nr_serial_ports = 0; @@ -191,7 +191,7 @@ static void ssb_mips_flash_detect(struct ssb_mipscore *mcore) struct ssb_bus *bus = mcore->dev->bus; /* When there is no chipcommon on the bus there is 4MB flash */ - if (!bus->chipco.dev) { + if (!ssb_chipco_available(&bus->chipco)) { mcore->pflash.present = true; mcore->pflash.buswidth = 2; mcore->pflash.window = SSB_FLASH1; @@ -227,9 +227,9 @@ u32 ssb_cpu_clock(struct ssb_mipscore *mcore) if (bus->chipco.capabilities & SSB_CHIPCO_CAP_PMU) return ssb_pmu_get_cpu_clock(&bus->chipco); - if (bus->extif.dev) { + if (ssb_extif_available(&bus->extif)) { ssb_extif_get_clockcontrol(&bus->extif, &pll_type, &n, &m); - } else if (bus->chipco.dev) { + } else if (ssb_chipco_available(&bus->chipco)) { ssb_chipco_get_clockcpu(&bus->chipco, &pll_type, &n, &m); } else return 0; @@ -265,9 +265,9 @@ void ssb_mipscore_init(struct ssb_mipscore *mcore) hz = 100000000; ns = 1000000000 / hz; - if (bus->extif.dev) + if (ssb_extif_available(&bus->extif)) ssb_extif_timing_init(&bus->extif, ns); - else if (bus->chipco.dev) + else if (ssb_chipco_available(&bus->chipco)) ssb_chipco_timing_init(&bus->chipco, ns); /* Assign IRQs to all cores on the bus, start with irq line 2, because serial usually takes 1 */ diff --git a/include/linux/bcma/bcma.h b/include/linux/bcma/bcma.h index fd15d98..93b1e09 100644 --- a/include/linux/bcma/bcma.h +++ b/include/linux/bcma/bcma.h @@ -157,6 +157,7 @@ struct bcma_host_ops { /* Chip IDs of SoCs */ #define BCMA_CHIP_ID_BCM4706 0x5300 +#define BCMA_PKG_ID_BCM4706L 1 #define BCMA_CHIP_ID_BCM4716 0x4716 #define BCMA_PKG_ID_BCM4716 8 #define BCMA_PKG_ID_BCM4717 9 @@ -166,7 +167,11 @@ struct bcma_host_ops { #define BCMA_CHIP_ID_BCM4749 0x4749 #define BCMA_CHIP_ID_BCM5356 0x5356 #define BCMA_CHIP_ID_BCM5357 0x5357 +#define BCMA_PKG_ID_BCM5358 9 +#define BCMA_PKG_ID_BCM47186 10 +#define BCMA_PKG_ID_BCM5357 11 #define BCMA_CHIP_ID_BCM53572 53572 +#define BCMA_PKG_ID_BCM47188 9 struct bcma_device { struct bcma_bus *bus; diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 4530d49..f9c5a78 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -131,6 +131,8 @@ #define IEEE80211_MAX_MESH_ID_LEN 32 +#define IEEE80211_NUM_TIDS 16 + #define IEEE80211_QOS_CTL_LEN 2 /* 1d tag mask */ #define IEEE80211_QOS_CTL_TAG1D_MASK 0x0007 @@ -666,6 +668,21 @@ struct ieee80211_meshconf_ie { } __attribute__ ((packed)); /** + * enum mesh_config_capab_flags - Mesh Configuration IE capability field flags + * + * @IEEE80211_MESHCONF_CAPAB_ACCEPT_PLINKS: STA is willing to establish + * additional mesh peerings with other mesh STAs + * @IEEE80211_MESHCONF_CAPAB_FORWARDING: the STA forwards MSDUs + * @IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING: TBTT adjustment procedure + * is ongoing + */ +enum mesh_config_capab_flags { + IEEE80211_MESHCONF_CAPAB_ACCEPT_PLINKS = 0x01, + IEEE80211_MESHCONF_CAPAB_FORWARDING = 0x08, + IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING = 0x20, +}; + +/** * struct ieee80211_rann_ie * * This structure refers to "Root Announcement information element" @@ -1146,11 +1163,13 @@ struct ieee80211_ht_operation { * STA can receive. Rate expressed in units of 1 Mbps. * If this field is 0 this value should not be used to * consider the highest RX data rate supported. + * The top 3 bits of this field are reserved. * @tx_mcs_map: TX MCS map 2 bits for each stream, total 8 streams * @tx_highest: Indicates highest long GI VHT PPDU data rate * STA can transmit. Rate expressed in units of 1 Mbps. * If this field is 0 this value should not be used to * consider the highest TX data rate supported. + * The top 3 bits of this field are reserved. */ struct ieee80211_vht_mcs_info { __le16 rx_mcs_map; @@ -1160,6 +1179,27 @@ struct ieee80211_vht_mcs_info { } __packed; /** + * enum ieee80211_vht_mcs_support - VHT MCS support definitions + * @IEEE80211_VHT_MCS_SUPPORT_0_7: MCSes 0-7 are supported for the + * number of streams + * @IEEE80211_VHT_MCS_SUPPORT_0_8: MCSes 0-8 are supported + * @IEEE80211_VHT_MCS_SUPPORT_0_9: MCSes 0-9 are supported + * @IEEE80211_VHT_MCS_NOT_SUPPORTED: This number of streams isn't supported + * + * These definitions are used in each 2-bit subfield of the @rx_mcs_map + * and @tx_mcs_map fields of &struct ieee80211_vht_mcs_info, which are + * both split into 8 subfields by number of streams. These values indicate + * which MCSes are supported for the number of streams the value appears + * for. + */ +enum ieee80211_vht_mcs_support { + IEEE80211_VHT_MCS_SUPPORT_0_7 = 0, + IEEE80211_VHT_MCS_SUPPORT_0_8 = 1, + IEEE80211_VHT_MCS_SUPPORT_0_9 = 2, + IEEE80211_VHT_MCS_NOT_SUPPORTED = 3, +}; + +/** * struct ieee80211_vht_cap - VHT capabilities * * This structure is the "VHT capabilities element" as diff --git a/include/linux/nfc/pn544.h b/include/linux/nfc/pn544.h deleted file mode 100644 index 9890bba..0000000 --- a/include/linux/nfc/pn544.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Driver include for the PN544 NFC chip. - * - * Copyright (C) Nokia Corporation - * - * Author: Jari Vanhala <ext-jari.vanhala@nokia.com> - * Contact: Matti Aaltoenn <matti.j.aaltonen@nokia.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _PN544_H_ -#define _PN544_H_ - -#include <linux/i2c.h> - -#define PN544_DRIVER_NAME "pn544" -#define PN544_MAXWINDOW_SIZE 7 -#define PN544_WINDOW_SIZE 4 -#define PN544_RETRIES 10 -#define PN544_MAX_I2C_TRANSFER 0x0400 -#define PN544_MSG_MAX_SIZE 0x21 /* at normal HCI mode */ - -/* ioctl */ -#define PN544_CHAR_BASE 'P' -#define PN544_IOR(num, dtype) _IOR(PN544_CHAR_BASE, num, dtype) -#define PN544_IOW(num, dtype) _IOW(PN544_CHAR_BASE, num, dtype) -#define PN544_GET_FW_MODE PN544_IOW(1, unsigned int) -#define PN544_SET_FW_MODE PN544_IOW(2, unsigned int) -#define PN544_GET_DEBUG PN544_IOW(3, unsigned int) -#define PN544_SET_DEBUG PN544_IOW(4, unsigned int) - -/* Timing restrictions (ms) */ -#define PN544_RESETVEN_TIME 30 /* 7 */ -#define PN544_PVDDVEN_TIME 0 -#define PN544_VBATVEN_TIME 0 -#define PN544_GPIO4VEN_TIME 0 -#define PN544_WAKEUP_ACK 5 -#define PN544_WAKEUP_GUARD (PN544_WAKEUP_ACK + 1) -#define PN544_INACTIVITY_TIME 1000 -#define PN544_INTERFRAME_DELAY 200 /* us */ -#define PN544_BAUDRATE_CHANGE 150 /* us */ - -/* Debug bits */ -#define PN544_DEBUG_BUF 0x01 -#define PN544_DEBUG_READ 0x02 -#define PN544_DEBUG_WRITE 0x04 -#define PN544_DEBUG_IRQ 0x08 -#define PN544_DEBUG_CALLS 0x10 -#define PN544_DEBUG_MODE 0x20 - -/* Normal (HCI) mode */ -#define PN544_LLC_HCI_OVERHEAD 3 /* header + crc (to length) */ -#define PN544_LLC_MIN_SIZE (1 + PN544_LLC_HCI_OVERHEAD) /* length + */ -#define PN544_LLC_MAX_DATA (PN544_MSG_MAX_SIZE - 2) -#define PN544_LLC_MAX_HCI_SIZE (PN544_LLC_MAX_DATA - 2) - -struct pn544_llc_packet { - unsigned char length; /* of rest of packet */ - unsigned char header; - unsigned char data[PN544_LLC_MAX_DATA]; /* includes crc-ccitt */ -}; - -/* Firmware upgrade mode */ -#define PN544_FW_HEADER_SIZE 3 -/* max fw transfer is 1024bytes, but I2C limits it to 0xC0 */ -#define PN544_MAX_FW_DATA (PN544_MAX_I2C_TRANSFER - PN544_FW_HEADER_SIZE) - -struct pn544_fw_packet { - unsigned char command; /* status in answer */ - unsigned char length[2]; /* big-endian order (msf) */ - unsigned char data[PN544_MAX_FW_DATA]; -}; - -#ifdef __KERNEL__ -enum { - NFC_GPIO_ENABLE, - NFC_GPIO_FW_RESET, - NFC_GPIO_IRQ -}; - -/* board config */ -struct pn544_nfc_platform_data { - int (*request_resources) (struct i2c_client *client); - void (*free_resources) (void); - void (*enable) (int fw); - int (*test) (void); - void (*disable) (void); - int (*get_gpio)(int type); -}; -#endif /* __KERNEL__ */ - -#endif /* _PN544_H_ */ diff --git a/include/linux/platform_data/pn544.h b/include/linux/platform_data/pn544.h new file mode 100644 index 0000000..713bfd7 --- /dev/null +++ b/include/linux/platform_data/pn544.h @@ -0,0 +1,44 @@ +/* + * Driver include for the PN544 NFC chip. + * + * Copyright (C) Nokia Corporation + * + * Author: Jari Vanhala <ext-jari.vanhala@nokia.com> + * Contact: Matti Aaltoenn <matti.j.aaltonen@nokia.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _PN544_H_ +#define _PN544_H_ + +#include <linux/i2c.h> + +enum { + NFC_GPIO_ENABLE, + NFC_GPIO_FW_RESET, + NFC_GPIO_IRQ +}; + +/* board config */ +struct pn544_nfc_platform_data { + int (*request_resources) (struct i2c_client *client); + void (*free_resources) (void); + void (*enable) (int fw); + int (*test) (void); + void (*disable) (void); + int (*get_gpio)(int type); +}; + +#endif /* _PN544_H_ */ diff --git a/include/linux/ssb/ssb_driver_extif.h b/include/linux/ssb/ssb_driver_extif.h index 91161f0..2604efa 100644 --- a/include/linux/ssb/ssb_driver_extif.h +++ b/include/linux/ssb/ssb_driver_extif.h @@ -205,10 +205,52 @@ void ssb_extif_get_clockcontrol(struct ssb_extif *extif, } static inline +void ssb_extif_timing_init(struct ssb_extif *extif, unsigned long ns) +{ +} + +static inline void ssb_extif_watchdog_timer_set(struct ssb_extif *extif, u32 ticks) { } +static inline u32 ssb_extif_gpio_in(struct ssb_extif *extif, u32 mask) +{ + return 0; +} + +static inline u32 ssb_extif_gpio_out(struct ssb_extif *extif, u32 mask, + u32 value) +{ + return 0; +} + +static inline u32 ssb_extif_gpio_outen(struct ssb_extif *extif, u32 mask, + u32 value) +{ + return 0; +} + +static inline u32 ssb_extif_gpio_polarity(struct ssb_extif *extif, u32 mask, + u32 value) +{ + return 0; +} + +static inline u32 ssb_extif_gpio_intmask(struct ssb_extif *extif, u32 mask, + u32 value) +{ + return 0; +} + +#ifdef CONFIG_SSB_SERIAL +static inline int ssb_extif_serial_init(struct ssb_extif *extif, + struct ssb_serial_port *ports) +{ + return 0; +} +#endif /* CONFIG_SSB_SERIAL */ + #endif /* CONFIG_SSB_DRIVER_EXTIF */ #endif /* LINUX_SSB_EXTIFCORE_H_ */ diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 81d7250..e78db2c 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -306,6 +306,88 @@ struct key_params { }; /** + * struct cfg80211_chan_def - channel definition + * @chan: the (control) channel + * @width: channel width + * @center_freq1: center frequency of first segment + * @center_freq2: center frequency of second segment + * (only with 80+80 MHz) + */ +struct cfg80211_chan_def { + struct ieee80211_channel *chan; + enum nl80211_chan_width width; + u32 center_freq1; + u32 center_freq2; +}; + +/** + * cfg80211_get_chandef_type - return old channel type from chandef + * @chandef: the channel definition + * + * Returns the old channel type (NOHT, HT20, HT40+/-) from a given + * chandef, which must have a bandwidth allowing this conversion. + */ +static inline enum nl80211_channel_type +cfg80211_get_chandef_type(const struct cfg80211_chan_def *chandef) +{ + switch (chandef->width) { + case NL80211_CHAN_WIDTH_20_NOHT: + return NL80211_CHAN_NO_HT; + case NL80211_CHAN_WIDTH_20: + return NL80211_CHAN_HT20; + case NL80211_CHAN_WIDTH_40: + if (chandef->center_freq1 > chandef->chan->center_freq) + return NL80211_CHAN_HT40PLUS; + return NL80211_CHAN_HT40MINUS; + default: + WARN_ON(1); + return NL80211_CHAN_NO_HT; + } +} + +/** + * cfg80211_chandef_create - create channel definition using channel type + * @chandef: the channel definition struct to fill + * @channel: the control channel + * @chantype: the channel type + * + * Given a channel type, create a channel definition. + */ +void cfg80211_chandef_create(struct cfg80211_chan_def *chandef, + struct ieee80211_channel *channel, + enum nl80211_channel_type chantype); + +/** + * cfg80211_chandef_identical - check if two channel definitions are identical + * @chandef1: first channel definition + * @chandef2: second channel definition + * + * Returns %true if the channels defined by the channel definitions are + * identical, %false otherwise. + */ +static inline bool +cfg80211_chandef_identical(const struct cfg80211_chan_def *chandef1, + const struct cfg80211_chan_def *chandef2) +{ + return (chandef1->chan == chandef2->chan && + chandef1->width == chandef2->width && + chandef1->center_freq1 == chandef2->center_freq1 && + chandef1->center_freq2 == chandef2->center_freq2); +} + +/** + * cfg80211_chandef_compatible - check if two channel definitions are compatible + * @chandef1: first channel definition + * @chandef2: second channel definition + * + * Returns %NULL if the given channel definitions are incompatible, + * chandef1 or chandef2 otherwise. + */ +const struct cfg80211_chan_def * +cfg80211_chandef_compatible(const struct cfg80211_chan_def *chandef1, + const struct cfg80211_chan_def *chandef2); + +/** * enum survey_info_flags - survey information flags * * @SURVEY_INFO_NOISE_DBM: noise (in dBm) was filled in @@ -426,8 +508,7 @@ struct cfg80211_beacon_data { * * Used to configure an AP interface. * - * @channel: the channel to start the AP on - * @channel_type: the channel type to use + * @chandef: defines the channel to use * @beacon: beacon data * @beacon_interval: beacon interval * @dtim_period: DTIM period @@ -441,8 +522,7 @@ struct cfg80211_beacon_data { * @inactivity_timeout: time in seconds to determine station's inactivity. */ struct cfg80211_ap_settings { - struct ieee80211_channel *channel; - enum nl80211_channel_type channel_type; + struct cfg80211_chan_def chandef; struct cfg80211_beacon_data beacon; @@ -582,16 +662,24 @@ enum station_info_flags { * Used by the driver to indicate the specific rate transmission * type for 802.11n transmissions. * - * @RATE_INFO_FLAGS_MCS: @tx_bitrate_mcs filled - * @RATE_INFO_FLAGS_40_MHZ_WIDTH: 40 Mhz width transmission + * @RATE_INFO_FLAGS_MCS: mcs field filled with HT MCS + * @RATE_INFO_FLAGS_VHT_MCS: mcs field filled with VHT MCS + * @RATE_INFO_FLAGS_40_MHZ_WIDTH: 40 MHz width transmission + * @RATE_INFO_FLAGS_80_MHZ_WIDTH: 80 MHz width transmission + * @RATE_INFO_FLAGS_80P80_MHZ_WIDTH: 80+80 MHz width transmission + * @RATE_INFO_FLAGS_160_MHZ_WIDTH: 160 MHz width transmission * @RATE_INFO_FLAGS_SHORT_GI: 400ns guard interval - * @RATE_INFO_FLAGS_60G: 60gHz MCS + * @RATE_INFO_FLAGS_60G: 60GHz MCS */ enum rate_info_flags { - RATE_INFO_FLAGS_MCS = 1<<0, - RATE_INFO_FLAGS_40_MHZ_WIDTH = 1<<1, - RATE_INFO_FLAGS_SHORT_GI = 1<<2, - RATE_INFO_FLAGS_60G = 1<<3, + RATE_INFO_FLAGS_MCS = BIT(0), + RATE_INFO_FLAGS_VHT_MCS = BIT(1), + RATE_INFO_FLAGS_40_MHZ_WIDTH = BIT(2), + RATE_INFO_FLAGS_80_MHZ_WIDTH = BIT(3), + RATE_INFO_FLAGS_80P80_MHZ_WIDTH = BIT(4), + RATE_INFO_FLAGS_160_MHZ_WIDTH = BIT(5), + RATE_INFO_FLAGS_SHORT_GI = BIT(6), + RATE_INFO_FLAGS_60G = BIT(7), }; /** @@ -602,11 +690,13 @@ enum rate_info_flags { * @flags: bitflag of flags from &enum rate_info_flags * @mcs: mcs index if struct describes a 802.11n bitrate * @legacy: bitrate in 100kbit/s for 802.11abg + * @nss: number of streams (VHT only) */ struct rate_info { u8 flags; u8 mcs; u16 legacy; + u8 nss; }; /** @@ -909,8 +999,7 @@ struct mesh_config { /** * struct mesh_setup - 802.11s mesh setup configuration - * @channel: the channel to start the mesh network on - * @channel_type: the channel type to use + * @chandef: defines the channel to use * @mesh_id: the mesh ID * @mesh_id_len: length of the mesh ID, at least 1 and at most 32 bytes * @sync_method: which synchronization method to use @@ -925,8 +1014,7 @@ struct mesh_config { * These parameters are fixed when the mesh is created. */ struct mesh_setup { - struct ieee80211_channel *channel; - enum nl80211_channel_type channel_type; + struct cfg80211_chan_def chandef; const u8 *mesh_id; u8 mesh_id_len; u8 sync_method; @@ -1266,8 +1354,7 @@ struct cfg80211_disassoc_request { * @ssid_len: The length of the SSID, will always be non-zero. * @bssid: Fixed BSSID requested, maybe be %NULL, if set do not * search for IBSSs with a different BSSID. - * @channel: The channel to use if no IBSS can be found to join. - * @channel_type: channel type (HT mode) + * @chandef: defines the channel to use if no other IBSS to join can be found * @channel_fixed: The channel should be fixed -- do not search for * IBSSs to join on other channels. * @ie: information element(s) to include in the beacon @@ -1285,8 +1372,7 @@ struct cfg80211_disassoc_request { struct cfg80211_ibss_params { u8 *ssid; u8 *bssid; - struct ieee80211_channel *channel; - enum nl80211_channel_type channel_type; + struct cfg80211_chan_def chandef; u8 *ie; u8 ssid_len, ie_len; u16 beacon_interval; @@ -1728,8 +1814,7 @@ struct cfg80211_ops { struct ieee80211_channel *chan); int (*set_monitor_channel)(struct wiphy *wiphy, - struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type); + struct cfg80211_chan_def *chandef); int (*scan)(struct wiphy *wiphy, struct cfg80211_scan_request *request); @@ -1791,7 +1876,6 @@ struct cfg80211_ops { int (*remain_on_channel)(struct wiphy *wiphy, struct wireless_dev *wdev, struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type, unsigned int duration, u64 *cookie); int (*cancel_remain_on_channel)(struct wiphy *wiphy, @@ -1800,10 +1884,8 @@ struct cfg80211_ops { int (*mgmt_tx)(struct wiphy *wiphy, struct wireless_dev *wdev, struct ieee80211_channel *chan, bool offchan, - enum nl80211_channel_type channel_type, - bool channel_type_valid, unsigned int wait, - const u8 *buf, size_t len, bool no_cck, - bool dont_wait_for_ack, u64 *cookie); + unsigned int wait, const u8 *buf, size_t len, + bool no_cck, bool dont_wait_for_ack, u64 *cookie); int (*mgmt_tx_cancel_wait)(struct wiphy *wiphy, struct wireless_dev *wdev, u64 cookie); @@ -1858,10 +1940,9 @@ struct cfg80211_ops { void (*get_et_strings)(struct wiphy *wiphy, struct net_device *dev, u32 sset, u8 *data); - struct ieee80211_channel * - (*get_channel)(struct wiphy *wiphy, + int (*get_channel)(struct wiphy *wiphy, struct wireless_dev *wdev, - enum nl80211_channel_type *type); + struct cfg80211_chan_def *chandef); int (*start_p2p_device)(struct wiphy *wiphy, struct wireless_dev *wdev); @@ -2469,8 +2550,7 @@ struct wireless_dev { spinlock_t event_lock; struct cfg80211_internal_bss *current_bss; /* associated / joined */ - struct ieee80211_channel *preset_chan; - enum nl80211_channel_type preset_chantype; + struct cfg80211_chan_def preset_chandef; /* for AP and mesh channel tracking */ struct ieee80211_channel *channel; @@ -3350,14 +3430,12 @@ void cfg80211_disconnected(struct net_device *dev, u16 reason, * @wdev: wireless device * @cookie: the request cookie * @chan: The current channel (from remain_on_channel request) - * @channel_type: Channel type * @duration: Duration in milliseconds that the driver intents to remain on the * channel * @gfp: allocation flags */ void cfg80211_ready_on_channel(struct wireless_dev *wdev, u64 cookie, struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type, unsigned int duration, gfp_t gfp); /** @@ -3365,12 +3443,10 @@ void cfg80211_ready_on_channel(struct wireless_dev *wdev, u64 cookie, * @wdev: wireless device * @cookie: the request cookie * @chan: The current channel (from remain_on_channel request) - * @channel_type: Channel type * @gfp: allocation flags */ void cfg80211_remain_on_channel_expired(struct wireless_dev *wdev, u64 cookie, struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type, gfp_t gfp); @@ -3570,28 +3646,44 @@ void cfg80211_report_obss_beacon(struct wiphy *wiphy, int freq, int sig_dbm); /** - * cfg80211_can_beacon_sec_chan - test if ht40 on extension channel can be used + * cfg80211_reg_can_beacon - check if beaconing is allowed * @wiphy: the wiphy - * @chan: main channel - * @channel_type: HT mode + * @chandef: the channel definition * * This function returns true if there is no secondary channel or the secondary - * channel can be used for beaconing (i.e. is not a radar channel etc.) + * channel(s) can be used for beaconing (i.e. is not a radar channel etc.) */ -bool cfg80211_can_beacon_sec_chan(struct wiphy *wiphy, - struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type); +bool cfg80211_reg_can_beacon(struct wiphy *wiphy, + struct cfg80211_chan_def *chandef); /* * cfg80211_ch_switch_notify - update wdev channel and notify userspace * @dev: the device which switched channels - * @freq: new channel frequency (in MHz) - * @type: channel type + * @chandef: the new channel definition * * Acquires wdev_lock, so must only be called from sleepable driver context! */ -void cfg80211_ch_switch_notify(struct net_device *dev, int freq, - enum nl80211_channel_type type); +void cfg80211_ch_switch_notify(struct net_device *dev, + struct cfg80211_chan_def *chandef); + +/* + * cfg80211_tdls_oper_request - request userspace to perform TDLS operation + * @dev: the device on which the operation is requested + * @peer: the MAC address of the peer device + * @oper: the requested TDLS operation (NL80211_TDLS_SETUP or + * NL80211_TDLS_TEARDOWN) + * @reason_code: the reason code for teardown request + * @gfp: allocation flags + * + * This function is used to request userspace to perform TDLS operation that + * requires knowledge of keys, i.e., link setup or teardown when the AP + * connection uses encryption. This is optional mechanism for the driver to use + * if it can automatically determine when a TDLS link could be useful (e.g., + * based on traffic and signal strength for a peer). + */ +void cfg80211_tdls_oper_request(struct net_device *dev, const u8 *peer, + enum nl80211_tdls_operation oper, + u16 reason_code, gfp_t gfp); /* * cfg80211_calculate_bitrate - calculate actual bitrate (in 100Kbps units) @@ -3633,8 +3725,9 @@ void cfg80211_unregister_wdev(struct wireless_dev *wdev); * the data is malformed or the attribute can't be found (respectively), * or the length of the found attribute (which can be zero). */ -unsigned int cfg80211_get_p2p_attr(const u8 *ies, unsigned int len, - u8 attr, u8 *buf, unsigned int bufsize); +int cfg80211_get_p2p_attr(const u8 *ies, unsigned int len, + enum ieee80211_p2p_attr_id attr, + u8 *buf, unsigned int bufsize); /* Logging, debugging and troubleshooting/diagnostic helpers. */ diff --git a/include/net/mac80211.h b/include/net/mac80211.h index a789dd1..db7680a 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -145,11 +145,11 @@ struct ieee80211_low_level_stats { /** * enum ieee80211_chanctx_change - change flag for channel context - * @IEEE80211_CHANCTX_CHANGE_CHANNEL_TYPE: The channel type was changed + * @IEEE80211_CHANCTX_CHANGE_WIDTH: The channel width changed * @IEEE80211_CHANCTX_CHANGE_RX_CHAINS: The number of RX chains changed */ enum ieee80211_chanctx_change { - IEEE80211_CHANCTX_CHANGE_CHANNEL_TYPE = BIT(0), + IEEE80211_CHANCTX_CHANGE_WIDTH = BIT(0), IEEE80211_CHANCTX_CHANGE_RX_CHAINS = BIT(1), }; @@ -159,8 +159,7 @@ enum ieee80211_chanctx_change { * This is the driver-visible part. The ieee80211_chanctx * that contains it is visible in mac80211 only. * - * @channel: the channel to tune to - * @channel_type: the channel (HT) type + * @def: the channel definition * @rx_chains_static: The number of RX chains that must always be * active on the channel to receive MIMO transmissions * @rx_chains_dynamic: The number of RX chains that must be enabled @@ -170,8 +169,7 @@ enum ieee80211_chanctx_change { * sizeof(void *), size is determined in hw information. */ struct ieee80211_chanctx_conf { - struct ieee80211_channel *channel; - enum nl80211_channel_type channel_type; + struct cfg80211_chan_def def; u8 rx_chains_static, rx_chains_dynamic; @@ -288,9 +286,8 @@ enum ieee80211_rssi_event { * @mcast_rate: per-band multicast rate index + 1 (0: disabled) * @bssid: The BSSID for this BSS * @enable_beacon: whether beaconing should be enabled or not - * @channel_type: Channel type for this BSS -- the hardware might be - * configured for HT40+ while this BSS only uses no-HT, for - * example. + * @chandef: Channel definition for this BSS -- the hardware might be + * configured a higher bandwidth than this BSS uses, for example. * @ht_operation_mode: HT operation mode like in &struct ieee80211_ht_operation. * This field is only valid when the channel type is one of the HT types. * @cqm_rssi_thold: Connection quality monitor RSSI threshold, a zero value @@ -339,7 +336,7 @@ struct ieee80211_bss_conf { u16 ht_operation_mode; s32 cqm_rssi_thold; u32 cqm_rssi_hyst; - enum nl80211_channel_type channel_type; + struct cfg80211_chan_def chandef; __be32 arp_addr_list[IEEE80211_BSS_ARP_ADDR_LIST_LEN]; u8 arp_addr_cnt; bool arp_filter_enabled; @@ -502,9 +499,14 @@ enum mac80211_tx_control_flags { * This is set if the current BSS requires ERP protection. * @IEEE80211_TX_RC_USE_SHORT_PREAMBLE: Use short preamble. * @IEEE80211_TX_RC_MCS: HT rate. + * @IEEE80211_TX_RC_VHT_MCS: VHT MCS rate, in this case the idx field is split + * into a higher 4 bits (Nss) and lower 4 bits (MCS number) * @IEEE80211_TX_RC_GREEN_FIELD: Indicates whether this rate should be used in * Greenfield mode. * @IEEE80211_TX_RC_40_MHZ_WIDTH: Indicates if the Channel Width should be 40 MHz. + * @IEEE80211_TX_RC_80_MHZ_WIDTH: Indicates 80 MHz transmission + * @IEEE80211_TX_RC_160_MHZ_WIDTH: Indicates 160 MHz transmission + * (80+80 isn't supported yet) * @IEEE80211_TX_RC_DUP_DATA: The frame should be transmitted on both of the * adjacent 20 MHz channels, if the current channel type is * NL80211_CHAN_HT40MINUS or NL80211_CHAN_HT40PLUS. @@ -515,12 +517,15 @@ enum mac80211_rate_control_flags { IEEE80211_TX_RC_USE_CTS_PROTECT = BIT(1), IEEE80211_TX_RC_USE_SHORT_PREAMBLE = BIT(2), - /* rate index is an MCS rate number instead of an index */ + /* rate index is an HT/VHT MCS instead of an index */ IEEE80211_TX_RC_MCS = BIT(3), IEEE80211_TX_RC_GREEN_FIELD = BIT(4), IEEE80211_TX_RC_40_MHZ_WIDTH = BIT(5), IEEE80211_TX_RC_DUP_DATA = BIT(6), IEEE80211_TX_RC_SHORT_GI = BIT(7), + IEEE80211_TX_RC_VHT_MCS = BIT(8), + IEEE80211_TX_RC_80_MHZ_WIDTH = BIT(9), + IEEE80211_TX_RC_160_MHZ_WIDTH = BIT(10), }; @@ -563,10 +568,32 @@ enum mac80211_rate_control_flags { */ struct ieee80211_tx_rate { s8 idx; - u8 count; - u8 flags; + u16 count:5, + flags:11; } __packed; +#define IEEE80211_MAX_TX_RETRY 31 + +static inline void ieee80211_rate_set_vht(struct ieee80211_tx_rate *rate, + u8 mcs, u8 nss) +{ + WARN_ON(mcs & ~0xF); + WARN_ON(nss & ~0x7); + rate->idx = (nss << 4) | mcs; +} + +static inline u8 +ieee80211_rate_get_vht_mcs(const struct ieee80211_tx_rate *rate) +{ + return rate->idx & 0xF; +} + +static inline u8 +ieee80211_rate_get_vht_nss(const struct ieee80211_tx_rate *rate) +{ + return rate->idx >> 4; +} + /** * struct ieee80211_tx_info - skb transmit information * @@ -711,13 +738,20 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info) * the frame. * @RX_FLAG_FAILED_PLCP_CRC: Set this flag if the PCLP check failed on * the frame. - * @RX_FLAG_MACTIME_MPDU: The timestamp passed in the RX status (@mactime + * @RX_FLAG_MACTIME_START: The timestamp passed in the RX status (@mactime * field) is valid and contains the time the first symbol of the MPDU * was received. This is useful in monitor mode and for proper IBSS * merging. + * @RX_FLAG_MACTIME_END: The timestamp passed in the RX status (@mactime + * field) is valid and contains the time the last symbol of the MPDU + * (including FCS) was received. * @RX_FLAG_SHORTPRE: Short preamble was used for this frame * @RX_FLAG_HT: HT MCS was used and rate_idx is MCS index + * @RX_FLAG_VHT: VHT MCS was used and rate_index is MCS index * @RX_FLAG_40MHZ: HT40 (40 MHz) was used + * @RX_FLAG_80MHZ: 80 MHz was used + * @RX_FLAG_80P80MHZ: 80+80 MHz was used + * @RX_FLAG_160MHZ: 160 MHz was used * @RX_FLAG_SHORT_GI: Short guard interval was used * @RX_FLAG_NO_SIGNAL_VAL: The signal strength value is not present. * Valid only for data frames (mainly A-MPDU) @@ -745,7 +779,7 @@ enum mac80211_rx_flags { RX_FLAG_IV_STRIPPED = BIT(4), RX_FLAG_FAILED_FCS_CRC = BIT(5), RX_FLAG_FAILED_PLCP_CRC = BIT(6), - RX_FLAG_MACTIME_MPDU = BIT(7), + RX_FLAG_MACTIME_START = BIT(7), RX_FLAG_SHORTPRE = BIT(8), RX_FLAG_HT = BIT(9), RX_FLAG_40MHZ = BIT(10), @@ -759,6 +793,11 @@ enum mac80211_rx_flags { RX_FLAG_AMPDU_IS_LAST = BIT(18), RX_FLAG_AMPDU_DELIM_CRC_ERROR = BIT(19), RX_FLAG_AMPDU_DELIM_CRC_KNOWN = BIT(20), + RX_FLAG_MACTIME_END = BIT(21), + RX_FLAG_VHT = BIT(22), + RX_FLAG_80MHZ = BIT(23), + RX_FLAG_80P80MHZ = BIT(24), + RX_FLAG_160MHZ = BIT(25), }; /** @@ -779,25 +818,39 @@ enum mac80211_rx_flags { * @IEEE80211_HW_SIGNAL_* * @antenna: antenna used * @rate_idx: index of data rate into band's supported rates or MCS index if - * HT rates are use (RX_FLAG_HT) + * HT or VHT is used (%RX_FLAG_HT/%RX_FLAG_VHT) + * @vht_nss: number of streams (VHT only) * @flag: %RX_FLAG_* * @rx_flags: internal RX flags for mac80211 * @ampdu_reference: A-MPDU reference number, must be a different value for * each A-MPDU but the same for each subframe within one A-MPDU * @ampdu_delimiter_crc: A-MPDU delimiter CRC + * @vendor_radiotap_bitmap: radiotap vendor namespace presence bitmap + * @vendor_radiotap_len: radiotap vendor namespace length + * @vendor_radiotap_align: radiotap vendor namespace alignment. Note + * that the actual data must be at the start of the SKB data + * already. + * @vendor_radiotap_oui: radiotap vendor namespace OUI + * @vendor_radiotap_subns: radiotap vendor sub namespace */ struct ieee80211_rx_status { u64 mactime; u32 device_timestamp; u32 ampdu_reference; u32 flag; + u32 vendor_radiotap_bitmap; + u16 vendor_radiotap_len; u16 freq; u8 rate_idx; + u8 vht_nss; u8 rx_flags; u8 band; u8 antenna; s8 signal; u8 ampdu_delimiter_crc; + u8 vendor_radiotap_align; + u8 vendor_radiotap_oui[3]; + u8 vendor_radiotap_subns; }; /** @@ -2192,6 +2245,14 @@ enum ieee80211_rate_control_changed { * @sta_remove: Notifies low level driver about removal of an associated * station, AP, IBSS/WDS/mesh peer etc. This callback can sleep. * + * @sta_add_debugfs: Drivers can use this callback to add debugfs files + * when a station is added to mac80211's station list. This callback + * and @sta_remove_debugfs should be within a CONFIG_MAC80211_DEBUGFS + * conditional. This callback can sleep. + * + * @sta_remove_debugfs: Remove the debugfs files which were added using + * @sta_add_debugfs. This callback can sleep. + * * @sta_notify: Notifies low level driver about power state transition of an * associated station, AP, IBSS/WDS/mesh peer etc. For a VIF operating * in AP mode, this callback will not be called when the flag @@ -2473,6 +2534,16 @@ struct ieee80211_ops { struct ieee80211_sta *sta); int (*sta_remove)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta); +#ifdef CONFIG_MAC80211_DEBUGFS + void (*sta_add_debugfs)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct dentry *dir); + void (*sta_remove_debugfs)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct dentry *dir); +#endif void (*sta_notify)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum sta_notify_cmd, struct ieee80211_sta *sta); int (*sta_state)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -2514,8 +2585,8 @@ struct ieee80211_ops { int (*get_antenna)(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant); int (*remain_on_channel)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type, int duration); int (*cancel_remain_on_channel)(struct ieee80211_hw *hw); int (*set_ringparam)(struct ieee80211_hw *hw, u32 tx, u32 rx); diff --git a/include/net/nfc/hci.h b/include/net/nfc/hci.h index 639f50a..671953e 100644 --- a/include/net/nfc/hci.h +++ b/include/net/nfc/hci.h @@ -149,6 +149,8 @@ void *nfc_hci_get_clientdata(struct nfc_hci_dev *hdev); void nfc_hci_driver_failure(struct nfc_hci_dev *hdev, int err); +int nfc_hci_result_to_errno(u8 result); + /* Host IDs */ #define NFC_HCI_HOST_CONTROLLER_ID 0x00 #define NFC_HCI_TERMINAL_HOST_ID 0x01 @@ -235,5 +237,6 @@ int nfc_hci_send_response(struct nfc_hci_dev *hdev, u8 gate, u8 response, int nfc_hci_send_event(struct nfc_hci_dev *hdev, u8 gate, u8 event, const u8 *param, size_t param_len); int nfc_hci_target_discovered(struct nfc_hci_dev *hdev, u8 gate); +u32 nfc_hci_sak_to_protocol(u8 sak); #endif /* __NET_HCI_H */ diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index cbd2d6b..33a4174 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -118,8 +118,9 @@ * to get a list of all present wiphys. * @NL80211_CMD_SET_WIPHY: set wiphy parameters, needs %NL80211_ATTR_WIPHY or * %NL80211_ATTR_IFINDEX; can be used to set %NL80211_ATTR_WIPHY_NAME, - * %NL80211_ATTR_WIPHY_TXQ_PARAMS, %NL80211_ATTR_WIPHY_FREQ, - * %NL80211_ATTR_WIPHY_CHANNEL_TYPE, %NL80211_ATTR_WIPHY_RETRY_SHORT, + * %NL80211_ATTR_WIPHY_TXQ_PARAMS, %NL80211_ATTR_WIPHY_FREQ (and the + * attributes determining the channel width; this is used for setting + * monitor mode channel), %NL80211_ATTR_WIPHY_RETRY_SHORT, * %NL80211_ATTR_WIPHY_RETRY_LONG, %NL80211_ATTR_WIPHY_FRAG_THRESHOLD, * and/or %NL80211_ATTR_WIPHY_RTS_THRESHOLD. * However, for setting the channel, see %NL80211_CMD_SET_CHANNEL @@ -171,7 +172,7 @@ * %NL80211_ATTR_AKM_SUITES, %NL80211_ATTR_PRIVACY, * %NL80211_ATTR_AUTH_TYPE and %NL80211_ATTR_INACTIVITY_TIMEOUT. * The channel to use can be set on the interface or be given using the - * %NL80211_ATTR_WIPHY_FREQ and %NL80211_ATTR_WIPHY_CHANNEL_TYPE attrs. + * %NL80211_ATTR_WIPHY_FREQ and the attributes determining channel width. * @NL80211_CMD_NEW_BEACON: old alias for %NL80211_CMD_START_AP * @NL80211_CMD_STOP_AP: Stop AP operation on the given interface * @NL80211_CMD_DEL_BEACON: old alias for %NL80211_CMD_STOP_AP @@ -401,8 +402,7 @@ * a response while being associated to an AP on another channel. * %NL80211_ATTR_IFINDEX is used to specify which interface (and thus * radio) is used. %NL80211_ATTR_WIPHY_FREQ is used to specify the - * frequency for the operation and %NL80211_ATTR_WIPHY_CHANNEL_TYPE may be - * optionally used to specify additional channel parameters. + * frequency for the operation. * %NL80211_ATTR_DURATION is used to specify the duration in milliseconds * to remain on the channel. This command is also used as an event to * notify when the requested duration starts (it may take a while for the @@ -440,12 +440,11 @@ * as an event indicating reception of a frame that was not processed in * kernel code, but is for us (i.e., which may need to be processed in a * user space application). %NL80211_ATTR_FRAME is used to specify the - * frame contents (including header). %NL80211_ATTR_WIPHY_FREQ (and - * optionally %NL80211_ATTR_WIPHY_CHANNEL_TYPE) is used to indicate on - * which channel the frame is to be transmitted or was received. If this - * channel is not the current channel (remain-on-channel or the - * operational channel) the device will switch to the given channel and - * transmit the frame, optionally waiting for a response for the time + * frame contents (including header). %NL80211_ATTR_WIPHY_FREQ is used + * to indicate on which channel the frame is to be transmitted or was + * received. If this channel is not the current channel (remain-on-channel + * or the operational channel) the device will switch to the given channel + * and transmit the frame, optionally waiting for a response for the time * specified using %NL80211_ATTR_DURATION. When called, this operation * returns a cookie (%NL80211_ATTR_COOKIE) that will be included with the * TX status event pertaining to the TX request. @@ -473,8 +472,8 @@ * command is used as an event to indicate the that a trigger level was * reached. * @NL80211_CMD_SET_CHANNEL: Set the channel (using %NL80211_ATTR_WIPHY_FREQ - * and %NL80211_ATTR_WIPHY_CHANNEL_TYPE) the given interface (identifed - * by %NL80211_ATTR_IFINDEX) shall operate on. + * and the attributes determining channel width) the given interface + * (identifed by %NL80211_ATTR_IFINDEX) shall operate on. * In case multiple channels are supported by the device, the mechanism * with which it switches channels is implementation-defined. * When a monitor interface is given, it can only switch channel while @@ -526,6 +525,12 @@ * of PMKSA caching dandidates. * * @NL80211_CMD_TDLS_OPER: Perform a high-level TDLS command (e.g. link setup). + * In addition, this can be used as an event to request userspace to take + * actions on TDLS links (set up a new link or tear down an existing one). + * In such events, %NL80211_ATTR_TDLS_OPERATION indicates the requested + * operation, %NL80211_ATTR_MAC contains the peer MAC address, and + * %NL80211_ATTR_REASON_CODE the reason code to be used (only with + * %NL80211_TDLS_TEARDOWN). * @NL80211_CMD_TDLS_MGMT: Send a TDLS management frame. * * @NL80211_CMD_UNEXPECTED_FRAME: Used by an application controlling an AP @@ -562,8 +567,8 @@ * * @NL80211_CMD_CH_SWITCH_NOTIFY: An AP or GO may decide to switch channels * independently of the userspace SME, send this event indicating - * %NL80211_ATTR_IFINDEX is now on %NL80211_ATTR_WIPHY_FREQ with - * %NL80211_ATTR_WIPHY_CHANNEL_TYPE. + * %NL80211_ATTR_IFINDEX is now on %NL80211_ATTR_WIPHY_FREQ and the + * attributes determining channel width. * * @NL80211_CMD_START_P2P_DEVICE: Start the given P2P Device, identified by * its %NL80211_ATTR_WDEV identifier. It must have been created with @@ -767,14 +772,26 @@ enum nl80211_commands { * /sys/class/ieee80211/<phyname>/index * @NL80211_ATTR_WIPHY_NAME: wiphy name (used for renaming) * @NL80211_ATTR_WIPHY_TXQ_PARAMS: a nested array of TX queue parameters - * @NL80211_ATTR_WIPHY_FREQ: frequency of the selected channel in MHz + * @NL80211_ATTR_WIPHY_FREQ: frequency of the selected channel in MHz, + * defines the channel together with the (deprecated) + * %NL80211_ATTR_WIPHY_CHANNEL_TYPE attribute or the attributes + * %NL80211_ATTR_CHANNEL_WIDTH and if needed %NL80211_ATTR_CENTER_FREQ1 + * and %NL80211_ATTR_CENTER_FREQ2 + * @NL80211_ATTR_CHANNEL_WIDTH: u32 attribute containing one of the values + * of &enum nl80211_chan_width, describing the channel width. See the + * documentation of the enum for more information. + * @NL80211_ATTR_CENTER_FREQ1: Center frequency of the first part of the + * channel, used for anything but 20 MHz bandwidth + * @NL80211_ATTR_CENTER_FREQ2: Center frequency of the second part of the + * channel, used only for 80+80 MHz bandwidth * @NL80211_ATTR_WIPHY_CHANNEL_TYPE: included with NL80211_ATTR_WIPHY_FREQ - * if HT20 or HT40 are allowed (i.e., 802.11n disabled if not included): + * if HT20 or HT40 are to be used (i.e., HT disabled if not included): * NL80211_CHAN_NO_HT = HT not allowed (i.e., same as not including * this attribute) * NL80211_CHAN_HT20 = HT20 only * NL80211_CHAN_HT40MINUS = secondary channel is below the primary channel * NL80211_CHAN_HT40PLUS = secondary channel is above the primary channel + * This attribute is now deprecated. * @NL80211_ATTR_WIPHY_RETRY_SHORT: TX retry limit for frames whose length is * less than or equal to the RTS threshold; allowed range: 1..255; * dot11ShortRetryLimit; u8 @@ -1549,6 +1566,10 @@ enum nl80211_attrs { NL80211_ATTR_SCAN_FLAGS, + NL80211_ATTR_CHANNEL_WIDTH, + NL80211_ATTR_CENTER_FREQ1, + NL80211_ATTR_CENTER_FREQ2, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -1713,10 +1734,15 @@ struct nl80211_sta_flag_update { * @__NL80211_RATE_INFO_INVALID: attribute number 0 is reserved * @NL80211_RATE_INFO_BITRATE: total bitrate (u16, 100kbit/s) * @NL80211_RATE_INFO_MCS: mcs index for 802.11n (u8) - * @NL80211_RATE_INFO_40_MHZ_WIDTH: 40 Mhz dualchannel bitrate + * @NL80211_RATE_INFO_40_MHZ_WIDTH: 40 MHz dualchannel bitrate * @NL80211_RATE_INFO_SHORT_GI: 400ns guard interval * @NL80211_RATE_INFO_BITRATE32: total bitrate (u32, 100kbit/s) * @NL80211_RATE_INFO_MAX: highest rate_info number currently defined + * @NL80211_RATE_INFO_VHT_MCS: MCS index for VHT (u8) + * @NL80211_RATE_INFO_VHT_NSS: number of streams in VHT (u8) + * @NL80211_RATE_INFO_80_MHZ_WIDTH: 80 MHz VHT rate + * @NL80211_RATE_INFO_80P80_MHZ_WIDTH: 80+80 MHz VHT rate + * @NL80211_RATE_INFO_160_MHZ_WIDTH: 160 MHz VHT rate * @__NL80211_RATE_INFO_AFTER_LAST: internal use */ enum nl80211_rate_info { @@ -1726,6 +1752,11 @@ enum nl80211_rate_info { NL80211_RATE_INFO_40_MHZ_WIDTH, NL80211_RATE_INFO_SHORT_GI, NL80211_RATE_INFO_BITRATE32, + NL80211_RATE_INFO_VHT_MCS, + NL80211_RATE_INFO_VHT_NSS, + NL80211_RATE_INFO_80_MHZ_WIDTH, + NL80211_RATE_INFO_80P80_MHZ_WIDTH, + NL80211_RATE_INFO_160_MHZ_WIDTH, /* keep last */ __NL80211_RATE_INFO_AFTER_LAST, @@ -2434,6 +2465,15 @@ enum nl80211_ac { #define NL80211_TXQ_Q_BE NL80211_AC_BE #define NL80211_TXQ_Q_BK NL80211_AC_BK +/** + * enum nl80211_channel_type - channel type + * @NL80211_CHAN_NO_HT: 20 MHz, non-HT channel + * @NL80211_CHAN_HT20: 20 MHz HT channel + * @NL80211_CHAN_HT40MINUS: HT40 channel, secondary channel + * below the control channel + * @NL80211_CHAN_HT40PLUS: HT40 channel, secondary channel + * above the control channel + */ enum nl80211_channel_type { NL80211_CHAN_NO_HT, NL80211_CHAN_HT20, @@ -2442,6 +2482,32 @@ enum nl80211_channel_type { }; /** + * enum nl80211_chan_width - channel width definitions + * + * These values are used with the %NL80211_ATTR_CHANNEL_WIDTH + * attribute. + * + * @NL80211_CHAN_WIDTH_20_NOHT: 20 MHz, non-HT channel + * @NL80211_CHAN_WIDTH_20: 20 MHz HT channel + * @NL80211_CHAN_WIDTH_40: 40 MHz channel, the %NL80211_ATTR_CENTER_FREQ1 + * attribute must be provided as well + * @NL80211_CHAN_WIDTH_80: 80 MHz channel, the %NL80211_ATTR_CENTER_FREQ1 + * attribute must be provided as well + * @NL80211_CHAN_WIDTH_80P80: 80+80 MHz channel, the %NL80211_ATTR_CENTER_FREQ1 + * and %NL80211_ATTR_CENTER_FREQ2 attributes must be provided as well + * @NL80211_CHAN_WIDTH_160: 160 MHz channel, the %NL80211_ATTR_CENTER_FREQ1 + * attribute must be provided as well + */ +enum nl80211_chan_width { + NL80211_CHAN_WIDTH_20_NOHT, + NL80211_CHAN_WIDTH_20, + NL80211_CHAN_WIDTH_40, + NL80211_CHAN_WIDTH_80, + NL80211_CHAN_WIDTH_80P80, + NL80211_CHAN_WIDTH_160, +}; + +/** * enum nl80211_bss - netlink attributes for a BSS * * @__NL80211_BSS_INVALID: invalid @@ -3057,6 +3123,9 @@ enum nl80211_ap_sme_features { * @NL80211_FEATURE_SCAN_FLUSH: Scan flush is supported * @NL80211_FEATURE_AP_SCAN: Support scanning using an AP vif * @NL80211_FEATURE_VIF_TXPOWER: The driver supports per-vif TX power setting + * @NL80211_FEATURE_NEED_OBSS_SCAN: The driver expects userspace to perform + * OBSS scans and generate 20/40 BSS coex reports. This flag is used only + * for drivers implementing the CONNECT API, for AUTH/ASSOC it is implied. */ enum nl80211_feature_flags { NL80211_FEATURE_SK_TX_STATUS = 1 << 0, @@ -3069,6 +3138,7 @@ enum nl80211_feature_flags { NL80211_FEATURE_SCAN_FLUSH = 1 << 7, NL80211_FEATURE_AP_SCAN = 1 << 8, NL80211_FEATURE_VIF_TXPOWER = 1 << 9, + NL80211_FEATURE_NEED_OBSS_SCAN = 1 << 10, }; /** diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index ec7d3a7..596660d 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1818,11 +1818,11 @@ int hci_register_dev(struct hci_dev *hdev) if (hdev->dev_type != HCI_AMP) set_bit(HCI_AUTO_OFF, &hdev->dev_flags); - schedule_work(&hdev->power_on); - hci_notify(hdev, HCI_DEV_REG); hci_dev_hold(hdev); + schedule_work(&hdev->power_on); + return id; err_wqueue: diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 5d0ef75..f559b96 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -326,7 +326,7 @@ static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data, struct hci_dev *d; size_t rp_len; u16 count; - int i, err; + int err; BT_DBG("sock %p", sk); @@ -347,9 +347,7 @@ static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data, return -ENOMEM; } - rp->num_controllers = cpu_to_le16(count); - - i = 0; + count = 0; list_for_each_entry(d, &hci_dev_list, list) { if (test_bit(HCI_SETUP, &d->dev_flags)) continue; @@ -357,10 +355,13 @@ static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data, if (!mgmt_valid_hdev(d)) continue; - rp->index[i++] = cpu_to_le16(d->id); + rp->index[count++] = cpu_to_le16(d->id); BT_DBG("Added hci%u", d->id); } + rp->num_controllers = cpu_to_le16(count); + rp_len = sizeof(*rp) + (2 * count); + read_unlock(&hci_dev_list_lock); err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp, @@ -1378,6 +1379,7 @@ static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data, continue; list_del(&match->list); + kfree(match); found++; } diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 9176bc1..68a9587 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -267,7 +267,7 @@ static void smp_failure(struct l2cap_conn *conn, u8 reason, u8 send) clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->hcon->flags); mgmt_auth_failed(conn->hcon->hdev, conn->dst, hcon->type, - hcon->dst_type, reason); + hcon->dst_type, HCI_ERROR_AUTH_FAILURE); cancel_delayed_work_sync(&conn->security_timer); diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index bcf02f6..017a8ba 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -429,6 +429,17 @@ static struct attribute_group netstat_group = { .name = "statistics", .attrs = netstat_attrs, }; + +#if IS_ENABLED(CONFIG_WIRELESS_EXT) || IS_ENABLED(CONFIG_CFG80211) +static struct attribute *wireless_attrs[] = { + NULL +}; + +static struct attribute_group wireless_group = { + .name = "wireless", + .attrs = wireless_attrs, +}; +#endif #endif /* CONFIG_SYSFS */ #ifdef CONFIG_RPS @@ -1409,6 +1420,15 @@ int netdev_register_kobject(struct net_device *net) groups++; *groups++ = &netstat_group; + +#if IS_ENABLED(CONFIG_WIRELESS_EXT) || IS_ENABLED(CONFIG_CFG80211) + if (net->ieee80211_ptr) + *groups++ = &wireless_group; +#if IS_ENABLED(CONFIG_WIRELESS_EXT) + else if (net->wireless_handlers) + *groups++ = &wireless_group; +#endif +#endif #endif /* CONFIG_SYSFS */ error = device_add(dev); diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index 186d991..808338a 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c @@ -118,7 +118,7 @@ void ieee80211_stop_rx_ba_session(struct ieee80211_vif *vif, u16 ba_rx_bitmap, return; } - for (i = 0; i < STA_TID_NUM; i++) + for (i = 0; i < IEEE80211_NUM_TIDS; i++) if (ba_rx_bitmap & BIT(i)) set_bit(i, sta->ampdu_mlme.tid_rx_stop_requested); diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 3195a63..4152ed1 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -448,7 +448,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid, if (WARN_ON(!local->ops->ampdu_action)) return -EINVAL; - if ((tid >= STA_TID_NUM) || + if ((tid >= IEEE80211_NUM_TIDS) || !(local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION) || (local->hw.flags & IEEE80211_HW_TX_AMPDU_SETUP_IN_HW)) return -EINVAL; @@ -605,9 +605,9 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid) trace_api_start_tx_ba_cb(sdata, ra, tid); - if (tid >= STA_TID_NUM) { + if (tid >= IEEE80211_NUM_TIDS) { ht_dbg(sdata, "Bad TID value: tid = %d (>= %d)\n", - tid, STA_TID_NUM); + tid, IEEE80211_NUM_TIDS); return; } @@ -687,7 +687,7 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid) if (!local->ops->ampdu_action) return -EINVAL; - if (tid >= STA_TID_NUM) + if (tid >= IEEE80211_NUM_TIDS) return -EINVAL; spin_lock_bh(&sta->lock); @@ -722,9 +722,9 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid) trace_api_stop_tx_ba_cb(sdata, ra, tid); - if (tid >= STA_TID_NUM) { + if (tid >= IEEE80211_NUM_TIDS) { ht_dbg(sdata, "Bad TID value: tid = %d (>= %d)\n", - tid, STA_TID_NUM); + tid, IEEE80211_NUM_TIDS); return; } diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 80e0618..4965aa6 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -370,30 +370,32 @@ static int ieee80211_config_default_mgmt_key(struct wiphy *wiphy, return 0; } -static void rate_idx_to_bitrate(struct rate_info *rate, struct sta_info *sta, int idx) -{ - enum ieee80211_band band = ieee80211_get_sdata_band(sta->sdata); - - if (!(rate->flags & RATE_INFO_FLAGS_MCS)) { - struct ieee80211_supported_band *sband; - sband = sta->local->hw.wiphy->bands[band]; - rate->legacy = sband->bitrates[idx].bitrate; - } else - rate->mcs = idx; -} - void sta_set_rate_info_tx(struct sta_info *sta, const struct ieee80211_tx_rate *rate, struct rate_info *rinfo) { rinfo->flags = 0; - if (rate->flags & IEEE80211_TX_RC_MCS) + if (rate->flags & IEEE80211_TX_RC_MCS) { rinfo->flags |= RATE_INFO_FLAGS_MCS; + rinfo->mcs = rate->idx; + } else if (rate->flags & IEEE80211_TX_RC_VHT_MCS) { + rinfo->flags |= RATE_INFO_FLAGS_VHT_MCS; + rinfo->mcs = ieee80211_rate_get_vht_mcs(rate); + rinfo->nss = ieee80211_rate_get_vht_nss(rate); + } else { + struct ieee80211_supported_band *sband; + sband = sta->local->hw.wiphy->bands[ + ieee80211_get_sdata_band(sta->sdata)]; + rinfo->legacy = sband->bitrates[rate->idx].bitrate; + } if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) rinfo->flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; + if (rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH) + rinfo->flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH; + if (rate->flags & IEEE80211_TX_RC_160_MHZ_WIDTH) + rinfo->flags |= RATE_INFO_FLAGS_160_MHZ_WIDTH; if (rate->flags & IEEE80211_TX_RC_SHORT_GI) rinfo->flags |= RATE_INFO_FLAGS_SHORT_GI; - rate_idx_to_bitrate(rinfo, sta, rate->idx); } static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) @@ -444,13 +446,32 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) sta_set_rate_info_tx(sta, &sta->last_tx_rate, &sinfo->txrate); sinfo->rxrate.flags = 0; - if (sta->last_rx_rate_flag & RX_FLAG_HT) + if (sta->last_rx_rate_flag & RX_FLAG_HT) { sinfo->rxrate.flags |= RATE_INFO_FLAGS_MCS; + sinfo->rxrate.mcs = sta->last_rx_rate_idx; + } else if (sta->last_rx_rate_flag & RX_FLAG_VHT) { + sinfo->rxrate.flags |= RATE_INFO_FLAGS_VHT_MCS; + sinfo->rxrate.nss = sta->last_rx_rate_vht_nss; + sinfo->rxrate.mcs = sta->last_rx_rate_idx; + } else { + struct ieee80211_supported_band *sband; + + sband = sta->local->hw.wiphy->bands[ + ieee80211_get_sdata_band(sta->sdata)]; + sinfo->rxrate.legacy = + sband->bitrates[sta->last_rx_rate_idx].bitrate; + } + if (sta->last_rx_rate_flag & RX_FLAG_40MHZ) sinfo->rxrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; if (sta->last_rx_rate_flag & RX_FLAG_SHORT_GI) sinfo->rxrate.flags |= RATE_INFO_FLAGS_SHORT_GI; - rate_idx_to_bitrate(&sinfo->rxrate, sta, sta->last_rx_rate_idx); + if (sta->last_rx_rate_flag & RX_FLAG_80MHZ) + sinfo->rxrate.flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH; + if (sta->last_rx_rate_flag & RX_FLAG_80P80MHZ) + sinfo->rxrate.flags |= RATE_INFO_FLAGS_80P80_MHZ_WIDTH; + if (sta->last_rx_rate_flag & RX_FLAG_160MHZ) + sinfo->rxrate.flags |= RATE_INFO_FLAGS_160_MHZ_WIDTH; if (ieee80211_vif_is_mesh(&sdata->vif)) { #ifdef CONFIG_MAC80211_MESH @@ -615,7 +636,7 @@ do_survey: rcu_read_lock(); chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); if (chanctx_conf) - channel = chanctx_conf->channel; + channel = chanctx_conf->def.chan; else channel = NULL; rcu_read_unlock(); @@ -735,15 +756,13 @@ static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev, } static int ieee80211_set_monitor_channel(struct wiphy *wiphy, - struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type) + struct cfg80211_chan_def *chandef) { struct ieee80211_local *local = wiphy_priv(wiphy); struct ieee80211_sub_if_data *sdata; int ret = 0; - if (local->monitor_channel == chan && - local->monitor_channel_type == channel_type) + if (cfg80211_chandef_identical(&local->monitor_chandef, chandef)) return 0; mutex_lock(&local->iflist_mtx); @@ -753,20 +772,17 @@ static int ieee80211_set_monitor_channel(struct wiphy *wiphy, lockdep_is_held(&local->iflist_mtx)); if (sdata) { ieee80211_vif_release_channel(sdata); - ret = ieee80211_vif_use_channel( - sdata, chan, channel_type, + ret = ieee80211_vif_use_channel(sdata, chandef, IEEE80211_CHANCTX_EXCLUSIVE); } } else if (local->open_count == local->monitors) { - local->_oper_channel = chan; - local->_oper_channel_type = channel_type; + local->_oper_channel = chandef->chan; + local->_oper_channel_type = cfg80211_get_chandef_type(chandef); ieee80211_hw_config(local, 0); } - if (ret == 0) { - local->monitor_channel = chan; - local->monitor_channel_type = channel_type; - } + if (ret == 0) + local->monitor_chandef = *chandef; mutex_unlock(&local->iflist_mtx); return ret; @@ -888,8 +904,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, sdata->smps_mode = IEEE80211_SMPS_OFF; sdata->needed_rx_chains = sdata->local->rx_chains; - err = ieee80211_vif_use_channel(sdata, params->channel, - params->channel_type, + err = ieee80211_vif_use_channel(sdata, ¶ms->chandef, IEEE80211_CHANCTX_SHARED); if (err) return err; @@ -1707,8 +1722,7 @@ static int ieee80211_join_mesh(struct wiphy *wiphy, struct net_device *dev, sdata->smps_mode = IEEE80211_SMPS_OFF; sdata->needed_rx_chains = sdata->local->rx_chains; - err = ieee80211_vif_use_channel(sdata, setup->channel, - setup->channel_type, + err = ieee80211_vif_use_channel(sdata, &setup->chandef, IEEE80211_CHANCTX_SHARED); if (err) return err; @@ -1990,10 +2004,16 @@ static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) return err; } - if (changed & WIPHY_PARAM_RETRY_SHORT) + if (changed & WIPHY_PARAM_RETRY_SHORT) { + if (wiphy->retry_short > IEEE80211_MAX_TX_RETRY) + return -EINVAL; local->hw.conf.short_frame_max_tx_count = wiphy->retry_short; - if (changed & WIPHY_PARAM_RETRY_LONG) + } + if (changed & WIPHY_PARAM_RETRY_LONG) { + if (wiphy->retry_long > IEEE80211_MAX_TX_RETRY) + return -EINVAL; local->hw.conf.long_frame_max_tx_count = wiphy->retry_long; + } if (changed & (WIPHY_PARAM_RETRY_SHORT | WIPHY_PARAM_RETRY_LONG)) ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_RETRY_LIMITS); @@ -2129,7 +2149,7 @@ int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata, * the new value until we associate. */ if (!sdata->u.mgd.associated || - sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT) + sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT) return 0; ap = sdata->u.mgd.associated->bssid; @@ -2236,7 +2256,6 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy, static int ieee80211_start_roc_work(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, struct ieee80211_channel *channel, - enum nl80211_channel_type channel_type, unsigned int duration, u64 *cookie, struct sk_buff *txskb) { @@ -2254,7 +2273,6 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local, return -ENOMEM; roc->chan = channel; - roc->chan_type = channel_type; roc->duration = duration; roc->req_duration = duration; roc->frame = txskb; @@ -2287,7 +2305,7 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local, if (!duration) duration = 10; - ret = drv_remain_on_channel(local, channel, channel_type, duration); + ret = drv_remain_on_channel(local, sdata, channel, duration); if (ret) { kfree(roc); return ret; @@ -2298,7 +2316,7 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local, out_check_combine: list_for_each_entry(tmp, &local->roc_list, list) { - if (tmp->chan != channel || tmp->chan_type != channel_type) + if (tmp->chan != channel || tmp->sdata != sdata) continue; /* @@ -2415,7 +2433,6 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local, static int ieee80211_remain_on_channel(struct wiphy *wiphy, struct wireless_dev *wdev, struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type, unsigned int duration, u64 *cookie) { @@ -2424,7 +2441,7 @@ static int ieee80211_remain_on_channel(struct wiphy *wiphy, int ret; mutex_lock(&local->mtx); - ret = ieee80211_start_roc_work(local, sdata, chan, channel_type, + ret = ieee80211_start_roc_work(local, sdata, chan, duration, cookie, NULL); mutex_unlock(&local->mtx); @@ -2517,10 +2534,8 @@ static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy, static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, struct ieee80211_channel *chan, bool offchan, - enum nl80211_channel_type channel_type, - bool channel_type_valid, unsigned int wait, - const u8 *buf, size_t len, bool no_cck, - bool dont_wait_for_ack, u64 *cookie) + unsigned int wait, const u8 *buf, size_t len, + bool no_cck, bool dont_wait_for_ack, u64 *cookie) { struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); struct ieee80211_local *local = sdata->local; @@ -2589,14 +2604,10 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, rcu_read_lock(); chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); - if (chanctx_conf) { - need_offchan = chan != chanctx_conf->channel; - if (channel_type_valid && - channel_type != chanctx_conf->channel_type) - need_offchan = true; - } else { + if (chanctx_conf) + need_offchan = chan != chanctx_conf->def.chan; + else need_offchan = true; - } rcu_read_unlock(); } @@ -2631,7 +2642,7 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, local->hw.offchannel_tx_hw_queue; /* This will handle all kinds of coalescing and immediate TX */ - ret = ieee80211_start_roc_work(local, sdata, chan, channel_type, + ret = ieee80211_start_roc_work(local, sdata, chan, wait, cookie, skb); if (ret) kfree_skb(skb); @@ -2673,6 +2684,9 @@ static void ieee80211_mgmt_frame_register(struct wiphy *wiphy, else local->probe_req_reg--; + if (!local->open_count) + break; + ieee80211_queue_work(&local->hw, &local->reconfig_filter); break; default: @@ -3062,7 +3076,7 @@ static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev, rcu_read_unlock(); return -EINVAL; } - band = chanctx_conf->channel->band; + band = chanctx_conf->def.chan->band; sta = sta_info_get(sdata, peer); if (sta) { qos = test_sta_flag(sta, WLAN_STA_WME); @@ -3119,23 +3133,23 @@ static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev, return 0; } -static struct ieee80211_channel * -ieee80211_cfg_get_channel(struct wiphy *wiphy, struct wireless_dev *wdev, - enum nl80211_channel_type *type) +static int ieee80211_cfg_get_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct cfg80211_chan_def *chandef) { struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); struct ieee80211_chanctx_conf *chanctx_conf; - struct ieee80211_channel *chan = NULL; + int ret = -ENODATA; rcu_read_lock(); chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); if (chanctx_conf) { - *type = chanctx_conf->channel_type; - chan = chanctx_conf->channel; + *chandef = chanctx_conf->def; + ret = 0; } rcu_read_unlock(); - return chan; + return ret; } #ifdef CONFIG_PM diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index a2b06d4..53f0312 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -8,93 +8,47 @@ #include "ieee80211_i.h" #include "driver-ops.h" -static bool -ieee80211_channel_types_are_compatible(enum nl80211_channel_type chantype1, - enum nl80211_channel_type chantype2, - enum nl80211_channel_type *compat) +static void ieee80211_change_chandef(struct ieee80211_local *local, + struct ieee80211_chanctx *ctx, + const struct cfg80211_chan_def *chandef) { - /* - * start out with chantype1 being the result, - * overwriting later if needed - */ - if (compat) - *compat = chantype1; - - switch (chantype1) { - case NL80211_CHAN_NO_HT: - if (compat) - *compat = chantype2; - break; - case NL80211_CHAN_HT20: - /* - * allow any change that doesn't go to no-HT - * (if it already is no-HT no change is needed) - */ - if (chantype2 == NL80211_CHAN_NO_HT) - break; - if (compat) - *compat = chantype2; - break; - case NL80211_CHAN_HT40PLUS: - case NL80211_CHAN_HT40MINUS: - /* allow smaller bandwidth and same */ - if (chantype2 == NL80211_CHAN_NO_HT) - break; - if (chantype2 == NL80211_CHAN_HT20) - break; - if (chantype2 == chantype1) - break; - return false; - } - - return true; -} - -static void ieee80211_change_chantype(struct ieee80211_local *local, - struct ieee80211_chanctx *ctx, - enum nl80211_channel_type chantype) -{ - if (chantype == ctx->conf.channel_type) + if (cfg80211_chandef_identical(&ctx->conf.def, chandef)) return; - ctx->conf.channel_type = chantype; - drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_CHANNEL_TYPE); + WARN_ON(!cfg80211_chandef_compatible(&ctx->conf.def, chandef)); + + ctx->conf.def = *chandef; + drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_WIDTH); if (!local->use_chanctx) { - local->_oper_channel_type = chantype; + local->_oper_channel_type = cfg80211_get_chandef_type(chandef); ieee80211_hw_config(local, 0); } } static struct ieee80211_chanctx * ieee80211_find_chanctx(struct ieee80211_local *local, - struct ieee80211_channel *channel, - enum nl80211_channel_type channel_type, + const struct cfg80211_chan_def *chandef, enum ieee80211_chanctx_mode mode) { struct ieee80211_chanctx *ctx; - enum nl80211_channel_type compat_type; lockdep_assert_held(&local->chanctx_mtx); if (mode == IEEE80211_CHANCTX_EXCLUSIVE) return NULL; - if (WARN_ON(!channel)) - return NULL; list_for_each_entry(ctx, &local->chanctx_list, list) { - compat_type = ctx->conf.channel_type; + const struct cfg80211_chan_def *compat; if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) continue; - if (ctx->conf.channel != channel) - continue; - if (!ieee80211_channel_types_are_compatible(ctx->conf.channel_type, - channel_type, - &compat_type)) + + compat = cfg80211_chandef_compatible(&ctx->conf.def, chandef); + if (!compat) continue; - ieee80211_change_chantype(local, ctx, compat_type); + ieee80211_change_chandef(local, ctx, compat); return ctx; } @@ -104,8 +58,7 @@ ieee80211_find_chanctx(struct ieee80211_local *local, static struct ieee80211_chanctx * ieee80211_new_chanctx(struct ieee80211_local *local, - struct ieee80211_channel *channel, - enum nl80211_channel_type channel_type, + const struct cfg80211_chan_def *chandef, enum ieee80211_chanctx_mode mode) { struct ieee80211_chanctx *ctx; @@ -117,15 +70,15 @@ ieee80211_new_chanctx(struct ieee80211_local *local, if (!ctx) return ERR_PTR(-ENOMEM); - ctx->conf.channel = channel; - ctx->conf.channel_type = channel_type; + ctx->conf.def = *chandef; ctx->conf.rx_chains_static = 1; ctx->conf.rx_chains_dynamic = 1; ctx->mode = mode; if (!local->use_chanctx) { - local->_oper_channel_type = channel_type; - local->_oper_channel = channel; + local->_oper_channel_type = + cfg80211_get_chandef_type(chandef); + local->_oper_channel = chandef->chan; ieee80211_hw_config(local, 0); } else { err = drv_add_chanctx(local, ctx); @@ -178,41 +131,37 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata, return 0; } -static enum nl80211_channel_type -ieee80211_calc_chantype(struct ieee80211_local *local, - struct ieee80211_chanctx *ctx) +static void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local, + struct ieee80211_chanctx *ctx) { struct ieee80211_chanctx_conf *conf = &ctx->conf; struct ieee80211_sub_if_data *sdata; - enum nl80211_channel_type result = NL80211_CHAN_NO_HT; + const struct cfg80211_chan_def *compat = NULL; lockdep_assert_held(&local->chanctx_mtx); rcu_read_lock(); list_for_each_entry_rcu(sdata, &local->interfaces, list) { + if (!ieee80211_sdata_running(sdata)) continue; if (rcu_access_pointer(sdata->vif.chanctx_conf) != conf) continue; - WARN_ON_ONCE(!ieee80211_channel_types_are_compatible( - sdata->vif.bss_conf.channel_type, - result, &result)); + if (!compat) + compat = &sdata->vif.bss_conf.chandef; + + compat = cfg80211_chandef_compatible( + &sdata->vif.bss_conf.chandef, compat); + if (!compat) + break; } rcu_read_unlock(); - return result; -} - -static void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local, - struct ieee80211_chanctx *ctx) -{ - enum nl80211_channel_type chantype; - - lockdep_assert_held(&local->chanctx_mtx); + if (WARN_ON_ONCE(!compat)) + return; - chantype = ieee80211_calc_chantype(local, ctx); - ieee80211_change_chantype(local, ctx, chantype); + ieee80211_change_chandef(local, ctx, compat); } static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data *sdata, @@ -337,8 +286,7 @@ void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, } int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, - struct ieee80211_channel *channel, - enum nl80211_channel_type channel_type, + const struct cfg80211_chan_def *chandef, enum ieee80211_chanctx_mode mode) { struct ieee80211_local *local = sdata->local; @@ -350,15 +298,15 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, mutex_lock(&local->chanctx_mtx); __ieee80211_vif_release_channel(sdata); - ctx = ieee80211_find_chanctx(local, channel, channel_type, mode); + ctx = ieee80211_find_chanctx(local, chandef, mode); if (!ctx) - ctx = ieee80211_new_chanctx(local, channel, channel_type, mode); + ctx = ieee80211_new_chanctx(local, chandef, mode); if (IS_ERR(ctx)) { ret = PTR_ERR(ctx); goto out; } - sdata->vif.bss_conf.channel_type = channel_type; + sdata->vif.bss_conf.chandef = *chandef; ret = ieee80211_assign_vif_chanctx(sdata, ctx); if (ret) { diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c index 090d08f..2d42354 100644 --- a/net/mac80211/debugfs_key.c +++ b/net/mac80211/debugfs_key.c @@ -116,7 +116,7 @@ static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { struct ieee80211_key *key = file->private_data; - char buf[14*NUM_RX_DATA_QUEUES+1], *p = buf; + char buf[14*IEEE80211_NUM_TIDS+1], *p = buf; int i, len; const u8 *rpn; @@ -126,7 +126,7 @@ static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf, len = scnprintf(buf, sizeof(buf), "\n"); break; case WLAN_CIPHER_SUITE_TKIP: - for (i = 0; i < NUM_RX_DATA_QUEUES; i++) + for (i = 0; i < IEEE80211_NUM_TIDS; i++) p += scnprintf(p, sizeof(buf)+buf-p, "%08x %04x\n", key->u.tkip.rx[i].iv32, @@ -134,7 +134,7 @@ static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf, len = p - buf; break; case WLAN_CIPHER_SUITE_CCMP: - for (i = 0; i < NUM_RX_DATA_QUEUES + 1; i++) { + for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++) { rpn = key->u.ccmp.rx_pn[i]; p += scnprintf(p, sizeof(buf)+buf-p, "%02x%02x%02x%02x%02x%02x\n", diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index ba9bd0e..cbde5cc 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -168,7 +168,6 @@ IEEE80211_IF_FILE(rc_rateidx_mcs_mask_5ghz, IEEE80211_IF_FILE(flags, flags, HEX); IEEE80211_IF_FILE(state, state, LHEX); -IEEE80211_IF_FILE(channel_type, vif.bss_conf.channel_type, DEC); IEEE80211_IF_FILE(txpower, vif.bss_conf.txpower, DEC); IEEE80211_IF_FILE(ap_power_level, ap_power_level, DEC); IEEE80211_IF_FILE(user_power_level, user_power_level, DEC); @@ -632,7 +631,6 @@ static void add_files(struct ieee80211_sub_if_data *sdata) DEBUGFS_ADD(flags); DEBUGFS_ADD(state); - DEBUGFS_ADD(channel_type); DEBUGFS_ADD(txpower); DEBUGFS_ADD(user_power_level); DEBUGFS_ADD(ap_power_level); diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 5ccec2c..89281d2 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -14,6 +14,7 @@ #include "debugfs.h" #include "debugfs_sta.h" #include "sta_info.h" +#include "driver-ops.h" /* sta attributtes */ @@ -131,10 +132,10 @@ STA_OPS(connected_time); static ssize_t sta_last_seq_ctrl_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { - char buf[15*NUM_RX_DATA_QUEUES], *p = buf; + char buf[15*IEEE80211_NUM_TIDS], *p = buf; int i; struct sta_info *sta = file->private_data; - for (i = 0; i < NUM_RX_DATA_QUEUES; i++) + for (i = 0; i < IEEE80211_NUM_TIDS; i++) p += scnprintf(p, sizeof(buf)+buf-p, "%x ", le16_to_cpu(sta->last_seq_ctrl[i])); p += scnprintf(p, sizeof(buf)+buf-p, "\n"); @@ -145,7 +146,7 @@ STA_OPS(last_seq_ctrl); static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { - char buf[71 + STA_TID_NUM * 40], *p = buf; + char buf[71 + IEEE80211_NUM_TIDS * 40], *p = buf; int i; struct sta_info *sta = file->private_data; struct tid_ampdu_rx *tid_rx; @@ -158,7 +159,7 @@ static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf, p += scnprintf(p, sizeof(buf) + buf - p, "TID\t\tRX active\tDTKN\tSSN\t\tTX\tDTKN\tpending\n"); - for (i = 0; i < STA_TID_NUM; i++) { + for (i = 0; i < IEEE80211_NUM_TIDS; i++) { tid_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[i]); tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[i]); @@ -220,7 +221,7 @@ static ssize_t sta_agg_status_write(struct file *file, const char __user *userbu tid = simple_strtoul(buf, NULL, 0); - if (tid >= STA_TID_NUM) + if (tid >= IEEE80211_NUM_TIDS) return -EINVAL; if (tx) { @@ -334,6 +335,8 @@ STA_OPS(ht_capa); void ieee80211_sta_debugfs_add(struct sta_info *sta) { + struct ieee80211_local *local = sta->local; + struct ieee80211_sub_if_data *sdata = sta->sdata; struct dentry *stations_dir = sta->sdata->debugfs.subdir_stations; u8 mac[3*ETH_ALEN]; @@ -379,10 +382,16 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta) DEBUGFS_ADD_COUNTER(tx_retry_failed, tx_retry_failed); DEBUGFS_ADD_COUNTER(tx_retry_count, tx_retry_count); DEBUGFS_ADD_COUNTER(wep_weak_iv_count, wep_weak_iv_count); + + drv_sta_add_debugfs(local, sdata, &sta->sta, sta->debugfs.dir); } void ieee80211_sta_debugfs_remove(struct sta_info *sta) { + struct ieee80211_local *local = sta->local; + struct ieee80211_sub_if_data *sdata = sta->sdata; + + drv_sta_remove_debugfs(local, sdata, &sta->sta, sta->debugfs.dir); debugfs_remove_recursive(sta->debugfs.dir); sta->debugfs.dir = NULL; } diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 4dc2577..c6560cc 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -490,6 +490,38 @@ static inline void drv_sta_remove(struct ieee80211_local *local, trace_drv_return_void(local); } +#ifdef CONFIG_MAC80211_DEBUGFS +static inline void drv_sta_add_debugfs(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + struct ieee80211_sta *sta, + struct dentry *dir) +{ + might_sleep(); + + sdata = get_bss_sdata(sdata); + check_sdata_in_driver(sdata); + + if (local->ops->sta_add_debugfs) + local->ops->sta_add_debugfs(&local->hw, &sdata->vif, + sta, dir); +} + +static inline void drv_sta_remove_debugfs(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + struct ieee80211_sta *sta, + struct dentry *dir) +{ + might_sleep(); + + sdata = get_bss_sdata(sdata); + check_sdata_in_driver(sdata); + + if (local->ops->sta_remove_debugfs) + local->ops->sta_remove_debugfs(&local->hw, &sdata->vif, + sta, dir); +} +#endif + static inline __must_check int drv_sta_state(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, @@ -704,17 +736,17 @@ static inline int drv_get_antenna(struct ieee80211_local *local, } static inline int drv_remain_on_channel(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, struct ieee80211_channel *chan, - enum nl80211_channel_type chantype, unsigned int duration) { int ret; might_sleep(); - trace_drv_remain_on_channel(local, chan, chantype, duration); - ret = local->ops->remain_on_channel(&local->hw, chan, chantype, - duration); + trace_drv_remain_on_channel(local, sdata, chan, duration); + ret = local->ops->remain_on_channel(&local->hw, &sdata->vif, + chan, duration); trace_drv_return_int(local, ret); return ret; diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 4b4538d..a71d891 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c @@ -185,7 +185,7 @@ void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta, bool tx) cancel_work_sync(&sta->ampdu_mlme.work); - for (i = 0; i < STA_TID_NUM; i++) { + for (i = 0; i < IEEE80211_NUM_TIDS; i++) { __ieee80211_stop_tx_ba_session(sta, i, WLAN_BACK_INITIATOR, tx); __ieee80211_stop_rx_ba_session(sta, i, WLAN_BACK_RECIPIENT, WLAN_REASON_QSTA_LEAVE_QBSS, tx); @@ -209,7 +209,7 @@ void ieee80211_ba_session_work(struct work_struct *work) return; mutex_lock(&sta->ampdu_mlme.mtx); - for (tid = 0; tid < STA_TID_NUM; tid++) { + for (tid = 0; tid < IEEE80211_NUM_TIDS; tid++) { if (test_and_clear_bit(tid, sta->ampdu_mlme.tid_rx_timer_expired)) ___ieee80211_stop_rx_ba_session( sta, tid, WLAN_BACK_RECIPIENT, diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index c7386b2..fa862b2 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -51,7 +51,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, struct cfg80211_bss *bss; u32 bss_change; u8 supp_rates[IEEE80211_MAX_SUPP_RATES]; - enum nl80211_channel_type channel_type; + struct cfg80211_chan_def chandef; lockdep_assert_held(&ifibss->mtx); @@ -79,12 +79,14 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0; - channel_type = ifibss->channel_type; - if (!cfg80211_can_beacon_sec_chan(local->hw.wiphy, chan, channel_type)) - channel_type = NL80211_CHAN_HT20; + cfg80211_chandef_create(&chandef, chan, ifibss->channel_type); + if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef)) { + chandef.width = NL80211_CHAN_WIDTH_20; + chandef.center_freq1 = chan->center_freq; + } ieee80211_vif_release_channel(sdata); - if (ieee80211_vif_use_channel(sdata, chan, channel_type, + if (ieee80211_vif_use_channel(sdata, &chandef, ifibss->fixed_channel ? IEEE80211_CHANCTX_SHARED : IEEE80211_CHANCTX_EXCLUSIVE)) { @@ -158,7 +160,8 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, ifibss->ie, ifibss->ie_len); /* add HT capability and information IEs */ - if (channel_type && sband->ht_cap.ht_supported) { + if (chandef.width != NL80211_CHAN_WIDTH_20_NOHT && + sband->ht_cap.ht_supported) { pos = skb_put(skb, 4 + sizeof(struct ieee80211_ht_cap) + sizeof(struct ieee80211_ht_operation)); @@ -170,7 +173,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, * keep them at 0 */ pos = ieee80211_ie_build_ht_oper(pos, &sband->ht_cap, - chan, channel_type, 0); + &chandef, 0); } if (local->hw.queues >= IEEE80211_NUM_ACS) { @@ -326,7 +329,7 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); if (WARN_ON_ONCE(!chanctx_conf)) return NULL; - band = chanctx_conf->channel->band; + band = chanctx_conf->def.chan->band; rcu_read_unlock(); sta = sta_info_alloc(sdata, addr, GFP_KERNEL); @@ -374,11 +377,13 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata, auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); - if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1) - return; ibss_dbg(sdata, "RX Auth SA=%pM DA=%pM BSSID=%pM (auth_transaction=%d)\n", mgmt->sa, mgmt->da, mgmt->bssid, auth_transaction); + + if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1) + return; + sta_info_destroy_addr(sdata, mgmt->sa); sta = ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, 0, false); rcu_read_unlock(); @@ -473,9 +478,11 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, sdata->u.ibss.channel_type != NL80211_CHAN_NO_HT) { /* we both use HT */ struct ieee80211_sta_ht_cap sta_ht_cap_new; - enum nl80211_channel_type channel_type = - ieee80211_ht_oper_to_channel_type( - elems->ht_operation); + struct cfg80211_chan_def chandef; + + ieee80211_ht_oper_to_chandef(channel, + elems->ht_operation, + &chandef); ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, elems->ht_cap_elem, @@ -485,9 +492,9 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, * fall back to HT20 if we don't use or use * the other extension channel */ - if (!(channel_type == NL80211_CHAN_HT40MINUS || - channel_type == NL80211_CHAN_HT40PLUS) || - channel_type != sdata->u.ibss.channel_type) + if (chandef.width != NL80211_CHAN_WIDTH_40 || + cfg80211_get_chandef_type(&chandef) != + sdata->u.ibss.channel_type) sta_ht_cap_new.cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; @@ -543,30 +550,11 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, if (ether_addr_equal(cbss->bssid, sdata->u.ibss.bssid)) goto put_bss; - if (rx_status->flag & RX_FLAG_MACTIME_MPDU) { - /* - * For correct IBSS merging we need mactime; since mactime is - * defined as the time the first data symbol of the frame hits - * the PHY, and the timestamp of the beacon is defined as "the - * time that the data symbol containing the first bit of the - * timestamp is transmitted to the PHY plus the transmitting - * STA's delays through its local PHY from the MAC-PHY - * interface to its interface with the WM" (802.11 11.1.2) - * - equals the time this bit arrives at the receiver - we have - * to take into account the offset between the two. - * - * E.g. at 1 MBit that means mactime is 192 usec earlier - * (=24 bytes * 8 usecs/byte) than the beacon timestamp. - */ - int rate; - - if (rx_status->flag & RX_FLAG_HT) - rate = 65; /* TODO: HT rates */ - else - rate = local->hw.wiphy->bands[band]-> - bitrates[rx_status->rate_idx].bitrate; - - rx_timestamp = rx_status->mactime + (24 * 8 * 10 / rate); + if (ieee80211_have_rx_timestamp(rx_status)) { + /* time when timestamp field was received */ + rx_timestamp = + ieee80211_calculate_rx_timestamp(local, rx_status, + len + FCS_LEN, 24); } else { /* * second best option: get current TSF @@ -630,7 +618,7 @@ void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata, rcu_read_unlock(); return; } - band = chanctx_conf->channel->band; + band = chanctx_conf->def.chan->band; rcu_read_unlock(); sta = sta_info_alloc(sdata, addr, GFP_ATOMIC); @@ -1095,8 +1083,9 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, sdata->vif.bss_conf.beacon_int = params->beacon_interval; - sdata->u.ibss.channel = params->channel; - sdata->u.ibss.channel_type = params->channel_type; + sdata->u.ibss.channel = params->chandef.chan; + sdata->u.ibss.channel_type = + cfg80211_get_chandef_type(¶ms->chandef); sdata->u.ibss.fixed_channel = params->channel_fixed; if (params->ie) { @@ -1156,10 +1145,6 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata) mutex_lock(&sdata->u.ibss.mtx); - sdata->u.ibss.state = IEEE80211_IBSS_MLME_SEARCH; - memset(sdata->u.ibss.bssid, 0, ETH_ALEN); - sdata->u.ibss.ssid_len = 0; - active_ibss = ieee80211_sta_active_ibss(sdata); if (!active_ibss && !is_zero_ether_addr(ifibss->bssid)) { @@ -1180,6 +1165,10 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata) } } + ifibss->state = IEEE80211_IBSS_MLME_SEARCH; + memset(ifibss->bssid, 0, ETH_ALEN); + ifibss->ssid_len = 0; + sta_info_flush(sdata->local, sdata); spin_lock_bh(&ifibss->incomplete_lock); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index e1fb97c..5c0d5a6 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -348,7 +348,6 @@ struct ieee80211_roc_work { struct ieee80211_sub_if_data *sdata; struct ieee80211_channel *chan; - enum nl80211_channel_type chan_type; bool started, abort, hw_begun, notified; @@ -364,7 +363,7 @@ enum ieee80211_sta_flags { IEEE80211_STA_BEACON_POLL = BIT(0), IEEE80211_STA_CONNECTION_POLL = BIT(1), IEEE80211_STA_CONTROL_PORT = BIT(2), - IEEE80211_STA_DISABLE_11N = BIT(4), + IEEE80211_STA_DISABLE_HT = BIT(4), IEEE80211_STA_CSA_RECEIVED = BIT(5), IEEE80211_STA_MFP_ENABLED = BIT(6), IEEE80211_STA_UAPSD_ENABLED = BIT(7), @@ -800,7 +799,7 @@ ieee80211_get_sdata_band(struct ieee80211_sub_if_data *sdata) rcu_read_lock(); chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); if (!WARN_ON(!chanctx_conf)) - band = chanctx_conf->channel->band; + band = chanctx_conf->def.chan->band; rcu_read_unlock(); return band; @@ -1048,7 +1047,6 @@ struct ieee80211_local { /* Temporary remain-on-channel for off-channel operations */ struct ieee80211_channel *tmp_channel; - enum nl80211_channel_type tmp_channel_type; /* channel contexts */ struct list_head chanctx_list; @@ -1158,8 +1156,7 @@ struct ieee80211_local { /* virtual monitor interface */ struct ieee80211_sub_if_data __rcu *monitor_sdata; - struct ieee80211_channel *monitor_channel; - enum nl80211_channel_type monitor_channel_type; + struct cfg80211_chan_def monitor_chandef; }; static inline struct ieee80211_sub_if_data * @@ -1259,7 +1256,18 @@ static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr) is_broadcast_ether_addr(raddr); } +static inline bool +ieee80211_have_rx_timestamp(struct ieee80211_rx_status *status) +{ + WARN_ON_ONCE(status->flag & RX_FLAG_MACTIME_START && + status->flag & RX_FLAG_MACTIME_END); + return status->flag & (RX_FLAG_MACTIME_START | RX_FLAG_MACTIME_END); +} +u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local, + struct ieee80211_rx_status *status, + unsigned int mpdu_len, + unsigned int mpdu_offset); int ieee80211_hw_config(struct ieee80211_local *local, u32 changed); void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx); void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, @@ -1388,6 +1396,8 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev); netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev); +void ieee80211_purge_tx_queue(struct ieee80211_hw *hw, + struct sk_buff_head *skbs); /* HT */ void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, @@ -1505,7 +1515,7 @@ static inline void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata, } __ieee80211_tx_skb_tid_band(sdata, skb, tid, - chanctx_conf->channel->band); + chanctx_conf->def.chan->band); rcu_read_unlock(); } @@ -1594,8 +1604,7 @@ size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset); u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, u16 cap); u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, - struct ieee80211_channel *channel, - enum nl80211_channel_type channel_type, + const struct cfg80211_chan_def *chandef, u16 prot_mode); u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, u32 cap); @@ -1607,13 +1616,13 @@ int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata, enum ieee80211_band band); /* channel management */ -enum nl80211_channel_type -ieee80211_ht_oper_to_channel_type(struct ieee80211_ht_operation *ht_oper); +void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan, + struct ieee80211_ht_operation *ht_oper, + struct cfg80211_chan_def *chandef); int __must_check ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, - struct ieee80211_channel *channel, - enum nl80211_channel_type channel_type, + const struct cfg80211_chan_def *chandef, enum ieee80211_chanctx_mode mode); void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata); diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 80ce90b..5331662 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -54,7 +54,7 @@ bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata) return false; } - power = chanctx_conf->channel->max_power; + power = chanctx_conf->def.chan->max_power; rcu_read_unlock(); if (sdata->user_power_level != IEEE80211_UNSET_POWER_LEVEL) @@ -415,8 +415,7 @@ static int ieee80211_add_virtual_monitor(struct ieee80211_local *local) goto out_unlock; } - ret = ieee80211_vif_use_channel(sdata, local->monitor_channel, - local->monitor_channel_type, + ret = ieee80211_vif_use_channel(sdata, &local->monitor_chandef, IEEE80211_CHANCTX_EXCLUSIVE); if (ret) { drv_remove_interface(local, sdata); diff --git a/net/mac80211/key.c b/net/mac80211/key.c index d27e61a..619c5d6 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -339,7 +339,7 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, key->conf.iv_len = TKIP_IV_LEN; key->conf.icv_len = TKIP_ICV_LEN; if (seq) { - for (i = 0; i < NUM_RX_DATA_QUEUES; i++) { + for (i = 0; i < IEEE80211_NUM_TIDS; i++) { key->u.tkip.rx[i].iv32 = get_unaligned_le32(&seq[2]); key->u.tkip.rx[i].iv16 = @@ -352,7 +352,7 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, key->conf.iv_len = CCMP_HDR_LEN; key->conf.icv_len = CCMP_MIC_LEN; if (seq) { - for (i = 0; i < NUM_RX_DATA_QUEUES + 1; i++) + for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++) for (j = 0; j < CCMP_PN_LEN; j++) key->u.ccmp.rx_pn[i][j] = seq[CCMP_PN_LEN - j - 1]; @@ -372,8 +372,9 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, key->conf.iv_len = 0; key->conf.icv_len = sizeof(struct ieee80211_mmie); if (seq) - for (j = 0; j < 6; j++) - key->u.aes_cmac.rx_pn[j] = seq[6 - j - 1]; + for (j = 0; j < CMAC_PN_LEN; j++) + key->u.aes_cmac.rx_pn[j] = + seq[CMAC_PN_LEN - j - 1]; /* * Initialize AES key state here as an optimization so that * it does not need to be initialized for every packet. @@ -654,16 +655,16 @@ void ieee80211_get_key_rx_seq(struct ieee80211_key_conf *keyconf, switch (key->conf.cipher) { case WLAN_CIPHER_SUITE_TKIP: - if (WARN_ON(tid < 0 || tid >= NUM_RX_DATA_QUEUES)) + if (WARN_ON(tid < 0 || tid >= IEEE80211_NUM_TIDS)) return; seq->tkip.iv32 = key->u.tkip.rx[tid].iv32; seq->tkip.iv16 = key->u.tkip.rx[tid].iv16; break; case WLAN_CIPHER_SUITE_CCMP: - if (WARN_ON(tid < -1 || tid >= NUM_RX_DATA_QUEUES)) + if (WARN_ON(tid < -1 || tid >= IEEE80211_NUM_TIDS)) return; if (tid < 0) - pn = key->u.ccmp.rx_pn[NUM_RX_DATA_QUEUES]; + pn = key->u.ccmp.rx_pn[IEEE80211_NUM_TIDS]; else pn = key->u.ccmp.rx_pn[tid]; memcpy(seq->ccmp.pn, pn, CCMP_PN_LEN); diff --git a/net/mac80211/key.h b/net/mac80211/key.h index 7d4e31f..7cff0d3 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h @@ -30,8 +30,6 @@ #define TKIP_ICV_LEN 4 #define CMAC_PN_LEN 6 -#define NUM_RX_DATA_QUEUES 16 - struct ieee80211_local; struct ieee80211_sub_if_data; struct sta_info; @@ -82,17 +80,17 @@ struct ieee80211_key { struct tkip_ctx tx; /* last received RSC */ - struct tkip_ctx rx[NUM_RX_DATA_QUEUES]; + struct tkip_ctx rx[IEEE80211_NUM_TIDS]; } tkip; struct { atomic64_t tx_pn; /* * Last received packet number. The first - * NUM_RX_DATA_QUEUES counters are used with Data + * IEEE80211_NUM_TIDS counters are used with Data * frames and the last counter is used with Robust * Management frames. */ - u8 rx_pn[NUM_RX_DATA_QUEUES + 1][CCMP_PN_LEN]; + u8 rx_pn[IEEE80211_NUM_TIDS + 1][CCMP_PN_LEN]; struct crypto_cipher *tfm; u32 replays; /* dot11RSNAStatsCCMPReplays */ } ccmp; diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 70e8760..f5e4c1f 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -115,7 +115,7 @@ static u32 ieee80211_hw_conf_chan(struct ieee80211_local *local) channel_type = NL80211_CHAN_NO_HT; } else if (local->tmp_channel) { chan = local->tmp_channel; - channel_type = local->tmp_channel_type; + channel_type = NL80211_CHAN_NO_HT; } else { chan = local->_oper_channel; channel_type = local->_oper_channel_type; @@ -798,10 +798,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) local->_oper_channel = &sband->channels[0]; local->hw.conf.channel_type = NL80211_CHAN_NO_HT; } - if (!local->monitor_channel) { - local->monitor_channel = &sband->channels[0]; - local->monitor_channel_type = NL80211_CHAN_NO_HT; - } + cfg80211_chandef_create(&local->monitor_chandef, + &sband->channels[0], + NL80211_CHAN_NO_HT); channels += sband->n_channels; if (max_bitrates < sband->n_bitrates) @@ -884,10 +883,22 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) if (supp_ht) local->scan_ies_len += 2 + sizeof(struct ieee80211_ht_cap); - if (supp_vht) + if (supp_vht) { local->scan_ies_len += 2 + sizeof(struct ieee80211_vht_cap); + /* + * (for now at least), drivers wanting to use VHT must + * support channel contexts, as they contain all the + * necessary VHT information and the global hw config + * doesn't (yet) + */ + if (WARN_ON(!local->use_chanctx)) { + result = -EINVAL; + goto fail_wiphy_register; + } + } + if (!local->ops->hw_scan) { /* For hw_scan, driver needs to set these up. */ local->hw.wiphy->max_scan_ssids = 4; @@ -925,8 +936,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) local->hw.wiphy->cipher_suites, sizeof(u32) * local->hw.wiphy->n_cipher_suites, GFP_KERNEL); - if (!suites) - return -ENOMEM; + if (!suites) { + result = -ENOMEM; + goto fail_wiphy_register; + } for (r = 0; r < local->hw.wiphy->n_cipher_suites; r++) { u32 suite = local->hw.wiphy->cipher_suites[r]; if (suite == WLAN_CIPHER_SUITE_WEP40 || diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index a350cab..1bf03f9 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -76,7 +76,7 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata, struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct ieee80211_local *local = sdata->local; u32 basic_rates = 0; - enum nl80211_channel_type sta_channel_type = NL80211_CHAN_NO_HT; + struct cfg80211_chan_def sta_chan_def; /* * As support for each feature is added, check for matching @@ -103,17 +103,11 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata, if (sdata->vif.bss_conf.basic_rates != basic_rates) goto mismatch; - if (ie->ht_operation) - sta_channel_type = - ieee80211_ht_oper_to_channel_type(ie->ht_operation); - - /* Disallow HT40+/- mismatch */ - if (ie->ht_operation && - (sdata->vif.bss_conf.channel_type == NL80211_CHAN_HT40MINUS || - sdata->vif.bss_conf.channel_type == NL80211_CHAN_HT40PLUS) && - (sta_channel_type == NL80211_CHAN_HT40MINUS || - sta_channel_type == NL80211_CHAN_HT40PLUS) && - sdata->vif.bss_conf.channel_type != sta_channel_type) + ieee80211_ht_oper_to_chandef(sdata->vif.bss_conf.chandef.chan, + ie->ht_operation, &sta_chan_def); + + if (!cfg80211_chandef_compatible(&sdata->vif.bss_conf.chandef, + &sta_chan_def)) goto mismatch; return true; @@ -129,7 +123,7 @@ mismatch: bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie) { return (ie->mesh_config->meshconf_cap & - MESHCONF_CAPAB_ACCEPT_PLINKS) != 0; + IEEE80211_MESHCONF_CAPAB_ACCEPT_PLINKS) != 0; } /** @@ -269,11 +263,11 @@ mesh_add_meshconf_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) neighbors = (neighbors > 15) ? 15 : neighbors; *pos++ = neighbors << 1; /* Mesh capability */ - *pos = MESHCONF_CAPAB_FORWARDING; + *pos = IEEE80211_MESHCONF_CAPAB_FORWARDING; *pos |= ifmsh->accepting_plinks ? - MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00; + IEEE80211_MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00; *pos++ |= ifmsh->adjusting_tbtt ? - MESHCONF_CAPAB_TBTT_ADJUSTING : 0x00; + IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING : 0x00; *pos++ = 0x00; return 0; @@ -368,7 +362,7 @@ int mesh_add_ds_params_ie(struct sk_buff *skb, rcu_read_unlock(); return -EINVAL; } - chan = chanctx_conf->channel; + chan = chanctx_conf->def.chan; rcu_read_unlock(); sband = local->hw.wiphy->bands[chan->band]; @@ -392,7 +386,7 @@ int mesh_add_ht_cap_ie(struct sk_buff *skb, sband = local->hw.wiphy->bands[band]; if (!sband->ht_cap.ht_supported || - sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT) + sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT) return 0; if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_ht_cap)) @@ -411,7 +405,7 @@ int mesh_add_ht_oper_ie(struct sk_buff *skb, struct ieee80211_chanctx_conf *chanctx_conf; struct ieee80211_channel *channel; enum nl80211_channel_type channel_type = - sdata->vif.bss_conf.channel_type; + cfg80211_get_chandef_type(&sdata->vif.bss_conf.chandef); struct ieee80211_supported_band *sband; struct ieee80211_sta_ht_cap *ht_cap; u8 *pos; @@ -422,7 +416,7 @@ int mesh_add_ht_oper_ie(struct sk_buff *skb, rcu_read_unlock(); return -EINVAL; } - channel = chanctx_conf->channel; + channel = chanctx_conf->def.chan; rcu_read_unlock(); sband = local->hw.wiphy->bands[channel->band]; @@ -435,7 +429,7 @@ int mesh_add_ht_oper_ie(struct sk_buff *skb, return -ENOMEM; pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_operation)); - ieee80211_ie_build_ht_oper(pos, ht_cap, channel, channel_type, + ieee80211_ie_build_ht_oper(pos, ht_cap, &sdata->vif.bss_conf.chandef, sdata->vif.bss_conf.ht_operation_mode); return 0; diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 9285f3f..7c9215f 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -19,20 +19,6 @@ /* Data structures */ /** - * enum mesh_config_capab_flags - mesh config IE capability flags - * - * @MESHCONF_CAPAB_ACCEPT_PLINKS: STA is willing to establish - * additional mesh peerings with other mesh STAs - * @MESHCONF_CAPAB_FORWARDING: the STA forwards MSDUs - * @MESHCONF_CAPAB_TBTT_ADJUSTING: TBTT adjustment procedure is ongoing - */ -enum mesh_config_capab_flags { - MESHCONF_CAPAB_ACCEPT_PLINKS = BIT(0), - MESHCONF_CAPAB_FORWARDING = BIT(3), - MESHCONF_CAPAB_TBTT_ADJUSTING = BIT(5), -}; - -/** * enum mesh_path_flags - mac80211 mesh path flags * * diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 234fe75..ca52dfd 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -19,12 +19,6 @@ #define mod_plink_timer(s, t) (mod_timer(&s->plink_timer, \ jiffies + HZ * t / 1000)) -#define dot11MeshMaxRetries(s) (s->u.mesh.mshcfg.dot11MeshMaxRetries) -#define dot11MeshRetryTimeout(s) (s->u.mesh.mshcfg.dot11MeshRetryTimeout) -#define dot11MeshConfirmTimeout(s) (s->u.mesh.mshcfg.dot11MeshConfirmTimeout) -#define dot11MeshHoldingTimeout(s) (s->u.mesh.mshcfg.dot11MeshHoldingTimeout) -#define dot11MeshMaxPeerLinks(s) (s->u.mesh.mshcfg.dot11MeshMaxPeerLinks) - /* We only need a valid sta if user configured a minimum rssi_threshold. */ #define rssi_threshold_check(sta, sdata) \ (sdata->u.mesh.mshcfg.rssi_threshold == 0 ||\ @@ -117,7 +111,7 @@ static u32 mesh_set_ht_prot_mode(struct ieee80211_sub_if_data *sdata) u16 ht_opmode; bool non_ht_sta = false, ht20_sta = false; - if (sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT) + if (sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT) return 0; rcu_read_lock(); @@ -126,14 +120,14 @@ static u32 mesh_set_ht_prot_mode(struct ieee80211_sub_if_data *sdata) sta->plink_state != NL80211_PLINK_ESTAB) continue; - switch (sta->ch_type) { - case NL80211_CHAN_NO_HT: + switch (sta->ch_width) { + case NL80211_CHAN_WIDTH_20_NOHT: mpl_dbg(sdata, "mesh_plink %pM: nonHT sta (%pM) is present\n", sdata->vif.addr, sta->sta.addr); non_ht_sta = true; goto out; - case NL80211_CHAN_HT20: + case NL80211_CHAN_WIDTH_20: mpl_dbg(sdata, "mesh_plink %pM: HT20 sta (%pM) is present\n", sdata->vif.addr, sta->sta.addr); @@ -148,7 +142,7 @@ out: if (non_ht_sta) ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED; else if (ht20_sta && - sdata->vif.bss_conf.channel_type > NL80211_CHAN_HT20) + sdata->vif.bss_conf.chandef.width > NL80211_CHAN_WIDTH_20) ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_20MHZ; else ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONE; @@ -378,7 +372,7 @@ static struct sta_info *mesh_peer_init(struct ieee80211_sub_if_data *sdata, sta->sta.supp_rates[band] = rates; if (elems->ht_cap_elem && - sdata->vif.bss_conf.channel_type != NL80211_CHAN_NO_HT) + sdata->vif.bss_conf.chandef.width != NL80211_CHAN_WIDTH_20_NOHT) ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, elems->ht_cap_elem, &sta->sta.ht_cap); @@ -386,12 +380,15 @@ static struct sta_info *mesh_peer_init(struct ieee80211_sub_if_data *sdata, memset(&sta->sta.ht_cap, 0, sizeof(sta->sta.ht_cap)); if (elems->ht_operation) { + struct cfg80211_chan_def chandef; + if (!(elems->ht_operation->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) sta->sta.ht_cap.cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; - sta->ch_type = - ieee80211_ht_oper_to_channel_type(elems->ht_operation); + ieee80211_ht_oper_to_chandef(sdata->vif.bss_conf.chandef.chan, + elems->ht_operation, &chandef); + sta->ch_width = chandef.width; } rate_control_rate_init(sta); @@ -430,6 +427,7 @@ static void mesh_plink_timer(unsigned long data) struct sta_info *sta; __le16 llid, plid, reason; struct ieee80211_sub_if_data *sdata; + struct mesh_config *mshcfg; /* * This STA is valid because sta_info_destroy() will @@ -456,12 +454,13 @@ static void mesh_plink_timer(unsigned long data) llid = sta->llid; plid = sta->plid; sdata = sta->sdata; + mshcfg = &sdata->u.mesh.mshcfg; switch (sta->plink_state) { case NL80211_PLINK_OPN_RCVD: case NL80211_PLINK_OPN_SNT: /* retry timer */ - if (sta->plink_retries < dot11MeshMaxRetries(sdata)) { + if (sta->plink_retries < mshcfg->dot11MeshMaxRetries) { u32 rand; mpl_dbg(sta->sdata, "Mesh plink for %pM (retry, timeout): %d %d\n", @@ -484,7 +483,7 @@ static void mesh_plink_timer(unsigned long data) if (!reason) reason = cpu_to_le16(WLAN_REASON_MESH_CONFIRM_TIMEOUT); sta->plink_state = NL80211_PLINK_HOLDING; - mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); + mod_plink_timer(sta, mshcfg->dot11MeshHoldingTimeout); spin_unlock_bh(&sta->lock); mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE, sta->sta.addr, llid, plid, reason); @@ -543,7 +542,7 @@ int mesh_plink_open(struct sta_info *sta) return -EBUSY; } sta->plink_state = NL80211_PLINK_OPN_SNT; - mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata)); + mesh_plink_timer_set(sta, sdata->u.mesh.mshcfg.dot11MeshRetryTimeout); spin_unlock_bh(&sta->lock); mpl_dbg(sdata, "Mesh plink: starting establishment with %pM\n", @@ -570,6 +569,7 @@ void mesh_plink_block(struct sta_info *sta) void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, size_t len, struct ieee80211_rx_status *rx_status) { + struct mesh_config *mshcfg = &sdata->u.mesh.mshcfg; struct ieee802_11_elems elems; struct sta_info *sta; enum plink_event event; @@ -777,7 +777,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m sta->plid = plid; get_random_bytes(&llid, 2); sta->llid = llid; - mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata)); + mesh_plink_timer_set(sta, + mshcfg->dot11MeshRetryTimeout); spin_unlock_bh(&sta->lock); mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_OPEN, @@ -803,7 +804,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m sta->reason = reason; sta->plink_state = NL80211_PLINK_HOLDING; if (!mod_plink_timer(sta, - dot11MeshHoldingTimeout(sdata))) + mshcfg->dot11MeshHoldingTimeout)) sta->ignore_plink_timer = true; llid = sta->llid; @@ -825,7 +826,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m case CNF_ACPT: sta->plink_state = NL80211_PLINK_CNF_RCVD; if (!mod_plink_timer(sta, - dot11MeshConfirmTimeout(sdata))) + mshcfg->dot11MeshConfirmTimeout)) sta->ignore_plink_timer = true; spin_unlock_bh(&sta->lock); @@ -847,7 +848,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m sta->reason = reason; sta->plink_state = NL80211_PLINK_HOLDING; if (!mod_plink_timer(sta, - dot11MeshHoldingTimeout(sdata))) + mshcfg->dot11MeshHoldingTimeout)) sta->ignore_plink_timer = true; llid = sta->llid; @@ -888,7 +889,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m sta->reason = reason; sta->plink_state = NL80211_PLINK_HOLDING; if (!mod_plink_timer(sta, - dot11MeshHoldingTimeout(sdata))) + mshcfg->dot11MeshHoldingTimeout)) sta->ignore_plink_timer = true; llid = sta->llid; @@ -923,7 +924,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m changed |= __mesh_plink_deactivate(sta); sta->plink_state = NL80211_PLINK_HOLDING; llid = sta->llid; - mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); + mod_plink_timer(sta, mshcfg->dot11MeshHoldingTimeout); spin_unlock_bh(&sta->lock); changed |= mesh_set_ht_prot_mode(sdata); mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE, diff --git a/net/mac80211/mesh_sync.c b/net/mac80211/mesh_sync.c index 407c870..0f40086 100644 --- a/net/mac80211/mesh_sync.c +++ b/net/mac80211/mesh_sync.c @@ -43,7 +43,7 @@ struct sync_method { static bool mesh_peer_tbtt_adjusting(struct ieee802_11_elems *ie) { return (ie->mesh_config->meshconf_cap & - MESHCONF_CAPAB_TBTT_ADJUSTING) != 0; + IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING) != 0; } void mesh_sync_adjust_tbtt(struct ieee80211_sub_if_data *sdata) @@ -116,43 +116,13 @@ static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, goto no_sync; } - if (rx_status->flag & RX_FLAG_MACTIME_MPDU && rx_status->mactime) { - /* - * The mactime is defined as the time the first data symbol - * of the frame hits the PHY, and the timestamp of the beacon - * is defined as "the time that the data symbol containing the - * first bit of the timestamp is transmitted to the PHY plus - * the transmitting STA's delays through its local PHY from the - * MAC-PHY interface to its interface with the WM" (802.11 - * 11.1.2) - * - * T_r, in 13.13.2.2.2, is just defined as "the frame reception - * time" but we unless we interpret that time to be the same - * time of the beacon timestamp, the offset calculation will be - * off. Below we adjust t_r to be "the time at which the first - * symbol of the timestamp element in the beacon is received". - * This correction depends on the rate. - * - * Based on similar code in ibss.c - */ - int rate; - - if (rx_status->flag & RX_FLAG_HT) { - /* TODO: - * In principle there could be HT-beacons (Dual Beacon - * HT Operation options), but for now ignore them and - * just use the primary (i.e. non-HT) beacons for - * synchronization. - * */ - goto no_sync; - } else - rate = local->hw.wiphy->bands[rx_status->band]-> - bitrates[rx_status->rate_idx].bitrate; - - /* 24 bytes of header * 8 bits/byte * - * 10*(100 Kbps)/Mbps / rate (100 Kbps)*/ - t_r = rx_status->mactime + (24 * 8 * 10 / rate); - } + if (ieee80211_have_rx_timestamp(rx_status)) + /* time when timestamp field was received */ + t_r = ieee80211_calculate_rx_timestamp(local, rx_status, + 24 + 12 + + elems->total_len + + FCS_LEN, + 24); /* Timing offset calculation (see 13.13.2.2.2) */ t_t = le64_to_cpu(mgmt->u.beacon.timestamp); diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 6161446..d2a4f78 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -191,17 +191,19 @@ static u32 ieee80211_config_ht_tx(struct ieee80211_sub_if_data *sdata, rcu_read_unlock(); return 0; } - chan = chanctx_conf->channel; + chan = chanctx_conf->def.chan; rcu_read_unlock(); sband = local->hw.wiphy->bands[chan->band]; - switch (sdata->vif.bss_conf.channel_type) { - case NL80211_CHAN_HT40PLUS: - if (chan->flags & IEEE80211_CHAN_NO_HT40PLUS) + switch (sdata->vif.bss_conf.chandef.width) { + case NL80211_CHAN_WIDTH_40: + if (sdata->vif.bss_conf.chandef.chan->center_freq > + sdata->vif.bss_conf.chandef.center_freq1 && + chan->flags & IEEE80211_CHAN_NO_HT40PLUS) disable_40 = true; - break; - case NL80211_CHAN_HT40MINUS: - if (chan->flags & IEEE80211_CHAN_NO_HT40MINUS) + if (sdata->vif.bss_conf.chandef.chan->center_freq < + sdata->vif.bss_conf.chandef.center_freq1 && + chan->flags & IEEE80211_CHAN_NO_HT40MINUS) disable_40 = true; break; default: @@ -381,7 +383,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) rcu_read_unlock(); return; } - chan = chanctx_conf->channel; + chan = chanctx_conf->def.chan; rcu_read_unlock(); sband = local->hw.wiphy->bands[chan->band]; @@ -541,7 +543,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) offset = noffset; } - if (!(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) + if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) ieee80211_add_ht_ie(sdata, skb, assoc_data->ap_ht_param, sband, chan, sdata->smps_mode); @@ -1528,8 +1530,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, changed |= BSS_CHANGED_BSSID | BSS_CHANGED_HT; ieee80211_bss_info_change_notify(sdata, changed); - ieee80211_vif_release_channel(sdata); - /* disassociated - set to defaults now */ ieee80211_set_wmm_default(sdata, false); @@ -1539,6 +1539,9 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, del_timer_sync(&sdata->u.mgd.chswitch_timer); sdata->u.mgd.timers_running = 0; + + ifmgd->flags = 0; + ieee80211_vif_release_channel(sdata); } void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, @@ -1864,6 +1867,7 @@ static void ieee80211_destroy_auth_data(struct ieee80211_sub_if_data *sdata, memset(sdata->u.mgd.bssid, 0, ETH_ALEN); ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); + sdata->u.mgd.flags = 0; ieee80211_vif_release_channel(sdata); } @@ -2106,6 +2110,7 @@ static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata, memset(sdata->u.mgd.bssid, 0, ETH_ALEN); ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); + sdata->u.mgd.flags = 0; ieee80211_vif_release_channel(sdata); } @@ -2170,7 +2175,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, sband = local->hw.wiphy->bands[ieee80211_get_sdata_band(sdata)]; - if (elems.ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) + if (elems.ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, elems.ht_cap_elem, &sta->sta.ht_cap); @@ -2222,7 +2227,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, changed |= BSS_CHANGED_QOS; if (elems.ht_operation && elems.wmm_param && - !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) + !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) changed |= ieee80211_config_ht_tx(sdata, elems.ht_operation, cbss->bssid, false); @@ -2473,11 +2478,11 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, return; } - if (rx_status->freq != chanctx_conf->channel->center_freq) { + if (rx_status->freq != chanctx_conf->def.chan->center_freq) { rcu_read_unlock(); return; } - chan = chanctx_conf->channel; + chan = chanctx_conf->def.chan; rcu_read_unlock(); if (ifmgd->assoc_data && !ifmgd->assoc_data->have_beacon && @@ -2658,7 +2663,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, if (elems.ht_cap_elem && elems.ht_operation && elems.wmm_param && - !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) + !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) changed |= ieee80211_config_ht_tx(sdata, elems.ht_operation, bssid, true); @@ -3188,6 +3193,7 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, const u8 *ht_oper_ie; const struct ieee80211_ht_operation *ht_oper = NULL; struct ieee80211_supported_band *sband; + struct cfg80211_chan_def chandef; sband = local->hw.wiphy->bands[cbss->channel->band]; @@ -3219,12 +3225,10 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, ht_cfreq, ht_oper->primary_chan, cbss->channel->band); ht_oper = NULL; - } else { - channel_type = NL80211_CHAN_HT20; } } - if (ht_oper && sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) { + if (ht_oper) { /* * cfg80211 already verified that the channel itself can * be used, but it didn't check that we can do the right @@ -3237,19 +3241,26 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, channel_type = NL80211_CHAN_HT20; - switch (ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { - case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: - if (cbss->channel->flags & IEEE80211_CHAN_NO_HT40PLUS) - ifmgd->flags |= IEEE80211_STA_DISABLE_40MHZ; - else - channel_type = NL80211_CHAN_HT40PLUS; - break; - case IEEE80211_HT_PARAM_CHA_SEC_BELOW: - if (cbss->channel->flags & IEEE80211_CHAN_NO_HT40MINUS) - ifmgd->flags |= IEEE80211_STA_DISABLE_40MHZ; - else - channel_type = NL80211_CHAN_HT40MINUS; - break; + if (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) { + switch (ht_oper->ht_param & + IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { + case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: + if (cbss->channel->flags & + IEEE80211_CHAN_NO_HT40PLUS) + ifmgd->flags |= + IEEE80211_STA_DISABLE_40MHZ; + else + channel_type = NL80211_CHAN_HT40PLUS; + break; + case IEEE80211_HT_PARAM_CHA_SEC_BELOW: + if (cbss->channel->flags & + IEEE80211_CHAN_NO_HT40MINUS) + ifmgd->flags |= + IEEE80211_STA_DISABLE_40MHZ; + else + channel_type = NL80211_CHAN_HT40MINUS; + break; + } } ht_cap_ie = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, @@ -3262,13 +3273,15 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, sdata->needed_rx_chains = min(chains, local->rx_chains); } else { sdata->needed_rx_chains = 1; + sdata->u.mgd.flags |= IEEE80211_STA_DISABLE_HT; } /* will change later if needed */ sdata->smps_mode = IEEE80211_SMPS_OFF; ieee80211_vif_release_channel(sdata); - return ieee80211_vif_use_channel(sdata, cbss->channel, channel_type, + cfg80211_chandef_create(&chandef, cbss->channel, channel_type); + return ieee80211_vif_use_channel(sdata, &chandef, IEEE80211_CHANCTX_SHARED); } @@ -3530,13 +3543,6 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, /* prepare assoc data */ - /* - * keep only the 40 MHz disable bit set as it might have - * been set during authentication already, all other bits - * should be reset for a new connection - */ - ifmgd->flags &= IEEE80211_STA_DISABLE_40MHZ; - ifmgd->beacon_crc_valid = false; /* @@ -3550,7 +3556,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 || req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_TKIP || req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) { - ifmgd->flags |= IEEE80211_STA_DISABLE_11N; + ifmgd->flags |= IEEE80211_STA_DISABLE_HT; ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; netdev_info(sdata->dev, "disabling HT/VHT due to WEP/TKIP use\n"); @@ -3558,7 +3564,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, } if (req->flags & ASSOC_REQ_DISABLE_HT) { - ifmgd->flags |= IEEE80211_STA_DISABLE_11N; + ifmgd->flags |= IEEE80211_STA_DISABLE_HT; ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; } @@ -3566,7 +3572,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, sband = local->hw.wiphy->bands[req->bss->channel->band]; if (!sband->ht_cap.ht_supported || local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used) { - ifmgd->flags |= IEEE80211_STA_DISABLE_11N; + ifmgd->flags |= IEEE80211_STA_DISABLE_HT; if (!bss->wmm_used) netdev_info(sdata->dev, "disabling HT as WMM/QoS is not supported by the AP\n"); @@ -3611,7 +3617,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, assoc_data->ap_ht_param = ((struct ieee80211_ht_operation *)(ht_ie + 2))->ht_param; else - ifmgd->flags |= IEEE80211_STA_DISABLE_11N; + ifmgd->flags |= IEEE80211_STA_DISABLE_HT; if (bss->wmm_used && bss->uapsd_supported && (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)) { diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index 0cd42d5..5abddfe 100644 --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c @@ -205,8 +205,8 @@ void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc) } } else { cfg80211_ready_on_channel(&roc->sdata->wdev, roc->cookie, - roc->chan, roc->chan_type, - roc->req_duration, GFP_KERNEL); + roc->chan, roc->req_duration, + GFP_KERNEL); } roc->notified = true; @@ -283,8 +283,7 @@ void ieee80211_start_next_roc(struct ieee80211_local *local) if (!duration) duration = 10; - ret = drv_remain_on_channel(local, roc->chan, - roc->chan_type, + ret = drv_remain_on_channel(local, roc->sdata, roc->chan, duration); roc->started = true; @@ -321,7 +320,7 @@ void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc) if (!roc->mgmt_tx_cookie) cfg80211_remain_on_channel_expired(&roc->sdata->wdev, roc->cookie, roc->chan, - roc->chan_type, GFP_KERNEL); + GFP_KERNEL); list_for_each_entry_safe(dep, tmp, &roc->dependents, list) ieee80211_roc_notify_destroy(dep); @@ -359,7 +358,6 @@ void ieee80211_sw_roc_work(struct work_struct *work) ieee80211_recalc_idle(local); local->tmp_channel = roc->chan; - local->tmp_channel_type = roc->chan_type; ieee80211_hw_config(local, 0); /* tell userspace or send frame */ diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index 0f1c434..79a48f3 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c @@ -33,6 +33,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_sub_if_data *sdata; struct sta_info *sta; + struct ieee80211_chanctx *ctx; if (!local->open_count) goto suspend; @@ -139,14 +140,51 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) rcu_access_pointer(sdata->u.ap.beacon)) drv_stop_ap(local, sdata); - /* the interface is leaving the channel and is removed */ - ieee80211_vif_release_channel(sdata); + if (local->use_chanctx) { + struct ieee80211_chanctx_conf *conf; + + mutex_lock(&local->chanctx_mtx); + conf = rcu_dereference_protected( + sdata->vif.chanctx_conf, + lockdep_is_held(&local->chanctx_mtx)); + if (conf) { + ctx = container_of(conf, + struct ieee80211_chanctx, + conf); + drv_unassign_vif_chanctx(local, sdata, ctx); + } + + mutex_unlock(&local->chanctx_mtx); + } drv_remove_interface(local, sdata); } sdata = rtnl_dereference(local->monitor_sdata); - if (sdata) + if (sdata) { + if (local->use_chanctx) { + struct ieee80211_chanctx_conf *conf; + + mutex_lock(&local->chanctx_mtx); + conf = rcu_dereference_protected( + sdata->vif.chanctx_conf, + lockdep_is_held(&local->chanctx_mtx)); + if (conf) { + ctx = container_of(conf, + struct ieee80211_chanctx, + conf); + drv_unassign_vif_chanctx(local, sdata, ctx); + } + + mutex_unlock(&local->chanctx_mtx); + } + drv_remove_interface(local, sdata); + } + + mutex_lock(&local->chanctx_mtx); + list_for_each_entry(ctx, &local->chanctx_list, list) + drv_remove_chanctx(local, ctx); + mutex_unlock(&local->chanctx_mtx); /* stop hardware - this must stop RX */ if (local->open_count) diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index 3313c11..dd88381 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c @@ -391,7 +391,7 @@ static void rate_idx_match_mask(struct ieee80211_tx_rate *rate, return; /* if HT BSS, and we handle a data frame, also try HT rates */ - if (txrc->bss_conf->channel_type == NL80211_CHAN_NO_HT) + if (txrc->bss_conf->chandef.width == NL80211_CHAN_WIDTH_20_NOHT) return; fc = hdr->frame_control; @@ -408,8 +408,7 @@ static void rate_idx_match_mask(struct ieee80211_tx_rate *rate, alt_rate.flags |= IEEE80211_TX_RC_MCS; - if ((txrc->bss_conf->channel_type == NL80211_CHAN_HT40MINUS) || - (txrc->bss_conf->channel_type == NL80211_CHAN_HT40PLUS)) + if (txrc->bss_conf->chandef.width == NL80211_CHAN_WIDTH_40) alt_rate.flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; if (rate_idx_match_mcs_mask(&alt_rate, mcs_mask)) { diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h index ec198ef..301386d 100644 --- a/net/mac80211/rate.h +++ b/net/mac80211/rate.h @@ -65,7 +65,7 @@ static inline void rate_control_rate_init(struct sta_info *sta) return; } - sband = local->hw.wiphy->bands[chanctx_conf->channel->band]; + sband = local->hw.wiphy->bands[chanctx_conf->def.chan->band]; rcu_read_unlock(); ref->ops->rate_init(ref->priv, sband, ista, priv_sta); diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 6ad3303..825f33c 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -40,6 +40,8 @@ static struct sk_buff *remove_monitor_info(struct ieee80211_local *local, struct sk_buff *skb) { + struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); + if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) { if (likely(skb->len > FCS_LEN)) __pskb_trim(skb, skb->len - FCS_LEN); @@ -51,19 +53,25 @@ static struct sk_buff *remove_monitor_info(struct ieee80211_local *local, } } + if (status->vendor_radiotap_len) + __pskb_pull(skb, status->vendor_radiotap_len); + return skb; } static inline int should_drop_frame(struct sk_buff *skb, int present_fcs_len) { struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ieee80211_hdr *hdr; + + hdr = (void *)(skb->data + status->vendor_radiotap_len); if (status->flag & (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC | RX_FLAG_AMPDU_IS_ZEROLEN)) return 1; - if (unlikely(skb->len < 16 + present_fcs_len)) + if (unlikely(skb->len < 16 + present_fcs_len + + status->vendor_radiotap_len)) return 1; if (ieee80211_is_ctl(hdr->frame_control) && !ieee80211_is_pspoll(hdr->frame_control) && @@ -73,32 +81,48 @@ static inline int should_drop_frame(struct sk_buff *skb, int present_fcs_len) } static int -ieee80211_rx_radiotap_len(struct ieee80211_local *local, - struct ieee80211_rx_status *status) +ieee80211_rx_radiotap_space(struct ieee80211_local *local, + struct ieee80211_rx_status *status) { int len; /* always present fields */ len = sizeof(struct ieee80211_radiotap_header) + 9; - if (status->flag & RX_FLAG_MACTIME_MPDU) + /* allocate extra bitmap */ + if (status->vendor_radiotap_len) + len += 4; + + if (ieee80211_have_rx_timestamp(status)) { + len = ALIGN(len, 8); len += 8; + } if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) len += 1; - if (len & 1) /* padding for RX_FLAGS if necessary */ - len++; + /* padding for RX_FLAGS if necessary */ + len = ALIGN(len, 2); if (status->flag & RX_FLAG_HT) /* HT info */ len += 3; if (status->flag & RX_FLAG_AMPDU_DETAILS) { - /* padding */ - while (len & 3) - len++; + len = ALIGN(len, 4); len += 8; } + if (status->vendor_radiotap_len) { + if (WARN_ON_ONCE(status->vendor_radiotap_align == 0)) + status->vendor_radiotap_align = 1; + /* align standard part of vendor namespace */ + len = ALIGN(len, 2); + /* allocate standard part of vendor namespace */ + len += 6; + /* align vendor-defined part */ + len = ALIGN(len, status->vendor_radiotap_align); + /* vendor-defined part is already in skb */ + } + return len; } @@ -117,6 +141,11 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, struct ieee80211_radiotap_header *rthdr; unsigned char *pos; u16 rx_flags = 0; + int mpdulen; + + mpdulen = skb->len; + if (!(has_fcs && (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS))) + mpdulen += FCS_LEN; rthdr = (struct ieee80211_radiotap_header *)skb_push(skb, rtap_len); memset(rthdr, 0, rtap_len); @@ -127,15 +156,29 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, (1 << IEEE80211_RADIOTAP_CHANNEL) | (1 << IEEE80211_RADIOTAP_ANTENNA) | (1 << IEEE80211_RADIOTAP_RX_FLAGS)); - rthdr->it_len = cpu_to_le16(rtap_len); + rthdr->it_len = cpu_to_le16(rtap_len + status->vendor_radiotap_len); pos = (unsigned char *)(rthdr + 1); + if (status->vendor_radiotap_len) { + rthdr->it_present |= + cpu_to_le32(BIT(IEEE80211_RADIOTAP_VENDOR_NAMESPACE)) | + cpu_to_le32(BIT(IEEE80211_RADIOTAP_EXT)); + put_unaligned_le32(status->vendor_radiotap_bitmap, pos); + pos += 4; + } + /* the order of the following fields is important */ /* IEEE80211_RADIOTAP_TSFT */ - if (status->flag & RX_FLAG_MACTIME_MPDU) { - put_unaligned_le64(status->mactime, pos); + if (ieee80211_have_rx_timestamp(status)) { + /* padding */ + while ((pos - (u8 *)rthdr) & 7) + *pos++ = 0; + put_unaligned_le64( + ieee80211_calculate_rx_timestamp(local, status, + mpdulen, 0), + pos); rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_TSFT); pos += 8; } @@ -150,7 +193,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, pos++; /* IEEE80211_RADIOTAP_RATE */ - if (!rate || status->flag & RX_FLAG_HT) { + if (!rate || status->flag & (RX_FLAG_HT | RX_FLAG_VHT)) { /* * Without rate information don't add it. If we have, * MCS information is a separate field in radiotap, @@ -170,7 +213,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, if (status->band == IEEE80211_BAND_5GHZ) put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ, pos); - else if (status->flag & RX_FLAG_HT) + else if (status->flag & (RX_FLAG_HT | RX_FLAG_VHT)) put_unaligned_le16(IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ, pos); else if (rate && rate->flags & IEEE80211_RATE_ERP_G) @@ -203,7 +246,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, /* IEEE80211_RADIOTAP_RX_FLAGS */ /* ensure 2 byte alignment for the 2 byte field as required */ if ((pos - (u8 *)rthdr) & 1) - pos++; + *pos++ = 0; if (status->flag & RX_FLAG_FAILED_PLCP_CRC) rx_flags |= IEEE80211_RADIOTAP_F_RX_BADPLCP; put_unaligned_le16(rx_flags, pos); @@ -253,6 +296,21 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, *pos++ = 0; *pos++ = 0; } + + if (status->vendor_radiotap_len) { + /* ensure 2 byte alignment for the vendor field as required */ + if ((pos - (u8 *)rthdr) & 1) + *pos++ = 0; + *pos++ = status->vendor_radiotap_oui[0]; + *pos++ = status->vendor_radiotap_oui[1]; + *pos++ = status->vendor_radiotap_oui[2]; + *pos++ = status->vendor_radiotap_subns; + put_unaligned_le16(status->vendor_radiotap_len, pos); + pos += 2; + /* align the actual payload as requested */ + while ((pos - (u8 *)rthdr) & (status->vendor_radiotap_align - 1)) + *pos++ = 0; + } } /* @@ -281,13 +339,13 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, */ /* room for the radiotap header based on driver features */ - needed_headroom = ieee80211_rx_radiotap_len(local, status); + needed_headroom = ieee80211_rx_radiotap_space(local, status); if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) present_fcs_len = FCS_LEN; - /* make sure hdr->frame_control is on the linear part */ - if (!pskb_may_pull(origskb, 2)) { + /* ensure hdr->frame_control and vendor radiotap data are in skb head */ + if (!pskb_may_pull(origskb, 2 + status->vendor_radiotap_len)) { dev_kfree_skb(origskb); return NULL; } @@ -400,10 +458,10 @@ static void ieee80211_parse_qos(struct ieee80211_rx_data *rx) * * We also use that counter for non-QoS STAs. */ - seqno_idx = NUM_RX_DATA_QUEUES; + seqno_idx = IEEE80211_NUM_TIDS; security_idx = 0; if (ieee80211_is_mgmt(hdr->frame_control)) - security_idx = NUM_RX_DATA_QUEUES; + security_idx = IEEE80211_NUM_TIDS; tid = 0; } @@ -1283,17 +1341,22 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) /* * Update last_rx only for IBSS packets which are for the current - * BSSID to avoid keeping the current IBSS network alive in cases - * where other STAs start using different BSSID. + * BSSID and for station already AUTHORIZED to avoid keeping the + * current IBSS network alive in cases where other STAs start + * using different BSSID. This will also give the station another + * chance to restart the authentication/authorization in case + * something went wrong the first time. */ if (rx->sdata->vif.type == NL80211_IFTYPE_ADHOC) { u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len, NL80211_IFTYPE_ADHOC); - if (ether_addr_equal(bssid, rx->sdata->u.ibss.bssid)) { + if (ether_addr_equal(bssid, rx->sdata->u.ibss.bssid) && + test_sta_flag(sta, WLAN_STA_AUTHORIZED)) { sta->last_rx = jiffies; if (ieee80211_is_data(hdr->frame_control)) { sta->last_rx_rate_idx = status->rate_idx; sta->last_rx_rate_flag = status->flag; + sta->last_rx_rate_vht_nss = status->vht_nss; } } } else if (!is_multicast_ether_addr(hdr->addr1)) { @@ -1305,6 +1368,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) if (ieee80211_is_data(hdr->frame_control)) { sta->last_rx_rate_idx = status->rate_idx; sta->last_rx_rate_flag = status->flag; + sta->last_rx_rate_vht_nss = status->vht_nss; } } @@ -2585,7 +2649,7 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx, goto out_free_skb; /* room for the radiotap header based on driver features */ - needed_headroom = ieee80211_rx_radiotap_len(local, status); + needed_headroom = ieee80211_rx_radiotap_space(local, status); if (skb_headroom(skb) < needed_headroom && pskb_expand_head(skb, needed_headroom, 0, GFP_ATOMIC)) @@ -2648,7 +2712,8 @@ static void ieee80211_rx_handlers_result(struct ieee80211_rx_data *rx, status = IEEE80211_SKB_RXCB((rx->skb)); sband = rx->local->hw.wiphy->bands[status->band]; - if (!(status->flag & RX_FLAG_HT)) + if (!(status->flag & RX_FLAG_HT) && + !(status->flag & RX_FLAG_VHT)) rate = &sband->bitrates[status->rate_idx]; ieee80211_rx_cooked_monitor(rx, rate); @@ -2815,8 +2880,8 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx, status->rx_flags &= ~IEEE80211_RX_RA_MATCH; } else if (!rx->sta) { int rate_idx; - if (status->flag & RX_FLAG_HT) - rate_idx = 0; /* TODO: HT rates */ + if (status->flag & (RX_FLAG_HT | RX_FLAG_VHT)) + rate_idx = 0; /* TODO: HT/VHT rates */ else rate_idx = status->rate_idx; ieee80211_ibss_rx_no_sta(sdata, bssid, hdr->addr2, @@ -3092,6 +3157,13 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) status->rate_idx, status->rate_idx)) goto drop; + } else if (status->flag & RX_FLAG_VHT) { + if (WARN_ONCE(status->rate_idx > 9 || + !status->vht_nss || + status->vht_nss > 8, + "Rate marked as a VHT rate but data is invalid: MCS: %d, NSS: %d\n", + status->rate_idx, status->vht_nss)) + goto drop; } else { if (WARN_ON(status->rate_idx >= sband->n_bitrates)) goto drop; diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 13d2329..f334027 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -174,7 +174,6 @@ void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb) u8 *elements; struct ieee80211_channel *channel; size_t baselen; - int freq; bool beacon; struct ieee802_11_elems elems; @@ -209,13 +208,7 @@ void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb) ieee802_11_parse_elems(elements, skb->len - baselen, &elems); - if (elems.ds_params && elems.ds_params_len == 1) - freq = ieee80211_channel_to_frequency(elems.ds_params[0], - rx_status->band); - else - freq = rx_status->freq; - - channel = ieee80211_get_channel(local->hw.wiphy, freq); + channel = ieee80211_get_channel(local->hw.wiphy, rx_status->freq); if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) return; @@ -934,7 +927,7 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, struct cfg80211_sched_scan_request *req) { struct ieee80211_local *local = sdata->local; - struct ieee80211_sched_scan_ies sched_scan_ies; + struct ieee80211_sched_scan_ies sched_scan_ies = {}; int ret, i; mutex_lock(&local->mtx); diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index f7bb54f..f3e5025 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -122,8 +122,8 @@ static void free_sta_work(struct work_struct *wk) for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { local->total_ps_buffered -= skb_queue_len(&sta->ps_tx_buf[ac]); - __skb_queue_purge(&sta->ps_tx_buf[ac]); - __skb_queue_purge(&sta->tx_filtered[ac]); + ieee80211_purge_tx_queue(&local->hw, &sta->ps_tx_buf[ac]); + ieee80211_purge_tx_queue(&local->hw, &sta->tx_filtered[ac]); } #ifdef CONFIG_MAC80211_MESH @@ -142,11 +142,11 @@ static void free_sta_work(struct work_struct *wk) * drivers have to handle aggregation stop being requested, followed * directly by station destruction. */ - for (i = 0; i < STA_TID_NUM; i++) { + for (i = 0; i < IEEE80211_NUM_TIDS; i++) { tid_tx = rcu_dereference_raw(sta->ampdu_mlme.tid_tx[i]); if (!tid_tx) continue; - __skb_queue_purge(&tid_tx->pending); + ieee80211_purge_tx_queue(&local->hw, &tid_tx->pending); kfree(tid_tx); } @@ -330,7 +330,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, return NULL; } - for (i = 0; i < STA_TID_NUM; i++) { + for (i = 0; i < IEEE80211_NUM_TIDS; i++) { /* * timer_to_tid must be initialized with identity mapping * to enable session_timer's data differentiation. See @@ -343,7 +343,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, skb_queue_head_init(&sta->tx_filtered[i]); } - for (i = 0; i < NUM_RX_DATA_QUEUES; i++) + for (i = 0; i < IEEE80211_NUM_TIDS; i++) sta->last_seq_ctrl[i] = cpu_to_le16(USHRT_MAX); sta_dbg(sdata, "Allocated STA %pM\n", sta->sta.addr); @@ -982,10 +982,11 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) struct ieee80211_local *local = sdata->local; struct sk_buff_head pending; int filtered = 0, buffered = 0, ac; + unsigned long flags; clear_sta_flag(sta, WLAN_STA_SP); - BUILD_BUG_ON(BITS_TO_LONGS(STA_TID_NUM) > 1); + BUILD_BUG_ON(BITS_TO_LONGS(IEEE80211_NUM_TIDS) > 1); sta->driver_buffered_tids = 0; if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS)) @@ -997,12 +998,16 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { int count = skb_queue_len(&pending), tmp; + spin_lock_irqsave(&sta->tx_filtered[ac].lock, flags); skb_queue_splice_tail_init(&sta->tx_filtered[ac], &pending); + spin_unlock_irqrestore(&sta->tx_filtered[ac].lock, flags); tmp = skb_queue_len(&pending); filtered += tmp - count; count = tmp; + spin_lock_irqsave(&sta->ps_tx_buf[ac].lock, flags); skb_queue_splice_tail_init(&sta->ps_tx_buf[ac], &pending); + spin_unlock_irqrestore(&sta->ps_tx_buf[ac].lock, flags); tmp = skb_queue_len(&pending); buffered += tmp - count; } @@ -1087,7 +1092,7 @@ static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata, return; } - ieee80211_xmit(sdata, skb, chanctx_conf->channel->band); + ieee80211_xmit(sdata, skb, chanctx_conf->def.chan->band); rcu_read_unlock(); } @@ -1369,7 +1374,7 @@ void ieee80211_sta_set_buffered(struct ieee80211_sta *pubsta, { struct sta_info *sta = container_of(pubsta, struct sta_info, sta); - if (WARN_ON(tid >= STA_TID_NUM)) + if (WARN_ON(tid >= IEEE80211_NUM_TIDS)) return; if (buffered) diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index c88f161f..6835cea 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -80,7 +80,6 @@ enum ieee80211_sta_info_flags { WLAN_STA_TOFFSET_KNOWN, }; -#define STA_TID_NUM 16 #define ADDBA_RESP_INTERVAL HZ #define HT_AGG_MAX_RETRIES 15 #define HT_AGG_BURST_RETRIES 3 @@ -197,15 +196,15 @@ struct tid_ampdu_rx { struct sta_ampdu_mlme { struct mutex mtx; /* rx */ - struct tid_ampdu_rx __rcu *tid_rx[STA_TID_NUM]; - unsigned long tid_rx_timer_expired[BITS_TO_LONGS(STA_TID_NUM)]; - unsigned long tid_rx_stop_requested[BITS_TO_LONGS(STA_TID_NUM)]; + struct tid_ampdu_rx __rcu *tid_rx[IEEE80211_NUM_TIDS]; + unsigned long tid_rx_timer_expired[BITS_TO_LONGS(IEEE80211_NUM_TIDS)]; + unsigned long tid_rx_stop_requested[BITS_TO_LONGS(IEEE80211_NUM_TIDS)]; /* tx */ struct work_struct work; - struct tid_ampdu_tx __rcu *tid_tx[STA_TID_NUM]; - struct tid_ampdu_tx *tid_start_tx[STA_TID_NUM]; - unsigned long last_addba_req_time[STA_TID_NUM]; - u8 addba_req_num[STA_TID_NUM]; + struct tid_ampdu_tx __rcu *tid_tx[IEEE80211_NUM_TIDS]; + struct tid_ampdu_tx *tid_start_tx[IEEE80211_NUM_TIDS]; + unsigned long last_addba_req_time[IEEE80211_NUM_TIDS]; + u8 addba_req_num[IEEE80211_NUM_TIDS]; u8 dialog_token_allocator; }; @@ -228,6 +227,7 @@ struct sta_ampdu_mlme { * "the" transmit rate * @last_rx_rate_idx: rx status rate index of the last data packet * @last_rx_rate_flag: rx status flag of the last data packet + * @last_rx_rate_vht_nss: rx status nss of last data packet * @lock: used for locking all fields that require locking, see comments * in the header file. * @drv_unblock_wk: used for driver PS unblocking @@ -273,7 +273,7 @@ struct sta_ampdu_mlme { * @t_offset: timing offset relative to this host * @t_offset_setpoint: reference timing offset of this sta to be used when * calculating clockdrift - * @ch_type: peer's channel type + * @ch_width: peer's channel width * @debugfs: debug filesystem info * @dead: set to true when sta is unlinked * @uploaded: set to true when sta is uploaded to the driver @@ -330,7 +330,7 @@ struct sta_info { int last_signal; struct ewma avg_signal; /* Plus 1 for non-QoS frames */ - __le16 last_seq_ctrl[NUM_RX_DATA_QUEUES + 1]; + __le16 last_seq_ctrl[IEEE80211_NUM_TIDS + 1]; /* Updated from TX status path only, no locking requirements */ unsigned long tx_filtered_count; @@ -344,14 +344,15 @@ struct sta_info { unsigned long tx_fragments; struct ieee80211_tx_rate last_tx_rate; int last_rx_rate_idx; - int last_rx_rate_flag; + u32 last_rx_rate_flag; + u8 last_rx_rate_vht_nss; u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1]; /* * Aggregation information, locked with lock. */ struct sta_ampdu_mlme ampdu_mlme; - u8 timer_to_tid[STA_TID_NUM]; + u8 timer_to_tid[IEEE80211_NUM_TIDS]; #ifdef CONFIG_MAC80211_MESH /* @@ -369,7 +370,7 @@ struct sta_info { struct timer_list plink_timer; s64 t_offset; s64 t_offset_setpoint; - enum nl80211_channel_type ch_type; + enum nl80211_chan_width ch_width; #endif #ifdef CONFIG_MAC80211_DEBUGFS diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 2d931ad..ab63237 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -666,3 +666,12 @@ void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb) dev_kfree_skb_any(skb); } EXPORT_SYMBOL(ieee80211_free_txskb); + +void ieee80211_purge_tx_queue(struct ieee80211_hw *hw, + struct sk_buff_head *skbs) +{ + struct sk_buff *skb; + + while ((skb = __skb_dequeue(skbs))) + ieee80211_free_txskb(hw, skb); +} diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 758836c..a8270b4 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h @@ -28,16 +28,21 @@ #define VIF_PR_FMT " vif:%s(%d%s)" #define VIF_PR_ARG __get_str(vif_name), __entry->vif_type, __entry->p2p ? "/p2p" : "" -#define CHANCTX_ENTRY __field(int, freq) \ - __field(int, chantype) \ +#define CHANCTX_ENTRY __field(u32, control_freq) \ + __field(u32, chan_width) \ + __field(u32, center_freq1) \ + __field(u32, center_freq2) \ __field(u8, rx_chains_static) \ __field(u8, rx_chains_dynamic) -#define CHANCTX_ASSIGN __entry->freq = ctx->conf.channel->center_freq; \ - __entry->chantype = ctx->conf.channel_type; \ +#define CHANCTX_ASSIGN __entry->control_freq = ctx->conf.def.chan->center_freq;\ + __entry->chan_width = ctx->conf.def.width; \ + __entry->center_freq1 = ctx->conf.def.center_freq1; \ + __entry->center_freq2 = ctx->conf.def.center_freq2; \ __entry->rx_chains_static = ctx->conf.rx_chains_static; \ __entry->rx_chains_dynamic = ctx->conf.rx_chains_dynamic -#define CHANCTX_PR_FMT " freq:%d MHz chantype:%d chains:%d/%d" -#define CHANCTX_PR_ARG __entry->freq, __entry->chantype, \ +#define CHANCTX_PR_FMT " control:%d MHz width:%d center: %d/%d MHz chains:%d/%d" +#define CHANCTX_PR_ARG __entry->control_freq, __entry->chan_width, \ + __entry->center_freq1, __entry->center_freq2, \ __entry->rx_chains_static, __entry->rx_chains_dynamic @@ -334,7 +339,8 @@ TRACE_EVENT(drv_bss_info_changed, __field(u16, ht_operation_mode) __field(s32, cqm_rssi_thold); __field(s32, cqm_rssi_hyst); - __field(u32, channel_type); + __field(u32, channel_width); + __field(u32, channel_cfreq1); __dynamic_array(u32, arp_addr_list, info->arp_addr_cnt); __field(bool, arp_filter_enabled); __field(bool, qos); @@ -370,7 +376,8 @@ TRACE_EVENT(drv_bss_info_changed, __entry->ht_operation_mode = info->ht_operation_mode; __entry->cqm_rssi_thold = info->cqm_rssi_thold; __entry->cqm_rssi_hyst = info->cqm_rssi_hyst; - __entry->channel_type = info->channel_type; + __entry->channel_width = info->chandef.width; + __entry->channel_cfreq1 = info->chandef.center_freq1; memcpy(__get_dynamic_array(arp_addr_list), info->arp_addr_list, sizeof(u32) * info->arp_addr_cnt); __entry->arp_filter_enabled = info->arp_filter_enabled; @@ -1019,28 +1026,31 @@ TRACE_EVENT(drv_get_antenna, ); TRACE_EVENT(drv_remain_on_channel, - TP_PROTO(struct ieee80211_local *local, struct ieee80211_channel *chan, - enum nl80211_channel_type chantype, unsigned int duration), + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + struct ieee80211_channel *chan, + unsigned int duration), - TP_ARGS(local, chan, chantype, duration), + TP_ARGS(local, sdata, chan, duration), TP_STRUCT__entry( LOCAL_ENTRY + VIF_ENTRY __field(int, center_freq) - __field(int, channel_type) __field(unsigned int, duration) ), TP_fast_assign( LOCAL_ASSIGN; + VIF_ASSIGN; __entry->center_freq = chan->center_freq; - __entry->channel_type = chantype; __entry->duration = duration; ), TP_printk( - LOCAL_PR_FMT " freq:%dMHz duration:%dms", - LOCAL_PR_ARG, __entry->center_freq, __entry->duration + LOCAL_PR_FMT VIF_PR_FMT " freq:%dMHz duration:%dms", + LOCAL_PR_ARG, VIF_PR_ARG, + __entry->center_freq, __entry->duration ) ); diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index b546887..d287a4f 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1361,7 +1361,7 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx) if (tx->skb) ieee80211_free_txskb(&tx->local->hw, tx->skb); else - __skb_queue_purge(&tx->skbs); + ieee80211_purge_tx_queue(&tx->local->hw, &tx->skbs); return -1; } else if (unlikely(res == TX_QUEUED)) { I802_DEBUG_INC(tx->local->tx_handlers_queued); @@ -1676,7 +1676,7 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb, if (!chanctx_conf) goto fail_rcu; - chan = chanctx_conf->channel; + chan = chanctx_conf->def.chan; /* * Frame injection is not allowed if beaconing is not allowed @@ -1779,7 +1779,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, chanctx_conf = rcu_dereference(ap_sdata->vif.chanctx_conf); if (!chanctx_conf) goto fail_rcu; - band = chanctx_conf->channel->band; + band = chanctx_conf->def.chan->band; if (sta) break; /* fall through */ @@ -1794,7 +1794,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); if (!chanctx_conf) goto fail_rcu; - band = chanctx_conf->channel->band; + band = chanctx_conf->def.chan->band; break; case NL80211_IFTYPE_WDS: fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); @@ -1871,7 +1871,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); if (!chanctx_conf) goto fail_rcu; - band = chanctx_conf->channel->band; + band = chanctx_conf->def.chan->band; break; #endif case NL80211_IFTYPE_STATION: @@ -1930,7 +1930,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); if (!chanctx_conf) goto fail_rcu; - band = chanctx_conf->channel->band; + band = chanctx_conf->def.chan->band; break; case NL80211_IFTYPE_ADHOC: /* DA SA BSSID */ @@ -1941,7 +1941,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); if (!chanctx_conf) goto fail_rcu; - band = chanctx_conf->channel->band; + band = chanctx_conf->def.chan->band; break; default: goto fail_rcu; @@ -2161,10 +2161,13 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, */ void ieee80211_clear_tx_pending(struct ieee80211_local *local) { + struct sk_buff *skb; int i; - for (i = 0; i < local->hw.queues; i++) - skb_queue_purge(&local->pending[i]); + for (i = 0; i < local->hw.queues; i++) { + while ((skb = skb_dequeue(&local->pending[i])) != NULL) + ieee80211_free_txskb(&local->hw, skb); + } } /* @@ -2191,7 +2194,7 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local, return true; } result = ieee80211_tx(sdata, skb, true, - chanctx_conf->channel->band); + chanctx_conf->def.chan->band); } else { struct sk_buff_head skbs; @@ -2455,7 +2458,7 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, *pos++ = WLAN_EID_SSID; *pos++ = 0x0; - band = chanctx_conf->channel->band; + band = chanctx_conf->def.chan->band; if (ieee80211_add_srates_ie(sdata, skb, true, band) || mesh_add_ds_params_ie(skb, sdata) || @@ -2474,7 +2477,7 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, goto out; } - band = chanctx_conf->channel->band; + band = chanctx_conf->def.chan->band; info = IEEE80211_SKB_CB(skb); @@ -2754,7 +2757,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, info = IEEE80211_SKB_CB(skb); tx.flags |= IEEE80211_TX_PS_BUFFERED; - info->band = chanctx_conf->channel->band; + info->band = chanctx_conf->def.chan->band; if (invoke_tx_handlers(&tx)) skb = NULL; diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 4e4f585..08132ff 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -898,7 +898,7 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, rcu_read_lock(); chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); use_11b = (chanctx_conf && - chanctx_conf->channel->band == IEEE80211_BAND_2GHZ) && + chanctx_conf->def.chan->band == IEEE80211_BAND_2GHZ) && !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE); rcu_read_unlock(); @@ -991,7 +991,7 @@ void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); if (chanctx_conf && - chanctx_conf->channel->band == IEEE80211_BAND_2GHZ && + chanctx_conf->def.chan->band == IEEE80211_BAND_2GHZ && have_higher_than_11mbit) sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; else @@ -1417,10 +1417,12 @@ int ieee80211_reconfig(struct ieee80211_local *local) } /* add channel contexts */ - mutex_lock(&local->chanctx_mtx); - list_for_each_entry(ctx, &local->chanctx_list, list) - WARN_ON(drv_add_chanctx(local, ctx)); - mutex_unlock(&local->chanctx_mtx); + if (local->use_chanctx) { + mutex_lock(&local->chanctx_mtx); + list_for_each_entry(ctx, &local->chanctx_list, list) + WARN_ON(drv_add_chanctx(local, ctx)); + mutex_unlock(&local->chanctx_mtx); + } list_for_each_entry(sdata, &local->interfaces, list) { struct ieee80211_chanctx_conf *ctx_conf; @@ -1439,6 +1441,21 @@ int ieee80211_reconfig(struct ieee80211_local *local) mutex_unlock(&local->chanctx_mtx); } + sdata = rtnl_dereference(local->monitor_sdata); + if (sdata && local->use_chanctx && ieee80211_sdata_running(sdata)) { + struct ieee80211_chanctx_conf *ctx_conf; + + mutex_lock(&local->chanctx_mtx); + ctx_conf = rcu_dereference_protected(sdata->vif.chanctx_conf, + lockdep_is_held(&local->chanctx_mtx)); + if (ctx_conf) { + ctx = container_of(ctx_conf, struct ieee80211_chanctx, + conf); + drv_assign_vif_chanctx(local, sdata, ctx); + } + mutex_unlock(&local->chanctx_mtx); + } + /* add STAs back */ mutex_lock(&local->sta_mtx); list_for_each_entry(sta, &local->sta_list, list) { @@ -1555,6 +1572,8 @@ int ieee80211_reconfig(struct ieee80211_local *local) list_for_each_entry(sdata, &local->interfaces, list) { if (sdata->vif.type != NL80211_IFTYPE_STATION) continue; + if (!sdata->u.mgd.associated) + continue; ieee80211_send_nullfunc(local, sdata, 0); } @@ -1854,8 +1873,7 @@ u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, } u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, - struct ieee80211_channel *channel, - enum nl80211_channel_type channel_type, + const struct cfg80211_chan_def *chandef, u16 prot_mode) { struct ieee80211_ht_operation *ht_oper; @@ -1863,23 +1881,25 @@ u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, *pos++ = WLAN_EID_HT_OPERATION; *pos++ = sizeof(struct ieee80211_ht_operation); ht_oper = (struct ieee80211_ht_operation *)pos; - ht_oper->primary_chan = - ieee80211_frequency_to_channel(channel->center_freq); - switch (channel_type) { - case NL80211_CHAN_HT40MINUS: - ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_BELOW; - break; - case NL80211_CHAN_HT40PLUS: - ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_ABOVE; + ht_oper->primary_chan = ieee80211_frequency_to_channel( + chandef->chan->center_freq); + switch (chandef->width) { + case NL80211_CHAN_WIDTH_160: + case NL80211_CHAN_WIDTH_80P80: + case NL80211_CHAN_WIDTH_80: + case NL80211_CHAN_WIDTH_40: + if (chandef->center_freq1 > chandef->chan->center_freq) + ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_ABOVE; + else + ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_BELOW; break; - case NL80211_CHAN_HT20: default: ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_NONE; break; } if (ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 && - channel_type != NL80211_CHAN_NO_HT && - channel_type != NL80211_CHAN_HT20) + chandef->width != NL80211_CHAN_WIDTH_20_NOHT && + chandef->width != NL80211_CHAN_WIDTH_20) ht_oper->ht_param |= IEEE80211_HT_PARAM_CHAN_WIDTH_ANY; ht_oper->operation_mode = cpu_to_le16(prot_mode); @@ -1893,13 +1913,17 @@ u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, return pos + sizeof(struct ieee80211_ht_operation); } -enum nl80211_channel_type -ieee80211_ht_oper_to_channel_type(struct ieee80211_ht_operation *ht_oper) +void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan, + struct ieee80211_ht_operation *ht_oper, + struct cfg80211_chan_def *chandef) { enum nl80211_channel_type channel_type; - if (!ht_oper) - return NL80211_CHAN_NO_HT; + if (!ht_oper) { + cfg80211_chandef_create(chandef, control_chan, + NL80211_CHAN_NO_HT); + return; + } switch (ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { case IEEE80211_HT_PARAM_CHA_SEC_NONE: @@ -1915,7 +1939,7 @@ ieee80211_ht_oper_to_channel_type(struct ieee80211_ht_operation *ht_oper) channel_type = NL80211_CHAN_NO_HT; } - return channel_type; + cfg80211_chandef_create(chandef, control_chan, channel_type); } int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata, @@ -2013,3 +2037,68 @@ u8 ieee80211_mcs_to_chains(const struct ieee80211_mcs_info *mcs) return 2; return 1; } + +/** + * ieee80211_calculate_rx_timestamp - calculate timestamp in frame + * @local: mac80211 hw info struct + * @status: RX status + * @mpdu_len: total MPDU length (including FCS) + * @mpdu_offset: offset into MPDU to calculate timestamp at + * + * This function calculates the RX timestamp at the given MPDU offset, taking + * into account what the RX timestamp was. An offset of 0 will just normalize + * the timestamp to TSF at beginning of MPDU reception. + */ +u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local, + struct ieee80211_rx_status *status, + unsigned int mpdu_len, + unsigned int mpdu_offset) +{ + u64 ts = status->mactime; + struct rate_info ri; + u16 rate; + + if (WARN_ON(!ieee80211_have_rx_timestamp(status))) + return 0; + + memset(&ri, 0, sizeof(ri)); + + /* Fill cfg80211 rate info */ + if (status->flag & RX_FLAG_HT) { + ri.mcs = status->rate_idx; + ri.flags |= RATE_INFO_FLAGS_MCS; + if (status->flag & RX_FLAG_40MHZ) + ri.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; + if (status->flag & RX_FLAG_SHORT_GI) + ri.flags |= RATE_INFO_FLAGS_SHORT_GI; + } else if (status->flag & RX_FLAG_VHT) { + ri.flags |= RATE_INFO_FLAGS_VHT_MCS; + ri.mcs = status->rate_idx; + ri.nss = status->vht_nss; + if (status->flag & RX_FLAG_40MHZ) + ri.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; + if (status->flag & RX_FLAG_80MHZ) + ri.flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH; + if (status->flag & RX_FLAG_80P80MHZ) + ri.flags |= RATE_INFO_FLAGS_80P80_MHZ_WIDTH; + if (status->flag & RX_FLAG_160MHZ) + ri.flags |= RATE_INFO_FLAGS_160_MHZ_WIDTH; + if (status->flag & RX_FLAG_SHORT_GI) + ri.flags |= RATE_INFO_FLAGS_SHORT_GI; + } else { + struct ieee80211_supported_band *sband; + + sband = local->hw.wiphy->bands[status->band]; + ri.legacy = sband->bitrates[status->rate_idx].bitrate; + } + + rate = cfg80211_calculate_bitrate(&ri); + + /* rewind from end of MPDU */ + if (status->flag & RX_FLAG_MACTIME_END) + ts -= mpdu_len * 8 * 10 / rate; + + ts += mpdu_offset * 8 * 10 / rate; + + return ts; +} diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index cea06e9..906f00c 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c @@ -160,31 +160,37 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, return ieee80211_downgrade_queue(sdata, skb); } +/** + * ieee80211_set_qos_hdr - Fill in the QoS header if there is one. + * + * @sdata: local subif + * @skb: packet to be updated + */ void ieee80211_set_qos_hdr(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) { struct ieee80211_hdr *hdr = (void *)skb->data; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + u8 *p; + u8 ack_policy, tid; - /* Fill in the QoS header if there is one. */ - if (ieee80211_is_data_qos(hdr->frame_control)) { - u8 *p = ieee80211_get_qos_ctl(hdr); - u8 ack_policy, tid; - - tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK; + if (!ieee80211_is_data_qos(hdr->frame_control)) + return; - /* preserve EOSP bit */ - ack_policy = *p & IEEE80211_QOS_CTL_EOSP; + p = ieee80211_get_qos_ctl(hdr); + tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK; - if (is_multicast_ether_addr(hdr->addr1) || - sdata->noack_map & BIT(tid)) { - ack_policy |= IEEE80211_QOS_CTL_ACK_POLICY_NOACK; - info->flags |= IEEE80211_TX_CTL_NO_ACK; - } + /* preserve EOSP bit */ + ack_policy = *p & IEEE80211_QOS_CTL_EOSP; - /* qos header is 2 bytes */ - *p++ = ack_policy | tid; - *p = ieee80211_vif_is_mesh(&sdata->vif) ? - (IEEE80211_QOS_CTL_MESH_CONTROL_PRESENT >> 8) : 0; + if (is_multicast_ether_addr(hdr->addr1) || + sdata->noack_map & BIT(tid)) { + ack_policy |= IEEE80211_QOS_CTL_ACK_POLICY_NOACK; + info->flags |= IEEE80211_TX_CTL_NO_ACK; } + + /* qos header is 2 bytes */ + *p++ = ack_policy | tid; + *p = ieee80211_vif_is_mesh(&sdata->vif) ? + (IEEE80211_QOS_CTL_MESH_CONTROL_PRESENT >> 8) : 0; } diff --git a/net/nfc/hci/command.c b/net/nfc/hci/command.c index 07659cf..7d99410 100644 --- a/net/nfc/hci/command.c +++ b/net/nfc/hci/command.c @@ -344,7 +344,7 @@ int nfc_hci_connect_gate(struct nfc_hci_dev *hdev, u8 dest_host, u8 dest_gate, return -EADDRINUSE; if (pipe != NFC_HCI_INVALID_PIPE) - goto pipe_is_open; + goto open_pipe; switch (dest_gate) { case NFC_HCI_LINK_MGMT_GATE: @@ -361,6 +361,7 @@ int nfc_hci_connect_gate(struct nfc_hci_dev *hdev, u8 dest_host, u8 dest_gate, break; } +open_pipe: r = nfc_hci_open_pipe(hdev, pipe); if (r < 0) { if (pipe_created) @@ -371,7 +372,6 @@ int nfc_hci_connect_gate(struct nfc_hci_dev *hdev, u8 dest_host, u8 dest_gate, return r; } -pipe_is_open: hdev->gate2pipe[dest_gate] = pipe; return 0; diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c index bc571b0..7bea574 100644 --- a/net/nfc/hci/core.c +++ b/net/nfc/hci/core.c @@ -33,17 +33,20 @@ /* Largest headroom needed for outgoing HCI commands */ #define HCI_CMDS_HEADROOM 1 -static int nfc_hci_result_to_errno(u8 result) +int nfc_hci_result_to_errno(u8 result) { switch (result) { case NFC_HCI_ANY_OK: return 0; + case NFC_HCI_ANY_E_REG_PAR_UNKNOWN: + return -EOPNOTSUPP; case NFC_HCI_ANY_E_TIMEOUT: return -ETIME; default: return -1; } } +EXPORT_SYMBOL(nfc_hci_result_to_errno); static void nfc_hci_msg_tx_work(struct work_struct *work) { @@ -167,7 +170,7 @@ void nfc_hci_cmd_received(struct nfc_hci_dev *hdev, u8 pipe, u8 cmd, kfree_skb(skb); } -static u32 nfc_hci_sak_to_protocol(u8 sak) +u32 nfc_hci_sak_to_protocol(u8 sak) { switch (NFC_HCI_TYPE_A_SEL_PROT(sak)) { case NFC_HCI_TYPE_A_SEL_PROT_MIFARE: @@ -182,6 +185,7 @@ static u32 nfc_hci_sak_to_protocol(u8 sak) return 0xffffffff; } } +EXPORT_SYMBOL(nfc_hci_sak_to_protocol); int nfc_hci_target_discovered(struct nfc_hci_dev *hdev, u8 gate) { @@ -284,6 +288,12 @@ void nfc_hci_event_received(struct nfc_hci_dev *hdev, u8 pipe, u8 event, struct sk_buff *skb) { int r = 0; + u8 gate = nfc_hci_pipe2gate(hdev, pipe); + + if (gate == 0xff) { + pr_err("Discarded event %x to unopened pipe %x\n", event, pipe); + goto exit; + } switch (event) { case NFC_HCI_EVT_TARGET_DISCOVERED: @@ -307,14 +317,11 @@ void nfc_hci_event_received(struct nfc_hci_dev *hdev, u8 pipe, u8 event, goto exit; } - r = nfc_hci_target_discovered(hdev, - nfc_hci_pipe2gate(hdev, pipe)); + r = nfc_hci_target_discovered(hdev, gate); break; default: if (hdev->ops->event_received) { - hdev->ops->event_received(hdev, - nfc_hci_pipe2gate(hdev, pipe), - event, skb); + hdev->ops->event_received(hdev, gate, event, skb); return; } @@ -419,6 +426,10 @@ static int hci_dev_version(struct nfc_hci_dev *hdev) r = nfc_hci_get_param(hdev, NFC_HCI_ID_MGMT_GATE, NFC_HCI_ID_MGMT_VERSION_SW, &skb); + if (r == -EOPNOTSUPP) { + pr_info("Software/Hardware info not available\n"); + return 0; + } if (r < 0) return r; diff --git a/net/nfc/llcp/commands.c b/net/nfc/llcp/commands.c index ed2d173..df24be4 100644 --- a/net/nfc/llcp/commands.c +++ b/net/nfc/llcp/commands.c @@ -528,6 +528,23 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock, if (local == NULL) return -ENODEV; + /* Remote is ready but has not acknowledged our frames */ + if((sock->remote_ready && + skb_queue_len(&sock->tx_pending_queue) >= sock->rw && + skb_queue_len(&sock->tx_queue) >= 2 * sock->rw)) { + pr_err("Pending queue is full %d frames\n", + skb_queue_len(&sock->tx_pending_queue)); + return -ENOBUFS; + } + + /* Remote is not ready and we've been queueing enough frames */ + if ((!sock->remote_ready && + skb_queue_len(&sock->tx_queue) >= 2 * sock->rw)) { + pr_err("Tx queue is full %d frames\n", + skb_queue_len(&sock->tx_queue)); + return -ENOBUFS; + } + msg_data = kzalloc(len, GFP_KERNEL); if (msg_data == NULL) return -ENOMEM; @@ -579,7 +596,7 @@ int nfc_llcp_send_ui_frame(struct nfc_llcp_sock *sock, u8 ssap, u8 dsap, struct sk_buff *pdu; struct nfc_llcp_local *local; size_t frag_len = 0, remaining_len; - u8 *msg_ptr; + u8 *msg_ptr, *msg_data; int err; pr_debug("Send UI frame len %zd\n", len); @@ -588,8 +605,17 @@ int nfc_llcp_send_ui_frame(struct nfc_llcp_sock *sock, u8 ssap, u8 dsap, if (local == NULL) return -ENODEV; + msg_data = kzalloc(len, GFP_KERNEL); + if (msg_data == NULL) + return -ENOMEM; + + if (memcpy_fromiovec(msg_data, msg->msg_iov, len)) { + kfree(msg_data); + return -EFAULT; + } + remaining_len = len; - msg_ptr = (u8 *) msg->msg_iov; + msg_ptr = msg_data; while (remaining_len > 0) { @@ -616,6 +642,8 @@ int nfc_llcp_send_ui_frame(struct nfc_llcp_sock *sock, u8 ssap, u8 dsap, msg_ptr += frag_len; } + kfree(msg_data); + return len; } diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c index f680453..2df8705 100644 --- a/net/nfc/llcp/llcp.c +++ b/net/nfc/llcp/llcp.c @@ -656,6 +656,8 @@ static void nfc_llcp_tx_work(struct work_struct *work) if (llcp_sock == NULL && nfc_llcp_ptype(skb) == LLCP_PDU_I) { nfc_llcp_send_symm(local->dev); } else { + struct sk_buff *copy_skb = NULL; + u8 ptype = nfc_llcp_ptype(skb); int ret; pr_debug("Sending pending skb\n"); @@ -663,22 +665,29 @@ static void nfc_llcp_tx_work(struct work_struct *work) DUMP_PREFIX_OFFSET, 16, 1, skb->data, skb->len, true); + if (ptype == LLCP_PDU_I) + copy_skb = skb_copy(skb, GFP_ATOMIC); + nfc_llcp_send_to_raw_sock(local, skb, NFC_LLCP_DIRECTION_TX); ret = nfc_data_exchange(local->dev, local->target_idx, skb, nfc_llcp_recv, local); - if (!ret && nfc_llcp_ptype(skb) == LLCP_PDU_I) { - skb = skb_get(skb); - skb_queue_tail(&llcp_sock->tx_pending_queue, - skb); + if (ret) { + kfree_skb(copy_skb); + goto out; } + + if (ptype == LLCP_PDU_I && copy_skb) + skb_queue_tail(&llcp_sock->tx_pending_queue, + copy_skb); } } else { nfc_llcp_send_symm(local->dev); } +out: mod_timer(&local->link_timer, jiffies + msecs_to_jiffies(2 * local->remote_lto)); } @@ -1388,7 +1397,7 @@ int nfc_llcp_register_device(struct nfc_dev *ndev) local->remote_miu = LLCP_DEFAULT_MIU; local->remote_lto = LLCP_DEFAULT_LTO; - list_add(&llcp_devices, &local->list); + list_add(&local->list, &llcp_devices); return 0; } diff --git a/net/wireless/chan.c b/net/wireless/chan.c index 48febd2..bf2dfd5 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c @@ -11,96 +11,264 @@ #include "core.h" #include "rdev-ops.h" -struct ieee80211_channel * -rdev_freq_to_chan(struct cfg80211_registered_device *rdev, - int freq, enum nl80211_channel_type channel_type) +void cfg80211_chandef_create(struct cfg80211_chan_def *chandef, + struct ieee80211_channel *chan, + enum nl80211_channel_type chan_type) { - struct ieee80211_channel *chan; - struct ieee80211_sta_ht_cap *ht_cap; + if (WARN_ON(!chan)) + return; - chan = ieee80211_get_channel(&rdev->wiphy, freq); + chandef->chan = chan; + chandef->center_freq2 = 0; - /* Primary channel not allowed */ - if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) - return NULL; + switch (chan_type) { + case NL80211_CHAN_NO_HT: + chandef->width = NL80211_CHAN_WIDTH_20_NOHT; + chandef->center_freq1 = chan->center_freq; + break; + case NL80211_CHAN_HT20: + chandef->width = NL80211_CHAN_WIDTH_20; + chandef->center_freq1 = chan->center_freq; + break; + case NL80211_CHAN_HT40PLUS: + chandef->width = NL80211_CHAN_WIDTH_40; + chandef->center_freq1 = chan->center_freq + 10; + break; + case NL80211_CHAN_HT40MINUS: + chandef->width = NL80211_CHAN_WIDTH_40; + chandef->center_freq1 = chan->center_freq - 10; + break; + default: + WARN_ON(1); + } +} +EXPORT_SYMBOL(cfg80211_chandef_create); - if (channel_type == NL80211_CHAN_HT40MINUS && - chan->flags & IEEE80211_CHAN_NO_HT40MINUS) - return NULL; - else if (channel_type == NL80211_CHAN_HT40PLUS && - chan->flags & IEEE80211_CHAN_NO_HT40PLUS) - return NULL; +bool cfg80211_chan_def_valid(const struct cfg80211_chan_def *chandef) +{ + u32 control_freq; - ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap; + if (!chandef->chan) + return false; - if (channel_type != NL80211_CHAN_NO_HT) { - if (!ht_cap->ht_supported) - return NULL; + control_freq = chandef->chan->center_freq; - if (channel_type != NL80211_CHAN_HT20 && - (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) || - ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT)) - return NULL; + switch (chandef->width) { + case NL80211_CHAN_WIDTH_20: + case NL80211_CHAN_WIDTH_20_NOHT: + if (chandef->center_freq1 != control_freq) + return false; + if (chandef->center_freq2) + return false; + break; + case NL80211_CHAN_WIDTH_40: + if (chandef->center_freq1 != control_freq + 10 && + chandef->center_freq1 != control_freq - 10) + return false; + if (chandef->center_freq2) + return false; + break; + case NL80211_CHAN_WIDTH_80P80: + if (chandef->center_freq1 != control_freq + 30 && + chandef->center_freq1 != control_freq + 10 && + chandef->center_freq1 != control_freq - 10 && + chandef->center_freq1 != control_freq - 30) + return false; + if (!chandef->center_freq2) + return false; + break; + case NL80211_CHAN_WIDTH_80: + if (chandef->center_freq1 != control_freq + 30 && + chandef->center_freq1 != control_freq + 10 && + chandef->center_freq1 != control_freq - 10 && + chandef->center_freq1 != control_freq - 30) + return false; + if (chandef->center_freq2) + return false; + break; + case NL80211_CHAN_WIDTH_160: + if (chandef->center_freq1 != control_freq + 70 && + chandef->center_freq1 != control_freq + 50 && + chandef->center_freq1 != control_freq + 30 && + chandef->center_freq1 != control_freq + 10 && + chandef->center_freq1 != control_freq - 10 && + chandef->center_freq1 != control_freq - 30 && + chandef->center_freq1 != control_freq - 50 && + chandef->center_freq1 != control_freq - 70) + return false; + if (chandef->center_freq2) + return false; + break; + default: + return false; } - return chan; + return true; } -bool cfg80211_can_beacon_sec_chan(struct wiphy *wiphy, - struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type) +static void chandef_primary_freqs(const struct cfg80211_chan_def *c, + int *pri40, int *pri80) { - struct ieee80211_channel *sec_chan; - int diff; - - trace_cfg80211_can_beacon_sec_chan(wiphy, chan, channel_type); + int tmp; - switch (channel_type) { - case NL80211_CHAN_HT40PLUS: - diff = 20; + switch (c->width) { + case NL80211_CHAN_WIDTH_40: + *pri40 = c->center_freq1; + *pri80 = 0; break; - case NL80211_CHAN_HT40MINUS: - diff = -20; + case NL80211_CHAN_WIDTH_80: + case NL80211_CHAN_WIDTH_80P80: + *pri80 = c->center_freq1; + /* n_P20 */ + tmp = (30 + c->chan->center_freq - c->center_freq1)/20; + /* n_P40 */ + tmp /= 2; + /* freq_P40 */ + *pri40 = c->center_freq1 - 20 + 40 * tmp; + break; + case NL80211_CHAN_WIDTH_160: + /* n_P20 */ + tmp = (70 + c->chan->center_freq - c->center_freq1)/20; + /* n_P40 */ + tmp /= 2; + /* freq_P40 */ + *pri40 = c->center_freq1 - 60 + 40 * tmp; + /* n_P80 */ + tmp /= 2; + *pri80 = c->center_freq1 - 40 + 80 * tmp; break; default: - trace_cfg80211_return_bool(true); - return true; + WARN_ON_ONCE(1); } +} + +const struct cfg80211_chan_def * +cfg80211_chandef_compatible(const struct cfg80211_chan_def *c1, + const struct cfg80211_chan_def *c2) +{ + u32 c1_pri40, c1_pri80, c2_pri40, c2_pri80; - sec_chan = ieee80211_get_channel(wiphy, chan->center_freq + diff); - if (!sec_chan) { + /* If they are identical, return */ + if (cfg80211_chandef_identical(c1, c2)) + return c1; + + /* otherwise, must have same control channel */ + if (c1->chan != c2->chan) + return NULL; + + /* + * If they have the same width, but aren't identical, + * then they can't be compatible. + */ + if (c1->width == c2->width) + return NULL; + + if (c1->width == NL80211_CHAN_WIDTH_20_NOHT || + c1->width == NL80211_CHAN_WIDTH_20) + return c2; + + if (c2->width == NL80211_CHAN_WIDTH_20_NOHT || + c2->width == NL80211_CHAN_WIDTH_20) + return c1; + + chandef_primary_freqs(c1, &c1_pri40, &c1_pri80); + chandef_primary_freqs(c2, &c2_pri40, &c2_pri80); + + if (c1_pri40 != c2_pri40) + return NULL; + + WARN_ON(!c1_pri80 && !c2_pri80); + if (c1_pri80 && c2_pri80 && c1_pri80 != c2_pri80) + return NULL; + + if (c1->width > c2->width) + return c1; + return c2; +} +EXPORT_SYMBOL(cfg80211_chandef_compatible); + +bool cfg80211_secondary_chans_ok(struct wiphy *wiphy, + u32 center_freq, u32 bandwidth, + u32 prohibited_flags) +{ + struct ieee80211_channel *c; + u32 freq; + + for (freq = center_freq - bandwidth/2 + 10; + freq <= center_freq + bandwidth/2 - 10; + freq += 20) { + c = ieee80211_get_channel(wiphy, freq); + if (!c || c->flags & prohibited_flags) + return false; + } + + return true; +} + +static bool cfg80211_check_beacon_chans(struct wiphy *wiphy, + u32 center_freq, u32 bw) +{ + return cfg80211_secondary_chans_ok(wiphy, center_freq, bw, + IEEE80211_CHAN_DISABLED | + IEEE80211_CHAN_PASSIVE_SCAN | + IEEE80211_CHAN_NO_IBSS | + IEEE80211_CHAN_RADAR); +} + +bool cfg80211_reg_can_beacon(struct wiphy *wiphy, + struct cfg80211_chan_def *chandef) +{ + u32 width; + bool res; + + trace_cfg80211_reg_can_beacon(wiphy, chandef); + + if (WARN_ON(!cfg80211_chan_def_valid(chandef))) { trace_cfg80211_return_bool(false); return false; } - /* we'll need a DFS capability later */ - if (sec_chan->flags & (IEEE80211_CHAN_DISABLED | - IEEE80211_CHAN_PASSIVE_SCAN | - IEEE80211_CHAN_NO_IBSS | - IEEE80211_CHAN_RADAR)) { + switch (chandef->width) { + case NL80211_CHAN_WIDTH_20_NOHT: + case NL80211_CHAN_WIDTH_20: + width = 20; + break; + case NL80211_CHAN_WIDTH_40: + width = 40; + break; + case NL80211_CHAN_WIDTH_80: + case NL80211_CHAN_WIDTH_80P80: + width = 80; + break; + case NL80211_CHAN_WIDTH_160: + width = 160; + break; + default: + WARN_ON_ONCE(1); trace_cfg80211_return_bool(false); return false; } - trace_cfg80211_return_bool(true); - return true; + + res = cfg80211_check_beacon_chans(wiphy, chandef->center_freq1, width); + + if (res && chandef->center_freq2) + res = cfg80211_check_beacon_chans(wiphy, chandef->center_freq2, + width); + + trace_cfg80211_return_bool(res); + return res; } -EXPORT_SYMBOL(cfg80211_can_beacon_sec_chan); +EXPORT_SYMBOL(cfg80211_reg_can_beacon); int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev, - int freq, enum nl80211_channel_type chantype) + struct cfg80211_chan_def *chandef) { - struct ieee80211_channel *chan; - if (!rdev->ops->set_monitor_channel) return -EOPNOTSUPP; if (!cfg80211_has_monitors_only(rdev)) return -EBUSY; - chan = rdev_freq_to_chan(rdev, freq, chantype); - if (!chan) - return -EINVAL; - - return rdev_set_monitor_channel(rdev, chan, chantype); + return rdev_set_monitor_channel(rdev, chandef); } void diff --git a/net/wireless/core.h b/net/wireless/core.h index e53831c..a0c8dec 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -309,9 +309,9 @@ int cfg80211_join_mesh(struct cfg80211_registered_device *rdev, const struct mesh_config *conf); int cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, struct net_device *dev); -int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev, - struct wireless_dev *wdev, int freq, - enum nl80211_channel_type channel_type); +int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev, + struct cfg80211_chan_def *chandef); /* AP */ int cfg80211_stop_ap(struct cfg80211_registered_device *rdev, @@ -378,10 +378,8 @@ void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev); int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev, struct ieee80211_channel *chan, bool offchan, - enum nl80211_channel_type channel_type, - bool channel_type_valid, unsigned int wait, - const u8 *buf, size_t len, bool no_cck, - bool dont_wait_for_ack, u64 *cookie); + unsigned int wait, const u8 *buf, size_t len, + bool no_cck, bool dont_wait_for_ack, u64 *cookie); void cfg80211_oper_and_ht_capa(struct ieee80211_ht_cap *ht_capa, const struct ieee80211_ht_cap *ht_capa_mask); @@ -472,11 +470,8 @@ cfg80211_get_chan_state(struct wireless_dev *wdev, struct ieee80211_channel **chan, enum cfg80211_chan_mode *chanmode); -struct ieee80211_channel * -rdev_freq_to_chan(struct cfg80211_registered_device *rdev, - int freq, enum nl80211_channel_type channel_type); int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev, - int freq, enum nl80211_channel_type chantype); + struct cfg80211_chan_def *chandef); int ieee80211_get_ratemask(struct ieee80211_supported_band *sband, const u8 *rates, unsigned int n_rates, @@ -488,6 +483,12 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, enum nl80211_iftype iftype, int num); +bool cfg80211_chan_def_valid(const struct cfg80211_chan_def *chandef); + +bool cfg80211_secondary_chans_ok(struct wiphy *wiphy, + u32 center_freq, u32 bandwidth, + u32 prohibited_flags); + #define CFG80211_MAX_NUM_DIFFERENT_CHANNELS 10 #ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index 27941d5..9b9551e 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c @@ -100,9 +100,9 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, * 11a for maximum compatibility. */ struct ieee80211_supported_band *sband = - rdev->wiphy.bands[params->channel->band]; + rdev->wiphy.bands[params->chandef.chan->band]; int j; - u32 flag = params->channel->band == IEEE80211_BAND_5GHZ ? + u32 flag = params->chandef.chan->band == IEEE80211_BAND_5GHZ ? IEEE80211_RATE_MANDATORY_A : IEEE80211_RATE_MANDATORY_B; @@ -118,11 +118,11 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, wdev->ibss_fixed = params->channel_fixed; #ifdef CONFIG_CFG80211_WEXT - wdev->wext.ibss.channel = params->channel; + wdev->wext.ibss.chandef = params->chandef; #endif wdev->sme_state = CFG80211_SME_CONNECTING; - err = cfg80211_can_use_chan(rdev, wdev, params->channel, + err = cfg80211_can_use_chan(rdev, wdev, params->chandef.chan, params->channel_fixed ? CHAN_MODE_SHARED : CHAN_MODE_EXCLUSIVE); @@ -251,7 +251,9 @@ int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev, wdev->wext.ibss.beacon_interval = 100; /* try to find an IBSS channel if none requested ... */ - if (!wdev->wext.ibss.channel) { + if (!wdev->wext.ibss.chandef.chan) { + wdev->wext.ibss.chandef.width = NL80211_CHAN_WIDTH_20_NOHT; + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { struct ieee80211_supported_band *sband; struct ieee80211_channel *chan; @@ -266,15 +268,15 @@ int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev, continue; if (chan->flags & IEEE80211_CHAN_DISABLED) continue; - wdev->wext.ibss.channel = chan; + wdev->wext.ibss.chandef.chan = chan; break; } - if (wdev->wext.ibss.channel) + if (wdev->wext.ibss.chandef.chan) break; } - if (!wdev->wext.ibss.channel) + if (!wdev->wext.ibss.chandef.chan) return -EINVAL; } @@ -336,7 +338,7 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev, return -EINVAL; } - if (wdev->wext.ibss.channel == chan) + if (wdev->wext.ibss.chandef.chan == chan) return 0; wdev_lock(wdev); @@ -349,7 +351,8 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev, return err; if (chan) { - wdev->wext.ibss.channel = chan; + wdev->wext.ibss.chandef.chan = chan; + wdev->wext.ibss.chandef.width = NL80211_CHAN_WIDTH_20_NOHT; wdev->wext.ibss.channel_fixed = true; } else { /* cfg80211_ibss_wext_join will pick one if needed */ @@ -379,8 +382,8 @@ int cfg80211_ibss_wext_giwfreq(struct net_device *dev, wdev_lock(wdev); if (wdev->current_bss) chan = wdev->current_bss->pub.channel; - else if (wdev->wext.ibss.channel) - chan = wdev->wext.ibss.channel; + else if (wdev->wext.ibss.chandef.chan) + chan = wdev->wext.ibss.chandef.chan; wdev_unlock(wdev); if (chan) { diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c index 966cfc4..3ee5a72 100644 --- a/net/wireless/mesh.c +++ b/net/wireless/mesh.c @@ -73,8 +73,6 @@ const struct mesh_config default_mesh_config = { const struct mesh_setup default_mesh_setup = { /* cfg80211_join_mesh() will pick a channel if needed */ - .channel = NULL, - .channel_type = NL80211_CHAN_NO_HT, .sync_method = IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET, .path_sel_proto = IEEE80211_PATH_PROTOCOL_HWMP, .path_metric = IEEE80211_PATH_METRIC_AIRTIME, @@ -111,13 +109,12 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, if (!rdev->ops->join_mesh) return -EOPNOTSUPP; - if (!setup->channel) { + if (!setup->chandef.chan) { /* if no channel explicitly given, use preset channel */ - setup->channel = wdev->preset_chan; - setup->channel_type = wdev->preset_chantype; + setup->chandef = wdev->preset_chandef; } - if (!setup->channel) { + if (!setup->chandef.chan) { /* if we don't have that either, use the first usable channel */ enum ieee80211_band band; @@ -137,26 +134,25 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, IEEE80211_CHAN_DISABLED | IEEE80211_CHAN_RADAR)) continue; - setup->channel = chan; + setup->chandef.chan = chan; break; } - if (setup->channel) + if (setup->chandef.chan) break; } /* no usable channel ... */ - if (!setup->channel) + if (!setup->chandef.chan) return -EINVAL; - setup->channel_type = NL80211_CHAN_NO_HT; + setup->chandef.width = NL80211_CHAN_WIDTH_20_NOHT;; } - if (!cfg80211_can_beacon_sec_chan(&rdev->wiphy, setup->channel, - setup->channel_type)) + if (!cfg80211_reg_can_beacon(&rdev->wiphy, &setup->chandef)) return -EINVAL; - err = cfg80211_can_use_chan(rdev, wdev, setup->channel, + err = cfg80211_can_use_chan(rdev, wdev, setup->chandef.chan, CHAN_MODE_SHARED); if (err) return err; @@ -165,7 +161,7 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, if (!err) { memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len); wdev->mesh_id_len = setup->mesh_id_len; - wdev->channel = setup->channel; + wdev->channel = setup->chandef.chan; } return err; @@ -188,20 +184,12 @@ int cfg80211_join_mesh(struct cfg80211_registered_device *rdev, return err; } -int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev, - struct wireless_dev *wdev, int freq, - enum nl80211_channel_type channel_type) +int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev, + struct cfg80211_chan_def *chandef) { - struct ieee80211_channel *channel; int err; - channel = rdev_freq_to_chan(rdev, freq, channel_type); - if (!channel || !cfg80211_can_beacon_sec_chan(&rdev->wiphy, - channel, - channel_type)) { - return -EINVAL; - } - /* * Workaround for libertas (only!), it puts the interface * into mesh mode but doesn't implement join_mesh. Instead, @@ -210,21 +198,21 @@ int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev, * compatible with 802.11 mesh. */ if (rdev->ops->libertas_set_mesh_channel) { - if (channel_type != NL80211_CHAN_NO_HT) + if (chandef->width != NL80211_CHAN_WIDTH_20_NOHT) return -EINVAL; if (!netif_running(wdev->netdev)) return -ENETDOWN; - err = cfg80211_can_use_chan(rdev, wdev, channel, + err = cfg80211_can_use_chan(rdev, wdev, chandef->chan, CHAN_MODE_SHARED); if (err) return err; err = rdev_libertas_set_mesh_channel(rdev, wdev->netdev, - channel); + chandef->chan); if (!err) - wdev->channel = channel; + wdev->channel = chandef->chan; return err; } @@ -232,8 +220,7 @@ int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev, if (wdev->mesh_id_len) return -EBUSY; - wdev->preset_chan = channel; - wdev->preset_chantype = channel_type; + wdev->preset_chandef = *chandef; return 0; } diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 4bfd14f..5e8123e 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -579,31 +579,25 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, void cfg80211_ready_on_channel(struct wireless_dev *wdev, u64 cookie, struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type, unsigned int duration, gfp_t gfp) { struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); - trace_cfg80211_ready_on_channel(wdev, cookie, chan, channel_type, - duration); - nl80211_send_remain_on_channel(rdev, wdev, cookie, chan, channel_type, - duration, gfp); + trace_cfg80211_ready_on_channel(wdev, cookie, chan, duration); + nl80211_send_remain_on_channel(rdev, wdev, cookie, chan, duration, gfp); } EXPORT_SYMBOL(cfg80211_ready_on_channel); void cfg80211_remain_on_channel_expired(struct wireless_dev *wdev, u64 cookie, struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type, gfp_t gfp) { struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); - trace_cfg80211_ready_on_channel_expired(wdev, cookie, chan, - channel_type); - nl80211_send_remain_on_channel_cancel(rdev, wdev, cookie, chan, - channel_type, gfp); + trace_cfg80211_ready_on_channel_expired(wdev, cookie, chan); + nl80211_send_remain_on_channel_cancel(rdev, wdev, cookie, chan, gfp); } EXPORT_SYMBOL(cfg80211_remain_on_channel_expired); @@ -758,10 +752,8 @@ void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev) int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev, struct ieee80211_channel *chan, bool offchan, - enum nl80211_channel_type channel_type, - bool channel_type_valid, unsigned int wait, - const u8 *buf, size_t len, bool no_cck, - bool dont_wait_for_ack, u64 *cookie) + unsigned int wait, const u8 *buf, size_t len, + bool no_cck, bool dont_wait_for_ack, u64 *cookie) { const struct ieee80211_mgmt *mgmt; u16 stype; @@ -855,7 +847,6 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, /* Transmit the Action frame as requested by user space */ return rdev_mgmt_tx(rdev, wdev, chan, offchan, - channel_type, channel_type_valid, wait, buf, len, no_cck, dont_wait_for_ack, cookie); } @@ -997,15 +988,14 @@ void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index, } EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify); -void cfg80211_ch_switch_notify(struct net_device *dev, int freq, - enum nl80211_channel_type type) +void cfg80211_ch_switch_notify(struct net_device *dev, + struct cfg80211_chan_def *chandef) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); - struct ieee80211_channel *chan; - trace_cfg80211_ch_switch_notify(dev, freq, type); + trace_cfg80211_ch_switch_notify(dev, chandef); wdev_lock(wdev); @@ -1013,12 +1003,8 @@ void cfg80211_ch_switch_notify(struct net_device *dev, int freq, wdev->iftype != NL80211_IFTYPE_P2P_GO)) goto out; - chan = rdev_freq_to_chan(rdev, freq, type); - if (WARN_ON(!chan)) - goto out; - - wdev->channel = chan; - nl80211_ch_switch_notify(rdev, dev, freq, type, GFP_KERNEL); + wdev->channel = chandef->chan; + nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL); out: wdev_unlock(wdev); return; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index c18b2fc..d038fa4 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -223,8 +223,13 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { [NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING, .len = 20-1 }, [NL80211_ATTR_WIPHY_TXQ_PARAMS] = { .type = NLA_NESTED }, + [NL80211_ATTR_WIPHY_FREQ] = { .type = NLA_U32 }, [NL80211_ATTR_WIPHY_CHANNEL_TYPE] = { .type = NLA_U32 }, + [NL80211_ATTR_CHANNEL_WIDTH] = { .type = NLA_U32 }, + [NL80211_ATTR_CENTER_FREQ1] = { .type = NLA_U32 }, + [NL80211_ATTR_CENTER_FREQ2] = { .type = NLA_U32 }, + [NL80211_ATTR_WIPHY_RETRY_SHORT] = { .type = NLA_U8 }, [NL80211_ATTR_WIPHY_RETRY_LONG] = { .type = NLA_U8 }, [NL80211_ATTR_WIPHY_FRAG_THRESHOLD] = { .type = NLA_U32 }, @@ -1360,51 +1365,139 @@ static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev) wdev->iftype == NL80211_IFTYPE_P2P_GO; } -static bool nl80211_valid_channel_type(struct genl_info *info, - enum nl80211_channel_type *channel_type) +static int nl80211_parse_chandef(struct cfg80211_registered_device *rdev, + struct genl_info *info, + struct cfg80211_chan_def *chandef) { - enum nl80211_channel_type tmp; + struct ieee80211_sta_ht_cap *ht_cap; + struct ieee80211_sta_vht_cap *vht_cap; + u32 control_freq, width; - if (!info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) - return false; + if (!info->attrs[NL80211_ATTR_WIPHY_FREQ]) + return -EINVAL; - tmp = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]); - if (tmp != NL80211_CHAN_NO_HT && - tmp != NL80211_CHAN_HT20 && - tmp != NL80211_CHAN_HT40PLUS && - tmp != NL80211_CHAN_HT40MINUS) - return false; + control_freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); - if (channel_type) - *channel_type = tmp; + chandef->chan = ieee80211_get_channel(&rdev->wiphy, control_freq); + chandef->width = NL80211_CHAN_WIDTH_20_NOHT; + chandef->center_freq1 = control_freq; + chandef->center_freq2 = 0; - return true; + /* Primary channel not allowed */ + if (!chandef->chan || chandef->chan->flags & IEEE80211_CHAN_DISABLED) + return -EINVAL; + + if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { + enum nl80211_channel_type chantype; + + chantype = nla_get_u32( + info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]); + + switch (chantype) { + case NL80211_CHAN_NO_HT: + case NL80211_CHAN_HT20: + case NL80211_CHAN_HT40PLUS: + case NL80211_CHAN_HT40MINUS: + cfg80211_chandef_create(chandef, chandef->chan, + chantype); + break; + default: + return -EINVAL; + } + } else if (info->attrs[NL80211_ATTR_CHANNEL_WIDTH]) { + chandef->width = + nla_get_u32(info->attrs[NL80211_ATTR_CHANNEL_WIDTH]); + if (info->attrs[NL80211_ATTR_CENTER_FREQ1]) + chandef->center_freq1 = + nla_get_u32( + info->attrs[NL80211_ATTR_CENTER_FREQ1]); + if (info->attrs[NL80211_ATTR_CENTER_FREQ2]) + chandef->center_freq2 = + nla_get_u32( + info->attrs[NL80211_ATTR_CENTER_FREQ2]); + } + + ht_cap = &rdev->wiphy.bands[chandef->chan->band]->ht_cap; + vht_cap = &rdev->wiphy.bands[chandef->chan->band]->vht_cap; + + if (!cfg80211_chan_def_valid(chandef)) + return -EINVAL; + + switch (chandef->width) { + case NL80211_CHAN_WIDTH_20: + if (!ht_cap->ht_supported) + return -EINVAL; + case NL80211_CHAN_WIDTH_20_NOHT: + width = 20; + break; + case NL80211_CHAN_WIDTH_40: + width = 40; + /* quick early regulatory check */ + if (chandef->center_freq1 < control_freq && + chandef->chan->flags & IEEE80211_CHAN_NO_HT40MINUS) + return -EINVAL; + if (chandef->center_freq1 > control_freq && + chandef->chan->flags & IEEE80211_CHAN_NO_HT40PLUS) + return -EINVAL; + if (!ht_cap->ht_supported) + return -EINVAL; + if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) || + ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT) + return -EINVAL; + break; + case NL80211_CHAN_WIDTH_80: + width = 80; + if (!vht_cap->vht_supported) + return -EINVAL; + break; + case NL80211_CHAN_WIDTH_80P80: + width = 80; + if (!vht_cap->vht_supported) + return -EINVAL; + if (!(vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)) + return -EINVAL; + break; + case NL80211_CHAN_WIDTH_160: + width = 160; + if (!vht_cap->vht_supported) + return -EINVAL; + if (!(vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ)) + return -EINVAL; + break; + default: + return -EINVAL; + } + + if (!cfg80211_secondary_chans_ok(&rdev->wiphy, chandef->center_freq1, + width, IEEE80211_CHAN_DISABLED)) + return -EINVAL; + if (chandef->center_freq2 && + !cfg80211_secondary_chans_ok(&rdev->wiphy, chandef->center_freq2, + width, IEEE80211_CHAN_DISABLED)) + return -EINVAL; + + /* TODO: missing regulatory check on bandwidth */ + + return 0; } static int __nl80211_set_channel(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev, struct genl_info *info) { - struct ieee80211_channel *channel; - enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; - u32 freq; + struct cfg80211_chan_def chandef; int result; enum nl80211_iftype iftype = NL80211_IFTYPE_MONITOR; if (wdev) iftype = wdev->iftype; - if (!info->attrs[NL80211_ATTR_WIPHY_FREQ]) - return -EINVAL; - if (!nl80211_can_set_dev_channel(wdev)) return -EOPNOTSUPP; - if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] && - !nl80211_valid_channel_type(info, &channel_type)) - return -EINVAL; - - freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); + result = nl80211_parse_chandef(rdev, info, &chandef); + if (result) + return result; mutex_lock(&rdev->devlist_mtx); switch (iftype) { @@ -1414,22 +1507,18 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev, result = -EBUSY; break; } - channel = rdev_freq_to_chan(rdev, freq, channel_type); - if (!channel || !cfg80211_can_beacon_sec_chan(&rdev->wiphy, - channel, - channel_type)) { + if (!cfg80211_reg_can_beacon(&rdev->wiphy, &chandef)) { result = -EINVAL; break; } - wdev->preset_chan = channel; - wdev->preset_chantype = channel_type; + wdev->preset_chandef = chandef; result = 0; break; case NL80211_IFTYPE_MESH_POINT: - result = cfg80211_set_mesh_freq(rdev, wdev, freq, channel_type); + result = cfg80211_set_mesh_channel(rdev, wdev, &chandef); break; case NL80211_IFTYPE_MONITOR: - result = cfg80211_set_monitor_channel(rdev, freq, channel_type); + result = cfg80211_set_monitor_channel(rdev, &chandef); break; default: result = -EINVAL; @@ -1749,6 +1838,35 @@ static inline u64 wdev_id(struct wireless_dev *wdev) ((u64)wiphy_to_dev(wdev->wiphy)->wiphy_idx << 32); } +static int nl80211_send_chandef(struct sk_buff *msg, + struct cfg80211_chan_def *chandef) +{ + WARN_ON(!cfg80211_chan_def_valid(chandef)); + + if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, + chandef->chan->center_freq)) + return -ENOBUFS; + switch (chandef->width) { + case NL80211_CHAN_WIDTH_20_NOHT: + case NL80211_CHAN_WIDTH_20: + case NL80211_CHAN_WIDTH_40: + if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, + cfg80211_get_chandef_type(chandef))) + return -ENOBUFS; + break; + default: + break; + } + if (nla_put_u32(msg, NL80211_ATTR_CHANNEL_WIDTH, chandef->width)) + return -ENOBUFS; + if (nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ1, chandef->center_freq1)) + return -ENOBUFS; + if (chandef->center_freq2 && + nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ2, chandef->center_freq2)) + return -ENOBUFS; + return 0; +} + static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flags, struct cfg80211_registered_device *rdev, struct wireless_dev *wdev) @@ -1775,16 +1893,14 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flag goto nla_put_failure; if (rdev->ops->get_channel) { - struct ieee80211_channel *chan; - enum nl80211_channel_type channel_type; - - chan = rdev_get_channel(rdev, wdev, &channel_type); - if (chan && - (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, - chan->center_freq) || - nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, - channel_type))) - goto nla_put_failure; + int ret; + struct cfg80211_chan_def chandef; + + ret = rdev_get_channel(rdev, wdev, &chandef); + if (ret == 0) { + if (nl80211_send_chandef(msg, &chandef)) + goto nla_put_failure; + } } if (wdev->ssid_len) { @@ -2492,11 +2608,10 @@ static bool nl80211_get_ap_channel(struct cfg80211_registered_device *rdev, wdev->iftype != NL80211_IFTYPE_P2P_GO) continue; - if (!wdev->preset_chan) + if (!wdev->preset_chandef.chan) continue; - params->channel = wdev->preset_chan; - params->channel_type = wdev->preset_chantype; + params->chandef = wdev->preset_chandef; ret = true; break; } @@ -2618,30 +2733,19 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) } if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { - enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; - - if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] && - !nl80211_valid_channel_type(info, &channel_type)) - return -EINVAL; - - params.channel = rdev_freq_to_chan(rdev, - nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]), - channel_type); - if (!params.channel) - return -EINVAL; - params.channel_type = channel_type; - } else if (wdev->preset_chan) { - params.channel = wdev->preset_chan; - params.channel_type = wdev->preset_chantype; + err = nl80211_parse_chandef(rdev, info, ¶ms.chandef); + if (err) + return err; + } else if (wdev->preset_chandef.chan) { + params.chandef = wdev->preset_chandef; } else if (!nl80211_get_ap_channel(rdev, ¶ms)) return -EINVAL; - if (!cfg80211_can_beacon_sec_chan(&rdev->wiphy, params.channel, - params.channel_type)) + if (!cfg80211_reg_can_beacon(&rdev->wiphy, ¶ms.chandef)) return -EINVAL; mutex_lock(&rdev->devlist_mtx); - err = cfg80211_can_use_chan(rdev, wdev, params.channel, + err = cfg80211_can_use_chan(rdev, wdev, params.chandef.chan, CHAN_MODE_SHARED); mutex_unlock(&rdev->devlist_mtx); @@ -2650,10 +2754,9 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) err = rdev_start_ap(rdev, dev, ¶ms); if (!err) { - wdev->preset_chan = params.channel; - wdev->preset_chantype = params.channel_type; + wdev->preset_chandef = params.chandef; wdev->beacon_interval = params.beacon_interval; - wdev->channel = params.channel; + wdev->channel = params.chandef.chan; wdev->ssid_len = params.ssid_len; memcpy(wdev->ssid, params.ssid, wdev->ssid_len); } @@ -2787,29 +2890,52 @@ static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info, rate = nla_nest_start(msg, attr); if (!rate) - goto nla_put_failure; + return false; /* cfg80211_calculate_bitrate will return 0 for mcs >= 32 */ bitrate = cfg80211_calculate_bitrate(info); /* report 16-bit bitrate only if we can */ bitrate_compat = bitrate < (1UL << 16) ? bitrate : 0; - if ((bitrate > 0 && - nla_put_u32(msg, NL80211_RATE_INFO_BITRATE32, bitrate)) || - (bitrate_compat > 0 && - nla_put_u16(msg, NL80211_RATE_INFO_BITRATE, bitrate_compat)) || - ((info->flags & RATE_INFO_FLAGS_MCS) && - nla_put_u8(msg, NL80211_RATE_INFO_MCS, info->mcs)) || - ((info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) && - nla_put_flag(msg, NL80211_RATE_INFO_40_MHZ_WIDTH)) || - ((info->flags & RATE_INFO_FLAGS_SHORT_GI) && - nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI))) - goto nla_put_failure; + if (bitrate > 0 && + nla_put_u32(msg, NL80211_RATE_INFO_BITRATE32, bitrate)) + return false; + if (bitrate_compat > 0 && + nla_put_u16(msg, NL80211_RATE_INFO_BITRATE, bitrate_compat)) + return false; + + if (info->flags & RATE_INFO_FLAGS_MCS) { + if (nla_put_u8(msg, NL80211_RATE_INFO_MCS, info->mcs)) + return false; + if (info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH && + nla_put_flag(msg, NL80211_RATE_INFO_40_MHZ_WIDTH)) + return false; + if (info->flags & RATE_INFO_FLAGS_SHORT_GI && + nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI)) + return false; + } else if (info->flags & RATE_INFO_FLAGS_VHT_MCS) { + if (nla_put_u8(msg, NL80211_RATE_INFO_VHT_MCS, info->mcs)) + return false; + if (nla_put_u8(msg, NL80211_RATE_INFO_VHT_NSS, info->nss)) + return false; + if (info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH && + nla_put_flag(msg, NL80211_RATE_INFO_40_MHZ_WIDTH)) + return false; + if (info->flags & RATE_INFO_FLAGS_80_MHZ_WIDTH && + nla_put_flag(msg, NL80211_RATE_INFO_80_MHZ_WIDTH)) + return false; + if (info->flags & RATE_INFO_FLAGS_80P80_MHZ_WIDTH && + nla_put_flag(msg, NL80211_RATE_INFO_80P80_MHZ_WIDTH)) + return false; + if (info->flags & RATE_INFO_FLAGS_160_MHZ_WIDTH && + nla_put_flag(msg, NL80211_RATE_INFO_160_MHZ_WIDTH)) + return false; + if (info->flags & RATE_INFO_FLAGS_SHORT_GI && + nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI)) + return false; + } nla_nest_end(msg, rate); return true; - -nla_put_failure: - return false; } static int nl80211_send_station(struct sk_buff *msg, u32 portid, u32 seq, @@ -5330,8 +5456,7 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) return -EINVAL; - if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] || - !info->attrs[NL80211_ATTR_SSID] || + if (!info->attrs[NL80211_ATTR_SSID] || !nla_len(info->attrs[NL80211_ATTR_SSID])) return -EINVAL; @@ -5366,35 +5491,17 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) ibss.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); } - if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { - enum nl80211_channel_type channel_type; - - if (!nl80211_valid_channel_type(info, &channel_type)) - return -EINVAL; - - if (channel_type != NL80211_CHAN_NO_HT && - !(wiphy->features & NL80211_FEATURE_HT_IBSS)) - return -EINVAL; - - ibss.channel_type = channel_type; - } else { - ibss.channel_type = NL80211_CHAN_NO_HT; - } + err = nl80211_parse_chandef(rdev, info, &ibss.chandef); + if (err) + return err; - ibss.channel = rdev_freq_to_chan(rdev, - nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]), - ibss.channel_type); - if (!ibss.channel || - ibss.channel->flags & IEEE80211_CHAN_NO_IBSS || - ibss.channel->flags & IEEE80211_CHAN_DISABLED) + if (!cfg80211_reg_can_beacon(&rdev->wiphy, &ibss.chandef)) return -EINVAL; - /* Both channels should be able to initiate communication */ - if ((ibss.channel_type == NL80211_CHAN_HT40PLUS || - ibss.channel_type == NL80211_CHAN_HT40MINUS) && - !cfg80211_can_beacon_sec_chan(&rdev->wiphy, ibss.channel, - ibss.channel_type)) + if (ibss.chandef.width > NL80211_CHAN_WIDTH_40) return -EINVAL; + if (ibss.chandef.width != NL80211_CHAN_WIDTH_20_NOHT && + !(rdev->wiphy.features & NL80211_FEATURE_HT_IBSS)) ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED]; ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY]; @@ -5405,7 +5512,7 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) int n_rates = nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]); struct ieee80211_supported_band *sband = - wiphy->bands[ibss.channel->band]; + wiphy->bands[ibss.chandef.chan->band]; err = ieee80211_get_ratemask(sband, rates, n_rates, &ibss.basic_rates); @@ -5427,7 +5534,8 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) if (IS_ERR(connkeys)) return PTR_ERR(connkeys); - if ((ibss.channel_type != NL80211_CHAN_NO_HT) && no_ht) { + if ((ibss.chandef.width != NL80211_CHAN_WIDTH_20_NOHT) && + no_ht) { kfree(connkeys); return -EINVAL; } @@ -5948,12 +6056,11 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, { struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct wireless_dev *wdev = info->user_ptr[1]; - struct ieee80211_channel *chan; + struct cfg80211_chan_def chandef; struct sk_buff *msg; void *hdr; u64 cookie; - enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; - u32 freq, duration; + u32 duration; int err; if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] || @@ -5974,14 +6081,9 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, duration > rdev->wiphy.max_remain_on_channel_duration) return -EINVAL; - if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] && - !nl80211_valid_channel_type(info, &channel_type)) - return -EINVAL; - - freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); - chan = rdev_freq_to_chan(rdev, freq, channel_type); - if (chan == NULL) - return -EINVAL; + err = nl80211_parse_chandef(rdev, info, &chandef); + if (err) + return err; msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!msg) @@ -5995,8 +6097,8 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, goto free_msg; } - err = rdev_remain_on_channel(rdev, wdev, chan, channel_type, duration, - &cookie); + err = rdev_remain_on_channel(rdev, wdev, chandef.chan, + duration, &cookie); if (err) goto free_msg; @@ -6215,10 +6317,7 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct wireless_dev *wdev = info->user_ptr[1]; - struct ieee80211_channel *chan; - enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; - bool channel_type_valid = false; - u32 freq; + struct cfg80211_chan_def chandef; int err; void *hdr = NULL; u64 cookie; @@ -6228,8 +6327,7 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) dont_wait_for_ack = info->attrs[NL80211_ATTR_DONT_WAIT_FOR_ACK]; - if (!info->attrs[NL80211_ATTR_FRAME] || - !info->attrs[NL80211_ATTR_WIPHY_FREQ]) + if (!info->attrs[NL80211_ATTR_FRAME]) return -EINVAL; if (!rdev->ops->mgmt_tx) @@ -6264,12 +6362,6 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) } - if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { - if (!nl80211_valid_channel_type(info, &channel_type)) - return -EINVAL; - channel_type_valid = true; - } - offchan = info->attrs[NL80211_ATTR_OFFCHANNEL_TX_OK]; if (offchan && !(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX)) @@ -6277,10 +6369,9 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) no_cck = nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]); - freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); - chan = rdev_freq_to_chan(rdev, freq, channel_type); - if (chan == NULL) - return -EINVAL; + err = nl80211_parse_chandef(rdev, info, &chandef); + if (err) + return err; if (!dont_wait_for_ack) { msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); @@ -6296,8 +6387,7 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) } } - err = cfg80211_mlme_mgmt_tx(rdev, wdev, chan, offchan, channel_type, - channel_type_valid, wait, + err = cfg80211_mlme_mgmt_tx(rdev, wdev, chandef.chan, offchan, wait, nla_data(info->attrs[NL80211_ATTR_FRAME]), nla_len(info->attrs[NL80211_ATTR_FRAME]), no_cck, dont_wait_for_ack, &cookie); @@ -6561,21 +6651,12 @@ static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info) } if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { - enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; - - if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] && - !nl80211_valid_channel_type(info, &channel_type)) - return -EINVAL; - - setup.channel = rdev_freq_to_chan(rdev, - nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]), - channel_type); - if (!setup.channel) - return -EINVAL; - setup.channel_type = channel_type; + err = nl80211_parse_chandef(rdev, info, &setup.chandef); + if (err) + return err; } else { /* cfg80211_join_mesh() will sort it out */ - setup.channel = NULL; + setup.chandef.chan = NULL; } return cfg80211_join_mesh(rdev, dev, &setup, &cfg); @@ -8395,7 +8476,6 @@ static void nl80211_send_remain_on_chan_event( int cmd, struct cfg80211_registered_device *rdev, struct wireless_dev *wdev, u64 cookie, struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type, unsigned int duration, gfp_t gfp) { struct sk_buff *msg; @@ -8416,7 +8496,8 @@ static void nl80211_send_remain_on_chan_event( wdev->netdev->ifindex)) || nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev)) || nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, chan->center_freq) || - nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, channel_type) || + nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, + NL80211_CHAN_NO_HT) || nla_put_u64(msg, NL80211_ATTR_COOKIE, cookie)) goto nla_put_failure; @@ -8438,23 +8519,20 @@ static void nl80211_send_remain_on_chan_event( void nl80211_send_remain_on_channel(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev, u64 cookie, struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type, unsigned int duration, gfp_t gfp) { nl80211_send_remain_on_chan_event(NL80211_CMD_REMAIN_ON_CHANNEL, rdev, wdev, cookie, chan, - channel_type, duration, gfp); + duration, gfp); } void nl80211_send_remain_on_channel_cancel( struct cfg80211_registered_device *rdev, struct wireless_dev *wdev, - u64 cookie, struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type, gfp_t gfp) + u64 cookie, struct ieee80211_channel *chan, gfp_t gfp) { nl80211_send_remain_on_chan_event(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, - rdev, wdev, cookie, chan, - channel_type, 0, gfp); + rdev, wdev, cookie, chan, 0, gfp); } void nl80211_send_sta_event(struct cfg80211_registered_device *rdev, @@ -8810,8 +8888,8 @@ void nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev, } void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev, - struct net_device *netdev, int freq, - enum nl80211_channel_type type, gfp_t gfp) + struct net_device *netdev, + struct cfg80211_chan_def *chandef, gfp_t gfp) { struct sk_buff *msg; void *hdr; @@ -8826,9 +8904,10 @@ void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev, return; } - if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) || - nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq) || - nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, type)) + if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex)) + goto nla_put_failure; + + if (nl80211_send_chandef(msg, chandef)) goto nla_put_failure; genlmsg_end(msg, hdr); @@ -9027,6 +9106,53 @@ void cfg80211_report_obss_beacon(struct wiphy *wiphy, } EXPORT_SYMBOL(cfg80211_report_obss_beacon); +void cfg80211_tdls_oper_request(struct net_device *dev, const u8 *peer, + enum nl80211_tdls_operation oper, + u16 reason_code, gfp_t gfp) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct sk_buff *msg; + void *hdr; + int err; + + trace_cfg80211_tdls_oper_request(wdev->wiphy, dev, peer, oper, + reason_code); + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); + if (!msg) + return; + + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_TDLS_OPER); + if (!hdr) { + nlmsg_free(msg); + return; + } + + if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || + nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) || + nla_put_u8(msg, NL80211_ATTR_TDLS_OPERATION, oper) || + nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer) || + (reason_code > 0 && + nla_put_u16(msg, NL80211_ATTR_REASON_CODE, reason_code))) + goto nla_put_failure; + + err = genlmsg_end(msg, hdr); + if (err < 0) { + nlmsg_free(msg); + return; + } + + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_mlme_mcgrp.id, gfp); + return; + + nla_put_failure: + genlmsg_cancel(msg, hdr); + nlmsg_free(msg); +} +EXPORT_SYMBOL(cfg80211_tdls_oper_request); + static int nl80211_netlink_notify(struct notifier_block * nb, unsigned long state, void *_notify) diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index f615351..2acba84 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h @@ -76,13 +76,11 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev, void nl80211_send_remain_on_channel(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev, u64 cookie, struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type, unsigned int duration, gfp_t gfp); void nl80211_send_remain_on_channel_cancel( struct cfg80211_registered_device *rdev, struct wireless_dev *wdev, - u64 cookie, struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type, gfp_t gfp); + u64 cookie, struct ieee80211_channel *chan, gfp_t gfp); void nl80211_send_sta_event(struct cfg80211_registered_device *rdev, struct net_device *dev, const u8 *mac_addr, @@ -129,8 +127,8 @@ void nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev, const u8 *bssid, bool preauth, gfp_t gfp); void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev, - struct net_device *dev, int freq, - enum nl80211_channel_type type, gfp_t gfp); + struct net_device *dev, + struct cfg80211_chan_def *chandef, gfp_t gfp); bool nl80211_unexpected_frame(struct net_device *dev, const u8 *addr, gfp_t gfp); diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index 6e5fa65..6c0c819 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h @@ -359,12 +359,11 @@ rdev_libertas_set_mesh_channel(struct cfg80211_registered_device *rdev, static inline int rdev_set_monitor_channel(struct cfg80211_registered_device *rdev, - struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type) + struct cfg80211_chan_def *chandef) { int ret; - trace_rdev_set_monitor_channel(&rdev->wiphy, chan, channel_type); - ret = rdev->ops->set_monitor_channel(&rdev->wiphy, chan, channel_type); + trace_rdev_set_monitor_channel(&rdev->wiphy, chandef); + ret = rdev->ops->set_monitor_channel(&rdev->wiphy, chandef); trace_rdev_return_int(&rdev->wiphy, ret); return ret; } @@ -600,14 +599,12 @@ static inline int rdev_remain_on_channel(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev, struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type, unsigned int duration, u64 *cookie) { int ret; - trace_rdev_remain_on_channel(&rdev->wiphy, wdev, chan, channel_type, - duration); + trace_rdev_remain_on_channel(&rdev->wiphy, wdev, chan, duration); ret = rdev->ops->remain_on_channel(&rdev->wiphy, wdev, chan, - channel_type, duration, cookie); + duration, cookie); trace_rdev_return_int_cookie(&rdev->wiphy, ret, *cookie); return ret; } @@ -626,17 +623,15 @@ rdev_cancel_remain_on_channel(struct cfg80211_registered_device *rdev, static inline int rdev_mgmt_tx(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev, struct ieee80211_channel *chan, bool offchan, - enum nl80211_channel_type channel_type, - bool channel_type_valid, unsigned int wait, - const u8 *buf, size_t len, bool no_cck, - bool dont_wait_for_ack, u64 *cookie) + unsigned int wait, const u8 *buf, size_t len, + bool no_cck, bool dont_wait_for_ack, u64 *cookie) { int ret; - trace_rdev_mgmt_tx(&rdev->wiphy, wdev, chan, offchan, channel_type, - channel_type_valid, wait, no_cck, dont_wait_for_ack); + trace_rdev_mgmt_tx(&rdev->wiphy, wdev, chan, offchan, + wait, no_cck, dont_wait_for_ack); ret = rdev->ops->mgmt_tx(&rdev->wiphy, wdev, chan, offchan, - channel_type, channel_type_valid, wait, buf, - len, no_cck, dont_wait_for_ack, cookie); + wait, buf, len, no_cck, + dont_wait_for_ack, cookie); trace_rdev_return_int_cookie(&rdev->wiphy, ret, *cookie); return ret; } @@ -848,14 +843,17 @@ static inline void rdev_get_et_strings(struct cfg80211_registered_device *rdev, trace_rdev_return_void(&rdev->wiphy); } -static inline struct ieee80211_channel -*rdev_get_channel(struct cfg80211_registered_device *rdev, - struct wireless_dev *wdev, enum nl80211_channel_type *type) +static inline int +rdev_get_channel(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev, + struct cfg80211_chan_def *chandef) { - struct ieee80211_channel *ret; + int ret; + trace_rdev_get_channel(&rdev->wiphy, wdev); - ret = rdev->ops->get_channel(&rdev->wiphy, wdev, type); - trace_rdev_return_channel(&rdev->wiphy, ret, *type); + ret = rdev->ops->get_channel(&rdev->wiphy, wdev, chandef); + trace_rdev_return_chandef(&rdev->wiphy, ret, chandef); + return ret; } diff --git a/net/wireless/reg.c b/net/wireless/reg.c index bcc7d7e..b75756b 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -141,9 +141,8 @@ static const struct ieee80211_regdomain world_regdom = { .reg_rules = { /* IEEE 802.11b/g, channels 1..11 */ REG_RULE(2412-10, 2462+10, 40, 6, 20, 0), - /* IEEE 802.11b/g, channels 12..13. No HT40 - * channel fits here. */ - REG_RULE(2467-10, 2472+10, 20, 6, 20, + /* IEEE 802.11b/g, channels 12..13. */ + REG_RULE(2467-10, 2472+10, 40, 6, 20, NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS), /* IEEE 802.11 channel 14 - Only JP enables diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 7f97a08..9596015 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -771,6 +771,38 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev, return found; } +static struct ieee80211_channel * +cfg80211_get_bss_channel(struct wiphy *wiphy, const u8 *ie, size_t ielen, + struct ieee80211_channel *channel) +{ + const u8 *tmp; + u32 freq; + int channel_number = -1; + + tmp = cfg80211_find_ie(WLAN_EID_DS_PARAMS, ie, ielen); + if (tmp && tmp[1] == 1) { + channel_number = tmp[2]; + } else { + tmp = cfg80211_find_ie(WLAN_EID_HT_OPERATION, ie, ielen); + if (tmp && tmp[1] >= sizeof(struct ieee80211_ht_operation)) { + struct ieee80211_ht_operation *htop = (void *)(tmp + 2); + + channel_number = htop->primary_chan; + } + } + + if (channel_number < 0) + return channel; + + freq = ieee80211_channel_to_frequency(channel_number, channel->band); + channel = ieee80211_get_channel(wiphy, freq); + if (!channel) + return NULL; + if (channel->flags & IEEE80211_CHAN_DISABLED) + return NULL; + return channel; +} + struct cfg80211_bss* cfg80211_inform_bss(struct wiphy *wiphy, struct ieee80211_channel *channel, @@ -790,6 +822,10 @@ cfg80211_inform_bss(struct wiphy *wiphy, (signal < 0 || signal > 100))) return NULL; + channel = cfg80211_get_bss_channel(wiphy, ie, ielen, channel); + if (!channel) + return NULL; + res = kzalloc(sizeof(*res) + privsz + ielen, gfp); if (!res) return NULL; @@ -839,11 +875,13 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy, s32 signal, gfp_t gfp) { struct cfg80211_internal_bss *res; - size_t ielen = len - offsetof(struct ieee80211_mgmt, u.probe_resp.variable); size_t privsz; + BUILD_BUG_ON(offsetof(struct ieee80211_mgmt, u.probe_resp.variable) != + offsetof(struct ieee80211_mgmt, u.beacon.variable)); + trace_cfg80211_inform_bss_frame(wiphy, channel, mgmt, len, signal); if (WARN_ON(!mgmt)) @@ -861,6 +899,11 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy, privsz = wiphy->bss_priv_size; + channel = cfg80211_get_bss_channel(wiphy, mgmt->u.beacon.variable, + ielen, channel); + if (!channel) + return NULL; + res = kzalloc(sizeof(*res) + privsz + ielen, gfp); if (!res) return NULL; diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 8e03c63..2134576 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -20,29 +20,26 @@ #define MAC_PR_FMT "%pM" #define MAC_PR_ARG(entry_mac) (__entry->entry_mac) -#define WIPHY_ENTRY MAC_ENTRY(wiphy_mac) -#define WIPHY_ASSIGN MAC_ASSIGN(wiphy_mac, wiphy->perm_addr) -#define WIPHY_PR_FMT "wiphy " MAC_PR_FMT -#define WIPHY_PR_ARG MAC_PR_ARG(wiphy_mac) - -#define WDEV_ENTRY __field(u32, id) -#define WDEV_ASSIGN (__entry->id) = (wdev ? wdev->identifier : 0) -#define WDEV_PR_FMT ", wdev id: %u" -#define WDEV_PR_ARG (__entry->id) - -#define NETDEV_ENTRY __array(char, name, IFNAMSIZ) \ - MAC_ENTRY(netdev_addr) \ - __field(int, ifindex) +#define MAXNAME 32 +#define WIPHY_ENTRY __array(char, wiphy_name, 32) +#define WIPHY_ASSIGN strlcpy(__entry->wiphy_name, wiphy_name(wiphy), MAXNAME) +#define WIPHY_PR_FMT "%s" +#define WIPHY_PR_ARG __entry->wiphy_name + +#define WDEV_ENTRY __field(u32, id) +#define WDEV_ASSIGN (__entry->id) = (wdev ? wdev->identifier : 0) +#define WDEV_PR_FMT "wdev(%u)" +#define WDEV_PR_ARG (__entry->id) + +#define NETDEV_ENTRY __array(char, name, IFNAMSIZ) \ + __field(int, ifindex) #define NETDEV_ASSIGN \ do { \ memcpy(__entry->name, netdev->name, IFNAMSIZ); \ - MAC_ASSIGN(netdev_addr, netdev->dev_addr); \ (__entry->ifindex) = (netdev->ifindex); \ } while (0) -#define NETDEV_PR_FMT ", netdev - name: %s, addr: " MAC_PR_FMT \ - ", intf index: %d" -#define NETDEV_PR_ARG (__entry->name), MAC_PR_ARG(netdev_addr), \ - (__entry->ifindex) +#define NETDEV_PR_FMT "netdev:%s(%d)" +#define NETDEV_PR_ARG __entry->name, __entry->ifindex #define MESH_CFG_ENTRY __field(u16, dot11MeshRetryTimeout) \ __field(u16, dot11MeshConfirmTimeout) \ @@ -123,9 +120,37 @@ __entry->center_freq = 0; \ } \ } while (0) -#define CHAN_PR_FMT ", band: %d, freq: %u" +#define CHAN_PR_FMT "band: %d, freq: %u" #define CHAN_PR_ARG __entry->band, __entry->center_freq +#define CHAN_DEF_ENTRY __field(enum ieee80211_band, band) \ + __field(u32, control_freq) \ + __field(u32, width) \ + __field(u32, center_freq1) \ + __field(u32, center_freq2) +#define CHAN_DEF_ASSIGN(chandef) \ + do { \ + if ((chandef) && (chandef)->chan) { \ + __entry->band = (chandef)->chan->band; \ + __entry->control_freq = \ + (chandef)->chan->center_freq; \ + __entry->width = (chandef)->width; \ + __entry->center_freq1 = (chandef)->center_freq1;\ + __entry->center_freq2 = (chandef)->center_freq2;\ + } else { \ + __entry->band = 0; \ + __entry->control_freq = 0; \ + __entry->width = 0; \ + __entry->center_freq1 = 0; \ + __entry->center_freq2 = 0; \ + } \ + } while (0) +#define CHAN_DEF_PR_FMT \ + "band: %d, control freq: %u, width: %d, cf1: %u, cf2: %u" +#define CHAN_DEF_PR_ARG __entry->band, __entry->control_freq, \ + __entry->width, __entry->center_freq1, \ + __entry->center_freq2 + #define SINFO_ENTRY __field(int, generation) \ __field(u32, connected_time) \ __field(u32, inactive_time) \ @@ -313,7 +338,7 @@ DECLARE_EVENT_CLASS(wiphy_wdev_evt, WIPHY_ASSIGN; WDEV_ASSIGN; ), - TP_printk(WIPHY_PR_FMT WDEV_PR_FMT, WIPHY_PR_ARG, WDEV_PR_ARG) + TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT, WIPHY_PR_ARG, WDEV_PR_ARG) ); DEFINE_EVENT(wiphy_wdev_evt, rdev_return_wdev, @@ -340,7 +365,7 @@ TRACE_EVENT(rdev_change_virtual_intf, NETDEV_ASSIGN; __entry->type = type; ), - TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", type: %d", + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", type: %d", WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->type) ); @@ -362,7 +387,7 @@ DECLARE_EVENT_CLASS(key_handle, __entry->key_index = key_index; __entry->pairwise = pairwise; ), - TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", key_index: %u, pairwise: %s, mac addr: " MAC_PR_FMT, + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", key_index: %u, pairwise: %s, mac addr: " MAC_PR_FMT, WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->key_index, BOOL_TO_STR(__entry->pairwise), MAC_PR_ARG(mac_addr)) ); @@ -403,7 +428,7 @@ TRACE_EVENT(rdev_set_default_key, __entry->unicast = unicast; __entry->multicast = multicast; ), - TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", key index: %u, unicast: %s, multicast: %s", + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", key index: %u, unicast: %s, multicast: %s", WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->key_index, BOOL_TO_STR(__entry->unicast), BOOL_TO_STR(__entry->multicast)) @@ -422,7 +447,7 @@ TRACE_EVENT(rdev_set_default_mgmt_key, NETDEV_ASSIGN; __entry->key_index = key_index; ), - TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", key index: %u", + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", key index: %u", WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->key_index) ); @@ -433,7 +458,7 @@ TRACE_EVENT(rdev_start_ap, TP_STRUCT__entry( WIPHY_ENTRY NETDEV_ENTRY - CHAN_ENTRY + CHAN_DEF_ENTRY __field(int, beacon_interval) __field(int, dtim_period) __array(char, ssid, IEEE80211_MAX_SSID_LEN + 1) @@ -446,7 +471,7 @@ TRACE_EVENT(rdev_start_ap, TP_fast_assign( WIPHY_ASSIGN; NETDEV_ASSIGN; - CHAN_ASSIGN(settings->channel); + CHAN_DEF_ASSIGN(&settings->chandef); __entry->beacon_interval = settings->beacon_interval; __entry->dtim_period = settings->dtim_period; __entry->hidden_ssid = settings->hidden_ssid; @@ -457,11 +482,11 @@ TRACE_EVENT(rdev_start_ap, memset(__entry->ssid, 0, IEEE80211_MAX_SSID_LEN + 1); memcpy(__entry->ssid, settings->ssid, settings->ssid_len); ), - TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", AP settings - ssid: %s, " - CHAN_PR_FMT ", beacon interval: %d, dtim period: %d, " + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", AP settings - ssid: %s, " + CHAN_DEF_PR_FMT ", beacon interval: %d, dtim period: %d, " "hidden ssid: %d, wpa versions: %u, privacy: %s, " "auth type: %d, inactivity timeout: %d", - WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->ssid, CHAN_PR_ARG, + WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->ssid, CHAN_DEF_PR_ARG, __entry->beacon_interval, __entry->dtim_period, __entry->hidden_ssid, __entry->wpa_ver, BOOL_TO_STR(__entry->privacy), __entry->auth_type, @@ -510,7 +535,7 @@ TRACE_EVENT(rdev_change_beacon, info->probe_resp, info->probe_resp_len); } ), - TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT, WIPHY_PR_ARG, NETDEV_PR_ARG) + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT, WIPHY_PR_ARG, NETDEV_PR_ARG) ); DECLARE_EVENT_CLASS(wiphy_netdev_evt, @@ -524,7 +549,7 @@ DECLARE_EVENT_CLASS(wiphy_netdev_evt, WIPHY_ASSIGN; NETDEV_ASSIGN; ), - TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT, WIPHY_PR_ARG, NETDEV_PR_ARG) + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT, WIPHY_PR_ARG, NETDEV_PR_ARG) ); DEFINE_EVENT(wiphy_netdev_evt, rdev_stop_ap, @@ -602,7 +627,7 @@ DECLARE_EVENT_CLASS(station_add_change, memcpy(__entry->ht_capa, params->ht_capa, sizeof(struct ieee80211_ht_cap)); ), - TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", station mac: " MAC_PR_FMT + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", station mac: " MAC_PR_FMT ", station flags mask: %u, station flags set: %u, " "station modify mask: %u, listen interval: %d, aid: %u, " "plink action: %u, plink state: %u, uapsd queues: %u", @@ -638,7 +663,7 @@ DECLARE_EVENT_CLASS(wiphy_netdev_mac_evt, NETDEV_ASSIGN; MAC_ASSIGN(sta_mac, mac); ), - TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", mac: " MAC_PR_FMT, + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", mac: " MAC_PR_FMT, WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(sta_mac)) ); @@ -678,7 +703,7 @@ TRACE_EVENT(rdev_dump_station, MAC_ASSIGN(sta_mac, mac); __entry->idx = idx; ), - TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", station mac: " MAC_PR_FMT ", idx: %d", + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", station mac: " MAC_PR_FMT ", idx: %d", WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(sta_mac), __entry->idx) ); @@ -716,7 +741,7 @@ DECLARE_EVENT_CLASS(mpath_evt, MAC_ASSIGN(dst, dst); MAC_ASSIGN(next_hop, next_hop); ), - TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", destination: " MAC_PR_FMT ", next hop: " MAC_PR_FMT, + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", destination: " MAC_PR_FMT ", next hop: " MAC_PR_FMT, WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(dst), MAC_PR_ARG(next_hop)) ); @@ -757,7 +782,7 @@ TRACE_EVENT(rdev_dump_mpath, MAC_ASSIGN(next_hop, next_hop); __entry->idx = idx; ), - TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", index: %d, destination: " + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", index: %d, destination: " MAC_PR_FMT ", next hop: " MAC_PR_FMT, WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->idx, MAC_PR_ARG(dst), MAC_PR_ARG(next_hop)) @@ -834,7 +859,7 @@ TRACE_EVENT(rdev_update_mesh_config, MESH_CFG_ASSIGN; __entry->mask = mask; ), - TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", mask: %u", + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", mask: %u", WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->mask) ); @@ -853,7 +878,7 @@ TRACE_EVENT(rdev_join_mesh, NETDEV_ASSIGN; MESH_CFG_ASSIGN; ), - TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT, + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT, WIPHY_PR_ARG, NETDEV_PR_ARG) ); @@ -879,7 +904,7 @@ TRACE_EVENT(rdev_change_bss, __entry->ap_isolate = params->ap_isolate; __entry->ht_opmode = params->ht_opmode; ), - TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", use cts prot: %d, " + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", use cts prot: %d, " "use short preamble: %d, use short slot time: %d, " "ap isolate: %d, ht opmode: %d", WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->use_cts_prot, @@ -909,7 +934,7 @@ TRACE_EVENT(rdev_set_txq_params, __entry->cwmax = params->cwmax; __entry->aifs = params->aifs; ), - TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", ac: %d, txop: %u, cwmin: %u, cwmax: %u, aifs: %u", + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", ac: %d, txop: %u, cwmin: %u, cwmax: %u, aifs: %u", WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->ac, __entry->txop, __entry->cwmin, __entry->cwmax, __entry->aifs) ); @@ -928,26 +953,24 @@ TRACE_EVENT(rdev_libertas_set_mesh_channel, NETDEV_ASSIGN; CHAN_ASSIGN(chan); ), - TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT CHAN_PR_FMT, WIPHY_PR_ARG, + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " CHAN_PR_FMT, WIPHY_PR_ARG, NETDEV_PR_ARG, CHAN_PR_ARG) ); TRACE_EVENT(rdev_set_monitor_channel, - TP_PROTO(struct wiphy *wiphy, struct ieee80211_channel *chan, - enum nl80211_channel_type chan_type), - TP_ARGS(wiphy, chan, chan_type), + TP_PROTO(struct wiphy *wiphy, + struct cfg80211_chan_def *chandef), + TP_ARGS(wiphy, chandef), TP_STRUCT__entry( WIPHY_ENTRY - CHAN_ENTRY - __field(enum nl80211_channel_type, chan_type) + CHAN_DEF_ENTRY ), TP_fast_assign( WIPHY_ASSIGN; - CHAN_ASSIGN(chan); - __entry->chan_type = chan_type; + CHAN_DEF_ASSIGN(chandef); ), - TP_printk(WIPHY_PR_FMT CHAN_PR_FMT ", channel type : %d", - WIPHY_PR_ARG, CHAN_PR_ARG, __entry->chan_type) + TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT, + WIPHY_PR_ARG, CHAN_DEF_PR_ARG) ); TRACE_EVENT(rdev_auth, @@ -969,7 +992,7 @@ TRACE_EVENT(rdev_auth, memset(__entry->bssid, 0, ETH_ALEN); __entry->auth_type = req->auth_type; ), - TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", auth type: %d, bssid: " MAC_PR_FMT, + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", auth type: %d, bssid: " MAC_PR_FMT, WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->auth_type, MAC_PR_ARG(bssid)) ); @@ -997,7 +1020,7 @@ TRACE_EVENT(rdev_assoc, __entry->use_mfp = req->use_mfp; __entry->flags = req->flags; ), - TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", bssid: " MAC_PR_FMT + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", bssid: " MAC_PR_FMT ", previous bssid: " MAC_PR_FMT ", use mfp: %s, flags: %u", WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(bssid), MAC_PR_ARG(prev_bssid), BOOL_TO_STR(__entry->use_mfp), @@ -1020,7 +1043,7 @@ TRACE_EVENT(rdev_deauth, MAC_ASSIGN(bssid, req->bssid); __entry->reason_code = req->reason_code; ), - TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", bssid: " MAC_PR_FMT ", reason: %u", + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", bssid: " MAC_PR_FMT ", reason: %u", WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(bssid), __entry->reason_code) ); @@ -1046,7 +1069,7 @@ TRACE_EVENT(rdev_disassoc, __entry->reason_code = req->reason_code; __entry->local_state_change = req->local_state_change; ), - TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", bssid: " MAC_PR_FMT + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", bssid: " MAC_PR_FMT ", reason: %u, local state change: %s", WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(bssid), __entry->reason_code, @@ -1067,7 +1090,7 @@ TRACE_EVENT(rdev_mgmt_tx_cancel_wait, WDEV_ASSIGN; __entry->cookie = cookie; ), - TP_printk(WIPHY_PR_FMT WDEV_PR_FMT ", cookie: %llu ", + TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", cookie: %llu ", WIPHY_PR_ARG, WDEV_PR_ARG, __entry->cookie) ); @@ -1087,7 +1110,7 @@ TRACE_EVENT(rdev_set_power_mgmt, __entry->enabled = enabled; __entry->timeout = timeout; ), - TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", %senabled, timeout: %d ", + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", %senabled, timeout: %d ", WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->enabled ? "" : "not ", __entry->timeout) ); @@ -1117,7 +1140,7 @@ TRACE_EVENT(rdev_connect, __entry->wpa_versions = sme->crypto.wpa_versions; __entry->flags = sme->flags; ), - TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", bssid: " MAC_PR_FMT + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", bssid: " MAC_PR_FMT ", ssid: %s, auth type: %d, privacy: %s, wpa versions: %u, " "flags: %u", WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(bssid), __entry->ssid, @@ -1142,7 +1165,7 @@ TRACE_EVENT(rdev_set_cqm_rssi_config, __entry->rssi_thold = rssi_thold; __entry->rssi_hyst = rssi_hyst; ), - TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", rssi_thold: %d, rssi_hyst: %u ", WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->rssi_thold, __entry->rssi_hyst) @@ -1166,7 +1189,7 @@ TRACE_EVENT(rdev_set_cqm_txe_config, __entry->pkts = pkts; __entry->intvl = intvl; ), - TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", rate: %u, packets: %u, interval: %u", + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", rate: %u, packets: %u, interval: %u", WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->rate, __entry->pkts, __entry->intvl) ); @@ -1185,7 +1208,7 @@ TRACE_EVENT(rdev_disconnect, NETDEV_ASSIGN; __entry->reason_code = reason_code; ), - TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", reason code: %u", WIPHY_PR_ARG, + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", reason code: %u", WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->reason_code) ); @@ -1206,7 +1229,7 @@ TRACE_EVENT(rdev_join_ibss, memset(__entry->ssid, 0, IEEE80211_MAX_SSID_LEN + 1); memcpy(__entry->ssid, params->ssid, params->ssid_len); ), - TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", bssid: " MAC_PR_FMT ", ssid: %s", + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", bssid: " MAC_PR_FMT ", ssid: %s", WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(bssid), __entry->ssid) ); @@ -1246,7 +1269,7 @@ TRACE_EVENT(rdev_set_tx_power, __entry->type = type; __entry->mbm = mbm; ), - TP_printk(WIPHY_PR_FMT WDEV_PR_FMT ", type: %d, mbm: %d", + TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", type: %u, mbm: %d", WIPHY_PR_ARG, WDEV_PR_ARG,__entry->type, __entry->mbm) ); @@ -1307,7 +1330,7 @@ TRACE_EVENT(rdev_set_bitrate_mask, NETDEV_ASSIGN; MAC_ASSIGN(peer, peer); ), - TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", peer: " MAC_PR_FMT, + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", peer: " MAC_PR_FMT, WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer)) ); @@ -1327,7 +1350,7 @@ TRACE_EVENT(rdev_mgmt_frame_register, __entry->frame_type = frame_type; __entry->reg = reg; ), - TP_printk(WIPHY_PR_FMT WDEV_PR_FMT ", frame_type: %u, reg: %s ", + TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", frame_type: 0x%.2x, reg: %s ", WIPHY_PR_ARG, WDEV_PR_ARG, __entry->frame_type, __entry->reg ? "true" : "false") ); @@ -1413,7 +1436,7 @@ TRACE_EVENT(rdev_sched_scan_start, WIPHY_ASSIGN; NETDEV_ASSIGN; ), - TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT, + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT, WIPHY_PR_ARG, NETDEV_PR_ARG) ); @@ -1441,7 +1464,7 @@ TRACE_EVENT(rdev_tdls_mgmt, __entry->status_code = status_code; memcpy(__get_dynamic_array(buf), buf, len); ), - TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT MAC_PR_FMT ", action_code: %u, " + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " MAC_PR_FMT ", action_code: %u, " "dialog_token: %u, status_code: %u, buf: %#.2x ", WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer), __entry->action_code, __entry->dialog_token, @@ -1461,7 +1484,7 @@ TRACE_EVENT(rdev_dump_survey, NETDEV_ASSIGN; __entry->idx = idx; ), - TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", index: %d", + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", index: %d", WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->idx) ); @@ -1518,7 +1541,7 @@ TRACE_EVENT(rdev_tdls_oper, MAC_ASSIGN(peer, peer); __entry->oper = oper; ), - TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT MAC_PR_FMT ", oper: %d", + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " MAC_PR_FMT ", oper: %d", WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer), __entry->oper) ); @@ -1536,7 +1559,7 @@ DECLARE_EVENT_CLASS(rdev_pmksa, NETDEV_ASSIGN; MAC_ASSIGN(bssid, pmksa->bssid); ), - TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", bssid: " MAC_PR_FMT, + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", bssid: " MAC_PR_FMT, WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(bssid)) ); @@ -1554,7 +1577,7 @@ TRACE_EVENT(rdev_probe_client, NETDEV_ASSIGN; MAC_ASSIGN(peer, peer); ), - TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT MAC_PR_FMT, + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " MAC_PR_FMT, WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer)) ); @@ -1573,25 +1596,22 @@ DEFINE_EVENT(rdev_pmksa, rdev_del_pmksa, TRACE_EVENT(rdev_remain_on_channel, TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type, unsigned int duration), - TP_ARGS(wiphy, wdev, chan, channel_type, duration), + unsigned int duration), + TP_ARGS(wiphy, wdev, chan, duration), TP_STRUCT__entry( WIPHY_ENTRY WDEV_ENTRY CHAN_ENTRY - __field(enum nl80211_channel_type, channel_type) __field(unsigned int, duration) ), TP_fast_assign( WIPHY_ASSIGN; WDEV_ASSIGN; CHAN_ASSIGN(chan); - __entry->channel_type = channel_type; __entry->duration = duration; ), - TP_printk(WIPHY_PR_FMT WDEV_PR_FMT CHAN_PR_FMT ", channel type: %d, duration: %u", - WIPHY_PR_ARG, WDEV_PR_ARG, CHAN_PR_ARG, __entry->channel_type, - __entry->duration) + TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", " CHAN_PR_FMT ", duration: %u", + WIPHY_PR_ARG, WDEV_PR_ARG, CHAN_PR_ARG, __entry->duration) ); TRACE_EVENT(rdev_return_int_cookie, @@ -1624,25 +1644,20 @@ TRACE_EVENT(rdev_cancel_remain_on_channel, WDEV_ASSIGN; __entry->cookie = cookie; ), - TP_printk(WIPHY_PR_FMT WDEV_PR_FMT ", cookie: %llu", + TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", cookie: %llu", WIPHY_PR_ARG, WDEV_PR_ARG, __entry->cookie) ); TRACE_EVENT(rdev_mgmt_tx, TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, struct ieee80211_channel *chan, bool offchan, - enum nl80211_channel_type channel_type, - bool channel_type_valid, unsigned int wait, bool no_cck, - bool dont_wait_for_ack), - TP_ARGS(wiphy, wdev, chan, offchan, channel_type, channel_type_valid, - wait, no_cck, dont_wait_for_ack), + unsigned int wait, bool no_cck, bool dont_wait_for_ack), + TP_ARGS(wiphy, wdev, chan, offchan, wait, no_cck, dont_wait_for_ack), TP_STRUCT__entry( WIPHY_ENTRY WDEV_ENTRY CHAN_ENTRY __field(bool, offchan) - __field(enum nl80211_channel_type, channel_type) - __field(bool, channel_type_valid) __field(unsigned int, wait) __field(bool, no_cck) __field(bool, dont_wait_for_ack) @@ -1652,18 +1667,14 @@ TRACE_EVENT(rdev_mgmt_tx, WDEV_ASSIGN; CHAN_ASSIGN(chan); __entry->offchan = offchan; - __entry->channel_type = channel_type; - __entry->channel_type_valid = channel_type_valid; __entry->wait = wait; __entry->no_cck = no_cck; __entry->dont_wait_for_ack = dont_wait_for_ack; ), - TP_printk(WIPHY_PR_FMT WDEV_PR_FMT CHAN_PR_FMT ", offchan: %s, " - "channel type: %d, channel type valid: %s, wait: %u, " - "no cck: %s, dont wait for ack: %s", + TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", " CHAN_PR_FMT ", offchan: %s," + " wait: %u, no cck: %s, dont wait for ack: %s", WIPHY_PR_ARG, WDEV_PR_ARG, CHAN_PR_ARG, - BOOL_TO_STR(__entry->offchan), __entry->channel_type, - BOOL_TO_STR(__entry->channel_type_valid), __entry->wait, + BOOL_TO_STR(__entry->offchan), __entry->wait, BOOL_TO_STR(__entry->no_cck), BOOL_TO_STR(__entry->dont_wait_for_ack)) ); @@ -1682,7 +1693,7 @@ TRACE_EVENT(rdev_set_noack_map, NETDEV_ASSIGN; __entry->noack_map = noack_map; ), - TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", noack_map: %u", + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", noack_map: %u", WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->noack_map) ); @@ -1699,7 +1710,7 @@ TRACE_EVENT(rdev_get_et_sset_count, NETDEV_ASSIGN; __entry->sset = sset; ), - TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", sset: %d", + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", sset: %d", WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->sset) ); @@ -1716,7 +1727,7 @@ TRACE_EVENT(rdev_get_et_strings, NETDEV_ASSIGN; __entry->sset = sset; ), - TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", sset: %u", + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", sset: %u", WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->sset) ); @@ -1725,22 +1736,25 @@ DEFINE_EVENT(wiphy_wdev_evt, rdev_get_channel, TP_ARGS(wiphy, wdev) ); -TRACE_EVENT(rdev_return_channel, - TP_PROTO(struct wiphy *wiphy, struct ieee80211_channel *chan, - enum nl80211_channel_type type), - TP_ARGS(wiphy, chan, type), +TRACE_EVENT(rdev_return_chandef, + TP_PROTO(struct wiphy *wiphy, int ret, + struct cfg80211_chan_def *chandef), + TP_ARGS(wiphy, ret, chandef), TP_STRUCT__entry( WIPHY_ENTRY - CHAN_ENTRY - __field(enum nl80211_channel_type, type) + __field(int, ret) + CHAN_DEF_ENTRY ), TP_fast_assign( WIPHY_ASSIGN; - CHAN_ASSIGN(chan); - __entry->type = type; + if (ret == 0) + CHAN_DEF_ASSIGN(chandef); + else + CHAN_DEF_ASSIGN((struct cfg80211_chan_def *)NULL); + __entry->ret = ret; ), - TP_printk(WIPHY_PR_FMT CHAN_PR_FMT ", channel type: %d", - WIPHY_PR_ARG, CHAN_PR_ARG, __entry->type) + TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT ", ret: %d", + WIPHY_PR_ARG, CHAN_DEF_PR_ARG, __entry->ret) ); DEFINE_EVENT(wiphy_wdev_evt, rdev_start_p2p_device, @@ -1819,7 +1833,7 @@ TRACE_EVENT(cfg80211_send_rx_assoc, MAC_ASSIGN(bssid, bss->bssid); CHAN_ASSIGN(bss->channel); ), - TP_printk(NETDEV_PR_FMT MAC_PR_FMT CHAN_PR_FMT, + TP_printk(NETDEV_PR_FMT ", " MAC_PR_FMT ", " CHAN_PR_FMT, NETDEV_PR_ARG, MAC_PR_ARG(bssid), CHAN_PR_ARG) ); @@ -1886,7 +1900,7 @@ TRACE_EVENT(cfg80211_michael_mic_failure, __entry->key_id = key_id; memcpy(__entry->tsc, tsc, 6); ), - TP_printk(NETDEV_PR_FMT MAC_PR_FMT ", key type: %d, key id: %d, tsc: %pm", + TP_printk(NETDEV_PR_FMT ", " MAC_PR_FMT ", key type: %d, key id: %d, tsc: %pm", NETDEV_PR_ARG, MAC_PR_ARG(addr), __entry->key_type, __entry->key_id, __entry->tsc) ); @@ -1894,47 +1908,41 @@ TRACE_EVENT(cfg80211_michael_mic_failure, TRACE_EVENT(cfg80211_ready_on_channel, TP_PROTO(struct wireless_dev *wdev, u64 cookie, struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type, unsigned int duration), - TP_ARGS(wdev, cookie, chan, channel_type, duration), + unsigned int duration), + TP_ARGS(wdev, cookie, chan, duration), TP_STRUCT__entry( WDEV_ENTRY __field(u64, cookie) CHAN_ENTRY - __field(enum nl80211_channel_type, channel_type) __field(unsigned int, duration) ), TP_fast_assign( WDEV_ASSIGN; __entry->cookie = cookie; CHAN_ASSIGN(chan); - __entry->channel_type = channel_type; __entry->duration = duration; ), - TP_printk(WDEV_PR_FMT ", cookie: %llu, " CHAN_PR_FMT ", channel type: %d, duration: %u", + TP_printk(WDEV_PR_FMT ", cookie: %llu, " CHAN_PR_FMT ", duration: %u", WDEV_PR_ARG, __entry->cookie, CHAN_PR_ARG, - __entry->channel_type, __entry->duration) + __entry->duration) ); TRACE_EVENT(cfg80211_ready_on_channel_expired, TP_PROTO(struct wireless_dev *wdev, u64 cookie, - struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type), - TP_ARGS(wdev, cookie, chan, channel_type), + struct ieee80211_channel *chan), + TP_ARGS(wdev, cookie, chan), TP_STRUCT__entry( WDEV_ENTRY __field(u64, cookie) CHAN_ENTRY - __field(enum nl80211_channel_type, channel_type) ), TP_fast_assign( WDEV_ASSIGN; __entry->cookie = cookie; CHAN_ASSIGN(chan); - __entry->channel_type = channel_type; ), - TP_printk(WDEV_PR_FMT ", cookie: %llu, " CHAN_PR_FMT ", channel type: %d", - WDEV_PR_ARG, __entry->cookie, CHAN_PR_ARG, - __entry->channel_type) + TP_printk(WDEV_PR_FMT ", cookie: %llu, " CHAN_PR_FMT, + WDEV_PR_ARG, __entry->cookie, CHAN_PR_ARG) ); TRACE_EVENT(cfg80211_new_sta, @@ -1951,7 +1959,7 @@ TRACE_EVENT(cfg80211_new_sta, MAC_ASSIGN(mac_addr, mac_addr); SINFO_ASSIGN; ), - TP_printk(NETDEV_PR_FMT MAC_PR_FMT, + TP_printk(NETDEV_PR_FMT ", " MAC_PR_FMT, NETDEV_PR_ARG, MAC_PR_ARG(mac_addr)) ); @@ -2010,40 +2018,35 @@ TRACE_EVENT(cfg80211_cqm_rssi_notify, NETDEV_PR_ARG, __entry->rssi_event) ); -TRACE_EVENT(cfg80211_can_beacon_sec_chan, - TP_PROTO(struct wiphy *wiphy, struct ieee80211_channel *channel, - enum nl80211_channel_type channel_type), - TP_ARGS(wiphy, channel, channel_type), +TRACE_EVENT(cfg80211_reg_can_beacon, + TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef), + TP_ARGS(wiphy, chandef), TP_STRUCT__entry( WIPHY_ENTRY - CHAN_ENTRY - __field(enum nl80211_channel_type, channel_type) + CHAN_DEF_ENTRY ), TP_fast_assign( WIPHY_ASSIGN; - CHAN_ASSIGN(channel); - __entry->channel_type = channel_type; + CHAN_DEF_ASSIGN(chandef); ), - TP_printk(WIPHY_PR_FMT CHAN_PR_FMT ", channel_type: %d", - WIPHY_PR_ARG, CHAN_PR_ARG, __entry->channel_type) + TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT, + WIPHY_PR_ARG, CHAN_DEF_PR_ARG) ); TRACE_EVENT(cfg80211_ch_switch_notify, - TP_PROTO(struct net_device *netdev, int freq, - enum nl80211_channel_type type), - TP_ARGS(netdev, freq, type), + TP_PROTO(struct net_device *netdev, + struct cfg80211_chan_def *chandef), + TP_ARGS(netdev, chandef), TP_STRUCT__entry( NETDEV_ENTRY - __field(int, freq) - __field(enum nl80211_channel_type, type) + CHAN_DEF_ENTRY ), TP_fast_assign( NETDEV_ASSIGN; - __entry->freq = freq; - __entry->type = type; + CHAN_DEF_ASSIGN(chandef); ), - TP_printk(NETDEV_PR_FMT ", freq: %d, type: %d", NETDEV_PR_ARG, - __entry->freq, __entry->type) + TP_printk(NETDEV_PR_FMT ", " CHAN_DEF_PR_FMT, + NETDEV_PR_ARG, CHAN_DEF_PR_ARG) ); DECLARE_EVENT_CLASS(cfg80211_rx_evt, @@ -2057,7 +2060,7 @@ DECLARE_EVENT_CLASS(cfg80211_rx_evt, NETDEV_ASSIGN; MAC_ASSIGN(addr, addr); ), - TP_printk(NETDEV_PR_FMT MAC_PR_FMT, NETDEV_PR_ARG, MAC_PR_ARG(addr)) + TP_printk(NETDEV_PR_FMT ", " MAC_PR_FMT, NETDEV_PR_ARG, MAC_PR_ARG(addr)) ); DEFINE_EVENT(cfg80211_rx_evt, cfg80211_ibss_joined, @@ -2091,7 +2094,7 @@ TRACE_EVENT(cfg80211_probe_status, __entry->cookie = cookie; __entry->acked = acked; ), - TP_printk(NETDEV_PR_FMT MAC_PR_FMT ", cookie: %llu, acked: %s", + TP_printk(NETDEV_PR_FMT " addr:" MAC_PR_FMT ", cookie: %llu, acked: %s", NETDEV_PR_ARG, MAC_PR_ARG(addr), __entry->cookie, BOOL_TO_STR(__entry->acked)) ); @@ -2157,6 +2160,29 @@ TRACE_EVENT(cfg80211_report_obss_beacon, WIPHY_PR_ARG, __entry->freq, __entry->sig_dbm) ); +TRACE_EVENT(cfg80211_tdls_oper_request, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, const u8 *peer, + enum nl80211_tdls_operation oper, u16 reason_code), + TP_ARGS(wiphy, netdev, peer, oper, reason_code), + TP_STRUCT__entry( + WIPHY_ENTRY + NETDEV_ENTRY + MAC_ENTRY(peer) + __field(enum nl80211_tdls_operation, oper) + __field(u16, reason_code) + ), + TP_fast_assign( + WIPHY_ASSIGN; + NETDEV_ASSIGN; + MAC_ASSIGN(peer, peer); + __entry->oper = oper; + __entry->reason_code = reason_code; + ), + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", peer: " MAC_PR_FMT ", oper: %d, reason_code %u", + WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer), __entry->oper, + __entry->reason_code) + ); + TRACE_EVENT(cfg80211_scan_done, TP_PROTO(struct cfg80211_scan_request *request, bool aborted), TP_ARGS(request, aborted), @@ -2218,7 +2244,7 @@ TRACE_EVENT(cfg80211_get_bss, __entry->capa_mask = capa_mask; __entry->capa_val = capa_val; ), - TP_printk(WIPHY_PR_FMT CHAN_PR_FMT MAC_PR_FMT ", buf: %#.2x, " + TP_printk(WIPHY_PR_FMT ", " CHAN_PR_FMT ", " MAC_PR_FMT ", buf: %#.2x, " "capa_mask: %d, capa_val: %u", WIPHY_PR_ARG, CHAN_PR_ARG, MAC_PR_ARG(bssid), ((u8 *)__get_dynamic_array(ssid))[0], __entry->capa_mask, __entry->capa_val) @@ -2242,7 +2268,7 @@ TRACE_EVENT(cfg80211_inform_bss_frame, memcpy(__get_dynamic_array(mgmt), mgmt, len); __entry->signal = signal; ), - TP_printk(WIPHY_PR_FMT CHAN_PR_FMT "signal: %d", + TP_printk(WIPHY_PR_FMT ", " CHAN_PR_FMT "signal: %d", WIPHY_PR_ARG, CHAN_PR_ARG, __entry->signal) ); @@ -2257,7 +2283,7 @@ DECLARE_EVENT_CLASS(cfg80211_bss_evt, MAC_ASSIGN(bssid, pub->bssid); CHAN_ASSIGN(pub->channel); ), - TP_printk(MAC_PR_FMT CHAN_PR_FMT, MAC_PR_ARG(bssid), CHAN_PR_ARG) + TP_printk(MAC_PR_FMT ", " CHAN_PR_FMT, MAC_PR_ARG(bssid), CHAN_PR_ARG) ); DEFINE_EVENT(cfg80211_bss_evt, cfg80211_return_bss, diff --git a/net/wireless/util.c b/net/wireless/util.c index b99f01c..3cce6e4 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -944,14 +944,86 @@ static u32 cfg80211_calculate_bitrate_60g(struct rate_info *rate) return __mcs2bitrate[rate->mcs]; } +static u32 cfg80211_calculate_bitrate_vht(struct rate_info *rate) +{ + static const u32 base[4][10] = { + { 6500000, + 13000000, + 19500000, + 26000000, + 39000000, + 52000000, + 58500000, + 65000000, + 78000000, + 0, + }, + { 13500000, + 27000000, + 40500000, + 54000000, + 81000000, + 108000000, + 121500000, + 135000000, + 162000000, + 180000000, + }, + { 29300000, + 58500000, + 87800000, + 117000000, + 175500000, + 234000000, + 263300000, + 292500000, + 351000000, + 390000000, + }, + { 58500000, + 117000000, + 175500000, + 234000000, + 351000000, + 468000000, + 526500000, + 585000000, + 702000000, + 780000000, + }, + }; + u32 bitrate; + int idx; + + if (WARN_ON_ONCE(rate->mcs > 9)) + return 0; + + idx = rate->flags & (RATE_INFO_FLAGS_160_MHZ_WIDTH | + RATE_INFO_FLAGS_80P80_MHZ_WIDTH) ? 3 : + rate->flags & RATE_INFO_FLAGS_80_MHZ_WIDTH ? 2 : + rate->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH ? 1 : 0; + + bitrate = base[idx][rate->mcs]; + bitrate *= rate->nss; + + if (rate->flags & RATE_INFO_FLAGS_SHORT_GI) + bitrate = (bitrate / 9) * 10; + + /* do NOT round down here */ + return (bitrate + 50000) / 100000; +} + u32 cfg80211_calculate_bitrate(struct rate_info *rate) { int modulation, streams, bitrate; - if (!(rate->flags & RATE_INFO_FLAGS_MCS)) + if (!(rate->flags & RATE_INFO_FLAGS_MCS) && + !(rate->flags & RATE_INFO_FLAGS_VHT_MCS)) return rate->legacy; if (rate->flags & RATE_INFO_FLAGS_60G) return cfg80211_calculate_bitrate_60g(rate); + if (rate->flags & RATE_INFO_FLAGS_VHT_MCS) + return cfg80211_calculate_bitrate_vht(rate); /* the formula below does only work for MCS values smaller than 32 */ if (WARN_ON_ONCE(rate->mcs >= 32)) @@ -980,8 +1052,9 @@ u32 cfg80211_calculate_bitrate(struct rate_info *rate) } EXPORT_SYMBOL(cfg80211_calculate_bitrate); -unsigned int cfg80211_get_p2p_attr(const u8 *ies, unsigned int len, - u8 attr, u8 *buf, unsigned int bufsize) +int cfg80211_get_p2p_attr(const u8 *ies, unsigned int len, + enum ieee80211_p2p_attr_id attr, + u8 *buf, unsigned int bufsize) { u8 *out = buf; u16 attr_remaining = 0; diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 742ab6e..f9680c9 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -784,6 +784,9 @@ static int cfg80211_wext_siwfreq(struct net_device *dev, { struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_chan_def chandef = { + .width = NL80211_CHAN_WIDTH_20_NOHT, + }; int freq, err; switch (wdev->iftype) { @@ -797,8 +800,12 @@ static int cfg80211_wext_siwfreq(struct net_device *dev, return freq; if (freq == 0) return -EINVAL; + chandef.center_freq1 = freq; + chandef.chan = ieee80211_get_channel(&rdev->wiphy, freq); + if (!chandef.chan) + return -EINVAL; mutex_lock(&rdev->devlist_mtx); - err = cfg80211_set_monitor_channel(rdev, freq, NL80211_CHAN_NO_HT); + err = cfg80211_set_monitor_channel(rdev, &chandef); mutex_unlock(&rdev->devlist_mtx); return err; case NL80211_IFTYPE_MESH_POINT: @@ -807,9 +814,12 @@ static int cfg80211_wext_siwfreq(struct net_device *dev, return freq; if (freq == 0) return -EINVAL; + chandef.center_freq1 = freq; + chandef.chan = ieee80211_get_channel(&rdev->wiphy, freq); + if (!chandef.chan) + return -EINVAL; mutex_lock(&rdev->devlist_mtx); - err = cfg80211_set_mesh_freq(rdev, wdev, freq, - NL80211_CHAN_NO_HT); + err = cfg80211_set_mesh_channel(rdev, wdev, &chandef); mutex_unlock(&rdev->devlist_mtx); return err; default: @@ -823,8 +833,8 @@ static int cfg80211_wext_giwfreq(struct net_device *dev, { struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); - struct ieee80211_channel *chan; - enum nl80211_channel_type channel_type; + struct cfg80211_chan_def chandef; + int ret; switch (wdev->iftype) { case NL80211_IFTYPE_STATION: @@ -835,10 +845,10 @@ static int cfg80211_wext_giwfreq(struct net_device *dev, if (!rdev->ops->get_channel) return -EINVAL; - chan = rdev_get_channel(rdev, wdev, &channel_type); - if (!chan) - return -EINVAL; - freq->m = chan->center_freq; + ret = rdev_get_channel(rdev, wdev, &chandef); + if (ret) + return ret; + freq->m = chandef.chan->center_freq; freq->e = 6; return 0; default: diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c index 1f773f6..873af63 100644 --- a/net/wireless/wext-sme.c +++ b/net/wireless/wext-sme.c @@ -119,7 +119,16 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev, * channel we disconnected above and reconnect below. */ if (chan && !wdev->wext.connect.ssid_len) { - err = cfg80211_set_monitor_channel(rdev, freq, NL80211_CHAN_NO_HT); + struct cfg80211_chan_def chandef = { + .width = NL80211_CHAN_WIDTH_20_NOHT, + .center_freq1 = freq, + }; + + chandef.chan = ieee80211_get_channel(&rdev->wiphy, freq); + if (chandef.chan) + err = cfg80211_set_monitor_channel(rdev, &chandef); + else + err = -EINVAL; goto out; } |