diff options
256 files changed, 10648 insertions, 7516 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 568ea9373091..46ce7c6d527d 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 e56449506695..e6b5c89469dc 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 fc2de5528dcc..b00000e8aef6 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 debda27df9b0..a1d4ede5b892 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -96,6 +96,7 @@ static struct usb_device_id btusb_table[] = { { USB_DEVICE(0x0c10, 0x0000) }, /* Broadcom BCM20702A0 */ + { USB_DEVICE(0x0b05, 0x17b5) }, { USB_DEVICE(0x04ca, 0x2003) }, { USB_DEVICE(0x0489, 0xe042) }, { USB_DEVICE(0x413c, 0x8197) }, @@ -124,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 c25dcf192fec..1a67a4f829fe 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 11d99ee8de51..0d320cc7769b 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 338c5c42357d..c9f81a388f15 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/ahb.c b/drivers/net/wireless/ath/ath5k/ahb.c index aec33cc207fd..8e8bcc7a4805 100644 --- a/drivers/net/wireless/ath/ath5k/ahb.c +++ b/drivers/net/wireless/ath/ath5k/ahb.c @@ -236,17 +236,4 @@ static struct platform_driver ath_ahb_driver = { }, }; -static int __init -ath5k_ahb_init(void) -{ - return platform_driver_register(&ath_ahb_driver); -} - -static void __exit -ath5k_ahb_exit(void) -{ - platform_driver_unregister(&ath_ahb_driver); -} - -module_init(ath5k_ahb_init); -module_exit(ath5k_ahb_exit); +module_platform_driver(ath_ahb_driver); diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 9f31cfa56cc0..2fd5bab2e22a 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -511,8 +511,9 @@ ath5k_update_bssid_mask_and_opmode(struct ath5k_hw *ah, ath5k_vif_iter(&iter_data, vif->addr, vif); /* Get list of all active MAC addresses */ - ieee80211_iterate_active_interfaces_atomic(ah->hw, ath5k_vif_iter, - &iter_data); + ieee80211_iterate_active_interfaces_atomic( + ah->hw, IEEE80211_IFACE_ITER_RESUME_ALL, + ath5k_vif_iter, &iter_data); memcpy(ah->bssidmask, iter_data.mask, ETH_ALEN); ah->opmode = iter_data.opmode; @@ -1348,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; @@ -3045,8 +3046,9 @@ ath5k_any_vif_assoc(struct ath5k_hw *ah) iter_data.need_set_hw_addr = false; iter_data.found_active = true; - ieee80211_iterate_active_interfaces_atomic(ah->hw, ath5k_vif_iter, - &iter_data); + ieee80211_iterate_active_interfaces_atomic( + ah->hw, IEEE80211_IFACE_ITER_RESUME_ALL, + ath5k_vif_iter, &iter_data); return iter_data.any_assoc; } diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c index 7a28538e6e05..1ea8c8795c8e 100644 --- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c +++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c @@ -452,8 +452,9 @@ ath5k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, iter_data.hw_macaddr = NULL; iter_data.n_stas = 0; iter_data.need_set_hw_addr = false; - ieee80211_iterate_active_interfaces_atomic(ah->hw, ath5k_vif_iter, - &iter_data); + ieee80211_iterate_active_interfaces_atomic( + ah->hw, IEEE80211_IFACE_ITER_RESUME_ALL, + ath5k_vif_iter, &iter_data); /* Set up RX Filter */ if (iter_data.n_stas > 1) { diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c index 0c2dd4771c36..4084b1076286 100644 --- a/drivers/net/wireless/ath/ath5k/reset.c +++ b/drivers/net/wireless/ath/ath5k/reset.c @@ -789,9 +789,9 @@ ath5k_hw_nic_wakeup(struct ath5k_hw *ah, struct ieee80211_channel *channel) * (I don't think it supports 44MHz) */ /* On 2425 initvals TURBO_SHORT is not present */ if (ah->ah_bwmode == AR5K_BWMODE_40MHZ) { - turbo = AR5K_PHY_TURBO_MODE | - (ah->ah_radio == AR5K_RF2425) ? 0 : - AR5K_PHY_TURBO_SHORT; + turbo = AR5K_PHY_TURBO_MODE; + if (ah->ah_radio != AR5K_RF2425) + turbo |= AR5K_PHY_TURBO_SHORT; } else if (ah->ah_bwmode != AR5K_BWMODE_DEFAULT) { if (ah->ah_radio == AR5K_RF5413) { mode |= (ah->ah_bwmode == AR5K_BWMODE_10MHZ) ? diff --git a/drivers/net/wireless/ath/ath6kl/Kconfig b/drivers/net/wireless/ath/ath6kl/Kconfig index d755a5e7ed20..26c4b7220859 100644 --- a/drivers/net/wireless/ath/ath6kl/Kconfig +++ b/drivers/net/wireless/ath/ath6kl/Kconfig @@ -30,3 +30,12 @@ config ATH6KL_DEBUG depends on ATH6KL ---help--- Enables debug support + +config ATH6KL_REGDOMAIN + bool "Atheros ath6kl regdomain support" + depends on ATH6KL + depends on CFG80211_CERTIFICATION_ONUS + ---help--- + Enabling this makes it possible to change the regdomain in + the firmware. This can be only enabled if regulatory requirements + are taken into account. diff --git a/drivers/net/wireless/ath/ath6kl/Makefile b/drivers/net/wireless/ath/ath6kl/Makefile index 8cae8886f17d..cab0ec0d5380 100644 --- a/drivers/net/wireless/ath/ath6kl/Makefile +++ b/drivers/net/wireless/ath/ath6kl/Makefile @@ -34,6 +34,7 @@ ath6kl_core-y += main.o ath6kl_core-y += txrx.o ath6kl_core-y += wmi.o ath6kl_core-y += core.o +ath6kl_core-y += recovery.o ath6kl_core-$(CONFIG_NL80211_TESTMODE) += testmode.o obj-$(CONFIG_ATH6KL_SDIO) += ath6kl_sdio.o diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 277089963eb4..5516a8ccc3c6 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -147,15 +147,15 @@ static bool __ath6kl_cfg80211_sscan_stop(struct ath6kl_vif *vif) { struct ath6kl *ar = vif->ar; - if (ar->state != ATH6KL_STATE_SCHED_SCAN) + if (!test_and_clear_bit(SCHED_SCANNING, &vif->flags)) return false; del_timer_sync(&vif->sched_scan_timer); - ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx, - ATH6KL_HOST_MODE_AWAKE); + if (ar->state == ATH6KL_STATE_RECOVERY) + return true; - ar->state = ATH6KL_STATE_ON; + ath6kl_wmi_enable_sched_scan_cmd(ar->wmi, vif->fw_vif_idx, false); return true; } @@ -369,17 +369,13 @@ static int ath6kl_nliftype_to_drv_iftype(enum nl80211_iftype type, u8 *nw_type) { switch (type) { case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_CLIENT: *nw_type = INFRA_NETWORK; break; case NL80211_IFTYPE_ADHOC: *nw_type = ADHOC_NETWORK; break; case NL80211_IFTYPE_AP: - *nw_type = AP_NETWORK; - break; - case NL80211_IFTYPE_P2P_CLIENT: - *nw_type = INFRA_NETWORK; - break; case NL80211_IFTYPE_P2P_GO: *nw_type = AP_NETWORK; break; @@ -1031,30 +1027,15 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, vif->scan_req = request; - if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX, - ar->fw_capabilities)) { - /* - * If capable of doing P2P mgmt operations using - * station interface, send additional information like - * supported rates to advertise and xmit rates for - * probe requests - */ - ret = ath6kl_wmi_beginscan_cmd(ar->wmi, vif->fw_vif_idx, - WMI_LONG_SCAN, force_fg_scan, - false, 0, - ATH6KL_FG_SCAN_INTERVAL, - n_channels, channels, - request->no_cck, - request->rates); - } else { - ret = ath6kl_wmi_startscan_cmd(ar->wmi, vif->fw_vif_idx, - WMI_LONG_SCAN, force_fg_scan, - false, 0, - ATH6KL_FG_SCAN_INTERVAL, - n_channels, channels); - } + ret = ath6kl_wmi_beginscan_cmd(ar->wmi, vif->fw_vif_idx, + WMI_LONG_SCAN, force_fg_scan, + false, 0, + ATH6KL_FG_SCAN_INTERVAL, + n_channels, channels, + request->no_cck, + request->rates); if (ret) { - ath6kl_err("wmi_startscan_cmd failed\n"); + ath6kl_err("failed to start scan: %d\n", ret); vif->scan_req = NULL; } @@ -1093,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, @@ -1384,11 +1368,8 @@ static int ath6kl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) return 0; } -/* - * The type nl80211_tx_power_setting replaces the following - * data type from 2.6.36 onwards -*/ static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy, + struct wireless_dev *wdev, enum nl80211_tx_power_setting type, int mbm) { @@ -1423,7 +1404,9 @@ static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy, return 0; } -static int ath6kl_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm) +static int ath6kl_cfg80211_get_txpower(struct wiphy *wiphy, + struct wireless_dev *wdev, + int *dbm) { struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy); struct ath6kl_vif *vif; @@ -1614,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) { /* @@ -1889,7 +1872,7 @@ static int ath6kl_wow_usr(struct ath6kl *ar, struct ath6kl_vif *vif, struct cfg80211_wowlan *wow, u32 *filter) { int ret, pos; - u8 mask[WOW_MASK_SIZE]; + u8 mask[WOW_PATTERN_SIZE]; u16 i; /* Configure the patterns that we received from the user. */ @@ -2107,33 +2090,16 @@ static int ath6kl_cfg80211_host_sleep(struct ath6kl *ar, struct ath6kl_vif *vif) return ret; } -static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) +static int ath6kl_wow_suspend_vif(struct ath6kl_vif *vif, + struct cfg80211_wowlan *wow, u32 *filter) { + struct ath6kl *ar = vif->ar; struct in_device *in_dev; struct in_ifaddr *ifa; - struct ath6kl_vif *vif; int ret; - u32 filter = 0; u16 i, bmiss_time; - u8 index = 0; __be32 ips[MAX_IP_ADDRS]; - - /* The FW currently can't support multi-vif WoW properly. */ - if (ar->num_vif > 1) - return -EIO; - - vif = ath6kl_vif_first(ar); - if (!vif) - return -EIO; - - if (!ath6kl_cfg80211_ready(vif)) - return -EIO; - - if (!test_bit(CONNECTED, &vif->flags)) - return -ENOTCONN; - - if (wow && (wow->n_patterns > WOW_MAX_FILTERS_PER_LIST)) - return -EINVAL; + u8 index = 0; if (!test_bit(NETDEV_MCAST_ALL_ON, &vif->flags) && test_bit(ATH6KL_FW_CAPABILITY_WOW_MULTICAST_FILTER, @@ -2155,7 +2121,7 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) * the user. */ if (wow) - ret = ath6kl_wow_usr(ar, vif, wow, &filter); + ret = ath6kl_wow_usr(ar, vif, wow, filter); else if (vif->nw_type == AP_NETWORK) ret = ath6kl_wow_ap(ar, vif); else @@ -2190,12 +2156,10 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) return ret; } - ar->state = ATH6KL_STATE_SUSPENDING; - /* Setup own IP addr for ARP agent. */ in_dev = __in_dev_get_rtnl(vif->ndev); if (!in_dev) - goto skip_arp; + return 0; ifa = in_dev->ifa_list; memset(&ips, 0, sizeof(ips)); @@ -2218,41 +2182,61 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) return ret; } -skip_arp: - ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, vif->fw_vif_idx, + return ret; +} + +static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) +{ + struct ath6kl_vif *first_vif, *vif; + int ret = 0; + u32 filter = 0; + bool connected = false; + + /* enter / leave wow suspend on first vif always */ + first_vif = ath6kl_vif_first(ar); + if (WARN_ON(unlikely(!first_vif)) || + !ath6kl_cfg80211_ready(first_vif)) + return -EIO; + + if (wow && (wow->n_patterns > WOW_MAX_FILTERS_PER_LIST)) + return -EINVAL; + + /* install filters for each connected vif */ + spin_lock_bh(&ar->list_lock); + list_for_each_entry(vif, &ar->vif_list, list) { + if (!test_bit(CONNECTED, &vif->flags) || + !ath6kl_cfg80211_ready(vif)) + continue; + connected = true; + + ret = ath6kl_wow_suspend_vif(vif, wow, &filter); + if (ret) + break; + } + spin_unlock_bh(&ar->list_lock); + + if (!connected) + return -ENOTCONN; + else if (ret) + return ret; + + ar->state = ATH6KL_STATE_SUSPENDING; + + ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, first_vif->fw_vif_idx, ATH6KL_WOW_MODE_ENABLE, filter, WOW_HOST_REQ_DELAY); if (ret) return ret; - ret = ath6kl_cfg80211_host_sleep(ar, vif); - if (ret) - return ret; - - return 0; + return ath6kl_cfg80211_host_sleep(ar, first_vif); } -static int ath6kl_wow_resume(struct ath6kl *ar) +static int ath6kl_wow_resume_vif(struct ath6kl_vif *vif) { - struct ath6kl_vif *vif; + struct ath6kl *ar = vif->ar; int ret; - vif = ath6kl_vif_first(ar); - if (!vif) - return -EIO; - - ar->state = ATH6KL_STATE_RESUMING; - - ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx, - ATH6KL_HOST_MODE_AWAKE); - if (ret) { - ath6kl_warn("Failed to configure host sleep mode for wow resume: %d\n", - ret); - ar->state = ATH6KL_STATE_WOW; - return ret; - } - if (vif->nw_type != AP_NETWORK) { ret = ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0); @@ -2270,13 +2254,11 @@ static int ath6kl_wow_resume(struct ath6kl *ar) return ret; } - ar->state = ATH6KL_STATE_ON; - if (!test_bit(NETDEV_MCAST_ALL_OFF, &vif->flags) && test_bit(ATH6KL_FW_CAPABILITY_WOW_MULTICAST_FILTER, ar->fw_capabilities)) { ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi, - vif->fw_vif_idx, true); + vif->fw_vif_idx, true); if (ret) return ret; } @@ -2286,6 +2268,48 @@ static int ath6kl_wow_resume(struct ath6kl *ar) return 0; } +static int ath6kl_wow_resume(struct ath6kl *ar) +{ + struct ath6kl_vif *vif; + int ret; + + vif = ath6kl_vif_first(ar); + if (WARN_ON(unlikely(!vif)) || + !ath6kl_cfg80211_ready(vif)) + return -EIO; + + ar->state = ATH6KL_STATE_RESUMING; + + ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx, + ATH6KL_HOST_MODE_AWAKE); + if (ret) { + ath6kl_warn("Failed to configure host sleep mode for wow resume: %d\n", + ret); + goto cleanup; + } + + spin_lock_bh(&ar->list_lock); + list_for_each_entry(vif, &ar->vif_list, list) { + if (!test_bit(CONNECTED, &vif->flags) || + !ath6kl_cfg80211_ready(vif)) + continue; + ret = ath6kl_wow_resume_vif(vif); + if (ret) + break; + } + spin_unlock_bh(&ar->list_lock); + + if (ret) + goto cleanup; + + ar->state = ATH6KL_STATE_ON; + return 0; + +cleanup: + ar->state = ATH6KL_STATE_WOW; + return ret; +} + static int ath6kl_cfg80211_deepsleep_suspend(struct ath6kl *ar) { struct ath6kl_vif *vif; @@ -2422,13 +2446,6 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar, break; - case ATH6KL_CFG_SUSPEND_SCHED_SCAN: - /* - * Nothing needed for schedule scan, firmware is already in - * wow mode and sleeping most of the time. - */ - break; - default: break; } @@ -2476,9 +2493,6 @@ int ath6kl_cfg80211_resume(struct ath6kl *ar) } break; - case ATH6KL_STATE_SCHED_SCAN: - break; - default: break; } @@ -2495,14 +2509,23 @@ static int __ath6kl_cfg80211_suspend(struct wiphy *wiphy, { struct ath6kl *ar = wiphy_priv(wiphy); + ath6kl_recovery_suspend(ar); + return ath6kl_hif_suspend(ar, wow); } static int __ath6kl_cfg80211_resume(struct wiphy *wiphy) { struct ath6kl *ar = wiphy_priv(wiphy); + int err; + + err = ath6kl_hif_resume(ar); + if (err) + return err; - return ath6kl_hif_resume(ar); + ath6kl_recovery_resume(ar); + + return 0; } /* @@ -2739,6 +2762,7 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, int res; int i, ret; u16 rsn_capab = 0; + int inactivity_timeout = 0; ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s:\n", __func__); @@ -2857,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); @@ -2875,14 +2899,22 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, } if (info->inactivity_timeout) { + + inactivity_timeout = info->inactivity_timeout; + + if (ar->hw.flags & ATH6KL_HW_AP_INACTIVITY_MINS) + inactivity_timeout = DIV_ROUND_UP(inactivity_timeout, + 60); + res = ath6kl_wmi_set_inact_period(ar->wmi, vif->fw_vif_idx, - info->inactivity_timeout); + inactivity_timeout); if (res < 0) 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; /* @@ -2898,6 +2930,7 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, WLAN_EID_RSN, WMI_RSN_IE_CAPB, (const u8 *) &rsn_capab, sizeof(rsn_capab)); + vif->rsn_capab = rsn_capab; if (res < 0) return res; } @@ -2977,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) { @@ -3136,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); @@ -3211,7 +3241,7 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy, struct ath6kl *ar = ath6kl_priv(dev); struct ath6kl_vif *vif = netdev_priv(dev); u16 interval; - int ret; + int ret, rssi_thold; if (ar->state != ATH6KL_STATE_ON) return -EIO; @@ -3219,10 +3249,6 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy, if (vif->sme_state != SME_DISCONNECTED) return -EBUSY; - /* The FW currently can't support multi-vif WoW properly. */ - if (ar->num_vif > 1) - return -EIO; - ath6kl_cfg80211_scan_complete_event(vif, true); ret = ath6kl_set_probed_ssids(ar, vif, request->ssids, @@ -3244,6 +3270,23 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy, return ret; } + if (test_bit(ATH6KL_FW_CAPABILITY_RSSI_SCAN_THOLD, + ar->fw_capabilities)) { + if (request->rssi_thold <= NL80211_SCAN_RSSI_THOLD_OFF) + rssi_thold = 0; + else if (request->rssi_thold < -127) + rssi_thold = -127; + else + rssi_thold = request->rssi_thold; + + ret = ath6kl_wmi_set_rssi_filter_cmd(ar->wmi, vif->fw_vif_idx, + rssi_thold); + if (ret) { + ath6kl_err("failed to set RSSI threshold for scan\n"); + return ret; + } + } + /* fw uses seconds, also make sure that it's >0 */ interval = max_t(u16, 1, request->interval / 1000); @@ -3251,15 +3294,6 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy, interval, interval, vif->bg_scan_period, 0, 0, 0, 3, 0, 0, 0); - ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, vif->fw_vif_idx, - ATH6KL_WOW_MODE_ENABLE, - WOW_FILTER_SSID, - WOW_HOST_REQ_DELAY); - if (ret) { - ath6kl_warn("Failed to enable wow with ssid filter: %d\n", ret); - return ret; - } - /* this also clears IE in fw if it's not set */ ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx, WMI_FRAME_PROBE_REQ, @@ -3270,17 +3304,13 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy, return ret; } - ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx, - ATH6KL_HOST_MODE_ASLEEP); - if (ret) { - ath6kl_warn("Failed to enable host sleep mode for sched scan: %d\n", - ret); + ret = ath6kl_wmi_enable_sched_scan_cmd(ar->wmi, vif->fw_vif_idx, true); + if (ret) return ret; - } - ar->state = ATH6KL_STATE_SCHED_SCAN; + set_bit(SCHED_SCANNING, &vif->flags); - return ret; + return 0; } static int ath6kl_cfg80211_sscan_stop(struct wiphy *wiphy, @@ -3309,6 +3339,27 @@ static int ath6kl_cfg80211_set_bitrate(struct wiphy *wiphy, mask); } +static int ath6kl_cfg80211_set_txe_config(struct wiphy *wiphy, + struct net_device *dev, + u32 rate, u32 pkts, u32 intvl) +{ + struct ath6kl *ar = ath6kl_priv(dev); + struct ath6kl_vif *vif = netdev_priv(dev); + + if (vif->nw_type != INFRA_NETWORK || + !test_bit(ATH6KL_FW_CAPABILITY_TX_ERR_NOTIFY, ar->fw_capabilities)) + return -EOPNOTSUPP; + + if (vif->sme_state != SME_CONNECTED) + return -ENOTCONN; + + /* save this since the firmware won't report the interval */ + vif->txe_intvl = intvl; + + return ath6kl_wmi_set_txe_notify(ar->wmi, vif->fw_vif_idx, + rate, pkts, intvl); +} + static const struct ieee80211_txrx_stypes ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = { [NL80211_IFTYPE_STATION] = { @@ -3375,6 +3426,7 @@ static struct cfg80211_ops ath6kl_cfg80211_ops = { .sched_scan_start = ath6kl_cfg80211_sscan_start, .sched_scan_stop = ath6kl_cfg80211_sscan_stop, .set_bitrate_mask = ath6kl_cfg80211_set_bitrate, + .set_cqm_txe_config = ath6kl_cfg80211_set_txe_config, }; void ath6kl_cfg80211_stop(struct ath6kl_vif *vif) @@ -3395,16 +3447,22 @@ void ath6kl_cfg80211_stop(struct ath6kl_vif *vif) break; } - if (test_bit(CONNECTED, &vif->flags) || - test_bit(CONNECT_PEND, &vif->flags)) + if (vif->ar->state != ATH6KL_STATE_RECOVERY && + (test_bit(CONNECTED, &vif->flags) || + test_bit(CONNECT_PEND, &vif->flags))) ath6kl_wmi_disconnect_cmd(vif->ar->wmi, vif->fw_vif_idx); vif->sme_state = SME_DISCONNECTED; clear_bit(CONNECTED, &vif->flags); clear_bit(CONNECT_PEND, &vif->flags); + /* Stop netdev queues, needed during recovery */ + netif_stop_queue(vif->ndev); + netif_carrier_off(vif->ndev); + /* disable scanning */ - if (ath6kl_wmi_scanparams_cmd(vif->ar->wmi, vif->fw_vif_idx, 0xFFFF, + if (vif->ar->state != ATH6KL_STATE_RECOVERY && + ath6kl_wmi_scanparams_cmd(vif->ar->wmi, vif->fw_vif_idx, 0xFFFF, 0, 0, 0, 0, 0, 0, 0, 0, 0) != 0) ath6kl_warn("failed to disable scan during stop\n"); @@ -3416,7 +3474,7 @@ void ath6kl_cfg80211_stop_all(struct ath6kl *ar) struct ath6kl_vif *vif; vif = ath6kl_vif_first(ar); - if (!vif) { + if (!vif && ar->state != ATH6KL_STATE_RECOVERY) { /* save the current power mode before enabling power save */ ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode; @@ -3434,6 +3492,56 @@ void ath6kl_cfg80211_stop_all(struct ath6kl *ar) ath6kl_cfg80211_stop(vif); } +static int ath6kl_cfg80211_reg_notify(struct wiphy *wiphy, + struct regulatory_request *request) +{ + struct ath6kl *ar = wiphy_priv(wiphy); + u32 rates[IEEE80211_NUM_BANDS]; + int ret, i; + + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, + "cfg reg_notify %c%c%s%s initiator %d hint_type %d\n", + request->alpha2[0], request->alpha2[1], + request->intersect ? " intersect" : "", + request->processed ? " processed" : "", + request->initiator, request->user_reg_hint_type); + + /* + * As firmware is not able intersect regdoms, we can only listen to + * cellular hints. + */ + if (request->user_reg_hint_type != NL80211_USER_REG_HINT_CELL_BASE) + return -EOPNOTSUPP; + + ret = ath6kl_wmi_set_regdomain_cmd(ar->wmi, request->alpha2); + if (ret) { + ath6kl_err("failed to set regdomain: %d\n", ret); + return ret; + } + + /* + * Firmware will apply the regdomain change only after a scan is + * issued and it will send a WMI_REGDOMAIN_EVENTID when it has been + * changed. + */ + + for (i = 0; i < IEEE80211_NUM_BANDS; i++) + if (wiphy->bands[i]) + rates[i] = (1 << wiphy->bands[i]->n_bitrates) - 1; + + + ret = ath6kl_wmi_beginscan_cmd(ar->wmi, 0, WMI_LONG_SCAN, false, + false, 0, ATH6KL_FG_SCAN_INTERVAL, + 0, NULL, false, rates); + if (ret) { + ath6kl_err("failed to start scan for a regdomain change: %d\n", + ret); + return ret; + } + + return 0; +} + static int ath6kl_cfg80211_vif_init(struct ath6kl_vif *vif) { vif->aggr_cntxt = aggr_init(vif); @@ -3506,9 +3614,13 @@ struct wireless_dev *ath6kl_interface_add(struct ath6kl *ar, const char *name, vif->htcap[IEEE80211_BAND_5GHZ].ht_enable = true; memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN); - if (fw_vif_idx != 0) + if (fw_vif_idx != 0) { ndev->dev_addr[0] = (ndev->dev_addr[0] ^ (1 << fw_vif_idx)) | 0x2; + if (test_bit(ATH6KL_FW_CAPABILITY_CUSTOM_MAC_ADDR, + ar->fw_capabilities)) + ndev->dev_addr[4] ^= 0x80; + } init_netdev(ndev); @@ -3562,6 +3674,12 @@ int ath6kl_cfg80211_init(struct ath6kl *ar) BIT(NL80211_IFTYPE_P2P_CLIENT); } + if (config_enabled(CONFIG_ATH6KL_REGDOMAIN) && + test_bit(ATH6KL_FW_CAPABILITY_REGDOMAIN, ar->fw_capabilities)) { + wiphy->reg_notifier = ath6kl_cfg80211_reg_notify; + ar->wiphy->features |= NL80211_FEATURE_CELL_BASE_REG_HINTS; + } + /* max num of ssids that can be probed during scanning */ wiphy->max_scan_ssids = MAX_PROBED_SSIDS; @@ -3607,7 +3725,7 @@ int ath6kl_cfg80211_init(struct ath6kl *ar) ath6kl_band_5ghz.ht_cap.ht_supported = false; } - if (ar->hw.flags & ATH6KL_HW_FLAG_64BIT_RATES) { + if (ar->hw.flags & ATH6KL_HW_64BIT_RATES) { ath6kl_band_2ghz.ht_cap.mcs.rx_mask[0] = 0xff; ath6kl_band_5ghz.ht_cap.mcs.rx_mask[0] = 0xff; ath6kl_band_2ghz.ht_cap.mcs.rx_mask[1] = 0xff; @@ -3646,7 +3764,7 @@ int ath6kl_cfg80211_init(struct ath6kl *ar) WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD; - if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN, ar->fw_capabilities)) + if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN_V2, ar->fw_capabilities)) ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; if (test_bit(ATH6KL_FW_CAPABILITY_INACTIVITY_TIMEOUT, diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.h b/drivers/net/wireless/ath/ath6kl/cfg80211.h index 780f77775a91..e5e70f3a8ca8 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.h +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.h @@ -22,7 +22,6 @@ enum ath6kl_cfg_suspend_mode { ATH6KL_CFG_SUSPEND_DEEPSLEEP, ATH6KL_CFG_SUSPEND_CUTPOWER, ATH6KL_CFG_SUSPEND_WOW, - ATH6KL_CFG_SUSPEND_SCHED_SCAN, }; struct wireless_dev *ath6kl_interface_add(struct ath6kl *ar, const char *name, diff --git a/drivers/net/wireless/ath/ath6kl/core.c b/drivers/net/wireless/ath/ath6kl/core.c index 82c4dd2a960e..4b46adbe8c92 100644 --- a/drivers/net/wireless/ath/ath6kl/core.c +++ b/drivers/net/wireless/ath/ath6kl/core.c @@ -33,6 +33,8 @@ static unsigned int wow_mode; static unsigned int uart_debug; static unsigned int ath6kl_p2p; static unsigned int testmode; +static unsigned int recovery_enable; +static unsigned int heart_beat_poll; module_param(debug_mask, uint, 0644); module_param(suspend_mode, uint, 0644); @@ -40,6 +42,12 @@ module_param(wow_mode, uint, 0644); module_param(uart_debug, uint, 0644); module_param(ath6kl_p2p, uint, 0644); module_param(testmode, uint, 0644); +module_param(recovery_enable, uint, 0644); +module_param(heart_beat_poll, uint, 0644); +MODULE_PARM_DESC(recovery_enable, "Enable recovery from firmware error"); +MODULE_PARM_DESC(heart_beat_poll, "Enable fw error detection periodic" \ + "polling. This also specifies the polling interval in" \ + "msecs. Set reocvery_enable for this to be effective"); void ath6kl_core_tx_complete(struct ath6kl *ar, struct sk_buff *skb) { @@ -202,6 +210,17 @@ int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type) ath6kl_dbg(ATH6KL_DBG_TRC, "%s: name=%s dev=0x%p, ar=0x%p\n", __func__, wdev->netdev->name, wdev->netdev, ar); + ar->fw_recovery.enable = !!recovery_enable; + if (!ar->fw_recovery.enable) + return ret; + + if (heart_beat_poll && + test_bit(ATH6KL_FW_CAPABILITY_HEART_BEAT_POLL, + ar->fw_capabilities)) + ar->fw_recovery.hb_poll = heart_beat_poll; + + ath6kl_recovery_init(ar); + return ret; err_rxbuf_cleanup: @@ -291,6 +310,8 @@ void ath6kl_core_cleanup(struct ath6kl *ar) { ath6kl_hif_power_off(ar); + ath6kl_recovery_cleanup(ar); + destroy_workqueue(ar->ath6kl_wq); if (ar->htc_target) diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index cec49a31029a..189d8faf8c87 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h @@ -115,6 +115,27 @@ enum ath6kl_fw_capability { */ ATH6KL_FW_CAPABILITY_SCHED_SCAN_MATCH_LIST, + /* Firmware supports filtering BSS results by RSSI */ + ATH6KL_FW_CAPABILITY_RSSI_SCAN_THOLD, + + /* FW sets mac_addr[4] ^= 0x80 for newly created interfaces */ + ATH6KL_FW_CAPABILITY_CUSTOM_MAC_ADDR, + + /* Firmware supports TX error rate notification */ + ATH6KL_FW_CAPABILITY_TX_ERR_NOTIFY, + + /* supports WMI_SET_REGDOMAIN_CMDID command */ + ATH6KL_FW_CAPABILITY_REGDOMAIN, + + /* Firmware supports sched scan decoupled from host sleep */ + ATH6KL_FW_CAPABILITY_SCHED_SCAN_V2, + + /* + * Firmware capability for hang detection through heart beat + * challenge messages. + */ + ATH6KL_FW_CAPABILITY_HEART_BEAT_POLL, + /* this needs to be last */ ATH6KL_FW_CAPABILITY_MAX, }; @@ -128,11 +149,15 @@ struct ath6kl_fw_ie { }; enum ath6kl_hw_flags { - ATH6KL_HW_FLAG_64BIT_RATES = BIT(0), + ATH6KL_HW_64BIT_RATES = BIT(0), + ATH6KL_HW_AP_INACTIVITY_MINS = BIT(1), + ATH6KL_HW_MAP_LP_ENDPOINT = BIT(2), + ATH6KL_HW_SDIO_CRC_ERROR_WAR = BIT(3), }; #define ATH6KL_FW_API2_FILE "fw-2.bin" #define ATH6KL_FW_API3_FILE "fw-3.bin" +#define ATH6KL_FW_API4_FILE "fw-4.bin" /* AR6003 1.0 definitions */ #define AR6003_HW_1_0_VERSION 0x300002ba @@ -186,6 +211,13 @@ enum ath6kl_hw_flags { #define AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE \ AR6004_HW_1_2_FW_DIR "/bdata.bin" +/* AR6004 1.3 definitions */ +#define AR6004_HW_1_3_VERSION 0x31c8088a +#define AR6004_HW_1_3_FW_DIR "ath6k/AR6004/hw1.3" +#define AR6004_HW_1_3_FIRMWARE_FILE "fw.ram.bin" +#define AR6004_HW_1_3_BOARD_DATA_FILE "ath6k/AR6004/hw1.3/bdata.bin" +#define AR6004_HW_1_3_DEFAULT_BOARD_DATA_FILE "ath6k/AR6004/hw1.3/bdata.bin" + /* Per STA data, used in AP mode */ #define STA_PS_AWAKE BIT(0) #define STA_PS_SLEEP BIT(1) @@ -536,6 +568,7 @@ enum ath6kl_vif_state { HOST_SLEEP_MODE_CMD_PROCESSED, NETDEV_MCAST_ALL_ON, NETDEV_MCAST_ALL_OFF, + SCHED_SCANNING, }; struct ath6kl_vif { @@ -580,11 +613,13 @@ struct ath6kl_vif { u16 assoc_bss_beacon_int; u16 listen_intvl_t; u16 bmiss_time_t; + u32 txe_intvl; u16 bg_scan_period; u8 assoc_bss_dtim_period; struct net_device_stats net_stats; struct target_stats target_stats; struct wmi_connect_cmd profile; + u16 rsn_capab; struct list_head mc_filter; }; @@ -609,6 +644,7 @@ enum ath6kl_dev_state { SKIP_SCAN, ROAM_TBL_PEND, FIRST_BOOT, + RECOVERY_CLEANUP, }; enum ath6kl_state { @@ -619,7 +655,16 @@ enum ath6kl_state { ATH6KL_STATE_DEEPSLEEP, ATH6KL_STATE_CUTPOWER, ATH6KL_STATE_WOW, - ATH6KL_STATE_SCHED_SCAN, + ATH6KL_STATE_RECOVERY, +}; + +/* Fw error recovery */ +#define ATH6KL_HB_RESP_MISS_THRES 5 + +enum ath6kl_fw_err { + ATH6KL_FW_ASSERT, + ATH6KL_FW_HB_RESP_FAILURE, + ATH6KL_FW_EP_FULL, }; struct ath6kl { @@ -679,6 +724,7 @@ struct ath6kl { struct ath6kl_req_key ap_mode_bkey; struct sk_buff_head mcastpsq; u32 want_ch_switch; + u16 last_ch; /* * FIXME: protects access to mcastpsq but is actually useless as @@ -764,6 +810,17 @@ struct ath6kl { bool wiphy_registered; + struct ath6kl_fw_recovery { + struct work_struct recovery_work; + unsigned long err_reason; + unsigned long hb_poll; + struct timer_list hb_timer; + u32 seq_num; + bool hb_pending; + u8 hb_misscnt; + bool enable; + } fw_recovery; + #ifdef CONFIG_ATH6KL_DEBUG struct { struct sk_buff_head fwlog_queue; @@ -899,4 +956,12 @@ int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type); void ath6kl_core_cleanup(struct ath6kl *ar); void ath6kl_core_destroy(struct ath6kl *ar); +/* Fw error recovery */ +void ath6kl_init_hw_restart(struct ath6kl *ar); +void ath6kl_recovery_err_notify(struct ath6kl *ar, enum ath6kl_fw_err reason); +void ath6kl_recovery_hb_event(struct ath6kl *ar, u32 cookie); +void ath6kl_recovery_init(struct ath6kl *ar); +void ath6kl_recovery_cleanup(struct ath6kl *ar); +void ath6kl_recovery_suspend(struct ath6kl *ar); +void ath6kl_recovery_resume(struct ath6kl *ar); #endif /* CORE_H */ diff --git a/drivers/net/wireless/ath/ath6kl/debug.h b/drivers/net/wireless/ath/ath6kl/debug.h index 49639d8266c2..f97cd4ead543 100644 --- a/drivers/net/wireless/ath/ath6kl/debug.h +++ b/drivers/net/wireless/ath/ath6kl/debug.h @@ -44,6 +44,7 @@ enum ATH6K_DEBUG_MASK { ATH6KL_DBG_SUSPEND = BIT(20), ATH6KL_DBG_USB = BIT(21), ATH6KL_DBG_USB_BULK = BIT(22), + ATH6KL_DBG_RECOVERY = BIT(23), ATH6KL_DBG_ANY = 0xffffffff /* enable all logs */ }; diff --git a/drivers/net/wireless/ath/ath6kl/hif.c b/drivers/net/wireless/ath/ath6kl/hif.c index 9e47c4a138a7..a6b614421fa4 100644 --- a/drivers/net/wireless/ath/ath6kl/hif.c +++ b/drivers/net/wireless/ath/ath6kl/hif.c @@ -136,6 +136,7 @@ static int ath6kl_hif_proc_dbg_intr(struct ath6kl_device *dev) ath6kl_hif_dump_fw_crash(dev->ar); ath6kl_read_fwlogs(dev->ar); + ath6kl_recovery_err_notify(dev->ar, ATH6KL_FW_ASSERT); return ret; } @@ -693,11 +694,6 @@ int ath6kl_hif_setup(struct ath6kl_device *dev) ath6kl_dbg(ATH6KL_DBG_HIF, "hif block size %d mbox addr 0x%x\n", dev->htc_cnxt->block_sz, dev->ar->mbox_info.htc_addr); - /* usb doesn't support enabling interrupts */ - /* FIXME: remove check once USB support is implemented */ - if (dev->ar->hif_type == ATH6KL_HIF_TYPE_USB) - return 0; - status = ath6kl_hif_disable_intrs(dev); fail_setup: diff --git a/drivers/net/wireless/ath/ath6kl/htc_mbox.c b/drivers/net/wireless/ath/ath6kl/htc_mbox.c index cd0e1ba410d6..fbb78dfe078f 100644 --- a/drivers/net/wireless/ath/ath6kl/htc_mbox.c +++ b/drivers/net/wireless/ath/ath6kl/htc_mbox.c @@ -2492,7 +2492,8 @@ static int ath6kl_htc_mbox_conn_service(struct htc_target *target, max_msg_sz = le16_to_cpu(resp_msg->max_msg_sz); } - if (assigned_ep >= ENDPOINT_MAX || !max_msg_sz) { + if (WARN_ON_ONCE(assigned_ep == ENDPOINT_UNUSED || + assigned_ep >= ENDPOINT_MAX || !max_msg_sz)) { status = -ENOMEM; goto fail_tx; } @@ -2655,12 +2656,6 @@ static int ath6kl_htc_mbox_wait_target(struct htc_target *target) struct htc_service_connect_resp resp; int status; - /* FIXME: remove once USB support is implemented */ - if (target->dev->ar->hif_type == ATH6KL_HIF_TYPE_USB) { - ath6kl_err("HTC doesn't support USB yet. Patience!\n"); - return -EOPNOTSUPP; - } - /* we should be getting 1 control message that the target is ready */ packet = htc_wait_for_ctrl_msg(target); @@ -2890,9 +2885,7 @@ static void ath6kl_htc_mbox_cleanup(struct htc_target *target) { struct htc_packet *packet, *tmp_packet; - /* FIXME: remove check once USB support is implemented */ - if (target->dev->ar->hif_type != ATH6KL_HIF_TYPE_USB) - ath6kl_hif_cleanup_scatter(target->dev->ar); + ath6kl_hif_cleanup_scatter(target->dev->ar); list_for_each_entry_safe(packet, tmp_packet, &target->free_ctrl_txbuf, list) { diff --git a/drivers/net/wireless/ath/ath6kl/htc_pipe.c b/drivers/net/wireless/ath/ath6kl/htc_pipe.c index f9626c723693..ba6bd497b787 100644 --- a/drivers/net/wireless/ath/ath6kl/htc_pipe.c +++ b/drivers/net/wireless/ath/ath6kl/htc_pipe.c @@ -374,9 +374,8 @@ static enum htc_send_queue_result htc_try_send(struct htc_target *target, packet = list_first_entry(txq, struct htc_packet, list); - list_del(&packet->list); - /* insert into local queue */ - list_add_tail(&packet->list, &send_queue); + /* move to local queue */ + list_move_tail(&packet->list, &send_queue); } /* @@ -399,11 +398,10 @@ static enum htc_send_queue_result htc_try_send(struct htc_target *target, * for cleanup */ } else { /* callback wants to keep this packet, - * remove from caller's queue */ - list_del(&packet->list); - /* put it in the send queue */ - list_add_tail(&packet->list, - &send_queue); + * move from caller's queue to the send + * queue */ + list_move_tail(&packet->list, + &send_queue); } } diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c index f90b5db741cf..f21fa322e5ca 100644 --- a/drivers/net/wireless/ath/ath6kl/init.c +++ b/drivers/net/wireless/ath/ath6kl/init.c @@ -42,7 +42,7 @@ static const struct ath6kl_hw hw_list[] = { .reserved_ram_size = 6912, .refclk_hz = 26000000, .uarttx_pin = 8, - .flags = 0, + .flags = ATH6KL_HW_SDIO_CRC_ERROR_WAR, /* hw2.0 needs override address hardcoded */ .app_start_override_addr = 0x944C00, @@ -68,7 +68,7 @@ static const struct ath6kl_hw hw_list[] = { .refclk_hz = 26000000, .uarttx_pin = 8, .testscript_addr = 0x57ef74, - .flags = 0, + .flags = ATH6KL_HW_SDIO_CRC_ERROR_WAR, .fw = { .dir = AR6003_HW_2_1_1_FW_DIR, @@ -93,7 +93,8 @@ static const struct ath6kl_hw hw_list[] = { .board_addr = 0x433900, .refclk_hz = 26000000, .uarttx_pin = 11, - .flags = ATH6KL_HW_FLAG_64BIT_RATES, + .flags = ATH6KL_HW_64BIT_RATES | + ATH6KL_HW_AP_INACTIVITY_MINS, .fw = { .dir = AR6004_HW_1_0_FW_DIR, @@ -113,8 +114,8 @@ static const struct ath6kl_hw hw_list[] = { .board_addr = 0x43d400, .refclk_hz = 40000000, .uarttx_pin = 11, - .flags = ATH6KL_HW_FLAG_64BIT_RATES, - + .flags = ATH6KL_HW_64BIT_RATES | + ATH6KL_HW_AP_INACTIVITY_MINS, .fw = { .dir = AR6004_HW_1_1_FW_DIR, .fw = AR6004_HW_1_1_FIRMWARE_FILE, @@ -133,7 +134,8 @@ static const struct ath6kl_hw hw_list[] = { .board_addr = 0x435c00, .refclk_hz = 40000000, .uarttx_pin = 11, - .flags = ATH6KL_HW_FLAG_64BIT_RATES, + .flags = ATH6KL_HW_64BIT_RATES | + ATH6KL_HW_AP_INACTIVITY_MINS, .fw = { .dir = AR6004_HW_1_2_FW_DIR, @@ -142,6 +144,28 @@ static const struct ath6kl_hw hw_list[] = { .fw_board = AR6004_HW_1_2_BOARD_DATA_FILE, .fw_default_board = AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE, }, + { + .id = AR6004_HW_1_3_VERSION, + .name = "ar6004 hw 1.3", + .dataset_patch_addr = 0x437860, + .app_load_addr = 0x1234, + .board_ext_data_addr = 0x437000, + .reserved_ram_size = 7168, + .board_addr = 0x436400, + .refclk_hz = 40000000, + .uarttx_pin = 11, + .flags = ATH6KL_HW_64BIT_RATES | + ATH6KL_HW_AP_INACTIVITY_MINS | + ATH6KL_HW_MAP_LP_ENDPOINT, + + .fw = { + .dir = AR6004_HW_1_3_FW_DIR, + .fw = AR6004_HW_1_3_FIRMWARE_FILE, + }, + + .fw_board = AR6004_HW_1_3_BOARD_DATA_FILE, + .fw_default_board = AR6004_HW_1_3_DEFAULT_BOARD_DATA_FILE, + }, }; /* @@ -337,7 +361,7 @@ static int ath6kl_init_service_ep(struct ath6kl *ar) if (ath6kl_connectservice(ar, &connect, "WMI DATA BK")) return -EIO; - /* connect to Video service, map this to to HI PRI */ + /* connect to Video service, map this to HI PRI */ connect.svc_id = WMI_DATA_VI_SVC; if (ath6kl_connectservice(ar, &connect, "WMI DATA VI")) return -EIO; @@ -1088,6 +1112,12 @@ int ath6kl_init_fetch_firmwares(struct ath6kl *ar) if (ret) return ret; + ret = ath6kl_fetch_fw_apin(ar, ATH6KL_FW_API4_FILE); + if (ret == 0) { + ar->fw_api = 4; + goto out; + } + ret = ath6kl_fetch_fw_apin(ar, ATH6KL_FW_API3_FILE); if (ret == 0) { ar->fw_api = 3; @@ -1401,8 +1431,7 @@ static int ath6kl_init_upload(struct ath6kl *ar) return status; /* WAR to avoid SDIO CRC err */ - if (ar->version.target_ver == AR6003_HW_2_0_VERSION || - ar->version.target_ver == AR6003_HW_2_1_1_VERSION) { + if (ar->hw.flags & ATH6KL_HW_SDIO_CRC_ERROR_WAR) { ath6kl_err("temporary war to avoid sdio crc error\n"); param = 0x28; @@ -1520,7 +1549,7 @@ static const char *ath6kl_init_get_hif_name(enum ath6kl_hif_type type) return NULL; } -int ath6kl_init_hw_start(struct ath6kl *ar) +static int __ath6kl_init_hw_start(struct ath6kl *ar) { long timeleft; int ret, i; @@ -1616,8 +1645,6 @@ int ath6kl_init_hw_start(struct ath6kl *ar) goto err_htc_stop; } - ar->state = ATH6KL_STATE_ON; - return 0; err_htc_stop: @@ -1630,7 +1657,18 @@ err_power_off: return ret; } -int ath6kl_init_hw_stop(struct ath6kl *ar) +int ath6kl_init_hw_start(struct ath6kl *ar) +{ + int err; + + err = __ath6kl_init_hw_start(ar); + if (err) + return err; + ar->state = ATH6KL_STATE_ON; + return 0; +} + +static int __ath6kl_init_hw_stop(struct ath6kl *ar) { int ret; @@ -1646,11 +1684,37 @@ int ath6kl_init_hw_stop(struct ath6kl *ar) if (ret) ath6kl_warn("failed to power off hif: %d\n", ret); - ar->state = ATH6KL_STATE_OFF; + return 0; +} +int ath6kl_init_hw_stop(struct ath6kl *ar) +{ + int err; + + err = __ath6kl_init_hw_stop(ar); + if (err) + return err; + ar->state = ATH6KL_STATE_OFF; return 0; } +void ath6kl_init_hw_restart(struct ath6kl *ar) +{ + clear_bit(WMI_READY, &ar->flag); + + ath6kl_cfg80211_stop_all(ar); + + if (__ath6kl_init_hw_stop(ar)) { + ath6kl_dbg(ATH6KL_DBG_RECOVERY, "Failed to stop during fw error recovery\n"); + return; + } + + if (__ath6kl_init_hw_start(ar)) { + ath6kl_dbg(ATH6KL_DBG_RECOVERY, "Failed to restart during fw error recovery\n"); + return; + } +} + /* FIXME: move this to cfg80211.c and rename to ath6kl_cfg80211_vif_stop() */ void ath6kl_cleanup_vif(struct ath6kl_vif *vif, bool wmi_ready) { diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c index c189e28e86a9..bd50b6b7b492 100644 --- a/drivers/net/wireless/ath/ath6kl/main.c +++ b/drivers/net/wireless/ath/ath6kl/main.c @@ -293,13 +293,17 @@ int ath6kl_read_fwlogs(struct ath6kl *ar) } address = TARG_VTOP(ar->target_type, debug_hdr_addr); - ath6kl_diag_read(ar, address, &debug_hdr, sizeof(debug_hdr)); + ret = ath6kl_diag_read(ar, address, &debug_hdr, sizeof(debug_hdr)); + if (ret) + goto out; address = TARG_VTOP(ar->target_type, le32_to_cpu(debug_hdr.dbuf_addr)); firstbuf = address; dropped = le32_to_cpu(debug_hdr.dropped); - ath6kl_diag_read(ar, address, &debug_buf, sizeof(debug_buf)); + ret = ath6kl_diag_read(ar, address, &debug_buf, sizeof(debug_buf)); + if (ret) + goto out; loop = 100; @@ -322,7 +326,8 @@ int ath6kl_read_fwlogs(struct ath6kl *ar) address = TARG_VTOP(ar->target_type, le32_to_cpu(debug_buf.next)); - ath6kl_diag_read(ar, address, &debug_buf, sizeof(debug_buf)); + ret = ath6kl_diag_read(ar, address, &debug_buf, + sizeof(debug_buf)); if (ret) goto out; @@ -436,12 +441,9 @@ void ath6kl_connect_ap_mode_bss(struct ath6kl_vif *vif, u16 channel) break; } - if (ar->want_ch_switch & (1 << vif->fw_vif_idx)) { - ar->want_ch_switch &= ~(1 << vif->fw_vif_idx); + if (ar->last_ch != channel) /* we actually don't know the phymode, default to HT20 */ - ath6kl_cfg80211_ch_switch_notify(vif, channel, - WMI_11G_HT20); - } + ath6kl_cfg80211_ch_switch_notify(vif, channel, WMI_11G_HT20); ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx, NONE_BSS_FILTER, 0); set_bit(CONNECTED, &vif->flags); @@ -606,6 +608,18 @@ static int ath6kl_commit_ch_switch(struct ath6kl_vif *vif, u16 channel) switch (vif->nw_type) { case AP_NETWORK: + /* + * reconfigure any saved RSN IE capabilites in the beacon / + * probe response to stay in sync with the supplicant. + */ + if (vif->rsn_capab && + test_bit(ATH6KL_FW_CAPABILITY_RSN_CAP_OVERRIDE, + ar->fw_capabilities)) + ath6kl_wmi_set_ie_cmd(ar->wmi, vif->fw_vif_idx, + WLAN_EID_RSN, WMI_RSN_IE_CAPB, + (const u8 *) &vif->rsn_capab, + sizeof(vif->rsn_capab)); + return ath6kl_wmi_ap_profile_commit(ar->wmi, vif->fw_vif_idx, &vif->profile); default: @@ -628,6 +642,9 @@ static void ath6kl_check_ch_switch(struct ath6kl *ar, u16 channel) if (ar->want_ch_switch & (1 << vif->fw_vif_idx)) res = ath6kl_commit_ch_switch(vif, channel); + /* if channel switch failed, oh well we tried */ + ar->want_ch_switch &= ~(1 << vif->fw_vif_idx); + if (res) ath6kl_err("channel switch failed nw_type %d res %d\n", vif->nw_type, res); @@ -981,8 +998,25 @@ void ath6kl_disconnect_event(struct ath6kl_vif *vif, u8 reason, u8 *bssid, if (vif->nw_type == AP_NETWORK) { /* disconnect due to other STA vif switching channels */ if (reason == BSS_DISCONNECTED && - prot_reason_status == WMI_AP_REASON_STA_ROAM) + prot_reason_status == WMI_AP_REASON_STA_ROAM) { ar->want_ch_switch |= 1 << vif->fw_vif_idx; + /* bail back to this channel if STA vif fails connect */ + ar->last_ch = le16_to_cpu(vif->profile.ch); + } + + if (prot_reason_status == WMI_AP_REASON_MAX_STA) { + /* send max client reached notification to user space */ + cfg80211_conn_failed(vif->ndev, bssid, + NL80211_CONN_FAIL_MAX_CLIENTS, + GFP_KERNEL); + } + + if (prot_reason_status == WMI_AP_REASON_ACL) { + /* send blocked client notification to user space */ + cfg80211_conn_failed(vif->ndev, bssid, + NL80211_CONN_FAIL_BLOCKED_CLIENT, + GFP_KERNEL); + } if (!ath6kl_remove_sta(ar, bssid, prot_reason_status)) return; @@ -1041,6 +1075,9 @@ void ath6kl_disconnect_event(struct ath6kl_vif *vif, u8 reason, u8 *bssid, } } + /* restart disconnected concurrent vifs waiting for new channel */ + ath6kl_check_ch_switch(ar, ar->last_ch); + /* update connect & link status atomically */ spin_lock_bh(&vif->if_lock); clear_bit(CONNECTED, &vif->flags); diff --git a/drivers/net/wireless/ath/ath6kl/recovery.c b/drivers/net/wireless/ath/ath6kl/recovery.c new file mode 100644 index 000000000000..3a8d5e97dc8e --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/recovery.c @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2012 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "core.h" +#include "cfg80211.h" +#include "debug.h" + +static void ath6kl_recovery_work(struct work_struct *work) +{ + struct ath6kl *ar = container_of(work, struct ath6kl, + fw_recovery.recovery_work); + + ar->state = ATH6KL_STATE_RECOVERY; + + del_timer_sync(&ar->fw_recovery.hb_timer); + + ath6kl_init_hw_restart(ar); + + ar->state = ATH6KL_STATE_ON; + clear_bit(WMI_CTRL_EP_FULL, &ar->flag); + + ar->fw_recovery.err_reason = 0; + + if (ar->fw_recovery.hb_poll) + mod_timer(&ar->fw_recovery.hb_timer, jiffies + + msecs_to_jiffies(ar->fw_recovery.hb_poll)); +} + +void ath6kl_recovery_err_notify(struct ath6kl *ar, enum ath6kl_fw_err reason) +{ + if (!ar->fw_recovery.enable) + return; + + ath6kl_dbg(ATH6KL_DBG_RECOVERY, "Fw error detected, reason:%d\n", + reason); + + set_bit(reason, &ar->fw_recovery.err_reason); + + if (!test_bit(RECOVERY_CLEANUP, &ar->flag) && + ar->state != ATH6KL_STATE_RECOVERY) + queue_work(ar->ath6kl_wq, &ar->fw_recovery.recovery_work); +} + +void ath6kl_recovery_hb_event(struct ath6kl *ar, u32 cookie) +{ + if (cookie == ar->fw_recovery.seq_num) + ar->fw_recovery.hb_pending = false; +} + +static void ath6kl_recovery_hb_timer(unsigned long data) +{ + struct ath6kl *ar = (struct ath6kl *) data; + int err; + + if (test_bit(RECOVERY_CLEANUP, &ar->flag) || + (ar->state == ATH6KL_STATE_RECOVERY)) + return; + + if (ar->fw_recovery.hb_pending) + ar->fw_recovery.hb_misscnt++; + else + ar->fw_recovery.hb_misscnt = 0; + + if (ar->fw_recovery.hb_misscnt > ATH6KL_HB_RESP_MISS_THRES) { + ar->fw_recovery.hb_misscnt = 0; + ar->fw_recovery.seq_num = 0; + ar->fw_recovery.hb_pending = false; + ath6kl_recovery_err_notify(ar, ATH6KL_FW_HB_RESP_FAILURE); + return; + } + + ar->fw_recovery.seq_num++; + ar->fw_recovery.hb_pending = true; + + err = ath6kl_wmi_get_challenge_resp_cmd(ar->wmi, + ar->fw_recovery.seq_num, 0); + if (err) + ath6kl_warn("Failed to send hb challenge request, err:%d\n", + err); + + mod_timer(&ar->fw_recovery.hb_timer, jiffies + + msecs_to_jiffies(ar->fw_recovery.hb_poll)); +} + +void ath6kl_recovery_init(struct ath6kl *ar) +{ + struct ath6kl_fw_recovery *recovery = &ar->fw_recovery; + + clear_bit(RECOVERY_CLEANUP, &ar->flag); + INIT_WORK(&recovery->recovery_work, ath6kl_recovery_work); + recovery->seq_num = 0; + recovery->hb_misscnt = 0; + ar->fw_recovery.hb_pending = false; + ar->fw_recovery.hb_timer.function = ath6kl_recovery_hb_timer; + ar->fw_recovery.hb_timer.data = (unsigned long) ar; + init_timer_deferrable(&ar->fw_recovery.hb_timer); + + if (ar->fw_recovery.hb_poll) + mod_timer(&ar->fw_recovery.hb_timer, jiffies + + msecs_to_jiffies(ar->fw_recovery.hb_poll)); +} + +void ath6kl_recovery_cleanup(struct ath6kl *ar) +{ + if (!ar->fw_recovery.enable) + return; + + set_bit(RECOVERY_CLEANUP, &ar->flag); + + del_timer_sync(&ar->fw_recovery.hb_timer); + cancel_work_sync(&ar->fw_recovery.recovery_work); +} + +void ath6kl_recovery_suspend(struct ath6kl *ar) +{ + if (!ar->fw_recovery.enable) + return; + + ath6kl_recovery_cleanup(ar); + + if (!ar->fw_recovery.err_reason) + return; + + /* Process pending fw error detection */ + ar->fw_recovery.err_reason = 0; + WARN_ON(ar->state != ATH6KL_STATE_ON); + ar->state = ATH6KL_STATE_RECOVERY; + ath6kl_init_hw_restart(ar); + ar->state = ATH6KL_STATE_ON; +} + +void ath6kl_recovery_resume(struct ath6kl *ar) +{ + if (!ar->fw_recovery.enable) + return; + + clear_bit(RECOVERY_CLEANUP, &ar->flag); + + if (!ar->fw_recovery.hb_poll) + return; + + ar->fw_recovery.hb_pending = false; + ar->fw_recovery.seq_num = 0; + ar->fw_recovery.hb_misscnt = 0; + mod_timer(&ar->fw_recovery.hb_timer, + jiffies + msecs_to_jiffies(ar->fw_recovery.hb_poll)); +} diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c index 05b95405f7b5..d111980d44c0 100644 --- a/drivers/net/wireless/ath/ath6kl/sdio.c +++ b/drivers/net/wireless/ath/ath6kl/sdio.c @@ -709,7 +709,7 @@ static int ath6kl_sdio_enable_scatter(struct ath6kl *ar) { struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); struct htc_target *target = ar->htc_target; - int ret; + int ret = 0; bool virt_scat = false; if (ar_sdio->scatter_enabled) @@ -844,22 +844,6 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) bool try_deepsleep = false; int ret; - if (ar->state == ATH6KL_STATE_SCHED_SCAN) { - ath6kl_dbg(ATH6KL_DBG_SUSPEND, "sched scan is in progress\n"); - - ret = ath6kl_set_sdio_pm_caps(ar); - if (ret) - goto cut_pwr; - - ret = ath6kl_cfg80211_suspend(ar, - ATH6KL_CFG_SUSPEND_SCHED_SCAN, - NULL); - if (ret) - goto cut_pwr; - - return 0; - } - if (ar->suspend_mode == WLAN_POWER_STATE_WOW || (!ar->suspend_mode && wow)) { @@ -942,14 +926,14 @@ static int ath6kl_sdio_resume(struct ath6kl *ar) case ATH6KL_STATE_WOW: break; - case ATH6KL_STATE_SCHED_SCAN: - break; - case ATH6KL_STATE_SUSPENDING: break; case ATH6KL_STATE_RESUMING: break; + + case ATH6KL_STATE_RECOVERY: + break; } ath6kl_cfg80211_resume(ar); @@ -1462,3 +1446,6 @@ MODULE_FIRMWARE(AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE); MODULE_FIRMWARE(AR6004_HW_1_2_FW_DIR "/" AR6004_HW_1_2_FIRMWARE_FILE); MODULE_FIRMWARE(AR6004_HW_1_2_BOARD_DATA_FILE); MODULE_FIRMWARE(AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE); +MODULE_FIRMWARE(AR6004_HW_1_3_FW_DIR "/" AR6004_HW_1_3_FIRMWARE_FILE); +MODULE_FIRMWARE(AR6004_HW_1_3_BOARD_DATA_FILE); +MODULE_FIRMWARE(AR6004_HW_1_3_DEFAULT_BOARD_DATA_FILE); diff --git a/drivers/net/wireless/ath/ath6kl/txrx.c b/drivers/net/wireless/ath/ath6kl/txrx.c index 7dfa0fd86d7b..78b369286579 100644 --- a/drivers/net/wireless/ath/ath6kl/txrx.c +++ b/drivers/net/wireless/ath/ath6kl/txrx.c @@ -288,8 +288,16 @@ int ath6kl_control_tx(void *devt, struct sk_buff *skb, int status = 0; struct ath6kl_cookie *cookie = NULL; - if (WARN_ON_ONCE(ar->state == ATH6KL_STATE_WOW)) + if (WARN_ON_ONCE(ar->state == ATH6KL_STATE_WOW)) { + dev_kfree_skb(skb); return -EACCES; + } + + if (WARN_ON_ONCE(eid == ENDPOINT_UNUSED || + eid >= ENDPOINT_MAX)) { + status = -EINVAL; + goto fail_ctrl_tx; + } spin_lock_bh(&ar->lock); @@ -591,6 +599,7 @@ enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target, */ set_bit(WMI_CTRL_EP_FULL, &ar->flag); ath6kl_err("wmi ctrl ep is full\n"); + ath6kl_recovery_err_notify(ar, ATH6KL_FW_EP_FULL); return action; } @@ -695,22 +704,31 @@ void ath6kl_tx_complete(struct htc_target *target, list); list_del(&packet->list); + if (WARN_ON_ONCE(packet->endpoint == ENDPOINT_UNUSED || + packet->endpoint >= ENDPOINT_MAX)) + continue; + ath6kl_cookie = (struct ath6kl_cookie *)packet->pkt_cntxt; - if (!ath6kl_cookie) - goto fatal; + if (WARN_ON_ONCE(!ath6kl_cookie)) + continue; status = packet->status; skb = ath6kl_cookie->skb; eid = packet->endpoint; map_no = ath6kl_cookie->map_no; - if (!skb || !skb->data) - goto fatal; + if (WARN_ON_ONCE(!skb || !skb->data)) { + dev_kfree_skb(skb); + ath6kl_free_cookie(ar, ath6kl_cookie); + continue; + } __skb_queue_tail(&skb_queue, skb); - if (!status && (packet->act_len != skb->len)) - goto fatal; + if (WARN_ON_ONCE(!status && (packet->act_len != skb->len))) { + ath6kl_free_cookie(ar, ath6kl_cookie); + continue; + } ar->tx_pending[eid]--; @@ -792,11 +810,6 @@ void ath6kl_tx_complete(struct htc_target *target, wake_up(&ar->event_wq); return; - -fatal: - WARN_ON(1); - spin_unlock_bh(&ar->lock); - return; } void ath6kl_tx_data_cleanup(struct ath6kl *ar) @@ -885,8 +898,11 @@ void ath6kl_rx_refill(struct htc_target *target, enum htc_endpoint_id endpoint) break; packet = (struct htc_packet *) skb->head; - if (!IS_ALIGNED((unsigned long) skb->data, 4)) + if (!IS_ALIGNED((unsigned long) skb->data, 4)) { + size_t len = skb_headlen(skb); skb->data = PTR_ALIGN(skb->data - 4, 4); + skb_set_tail_pointer(skb, len); + } set_htc_rxpkt_info(packet, skb, skb->data, ATH6KL_BUFFER_SIZE, endpoint); packet->skb = skb; @@ -908,8 +924,11 @@ void ath6kl_refill_amsdu_rxbufs(struct ath6kl *ar, int count) return; packet = (struct htc_packet *) skb->head; - if (!IS_ALIGNED((unsigned long) skb->data, 4)) + if (!IS_ALIGNED((unsigned long) skb->data, 4)) { + size_t len = skb_headlen(skb); skb->data = PTR_ALIGN(skb->data - 4, 4); + skb_set_tail_pointer(skb, len); + } set_htc_rxpkt_info(packet, skb, skb->data, ATH6KL_AMSDU_BUFFER_SIZE, 0); packet->skb = skb; diff --git a/drivers/net/wireless/ath/ath6kl/usb.c b/drivers/net/wireless/ath/ath6kl/usb.c index 3740c3d6ab88..62bcc0d5bc23 100644 --- a/drivers/net/wireless/ath/ath6kl/usb.c +++ b/drivers/net/wireless/ath/ath6kl/usb.c @@ -185,9 +185,10 @@ static int ath6kl_usb_alloc_pipe_resources(struct ath6kl_usb_pipe *pipe, for (i = 0; i < urb_cnt; i++) { urb_context = kzalloc(sizeof(struct ath6kl_urb_context), GFP_KERNEL); - if (urb_context == NULL) - /* FIXME: set status to -ENOMEM */ - break; + if (urb_context == NULL) { + status = -ENOMEM; + goto fail_alloc_pipe_resources; + } urb_context->pipe = pipe; @@ -204,6 +205,7 @@ static int ath6kl_usb_alloc_pipe_resources(struct ath6kl_usb_pipe *pipe, pipe->logical_pipe_num, pipe->usb_pipe_handle, pipe->urb_alloc); +fail_alloc_pipe_resources: return status; } @@ -803,7 +805,11 @@ static int ath6kl_usb_map_service_pipe(struct ath6kl *ar, u16 svc_id, *dl_pipe = ATH6KL_USB_PIPE_RX_DATA; break; case WMI_DATA_VI_SVC: - *ul_pipe = ATH6KL_USB_PIPE_TX_DATA_MP; + + if (ar->hw.flags & ATH6KL_HW_MAP_LP_ENDPOINT) + *ul_pipe = ATH6KL_USB_PIPE_TX_DATA_LP; + else + *ul_pipe = ATH6KL_USB_PIPE_TX_DATA_MP; /* * Disable rxdata2 directly, it will be enabled * if FW enable rxdata2 @@ -811,7 +817,11 @@ static int ath6kl_usb_map_service_pipe(struct ath6kl *ar, u16 svc_id, *dl_pipe = ATH6KL_USB_PIPE_RX_DATA; break; case WMI_DATA_VO_SVC: - *ul_pipe = ATH6KL_USB_PIPE_TX_DATA_HP; + + if (ar->hw.flags & ATH6KL_HW_MAP_LP_ENDPOINT) + *ul_pipe = ATH6KL_USB_PIPE_TX_DATA_LP; + else + *ul_pipe = ATH6KL_USB_PIPE_TX_DATA_MP; /* * Disable rxdata2 directly, it will be enabled * if FW enable rxdata2 @@ -1196,7 +1206,14 @@ static struct usb_driver ath6kl_usb_driver = { static int ath6kl_usb_init(void) { - usb_register(&ath6kl_usb_driver); + int ret; + + ret = usb_register(&ath6kl_usb_driver); + if (ret) { + ath6kl_err("usb registration failed: %d\n", ret); + return ret; + } + return 0; } @@ -1220,3 +1237,6 @@ MODULE_FIRMWARE(AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE); MODULE_FIRMWARE(AR6004_HW_1_2_FIRMWARE_FILE); MODULE_FIRMWARE(AR6004_HW_1_2_BOARD_DATA_FILE); MODULE_FIRMWARE(AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE); +MODULE_FIRMWARE(AR6004_HW_1_3_FW_DIR "/" AR6004_HW_1_3_FIRMWARE_FILE); +MODULE_FIRMWARE(AR6004_HW_1_3_BOARD_DATA_FILE); +MODULE_FIRMWARE(AR6004_HW_1_3_DEFAULT_BOARD_DATA_FILE); diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index c30ab4b11d61..998f8b0f62fd 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; } @@ -936,8 +935,12 @@ static void ath6kl_wmi_regdomain_event(struct wmi *wmi, u8 *datap, int len) regpair = ath6kl_get_regpair((u16) reg_code); country = ath6kl_regd_find_country_by_rd((u16) reg_code); - ath6kl_dbg(ATH6KL_DBG_WMI, "Regpair used: 0x%0x\n", - regpair->regDmnEnum); + if (regpair) + ath6kl_dbg(ATH6KL_DBG_WMI, "Regpair used: 0x%0x\n", + regpair->regDmnEnum); + else + ath6kl_warn("Regpair not found reg_code 0x%0x\n", + reg_code); } if (country && wmi->parent_dev->wiphy_registered) { @@ -1116,7 +1119,7 @@ static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len, * the timer would not ever fire if the scan interval is short * enough. */ - if (ar->state == ATH6KL_STATE_SCHED_SCAN && + if (test_bit(SCHED_SCANNING, &vif->flags) && !timer_pending(&vif->sched_scan_timer)) { mod_timer(&vif->sched_scan_timer, jiffies + msecs_to_jiffies(ATH6KL_SCHED_SCAN_RESULT_DELAY)); @@ -1170,6 +1173,9 @@ static int ath6kl_wmi_bitrate_reply_rx(struct wmi *wmi, u8 *datap, int len) rate = RATE_AUTO; } else { index = reply->rate_index & 0x7f; + if (WARN_ON_ONCE(index > (RATE_MCS_7_40 + 1))) + return -EINVAL; + sgi = (reply->rate_index & 0x80) ? 1 : 0; rate = wmi_rate_tbl[index][sgi]; } @@ -1531,6 +1537,68 @@ static int ath6kl_wmi_cac_event_rx(struct wmi *wmi, u8 *datap, int len, return 0; } +static int ath6kl_wmi_txe_notify_event_rx(struct wmi *wmi, u8 *datap, int len, + struct ath6kl_vif *vif) +{ + struct wmi_txe_notify_event *ev; + u32 rate, pkts; + + if (len < sizeof(*ev)) + return -EINVAL; + + if (vif->sme_state != SME_CONNECTED) + return -ENOTCONN; + + ev = (struct wmi_txe_notify_event *) datap; + rate = le32_to_cpu(ev->rate); + pkts = le32_to_cpu(ev->pkts); + + ath6kl_dbg(ATH6KL_DBG_WMI, "TXE notify event: peer %pM rate %d% pkts %d intvl %ds\n", + vif->bssid, rate, pkts, vif->txe_intvl); + + cfg80211_cqm_txe_notify(vif->ndev, vif->bssid, pkts, + rate, vif->txe_intvl, GFP_KERNEL); + + return 0; +} + +int ath6kl_wmi_set_txe_notify(struct wmi *wmi, u8 idx, + u32 rate, u32 pkts, u32 intvl) +{ + struct sk_buff *skb; + struct wmi_txe_notify_cmd *cmd; + + skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_txe_notify_cmd *) skb->data; + cmd->rate = cpu_to_le32(rate); + cmd->pkts = cpu_to_le32(pkts); + cmd->intvl = cpu_to_le32(intvl); + + return ath6kl_wmi_cmd_send(wmi, idx, skb, WMI_SET_TXE_NOTIFY_CMDID, + NO_SYNC_WMIFLAG); +} + +int ath6kl_wmi_set_rssi_filter_cmd(struct wmi *wmi, u8 if_idx, s8 rssi) +{ + struct sk_buff *skb; + struct wmi_set_rssi_filter_cmd *cmd; + int ret; + + skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_set_rssi_filter_cmd *) skb->data; + cmd->rssi = rssi; + + ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_RSSI_FILTER_CMDID, + NO_SYNC_WMIFLAG); + return ret; +} + static int ath6kl_wmi_send_snr_threshold_params(struct wmi *wmi, struct wmi_snr_threshold_params_cmd *snr_cmd) { @@ -1677,8 +1745,11 @@ int ath6kl_wmi_cmd_send(struct wmi *wmi, u8 if_idx, struct sk_buff *skb, int ret; u16 info1; - if (WARN_ON(skb == NULL || (if_idx > (wmi->parent_dev->vif_max - 1)))) + if (WARN_ON(skb == NULL || + (if_idx > (wmi->parent_dev->vif_max - 1)))) { + dev_kfree_skb(skb); return -EINVAL; + } ath6kl_dbg(ATH6KL_DBG_WMI, "wmi tx id %d len %d flag %d\n", cmd_id, skb->len, sync_flag); @@ -1833,6 +1904,59 @@ int ath6kl_wmi_disconnect_cmd(struct wmi *wmi, u8 if_idx) return ret; } +/* ath6kl_wmi_start_scan_cmd is to be deprecated. Use + * ath6kl_wmi_begin_scan_cmd instead. The new function supports P2P + * mgmt operations using station interface. + */ +static int ath6kl_wmi_startscan_cmd(struct wmi *wmi, u8 if_idx, + enum wmi_scan_type scan_type, + u32 force_fgscan, u32 is_legacy, + u32 home_dwell_time, + u32 force_scan_interval, + s8 num_chan, u16 *ch_list) +{ + struct sk_buff *skb; + struct wmi_start_scan_cmd *sc; + s8 size; + int i, ret; + + size = sizeof(struct wmi_start_scan_cmd); + + if ((scan_type != WMI_LONG_SCAN) && (scan_type != WMI_SHORT_SCAN)) + return -EINVAL; + + if (num_chan > WMI_MAX_CHANNELS) + return -EINVAL; + + if (num_chan) + size += sizeof(u16) * (num_chan - 1); + + skb = ath6kl_wmi_get_new_buf(size); + if (!skb) + return -ENOMEM; + + sc = (struct wmi_start_scan_cmd *) skb->data; + sc->scan_type = scan_type; + sc->force_fg_scan = cpu_to_le32(force_fgscan); + sc->is_legacy = cpu_to_le32(is_legacy); + sc->home_dwell_time = cpu_to_le32(home_dwell_time); + sc->force_scan_intvl = cpu_to_le32(force_scan_interval); + sc->num_ch = num_chan; + + for (i = 0; i < num_chan; i++) + sc->ch_list[i] = cpu_to_le16(ch_list[i]); + + ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_START_SCAN_CMDID, + NO_SYNC_WMIFLAG); + + return ret; +} + +/* + * beginscan supports (compared to old startscan) P2P mgmt operations using + * station interface, send additional information like supported rates to + * advertise and xmit rates for probe requests + */ int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx, enum wmi_scan_type scan_type, u32 force_fgscan, u32 is_legacy, @@ -1848,6 +1972,15 @@ int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx, int num_rates; u32 ratemask; + if (!test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX, + ar->fw_capabilities)) { + return ath6kl_wmi_startscan_cmd(wmi, if_idx, + scan_type, force_fgscan, + is_legacy, home_dwell_time, + force_scan_interval, + num_chan, ch_list); + } + size = sizeof(struct wmi_begin_scan_cmd); if ((scan_type != WMI_LONG_SCAN) && (scan_type != WMI_SHORT_SCAN)) @@ -1900,50 +2033,24 @@ int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx, return ret; } -/* ath6kl_wmi_start_scan_cmd is to be deprecated. Use - * ath6kl_wmi_begin_scan_cmd instead. The new function supports P2P - * mgmt operations using station interface. - */ -int ath6kl_wmi_startscan_cmd(struct wmi *wmi, u8 if_idx, - enum wmi_scan_type scan_type, - u32 force_fgscan, u32 is_legacy, - u32 home_dwell_time, u32 force_scan_interval, - s8 num_chan, u16 *ch_list) +int ath6kl_wmi_enable_sched_scan_cmd(struct wmi *wmi, u8 if_idx, bool enable) { struct sk_buff *skb; - struct wmi_start_scan_cmd *sc; - s8 size; - int i, ret; - - size = sizeof(struct wmi_start_scan_cmd); - - if ((scan_type != WMI_LONG_SCAN) && (scan_type != WMI_SHORT_SCAN)) - return -EINVAL; - - if (num_chan > WMI_MAX_CHANNELS) - return -EINVAL; - - if (num_chan) - size += sizeof(u16) * (num_chan - 1); + struct wmi_enable_sched_scan_cmd *sc; + int ret; - skb = ath6kl_wmi_get_new_buf(size); + skb = ath6kl_wmi_get_new_buf(sizeof(*sc)); if (!skb) return -ENOMEM; - sc = (struct wmi_start_scan_cmd *) skb->data; - sc->scan_type = scan_type; - sc->force_fg_scan = cpu_to_le32(force_fgscan); - sc->is_legacy = cpu_to_le32(is_legacy); - sc->home_dwell_time = cpu_to_le32(home_dwell_time); - sc->force_scan_intvl = cpu_to_le32(force_scan_interval); - sc->num_ch = num_chan; - - for (i = 0; i < num_chan; i++) - sc->ch_list[i] = cpu_to_le16(ch_list[i]); + ath6kl_dbg(ATH6KL_DBG_WMI, "%s scheduled scan on vif %d\n", + enable ? "enabling" : "disabling", if_idx); + sc = (struct wmi_enable_sched_scan_cmd *) skb->data; + sc->enable = enable ? 1 : 0; - ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_START_SCAN_CMDID, + ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, + WMI_ENABLE_SCHED_SCAN_CMDID, NO_SYNC_WMIFLAG); - return ret; } @@ -2275,8 +2382,10 @@ static int ath6kl_wmi_data_sync_send(struct wmi *wmi, struct sk_buff *skb, struct wmi_data_hdr *data_hdr; int ret; - if (WARN_ON(skb == NULL || ep_id == wmi->ep_id)) + if (WARN_ON(skb == NULL || ep_id == wmi->ep_id)) { + dev_kfree_skb(skb); return -EINVAL; + } skb_push(skb, sizeof(struct wmi_data_hdr)); @@ -2313,10 +2422,8 @@ static int ath6kl_wmi_sync_point(struct wmi *wmi, u8 if_idx) spin_unlock_bh(&wmi->lock); skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); - if (!skb) { - ret = -ENOMEM; - goto free_skb; - } + if (!skb) + return -ENOMEM; cmd = (struct wmi_sync_cmd *) skb->data; @@ -2339,7 +2446,7 @@ static int ath6kl_wmi_sync_point(struct wmi *wmi, u8 if_idx) * then do not send the Synchronize cmd on the control ep */ if (ret) - goto free_skb; + goto free_cmd_skb; /* * Send sync cmd followed by sync data messages on all @@ -2349,15 +2456,12 @@ static int ath6kl_wmi_sync_point(struct wmi *wmi, u8 if_idx) NO_SYNC_WMIFLAG); if (ret) - goto free_skb; - - /* cmd buffer sent, we no longer own it */ - skb = NULL; + goto free_data_skb; for (index = 0; index < num_pri_streams; index++) { if (WARN_ON(!data_sync_bufs[index].skb)) - break; + goto free_data_skb; ep_id = ath6kl_ac2_endpoint_id(wmi->parent_dev, data_sync_bufs[index]. @@ -2366,17 +2470,20 @@ static int ath6kl_wmi_sync_point(struct wmi *wmi, u8 if_idx) ath6kl_wmi_data_sync_send(wmi, data_sync_bufs[index].skb, ep_id, if_idx); - if (ret) - break; - data_sync_bufs[index].skb = NULL; + + if (ret) + goto free_data_skb; } -free_skb: + return 0; + +free_cmd_skb: /* free up any resources left over (possibly due to an error) */ if (skb) dev_kfree_skb(skb); +free_data_skb: for (index = 0; index < num_pri_streams; index++) { if (data_sync_bufs[index].skb != NULL) { dev_kfree_skb((struct sk_buff *)data_sync_bufs[index]. @@ -2618,11 +2725,13 @@ static int ath6kl_set_bitrate_mask64(struct wmi *wmi, u8 if_idx, { struct sk_buff *skb; int ret, mode, band; - u64 mcsrate, ratemask[IEEE80211_NUM_BANDS]; + u64 mcsrate, ratemask[ATH6KL_NUM_BANDS]; struct wmi_set_tx_select_rates64_cmd *cmd; memset(&ratemask, 0, sizeof(ratemask)); - for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + + /* only check 2.4 and 5 GHz bands, skip the rest */ + for (band = 0; band <= IEEE80211_BAND_5GHZ; band++) { /* copy legacy rate mask */ ratemask[band] = mask->control[band].legacy; if (band == IEEE80211_BAND_5GHZ) @@ -2668,11 +2777,13 @@ static int ath6kl_set_bitrate_mask32(struct wmi *wmi, u8 if_idx, { struct sk_buff *skb; int ret, mode, band; - u32 mcsrate, ratemask[IEEE80211_NUM_BANDS]; + u32 mcsrate, ratemask[ATH6KL_NUM_BANDS]; struct wmi_set_tx_select_rates32_cmd *cmd; memset(&ratemask, 0, sizeof(ratemask)); - for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + + /* only check 2.4 and 5 GHz bands, skip the rest */ + for (band = 0; band <= IEEE80211_BAND_5GHZ; band++) { /* copy legacy rate mask */ ratemask[band] = mask->control[band].legacy; if (band == IEEE80211_BAND_5GHZ) @@ -2716,7 +2827,7 @@ int ath6kl_wmi_set_bitrate_mask(struct wmi *wmi, u8 if_idx, { struct ath6kl *ar = wmi->parent_dev; - if (ar->hw.flags & ATH6KL_HW_FLAG_64BIT_RATES) + if (ar->hw.flags & ATH6KL_HW_64BIT_RATES) return ath6kl_set_bitrate_mask64(wmi, if_idx, mask); else return ath6kl_set_bitrate_mask32(wmi, if_idx, mask); @@ -3139,12 +3250,40 @@ int ath6kl_wmi_sta_bmiss_enhance_cmd(struct wmi *wmi, u8 if_idx, bool enhance) return ret; } +int ath6kl_wmi_set_regdomain_cmd(struct wmi *wmi, const char *alpha2) +{ + struct sk_buff *skb; + struct wmi_set_regdomain_cmd *cmd; + + skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_set_regdomain_cmd *) skb->data; + memcpy(cmd->iso_name, alpha2, 2); + + return ath6kl_wmi_cmd_send(wmi, 0, skb, + WMI_SET_REGDOMAIN_CMDID, + NO_SYNC_WMIFLAG); +} + s32 ath6kl_wmi_get_rate(s8 rate_index) { + u8 sgi = 0; + if (rate_index == RATE_AUTO) return 0; - return wmi_rate_tbl[(u32) rate_index][0]; + /* SGI is stored as the MSB of the rate_index */ + if (rate_index & RATE_INDEX_MSB) { + rate_index &= RATE_INDEX_WITHOUT_SGI_MASK; + sgi = 1; + } + + if (WARN_ON(rate_index > RATE_MCS_7_40)) + rate_index = RATE_MCS_7_40; + + return wmi_rate_tbl[(u32) rate_index][sgi]; } static int ath6kl_wmi_get_pmkid_list_event_rx(struct wmi *wmi, u8 *datap, @@ -3634,6 +3773,19 @@ int ath6kl_wmi_set_inact_period(struct wmi *wmi, u8 if_idx, int inact_timeout) NO_SYNC_WMIFLAG); } +static void ath6kl_wmi_hb_challenge_resp_event(struct wmi *wmi, u8 *datap, + int len) +{ + struct wmix_hb_challenge_resp_cmd *cmd; + + if (len < sizeof(struct wmix_hb_challenge_resp_cmd)) + return; + + cmd = (struct wmix_hb_challenge_resp_cmd *) datap; + ath6kl_recovery_hb_event(wmi->parent_dev, + le32_to_cpu(cmd->cookie)); +} + static int ath6kl_wmi_control_rx_xtnd(struct wmi *wmi, struct sk_buff *skb) { struct wmix_cmd_hdr *cmd; @@ -3658,6 +3810,7 @@ static int ath6kl_wmi_control_rx_xtnd(struct wmi *wmi, struct sk_buff *skb) switch (id) { case WMIX_HB_CHALLENGE_RESP_EVENTID: ath6kl_dbg(ATH6KL_DBG_WMI, "wmi event hb challenge resp\n"); + ath6kl_wmi_hb_challenge_resp_event(wmi, datap, len); break; case WMIX_DBGLOG_EVENTID: ath6kl_dbg(ATH6KL_DBG_WMI, "wmi event dbglog len %d\n", len); @@ -3750,6 +3903,9 @@ static int ath6kl_wmi_proc_events_vif(struct wmi *wmi, u16 if_idx, u16 cmd_id, case WMI_RX_ACTION_EVENTID: ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RX_ACTION_EVENTID\n"); return ath6kl_wmi_rx_action_event_rx(wmi, datap, len, vif); + case WMI_TXE_NOTIFY_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TXE_NOTIFY_EVENTID\n"); + return ath6kl_wmi_txe_notify_event_rx(wmi, datap, len, vif); default: ath6kl_dbg(ATH6KL_DBG_WMI, "unknown cmd id 0x%x\n", cmd_id); return -EINVAL; diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h index 43339aca585d..98b1755e67f4 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.h +++ b/drivers/net/wireless/ath/ath6kl/wmi.h @@ -48,7 +48,7 @@ #define A_BAND_24GHZ 0 #define A_BAND_5GHZ 1 -#define A_NUM_BANDS 2 +#define ATH6KL_NUM_BANDS 2 /* in ms */ #define WMI_IMPLICIT_PSTREAM_INACTIVITY_INT 5000 @@ -628,6 +628,20 @@ enum wmi_cmd_id { WMI_SET_MCASTRATE, WMI_STA_BMISS_ENHANCE_CMDID, + + WMI_SET_REGDOMAIN_CMDID, + + WMI_SET_RSSI_FILTER_CMDID, + + WMI_SET_KEEP_ALIVE_EXT, + + WMI_VOICE_DETECTION_ENABLE_CMDID, + + WMI_SET_TXE_NOTIFY_CMDID, + + WMI_SET_RECOVERY_TEST_PARAMETER_CMDID, /*0xf094*/ + + WMI_ENABLE_SCHED_SCAN_CMDID, }; enum wmi_mgmt_frame_type { @@ -843,7 +857,7 @@ struct wmi_begin_scan_cmd { u8 scan_type; /* Supported rates to advertise in the probe request frames */ - struct wmi_supp_rates supp_rates[IEEE80211_NUM_BANDS]; + struct wmi_supp_rates supp_rates[ATH6KL_NUM_BANDS]; /* how many channels follow */ u8 num_ch; @@ -941,6 +955,11 @@ struct wmi_scan_params_cmd { __le32 max_dfsch_act_time; } __packed; +/* WMI_ENABLE_SCHED_SCAN_CMDID */ +struct wmi_enable_sched_scan_cmd { + u8 enable; +} __packed; + /* WMI_SET_BSS_FILTER_CMDID */ enum wmi_bss_filter { /* no beacons forwarded */ @@ -1032,6 +1051,11 @@ struct wmi_sta_bmiss_enhance_cmd { u8 enable; } __packed; +struct wmi_set_regdomain_cmd { + u8 length; + u8 iso_name[2]; +} __packed; + /* WMI_SET_POWER_MODE_CMDID */ enum wmi_power_mode { REC_POWER = 0x01, @@ -1276,6 +1300,11 @@ struct wmi_snr_threshold_params_cmd { u8 reserved[3]; } __packed; +/* Don't report BSSs with signal (RSSI) below this threshold */ +struct wmi_set_rssi_filter_cmd { + s8 rssi; +} __packed; + enum wmi_preamble_policy { WMI_IGNORE_BARKER_IN_ERP = 0, WMI_FOLLOW_BARKER_IN_ERP, @@ -1455,6 +1484,20 @@ enum wmi_event_id { WMI_P2P_CAPABILITIES_EVENTID, WMI_RX_ACTION_EVENTID, WMI_P2P_INFO_EVENTID, + + /* WPS Events */ + WMI_WPS_GET_STATUS_EVENTID, + WMI_WPS_PROFILE_EVENTID, + + /* more P2P events */ + WMI_NOA_INFO_EVENTID, + WMI_OPPPS_INFO_EVENTID, + WMI_PORT_STATUS_EVENTID, + + /* 802.11w */ + WMI_GET_RSN_CAP_EVENTID, + + WMI_TXE_NOTIFY_EVENTID, }; struct wmi_ready_event_2 { @@ -1749,6 +1792,9 @@ struct rx_stats { a_sle32 ucast_rate; } __packed; +#define RATE_INDEX_WITHOUT_SGI_MASK 0x7f +#define RATE_INDEX_MSB 0x80 + struct tkip_ccmp_stats { __le32 tkip_local_mic_fail; __le32 tkip_cnter_measures_invoked; @@ -2019,7 +2065,6 @@ struct wmi_set_ie_cmd { #define WOW_MAX_FILTERS_PER_LIST 4 #define WOW_PATTERN_SIZE 64 -#define WOW_MASK_SIZE 64 #define MAC_MAX_FILTERS_PER_LIST 4 @@ -2028,7 +2073,7 @@ struct wow_filter { u8 wow_filter_id; u8 wow_filter_size; u8 wow_filter_offset; - u8 wow_filter_mask[WOW_MASK_SIZE]; + u8 wow_filter_mask[WOW_PATTERN_SIZE]; u8 wow_filter_pattern[WOW_PATTERN_SIZE]; } __packed; @@ -2087,6 +2132,19 @@ struct wmi_del_wow_pattern_cmd { __le16 filter_id; } __packed; +/* WMI_SET_TXE_NOTIFY_CMDID */ +struct wmi_txe_notify_cmd { + __le32 rate; + __le32 pkts; + __le32 intvl; +} __packed; + +/* WMI_TXE_NOTIFY_EVENTID */ +struct wmi_txe_notify_event { + __le32 rate; + __le32 pkts; +} __packed; + /* WMI_SET_AKMP_PARAMS_CMD */ struct wmi_pmkid { @@ -2505,11 +2563,6 @@ int ath6kl_wmi_connect_cmd(struct wmi *wmi, u8 if_idx, int ath6kl_wmi_reconnect_cmd(struct wmi *wmi, u8 if_idx, u8 *bssid, u16 channel); int ath6kl_wmi_disconnect_cmd(struct wmi *wmi, u8 if_idx); -int ath6kl_wmi_startscan_cmd(struct wmi *wmi, u8 if_idx, - enum wmi_scan_type scan_type, - u32 force_fgscan, u32 is_legacy, - u32 home_dwell_time, u32 force_scan_interval, - s8 num_chan, u16 *ch_list); int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx, enum wmi_scan_type scan_type, @@ -2517,6 +2570,7 @@ int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx, u32 home_dwell_time, u32 force_scan_interval, s8 num_chan, u16 *ch_list, u32 no_cck, u32 *rates); +int ath6kl_wmi_enable_sched_scan_cmd(struct wmi *wmi, u8 if_idx, bool enable); int ath6kl_wmi_scanparams_cmd(struct wmi *wmi, u8 if_idx, u16 fg_start_sec, u16 fg_end_sec, u16 bg_sec, @@ -2592,6 +2646,7 @@ int ath6kl_wmi_add_wow_pattern_cmd(struct wmi *wmi, u8 if_idx, const u8 *mask); int ath6kl_wmi_del_wow_pattern_cmd(struct wmi *wmi, u8 if_idx, u16 list_id, u16 filter_id); +int ath6kl_wmi_set_rssi_filter_cmd(struct wmi *wmi, u8 if_idx, s8 rssi); int ath6kl_wmi_set_roam_lrssi_cmd(struct wmi *wmi, u8 lrssi); int ath6kl_wmi_ap_set_dtim_cmd(struct wmi *wmi, u8 if_idx, u32 dtim_period); int ath6kl_wmi_force_roam_cmd(struct wmi *wmi, const u8 *bssid); @@ -2600,6 +2655,9 @@ int ath6kl_wmi_mcast_filter_cmd(struct wmi *wmi, u8 if_idx, bool mc_all_on); int ath6kl_wmi_add_del_mcast_filter_cmd(struct wmi *wmi, u8 if_idx, u8 *filter, bool add_filter); int ath6kl_wmi_sta_bmiss_enhance_cmd(struct wmi *wmi, u8 if_idx, bool enable); +int ath6kl_wmi_set_txe_notify(struct wmi *wmi, u8 idx, + u32 rate, u32 pkts, u32 intvl); +int ath6kl_wmi_set_regdomain_cmd(struct wmi *wmi, const char *alpha2); /* AP mode uAPSD */ int ath6kl_wmi_ap_set_apsd(struct wmi *wmi, u8 if_idx, u8 enable); @@ -2658,6 +2716,8 @@ int ath6kl_wmi_set_inact_period(struct wmi *wmi, u8 if_idx, int inact_timeout); void ath6kl_wmi_sscan_timer(unsigned long ptr); +int ath6kl_wmi_get_challenge_resp_cmd(struct wmi *wmi, u32 cookie, u32 source); + struct ath6kl_vif *ath6kl_get_vif_by_index(struct ath6kl *ar, u8 if_idx); void *ath6kl_wmi_init(struct ath6kl *devt); void ath6kl_wmi_shutdown(struct wmi *wmi); diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig index c7aa6646123e..5fc15bf8be09 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_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c index 162401f22f8c..8b0d8dcd7625 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c @@ -891,6 +891,74 @@ static void ar9003_hw_tx_iq_cal_reload(struct ath_hw *ah) AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN, 0x1); } +static void ar9003_hw_manual_peak_cal(struct ath_hw *ah, u8 chain, bool is_2g) +{ + int offset[8], total = 0, test; + int agc_out, i; + + REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain), + AR_PHY_65NM_RXRF_GAINSTAGES_RX_OVERRIDE, 0x1); + REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain), + AR_PHY_65NM_RXRF_GAINSTAGES_LNAON_CALDC, 0x0); + if (is_2g) + REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain), + AR_PHY_65NM_RXRF_GAINSTAGES_LNA2G_GAIN_OVR, 0x0); + else + REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain), + AR_PHY_65NM_RXRF_GAINSTAGES_LNA5G_GAIN_OVR, 0x0); + + REG_RMW_FIELD(ah, AR_PHY_65NM_RXTX2(chain), + AR_PHY_65NM_RXTX2_RXON_OVR, 0x1); + REG_RMW_FIELD(ah, AR_PHY_65NM_RXTX2(chain), + AR_PHY_65NM_RXTX2_RXON, 0x0); + + REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), + AR_PHY_65NM_RXRF_AGC_AGC_OVERRIDE, 0x1); + REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), + AR_PHY_65NM_RXRF_AGC_AGC_ON_OVR, 0x1); + REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), + AR_PHY_65NM_RXRF_AGC_AGC_CAL_OVR, 0x1); + if (is_2g) + REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), + AR_PHY_65NM_RXRF_AGC_AGC2G_DBDAC_OVR, 0x0); + else + REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), + AR_PHY_65NM_RXRF_AGC_AGC5G_DBDAC_OVR, 0x0); + + for (i = 6; i > 0; i--) { + offset[i] = BIT(i - 1); + test = total + offset[i]; + + if (is_2g) + REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), + AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR, + test); + else + REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), + AR_PHY_65NM_RXRF_AGC_AGC5G_CALDAC_OVR, + test); + udelay(100); + agc_out = REG_READ_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), + AR_PHY_65NM_RXRF_AGC_AGC_OUT); + offset[i] = (agc_out) ? 0 : 1; + total += (offset[i] << (i - 1)); + } + + if (is_2g) + REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), + AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR, total); + else + REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), + AR_PHY_65NM_RXRF_AGC_AGC5G_CALDAC_OVR, total); + + REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain), + AR_PHY_65NM_RXRF_GAINSTAGES_RX_OVERRIDE, 0); + REG_RMW_FIELD(ah, AR_PHY_65NM_RXTX2(chain), + AR_PHY_65NM_RXTX2_RXON_OVR, 0); + REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), + AR_PHY_65NM_RXRF_AGC_AGC_CAL_OVR, 0); +} + static bool ar9003_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan) { @@ -989,6 +1057,14 @@ skip_tx_iqcal: status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0, AH_WAIT_TIMEOUT); + if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) { + for (i = 0; i < AR9300_MAX_CHAINS; i++) { + if (!(ah->rxchainmask & (1 << i))) + continue; + ar9003_hw_manual_peak_cal(ah, i, + IS_CHAN_2GHZ(chan)); + } + } } if (ath9k_hw_mci_is_enabled(ah) && IS_CHAN_2GHZ(chan) && run_agc_cal) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c index 0693cd95b746..74fd3977feeb 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c @@ -35,12 +35,6 @@ */ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) { -#define AR9462_BB_CTX_COEFJ(x) \ - ar9462_##x##_baseband_core_txfir_coeff_japan_2484 - -#define AR9462_BBC_TXIFR_COEFFJ \ - ar9462_2p0_baseband_core_txfir_coeff_japan_2484 - if (AR_SREV_9330_11(ah)) { /* mac */ INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], @@ -70,6 +64,10 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9331_modes_lowest_ob_db_tx_gain_1p1); + /* Japan 2484 Mhz CCK */ + INIT_INI_ARRAY(&ah->iniCckfirJapan2484, + ar9331_1p1_baseband_core_txfir_coeff_japan_2484); + /* additional clock settings */ if (ah->is_clk_25mhz) INIT_INI_ARRAY(&ah->iniAdditional, @@ -106,6 +104,10 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9331_modes_lowest_ob_db_tx_gain_1p2); + /* Japan 2484 Mhz CCK */ + INIT_INI_ARRAY(&ah->iniCckfirJapan2484, + ar9331_1p2_baseband_core_txfir_coeff_japan_2484); + /* additional clock settings */ if (ah->is_clk_25mhz) INIT_INI_ARRAY(&ah->iniAdditional, @@ -180,6 +182,10 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9485_modes_lowest_ob_db_tx_gain_1_1); + /* Japan 2484 Mhz CCK */ + INIT_INI_ARRAY(&ah->iniCckfirJapan2484, + ar9485_1_1_baseband_core_txfir_coeff_japan_2484); + /* Load PCIE SERDES settings from INI */ /* Awake Setting */ @@ -229,9 +235,7 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) ar9462_modes_fast_clock_2p0); INIT_INI_ARRAY(&ah->iniCckfirJapan2484, - AR9462_BB_CTX_COEFJ(2p0)); - - INIT_INI_ARRAY(&ah->ini_japan2484, AR9462_BBC_TXIFR_COEFFJ); + ar9462_2p0_baseband_core_txfir_coeff_japan_2484); } else if (AR_SREV_9550(ah)) { /* mac */ INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.c b/drivers/net/wireless/ath/ath9k/ar9003_mci.c index 42b4412d6794..8dd069259e7b 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/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index 759f5f5a7154..ce19c09fa8e8 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -784,7 +784,7 @@ static int ar9003_hw_process_ini(struct ath_hw *ah, REG_WRITE_ARRAY(&ah->iniAdditional, 1, regWrites); if (chan->channel == 2484) - ar9003_hw_prog_ini(ah, &ah->ini_japan2484, 1); + ar9003_hw_prog_ini(ah, &ah->iniCckfirJapan2484, 1); if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) REG_WRITE(ah, AR_GLB_SWREG_DISCONT_MODE, diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h index 8f585233a788..4c3d06de7111 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h @@ -698,13 +698,6 @@ #define AR_PHY_65NM_CH0_THERM_SAR_ADC_OUT 0x0000ff00 #define AR_PHY_65NM_CH0_THERM_SAR_ADC_OUT_S 8 -#define AR_PHY_65NM_CH0_RXTX1 0x16100 -#define AR_PHY_65NM_CH0_RXTX2 0x16104 -#define AR_PHY_65NM_CH1_RXTX1 0x16500 -#define AR_PHY_65NM_CH1_RXTX2 0x16504 -#define AR_PHY_65NM_CH2_RXTX1 0x16900 -#define AR_PHY_65NM_CH2_RXTX2 0x16904 - #define AR_CH0_TOP2 (AR_SREV_9300(ah) ? 0x1628c : \ (AR_SREV_9462(ah) ? 0x16290 : 0x16284)) #define AR_CH0_TOP2_XPABIASLVL 0xf000 @@ -1286,4 +1279,43 @@ #define AR_BTCOEX_WL_LNADIV_BT_INACTIVE_THRESHOLD 0xFC000000 #define AR_BTCOEX_WL_LNADIV_BT_INACTIVE_THRESHOLD_S 26 +/* Manual Peak detector calibration */ +#define AR_PHY_65NM_BASE 0x16000 +#define AR_PHY_65NM_RXRF_GAINSTAGES(i) (AR_PHY_65NM_BASE + \ + (i * 0x400) + 0x8) +#define AR_PHY_65NM_RXRF_GAINSTAGES_RX_OVERRIDE 0x80000000 +#define AR_PHY_65NM_RXRF_GAINSTAGES_RX_OVERRIDE_S 31 +#define AR_PHY_65NM_RXRF_GAINSTAGES_LNAON_CALDC 0x00000002 +#define AR_PHY_65NM_RXRF_GAINSTAGES_LNAON_CALDC_S 1 +#define AR_PHY_65NM_RXRF_GAINSTAGES_LNA2G_GAIN_OVR 0x70000000 +#define AR_PHY_65NM_RXRF_GAINSTAGES_LNA2G_GAIN_OVR_S 28 +#define AR_PHY_65NM_RXRF_GAINSTAGES_LNA5G_GAIN_OVR 0x03800000 +#define AR_PHY_65NM_RXRF_GAINSTAGES_LNA5G_GAIN_OVR_S 23 + +#define AR_PHY_65NM_RXTX2(i) (AR_PHY_65NM_BASE + \ + (i * 0x400) + 0x104) +#define AR_PHY_65NM_RXTX2_RXON_OVR 0x00001000 +#define AR_PHY_65NM_RXTX2_RXON_OVR_S 12 +#define AR_PHY_65NM_RXTX2_RXON 0x00000800 +#define AR_PHY_65NM_RXTX2_RXON_S 11 + +#define AR_PHY_65NM_RXRF_AGC(i) (AR_PHY_65NM_BASE + \ + (i * 0x400) + 0xc) +#define AR_PHY_65NM_RXRF_AGC_AGC_OVERRIDE 0x80000000 +#define AR_PHY_65NM_RXRF_AGC_AGC_OVERRIDE_S 31 +#define AR_PHY_65NM_RXRF_AGC_AGC_ON_OVR 0x40000000 +#define AR_PHY_65NM_RXRF_AGC_AGC_ON_OVR_S 30 +#define AR_PHY_65NM_RXRF_AGC_AGC_CAL_OVR 0x20000000 +#define AR_PHY_65NM_RXRF_AGC_AGC_CAL_OVR_S 29 +#define AR_PHY_65NM_RXRF_AGC_AGC2G_DBDAC_OVR 0x1E000000 +#define AR_PHY_65NM_RXRF_AGC_AGC2G_DBDAC_OVR_S 25 +#define AR_PHY_65NM_RXRF_AGC_AGC5G_DBDAC_OVR 0x00078000 +#define AR_PHY_65NM_RXRF_AGC_AGC5G_DBDAC_OVR_S 15 +#define AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR 0x01F80000 +#define AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR_S 19 +#define AR_PHY_65NM_RXRF_AGC_AGC5G_CALDAC_OVR 0x00007e00 +#define AR_PHY_65NM_RXRF_AGC_AGC5G_CALDAC_OVR_S 9 +#define AR_PHY_65NM_RXRF_AGC_AGC_OUT 0x00000004 +#define AR_PHY_65NM_RXRF_AGC_AGC_OUT_S 2 + #endif /* AR9003_PHY_H */ diff --git a/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h index 58f30f65c6b6..ccc42a71b436 100644 --- a/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h @@ -78,7 +78,7 @@ static const u32 ar9462_2p0_baseband_postamble[][5] = { {0x0000a284, 0x00000000, 0x00000000, 0x00000150, 0x00000150}, {0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110}, {0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222}, - {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18}, + {0x0000a2c4, 0x00058d18, 0x00058d18, 0x00058d18, 0x00058d18}, {0x0000a2d0, 0x00041981, 0x00041981, 0x00041981, 0x00041982}, {0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b}, {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, diff --git a/drivers/net/wireless/ath/ath9k/ar9485_initvals.h b/drivers/net/wireless/ath/ath9k/ar9485_initvals.h index fb4497fc7a3d..a3710f3bb90c 100644 --- a/drivers/net/wireless/ath/ath9k/ar9485_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9485_initvals.h @@ -18,7 +18,7 @@ #ifndef INITVALS_9485_H #define INITVALS_9485_H -/* AR9485 1.0 */ +/* AR9485 1.1 */ #define ar9485_1_1_mac_postamble ar9300_2p2_mac_postamble @@ -31,6 +31,11 @@ static const u32 ar9485_1_1_pcie_phy_pll_on_clkreq_disable_L1[][2] = { static const u32 ar9485Common_wo_xlna_rx_gain_1_1[][2] = { /* Addr allmodes */ + {0x00009e00, 0x037216a0}, + {0x00009e04, 0x00182020}, + {0x00009e18, 0x00000000}, + {0x00009e2c, 0x00004121}, + {0x00009e44, 0x02282324}, {0x0000a000, 0x00060005}, {0x0000a004, 0x00810080}, {0x0000a008, 0x00830082}, @@ -164,6 +169,11 @@ static const u32 ar9485Common_wo_xlna_rx_gain_1_1[][2] = { static const u32 ar9485Modes_high_power_tx_gain_1_1[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002}, + {0x0000a2d8, 0xf999a83a, 0xf999a83a, 0x7999a83a, 0x7999a83a}, + {0x0000a2dc, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552}, + {0x0000a2e0, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552}, + {0x0000a2e4, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552}, + {0x0000a2e8, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552}, {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8}, {0x0000a458, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000}, @@ -198,6 +208,22 @@ static const u32 ar9485Modes_high_power_tx_gain_1_1[][5] = { {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, + {0x0000a580, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a584, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a588, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a58c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a590, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a594, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a598, 0x00000000, 0x00000000, 0x01404501, 0x01404501}, + {0x0000a59c, 0x00000000, 0x00000000, 0x02808a02, 0x02808a02}, + {0x0000a5a0, 0x00000000, 0x00000000, 0x02808a02, 0x02808a02}, + {0x0000a5a4, 0x00000000, 0x00000000, 0x02808803, 0x02808803}, + {0x0000a5a8, 0x00000000, 0x00000000, 0x04c14b04, 0x04c14b04}, + {0x0000a5ac, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305}, + {0x0000a5b0, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305}, + {0x0000a5b4, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305}, + {0x0000a5b8, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305}, + {0x0000a5bc, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305}, {0x0000b500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000b504, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000b508, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, @@ -234,9 +260,193 @@ static const u32 ar9485Modes_high_power_tx_gain_1_1[][5] = { {0x00016048, 0x6c924260, 0x6c924260, 0x6c924260, 0x6c924260}, }; -#define ar9485Modes_high_ob_db_tx_gain_1_1 ar9485Modes_high_power_tx_gain_1_1 +static const u32 ar9485Modes_high_ob_db_tx_gain_1_1[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002}, + {0x0000a2d8, 0xf999a83a, 0xf999a83a, 0x7999a83a, 0x7999a83a}, + {0x0000a2dc, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552}, + {0x0000a2e0, 0x00000000, 0x00000000, 0xffc63a84, 0xffc63a84}, + {0x0000a2e4, 0x00000000, 0x00000000, 0xfe0fc000, 0xfe0fc000}, + {0x0000a2e8, 0x00000000, 0x00000000, 0xfff00000, 0xfff00000}, + {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8}, + {0x0000a458, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000}, + {0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002}, + {0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004}, + {0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200}, + {0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202}, + {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400}, + {0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402}, + {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404}, + {0x0000a520, 0x2f001f04, 0x2f001f04, 0x21000603, 0x21000603}, + {0x0000a524, 0x35001fc4, 0x35001fc4, 0x25000605, 0x25000605}, + {0x0000a528, 0x3c022f04, 0x3c022f04, 0x2a000a03, 0x2a000a03}, + {0x0000a52c, 0x41023e85, 0x41023e85, 0x2c000a04, 0x2c000a04}, + {0x0000a530, 0x48023ec6, 0x48023ec6, 0x34000e20, 0x34000e20}, + {0x0000a534, 0x4d023f01, 0x4d023f01, 0x35000e21, 0x35000e21}, + {0x0000a538, 0x53023f4b, 0x53023f4b, 0x43000e62, 0x43000e62}, + {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x45000e63, 0x45000e63}, + {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x49000e65, 0x49000e65}, + {0x0000a544, 0x6502feca, 0x6502feca, 0x4b000e66, 0x4b000e66}, + {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x4d001645, 0x4d001645}, + {0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865}, + {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86}, + {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9}, + {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb}, + {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb}, + {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb}, + {0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb}, + {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, + {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, + {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, + {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, + {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, + {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, + {0x0000a580, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a584, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a588, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a58c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a590, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a594, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a598, 0x00000000, 0x00000000, 0x01404501, 0x01404501}, + {0x0000a59c, 0x00000000, 0x00000000, 0x02808a02, 0x02808a02}, + {0x0000a5a0, 0x00000000, 0x00000000, 0x02808a02, 0x02808a02}, + {0x0000a5a4, 0x00000000, 0x00000000, 0x02808803, 0x02808803}, + {0x0000a5a8, 0x00000000, 0x00000000, 0x04c14b04, 0x04c14b04}, + {0x0000a5ac, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305}, + {0x0000a5b0, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305}, + {0x0000a5b4, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305}, + {0x0000a5b8, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305}, + {0x0000a5bc, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305}, + {0x0000b500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b504, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b508, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b50c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b510, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b514, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b518, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b51c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b520, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b524, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b528, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b52c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b530, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b534, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b538, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b53c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b540, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b544, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b548, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b54c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b550, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b554, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b558, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b55c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b560, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b564, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b568, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b56c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b570, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b574, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b578, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b57c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00016044, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db}, + {0x00016048, 0x6c924260, 0x6c924260, 0x6c924260, 0x6c924260}, +}; -#define ar9485Modes_low_ob_db_tx_gain_1_1 ar9485Modes_high_ob_db_tx_gain_1_1 +static const u32 ar9485Modes_low_ob_db_tx_gain_1_1[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002}, + {0x0000a2d8, 0xf999a83a, 0xf999a83a, 0x7999a83a, 0x7999a83a}, + {0x0000a2dc, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552}, + {0x0000a2e0, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552}, + {0x0000a2e4, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552}, + {0x0000a2e8, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552}, + {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8}, + {0x0000a458, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000}, + {0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002}, + {0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004}, + {0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200}, + {0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202}, + {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400}, + {0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402}, + {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404}, + {0x0000a520, 0x2f001f04, 0x2f001f04, 0x21000603, 0x21000603}, + {0x0000a524, 0x35001fc4, 0x35001fc4, 0x25000605, 0x25000605}, + {0x0000a528, 0x3c022f04, 0x3c022f04, 0x2a000a03, 0x2a000a03}, + {0x0000a52c, 0x41023e85, 0x41023e85, 0x2c000a04, 0x2c000a04}, + {0x0000a530, 0x48023ec6, 0x48023ec6, 0x34000e20, 0x34000e20}, + {0x0000a534, 0x4d023f01, 0x4d023f01, 0x35000e21, 0x35000e21}, + {0x0000a538, 0x53023f4b, 0x53023f4b, 0x43000e62, 0x43000e62}, + {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x45000e63, 0x45000e63}, + {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x49000e65, 0x49000e65}, + {0x0000a544, 0x6502feca, 0x6502feca, 0x4b000e66, 0x4b000e66}, + {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x4d001645, 0x4d001645}, + {0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865}, + {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86}, + {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9}, + {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb}, + {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb}, + {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb}, + {0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb}, + {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, + {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, + {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, + {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, + {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, + {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, + {0x0000a580, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a584, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a588, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a58c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a590, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a594, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a598, 0x00000000, 0x00000000, 0x01404501, 0x01404501}, + {0x0000a59c, 0x00000000, 0x00000000, 0x02808a02, 0x02808a02}, + {0x0000a5a0, 0x00000000, 0x00000000, 0x02808a02, 0x02808a02}, + {0x0000a5a4, 0x00000000, 0x00000000, 0x02808803, 0x02808803}, + {0x0000a5a8, 0x00000000, 0x00000000, 0x04c14b04, 0x04c14b04}, + {0x0000a5ac, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305}, + {0x0000a5b0, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305}, + {0x0000a5b4, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305}, + {0x0000a5b8, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305}, + {0x0000a5bc, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305}, + {0x0000b500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b504, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b508, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b50c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b510, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b514, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b518, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b51c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b520, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b524, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b528, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b52c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b530, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b534, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b538, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b53c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b540, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b544, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b548, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b54c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b550, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b554, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b558, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b55c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b560, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b564, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b568, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b56c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b570, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b574, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b578, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b57c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00016044, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db}, + {0x00016048, 0x6c924260, 0x6c924260, 0x6c924260, 0x6c924260}, +}; #define ar9485_modes_lowest_ob_db_tx_gain_1_1 ar9485Modes_low_ob_db_tx_gain_1_1 @@ -245,19 +455,19 @@ static const u32 ar9485_1_1[][2] = { {0x0000a580, 0x00000000}, {0x0000a584, 0x00000000}, {0x0000a588, 0x00000000}, - {0x0000a58c, 0x00000000}, - {0x0000a590, 0x00000000}, - {0x0000a594, 0x00000000}, - {0x0000a598, 0x00000000}, - {0x0000a59c, 0x00000000}, - {0x0000a5a0, 0x00000000}, - {0x0000a5a4, 0x00000000}, - {0x0000a5a8, 0x00000000}, - {0x0000a5ac, 0x00000000}, - {0x0000a5b0, 0x00000000}, - {0x0000a5b4, 0x00000000}, - {0x0000a5b8, 0x00000000}, - {0x0000a5bc, 0x00000000}, + {0x0000a58c, 0x01804000}, + {0x0000a590, 0x02808a02}, + {0x0000a594, 0x0340ca02}, + {0x0000a598, 0x0340cd03}, + {0x0000a59c, 0x0340cd03}, + {0x0000a5a0, 0x06415304}, + {0x0000a5a4, 0x04c11905}, + {0x0000a5a8, 0x06415905}, + {0x0000a5ac, 0x06415905}, + {0x0000a5b0, 0x06415905}, + {0x0000a5b4, 0x06415905}, + {0x0000a5b8, 0x06415905}, + {0x0000a5bc, 0x06415905}, }; static const u32 ar9485_1_1_radio_core[][2] = { @@ -340,7 +550,7 @@ static const u32 ar9485_1_1_baseband_core[][2] = { {0x00009880, 0x201fff00}, {0x00009884, 0x00001042}, {0x000098a4, 0x00200400}, - {0x000098b0, 0x52440bbe}, + {0x000098b0, 0x32840bbe}, {0x000098d0, 0x004b6a8e}, {0x000098d4, 0x00000820}, {0x000098dc, 0x00000000}, @@ -362,7 +572,7 @@ static const u32 ar9485_1_1_baseband_core[][2] = { {0x00009d18, 0x00000000}, {0x00009d1c, 0x00000000}, {0x00009e08, 0x0038233c}, - {0x00009e24, 0x9927b515}, + {0x00009e24, 0x992bb515}, {0x00009e28, 0x12ef0200}, {0x00009e30, 0x06336f77}, {0x00009e34, 0x6af6532f}, @@ -427,7 +637,7 @@ static const u32 ar9485_1_1_baseband_core[][2] = { {0x0000a408, 0x0e79e5c6}, {0x0000a40c, 0x00820820}, {0x0000a414, 0x1ce739cf}, - {0x0000a418, 0x2d0019ce}, + {0x0000a418, 0x2d0021ce}, {0x0000a41c, 0x1ce739ce}, {0x0000a420, 0x000001ce}, {0x0000a424, 0x1ce739ce}, @@ -443,8 +653,8 @@ static const u32 ar9485_1_1_baseband_core[][2] = { {0x0000a44c, 0x00000001}, {0x0000a450, 0x00010000}, {0x0000a5c4, 0xbfad9d74}, - {0x0000a5c8, 0x0048060a}, - {0x0000a5cc, 0x00000637}, + {0x0000a5c8, 0x00480605}, + {0x0000a5cc, 0x00002e37}, {0x0000a760, 0x03020100}, {0x0000a764, 0x09080504}, {0x0000a768, 0x0d0c0b0a}, @@ -464,17 +674,22 @@ static const u32 ar9485_1_1_baseband_core[][2] = { static const u32 ar9485_common_rx_gain_1_1[][2] = { /* Addr allmodes */ - {0x0000a000, 0x00010000}, - {0x0000a004, 0x00030002}, - {0x0000a008, 0x00050004}, - {0x0000a00c, 0x00810080}, - {0x0000a010, 0x01800082}, - {0x0000a014, 0x01820181}, - {0x0000a018, 0x01840183}, - {0x0000a01c, 0x01880185}, - {0x0000a020, 0x018a0189}, - {0x0000a024, 0x02850284}, - {0x0000a028, 0x02890288}, + {0x00009e00, 0x03721b20}, + {0x00009e04, 0x00082020}, + {0x00009e18, 0x0300501e}, + {0x00009e2c, 0x00002e21}, + {0x00009e44, 0x02182324}, + {0x0000a000, 0x00060005}, + {0x0000a004, 0x00810080}, + {0x0000a008, 0x00830082}, + {0x0000a00c, 0x00850084}, + {0x0000a010, 0x01820181}, + {0x0000a014, 0x01840183}, + {0x0000a018, 0x01880185}, + {0x0000a01c, 0x018a0189}, + {0x0000a020, 0x02850284}, + {0x0000a024, 0x02890288}, + {0x0000a028, 0x028b028a}, {0x0000a02c, 0x03850384}, {0x0000a030, 0x03890388}, {0x0000a034, 0x038b038a}, @@ -496,15 +711,15 @@ static const u32 ar9485_common_rx_gain_1_1[][2] = { {0x0000a074, 0x00000000}, {0x0000a078, 0x00000000}, {0x0000a07c, 0x00000000}, - {0x0000a080, 0x28282828}, - {0x0000a084, 0x28282828}, - {0x0000a088, 0x28282828}, - {0x0000a08c, 0x28282828}, - {0x0000a090, 0x28282828}, - {0x0000a094, 0x21212128}, - {0x0000a098, 0x171c1c1c}, - {0x0000a09c, 0x02020212}, - {0x0000a0a0, 0x00000202}, + {0x0000a080, 0x18181818}, + {0x0000a084, 0x18181818}, + {0x0000a088, 0x18181818}, + {0x0000a08c, 0x18181818}, + {0x0000a090, 0x18181818}, + {0x0000a094, 0x18181818}, + {0x0000a098, 0x17181818}, + {0x0000a09c, 0x02020b0b}, + {0x0000a0a0, 0x02020202}, {0x0000a0a4, 0x00000000}, {0x0000a0a8, 0x00000000}, {0x0000a0ac, 0x00000000}, @@ -512,22 +727,22 @@ static const u32 ar9485_common_rx_gain_1_1[][2] = { {0x0000a0b4, 0x00000000}, {0x0000a0b8, 0x00000000}, {0x0000a0bc, 0x00000000}, - {0x0000a0c0, 0x001f0000}, - {0x0000a0c4, 0x111f1100}, - {0x0000a0c8, 0x111d111e}, - {0x0000a0cc, 0x111b111c}, - {0x0000a0d0, 0x22032204}, - {0x0000a0d4, 0x22012202}, - {0x0000a0d8, 0x221f2200}, - {0x0000a0dc, 0x221d221e}, - {0x0000a0e0, 0x33013302}, - {0x0000a0e4, 0x331f3300}, - {0x0000a0e8, 0x4402331e}, - {0x0000a0ec, 0x44004401}, - {0x0000a0f0, 0x441e441f}, - {0x0000a0f4, 0x55015502}, - {0x0000a0f8, 0x551f5500}, - {0x0000a0fc, 0x6602551e}, + {0x0000a0c0, 0x22072208}, + {0x0000a0c4, 0x22052206}, + {0x0000a0c8, 0x22032204}, + {0x0000a0cc, 0x22012202}, + {0x0000a0d0, 0x221f2200}, + {0x0000a0d4, 0x221d221e}, + {0x0000a0d8, 0x33023303}, + {0x0000a0dc, 0x33003301}, + {0x0000a0e0, 0x331e331f}, + {0x0000a0e4, 0x4402331d}, + {0x0000a0e8, 0x44004401}, + {0x0000a0ec, 0x441e441f}, + {0x0000a0f0, 0x55025503}, + {0x0000a0f4, 0x55005501}, + {0x0000a0f8, 0x551e551f}, + {0x0000a0fc, 0x6602551d}, {0x0000a100, 0x66006601}, {0x0000a104, 0x661e661f}, {0x0000a108, 0x7703661d}, @@ -636,17 +851,12 @@ static const u32 ar9485_1_1_baseband_postamble[][5] = { {0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4}, {0x00009830, 0x0000059c, 0x0000059c, 0x0000059c, 0x0000059c}, {0x00009c00, 0x00000044, 0x00000044, 0x00000044, 0x00000044}, - {0x00009e00, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0}, - {0x00009e04, 0x00182020, 0x00182020, 0x00182020, 0x00182020}, {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2}, {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec80d2e, 0x7ec80d2e}, - {0x00009e14, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e}, - {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00009e14, 0x31395d53, 0x31396053, 0x312e6053, 0x312e5d53}, {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, - {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021}, {0x00009e3c, 0xcf946220, 0xcf946220, 0xcf946222, 0xcf946222}, - {0x00009e44, 0x02321e27, 0x02321e27, 0x02282324, 0x02282324}, {0x00009e48, 0x5030201a, 0x5030201a, 0x50302010, 0x50302010}, {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, {0x0000a204, 0x01303fc0, 0x01303fc4, 0x01303fc4, 0x01303fc0}, @@ -850,4 +1060,6 @@ static const u32 ar9485_1_1_mac_core[][2] = { {0x000083d0, 0x000301ff}, }; +#define ar9485_1_1_baseband_core_txfir_coeff_japan_2484 ar9462_2p0_baseband_core_txfir_coeff_japan_2484 + #endif /* INITVALS_9485_H */ diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 4e125d8904a0..86e26a19efda 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 1b48414dca95..531fffd801a3 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 c90e9bc4b026..9963b0bf9f72 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 2f84ab273d0c..6de26ea5d5fa 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 ad14fecc76c6..5f845beeb18b 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 a8be94b2a53a..13ff9edc2401 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 2ed9785a38fa..72d4893311b1 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/dfs_pattern_detector.c b/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c index 3b129143653f..24877b00cbf4 100644 --- a/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c +++ b/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c @@ -42,10 +42,15 @@ struct radar_types { #define MIN_PPB_THRESH 50 #define PPB_THRESH(PPB) ((PPB * MIN_PPB_THRESH + 50) / 100) #define PRF2PRI(PRF) ((1000000 + PRF / 2) / PRF) +/* percentage of pulse width tolerance */ +#define WIDTH_TOLERANCE 5 +#define WIDTH_LOWER(X) ((X*(100-WIDTH_TOLERANCE)+50)/100) +#define WIDTH_UPPER(X) ((X*(100+WIDTH_TOLERANCE)+50)/100) #define ETSI_PATTERN(ID, WMIN, WMAX, PMIN, PMAX, PRF, PPB) \ { \ - ID, WMIN, WMAX, (PRF2PRI(PMAX) - PRI_TOLERANCE), \ + ID, WIDTH_LOWER(WMIN), WIDTH_UPPER(WMAX), \ + (PRF2PRI(PMAX) - PRI_TOLERANCE), \ (PRF2PRI(PMIN) * PRF + PRI_TOLERANCE), PRF, PPB * PRF, \ PPB_THRESH(PPB), PRI_TOLERANCE, \ } diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c index a8ea57b9f49c..4b412aaf4f36 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 b30596fcf73a..96bfb18078fa 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 f42d2eb6af99..d0ce1f5bba10 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); @@ -587,9 +587,9 @@ static bool ath9k_htc_check_beacon_config(struct ath9k_htc_priv *priv, (priv->num_sta_vif > 1) && (vif->type == NL80211_IFTYPE_STATION)) { beacon_configured = false; - ieee80211_iterate_active_interfaces_atomic(priv->hw, - ath9k_htc_beacon_iter, - &beacon_configured); + ieee80211_iterate_active_interfaces_atomic( + priv->hw, IEEE80211_IFACE_ITER_RESUME_ALL, + ath9k_htc_beacon_iter, &beacon_configured); if (beacon_configured) { ath_dbg(common, CONFIG, diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c index 3035deb7a0cd..87110de577ef 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 0eacfc13c915..105582d6b714 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 5ecf1287dddd..05d5ba66cac3 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 66f6a74c508e..9c07a8fa5134 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -127,8 +127,9 @@ static void ath9k_htc_vif_reconfig(struct ath9k_htc_priv *priv) priv->rearm_ani = false; priv->reconfig_beacon = false; - ieee80211_iterate_active_interfaces_atomic(priv->hw, - ath9k_htc_vif_iter, priv); + ieee80211_iterate_active_interfaces_atomic( + priv->hw, IEEE80211_IFACE_ITER_RESUME_ALL, + ath9k_htc_vif_iter, priv); if (priv->rearm_ani) ath9k_htc_start_ani(priv); @@ -165,8 +166,9 @@ static void ath9k_htc_set_bssid_mask(struct ath9k_htc_priv *priv, ath9k_htc_bssid_iter(&iter_data, vif->addr, vif); /* Get list of all active MAC addresses */ - ieee80211_iterate_active_interfaces_atomic(priv->hw, ath9k_htc_bssid_iter, - &iter_data); + ieee80211_iterate_active_interfaces_atomic( + priv->hw, IEEE80211_IFACE_ITER_RESUME_ALL, + ath9k_htc_bssid_iter, &iter_data); memcpy(common->bssidmask, iter_data.mask, ETH_ALEN); ath_hw_setbssidmask(common); @@ -1144,8 +1146,9 @@ static void ath9k_htc_remove_interface(struct ieee80211_hw *hw, */ if ((vif->type == NL80211_IFTYPE_AP) && (priv->num_ap_vif == 0)) { priv->rearm_ani = false; - ieee80211_iterate_active_interfaces_atomic(priv->hw, - ath9k_htc_vif_iter, priv); + ieee80211_iterate_active_interfaces_atomic( + priv->hw, IEEE80211_IFACE_ITER_RESUME_ALL, + ath9k_htc_vif_iter, priv); if (!priv->rearm_ani) ath9k_htc_stop_ani(priv); } @@ -1346,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); @@ -1373,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); @@ -1466,8 +1469,9 @@ static void ath9k_htc_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif) static void ath9k_htc_choose_set_bssid(struct ath9k_htc_priv *priv) { if (priv->num_sta_assoc_vif == 1) { - ieee80211_iterate_active_interfaces_atomic(priv->hw, - ath9k_htc_bss_iter, priv); + ieee80211_iterate_active_interfaces_atomic( + priv->hw, IEEE80211_IFACE_ITER_RESUME_ALL, + ath9k_htc_bss_iter, priv); ath9k_htc_set_bssid(priv); } } diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index 06cdcb772d78..28cd50ee521a 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 71cd9f0c96af..e06bcec655a7 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: @@ -2561,11 +2561,6 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) pCap->hw_caps |= ATH9K_HW_CAP_ANT_DIV_COMB; } - if (AR_SREV_9485_10(ah)) { - pCap->pcie_lcr_extsync_en = true; - pCap->pcie_lcr_offset = 0x80; - } - if (ath9k_hw_dfs_tested(ah)) pCap->hw_caps |= ATH9K_HW_CAP_DFS; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 3e73bfe2315e..3636dabf03e1 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -273,8 +273,6 @@ struct ath9k_hw_capabilities { u8 rx_status_len; u8 tx_desc_len; u8 txs_len; - u16 pcie_lcr_offset; - bool pcie_lcr_extsync_en; }; struct ath9k_ops_config { @@ -877,7 +875,6 @@ struct ath_hw { struct ar5416IniArray iniModesTxGain; struct ar5416IniArray iniCckfirNormal; struct ar5416IniArray iniCckfirJapan2484; - struct ar5416IniArray ini_japan2484; struct ar5416IniArray iniModes_9271_ANI_reg; struct ar5416IniArray ini_radio_post_sys2ant; @@ -930,7 +927,6 @@ struct ath_bus_ops { void (*read_cachesize)(struct ath_common *common, int *csz); bool (*eeprom_read)(struct ath_common *common, u32 off, u16 *data); void (*bt_coex_prep)(struct ath_common *common); - void (*extn_synch_en)(struct ath_common *common); void (*aspm_init)(struct ath_common *common); }; diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 546bae93647b..80cae53a33e5 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 223b9693527e..fc6b075ad635 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 578a7234aa56..be30a9af1528 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); @@ -686,9 +672,6 @@ static int ath9k_start(struct ieee80211_hw *hw) spin_unlock_bh(&sc->sc_pcu_lock); - if (ah->caps.pcie_lcr_extsync_en && common->bus_ops->extn_synch_en) - common->bus_ops->extn_synch_en(common); - mutex_unlock(&sc->mutex); ath9k_ps_restore(sc); @@ -924,8 +907,9 @@ void ath9k_calculate_iter_data(struct ieee80211_hw *hw, ath9k_vif_iter(iter_data, vif->addr, vif); /* Get list of all active MAC addresses */ - ieee80211_iterate_active_interfaces_atomic(sc->hw, ath9k_vif_iter, - iter_data); + ieee80211_iterate_active_interfaces_atomic( + sc->hw, IEEE80211_IFACE_ITER_RESUME_ALL, + ath9k_vif_iter, iter_data); } /* Called with sc->mutex held. */ @@ -975,8 +959,9 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw, if (ah->opmode == NL80211_IFTYPE_STATION && old_opmode == NL80211_IFTYPE_AP && test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) { - ieee80211_iterate_active_interfaces_atomic(sc->hw, - ath9k_sta_vif_iter, sc); + ieee80211_iterate_active_interfaces_atomic( + sc->hw, IEEE80211_IFACE_ITER_RESUME_ALL, + ath9k_sta_vif_iter, sc); } } @@ -1329,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]; @@ -1505,8 +1490,9 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, clear_bit(SC_OP_BEACONS, &sc->sc_flags); } - ieee80211_iterate_active_interfaces_atomic(sc->hw, - ath9k_bss_assoc_iter, sc); + ieee80211_iterate_active_interfaces_atomic( + sc->hw, IEEE80211_IFACE_ITER_RESUME_ALL, + ath9k_bss_assoc_iter, sc); if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags) && ah->opmode == NL80211_IFTYPE_STATION) { @@ -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 0dd2cbb52d65..5c02702f21e7 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 f088f4bf9a26..8e9b826f878b 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -96,17 +96,6 @@ static bool ath_pci_eeprom_read(struct ath_common *common, u32 off, u16 *data) return true; } -static void ath_pci_extn_synch_enable(struct ath_common *common) -{ - struct ath_softc *sc = (struct ath_softc *) common->priv; - struct pci_dev *pdev = to_pci_dev(sc->dev); - u8 lnkctl; - - pci_read_config_byte(pdev, sc->sc_ah->caps.pcie_lcr_offset, &lnkctl); - lnkctl |= PCI_EXP_LNKCTL_ES; - pci_write_config_byte(pdev, sc->sc_ah->caps.pcie_lcr_offset, lnkctl); -} - /* Need to be called after we discover btcoex capabilities */ static void ath_pci_aspm_init(struct ath_common *common) { @@ -153,7 +142,6 @@ static const struct ath_bus_ops ath_pci_bus_ops = { .ath_bus_type = ATH_PCI, .read_cachesize = ath_pci_read_cachesize, .eeprom_read = ath_pci_eeprom_read, - .extn_synch_en = ath_pci_extn_synch_enable, .aspm_init = ath_pci_aspm_init, }; @@ -299,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) { @@ -345,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 27ed80b54881..714558d1ba78 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 268e67dc5fb2..267dbfcfaa96 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 a04028bce28b..6aafbb77c498 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 1ffca7511fa8..90e48a0fafe5 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 267d5dcf82dc..13a204598766 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/ath/carl9170/rx.c b/drivers/net/wireless/ath/carl9170/rx.c index 6d22382875bc..876a773fd0b4 100644 --- a/drivers/net/wireless/ath/carl9170/rx.c +++ b/drivers/net/wireless/ath/carl9170/rx.c @@ -814,6 +814,8 @@ static void carl9170_rx_untie_data(struct ar9170 *ar, u8 *buf, int len) if (phy) carl9170_rx_phy_status(ar, phy, &status); + else + status.flag |= RX_FLAG_NO_SIGNAL_VAL; if (carl9170_handle_mpdu(ar, buf, mpdu_len, &status)) goto drop; diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index 136510edf3cf..8cb206a89083 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 b8ffea6f5c64..849a28c80302 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 b480088b3dbe..1d92d874ebb6 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/Makefile b/drivers/net/wireless/brcm80211/brcmfmac/Makefile index fe80b637c519..1a6661a9f008 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/Makefile +++ b/drivers/net/wireless/brcm80211/brcmfmac/Makefile @@ -25,6 +25,7 @@ obj-$(CONFIG_BRCMFMAC) += brcmfmac.o brcmfmac-objs += \ wl_cfg80211.o \ fwil.o \ + fweh.o \ dhd_cdc.o \ dhd_common.o \ dhd_linux.o diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c index 1aec4342875d..334ddab4a8c5 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c @@ -42,7 +42,8 @@ #ifdef CONFIG_BRCMFMAC_SDIO_OOB static irqreturn_t brcmf_sdio_irqhandler(int irq, void *dev_id) { - struct brcmf_sdio_dev *sdiodev = dev_get_drvdata(dev_id); + struct brcmf_bus *bus_if = dev_get_drvdata(dev_id); + struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; brcmf_dbg(INTR, "oob intr triggered\n"); @@ -71,7 +72,7 @@ int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev) brcmf_dbg(ERROR, "requesting irq %d\n", sdiodev->irq); ret = request_irq(sdiodev->irq, brcmf_sdio_irqhandler, sdiodev->irq_flags, "brcmf_oob_intr", - &sdiodev->func[1]->card->dev); + &sdiodev->func[1]->dev); if (ret != 0) return ret; spin_lock_init(&sdiodev->irq_en_lock); @@ -115,7 +116,7 @@ int brcmf_sdio_intr_unregister(struct brcmf_sdio_dev *sdiodev) disable_irq_wake(sdiodev->irq); sdiodev->irq_wake = false; } - free_irq(sdiodev->irq, &sdiodev->func[1]->card->dev); + free_irq(sdiodev->irq, &sdiodev->func[1]->dev); sdiodev->irq_en = false; return 0; @@ -123,7 +124,8 @@ int brcmf_sdio_intr_unregister(struct brcmf_sdio_dev *sdiodev) #else /* CONFIG_BRCMFMAC_SDIO_OOB */ static void brcmf_sdio_irqhandler(struct sdio_func *func) { - struct brcmf_sdio_dev *sdiodev = dev_get_drvdata(&func->card->dev); + struct brcmf_bus *bus_if = dev_get_drvdata(&func->dev); + struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; brcmf_dbg(INTR, "ib intr triggered\n"); @@ -514,9 +516,6 @@ int brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev) regs = SI_ENUM_BASE; - /* Report the BAR, to fix if needed */ - sdiodev->sbwad = SI_ENUM_BASE; - /* try to attach to the target device */ sdiodev->bus = brcmf_sdbrcm_probe(regs, sdiodev); if (!sdiodev->bus) { @@ -535,6 +534,8 @@ EXPORT_SYMBOL(brcmf_sdio_probe); int brcmf_sdio_remove(struct brcmf_sdio_dev *sdiodev) { + sdiodev->bus_if->state = BRCMF_BUS_DOWN; + if (sdiodev->bus) { brcmf_sdbrcm_disconnect(sdiodev->bus); sdiodev->bus = NULL; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c index c62ec2a5b271..a80050223710 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c @@ -456,95 +456,106 @@ static inline int brcmf_sdio_getintrcfg(struct brcmf_sdio_dev *sdiodev) #endif /* CONFIG_BRCMFMAC_SDIO_OOB */ static int brcmf_ops_sdio_probe(struct sdio_func *func, - const struct sdio_device_id *id) + const struct sdio_device_id *id) { - int ret = 0; + int err; struct brcmf_sdio_dev *sdiodev; struct brcmf_bus *bus_if; brcmf_dbg(TRACE, "Enter\n"); - brcmf_dbg(TRACE, "func->class=%x\n", func->class); - brcmf_dbg(TRACE, "sdio_vendor: 0x%04x\n", func->vendor); - brcmf_dbg(TRACE, "sdio_device: 0x%04x\n", func->device); - brcmf_dbg(TRACE, "Function#: 0x%04x\n", func->num); - - if (func->num == 1) { - if (dev_get_drvdata(&func->card->dev)) { - brcmf_dbg(ERROR, "card private drvdata occupied\n"); - return -ENXIO; - } - bus_if = kzalloc(sizeof(struct brcmf_bus), GFP_KERNEL); - if (!bus_if) - return -ENOMEM; - sdiodev = kzalloc(sizeof(struct brcmf_sdio_dev), GFP_KERNEL); - if (!sdiodev) { - kfree(bus_if); - return -ENOMEM; - } - sdiodev->func[0] = func; - sdiodev->func[1] = func; - sdiodev->bus_if = bus_if; - bus_if->bus_priv.sdio = sdiodev; - bus_if->type = SDIO_BUS; - bus_if->align = BRCMF_SDALIGN; - dev_set_drvdata(&func->card->dev, sdiodev); - - atomic_set(&sdiodev->suspend, false); - init_waitqueue_head(&sdiodev->request_byte_wait); - init_waitqueue_head(&sdiodev->request_word_wait); - init_waitqueue_head(&sdiodev->request_chain_wait); - init_waitqueue_head(&sdiodev->request_buffer_wait); + brcmf_dbg(TRACE, "Class=%x\n", func->class); + brcmf_dbg(TRACE, "sdio vendor ID: 0x%04x\n", func->vendor); + brcmf_dbg(TRACE, "sdio device ID: 0x%04x\n", func->device); + brcmf_dbg(TRACE, "Function#: %d\n", func->num); + + /* Consume func num 1 but dont do anything with it. */ + if (func->num == 1) + return 0; + + /* Ignore anything but func 2 */ + if (func->num != 2) + return -ENODEV; + + bus_if = kzalloc(sizeof(struct brcmf_bus), GFP_KERNEL); + if (!bus_if) + return -ENOMEM; + sdiodev = kzalloc(sizeof(struct brcmf_sdio_dev), GFP_KERNEL); + if (!sdiodev) { + kfree(bus_if); + return -ENOMEM; } - if (func->num == 2) { - sdiodev = dev_get_drvdata(&func->card->dev); - if ((!sdiodev) || (sdiodev->func[1]->card != func->card)) - return -ENODEV; + sdiodev->func[0] = func->card->sdio_func[0]; + sdiodev->func[1] = func->card->sdio_func[0]; + sdiodev->func[2] = func; - ret = brcmf_sdio_getintrcfg(sdiodev); - if (ret) - return ret; - sdiodev->func[2] = func; + sdiodev->bus_if = bus_if; + bus_if->bus_priv.sdio = sdiodev; + bus_if->align = BRCMF_SDALIGN; + dev_set_drvdata(&func->dev, bus_if); + dev_set_drvdata(&sdiodev->func[1]->dev, bus_if); + sdiodev->dev = &sdiodev->func[1]->dev; - bus_if = sdiodev->bus_if; - sdiodev->dev = &func->dev; - dev_set_drvdata(&func->dev, bus_if); - - brcmf_dbg(TRACE, "F2 found, calling brcmf_sdio_probe...\n"); - ret = brcmf_sdio_probe(sdiodev); + atomic_set(&sdiodev->suspend, false); + init_waitqueue_head(&sdiodev->request_byte_wait); + init_waitqueue_head(&sdiodev->request_word_wait); + init_waitqueue_head(&sdiodev->request_chain_wait); + init_waitqueue_head(&sdiodev->request_buffer_wait); + err = brcmf_sdio_getintrcfg(sdiodev); + if (err) + goto fail; + + brcmf_dbg(TRACE, "F2 found, calling brcmf_sdio_probe...\n"); + err = brcmf_sdio_probe(sdiodev); + if (err) { + brcmf_dbg(ERROR, "F2 error, probe failed %d...\n", err); + goto fail; } + brcmf_dbg(TRACE, "F2 init completed...\n"); + return 0; - return ret; +fail: + dev_set_drvdata(&func->dev, NULL); + dev_set_drvdata(&sdiodev->func[1]->dev, NULL); + kfree(sdiodev); + kfree(bus_if); + return err; } static void brcmf_ops_sdio_remove(struct sdio_func *func) { struct brcmf_bus *bus_if; struct brcmf_sdio_dev *sdiodev; + brcmf_dbg(TRACE, "Enter\n"); - brcmf_dbg(INFO, "func->class=%x\n", func->class); - brcmf_dbg(INFO, "sdio_vendor: 0x%04x\n", func->vendor); - brcmf_dbg(INFO, "sdio_device: 0x%04x\n", func->device); - brcmf_dbg(INFO, "Function#: 0x%04x\n", func->num); + brcmf_dbg(TRACE, "sdio vendor ID: 0x%04x\n", func->vendor); + brcmf_dbg(TRACE, "sdio device ID: 0x%04x\n", func->device); + brcmf_dbg(TRACE, "Function: %d\n", func->num); + + if (func->num != 1 && func->num != 2) + return; - if (func->num == 2) { - bus_if = dev_get_drvdata(&func->dev); + bus_if = dev_get_drvdata(&func->dev); + if (bus_if) { sdiodev = bus_if->bus_priv.sdio; - brcmf_dbg(TRACE, "F2 found, calling brcmf_sdio_remove...\n"); brcmf_sdio_remove(sdiodev); - dev_set_drvdata(&func->card->dev, NULL); - dev_set_drvdata(&func->dev, NULL); + + dev_set_drvdata(&sdiodev->func[1]->dev, NULL); + dev_set_drvdata(&sdiodev->func[2]->dev, NULL); + kfree(bus_if); kfree(sdiodev); } + + brcmf_dbg(TRACE, "Exit\n"); } #ifdef CONFIG_PM_SLEEP static int brcmf_sdio_suspend(struct device *dev) { mmc_pm_flag_t sdio_flags; - struct sdio_func *func = dev_to_sdio_func(dev); - struct brcmf_sdio_dev *sdiodev = dev_get_drvdata(&func->card->dev); + struct brcmf_bus *bus_if = dev_get_drvdata(dev); + struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; int ret = 0; brcmf_dbg(TRACE, "\n"); @@ -570,8 +581,8 @@ static int brcmf_sdio_suspend(struct device *dev) static int brcmf_sdio_resume(struct device *dev) { - struct sdio_func *func = dev_to_sdio_func(dev); - struct brcmf_sdio_dev *sdiodev = dev_get_drvdata(&func->card->dev); + struct brcmf_bus *bus_if = dev_get_drvdata(dev); + struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; brcmf_sdio_wdtmr_enable(sdiodev, true); atomic_set(&sdiodev->suspend, false); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h index 9807092c49cb..24bc4e3e162b 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h @@ -23,6 +23,8 @@ #define BRCMF_VERSION_STR "4.218.248.5" +#include "fweh.h" + /******************************************************************************* * IO codes that are interpreted by dongle firmware ******************************************************************************/ @@ -38,8 +40,11 @@ #define BRCMF_C_GET_SSID 25 #define BRCMF_C_SET_SSID 26 #define BRCMF_C_GET_CHANNEL 29 +#define BRCMF_C_SET_CHANNEL 30 #define BRCMF_C_GET_SRL 31 +#define BRCMF_C_SET_SRL 32 #define BRCMF_C_GET_LRL 33 +#define BRCMF_C_SET_LRL 34 #define BRCMF_C_GET_RADIO 37 #define BRCMF_C_SET_RADIO 38 #define BRCMF_C_GET_PHYTYPE 39 @@ -58,6 +63,7 @@ #define BRCMF_C_SET_COUNTRY 84 #define BRCMF_C_GET_PM 85 #define BRCMF_C_SET_PM 86 +#define BRCMF_C_GET_CURR_RATESET 114 #define BRCMF_C_GET_AP 117 #define BRCMF_C_SET_AP 118 #define BRCMF_C_GET_RSSI 127 @@ -65,6 +71,7 @@ #define BRCMF_C_SET_WSEC 134 #define BRCMF_C_GET_PHY_NOISE 135 #define BRCMF_C_GET_BSS_INFO 136 +#define BRCMF_C_GET_PHYLIST 180 #define BRCMF_C_SET_SCAN_CHANNEL_TIME 185 #define BRCMF_C_SET_SCAN_UNASSOC_TIME 187 #define BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON 201 @@ -100,16 +107,8 @@ #define BRCMF_SCAN_PARAMS_COUNT_MASK 0x0000ffff #define BRCMF_SCAN_PARAMS_NSSID_SHIFT 16 -/* Indicates this key is using soft encrypt */ -#define WL_SOFT_KEY (1 << 0) /* primary (ie tx) key */ #define BRCMF_PRIMARY_KEY (1 << 1) -/* Reserved for backward compat */ -#define WL_KF_RES_4 (1 << 4) -/* Reserved for backward compat */ -#define WL_KF_RES_5 (1 << 5) -/* Indicates a group key for a IBSS PEER */ -#define WL_IBSS_PEER_GROUP_KEY (1 << 6) /* For supporting multiple interfaces */ #define BRCMF_MAX_IFS 16 @@ -117,10 +116,6 @@ #define DOT11_BSSTYPE_ANY 2 #define DOT11_MAX_DEFAULT_KEYS 4 -#define BRCMF_EVENT_MSG_LINK 0x01 -#define BRCMF_EVENT_MSG_FLUSHTXQ 0x02 -#define BRCMF_EVENT_MSG_GROUP 0x04 - #define BRCMF_ESCAN_REQ_VERSION 1 #define WLC_BSS_RSSI_ON_CHANNEL 0x0002 @@ -128,108 +123,6 @@ #define BRCMF_MAXRATES_IN_SET 16 /* max # of rates in rateset */ #define BRCMF_STA_ASSOC 0x10 /* Associated */ -struct brcmf_event_msg { - __be16 version; - __be16 flags; - __be32 event_type; - __be32 status; - __be32 reason; - __be32 auth_type; - __be32 datalen; - u8 addr[ETH_ALEN]; - char ifname[IFNAMSIZ]; - u8 ifidx; - u8 bsscfgidx; -} __packed; - -struct brcm_ethhdr { - u16 subtype; - u16 length; - u8 version; - u8 oui[3]; - u16 usr_subtype; -} __packed; - -struct brcmf_event { - struct ethhdr eth; - struct brcm_ethhdr hdr; - struct brcmf_event_msg msg; -} __packed; - -/* event codes sent by the dongle to this driver */ -#define BRCMF_E_SET_SSID 0 -#define BRCMF_E_JOIN 1 -#define BRCMF_E_START 2 -#define BRCMF_E_AUTH 3 -#define BRCMF_E_AUTH_IND 4 -#define BRCMF_E_DEAUTH 5 -#define BRCMF_E_DEAUTH_IND 6 -#define BRCMF_E_ASSOC 7 -#define BRCMF_E_ASSOC_IND 8 -#define BRCMF_E_REASSOC 9 -#define BRCMF_E_REASSOC_IND 10 -#define BRCMF_E_DISASSOC 11 -#define BRCMF_E_DISASSOC_IND 12 -#define BRCMF_E_QUIET_START 13 -#define BRCMF_E_QUIET_END 14 -#define BRCMF_E_BEACON_RX 15 -#define BRCMF_E_LINK 16 -#define BRCMF_E_MIC_ERROR 17 -#define BRCMF_E_NDIS_LINK 18 -#define BRCMF_E_ROAM 19 -#define BRCMF_E_TXFAIL 20 -#define BRCMF_E_PMKID_CACHE 21 -#define BRCMF_E_RETROGRADE_TSF 22 -#define BRCMF_E_PRUNE 23 -#define BRCMF_E_AUTOAUTH 24 -#define BRCMF_E_EAPOL_MSG 25 -#define BRCMF_E_SCAN_COMPLETE 26 -#define BRCMF_E_ADDTS_IND 27 -#define BRCMF_E_DELTS_IND 28 -#define BRCMF_E_BCNSENT_IND 29 -#define BRCMF_E_BCNRX_MSG 30 -#define BRCMF_E_BCNLOST_MSG 31 -#define BRCMF_E_ROAM_PREP 32 -#define BRCMF_E_PFN_NET_FOUND 33 -#define BRCMF_E_PFN_NET_LOST 34 -#define BRCMF_E_RESET_COMPLETE 35 -#define BRCMF_E_JOIN_START 36 -#define BRCMF_E_ROAM_START 37 -#define BRCMF_E_ASSOC_START 38 -#define BRCMF_E_IBSS_ASSOC 39 -#define BRCMF_E_RADIO 40 -#define BRCMF_E_PSM_WATCHDOG 41 -#define BRCMF_E_PROBREQ_MSG 44 -#define BRCMF_E_SCAN_CONFIRM_IND 45 -#define BRCMF_E_PSK_SUP 46 -#define BRCMF_E_COUNTRY_CODE_CHANGED 47 -#define BRCMF_E_EXCEEDED_MEDIUM_TIME 48 -#define BRCMF_E_ICV_ERROR 49 -#define BRCMF_E_UNICAST_DECODE_ERROR 50 -#define BRCMF_E_MULTICAST_DECODE_ERROR 51 -#define BRCMF_E_TRACE 52 -#define BRCMF_E_IF 54 -#define BRCMF_E_RSSI 56 -#define BRCMF_E_PFN_SCAN_COMPLETE 57 -#define BRCMF_E_EXTLOG_MSG 58 -#define BRCMF_E_ACTION_FRAME 59 -#define BRCMF_E_ACTION_FRAME_COMPLETE 60 -#define BRCMF_E_PRE_ASSOC_IND 61 -#define BRCMF_E_PRE_REASSOC_IND 62 -#define BRCMF_E_CHANNEL_ADOPTED 63 -#define BRCMF_E_AP_STARTED 64 -#define BRCMF_E_DFS_AP_STOP 65 -#define BRCMF_E_DFS_AP_RESUME 66 -#define BRCMF_E_RESERVED1 67 -#define BRCMF_E_RESERVED2 68 -#define BRCMF_E_ESCAN_RESULT 69 -#define BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE 70 -#define BRCMF_E_DCS_REQUEST 73 - -#define BRCMF_E_FIFO_CREDIT_MAP 74 - -#define BRCMF_E_LAST 75 - #define BRCMF_E_STATUS_SUCCESS 0 #define BRCMF_E_STATUS_FAIL 1 #define BRCMF_E_STATUS_TIMEOUT 2 @@ -390,7 +283,7 @@ struct brcm_rateset_le { /* # rates in this set */ __le32 count; /* rates in 500kbps units w/hi bit set if basic */ - u8 rates[WL_NUMRATES]; + u8 rates[BRCMF_MAXRATES_IN_SET]; }; struct brcmf_ssid { @@ -617,11 +510,11 @@ struct brcmf_pub { struct mutex proto_block; unsigned char proto_buf[BRCMF_DCMD_MAXLEN]; - struct work_struct setmacaddr_work; - struct work_struct multicast_work; u8 macvalue[ETH_ALEN]; atomic_t pend_8021x_cnt; wait_queue_head_t pend_8021x_wait; + + struct brcmf_fweh_info fweh; #ifdef DEBUG struct dentry *dbgfs_dir; #endif @@ -658,6 +551,8 @@ struct brcmf_if { struct brcmf_cfg80211_vif *vif; struct net_device *ndev; struct net_device_stats stats; + struct work_struct setmacaddr_work; + struct work_struct multicast_work; int idx; s32 bssidx; u8 mac_addr[ETH_ALEN]; @@ -682,14 +577,9 @@ extern int brcmf_proto_cdc_query_dcmd(struct brcmf_pub *drvr, int ifidx, extern int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd, void *buf, uint len); -extern int brcmf_ifname2idx(struct brcmf_pub *drvr, char *name); -extern int brcmf_c_host_event(struct brcmf_pub *drvr, int *idx, - void *pktdata, struct brcmf_event_msg *, - void **data_ptr); - extern int brcmf_net_attach(struct brcmf_if *ifp); -extern struct brcmf_if *brcmf_add_if(struct device *dev, int ifidx, s32 bssidx, - char *name, u8 *mac_addr); +extern struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, int ifidx, + s32 bssidx, char *name, u8 *mac_addr); extern void brcmf_del_if(struct brcmf_pub *drvr, int ifidx); #endif /* _BRCMF_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h index 265580f5b270..b8f248797f62 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h @@ -45,7 +45,6 @@ struct brcmf_bus_dcmd { /* interface structure between common and bus layer */ struct brcmf_bus { - u8 type; /* bus type */ union { struct brcmf_sdio_dev *sdio; struct brcmf_usbdev *usb; @@ -85,7 +84,7 @@ extern bool brcmf_c_prec_enq(struct device *dev, struct pktq *q, struct sk_buff *pkt, int prec); /* Receive frame for delivery to OS. Callee disposes of rxp. */ -extern void brcmf_rx_frame(struct device *dev, int ifidx, +extern void brcmf_rx_frame(struct device *dev, u8 ifidx, struct sk_buff_head *rxlist); static inline void brcmf_rx_packet(struct device *dev, int ifidx, struct sk_buff *pkt) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c index 601d4d789a93..87536d38a4ca 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c @@ -23,8 +23,6 @@ #include <linux/types.h> #include <linux/netdevice.h> -#include <linux/sched.h> -#include <defs.h> #include <brcmu_utils.h> #include <brcmu_wifi.h> diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c index 3b311393f04a..eee7175f1515 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c @@ -18,10 +18,7 @@ #include <linux/kernel.h> #include <linux/string.h> -#include <linux/sched.h> #include <linux/netdevice.h> -#include <asm/unaligned.h> -#include <defs.h> #include <brcmu_wifi.h> #include <brcmu_utils.h> #include "dhd.h" @@ -30,9 +27,6 @@ #include "dhd_dbg.h" #include "fwil.h" -#define BRCM_OUI "\x00\x10\x18" -#define DOT11_OUI_LEN 3 -#define BCMILCP_BCM_SUBTYPE_EVENT 1 #define PKTFILTER_BUF_SIZE 128 #define BRCMF_ARPOL_MODE 0xb /* agent|snoop|peer_autoreply */ #define BRCMF_DEFAULT_BCN_TIMEOUT 3 @@ -40,8 +34,6 @@ #define BRCMF_DEFAULT_SCAN_UNASSOC_TIME 40 #define BRCMF_DEFAULT_PACKET_FILTER "100 0 0 0 0x01 0x00" -#define MSGTRACE_VERSION 1 - #ifdef DEBUG static const char brcmf_version[] = "Dongle Host Driver, version " BRCMF_VERSION_STR "\nCompiled on " @@ -51,22 +43,6 @@ static const char brcmf_version[] = "Dongle Host Driver, version " BRCMF_VERSION_STR; #endif -/* Message trace header */ -struct msgtrace_hdr { - u8 version; - u8 spare; - __be16 len; /* Len of the trace */ - __be32 seqnum; /* Sequence number of message. Useful - * if the messsage has been lost - * because of DMA error or a bus reset - * (ex: SDIO Func2) - */ - __be32 discarded_bytes; /* Number of discarded bytes because of - trace overflow */ - __be32 discarded_printf; /* Number of discarded printf - because of trace overflow */ -} __packed; - bool brcmf_c_prec_enq(struct device *dev, struct pktq *q, struct sk_buff *pkt, int prec) @@ -118,405 +94,6 @@ bool brcmf_c_prec_enq(struct device *dev, struct pktq *q, return p != NULL; } -#ifdef DEBUG -static void -brcmf_c_show_host_event(struct brcmf_event_msg *event, void *event_data) -{ - uint i, status, reason; - bool group = false, flush_txq = false, link = false; - char *auth_str, *event_name; - unsigned char *buf; - char err_msg[256], eabuf[ETHER_ADDR_STR_LEN]; - static struct { - uint event; - char *event_name; - } event_names[] = { - { - BRCMF_E_SET_SSID, "SET_SSID"}, { - BRCMF_E_JOIN, "JOIN"}, { - BRCMF_E_START, "START"}, { - BRCMF_E_AUTH, "AUTH"}, { - BRCMF_E_AUTH_IND, "AUTH_IND"}, { - BRCMF_E_DEAUTH, "DEAUTH"}, { - BRCMF_E_DEAUTH_IND, "DEAUTH_IND"}, { - BRCMF_E_ASSOC, "ASSOC"}, { - BRCMF_E_ASSOC_IND, "ASSOC_IND"}, { - BRCMF_E_REASSOC, "REASSOC"}, { - BRCMF_E_REASSOC_IND, "REASSOC_IND"}, { - BRCMF_E_DISASSOC, "DISASSOC"}, { - BRCMF_E_DISASSOC_IND, "DISASSOC_IND"}, { - BRCMF_E_QUIET_START, "START_QUIET"}, { - BRCMF_E_QUIET_END, "END_QUIET"}, { - BRCMF_E_BEACON_RX, "BEACON_RX"}, { - BRCMF_E_LINK, "LINK"}, { - BRCMF_E_MIC_ERROR, "MIC_ERROR"}, { - BRCMF_E_NDIS_LINK, "NDIS_LINK"}, { - BRCMF_E_ROAM, "ROAM"}, { - BRCMF_E_TXFAIL, "TXFAIL"}, { - BRCMF_E_PMKID_CACHE, "PMKID_CACHE"}, { - BRCMF_E_RETROGRADE_TSF, "RETROGRADE_TSF"}, { - BRCMF_E_PRUNE, "PRUNE"}, { - BRCMF_E_AUTOAUTH, "AUTOAUTH"}, { - BRCMF_E_EAPOL_MSG, "EAPOL_MSG"}, { - BRCMF_E_SCAN_COMPLETE, "SCAN_COMPLETE"}, { - BRCMF_E_ADDTS_IND, "ADDTS_IND"}, { - BRCMF_E_DELTS_IND, "DELTS_IND"}, { - BRCMF_E_BCNSENT_IND, "BCNSENT_IND"}, { - BRCMF_E_BCNRX_MSG, "BCNRX_MSG"}, { - BRCMF_E_BCNLOST_MSG, "BCNLOST_MSG"}, { - BRCMF_E_ROAM_PREP, "ROAM_PREP"}, { - BRCMF_E_PFN_NET_FOUND, "PNO_NET_FOUND"}, { - BRCMF_E_PFN_NET_LOST, "PNO_NET_LOST"}, { - BRCMF_E_RESET_COMPLETE, "RESET_COMPLETE"}, { - BRCMF_E_JOIN_START, "JOIN_START"}, { - BRCMF_E_ROAM_START, "ROAM_START"}, { - BRCMF_E_ASSOC_START, "ASSOC_START"}, { - BRCMF_E_IBSS_ASSOC, "IBSS_ASSOC"}, { - BRCMF_E_RADIO, "RADIO"}, { - BRCMF_E_PSM_WATCHDOG, "PSM_WATCHDOG"}, { - BRCMF_E_PROBREQ_MSG, "PROBREQ_MSG"}, { - BRCMF_E_SCAN_CONFIRM_IND, "SCAN_CONFIRM_IND"}, { - BRCMF_E_PSK_SUP, "PSK_SUP"}, { - BRCMF_E_COUNTRY_CODE_CHANGED, "COUNTRY_CODE_CHANGED"}, { - BRCMF_E_EXCEEDED_MEDIUM_TIME, "EXCEEDED_MEDIUM_TIME"}, { - BRCMF_E_ICV_ERROR, "ICV_ERROR"}, { - BRCMF_E_UNICAST_DECODE_ERROR, "UNICAST_DECODE_ERROR"}, { - BRCMF_E_MULTICAST_DECODE_ERROR, "MULTICAST_DECODE_ERROR"}, { - BRCMF_E_TRACE, "TRACE"}, { - BRCMF_E_ACTION_FRAME, "ACTION FRAME"}, { - BRCMF_E_ACTION_FRAME_COMPLETE, "ACTION FRAME TX COMPLETE"}, { - BRCMF_E_IF, "IF"}, { - BRCMF_E_RSSI, "RSSI"}, { - BRCMF_E_PFN_SCAN_COMPLETE, "SCAN_COMPLETE"}, { - BRCMF_E_ESCAN_RESULT, "ESCAN_RESULT"} - }; - uint event_type, flags, auth_type, datalen; - static u32 seqnum_prev; - struct msgtrace_hdr hdr; - u32 nblost; - char *s, *p; - - event_type = be32_to_cpu(event->event_type); - flags = be16_to_cpu(event->flags); - status = be32_to_cpu(event->status); - reason = be32_to_cpu(event->reason); - auth_type = be32_to_cpu(event->auth_type); - datalen = be32_to_cpu(event->datalen); - /* debug dump of event messages */ - sprintf(eabuf, "%pM", event->addr); - - event_name = "UNKNOWN"; - for (i = 0; i < ARRAY_SIZE(event_names); i++) { - if (event_names[i].event == event_type) - event_name = event_names[i].event_name; - } - - brcmf_dbg(EVENT, "EVENT: %s, event ID = %d\n", event_name, event_type); - brcmf_dbg(EVENT, "flags 0x%04x, status %d, reason %d, auth_type %d MAC %s\n", - flags, status, reason, auth_type, eabuf); - - if (flags & BRCMF_EVENT_MSG_LINK) - link = true; - if (flags & BRCMF_EVENT_MSG_GROUP) - group = true; - if (flags & BRCMF_EVENT_MSG_FLUSHTXQ) - flush_txq = true; - - switch (event_type) { - case BRCMF_E_START: - case BRCMF_E_DEAUTH: - case BRCMF_E_DISASSOC: - brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s\n", event_name, eabuf); - break; - - case BRCMF_E_ASSOC_IND: - case BRCMF_E_REASSOC_IND: - brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s\n", event_name, eabuf); - break; - - case BRCMF_E_ASSOC: - case BRCMF_E_REASSOC: - if (status == BRCMF_E_STATUS_SUCCESS) - brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, SUCCESS\n", - event_name, eabuf); - else if (status == BRCMF_E_STATUS_TIMEOUT) - brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, TIMEOUT\n", - event_name, eabuf); - else if (status == BRCMF_E_STATUS_FAIL) - brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, FAILURE, reason %d\n", - event_name, eabuf, (int)reason); - else - brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, unexpected status %d\n", - event_name, eabuf, (int)status); - break; - - case BRCMF_E_DEAUTH_IND: - case BRCMF_E_DISASSOC_IND: - brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, reason %d\n", - event_name, eabuf, (int)reason); - break; - - case BRCMF_E_AUTH: - case BRCMF_E_AUTH_IND: - if (auth_type == WLAN_AUTH_OPEN) - auth_str = "Open System"; - else if (auth_type == WLAN_AUTH_SHARED_KEY) - auth_str = "Shared Key"; - else { - sprintf(err_msg, "AUTH unknown: %d", (int)auth_type); - auth_str = err_msg; - } - if (event_type == BRCMF_E_AUTH_IND) - brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, %s\n", - event_name, eabuf, auth_str); - else if (status == BRCMF_E_STATUS_SUCCESS) - brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, %s, SUCCESS\n", - event_name, eabuf, auth_str); - else if (status == BRCMF_E_STATUS_TIMEOUT) - brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, %s, TIMEOUT\n", - event_name, eabuf, auth_str); - else if (status == BRCMF_E_STATUS_FAIL) { - brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, %s, FAILURE, reason %d\n", - event_name, eabuf, auth_str, (int)reason); - } - - break; - - case BRCMF_E_JOIN: - case BRCMF_E_ROAM: - case BRCMF_E_SET_SSID: - if (status == BRCMF_E_STATUS_SUCCESS) - brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s\n", - event_name, eabuf); - else if (status == BRCMF_E_STATUS_FAIL) - brcmf_dbg(EVENT, "MACEVENT: %s, failed\n", event_name); - else if (status == BRCMF_E_STATUS_NO_NETWORKS) - brcmf_dbg(EVENT, "MACEVENT: %s, no networks found\n", - event_name); - else - brcmf_dbg(EVENT, "MACEVENT: %s, unexpected status %d\n", - event_name, (int)status); - break; - - case BRCMF_E_BEACON_RX: - if (status == BRCMF_E_STATUS_SUCCESS) - brcmf_dbg(EVENT, "MACEVENT: %s, SUCCESS\n", event_name); - else if (status == BRCMF_E_STATUS_FAIL) - brcmf_dbg(EVENT, "MACEVENT: %s, FAIL\n", event_name); - else - brcmf_dbg(EVENT, "MACEVENT: %s, status %d\n", - event_name, status); - break; - - case BRCMF_E_LINK: - brcmf_dbg(EVENT, "MACEVENT: %s %s\n", - event_name, link ? "UP" : "DOWN"); - break; - - case BRCMF_E_MIC_ERROR: - brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, Group %d, Flush %d\n", - event_name, eabuf, group, flush_txq); - break; - - case BRCMF_E_ICV_ERROR: - case BRCMF_E_UNICAST_DECODE_ERROR: - case BRCMF_E_MULTICAST_DECODE_ERROR: - brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s\n", event_name, eabuf); - break; - - case BRCMF_E_TXFAIL: - brcmf_dbg(EVENT, "MACEVENT: %s, RA %s\n", event_name, eabuf); - break; - - case BRCMF_E_SCAN_COMPLETE: - case BRCMF_E_PMKID_CACHE: - brcmf_dbg(EVENT, "MACEVENT: %s\n", event_name); - break; - - case BRCMF_E_ESCAN_RESULT: - brcmf_dbg(EVENT, "MACEVENT: %s\n", event_name); - datalen = 0; - break; - - case BRCMF_E_PFN_NET_FOUND: - case BRCMF_E_PFN_NET_LOST: - case BRCMF_E_PFN_SCAN_COMPLETE: - brcmf_dbg(EVENT, "PNOEVENT: %s\n", event_name); - break; - - case BRCMF_E_PSK_SUP: - case BRCMF_E_PRUNE: - brcmf_dbg(EVENT, "MACEVENT: %s, status %d, reason %d\n", - event_name, (int)status, (int)reason); - break; - - case BRCMF_E_TRACE: - buf = (unsigned char *) event_data; - memcpy(&hdr, buf, sizeof(struct msgtrace_hdr)); - - if (hdr.version != MSGTRACE_VERSION) { - brcmf_dbg(ERROR, - "MACEVENT: %s [unsupported version --> brcmf" - " version:%d dongle version:%d]\n", - event_name, MSGTRACE_VERSION, hdr.version); - /* Reset datalen to avoid display below */ - datalen = 0; - break; - } - - /* There are 2 bytes available at the end of data */ - *(buf + sizeof(struct msgtrace_hdr) - + be16_to_cpu(hdr.len)) = '\0'; - - if (be32_to_cpu(hdr.discarded_bytes) - || be32_to_cpu(hdr.discarded_printf)) - brcmf_dbg(ERROR, - "WLC_E_TRACE: [Discarded traces in dongle -->" - " discarded_bytes %d discarded_printf %d]\n", - be32_to_cpu(hdr.discarded_bytes), - be32_to_cpu(hdr.discarded_printf)); - - nblost = be32_to_cpu(hdr.seqnum) - seqnum_prev - 1; - if (nblost > 0) - brcmf_dbg(ERROR, "WLC_E_TRACE: [Event lost --> seqnum " - " %d nblost %d\n", be32_to_cpu(hdr.seqnum), - nblost); - seqnum_prev = be32_to_cpu(hdr.seqnum); - - /* Display the trace buffer. Advance from \n to \n to - * avoid display big - * printf (issue with Linux printk ) - */ - p = (char *)&buf[sizeof(struct msgtrace_hdr)]; - while ((s = strstr(p, "\n")) != NULL) { - *s = '\0'; - pr_debug("%s\n", p); - p = s + 1; - } - pr_debug("%s\n", p); - - /* Reset datalen to avoid display below */ - datalen = 0; - break; - - case BRCMF_E_RSSI: - brcmf_dbg(EVENT, "MACEVENT: %s %d\n", - event_name, be32_to_cpu(*((__be32 *)event_data))); - break; - - default: - brcmf_dbg(EVENT, - "MACEVENT: %s %d, MAC %s, status %d, reason %d, " - "auth %d\n", event_name, event_type, eabuf, - (int)status, (int)reason, (int)auth_type); - break; - } - - /* show any appended data */ - brcmf_dbg_hex_dump(datalen, event_data, datalen, "Received data"); -} -#endif /* DEBUG */ - -int -brcmf_c_host_event(struct brcmf_pub *drvr, int *ifidx, void *pktdata, - struct brcmf_event_msg *event, void **data_ptr) -{ - /* check whether packet is a BRCM event pkt */ - struct brcmf_event *pvt_data = (struct brcmf_event *) pktdata; - struct brcmf_if_event *ifevent; - struct brcmf_if *ifp; - char *event_data; - u32 type, status; - u16 flags; - int evlen; - - if (memcmp(BRCM_OUI, &pvt_data->hdr.oui[0], DOT11_OUI_LEN)) { - brcmf_dbg(ERROR, "mismatched OUI, bailing\n"); - return -EBADE; - } - - /* BRCM event pkt may be unaligned - use xxx_ua to load user_subtype. */ - if (get_unaligned_be16(&pvt_data->hdr.usr_subtype) != - BCMILCP_BCM_SUBTYPE_EVENT) { - brcmf_dbg(ERROR, "mismatched subtype, bailing\n"); - return -EBADE; - } - - *data_ptr = &pvt_data[1]; - event_data = *data_ptr; - - /* memcpy since BRCM event pkt may be unaligned. */ - memcpy(event, &pvt_data->msg, sizeof(struct brcmf_event_msg)); - - type = get_unaligned_be32(&event->event_type); - flags = get_unaligned_be16(&event->flags); - status = get_unaligned_be32(&event->status); - evlen = get_unaligned_be32(&event->datalen) + - sizeof(struct brcmf_event); - - switch (type) { - case BRCMF_E_IF: - ifevent = (struct brcmf_if_event *) event_data; - brcmf_dbg(TRACE, "if event\n"); - - if (ifevent->ifidx > 0 && ifevent->ifidx < BRCMF_MAX_IFS) { - if (ifevent->action == BRCMF_E_IF_ADD) { - ifp = brcmf_add_if(drvr->dev, ifevent->ifidx, - ifevent->bssidx, - event->ifname, - pvt_data->eth.h_dest); - if (IS_ERR(ifp)) - return PTR_ERR(ifp); - brcmf_net_attach(ifp); - } else { - brcmf_del_if(drvr, ifevent->ifidx); - } - } else { - brcmf_dbg(ERROR, "Invalid ifidx %d for %s\n", - ifevent->ifidx, event->ifname); - } - - /* send up the if event: btamp user needs it */ - *ifidx = brcmf_ifname2idx(drvr, event->ifname); - break; - - /* These are what external supplicant/authenticator wants */ - case BRCMF_E_LINK: - case BRCMF_E_ASSOC_IND: - case BRCMF_E_REASSOC_IND: - case BRCMF_E_DISASSOC_IND: - case BRCMF_E_MIC_ERROR: - default: - /* Fall through: this should get _everything_ */ - - *ifidx = brcmf_ifname2idx(drvr, event->ifname); - brcmf_dbg(TRACE, "MAC event %d, flags %x, status %x\n", - type, flags, status); - - /* put it back to BRCMF_E_NDIS_LINK */ - if (type == BRCMF_E_NDIS_LINK) { - u32 temp1; - __be32 temp2; - - temp1 = get_unaligned_be32(&event->event_type); - brcmf_dbg(TRACE, "Converted to WLC_E_LINK type %d\n", - temp1); - - temp2 = cpu_to_be32(BRCMF_E_NDIS_LINK); - memcpy((void *)(&pvt_data->msg.event_type), &temp2, - sizeof(pvt_data->msg.event_type)); - } - break; - } - -#ifdef DEBUG - if (BRCMF_EVENT_ON()) - brcmf_c_show_host_event(event, event_data); -#endif /* DEBUG */ - - return 0; -} - /* Convert user's input in hex pattern to byte-size mask */ static int brcmf_c_pattern_atoh(char *src, char *dst) { diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c index 49f53ba6eced..7e58e8ce9aba 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c @@ -14,17 +14,12 @@ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <linux/debugfs.h> -#include <linux/if_ether.h> -#include <linux/if.h> #include <linux/netdevice.h> -#include <linux/ieee80211.h> #include <linux/module.h> -#include <defs.h> #include <brcmu_wifi.h> #include <brcmu_utils.h> #include "dhd.h" -#include "dhd_bus.h" #include "dhd_dbg.h" static struct dentry *root_folder; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c index c2cd28e20d53..b6c86b046c15 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c @@ -16,27 +16,11 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#include <linux/init.h> #include <linux/kernel.h> -#include <linux/kthread.h> -#include <linux/slab.h> -#include <linux/skbuff.h> -#include <linux/netdevice.h> #include <linux/etherdevice.h> -#include <linux/mmc/sdio_func.h> -#include <linux/random.h> -#include <linux/spinlock.h> -#include <linux/ethtool.h> -#include <linux/fcntl.h> -#include <linux/fs.h> -#include <linux/uaccess.h> -#include <linux/hardirq.h> -#include <linux/mutex.h> -#include <linux/wait.h> #include <linux/module.h> #include <net/cfg80211.h> #include <net/rtnetlink.h> -#include <defs.h> #include <brcmu_utils.h> #include <brcmu_wifi.h> @@ -48,8 +32,8 @@ #include "fwil.h" MODULE_AUTHOR("Broadcom Corporation"); -MODULE_DESCRIPTION("Broadcom 802.11n wireless LAN fullmac driver."); -MODULE_SUPPORTED_DEVICE("Broadcom 802.11n WLAN fullmac cards"); +MODULE_DESCRIPTION("Broadcom 802.11 wireless LAN fullmac driver."); +MODULE_SUPPORTED_DEVICE("Broadcom 802.11 WLAN fullmac cards"); MODULE_LICENSE("Dual BSD/GPL"); #define MAX_WAIT_FOR_8021X_TX 50 /* msecs */ @@ -58,24 +42,6 @@ MODULE_LICENSE("Dual BSD/GPL"); int brcmf_msg_level = BRCMF_ERROR_VAL; module_param(brcmf_msg_level, int, 0); -int brcmf_ifname2idx(struct brcmf_pub *drvr, char *name) -{ - int i = BRCMF_MAX_IFS; - struct brcmf_if *ifp; - - if (name == NULL || *name == '\0') - return 0; - - while (--i > 0) { - ifp = drvr->iflist[i]; - if (ifp && !strncmp(ifp->ndev->name, name, IFNAMSIZ)) - break; - } - - brcmf_dbg(TRACE, "return idx %d for \"%s\"\n", i, name); - - return i; /* default - the primary interface */ -} char *brcmf_ifname(struct brcmf_pub *drvr, int ifidx) { @@ -105,12 +71,10 @@ static void _brcmf_set_multicast_list(struct work_struct *work) char *buf, *bufp; u32 buflen; s32 err; - struct brcmf_pub *drvr = container_of(work, struct brcmf_pub, - multicast_work); brcmf_dbg(TRACE, "enter\n"); - ifp = drvr->iflist[0]; + ifp = container_of(work, struct brcmf_if, multicast_work); ndev = ifp->ndev; /* Determine initial value of allmulti flag */ @@ -165,45 +129,37 @@ static void _brcmf_set_mac_address(struct work_struct *work) { struct brcmf_if *ifp; - struct net_device *ndev; s32 err; - struct brcmf_pub *drvr = container_of(work, struct brcmf_pub, - setmacaddr_work); - brcmf_dbg(TRACE, "enter\n"); - ifp = drvr->iflist[0]; - ndev = ifp->ndev; - - err = brcmf_fil_iovar_data_set(ifp, "cur_etheraddr", drvr->macvalue, + ifp = container_of(work, struct brcmf_if, setmacaddr_work); + err = brcmf_fil_iovar_data_set(ifp, "cur_etheraddr", ifp->mac_addr, ETH_ALEN); if (err < 0) { brcmf_dbg(ERROR, "Setting cur_etheraddr failed, %d\n", err); } else { brcmf_dbg(TRACE, "MAC address updated to %pM\n", - drvr->macvalue); - memcpy(ndev->dev_addr, drvr->macvalue, ETH_ALEN); + ifp->mac_addr); + memcpy(ifp->ndev->dev_addr, ifp->mac_addr, ETH_ALEN); } } static int brcmf_netdev_set_mac_address(struct net_device *ndev, void *addr) { struct brcmf_if *ifp = netdev_priv(ndev); - struct brcmf_pub *drvr = ifp->drvr; struct sockaddr *sa = (struct sockaddr *)addr; - memcpy(&drvr->macvalue, sa->sa_data, ETH_ALEN); - schedule_work(&drvr->setmacaddr_work); + memcpy(&ifp->mac_addr, sa->sa_data, ETH_ALEN); + schedule_work(&ifp->setmacaddr_work); return 0; } static void brcmf_netdev_set_multicast_list(struct net_device *ndev) { struct brcmf_if *ifp = netdev_priv(ndev); - struct brcmf_pub *drvr = ifp->drvr; - schedule_work(&drvr->multicast_work); + schedule_work(&ifp->multicast_work); } static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev) @@ -294,33 +250,13 @@ void brcmf_txflowblock(struct device *dev, bool state) } } -static int brcmf_host_event(struct brcmf_pub *drvr, int *ifidx, - void *pktdata, struct brcmf_event_msg *event, - void **data) -{ - int bcmerror = 0; - - bcmerror = brcmf_c_host_event(drvr, ifidx, pktdata, event, data); - if (bcmerror != 0) - return bcmerror; - - /* only forward if interface has netdev */ - if (drvr->iflist[*ifidx]->ndev) - brcmf_cfg80211_event(drvr->iflist[*ifidx], - event, *data); - - return bcmerror; -} - -void brcmf_rx_frame(struct device *dev, int ifidx, +void brcmf_rx_frame(struct device *dev, u8 ifidx, struct sk_buff_head *skb_list) { unsigned char *eth; uint len; - void *data; struct sk_buff *skb, *pnext; struct brcmf_if *ifp; - struct brcmf_event_msg event; struct brcmf_bus *bus_if = dev_get_drvdata(dev); struct brcmf_pub *drvr = bus_if->drvr; @@ -367,10 +303,7 @@ void brcmf_rx_frame(struct device *dev, int ifidx, skb_pull(skb, ETH_HLEN); /* Process special event packets and then discard them */ - if (ntohs(skb->protocol) == ETH_P_LINK_CTL) - brcmf_host_event(drvr, &ifidx, - skb_mac_header(skb), - &event, &data); + brcmf_fweh_process_skb(drvr, skb, &ifidx); if (drvr->iflist[ifidx]) { ifp = drvr->iflist[ifidx]; @@ -605,7 +538,7 @@ static int brcmf_netdev_stop(struct net_device *ndev) if (drvr->bus_if->drvr_up == 0) return 0; - brcmf_cfg80211_down(drvr->config); + brcmf_cfg80211_down(ndev); /* Set state and stop OS transmissions */ drvr->bus_if->drvr_up = false; @@ -624,26 +557,24 @@ static int brcmf_netdev_open(struct net_device *ndev) brcmf_dbg(TRACE, "ifidx %d\n", ifp->idx); - if (ifp->idx == 0) { /* do it only for primary eth0 */ - /* If bus is not ready, can't continue */ - if (bus_if->state != BRCMF_BUS_DATA) { - brcmf_dbg(ERROR, "failed bus is not ready\n"); - return -EAGAIN; - } + /* If bus is not ready, can't continue */ + if (bus_if->state != BRCMF_BUS_DATA) { + brcmf_dbg(ERROR, "failed bus is not ready\n"); + return -EAGAIN; + } - atomic_set(&drvr->pend_8021x_cnt, 0); + atomic_set(&drvr->pend_8021x_cnt, 0); - memcpy(ndev->dev_addr, drvr->mac, ETH_ALEN); + memcpy(ndev->dev_addr, drvr->mac, ETH_ALEN); - /* Get current TOE mode from dongle */ - if (brcmf_fil_iovar_int_get(ifp, "toe_ol", &toe_ol) >= 0 - && (toe_ol & TOE_TX_CSUM_OL) != 0) - drvr->iflist[ifp->idx]->ndev->features |= - NETIF_F_IP_CSUM; - else - drvr->iflist[ifp->idx]->ndev->features &= - ~NETIF_F_IP_CSUM; - } + /* Get current TOE mode from dongle */ + if (brcmf_fil_iovar_int_get(ifp, "toe_ol", &toe_ol) >= 0 + && (toe_ol & TOE_TX_CSUM_OL) != 0) + drvr->iflist[ifp->idx]->ndev->features |= + NETIF_F_IP_CSUM; + else + drvr->iflist[ifp->idx]->ndev->features &= + ~NETIF_F_IP_CSUM; /* make sure RF is ready for work */ brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0); @@ -651,7 +582,7 @@ static int brcmf_netdev_open(struct net_device *ndev) /* Allow transmit calls */ netif_start_queue(ndev); drvr->bus_if->drvr_up = true; - if (brcmf_cfg80211_up(drvr->config)) { + if (brcmf_cfg80211_up(ndev)) { brcmf_dbg(ERROR, "failed to bring up cfg80211\n"); return -1; } @@ -669,39 +600,38 @@ static const struct net_device_ops brcmf_netdev_ops_pri = { .ndo_set_rx_mode = brcmf_netdev_set_multicast_list }; +static const struct net_device_ops brcmf_netdev_ops_virt = { + .ndo_open = brcmf_cfg80211_up, + .ndo_stop = brcmf_cfg80211_down, + .ndo_get_stats = brcmf_netdev_get_stats, + .ndo_do_ioctl = brcmf_netdev_ioctl_entry, + .ndo_start_xmit = brcmf_netdev_start_xmit, + .ndo_set_mac_address = brcmf_netdev_set_mac_address, + .ndo_set_rx_mode = brcmf_netdev_set_multicast_list +}; + int brcmf_net_attach(struct brcmf_if *ifp) { struct brcmf_pub *drvr = ifp->drvr; struct net_device *ndev; - u8 temp_addr[ETH_ALEN]; - - brcmf_dbg(TRACE, "ifidx %d\n", ifp->idx); - ndev = drvr->iflist[ifp->idx]->ndev; - ndev->netdev_ops = &brcmf_netdev_ops_pri; + brcmf_dbg(TRACE, "ifidx %d mac %pM\n", ifp->idx, ifp->mac_addr); + ndev = ifp->ndev; - /* - * determine mac address to use - */ - if (is_valid_ether_addr(ifp->mac_addr)) - memcpy(temp_addr, ifp->mac_addr, ETH_ALEN); + /* set appropriate operations */ + if (!ifp->idx) + ndev->netdev_ops = &brcmf_netdev_ops_pri; else - memcpy(temp_addr, drvr->mac, ETH_ALEN); - - if (ifp->idx == 1) { - brcmf_dbg(TRACE, "ACCESS POINT MAC:\n"); - /* ACCESSPOINT INTERFACE CASE */ - temp_addr[0] |= 0X02; /* set bit 2 , - - Locally Administered address */ + ndev->netdev_ops = &brcmf_netdev_ops_virt; - } ndev->hard_header_len = ETH_HLEN + drvr->hdrlen; ndev->ethtool_ops = &brcmf_ethtool_ops; drvr->rxsz = ndev->mtu + ndev->hard_header_len + drvr->hdrlen; - memcpy(ndev->dev_addr, temp_addr, ETH_ALEN); + /* set the mac address */ + memcpy(ndev->dev_addr, ifp->mac_addr, ETH_ALEN); if (register_netdev(ndev) != 0) { brcmf_dbg(ERROR, "couldn't register the net device\n"); @@ -717,13 +647,12 @@ fail: return -EBADE; } -struct brcmf_if *brcmf_add_if(struct device *dev, int ifidx, s32 bssidx, - char *name, u8 *mac_addr) +struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, int ifidx, s32 bssidx, + char *name, u8 *addr_mask) { struct brcmf_if *ifp; struct net_device *ndev; - struct brcmf_bus *bus_if = dev_get_drvdata(dev); - struct brcmf_pub *drvr = bus_if->drvr; + int i; brcmf_dbg(TRACE, "idx %d\n", ifidx); @@ -733,12 +662,17 @@ struct brcmf_if *brcmf_add_if(struct device *dev, int ifidx, s32 bssidx, * in case we missed the BRCMF_E_IF_DEL event. */ if (ifp) { - brcmf_dbg(ERROR, "ERROR: netdev:%s already exists, try free & unregister\n", + brcmf_dbg(ERROR, "ERROR: netdev:%s already exists\n", ifp->ndev->name); - netif_stop_queue(ifp->ndev); - unregister_netdev(ifp->ndev); - free_netdev(ifp->ndev); - drvr->iflist[ifidx] = NULL; + if (ifidx) { + netif_stop_queue(ifp->ndev); + unregister_netdev(ifp->ndev); + free_netdev(ifp->ndev); + drvr->iflist[ifidx] = NULL; + } else { + brcmf_dbg(ERROR, "ignore IF event\n"); + return ERR_PTR(-EINVAL); + } } /* Allocate netdev, including space for private structure */ @@ -754,11 +688,16 @@ struct brcmf_if *brcmf_add_if(struct device *dev, int ifidx, s32 bssidx, drvr->iflist[ifidx] = ifp; ifp->idx = ifidx; ifp->bssidx = bssidx; - if (mac_addr != NULL) - memcpy(&ifp->mac_addr, mac_addr, ETH_ALEN); - brcmf_dbg(TRACE, " ==== pid:%x, net_device for if:%s created ===\n", - current->pid, ifp->ndev->name); + INIT_WORK(&ifp->setmacaddr_work, _brcmf_set_mac_address); + INIT_WORK(&ifp->multicast_work, _brcmf_set_multicast_list); + + if (addr_mask != NULL) + for (i = 0; i < ETH_ALEN; i++) + ifp->mac_addr[i] = drvr->mac[i] ^ addr_mask[i]; + + brcmf_dbg(TRACE, " ==== pid:%x, if:%s (%pM) created ===\n", + current->pid, ifp->ndev->name, ifp->mac_addr); return ifp; } @@ -785,6 +724,9 @@ void brcmf_del_if(struct brcmf_pub *drvr, int ifidx) netif_stop_queue(ifp->ndev); } + cancel_work_sync(&ifp->setmacaddr_work); + cancel_work_sync(&ifp->multicast_work); + unregister_netdev(ifp->ndev); drvr->iflist[ifidx] = NULL; if (ifidx == 0) @@ -823,8 +765,8 @@ int brcmf_attach(uint bus_hdrlen, struct device *dev) goto fail; } - INIT_WORK(&drvr->setmacaddr_work, _brcmf_set_mac_address); - INIT_WORK(&drvr->multicast_work, _brcmf_set_multicast_list); + /* attach firmware event handler */ + brcmf_fweh_attach(drvr); INIT_LIST_HEAD(&drvr->bus_if->dcmd_list); @@ -855,7 +797,7 @@ int brcmf_bus_start(struct device *dev) } /* add primary networking interface */ - ifp = brcmf_add_if(dev, 0, 0, "wlan%d", NULL); + ifp = brcmf_add_if(drvr, 0, 0, "wlan%d", NULL); if (IS_ERR(ifp)) return PTR_ERR(ifp); @@ -873,10 +815,14 @@ int brcmf_bus_start(struct device *dev) goto fail; } + ret = brcmf_fweh_activate_events(ifp); + if (ret < 0) + goto fail; + ret = brcmf_net_attach(ifp); fail: if (ret < 0) { - brcmf_dbg(ERROR, "brcmf_net_attach failed"); + brcmf_dbg(ERROR, "failed: %d\n", ret); if (drvr->config) brcmf_cfg80211_detach(drvr->config); free_netdev(drvr->iflist[0]->ndev); @@ -911,6 +857,9 @@ void brcmf_detach(struct device *dev) if (drvr == NULL) return; + /* stop firmware event handling */ + brcmf_fweh_detach(drvr); + /* make sure primary interface removed last */ for (i = BRCMF_MAX_IFS-1; i > -1; i--) if (drvr->iflist[i]) @@ -919,8 +868,6 @@ void brcmf_detach(struct device *dev) brcmf_bus_detach(drvr); if (drvr->prot) { - cancel_work_sync(&drvr->setmacaddr_work); - cancel_work_sync(&drvr->multicast_work); brcmf_proto_detach(drvr); } diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_proto.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_proto.h index 9b7969d8e76a..48fa70302192 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_proto.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_proto.h @@ -36,10 +36,6 @@ extern void brcmf_proto_stop(struct brcmf_pub *drvr); extern void brcmf_proto_hdrpush(struct brcmf_pub *, int ifidx, struct sk_buff *txp); -/* Use protocol to issue command to dongle */ -extern int brcmf_proto_dcmd(struct brcmf_pub *drvr, int ifidx, - struct brcmf_dcmd *dcmd, int len); - /* Sets dongle media info (drv_version, mac address). */ extern int brcmf_c_preinit_dcmds(struct brcmf_if *ifp); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index ba339f798aa5..45725454714d 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -3576,7 +3576,7 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus) } #ifdef DEBUG /* Poll for console output periodically */ - if (bus_if->state == BRCMF_BUS_DATA && + if (bus_if && bus_if->state == BRCMF_BUS_DATA && bus->console_interval != 0) { bus->console.count += BRCMF_WD_POLL_MS; if (bus->console.count >= bus->console_interval) { @@ -3867,7 +3867,8 @@ static void brcmf_sdbrcm_release(struct brcmf_sdio *bus) brcmf_sdio_intr_unregister(bus->sdiodev); cancel_work_sync(&bus->datawork); - destroy_workqueue(bus->brcmf_wq); + if (bus->brcmf_wq) + destroy_workqueue(bus->brcmf_wq); if (bus->sdiodev->bus_if->drvr) { brcmf_detach(bus->sdiodev->dev); @@ -3909,6 +3910,13 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev) bus->txminmax = BRCMF_TXMINMAX; bus->tx_seq = SDPCM_SEQUENCE_WRAP - 1; + INIT_WORK(&bus->datawork, brcmf_sdio_dataworker); + bus->brcmf_wq = create_singlethread_workqueue("brcmf_wq"); + if (bus->brcmf_wq == NULL) { + brcmf_dbg(ERROR, "insufficient memory to create txworkqueue\n"); + goto fail; + } + /* attempt to attach to the dongle */ if (!(brcmf_sdbrcm_probe_attach(bus, regsva))) { brcmf_dbg(ERROR, "brcmf_sdbrcm_probe_attach failed\n"); @@ -3920,13 +3928,6 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev) init_waitqueue_head(&bus->ctrl_wait); init_waitqueue_head(&bus->dcmd_resp_wait); - bus->brcmf_wq = create_singlethread_workqueue("brcmf_wq"); - if (bus->brcmf_wq == NULL) { - brcmf_dbg(ERROR, "insufficient memory to create txworkqueue\n"); - goto fail; - } - INIT_WORK(&bus->datawork, brcmf_sdio_dataworker); - /* Set up the watchdog timer */ init_timer(&bus->timer); bus->timer.data = (unsigned long)bus; @@ -3994,10 +3995,8 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev) /* if firmware path present try to download and bring up bus */ ret = brcmf_bus_start(bus->sdiodev->dev); if (ret != 0) { - if (ret == -ENOLINK) { - brcmf_dbg(ERROR, "dongle is not responding\n"); - goto fail; - } + brcmf_dbg(ERROR, "dongle is not responding\n"); + goto fail; } return bus; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fweh.c b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c new file mode 100644 index 000000000000..7a00c4614baf --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c @@ -0,0 +1,509 @@ +/* + * 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. + */ +#include <linux/netdevice.h> + +#include "brcmu_wifi.h" +#include "brcmu_utils.h" + +#include "dhd.h" +#include "dhd_dbg.h" +#include "fweh.h" +#include "fwil.h" + +/** + * struct brcm_ethhdr - broadcom specific ether header. + * + * @subtype: subtype for this packet. + * @length: TODO: length of appended data. + * @version: version indication. + * @oui: OUI of this packet. + * @usr_subtype: subtype for this OUI. + */ +struct brcm_ethhdr { + __be16 subtype; + __be16 length; + u8 version; + u8 oui[3]; + __be16 usr_subtype; +} __packed; + +struct brcmf_event_msg_be { + __be16 version; + __be16 flags; + __be32 event_type; + __be32 status; + __be32 reason; + __be32 auth_type; + __be32 datalen; + u8 addr[ETH_ALEN]; + char ifname[IFNAMSIZ]; + u8 ifidx; + u8 bsscfgidx; +} __packed; + +/** + * struct brcmf_event - contents of broadcom event packet. + * + * @eth: standard ether header. + * @hdr: broadcom specific ether header. + * @msg: common part of the actual event message. + */ +struct brcmf_event { + struct ethhdr eth; + struct brcm_ethhdr hdr; + struct brcmf_event_msg_be msg; +} __packed; + +/** + * struct brcmf_fweh_queue_item - event item on event queue. + * + * @q: list element for queuing. + * @code: event code. + * @ifidx: interface index related to this event. + * @ifaddr: ethernet address for interface. + * @emsg: common parameters of the firmware event message. + * @data: event specific data part of the firmware event. + */ +struct brcmf_fweh_queue_item { + struct list_head q; + enum brcmf_fweh_event_code code; + u8 ifidx; + u8 ifaddr[ETH_ALEN]; + struct brcmf_event_msg_be emsg; + u8 data[0]; +}; + +/** + * struct brcmf_fweh_event_name - code, name mapping entry. + */ +struct brcmf_fweh_event_name { + enum brcmf_fweh_event_code code; + const char *name; +}; + +#ifdef DEBUG +/* array for mapping code to event name */ +static struct brcmf_fweh_event_name fweh_event_names[] = { + { BRCMF_E_SET_SSID, "SET_SSID" }, + { BRCMF_E_JOIN, "JOIN" }, + { BRCMF_E_START, "START" }, + { BRCMF_E_AUTH, "AUTH" }, + { BRCMF_E_AUTH_IND, "AUTH_IND" }, + { BRCMF_E_DEAUTH, "DEAUTH" }, + { BRCMF_E_DEAUTH_IND, "DEAUTH_IND" }, + { BRCMF_E_ASSOC, "ASSOC" }, + { BRCMF_E_ASSOC_IND, "ASSOC_IND" }, + { BRCMF_E_REASSOC, "REASSOC" }, + { BRCMF_E_REASSOC_IND, "REASSOC_IND" }, + { BRCMF_E_DISASSOC, "DISASSOC" }, + { BRCMF_E_DISASSOC_IND, "DISASSOC_IND" }, + { BRCMF_E_QUIET_START, "START_QUIET" }, + { BRCMF_E_QUIET_END, "END_QUIET" }, + { BRCMF_E_BEACON_RX, "BEACON_RX" }, + { BRCMF_E_LINK, "LINK" }, + { BRCMF_E_MIC_ERROR, "MIC_ERROR" }, + { BRCMF_E_NDIS_LINK, "NDIS_LINK" }, + { BRCMF_E_ROAM, "ROAM" }, + { BRCMF_E_TXFAIL, "TXFAIL" }, + { BRCMF_E_PMKID_CACHE, "PMKID_CACHE" }, + { BRCMF_E_RETROGRADE_TSF, "RETROGRADE_TSF" }, + { BRCMF_E_PRUNE, "PRUNE" }, + { BRCMF_E_AUTOAUTH, "AUTOAUTH" }, + { BRCMF_E_EAPOL_MSG, "EAPOL_MSG" }, + { BRCMF_E_SCAN_COMPLETE, "SCAN_COMPLETE" }, + { BRCMF_E_ADDTS_IND, "ADDTS_IND" }, + { BRCMF_E_DELTS_IND, "DELTS_IND" }, + { BRCMF_E_BCNSENT_IND, "BCNSENT_IND" }, + { BRCMF_E_BCNRX_MSG, "BCNRX_MSG" }, + { BRCMF_E_BCNLOST_MSG, "BCNLOST_MSG" }, + { BRCMF_E_ROAM_PREP, "ROAM_PREP" }, + { BRCMF_E_PFN_NET_FOUND, "PNO_NET_FOUND" }, + { BRCMF_E_PFN_NET_LOST, "PNO_NET_LOST" }, + { BRCMF_E_RESET_COMPLETE, "RESET_COMPLETE" }, + { BRCMF_E_JOIN_START, "JOIN_START" }, + { BRCMF_E_ROAM_START, "ROAM_START" }, + { BRCMF_E_ASSOC_START, "ASSOC_START" }, + { BRCMF_E_IBSS_ASSOC, "IBSS_ASSOC" }, + { BRCMF_E_RADIO, "RADIO" }, + { BRCMF_E_PSM_WATCHDOG, "PSM_WATCHDOG" }, + { BRCMF_E_PROBREQ_MSG, "PROBREQ_MSG" }, + { BRCMF_E_SCAN_CONFIRM_IND, "SCAN_CONFIRM_IND" }, + { BRCMF_E_PSK_SUP, "PSK_SUP" }, + { BRCMF_E_COUNTRY_CODE_CHANGED, "COUNTRY_CODE_CHANGED" }, + { BRCMF_E_EXCEEDED_MEDIUM_TIME, "EXCEEDED_MEDIUM_TIME" }, + { BRCMF_E_ICV_ERROR, "ICV_ERROR" }, + { BRCMF_E_UNICAST_DECODE_ERROR, "UNICAST_DECODE_ERROR" }, + { BRCMF_E_MULTICAST_DECODE_ERROR, "MULTICAST_DECODE_ERROR" }, + { BRCMF_E_TRACE, "TRACE" }, + { BRCMF_E_IF, "IF" }, + { BRCMF_E_RSSI, "RSSI" }, + { BRCMF_E_PFN_SCAN_COMPLETE, "PFN_SCAN_COMPLETE" }, + { BRCMF_E_EXTLOG_MSG, "EXTLOG_MSG" }, + { BRCMF_E_ACTION_FRAME, "ACTION_FRAME" }, + { BRCMF_E_ACTION_FRAME_COMPLETE, "ACTION_FRAME_COMPLETE" }, + { BRCMF_E_PRE_ASSOC_IND, "PRE_ASSOC_IND" }, + { BRCMF_E_PRE_REASSOC_IND, "PRE_REASSOC_IND" }, + { BRCMF_E_CHANNEL_ADOPTED, "CHANNEL_ADOPTED" }, + { BRCMF_E_AP_STARTED, "AP_STARTED" }, + { BRCMF_E_DFS_AP_STOP, "DFS_AP_STOP" }, + { BRCMF_E_DFS_AP_RESUME, "DFS_AP_RESUME" }, + { BRCMF_E_ESCAN_RESULT, "ESCAN_RESULT" }, + { BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE, "ACTION_FRM_OFF_CHAN_CMPLT" }, + { BRCMF_E_DCS_REQUEST, "DCS_REQUEST" }, + { BRCMF_E_FIFO_CREDIT_MAP, "FIFO_CREDIT_MAP"} +}; + +/** + * brcmf_fweh_event_name() - returns name for given event code. + * + * @code: code to lookup. + */ +static const char *brcmf_fweh_event_name(enum brcmf_fweh_event_code code) +{ + int i; + for (i = 0; i < ARRAY_SIZE(fweh_event_names); i++) { + if (fweh_event_names[i].code == code) + return fweh_event_names[i].name; + } + return "unknown"; +} +#else +static const char *brcmf_fweh_event_name(enum brcmf_fweh_event_code code) +{ + return "nodebug"; +} +#endif + +/** + * brcmf_fweh_queue_event() - create and queue event. + * + * @fweh: firmware event handling info. + * @event: event queue entry. + */ +static void brcmf_fweh_queue_event(struct brcmf_fweh_info *fweh, + struct brcmf_fweh_queue_item *event) +{ + ulong flags; + + spin_lock_irqsave(&fweh->evt_q_lock, flags); + list_add_tail(&event->q, &fweh->event_q); + spin_unlock_irqrestore(&fweh->evt_q_lock, flags); + schedule_work(&fweh->event_work); +} + +static int brcmf_fweh_call_event_handler(struct brcmf_if *ifp, + enum brcmf_fweh_event_code code, + struct brcmf_event_msg *emsg, + void *data) +{ + struct brcmf_fweh_info *fweh; + int err = -EINVAL; + + if (ifp) { + fweh = &ifp->drvr->fweh; + + /* handle the event if valid interface and handler */ + if (ifp->ndev && fweh->evt_handler[code]) + err = fweh->evt_handler[code](ifp, emsg, data); + else + brcmf_dbg(ERROR, "unhandled event %d ignored\n", code); + } else { + brcmf_dbg(ERROR, "no interface object\n"); + } + return err; +} + +/** + * brcmf_fweh_handle_if_event() - handle IF event. + * + * @drvr: driver information object. + * @item: queue entry. + * @ifpp: interface object (may change upon ADD action). + */ +static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr, + struct brcmf_event_msg *emsg, + void *data) +{ + struct brcmf_if_event *ifevent = data; + struct brcmf_if *ifp; + int err = 0; + + brcmf_dbg(EVENT, "action: %u idx: %u bsscfg: %u flags: %u\n", + ifevent->action, ifevent->ifidx, + ifevent->bssidx, ifevent->flags); + + if (ifevent->ifidx >= BRCMF_MAX_IFS) { + brcmf_dbg(ERROR, "invalid interface index: %u\n", + ifevent->ifidx); + return; + } + + ifp = drvr->iflist[ifevent->ifidx]; + + if (ifevent->action == BRCMF_E_IF_ADD) { + brcmf_dbg(EVENT, "adding %s (%pM)\n", emsg->ifname, + emsg->addr); + ifp = brcmf_add_if(drvr, ifevent->ifidx, ifevent->bssidx, + emsg->ifname, emsg->addr); + if (IS_ERR(ifp)) + return; + + if (!drvr->fweh.evt_handler[BRCMF_E_IF]) + err = brcmf_net_attach(ifp); + } + + err = brcmf_fweh_call_event_handler(ifp, emsg->event_code, emsg, data); + + if (ifevent->action == BRCMF_E_IF_DEL) + brcmf_del_if(drvr, ifevent->ifidx); +} + +/** + * brcmf_fweh_dequeue_event() - get event from the queue. + * + * @fweh: firmware event handling info. + */ +static struct brcmf_fweh_queue_item * +brcmf_fweh_dequeue_event(struct brcmf_fweh_info *fweh) +{ + struct brcmf_fweh_queue_item *event = NULL; + ulong flags; + + spin_lock_irqsave(&fweh->evt_q_lock, flags); + if (!list_empty(&fweh->event_q)) { + event = list_first_entry(&fweh->event_q, + struct brcmf_fweh_queue_item, q); + list_del(&event->q); + } + spin_unlock_irqrestore(&fweh->evt_q_lock, flags); + + return event; +} + +/** + * brcmf_fweh_event_worker() - firmware event worker. + * + * @work: worker object. + */ +static void brcmf_fweh_event_worker(struct work_struct *work) +{ + struct brcmf_pub *drvr; + struct brcmf_if *ifp; + struct brcmf_fweh_info *fweh; + struct brcmf_fweh_queue_item *event; + int err = 0; + struct brcmf_event_msg_be *emsg_be; + struct brcmf_event_msg emsg; + + fweh = container_of(work, struct brcmf_fweh_info, event_work); + drvr = container_of(fweh, struct brcmf_pub, fweh); + + 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_fweh_event_name(event->code), event->code, + event->emsg.ifidx, event->emsg.bsscfgidx, + event->emsg.addr); + + /* convert event message */ + emsg_be = &event->emsg; + emsg.version = be16_to_cpu(emsg_be->version); + emsg.flags = be16_to_cpu(emsg_be->flags); + emsg.event_code = event->code; + emsg.status = be32_to_cpu(emsg_be->status); + emsg.reason = be32_to_cpu(emsg_be->reason); + emsg.auth_type = be32_to_cpu(emsg_be->auth_type); + emsg.datalen = be32_to_cpu(emsg_be->datalen); + memcpy(emsg.addr, emsg_be->addr, ETH_ALEN); + memcpy(emsg.ifname, emsg_be->ifname, sizeof(emsg.ifname)); + emsg.ifidx = emsg_be->ifidx; + emsg.bsscfgidx = emsg_be->bsscfgidx; + + brcmf_dbg(EVENT, " version %u flags %u status %u reason %u\n", + emsg.version, emsg.flags, emsg.status, emsg.reason); + brcmf_dbg_hex_dump(BRCMF_EVENT_ON(), event->data, + min_t(u32, emsg.datalen, 64), + "event payload, len=%d\n", emsg.datalen); + + /* special handling of interface event */ + if (event->code == BRCMF_E_IF) { + brcmf_fweh_handle_if_event(drvr, &emsg, event->data); + goto event_free; + } + + err = brcmf_fweh_call_event_handler(ifp, event->code, &emsg, + event->data); + if (err) { + brcmf_dbg(ERROR, "event handler failed (%d)\n", + event->code); + err = 0; + } +event_free: + kfree(event); + } +} + +/** + * brcmf_fweh_attach() - initialize firmware event handling. + * + * @drvr: driver information object. + */ +void brcmf_fweh_attach(struct brcmf_pub *drvr) +{ + struct brcmf_fweh_info *fweh = &drvr->fweh; + INIT_WORK(&fweh->event_work, brcmf_fweh_event_worker); + spin_lock_init(&fweh->evt_q_lock); + INIT_LIST_HEAD(&fweh->event_q); +} + +/** + * brcmf_fweh_detach() - cleanup firmware event handling. + * + * @drvr: driver information object. + */ +void brcmf_fweh_detach(struct brcmf_pub *drvr) +{ + struct brcmf_fweh_info *fweh = &drvr->fweh; + struct brcmf_if *ifp = drvr->iflist[0]; + s8 eventmask[BRCMF_EVENTING_MASK_LEN]; + + if (ifp) { + /* clear all events */ + memset(eventmask, 0, BRCMF_EVENTING_MASK_LEN); + (void)brcmf_fil_iovar_data_set(ifp, "event_msgs", + eventmask, + BRCMF_EVENTING_MASK_LEN); + } + /* cancel the worker */ + cancel_work_sync(&fweh->event_work); + WARN_ON(!list_empty(&fweh->event_q)); + memset(fweh->evt_handler, 0, sizeof(fweh->evt_handler)); +} + +/** + * brcmf_fweh_register() - register handler for given event code. + * + * @drvr: driver information object. + * @code: event code. + * @handler: handler for the given event code. + */ +int brcmf_fweh_register(struct brcmf_pub *drvr, enum brcmf_fweh_event_code code, + brcmf_fweh_handler_t handler) +{ + if (drvr->fweh.evt_handler[code]) { + brcmf_dbg(ERROR, "event code %d already registered\n", code); + return -ENOSPC; + } + drvr->fweh.evt_handler[code] = handler; + brcmf_dbg(TRACE, "event handler registered for %s\n", + brcmf_fweh_event_name(code)); + return 0; +} + +/** + * brcmf_fweh_unregister() - remove handler for given code. + * + * @drvr: driver information object. + * @code: event code. + */ +void brcmf_fweh_unregister(struct brcmf_pub *drvr, + enum brcmf_fweh_event_code code) +{ + brcmf_dbg(TRACE, "event handler cleared for %s\n", + brcmf_fweh_event_name(code)); + drvr->fweh.evt_handler[code] = NULL; +} + +/** + * brcmf_fweh_activate_events() - enables firmware events registered. + * + * @ifp: primary interface object. + */ +int brcmf_fweh_activate_events(struct brcmf_if *ifp) +{ + int i, err; + s8 eventmask[BRCMF_EVENTING_MASK_LEN]; + + for (i = 0; i < BRCMF_E_LAST; i++) { + if (ifp->drvr->fweh.evt_handler[i]) { + brcmf_dbg(EVENT, "enable event %s\n", + brcmf_fweh_event_name(i)); + setbit(eventmask, i); + } + } + + /* want to handle IF event as well */ + brcmf_dbg(EVENT, "enable event IF\n"); + setbit(eventmask, BRCMF_E_IF); + + err = brcmf_fil_iovar_data_set(ifp, "event_msgs", + eventmask, BRCMF_EVENTING_MASK_LEN); + if (err) + brcmf_dbg(ERROR, "Set event_msgs error (%d)\n", err); + + return err; +} + +/** + * brcmf_fweh_process_event() - process skb as firmware event. + * + * @drvr: driver information object. + * @event_packet: event packet to process. + * @ifidx: index of the firmware interface (may change). + * + * If the packet buffer contains a firmware event message it will + * dispatch the event to a registered handler (using worker). + */ +void brcmf_fweh_process_event(struct brcmf_pub *drvr, + struct brcmf_event *event_packet, u8 *ifidx) +{ + enum brcmf_fweh_event_code code; + struct brcmf_fweh_info *fweh = &drvr->fweh; + struct brcmf_fweh_queue_item *event; + gfp_t alloc_flag = GFP_KERNEL; + void *data; + u32 datalen; + + /* get event info */ + code = get_unaligned_be32(&event_packet->msg.event_type); + datalen = get_unaligned_be32(&event_packet->msg.datalen); + *ifidx = event_packet->msg.ifidx; + data = &event_packet[1]; + + if (code >= BRCMF_E_LAST) + return; + + if (code != BRCMF_E_IF && !fweh->evt_handler[code]) + return; + + if (in_interrupt()) + alloc_flag = GFP_ATOMIC; + + event = kzalloc(sizeof(*event) + datalen, alloc_flag); + if (!event) + return; + + event->code = code; + event->ifidx = *ifidx; + + /* use memcpy to get aligned event message */ + memcpy(&event->emsg, &event_packet->msg, sizeof(event->emsg)); + memcpy(event->data, data, datalen); + memcpy(event->ifaddr, event_packet->eth.h_dest, ETH_ALEN); + + brcmf_fweh_queue_event(fweh, event); +} diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fweh.h b/drivers/net/wireless/brcm80211/brcmfmac/fweh.h new file mode 100644 index 000000000000..b39246a630df --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.h @@ -0,0 +1,207 @@ +/* + * 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 FWEH_H_ +#define FWEH_H_ + +#include <asm/unaligned.h> +#include <linux/skbuff.h> +#include <linux/if_ether.h> +#include <linux/if.h> + +/* formward declarations */ +struct brcmf_pub; +struct brcmf_if; +struct brcmf_cfg80211_info; +struct brcmf_event; + +/* firmware event codes sent by the dongle */ +enum brcmf_fweh_event_code { + BRCMF_E_SET_SSID = 0, + BRCMF_E_JOIN = 1, + BRCMF_E_START = 2, + BRCMF_E_AUTH = 3, + BRCMF_E_AUTH_IND = 4, + BRCMF_E_DEAUTH = 5, + BRCMF_E_DEAUTH_IND = 6, + BRCMF_E_ASSOC = 7, + BRCMF_E_ASSOC_IND = 8, + BRCMF_E_REASSOC = 9, + BRCMF_E_REASSOC_IND = 10, + BRCMF_E_DISASSOC = 11, + BRCMF_E_DISASSOC_IND = 12, + BRCMF_E_QUIET_START = 13, + BRCMF_E_QUIET_END = 14, + BRCMF_E_BEACON_RX = 15, + BRCMF_E_LINK = 16, + BRCMF_E_MIC_ERROR = 17, + BRCMF_E_NDIS_LINK = 18, + BRCMF_E_ROAM = 19, + BRCMF_E_TXFAIL = 20, + BRCMF_E_PMKID_CACHE = 21, + BRCMF_E_RETROGRADE_TSF = 22, + BRCMF_E_PRUNE = 23, + BRCMF_E_AUTOAUTH = 24, + BRCMF_E_EAPOL_MSG = 25, + BRCMF_E_SCAN_COMPLETE = 26, + BRCMF_E_ADDTS_IND = 27, + BRCMF_E_DELTS_IND = 28, + BRCMF_E_BCNSENT_IND = 29, + BRCMF_E_BCNRX_MSG = 30, + BRCMF_E_BCNLOST_MSG = 31, + BRCMF_E_ROAM_PREP = 32, + BRCMF_E_PFN_NET_FOUND = 33, + BRCMF_E_PFN_NET_LOST = 34, + BRCMF_E_RESET_COMPLETE = 35, + BRCMF_E_JOIN_START = 36, + BRCMF_E_ROAM_START = 37, + BRCMF_E_ASSOC_START = 38, + BRCMF_E_IBSS_ASSOC = 39, + BRCMF_E_RADIO = 40, + BRCMF_E_PSM_WATCHDOG = 41, + BRCMF_E_PROBREQ_MSG = 44, + BRCMF_E_SCAN_CONFIRM_IND = 45, + BRCMF_E_PSK_SUP = 46, + BRCMF_E_COUNTRY_CODE_CHANGED = 47, + BRCMF_E_EXCEEDED_MEDIUM_TIME = 48, + BRCMF_E_ICV_ERROR = 49, + BRCMF_E_UNICAST_DECODE_ERROR = 50, + BRCMF_E_MULTICAST_DECODE_ERROR = 51, + BRCMF_E_TRACE = 52, + BRCMF_E_IF = 54, + BRCMF_E_RSSI = 56, + BRCMF_E_PFN_SCAN_COMPLETE = 57, + BRCMF_E_EXTLOG_MSG = 58, + BRCMF_E_ACTION_FRAME = 59, + BRCMF_E_ACTION_FRAME_COMPLETE = 60, + BRCMF_E_PRE_ASSOC_IND = 61, + BRCMF_E_PRE_REASSOC_IND = 62, + BRCMF_E_CHANNEL_ADOPTED = 63, + BRCMF_E_AP_STARTED = 64, + BRCMF_E_DFS_AP_STOP = 65, + BRCMF_E_DFS_AP_RESUME = 66, + BRCMF_E_ESCAN_RESULT = 69, + BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE = 70, + BRCMF_E_DCS_REQUEST = 73, + BRCMF_E_FIFO_CREDIT_MAP = 74, + BRCMF_E_LAST +}; + +/* flags field values in struct brcmf_event_msg */ +#define BRCMF_EVENT_MSG_LINK 0x01 +#define BRCMF_EVENT_MSG_FLUSHTXQ 0x02 +#define BRCMF_EVENT_MSG_GROUP 0x04 + +/** + * definitions for event packet validation. + */ +#define BRCMF_EVENT_OUI_OFFSET 19 +#define BRCM_OUI "\x00\x10\x18" +#define DOT11_OUI_LEN 3 +#define BCMILCP_BCM_SUBTYPE_EVENT 1 + + +/** + * struct brcmf_event_msg - firmware event message. + * + * @version: version information. + * @flags: event flags. + * @event_code: firmware event code. + * @status: status information. + * @reason: reason code. + * @auth_type: authentication type. + * @datalen: lenght of event data buffer. + * @addr: ether address. + * @ifname: interface name. + * @ifidx: interface index. + * @bsscfgidx: bsscfg index. + */ +struct brcmf_event_msg { + u16 version; + u16 flags; + u32 event_code; + u32 status; + u32 reason; + s32 auth_type; + u32 datalen; + u8 addr[ETH_ALEN]; + char ifname[IFNAMSIZ]; + u8 ifidx; + u8 bsscfgidx; +}; + +typedef int (*brcmf_fweh_handler_t)(struct brcmf_if *ifp, + const struct brcmf_event_msg *evtmsg, + void *data); + +/** + * struct brcmf_fweh_info - firmware event handling information. + * + * @event_work: event worker. + * @evt_q_lock: lock for event queue protection. + * @event_q: event queue. + * @evt_handler: registered event handlers. + */ +struct brcmf_fweh_info { + struct work_struct event_work; + struct spinlock evt_q_lock; + struct list_head event_q; + int (*evt_handler[BRCMF_E_LAST])(struct brcmf_if *ifp, + const struct brcmf_event_msg *evtmsg, + void *data); +}; + +void brcmf_fweh_attach(struct brcmf_pub *drvr); +void brcmf_fweh_detach(struct brcmf_pub *drvr); +int brcmf_fweh_register(struct brcmf_pub *drvr, enum brcmf_fweh_event_code code, + int (*handler)(struct brcmf_if *ifp, + const struct brcmf_event_msg *evtmsg, + void *data)); +void brcmf_fweh_unregister(struct brcmf_pub *drvr, + enum brcmf_fweh_event_code code); +int brcmf_fweh_activate_events(struct brcmf_if *ifp); +void brcmf_fweh_process_event(struct brcmf_pub *drvr, + struct brcmf_event *event_packet, u8 *ifidx); + +static inline void brcmf_fweh_process_skb(struct brcmf_pub *drvr, + struct sk_buff *skb, u8 *ifidx) +{ + struct brcmf_event *event_packet; + u8 *data; + u16 usr_stype; + + /* only process events when protocol matches */ + if (skb->protocol != cpu_to_be16(ETH_P_LINK_CTL)) + return; + + /* check for BRCM oui match */ + event_packet = (struct brcmf_event *)skb_mac_header(skb); + data = (u8 *)event_packet; + data += BRCMF_EVENT_OUI_OFFSET; + if (memcmp(BRCM_OUI, data, DOT11_OUI_LEN)) + return; + + /* final match on usr_subtype */ + data += DOT11_OUI_LEN; + usr_stype = get_unaligned_be16(data); + if (usr_stype != BCMILCP_BCM_SUBTYPE_EVENT) + return; + + brcmf_fweh_process_event(drvr, event_packet, ifidx); +} + +#endif /* FWEH_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil.c b/drivers/net/wireless/brcm80211/brcmfmac/fwil.c index 62e0960c1d3e..51a14505197a 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fwil.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil.c @@ -20,7 +20,6 @@ #include <linux/kernel.h> #include <linux/netdevice.h> -#include <defs.h> #include <brcmu_utils.h> #include <brcmu_wifi.h> #include "dhd.h" @@ -29,6 +28,9 @@ #include "fwil.h" +#define MAX_HEX_DUMP_LEN 64 + + static s32 brcmf_fil_cmd_data(struct brcmf_if *ifp, u32 cmd, void *data, u32 len, bool set) { @@ -64,7 +66,8 @@ brcmf_fil_cmd_data_set(struct brcmf_if *ifp, u32 cmd, void *data, u32 len) mutex_lock(&ifp->drvr->proto_block); brcmf_dbg(FIL, "cmd=%d, len=%d\n", cmd, len); - brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, len, "data"); + brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, + min_t(uint, len, MAX_HEX_DUMP_LEN), "data"); err = brcmf_fil_cmd_data(ifp, cmd, data, len, true); mutex_unlock(&ifp->drvr->proto_block); @@ -81,7 +84,8 @@ brcmf_fil_cmd_data_get(struct brcmf_if *ifp, u32 cmd, void *data, u32 len) err = brcmf_fil_cmd_data(ifp, cmd, data, len, false); brcmf_dbg(FIL, "cmd=%d, len=%d\n", cmd, len); - brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, len, "data"); + brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, + min_t(uint, len, MAX_HEX_DUMP_LEN), "data"); mutex_unlock(&ifp->drvr->proto_block); @@ -147,7 +151,8 @@ brcmf_fil_iovar_data_set(struct brcmf_if *ifp, char *name, void *data, mutex_lock(&drvr->proto_block); brcmf_dbg(FIL, "name=%s, len=%d\n", name, len); - brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, len, "data"); + brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, + min_t(uint, len, MAX_HEX_DUMP_LEN), "data"); buflen = brcmf_create_iovar(name, data, len, drvr->proto_buf, sizeof(drvr->proto_buf)); @@ -186,7 +191,8 @@ brcmf_fil_iovar_data_get(struct brcmf_if *ifp, char *name, void *data, } brcmf_dbg(FIL, "name=%s, len=%d\n", name, len); - brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, len, "data"); + brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, + min_t(uint, len, MAX_HEX_DUMP_LEN), "data"); mutex_unlock(&drvr->proto_block); return err; @@ -268,7 +274,8 @@ brcmf_fil_bsscfg_data_set(struct brcmf_if *ifp, char *name, mutex_lock(&drvr->proto_block); brcmf_dbg(FIL, "bssidx=%d, name=%s, len=%d\n", ifp->bssidx, name, len); - brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, len, "data"); + brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, + min_t(uint, len, MAX_HEX_DUMP_LEN), "data"); buflen = brcmf_create_bsscfg(ifp->bssidx, name, data, len, drvr->proto_buf, sizeof(drvr->proto_buf)); @@ -306,7 +313,8 @@ brcmf_fil_bsscfg_data_get(struct brcmf_if *ifp, char *name, brcmf_dbg(ERROR, "Creating bsscfg failed\n"); } brcmf_dbg(FIL, "bssidx=%d, name=%s, len=%d\n", ifp->bssidx, name, len); - brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, len, "data"); + brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, + min_t(uint, len, MAX_HEX_DUMP_LEN), "data"); mutex_unlock(&drvr->proto_block); return err; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/brcm80211/brcmfmac/usb.c index 15070b61b161..39a5baa92f21 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/usb.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c @@ -14,24 +14,12 @@ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/kthread.h> -#include <linux/slab.h> -#include <linux/skbuff.h> -#include <linux/netdevice.h> -#include <linux/spinlock.h> -#include <linux/ethtool.h> -#include <linux/fcntl.h> -#include <linux/fs.h> -#include <linux/uaccess.h> #include <linux/firmware.h> #include <linux/usb.h> #include <linux/vmalloc.h> -#include <net/cfg80211.h> -#include <defs.h> #include <brcmu_utils.h> #include <brcmu_wifi.h> #include <dhd_bus.h> @@ -42,13 +30,11 @@ #define IOCTL_RESP_TIMEOUT 2000 -#define BRCMF_USB_DLIMAGE_SPINWAIT 100 /* in unit of ms */ -#define BRCMF_USB_DLIMAGE_LIMIT 500 /* spinwait limit (ms) */ +#define BRCMF_USB_RESET_GETVER_SPINWAIT 100 /* in unit of ms */ +#define BRCMF_USB_RESET_GETVER_LOOP_CNT 10 #define BRCMF_POSTBOOT_ID 0xA123 /* ID to detect if dongle has boot up */ -#define BRCMF_USB_RESETCFG_SPINWAIT 1 /* wait after resetcfg (ms) */ - #define BRCMF_USB_NRXQ 50 #define BRCMF_USB_NTXQ 50 @@ -69,16 +55,6 @@ #define BRCMF_USB_43236_FW_NAME "brcm/brcmfmac43236b.bin" #define BRCMF_USB_43242_FW_NAME "brcm/brcmfmac43242a.bin" -enum usbdev_suspend_state { - USBOS_SUSPEND_STATE_DEVICE_ACTIVE = 0, /* Device is busy, won't allow - suspend */ - USBOS_SUSPEND_STATE_SUSPEND_PENDING, /* Device is idle, can be - * suspended. Wating PM to - * suspend the device - */ - USBOS_SUSPEND_STATE_SUSPENDED /* Device suspended */ -}; - struct brcmf_usb_image { struct list_head list; s8 *fwname; @@ -99,10 +75,8 @@ struct brcmf_usbdev_info { struct list_head rx_postq; struct list_head tx_freeq; struct list_head tx_postq; - enum usbdev_suspend_state suspend_state; uint rx_pipe, tx_pipe, intr_pipe, rx_pipe2; - bool activity; int rx_low_watermark; int tx_low_watermark; int tx_high_watermark; @@ -215,11 +189,6 @@ brcmf_usb_ctlwrite_complete(struct urb *urb) urb->status); } -static int brcmf_usb_pnp(struct brcmf_usbdev_info *devinfo, uint state) -{ - return 0; -} - static int brcmf_usb_send_ctl(struct brcmf_usbdev_info *devinfo, u8 *buf, int len) { @@ -231,14 +200,6 @@ brcmf_usb_send_ctl(struct brcmf_usbdev_info *devinfo, u8 *buf, int len) len == 0 || devinfo->ctl_urb == NULL) return -EINVAL; - /* If the USB/HSIC bus in sleep state, wake it up */ - if (devinfo->suspend_state == USBOS_SUSPEND_STATE_SUSPENDED) - if (brcmf_usb_pnp(devinfo, BCMFMAC_USB_PNP_RESUME) != 0) { - brcmf_dbg(ERROR, "Could not Resume the bus!\n"); - return -EIO; - } - - devinfo->activity = true; size = len; devinfo->ctl_write.wLength = cpu_to_le16p(&size); devinfo->ctl_urb->transfer_buffer_length = size; @@ -301,10 +262,8 @@ static int brcmf_usb_tx_ctlpkt(struct device *dev, u8 *buf, u32 len) struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev); brcmf_dbg(USB, "Enter\n"); - if (devinfo->bus_pub.state != BCMFMAC_USB_STATE_UP) { - /* TODO: handle suspend/resume */ + if (devinfo->bus_pub.state != BRCMFMAC_USB_STATE_UP) return -EIO; - } if (test_and_set_bit(0, &devinfo->ctl_op)) return -EIO; @@ -332,10 +291,9 @@ static int brcmf_usb_rx_ctlpkt(struct device *dev, u8 *buf, u32 len) struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev); brcmf_dbg(USB, "Enter\n"); - if (devinfo->bus_pub.state != BCMFMAC_USB_STATE_UP) { - /* TODO: handle suspend/resume */ + if (devinfo->bus_pub.state != BRCMFMAC_USB_STATE_UP) return -EIO; - } + if (test_and_set_bit(0, &devinfo->ctl_op)) return -EIO; @@ -501,7 +459,7 @@ static void brcmf_usb_rx_complete(struct urb *urb) return; } - if (devinfo->bus_pub.state == BCMFMAC_USB_STATE_UP) { + if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_UP) { skb_put(skb, urb->actual_length); if (brcmf_proto_hdrpull(devinfo->dev, &ifidx, skb) != 0) { brcmf_dbg(ERROR, "rx protocol error\n"); @@ -554,8 +512,8 @@ static void brcmf_usb_rx_fill_all(struct brcmf_usbdev_info *devinfo) { struct brcmf_usbreq *req; - if (devinfo->bus_pub.state != BCMFMAC_USB_STATE_UP) { - brcmf_dbg(ERROR, "bus is not up\n"); + if (devinfo->bus_pub.state != BRCMFMAC_USB_STATE_UP) { + brcmf_dbg(ERROR, "bus is not up=%d\n", devinfo->bus_pub.state); return; } while ((req = brcmf_usb_deq(devinfo, &devinfo->rx_freeq, NULL)) != NULL) @@ -575,20 +533,15 @@ brcmf_usb_state_change(struct brcmf_usbdev_info *devinfo, int state) return; old_state = devinfo->bus_pub.state; - - /* Don't update state if it's PnP firmware re-download */ - if (state != BCMFMAC_USB_STATE_PNP_FWDL) /* TODO */ - devinfo->bus_pub.state = state; - - if ((old_state == BCMFMAC_USB_STATE_SLEEP) - && (state == BCMFMAC_USB_STATE_UP)) { - brcmf_usb_rx_fill_all(devinfo); - } + devinfo->bus_pub.state = state; /* update state of upper layer */ - if (state == BCMFMAC_USB_STATE_DOWN) { + if (state == BRCMFMAC_USB_STATE_DOWN) { brcmf_dbg(USB, "DBUS is down\n"); bcmf_bus->state = BRCMF_BUS_DOWN; + } else if (state == BRCMFMAC_USB_STATE_UP) { + brcmf_dbg(USB, "DBUS is up\n"); + bcmf_bus->state = BRCMF_BUS_DATA; } else { brcmf_dbg(USB, "DBUS current state=%d\n", state); } @@ -599,7 +552,7 @@ brcmf_usb_intr_complete(struct urb *urb) { struct brcmf_usbdev_info *devinfo = (struct brcmf_usbdev_info *)urb->context; - bool killed; + int err; brcmf_dbg(USB, "Enter, urb->status=%d\n", urb->status); @@ -607,24 +560,24 @@ brcmf_usb_intr_complete(struct urb *urb) return; if (unlikely(urb->status)) { - if (devinfo->suspend_state == - USBOS_SUSPEND_STATE_SUSPEND_PENDING) - killed = true; - - if ((urb->status == -ENOENT && (!killed)) - || urb->status == -ESHUTDOWN || - urb->status == -ENODEV) { - brcmf_usb_state_change(devinfo, BCMFMAC_USB_STATE_DOWN); + if (urb->status == -ENOENT || + urb->status == -ESHUTDOWN || + urb->status == -ENODEV) { + brcmf_usb_state_change(devinfo, + BRCMFMAC_USB_STATE_DOWN); } } - if (devinfo->bus_pub.state == BCMFMAC_USB_STATE_DOWN) { + if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_DOWN) { brcmf_dbg(ERROR, "intr cb when DBUS down, ignoring\n"); return; } - if (devinfo->bus_pub.state == BCMFMAC_USB_STATE_UP) - usb_submit_urb(devinfo->intr_urb, GFP_ATOMIC); + if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_UP) { + err = usb_submit_urb(devinfo->intr_urb, GFP_ATOMIC); + if (err) + brcmf_dbg(ERROR, "usb_submit_urb, err=%d\n", err); + } } static int brcmf_usb_tx(struct device *dev, struct sk_buff *skb) @@ -634,10 +587,8 @@ static int brcmf_usb_tx(struct device *dev, struct sk_buff *skb) int ret; brcmf_dbg(USB, "Enter, skb=%p\n", skb); - if (devinfo->bus_pub.state != BCMFMAC_USB_STATE_UP) { - /* TODO: handle suspend/resume */ + if (devinfo->bus_pub.state != BRCMFMAC_USB_STATE_UP) return -EIO; - } req = brcmf_usb_deq(devinfo, &devinfo->tx_freeq, &devinfo->tx_freecount); @@ -677,26 +628,16 @@ static int brcmf_usb_up(struct device *dev) { struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev); u16 ifnum; + int ret; brcmf_dbg(USB, "Enter\n"); - if (devinfo->bus_pub.state == BCMFMAC_USB_STATE_UP) + if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_UP) return 0; - /* If the USB/HSIC bus in sleep state, wake it up */ - if (devinfo->suspend_state == USBOS_SUSPEND_STATE_SUSPENDED) { - if (brcmf_usb_pnp(devinfo, BCMFMAC_USB_PNP_RESUME) != 0) { - brcmf_dbg(ERROR, "Could not Resume the bus!\n"); - return -EIO; - } - } - devinfo->activity = true; - /* Success, indicate devinfo is fully up */ - brcmf_usb_state_change(devinfo, BCMFMAC_USB_STATE_UP); + brcmf_usb_state_change(devinfo, BRCMFMAC_USB_STATE_UP); if (devinfo->intr_urb) { - int ret; - usb_fill_int_urb(devinfo->intr_urb, devinfo->usbdev, devinfo->intr_pipe, &devinfo->intr, @@ -745,10 +686,10 @@ static void brcmf_usb_down(struct device *dev) if (devinfo == NULL) return; - if (devinfo->bus_pub.state == BCMFMAC_USB_STATE_DOWN) + if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_DOWN) return; - brcmf_usb_state_change(devinfo, BCMFMAC_USB_STATE_DOWN); + brcmf_usb_state_change(devinfo, BRCMFMAC_USB_STATE_DOWN); if (devinfo->intr_urb) usb_kill_urb(devinfo->intr_urb); @@ -829,8 +770,7 @@ brcmf_usb_dlneeded(struct brcmf_usbdev_info *devinfo) /* Check if firmware downloaded already by querying runtime ID */ id.chip = cpu_to_le32(0xDEAD); - brcmf_usb_dl_cmd(devinfo, DL_GETVER, &id, - sizeof(struct bootrom_id_le)); + brcmf_usb_dl_cmd(devinfo, DL_GETVER, &id, sizeof(id)); chipid = le32_to_cpu(id.chip); chiprev = le32_to_cpu(id.chiprev); @@ -841,8 +781,7 @@ brcmf_usb_dlneeded(struct brcmf_usbdev_info *devinfo) brcmf_dbg(USB, "chip %d rev 0x%x\n", chipid, chiprev); if (chipid == BRCMF_POSTBOOT_ID) { brcmf_dbg(USB, "firmware already downloaded\n"); - brcmf_usb_dl_cmd(devinfo, DL_RESETCFG, &id, - sizeof(struct bootrom_id_le)); + brcmf_usb_dl_cmd(devinfo, DL_RESETCFG, &id, sizeof(id)); return false; } else { devinfo->bus_pub.devid = chipid; @@ -855,38 +794,29 @@ static int brcmf_usb_resetcfg(struct brcmf_usbdev_info *devinfo) { struct bootrom_id_le id; - u16 wait = 0, wait_time; + u32 loop_cnt; brcmf_dbg(USB, "Enter\n"); - if (devinfo == NULL) - return -EINVAL; - - /* Give dongle chance to boot */ - wait_time = BRCMF_USB_DLIMAGE_SPINWAIT; - while (wait < BRCMF_USB_DLIMAGE_LIMIT) { - mdelay(wait_time); - wait += wait_time; + loop_cnt = 0; + do { + mdelay(BRCMF_USB_RESET_GETVER_SPINWAIT); + loop_cnt++; id.chip = cpu_to_le32(0xDEAD); /* Get the ID */ - brcmf_usb_dl_cmd(devinfo, DL_GETVER, &id, - sizeof(struct bootrom_id_le)); + brcmf_usb_dl_cmd(devinfo, DL_GETVER, &id, sizeof(id)); if (id.chip == cpu_to_le32(BRCMF_POSTBOOT_ID)) break; - } + } while (loop_cnt < BRCMF_USB_RESET_GETVER_LOOP_CNT); if (id.chip == cpu_to_le32(BRCMF_POSTBOOT_ID)) { - brcmf_dbg(USB, "download done %d ms postboot chip 0x%x/rev 0x%x\n", - wait, le32_to_cpu(id.chip), le32_to_cpu(id.chiprev)); + brcmf_dbg(USB, "postboot chip 0x%x/rev 0x%x\n", + le32_to_cpu(id.chip), le32_to_cpu(id.chiprev)); - brcmf_usb_dl_cmd(devinfo, DL_RESETCFG, &id, - sizeof(struct bootrom_id_le)); - - /* XXX this wait may not be necessary */ - mdelay(BRCMF_USB_RESETCFG_SPINWAIT); + brcmf_usb_dl_cmd(devinfo, DL_RESETCFG, &id, sizeof(id)); return 0; } else { brcmf_dbg(ERROR, "Cannot talk to Dongle. Firmware is not UP, %d ms\n", - wait); + BRCMF_USB_RESET_GETVER_SPINWAIT * loop_cnt); return -EINVAL; } } @@ -1019,9 +949,9 @@ static int brcmf_usb_dlstart(struct brcmf_usbdev_info *devinfo, u8 *fw, int len) err = brcmf_usb_dl_writeimage(devinfo, fw, len); if (err == 0) - devinfo->bus_pub.state = BCMFMAC_USB_STATE_DL_DONE; + devinfo->bus_pub.state = BRCMFMAC_USB_STATE_DL_DONE; else - devinfo->bus_pub.state = BCMFMAC_USB_STATE_DL_PENDING; + devinfo->bus_pub.state = BRCMFMAC_USB_STATE_DL_FAIL; brcmf_dbg(USB, "Exit, err=%d\n", err); return err; @@ -1234,6 +1164,7 @@ struct brcmf_usbdev *brcmf_usb_attach(struct brcmf_usbdev_info *devinfo, devinfo->rx_low_watermark = nrxq / 2; devinfo->bus_pub.devinfo = devinfo; devinfo->bus_pub.ntxq = ntxq; + devinfo->bus_pub.state = BRCMFMAC_USB_STATE_DOWN; /* flow control when too many tx urbs posted */ devinfo->tx_low_watermark = ntxq / 4; @@ -1297,8 +1228,7 @@ error: return NULL; } -static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo, - const char *desc, u32 bustype, u32 hdrlen) +static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo) { struct brcmf_bus *bus = NULL; struct brcmf_usbdev *bus_pub = NULL; @@ -1322,12 +1252,11 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo, bus->brcmf_bus_stop = brcmf_usb_down; bus->brcmf_bus_txctl = brcmf_usb_tx_ctlpkt; bus->brcmf_bus_rxctl = brcmf_usb_rx_ctlpkt; - bus->type = bustype; bus->bus_priv.usb = bus_pub; dev_set_drvdata(dev, bus); /* Attach to the common driver interface */ - ret = brcmf_attach(hdrlen, dev); + ret = brcmf_attach(0, dev); if (ret) { brcmf_dbg(ERROR, "brcmf_attach failed\n"); goto fail; @@ -1476,7 +1405,7 @@ brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) else brcmf_dbg(USB, "Broadcom full speed USB wireless device detected\n"); - ret = brcmf_usb_probe_cb(devinfo, "", USB_BUS, 0); + ret = brcmf_usb_probe_cb(devinfo); if (ret) goto fail; @@ -1504,7 +1433,7 @@ brcmf_usb_disconnect(struct usb_interface *intf) } /* - * only need to signal the bus being down and update the suspend state. + * only need to signal the bus being down and update the state. */ static int brcmf_usb_suspend(struct usb_interface *intf, pm_message_t state) { @@ -1512,13 +1441,13 @@ static int brcmf_usb_suspend(struct usb_interface *intf, pm_message_t state) struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(&usb->dev); brcmf_dbg(USB, "Enter\n"); - devinfo->bus_pub.state = BCMFMAC_USB_STATE_DOWN; - devinfo->suspend_state = USBOS_SUSPEND_STATE_SUSPENDED; + devinfo->bus_pub.state = BRCMFMAC_USB_STATE_SLEEP; + brcmf_detach(&usb->dev); return 0; } /* - * mark suspend state active and crank up the bus. + * (re-) start the bus. */ static int brcmf_usb_resume(struct usb_interface *intf) { @@ -1526,11 +1455,25 @@ static int brcmf_usb_resume(struct usb_interface *intf) struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(&usb->dev); brcmf_dbg(USB, "Enter\n"); - devinfo->suspend_state = USBOS_SUSPEND_STATE_DEVICE_ACTIVE; - brcmf_bus_start(&usb->dev); + if (!brcmf_attach(0, devinfo->dev)) + return brcmf_bus_start(&usb->dev); + return 0; } +static int brcmf_usb_reset_resume(struct usb_interface *intf) +{ + struct usb_device *usb = interface_to_usbdev(intf); + struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(&usb->dev); + + brcmf_dbg(USB, "Enter\n"); + + if (!brcmf_usb_fw_download(devinfo)) + return brcmf_usb_resume(intf); + + return -EIO; +} + #define BRCMF_USB_VENDOR_ID_BROADCOM 0x0a5c #define BRCMF_USB_DEVICE_ID_43143 0xbd1e #define BRCMF_USB_DEVICE_ID_43236 0xbd17 @@ -1550,7 +1493,6 @@ MODULE_FIRMWARE(BRCMF_USB_43143_FW_NAME); MODULE_FIRMWARE(BRCMF_USB_43236_FW_NAME); MODULE_FIRMWARE(BRCMF_USB_43242_FW_NAME); -/* TODO: suspend and resume entries */ static struct usb_driver brcmf_usbdrvr = { .name = KBUILD_MODNAME, .probe = brcmf_usb_probe, @@ -1558,6 +1500,7 @@ static struct usb_driver brcmf_usbdrvr = { .id_table = brcmf_usb_devid_table, .suspend = brcmf_usb_suspend, .resume = brcmf_usb_resume, + .reset_resume = brcmf_usb_reset_resume, .supports_autosuspend = 1, .disable_hub_initiated_lpm = 1, }; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.h b/drivers/net/wireless/brcm80211/brcmfmac/usb.h index acfa5e89872f..f483a8c9945b 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/usb.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.h @@ -17,19 +17,11 @@ #define BRCMFMAC_USB_H enum brcmf_usb_state { - BCMFMAC_USB_STATE_DL_PENDING, - BCMFMAC_USB_STATE_DL_DONE, - BCMFMAC_USB_STATE_UP, - BCMFMAC_USB_STATE_DOWN, - BCMFMAC_USB_STATE_PNP_FWDL, - BCMFMAC_USB_STATE_DISCONNECT, - BCMFMAC_USB_STATE_SLEEP -}; - -enum brcmf_usb_pnp_state { - BCMFMAC_USB_PNP_DISCONNECT, - BCMFMAC_USB_PNP_SLEEP, - BCMFMAC_USB_PNP_RESUME, + BRCMFMAC_USB_STATE_DOWN, + BRCMFMAC_USB_STATE_DL_FAIL, + BRCMFMAC_USB_STATE_DL_DONE, + BRCMFMAC_USB_STATE_UP, + BRCMFMAC_USB_STATE_SLEEP }; struct brcmf_stats { diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index 4387ca506b3b..96bc349d7f6c 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -19,14 +19,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/kernel.h> -#include <linux/if_arp.h> -#include <linux/sched.h> -#include <linux/kthread.h> -#include <linux/netdevice.h> -#include <linux/bitops.h> #include <linux/etherdevice.h> -#include <linux/ieee80211.h> -#include <linux/uaccess.h> #include <net/cfg80211.h> #include <net/netlink.h> @@ -454,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; @@ -468,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: @@ -485,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; @@ -883,7 +874,7 @@ static s32 brcmf_set_frag(struct net_device *ndev, u32 frag_threshold) static s32 brcmf_set_retry(struct net_device *ndev, u32 retry, bool l) { s32 err = 0; - u32 cmd = (l ? BRCM_SET_LRL : BRCM_SET_SRL); + u32 cmd = (l ? BRCMF_C_SET_LRL : BRCMF_C_SET_SRL); err = brcmf_fil_cmd_int_set(netdev_priv(ndev), cmd, retry); if (err) { @@ -970,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"); } @@ -1020,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"); @@ -1066,7 +1056,7 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev, else bcnprd = 100; - err = brcmf_fil_cmd_int_set(ifp, BRCM_SET_BCNPRD, bcnprd); + err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD, bcnprd); if (err) { WL_ERR("WLC_SET_BCNPRD failed (%d)\n", err); goto done; @@ -1094,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, @@ -1108,7 +1098,7 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev, /* set channel for starter */ target_channel = cfg->channel; - err = brcmf_fil_cmd_int_set(ifp, BRCM_SET_CHANNEL, + err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_CHANNEL, target_channel); if (err) { WL_ERR("WLC_SET_CHANNEL failed (%d)\n", err); @@ -1137,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; @@ -1145,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"); @@ -1503,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; @@ -1522,14 +1510,12 @@ 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; } static s32 -brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, +brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, enum nl80211_tx_power_setting type, s32 mbm) { @@ -1578,7 +1564,9 @@ done: return err; } -static s32 brcmf_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm) +static s32 brcmf_cfg80211_get_tx_power(struct wiphy *wiphy, + struct wireless_dev *wdev, + s32 *dbm) { struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg)); @@ -1721,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; @@ -1763,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)); @@ -1913,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; @@ -1927,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, @@ -1944,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); @@ -2044,7 +2030,7 @@ brcmf_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *ndev, /* addr param is always NULL. ignore it */ /* Get current rateset */ - err = brcmf_fil_cmd_data_get(ifp, BRCM_GET_CURR_RATESET, + err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_CURR_RATESET, &rateset_le, sizeof(rateset_le)); if (err) { WL_ERR("could not get current rateset (%d)\n", err); @@ -2254,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; } /* @@ -2341,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; @@ -2468,7 +2454,7 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp, u32 i; bool aborted; - status = be32_to_cpu(e->status); + status = e->status; if (!ndev || !test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) { WL_ERR("scan not ready ndev %p drv_status %x\n", ndev, @@ -2549,9 +2535,8 @@ exit: static void brcmf_init_escan(struct brcmf_cfg80211_info *cfg) { - - cfg->el.handler[BRCMF_E_ESCAN_RESULT] = - brcmf_cfg80211_escan_handler; + brcmf_fweh_register(cfg->pub, BRCMF_E_ESCAN_RESULT, + brcmf_cfg80211_escan_handler); cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE; /* Init scan_timeout timer */ init_timer(&cfg->escan_timeout); @@ -2602,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 */ @@ -2792,7 +2773,7 @@ brcmf_notify_sched_scan_results(struct brcmf_if *ifp, WL_SCAN("Enter\n"); - if (e->event_type == cpu_to_be32(BRCMF_E_PFN_NET_LOST)) { + if (e->event_code == BRCMF_E_PFN_NET_LOST) { WL_SCAN("PFN NET LOST event. Do Nothing\n"); return 0; } @@ -3312,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; } @@ -3415,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; } @@ -3457,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, @@ -3468,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, @@ -3512,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, @@ -3648,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; @@ -3854,26 +3838,23 @@ 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 = be32_to_cpu(e->event_type); - u32 status = be32_to_cpu(e->status); + 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 = be32_to_cpu(e->event_type); - u16 flags = be16_to_cpu(e->flags); + u32 event = e->event_code; + u16 flags = e->flags; if (event == BRCMF_E_LINK && (!(flags & BRCMF_EVENT_MSG_LINK))) { WL_CONN("Processing link down\n"); @@ -3885,13 +3866,12 @@ static bool brcmf_is_linkdown(struct brcmf_cfg80211_info *cfg, static bool brcmf_is_nonetwork(struct brcmf_cfg80211_info *cfg, const struct brcmf_event_msg *e) { - u32 event = be32_to_cpu(e->event_type); - u32 status = be32_to_cpu(e->status); + u32 event = e->event_code; + u32 status = e->status; if (event == BRCMF_E_LINK && status == BRCMF_E_STATUS_NO_NETWORKS) { WL_CONN("Processing Link %s & no network found\n", - be16_to_cpu(e->flags) & BRCMF_EVENT_MSG_LINK ? - "up" : "down"); + e->flags & BRCMF_EVENT_MSG_LINK ? "up" : "down"); return true; } @@ -4079,9 +4059,9 @@ brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg, const struct brcmf_event_msg *e, void *data) { s32 err = 0; - u32 event = be32_to_cpu(e->event_type); - u32 reason = be32_to_cpu(e->reason); - u32 len = be32_to_cpu(e->datalen); + u32 event = e->event_code; + u32 reason = e->reason; + u32 len = e->datalen; static int generation; struct station_info sinfo; @@ -4121,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); @@ -4135,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 @@ -4170,8 +4143,8 @@ brcmf_notify_roaming_status(struct brcmf_if *ifp, { struct brcmf_cfg80211_info *cfg = ifp->drvr->config; s32 err = 0; - u32 event = be32_to_cpu(e->event_type); - u32 status = be32_to_cpu(e->status); + u32 event = e->event_code; + u32 status = e->status; if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) { if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state)) @@ -4187,7 +4160,7 @@ static s32 brcmf_notify_mic_status(struct brcmf_if *ifp, const struct brcmf_event_msg *e, void *data) { - u16 flags = be16_to_cpu(e->flags); + u16 flags = e->flags; enum nl80211_key_type key_type; if (flags & BRCMF_EVENT_MSG_GROUP) @@ -4203,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; @@ -4211,19 +4183,28 @@ static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf) conf->tx_power = -1; } -static void brcmf_init_eloop_handler(struct brcmf_cfg80211_event_loop *el) +static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg) { - memset(el, 0, sizeof(*el)); - el->handler[BRCMF_E_LINK] = brcmf_notify_connect_status; - el->handler[BRCMF_E_DEAUTH_IND] = brcmf_notify_connect_status; - el->handler[BRCMF_E_DEAUTH] = brcmf_notify_connect_status; - el->handler[BRCMF_E_DISASSOC_IND] = brcmf_notify_connect_status; - el->handler[BRCMF_E_ASSOC_IND] = brcmf_notify_connect_status; - el->handler[BRCMF_E_REASSOC_IND] = brcmf_notify_connect_status; - el->handler[BRCMF_E_ROAM] = brcmf_notify_roaming_status; - el->handler[BRCMF_E_MIC_ERROR] = brcmf_notify_mic_status; - el->handler[BRCMF_E_SET_SSID] = brcmf_notify_connect_status; - el->handler[BRCMF_E_PFN_NET_FOUND] = brcmf_notify_sched_scan_results; + brcmf_fweh_register(cfg->pub, BRCMF_E_LINK, + brcmf_notify_connect_status); + brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH_IND, + brcmf_notify_connect_status); + brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH, + brcmf_notify_connect_status); + brcmf_fweh_register(cfg->pub, BRCMF_E_DISASSOC_IND, + brcmf_notify_connect_status); + brcmf_fweh_register(cfg->pub, BRCMF_E_ASSOC_IND, + brcmf_notify_connect_status); + brcmf_fweh_register(cfg->pub, BRCMF_E_REASSOC_IND, + brcmf_notify_connect_status); + brcmf_fweh_register(cfg->pub, BRCMF_E_ROAM, + brcmf_notify_roaming_status); + brcmf_fweh_register(cfg->pub, BRCMF_E_MIC_ERROR, + brcmf_notify_mic_status); + brcmf_fweh_register(cfg->pub, BRCMF_E_SET_SSID, + brcmf_notify_connect_status); + brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND, + brcmf_notify_sched_scan_results); } static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg) @@ -4261,115 +4242,6 @@ init_priv_mem_out: return -ENOMEM; } -/* -* retrieve first queued event from head -*/ - -static struct brcmf_cfg80211_event_q *brcmf_deq_event( - struct brcmf_cfg80211_info *cfg) -{ - struct brcmf_cfg80211_event_q *e = NULL; - - spin_lock_irq(&cfg->evt_q_lock); - if (!list_empty(&cfg->evt_q_list)) { - e = list_first_entry(&cfg->evt_q_list, - struct brcmf_cfg80211_event_q, evt_q_list); - list_del(&e->evt_q_list); - } - spin_unlock_irq(&cfg->evt_q_lock); - - return e; -} - -/* -* push event to tail of the queue -* -* remark: this function may not sleep as it is called in atomic context. -*/ - -static s32 -brcmf_enq_event(struct brcmf_if *ifp, u32 event, - const struct brcmf_event_msg *msg, void *data) -{ - struct brcmf_cfg80211_info *cfg = ifp->drvr->config; - struct brcmf_cfg80211_event_q *e; - s32 err = 0; - ulong flags; - u32 data_len; - u32 total_len; - - total_len = sizeof(struct brcmf_cfg80211_event_q); - if (data) - data_len = be32_to_cpu(msg->datalen); - else - data_len = 0; - total_len += data_len; - e = kzalloc(total_len, GFP_ATOMIC); - if (!e) - return -ENOMEM; - - e->etype = event; - e->ifp = ifp; - memcpy(&e->emsg, msg, sizeof(struct brcmf_event_msg)); - if (data) - memcpy(&e->edata, data, data_len); - - spin_lock_irqsave(&cfg->evt_q_lock, flags); - list_add_tail(&e->evt_q_list, &cfg->evt_q_list); - spin_unlock_irqrestore(&cfg->evt_q_lock, flags); - - return err; -} - -static void brcmf_put_event(struct brcmf_cfg80211_event_q *e) -{ - kfree(e); -} - -static void brcmf_cfg80211_event_handler(struct work_struct *work) -{ - struct brcmf_cfg80211_info *cfg = - container_of(work, struct brcmf_cfg80211_info, - event_work); - struct brcmf_cfg80211_event_q *e; - - e = brcmf_deq_event(cfg); - if (unlikely(!e)) { - WL_ERR("event queue empty...\n"); - return; - } - - do { - WL_INFO("event type (%d)\n", e->etype); - if (cfg->el.handler[e->etype]) - cfg->el.handler[e->etype](e->ifp, &e->emsg, e->edata); - else - WL_INFO("Unknown Event (%d): ignoring\n", e->etype); - brcmf_put_event(e); - } while ((e = brcmf_deq_event(cfg))); - -} - -static void brcmf_init_eq(struct brcmf_cfg80211_info *cfg) -{ - spin_lock_init(&cfg->evt_q_lock); - INIT_LIST_HEAD(&cfg->evt_q_list); -} - -static void brcmf_flush_eq(struct brcmf_cfg80211_info *cfg) -{ - struct brcmf_cfg80211_event_q *e; - - spin_lock_irq(&cfg->evt_q_lock); - while (!list_empty(&cfg->evt_q_list)) { - e = list_first_entry(&cfg->evt_q_list, - struct brcmf_cfg80211_event_q, evt_q_list); - list_del(&e->evt_q_list); - kfree(e); - } - spin_unlock_irq(&cfg->evt_q_lock); -} - static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg) { s32 err = 0; @@ -4381,26 +4253,20 @@ static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg) cfg->active_scan = true; /* we do active scan for specific scan per default */ cfg->dongle_up = false; /* dongle is not up yet */ - brcmf_init_eq(cfg); err = brcmf_init_priv_mem(cfg); if (err) return err; - INIT_WORK(&cfg->event_work, brcmf_cfg80211_event_handler); - brcmf_init_eloop_handler(&cfg->el); + brcmf_register_event_handlers(cfg); mutex_init(&cfg->usr_sync); brcmf_init_escan(cfg); brcmf_init_conf(cfg->conf); - brcmf_link_down(cfg); return err; } static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg) { - cancel_work_sync(&cfg->event_work); cfg->dongle_up = false; /* dongle down */ - brcmf_flush_eq(cfg); - brcmf_link_down(cfg); brcmf_abort_scanning(cfg); brcmf_deinit_priv_mem(cfg); } @@ -4461,64 +4327,6 @@ void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg) } } -void brcmf_cfg80211_event(struct brcmf_if *ifp, - const struct brcmf_event_msg *e, void *data) -{ - struct brcmf_cfg80211_info *cfg = ifp->drvr->config; - u32 event_type = be32_to_cpu(e->event_type); - - if (!brcmf_enq_event(ifp, event_type, e, data)) - schedule_work(&cfg->event_work); -} - -static s32 brcmf_dongle_eventmsg(struct net_device *ndev) -{ - s8 eventmask[BRCMF_EVENTING_MASK_LEN]; - s32 err = 0; - - WL_TRACE("Enter\n"); - - /* Setup event_msgs */ - err = brcmf_fil_iovar_data_get(netdev_priv(ndev), "event_msgs", - eventmask, BRCMF_EVENTING_MASK_LEN); - if (err) { - WL_ERR("Get event_msgs error (%d)\n", err); - goto dongle_eventmsg_out; - } - - setbit(eventmask, BRCMF_E_SET_SSID); - setbit(eventmask, BRCMF_E_ROAM); - setbit(eventmask, BRCMF_E_PRUNE); - setbit(eventmask, BRCMF_E_AUTH); - setbit(eventmask, BRCMF_E_REASSOC); - setbit(eventmask, BRCMF_E_REASSOC_IND); - setbit(eventmask, BRCMF_E_DEAUTH_IND); - setbit(eventmask, BRCMF_E_DISASSOC_IND); - setbit(eventmask, BRCMF_E_DISASSOC); - setbit(eventmask, BRCMF_E_JOIN); - setbit(eventmask, BRCMF_E_ASSOC_IND); - setbit(eventmask, BRCMF_E_PSK_SUP); - setbit(eventmask, BRCMF_E_LINK); - setbit(eventmask, BRCMF_E_NDIS_LINK); - setbit(eventmask, BRCMF_E_MIC_ERROR); - setbit(eventmask, BRCMF_E_PMKID_CACHE); - setbit(eventmask, BRCMF_E_TXFAIL); - setbit(eventmask, BRCMF_E_JOIN_START); - setbit(eventmask, BRCMF_E_ESCAN_RESULT); - setbit(eventmask, BRCMF_E_PFN_NET_FOUND); - - err = brcmf_fil_iovar_data_set(netdev_priv(ndev), "event_msgs", - eventmask, BRCMF_EVENTING_MASK_LEN); - if (err) { - WL_ERR("Set event_msgs error (%d)\n", err); - goto dongle_eventmsg_out; - } - -dongle_eventmsg_out: - WL_TRACE("Exit\n"); - return err; -} - static s32 brcmf_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout) { @@ -4620,7 +4428,7 @@ static s32 wl_update_wiphybands(struct brcmf_cfg80211_info *cfg) s8 phy; s32 err = 0; - err = brcmf_fil_cmd_data_get(ifp, BRCM_GET_PHYLIST, + err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_PHYLIST, &phy_list, sizeof(phy_list)); if (err) { WL_ERR("error (%d)\n", err); @@ -4658,10 +4466,6 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg) brcmf_dongle_scantime(ndev, WL_SCAN_CHANNEL_TIME, WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME); - err = brcmf_dongle_eventmsg(ndev); - if (err) - goto default_conf_out; - power_mode = cfg->pwr_save ? PM_FAST : PM_OFF; err = brcmf_fil_cmd_int_set(netdev_priv(ndev), BRCMF_C_SET_PM, power_mode); @@ -4692,29 +4496,25 @@ default_conf_out: } -static s32 __brcmf_cfg80211_up(struct brcmf_cfg80211_info *cfg) +static s32 __brcmf_cfg80211_up(struct brcmf_if *ifp) { - struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg)); - set_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state); + if (ifp->idx) + return 0; - return brcmf_config_dongle(cfg); + return brcmf_config_dongle(ifp->drvr->config); } -static s32 __brcmf_cfg80211_down(struct brcmf_cfg80211_info *cfg) +static s32 __brcmf_cfg80211_down(struct brcmf_if *ifp) { - struct net_device *ndev = cfg_to_ndev(cfg); - struct brcmf_if *ifp = netdev_priv(ndev); + struct brcmf_cfg80211_info *cfg = ifp->drvr->config; /* * 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 @@ -4729,23 +4529,27 @@ static s32 __brcmf_cfg80211_down(struct brcmf_cfg80211_info *cfg) return 0; } -s32 brcmf_cfg80211_up(struct brcmf_cfg80211_info *cfg) +s32 brcmf_cfg80211_up(struct net_device *ndev) { + struct brcmf_if *ifp = netdev_priv(ndev); + struct brcmf_cfg80211_info *cfg = ifp->drvr->config; s32 err = 0; mutex_lock(&cfg->usr_sync); - err = __brcmf_cfg80211_up(cfg); + err = __brcmf_cfg80211_up(ifp); mutex_unlock(&cfg->usr_sync); return err; } -s32 brcmf_cfg80211_down(struct brcmf_cfg80211_info *cfg) +s32 brcmf_cfg80211_down(struct net_device *ndev) { + struct brcmf_if *ifp = netdev_priv(ndev); + struct brcmf_cfg80211_info *cfg = ifp->drvr->config; s32 err = 0; mutex_lock(&cfg->usr_sync); - err = __brcmf_cfg80211_down(cfg); + err = __brcmf_cfg80211_down(ifp); mutex_unlock(&cfg->usr_sync); return err; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h index 399925d32e47..d60de187e7d9 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; @@ -226,25 +225,6 @@ struct brcmf_cfg80211_vif { struct list_head list; }; -/* forward declaration */ -struct brcmf_cfg80211_info; - -/* cfg80211 main event loop */ -struct brcmf_cfg80211_event_loop { - s32(*handler[BRCMF_E_LAST]) (struct brcmf_if *ifp, - const struct brcmf_event_msg *e, - void *data); -}; - -/* event queue for cfg80211 main event */ -struct brcmf_cfg80211_event_q { - struct list_head evt_q_list; - u32 etype; - struct brcmf_if *ifp; - struct brcmf_event_msg emsg; - s8 edata[1]; -}; - /* association inform */ struct brcmf_cfg80211_connect_info { u8 *req_ie; @@ -365,9 +345,6 @@ struct brcmf_pno_scanresults_le { * @wiphy: wiphy object for cfg80211 interface. * @conf: dongle configuration. * @scan_request: cfg80211 scan request object. - * @el: main event loop. - * @evt_q_list: used for event queue. - * @evt_q_lock: for event queue synchronization. * @usr_sync: mainly for dongle up/down synchronization. * @bss_list: bss_list holding scanned ap information. * @scan_req_int: internal scan request object. @@ -375,14 +352,12 @@ struct brcmf_pno_scanresults_le { * @ie: information element object for internal purpose. * @conn_info: association info. * @pmk_list: wpa2 pmk list. - * @event_work: event handler work struct. * @scan_status: scan activity on the dongle. * @pub: common driver information. * @channel: current channel. * @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. @@ -401,9 +376,6 @@ struct brcmf_cfg80211_info { struct wiphy *wiphy; struct brcmf_cfg80211_conf *conf; struct cfg80211_scan_request *scan_request; - struct brcmf_cfg80211_event_loop el; - struct list_head evt_q_list; - spinlock_t evt_q_lock; struct mutex usr_sync; struct brcmf_scan_results *bss_list; struct brcmf_cfg80211_scan_req scan_req_int; @@ -411,14 +383,12 @@ struct brcmf_cfg80211_info { struct brcmf_cfg80211_ie ie; struct brcmf_cfg80211_connect_info conn_info; struct brcmf_cfg80211_pmk_list *pmk_list; - struct work_struct event_work; unsigned long scan_status; struct brcmf_pub *pub; u32 channel; bool active_scan; bool sched_escan; bool ibss_starter; - bool link_up; bool pwr_save; bool dongle_up; bool roam_on; @@ -482,11 +452,7 @@ brcmf_cfg80211_connect_info *cfg_to_conn(struct brcmf_cfg80211_info *cfg) struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr); void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg); - -/* event handler from dongle */ -void brcmf_cfg80211_event(struct brcmf_if *ifp, const struct brcmf_event_msg *e, - void *data); -s32 brcmf_cfg80211_up(struct brcmf_cfg80211_info *cfg); -s32 brcmf_cfg80211_down(struct brcmf_cfg80211_info *cfg); +s32 brcmf_cfg80211_up(struct net_device *ndev); +s32 brcmf_cfg80211_down(struct net_device *ndev); #endif /* _wl_cfg80211_h_ */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/Makefile b/drivers/net/wireless/brcm80211/brcmsmac/Makefile index e227c4c68ef9..d3d4151c3eda 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 be5bcfb9153b..1de94f30564f 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 421f4ba7c63c..73d01e586109 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 55e12c327911..54c616919590 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 27dd73eef56d..871781e6a713 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 64a48f06d68b..a90b72202ec5 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 000000000000..be84791857cb --- /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 000000000000..796836b0f469 --- /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 5e53305bd9a9..1860c572b3c4 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 cc269ee5c499..ff5b80b09046 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 a744ea5a9559..85dbaf8ac997 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 565c15abbed5..8fce68751e47 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 8debc74c54e1..fb447747c2c6 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 abfd78822fb8..606b534347bc 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 622c01ca72c5..b7e95acc2084 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 5855f4fd16dc..4fb2834f4e64 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 ed1d1aa71d2d..dd9162722495 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 e11ae83111e4..ae1f3ad40d45 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 f0d8c04a9c8c..fb7cbcf81179 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/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c index 29b8fa1adefd..46938bc9886d 100644 --- a/drivers/net/wireless/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/ipw2x00/ipw2100.c @@ -1788,10 +1788,7 @@ static int ipw2100_up(struct ipw2100_priv *priv, int deferred) } /* Initialize the geo */ - if (libipw_set_geo(priv->ieee, &ipw_geos[0])) { - printk(KERN_WARNING DRV_NAME "Could not set geo\n"); - return 0; - } + libipw_set_geo(priv->ieee, &ipw_geos[0]); priv->ieee->freq_band = LIBIPW_24GHZ_BAND; lock = LOCK_NONE; diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c index 768bf612533e..482f505f3f35 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,22 +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; - } - if (libipw_set_geo(priv->ieee, &ipw_geos[j])) { - IPW_WARNING("Could not set geography."); - return 0; - } + 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/ipw2x00/libipw.h b/drivers/net/wireless/ipw2x00/libipw.h index 0b22fb421735..6eede52ad8c0 100644 --- a/drivers/net/wireless/ipw2x00/libipw.h +++ b/drivers/net/wireless/ipw2x00/libipw.h @@ -978,7 +978,7 @@ extern void libipw_network_reset(struct libipw_network *network); /* libipw_geo.c */ extern const struct libipw_geo *libipw_get_geo(struct libipw_device *ieee); -extern int libipw_set_geo(struct libipw_device *ieee, +extern void libipw_set_geo(struct libipw_device *ieee, const struct libipw_geo *geo); extern int libipw_is_valid_channel(struct libipw_device *ieee, diff --git a/drivers/net/wireless/ipw2x00/libipw_geo.c b/drivers/net/wireless/ipw2x00/libipw_geo.c index c9fe3c99cb00..218f2a32de21 100644 --- a/drivers/net/wireless/ipw2x00/libipw_geo.c +++ b/drivers/net/wireless/ipw2x00/libipw_geo.c @@ -132,7 +132,7 @@ u8 libipw_freq_to_channel(struct libipw_device * ieee, u32 freq) return 0; } -int libipw_set_geo(struct libipw_device *ieee, +void libipw_set_geo(struct libipw_device *ieee, const struct libipw_geo *geo) { memcpy(ieee->geo.name, geo->name, 3); @@ -143,7 +143,6 @@ int libipw_set_geo(struct libipw_device *ieee, sizeof(struct libipw_channel)); memcpy(ieee->geo.a, geo->a, ieee->geo.a_channels * sizeof(struct libipw_channel)); - return 0; } const struct libipw_geo *libipw_get_geo(struct libipw_device *ieee) diff --git a/drivers/net/wireless/iwlegacy/3945.c b/drivers/net/wireless/iwlegacy/3945.c index 87e539894330..e0b9d7fa5de0 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 eac4dc8bc879..07ffa575e3ef 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/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index 727fbb5db9da..5cf43236421e 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig @@ -133,12 +133,3 @@ config IWLWIFI_P2P support when it is loaded. Say Y only if you want to experiment with P2P. - -config IWLWIFI_EXPERIMENTAL_MFP - bool "support MFP (802.11w) even if uCode doesn't advertise" - depends on IWLWIFI - help - This option enables experimental MFP (802.11W) support - even if the microcode doesn't advertise it. - - Say Y only if you want to experiment with MFP. diff --git a/drivers/net/wireless/iwlwifi/dvm/agn.h b/drivers/net/wireless/iwlwifi/dvm/agn.h index 75e12f29d9eb..33b3ad2e546b 100644 --- a/drivers/net/wireless/iwlwifi/dvm/agn.h +++ b/drivers/net/wireless/iwlwifi/dvm/agn.h @@ -176,8 +176,8 @@ int iwlagn_hw_valid_rtc_data_addr(u32 addr); /* lib */ int iwlagn_send_tx_power(struct iwl_priv *priv); void iwlagn_temperature(struct iwl_priv *priv); -int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control); -void iwlagn_dev_txfifo_flush(struct iwl_priv *priv, u16 flush_control); +int iwlagn_txfifo_flush(struct iwl_priv *priv); +void iwlagn_dev_txfifo_flush(struct iwl_priv *priv); int iwlagn_send_beacon_cmd(struct iwl_priv *priv); int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags, bool clear); diff --git a/drivers/net/wireless/iwlwifi/dvm/commands.h b/drivers/net/wireless/iwlwifi/dvm/commands.h index 01128c96b5d8..71ab76b2b39d 100644 --- a/drivers/net/wireless/iwlwifi/dvm/commands.h +++ b/drivers/net/wireless/iwlwifi/dvm/commands.h @@ -986,8 +986,7 @@ struct iwl_rem_sta_cmd { #define IWL_AGG_TX_QUEUE_MSK cpu_to_le32(0xffc00) -#define IWL_DROP_SINGLE 0 -#define IWL_DROP_ALL (BIT(IWL_RXON_CTX_BSS) | BIT(IWL_RXON_CTX_PAN)) +#define IWL_DROP_ALL BIT(1) /* * REPLY_TXFIFO_FLUSH = 0x1e(command and response) @@ -1004,14 +1003,14 @@ struct iwl_rem_sta_cmd { * the flush operation ends when both the scheduler DMA done and TXFIFO empty * are set. * - * @fifo_control: bit mask for which queues to flush + * @queue_control: bit mask for which queues to flush * @flush_control: flush controls * 0: Dump single MSDU * 1: Dump multiple MSDU according to PS, INVALID STA, TTL, TID disable. * 2: Dump all FIFO */ struct iwl_txfifo_flush_cmd { - __le32 fifo_control; + __le32 queue_control; __le16 flush_control; __le16 reserved; } __packed; diff --git a/drivers/net/wireless/iwlwifi/dvm/debugfs.c b/drivers/net/wireless/iwlwifi/dvm/debugfs.c index 1a98fa3ab06d..769a08bca86f 100644 --- a/drivers/net/wireless/iwlwifi/dvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/dvm/debugfs.c @@ -2101,7 +2101,7 @@ static ssize_t iwl_dbgfs_txfifo_flush_write(struct file *file, if (iwl_is_rfkill(priv)) return -EFAULT; - iwlagn_dev_txfifo_flush(priv, IWL_DROP_ALL); + iwlagn_dev_txfifo_flush(priv); return count; } diff --git a/drivers/net/wireless/iwlwifi/dvm/dev.h b/drivers/net/wireless/iwlwifi/dvm/dev.h index 8141f91c3725..29c571a56251 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/lib.c b/drivers/net/wireless/iwlwifi/dvm/lib.c index bef88c1a2c9b..7e59be4b89b8 100644 --- a/drivers/net/wireless/iwlwifi/dvm/lib.c +++ b/drivers/net/wireless/iwlwifi/dvm/lib.c @@ -136,7 +136,7 @@ int iwlagn_manage_ibss_station(struct iwl_priv *priv, * 1. acquire mutex before calling * 2. make sure rf is on and not in exit state */ -int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control) +int iwlagn_txfifo_flush(struct iwl_priv *priv) { struct iwl_txfifo_flush_cmd flush_cmd; struct iwl_host_cmd cmd = { @@ -146,35 +146,34 @@ int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control) .data = { &flush_cmd, }, }; - might_sleep(); - memset(&flush_cmd, 0, sizeof(flush_cmd)); - if (flush_control & BIT(IWL_RXON_CTX_BSS)) - flush_cmd.fifo_control = IWL_SCD_VO_MSK | IWL_SCD_VI_MSK | - IWL_SCD_BE_MSK | IWL_SCD_BK_MSK | - IWL_SCD_MGMT_MSK; - if ((flush_control & BIT(IWL_RXON_CTX_PAN)) && - (priv->valid_contexts != BIT(IWL_RXON_CTX_BSS))) - flush_cmd.fifo_control |= IWL_PAN_SCD_VO_MSK | - IWL_PAN_SCD_VI_MSK | IWL_PAN_SCD_BE_MSK | - IWL_PAN_SCD_BK_MSK | IWL_PAN_SCD_MGMT_MSK | - IWL_PAN_SCD_MULTICAST_MSK; + + flush_cmd.queue_control = IWL_SCD_VO_MSK | IWL_SCD_VI_MSK | + IWL_SCD_BE_MSK | IWL_SCD_BK_MSK | + IWL_SCD_MGMT_MSK; + if ((priv->valid_contexts != BIT(IWL_RXON_CTX_BSS))) + flush_cmd.queue_control |= IWL_PAN_SCD_VO_MSK | + IWL_PAN_SCD_VI_MSK | + IWL_PAN_SCD_BE_MSK | + IWL_PAN_SCD_BK_MSK | + IWL_PAN_SCD_MGMT_MSK | + IWL_PAN_SCD_MULTICAST_MSK; if (priv->eeprom_data->sku & EEPROM_SKU_CAP_11N_ENABLE) - flush_cmd.fifo_control |= IWL_AGG_TX_QUEUE_MSK; + flush_cmd.queue_control |= IWL_AGG_TX_QUEUE_MSK; - IWL_DEBUG_INFO(priv, "fifo queue control: 0X%x\n", - flush_cmd.fifo_control); - flush_cmd.flush_control = cpu_to_le16(flush_control); + IWL_DEBUG_INFO(priv, "queue control: 0x%x\n", + flush_cmd.queue_control); + flush_cmd.flush_control = cpu_to_le16(IWL_DROP_ALL); return iwl_dvm_send_cmd(priv, &cmd); } -void iwlagn_dev_txfifo_flush(struct iwl_priv *priv, u16 flush_control) +void iwlagn_dev_txfifo_flush(struct iwl_priv *priv) { mutex_lock(&priv->mutex); ieee80211_stop_queues(priv->hw); - if (iwlagn_txfifo_flush(priv, IWL_DROP_ALL)) { + if (iwlagn_txfifo_flush(priv)) { IWL_ERR(priv, "flush request fail\n"); goto done; } diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c index ff8162d4c454..fb959b00b208 100644 --- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c @@ -168,10 +168,13 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv, hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS | IEEE80211_HW_SUPPORTS_STATIC_SMPS; -#ifndef CONFIG_IWLWIFI_EXPERIMENTAL_MFP - /* enable 11w if the uCode advertise */ - if (capa->flags & IWL_UCODE_TLV_FLAGS_MFP) -#endif /* !CONFIG_IWLWIFI_EXPERIMENTAL_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); @@ -521,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, @@ -1019,7 +1022,7 @@ static void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop) */ if (drop) { IWL_DEBUG_MAC80211(priv, "send flush command\n"); - if (iwlagn_txfifo_flush(priv, IWL_DROP_ALL)) { + if (iwlagn_txfifo_flush(priv)) { IWL_ERR(priv, "flush request fail\n"); goto done; } @@ -1032,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); @@ -1065,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; @@ -1354,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 475df45c8320..e3a07c916812 100644 --- a/drivers/net/wireless/iwlwifi/dvm/main.c +++ b/drivers/net/wireless/iwlwifi/dvm/main.c @@ -511,7 +511,7 @@ static void iwl_bg_tx_flush(struct work_struct *work) return; IWL_DEBUG_INFO(priv, "device request: flush all tx frames\n"); - iwlagn_dev_txfifo_flush(priv, IWL_DROP_ALL); + iwlagn_dev_txfifo_flush(priv); } /* @@ -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"); @@ -1204,7 +1202,7 @@ static int iwl_eeprom_init_hw_params(struct iwl_priv *priv) return -EINVAL; } - IWL_INFO(priv, "Device SKU: 0x%X\n", priv->eeprom_data->sku); + IWL_DEBUG_INFO(priv, "Device SKU: 0x%X\n", priv->eeprom_data->sku); priv->hw_params.tx_chains_num = num_of_ant(priv->eeprom_data->valid_tx_ant); @@ -1214,9 +1212,9 @@ static int iwl_eeprom_init_hw_params(struct iwl_priv *priv) priv->hw_params.rx_chains_num = num_of_ant(priv->eeprom_data->valid_rx_ant); - IWL_INFO(priv, "Valid Tx ant: 0x%X, Valid Rx ant: 0x%X\n", - priv->eeprom_data->valid_tx_ant, - priv->eeprom_data->valid_rx_ant); + IWL_DEBUG_INFO(priv, "Valid Tx ant: 0x%X, Valid Rx ant: 0x%X\n", + priv->eeprom_data->valid_tx_ant, + priv->eeprom_data->valid_rx_ant); return 0; } @@ -1231,7 +1229,7 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans, struct iwl_op_mode *op_mode; u16 num_mac; u32 ucode_flags; - struct iwl_trans_config trans_cfg; + struct iwl_trans_config trans_cfg = {}; static const u8 no_reclaim_cmds[] = { REPLY_RX_PHY_CMD, REPLY_RX_MPDU_CMD, @@ -1507,10 +1505,6 @@ static void iwl_op_mode_dvm_stop(struct iwl_op_mode *op_mode) iwl_tt_exit(priv); - /*This will stop the queues, move the device to low power state */ - priv->ucode_loaded = false; - iwl_trans_stop_device(priv->trans); - kfree(priv->eeprom_blob); iwl_free_eeprom_data(priv->eeprom_data); @@ -1926,8 +1920,6 @@ static void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand) * commands by clearing the ready bit */ clear_bit(STATUS_READY, &priv->status); - wake_up(&priv->trans->wait_command_queue); - if (!ondemand) { /* * If firmware keep reloading, then it indicate something @@ -2113,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 5a9c325804f6..cac4f37cc427 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rx.c +++ b/drivers/net/wireless/iwlwifi/dvm/rx.c @@ -631,8 +631,6 @@ static int iwlagn_rx_card_state_notif(struct iwl_priv *priv, test_bit(STATUS_RF_KILL_HW, &priv->status))) wiphy_rfkill_set_hw_state(priv->hw->wiphy, test_bit(STATUS_RF_KILL_HW, &priv->status)); - else - wake_up(&priv->trans->wait_command_queue); return 0; } @@ -901,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; @@ -951,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/dvm/tx.c b/drivers/net/wireless/iwlwifi/dvm/tx.c index f5ca73a89870..4ae031f6726b 100644 --- a/drivers/net/wireless/iwlwifi/dvm/tx.c +++ b/drivers/net/wireless/iwlwifi/dvm/tx.c @@ -1075,14 +1075,11 @@ static void iwlagn_count_tx_err_status(struct iwl_priv *priv, u16 status) static void iwlagn_set_tx_status(struct iwl_priv *priv, struct ieee80211_tx_info *info, - struct iwlagn_tx_resp *tx_resp, - bool is_agg) + struct iwlagn_tx_resp *tx_resp) { - u16 status = le16_to_cpu(tx_resp->status.status); + u16 status = le16_to_cpu(tx_resp->status.status); info->status.rates[0].count = tx_resp->failure_frame + 1; - if (is_agg) - info->flags &= ~IEEE80211_TX_CTL_AMPDU; info->flags |= iwl_tx_status_to_mac80211(status); iwlagn_hwrate_to_tx_control(priv, le32_to_cpu(tx_resp->rate_n_flags), info); @@ -1231,7 +1228,7 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, if (is_agg && !iwl_is_tx_success(status)) info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; iwlagn_set_tx_status(priv, IEEE80211_SKB_CB(skb), - tx_resp, is_agg); + tx_resp); if (!is_agg) iwlagn_non_agg_tx_status(priv, ctx, hdr->addr1); diff --git a/drivers/net/wireless/iwlwifi/dvm/ucode.c b/drivers/net/wireless/iwlwifi/dvm/ucode.c index 2cb1efbc5ed1..95e6d33f5159 100644 --- a/drivers/net/wireless/iwlwifi/dvm/ucode.c +++ b/drivers/net/wireless/iwlwifi/dvm/ucode.c @@ -254,7 +254,7 @@ static int iwl_alive_notify(struct iwl_priv *priv) int ret; int i; - iwl_trans_fw_alive(priv->trans); + iwl_trans_fw_alive(priv->trans, 0); if (priv->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PAN && priv->eeprom_data->sku & EEPROM_SKU_CAP_IPAN_ENABLE) { diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h index 87f465a49df1..196266aa5a9d 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-devtrace.h b/drivers/net/wireless/iwlwifi/iwl-devtrace.h index 678717bf62eb..b3fde5f7b9bc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-devtrace.h +++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.h @@ -306,7 +306,7 @@ TRACE_EVENT(iwlwifi_dev_rx_data, memcpy(__get_dynamic_array(data), ((u8 *)rxbuf) + offs, len - offs); ), - TP_printk("[%s] TX frame data", __get_str(dev)) + TP_printk("[%s] RX frame data", __get_str(dev)) ); #undef TRACE_SYSTEM diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c index f10170fe8799..4a9dc9629efe 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c @@ -889,8 +889,8 @@ int iwl_eeprom_check_version(struct iwl_eeprom_data *data, { if (data->eeprom_version >= trans->cfg->eeprom_ver || data->calib_version >= trans->cfg->eeprom_calib_ver) { - IWL_INFO(trans, "device EEPROM VER=0x%x, CALIB=0x%x\n", - data->eeprom_version, data->calib_version); + IWL_DEBUG_INFO(trans, "device EEPROM VER=0x%x, CALIB=0x%x\n", + data->eeprom_version, data->calib_version); return 0; } diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h index 806046641747..ec48563d3c6a 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/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index f75ea6d73ffc..e378ea6dca9c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -221,14 +221,21 @@ struct iwl_device_cmd { /** * struct iwl_hcmd_dataflag - flag for each one of the chunks of the command * - * IWL_HCMD_DFL_NOCOPY: By default, the command is copied to the host command's + * @IWL_HCMD_DFL_NOCOPY: By default, the command is copied to the host command's * ring. The transport layer doesn't map the command's buffer to DMA, but * rather copies it to an previously allocated DMA buffer. This flag tells * the transport layer not to copy the command, but to map the existing - * buffer. This can save memcpy and is worth with very big comamnds. + * buffer (that is passed in) instead. This saves the memcpy and allows + * commands that are bigger than the fixed buffer to be submitted. + * Note that a TFD entry after a NOCOPY one cannot be a normal copied one. + * @IWL_HCMD_DFL_DUP: Only valid without NOCOPY, duplicate the memory for this + * chunk internally and free it again after the command completes. This + * can (currently) be used only once per command. + * Note that a TFD entry after a DUP one cannot be a normal copied one. */ enum iwl_hcmd_dataflag { IWL_HCMD_DFL_NOCOPY = BIT(0), + IWL_HCMD_DFL_DUP = BIT(1), }; /** @@ -348,14 +355,17 @@ struct iwl_trans; * @start_fw: allocates and inits all the resources for the transport * layer. Also kick a fw image. * May sleep - * @fw_alive: called when the fw sends alive notification + * @fw_alive: called when the fw sends alive notification. If the fw provides + * the SCD base address in SRAM, then provide it here, or 0 otherwise. * May sleep * @stop_device:stops the whole device (embedded CPU put to reset) * May sleep * @wowlan_suspend: put the device into the correct mode for WoWLAN during * suspend. This is optional, if not implemented WoWLAN will not be * supported. This callback may sleep. - * @send_cmd:send a host command + * @send_cmd:send a host command. Must return -ERFKILL if RFkill is asserted. + * If RFkill is asserted in the middle of a SYNC host command, it must + * return -ERFKILL straight away. * May sleep only if CMD_SYNC is set * @tx: send an skb * Must be atomic @@ -385,7 +395,7 @@ struct iwl_trans_ops { int (*start_hw)(struct iwl_trans *iwl_trans); void (*stop_hw)(struct iwl_trans *iwl_trans, bool op_mode_leaving); int (*start_fw)(struct iwl_trans *trans, const struct fw_img *fw); - void (*fw_alive)(struct iwl_trans *trans); + void (*fw_alive)(struct iwl_trans *trans, u32 scd_addr); void (*stop_device)(struct iwl_trans *trans); void (*wowlan_suspend)(struct iwl_trans *trans); @@ -438,7 +448,6 @@ enum iwl_trans_state { * Set during transport allocation. * @hw_id_str: a string with info about HW ID. Set during transport allocation. * @pm_support: set to true in start_hw if link pm is supported - * @wait_command_queue: the wait_queue for SYNC host commands * @dev_cmd_pool: pool for Tx cmd allocation - for internal use only. * The user should use iwl_trans_{alloc,free}_tx_cmd. * @dev_cmd_headroom: room needed for the transport's private use before the @@ -465,8 +474,6 @@ struct iwl_trans { bool pm_support; - wait_queue_head_t wait_command_queue; - /* The following fields are internal only */ struct kmem_cache *dev_cmd_pool; size_t dev_cmd_headroom; @@ -508,13 +515,13 @@ static inline void iwl_trans_stop_hw(struct iwl_trans *trans, trans->state = IWL_TRANS_NO_FW; } -static inline void iwl_trans_fw_alive(struct iwl_trans *trans) +static inline void iwl_trans_fw_alive(struct iwl_trans *trans, u32 scd_addr) { might_sleep(); trans->state = IWL_TRANS_FW_ALIVE; - trans->ops->fw_alive(trans); + trans->ops->fw_alive(trans, scd_addr); } static inline int iwl_trans_start_fw(struct iwl_trans *trans, diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c index 2a4675396707..956fe6c370bc 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 401178f44a3b..d91d2e8c62f5 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,15 +182,17 @@ 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; + /* buffer to free after command completes */ + const void *free_buf; struct iwl_cmd_meta meta; }; /** - * 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) @@ -203,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; @@ -236,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; @@ -258,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)]; @@ -268,6 +270,8 @@ struct iwl_trans_pcie { bool ucode_write_complete; wait_queue_head_t ucode_write_waitq; + wait_queue_head_t wait_command_queue; + unsigned long status; u8 cmd_queue; u8 cmd_fifo; @@ -283,13 +287,23 @@ struct iwl_trans_pcie { unsigned long wd_timeout; }; -/***************************************************** -* DRIVER STATUS FUNCTIONS -******************************************************/ -#define STATUS_HCMD_ACTIVE 0 -#define STATUS_DEVICE_ENABLED 1 -#define STATUS_TPOWER_PMI 2 -#define STATUS_INT_ENABLED 3 +/** + * 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, + STATUS_INT_ENABLED, + STATUS_RFKILL, + STATUS_FW_ERROR, +}; #define IWL_TRANS_GET_PCIE_TRANS(_iwl_trans) \ ((struct iwl_trans_pcie *) ((_iwl_trans)->trans_specific)) @@ -301,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); @@ -309,50 +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); -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 @@ -388,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); @@ -399,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); @@ -411,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) : @@ -423,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 137af4c46a6c..bb32510fdd62 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,11 +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 list_head *element; + struct iwl_rxq *rxq = &trans_pcie->rxq; struct iwl_rx_mem_buffer *rxb; unsigned long flags; @@ -215,18 +223,18 @@ 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); /* Get next free Rx buffer, remove from free list */ - element = rxq->rx_free.next; - rxb = list_entry(element, struct iwl_rx_mem_buffer, list); - list_del(element); + rxb = list_first_entry(&rxq->rx_free, struct iwl_rx_mem_buffer, + list); + 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--; @@ -243,24 +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 list_head *element; + struct iwl_rxq *rxq = &trans_pcie->rxq; struct iwl_rx_mem_buffer *rxb; struct page *page; unsigned long flags; @@ -308,10 +315,9 @@ static void iwl_rx_allocate(struct iwl_trans *trans, gfp_t priority) __free_pages(page, trans_pcie->rx_page_order); return; } - element = rxq->rx_used.next; - rxb = list_entry(element, struct iwl_rx_mem_buffer, list); - list_del(element); - + rxb = list_first_entry(&rxq->rx_used, struct iwl_rx_mem_buffer, + list); + list_del(&rxb->list); spin_unlock_irqrestore(&rxq->lock, flags); BUG_ON(rxb->page); @@ -321,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! */ @@ -335,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_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_rx_handle_rxbuf(struct iwl_trans *trans, +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; @@ -405,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; @@ -438,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); @@ -452,6 +645,9 @@ static void iwl_rx_handle_rxbuf(struct iwl_trans *trans, /* The original command isn't needed any more */ kfree(txq->entries[cmd_index].copy_cmd); txq->entries[cmd_index].copy_cmd = NULL; + /* nor is the duplicated part of the command */ + kfree(txq->entries[cmd_index].free_buf); + txq->entries[cmd_index].free_buf = NULL; } /* @@ -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,39 +758,41 @@ 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); + /* W/A for WiFi/WiMAX coex and WiMAX own the RF */ if (trans->cfg->internal_wimax_coex && (!(iwl_read_prph(trans, APMG_CLK_CTRL_REG) & APMS_CLK_VAL_MRB_FUNC_MODE) || (iwl_read_prph(trans, APMG_PS_CTRL_REG) & APMG_PS_CTRL_VAL_RESET_REQ))) { - struct iwl_trans_pcie *trans_pcie = - IWL_TRANS_GET_PCIE_TRANS(trans); - clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status); iwl_op_mode_wimax_active(trans->op_mode); - wake_up(&trans->wait_command_queue); + wake_up(&trans_pcie->wait_command_queue); 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); + wake_up(&trans_pcie->wait_command_queue); 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; @@ -639,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; @@ -676,6 +881,16 @@ void iwl_irq_tasklet(struct iwl_trans *trans) isr_stats->rfkill++; iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill); + if (hw_rfkill) { + set_bit(STATUS_RFKILL, &trans_pcie->status); + if (test_and_clear_bit(STATUS_HCMD_ACTIVE, + &trans_pcie->status)) + IWL_DEBUG_RF_KILL(trans, + "Rfkill while SYNC HCMD in flight\n"); + wake_up(&trans_pcie->wait_command_queue); + } else { + clear_bit(STATUS_RFKILL, &trans_pcie->status); + } handled |= CSR_INT_BIT_RF_KILL; } @@ -692,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++; @@ -740,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 @@ -798,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); @@ -811,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); @@ -830,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; } @@ -851,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; @@ -881,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; @@ -892,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); @@ -939,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) && @@ -964,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; @@ -984,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. @@ -1000,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. */ @@ -1049,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 4d9dfa7de4ec..f6c21e7edaf2 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -74,584 +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 - */ -static 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); - } - - /* 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) @@ -673,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; - - pcie_capability_read_word(trans_pcie->pci_dev, PCI_EXP_LNKCTL, - &pci_lnk_ctl); - return pci_lnk_ctl; -} + u16 lctl; -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. @@ -693,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) { @@ -710,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; @@ -745,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) @@ -791,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; @@ -809,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"); @@ -817,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); @@ -832,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) { @@ -869,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; @@ -887,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; @@ -904,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; @@ -918,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); @@ -965,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; @@ -986,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", @@ -1000,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; @@ -1009,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; } @@ -1023,15 +441,18 @@ static int iwl_load_given_ucode(struct iwl_trans *trans, static int iwl_trans_pcie_start_fw(struct iwl_trans *trans, const struct fw_img *fw) { + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); int ret; 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; } + clear_bit(STATUS_FW_ERROR, &trans_pcie->status); + iwl_enable_rfkill_int(trans); /* If platform's RF_KILL switch is NOT set to KILL */ @@ -1042,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; @@ -1062,125 +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); + return iwl_pcie_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) +static void iwl_trans_pcie_fw_alive(struct iwl_trans *trans, u32 scd_addr) { - 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) -{ - 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); - 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); -} - -static void iwl_trans_pcie_fw_alive(struct iwl_trans *trans) -{ - iwl_reset_ict(trans); - iwl_tx_start(trans); -} - -/** - * 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) @@ -1194,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, @@ -1204,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, @@ -1218,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 @@ -1243,6 +552,7 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) clear_bit(STATUS_INT_ENABLED, &trans_pcie->status); clear_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status); clear_bit(STATUS_TPOWER_PMI, &trans_pcie->status); + clear_bit(STATUS_RFKILL, &trans_pcie->status); } static void iwl_trans_pcie_wowlan_suspend(struct iwl_trans *trans) @@ -1256,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); @@ -1431,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); @@ -1467,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; } @@ -1483,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); @@ -1507,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); @@ -1574,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); @@ -1625,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; @@ -1672,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[] = { @@ -1751,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[] = { @@ -1808,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 = { \ @@ -1841,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; @@ -1878,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); @@ -1997,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; } @@ -2011,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); @@ -2080,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, @@ -2090,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, @@ -2115,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); @@ -2166,19 +1288,20 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, goto out_pci_release_regions; } - dev_info(&pdev->dev, "pci_resource_len = 0x%08llx\n", - (unsigned long long) pci_resource_len(pdev, 0)); - dev_info(&pdev->dev, "pci_resource_base = %p\n", trans_pcie->hw_base); - - dev_info(&pdev->dev, "HW Revision ID = 0x%X\n", pdev->revision); - /* We disable the RETRY_TIMEOUT register (0x41) to keep * PCI Tx retries from interfering with C3 CPU state */ 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; @@ -2188,16 +1311,8 @@ 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->wait_command_queue); + init_waitqueue_head(&trans_pcie->wait_command_queue); spin_lock_init(&trans->reg_lock); snprintf(trans->dev_cmd_pool_name, sizeof(trans->dev_cmd_pool_name), diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index db3efbb84d92..6c5b867c353a 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; -int iwl_queue_space(const struct iwl_queue *q) + 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; + + 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); +} + +/* + * 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_txq_set_ratid_map(struct iwl_trans *trans, u16 ra_tid, +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,18 +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_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 * @@ -508,15 +1120,17 @@ 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; + void *dup_buf = NULL; dma_addr_t phys_addr; - u32 idx; + int idx; u16 copy_size, cmd_size; bool had_nocopy = false; int i; @@ -533,10 +1147,33 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) continue; if (cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY) { had_nocopy = true; + if (WARN_ON(cmd->dataflags[i] & IWL_HCMD_DFL_DUP)) { + idx = -EINVAL; + goto free_dup_buf; + } + } else if (cmd->dataflags[i] & IWL_HCMD_DFL_DUP) { + /* + * This is also a chunk that isn't copied + * to the static buffer so set had_nocopy. + */ + had_nocopy = true; + + /* only allowed once */ + if (WARN_ON(dup_buf)) { + idx = -EINVAL; + goto free_dup_buf; + } + + dup_buf = kmemdup(cmd->data[i], cmd->len[i], + GFP_ATOMIC); + if (!dup_buf) + return -ENOMEM; } else { /* NOCOPY must not be followed by normal! */ - if (WARN_ON(had_nocopy)) - return -EINVAL; + if (WARN_ON(had_nocopy)) { + idx = -EINVAL; + goto free_dup_buf; + } copy_size += cmd->len[i]; } cmd_size += cmd->len[i]; @@ -550,9 +1187,10 @@ 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)) - return -EINVAL; + get_cmd_string(trans_pcie, cmd->id), cmd->id, copy_size)) { + idx = -EINVAL; + goto free_dup_buf; + } spin_lock_bh(&txq->lock); @@ -561,7 +1199,8 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) IWL_ERR(trans, "No space in command queue\n"); iwl_op_mode_cmd_queue_full(trans->op_mode); - return -ENOSPC; + idx = -ENOSPC; + goto free_dup_buf; } idx = get_cmd_index(q, q->write_ptr); @@ -585,7 +1224,8 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) for (i = 0; i < IWL_MAX_CMD_TFDS; i++) { if (!cmd->len[i]) continue; - if (cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY) + if (cmd->dataflags[i] & (IWL_HCMD_DFL_NOCOPY | + IWL_HCMD_DFL_DUP)) break; memcpy((u8 *)out_cmd + cmd_pos, cmd->data[i], cmd->len[i]); cmd_pos += cmd->len[i]; @@ -610,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); @@ -624,28 +1264,35 @@ 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]; + if (!cmd->len[i]) continue; - if (!(cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY)) + if (!(cmd->dataflags[i] & (IWL_HCMD_DFL_NOCOPY | + IWL_HCMD_DFL_DUP))) continue; - phys_addr = dma_map_single(trans->dev, (void *)cmd->data[i], + if (cmd->dataflags[i] & IWL_HCMD_DFL_DUP) + data = dup_buf; + 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; + if (WARN_ON_ONCE(txq->entries[idx].free_buf)) + kfree(txq->entries[idx].free_buf); + txq->entries[idx].free_buf = dup_buf; txq->need_update = 1; @@ -658,70 +1305,18 @@ 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); + free_dup_buf: + if (idx < 0) + kfree(dup_buf); 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) @@ -730,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); @@ -741,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 @@ -761,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) { @@ -773,20 +1368,18 @@ 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)); - wake_up(&trans->wait_command_queue); + get_cmd_string(trans_pcie, cmd->hdr.cmd)); + wake_up(&trans_pcie->wait_command_queue); } meta->flags = 0; @@ -796,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; @@ -805,59 +1399,59 @@ 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; } - ret = wait_event_timeout(trans->wait_command_queue, + ret = wait_event_timeout(trans_pcie->wait_command_queue, !test_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status), 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, @@ -867,16 +1461,28 @@ 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; } } + if (test_bit(STATUS_FW_ERROR, &trans_pcie->status)) { + IWL_ERR(trans, "FW error in SYNC CMD %s\n", + get_cmd_string(trans_pcie, cmd->id)); + ret = -EIO; + goto cancel; + } + + if (test_bit(STATUS_RFKILL, &trans_pcie->status)) { + IWL_DEBUG_RF_KILL(trans, "RFKILL in SYNC CMD... no rsp\n"); + ret = -ERFKILL; + goto cancel; + } + 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; } @@ -903,64 +1509,183 @@ 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); + + if (test_bit(STATUS_FW_ERROR, &trans_pcie->status)) + return -EIO; + + if (test_bit(STATUS_RFKILL, &trans_pcie->status)) + return -ERFKILL; + if (cmd->flags & CMD_ASYNC) - return iwl_send_cmd_async(trans, cmd); + return iwl_pcie_send_hcmd_async(trans, cmd); - return iwl_send_cmd_sync(trans, cmd); + /* We still can fail on RFKILL that can be asserted while we wait */ + 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); - iwl_queue_progress(trans_pcie, txq); + /* 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_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 1c10b542ab23..ec36868f6fc5 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 429ca3215fdb..2aa8a1aa1184 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -44,9 +44,9 @@ static int radios = 2; module_param(radios, int, 0444); MODULE_PARM_DESC(radios, "Number of simulated radios"); -static bool fake_hw_scan; -module_param(fake_hw_scan, bool, 0444); -MODULE_PARM_DESC(fake_hw_scan, "Install fake (no-op) hw-scan handler"); +static int channels = 1; +module_param(channels, int, 0444); +MODULE_PARM_DESC(channels, "Number of concurrent channels"); /** * enum hwsim_regtest - the type of regulatory tests we offer @@ -166,7 +166,9 @@ struct hwsim_vif_priv { static inline void hwsim_check_magic(struct ieee80211_vif *vif) { struct hwsim_vif_priv *vp = (void *)vif->drv_priv; - WARN_ON(vp->magic != HWSIM_VIF_MAGIC); + WARN(vp->magic != HWSIM_VIF_MAGIC, + "Invalid VIF (%p) magic %#x, %pM, %d/%d\n", + vif, vp->magic, vif->addr, vif->type, vif->p2p); } static inline void hwsim_set_magic(struct ieee80211_vif *vif) @@ -185,7 +187,7 @@ struct hwsim_sta_priv { u32 magic; }; -#define HWSIM_STA_MAGIC 0x6d537748 +#define HWSIM_STA_MAGIC 0x6d537749 static inline void hwsim_check_sta_magic(struct ieee80211_sta *sta) { @@ -205,6 +207,30 @@ static inline void hwsim_clear_sta_magic(struct ieee80211_sta *sta) sp->magic = 0; } +struct hwsim_chanctx_priv { + u32 magic; +}; + +#define HWSIM_CHANCTX_MAGIC 0x6d53774a + +static inline void hwsim_check_chanctx_magic(struct ieee80211_chanctx_conf *c) +{ + struct hwsim_chanctx_priv *cp = (void *)c->drv_priv; + WARN_ON(cp->magic != HWSIM_CHANCTX_MAGIC); +} + +static inline void hwsim_set_chanctx_magic(struct ieee80211_chanctx_conf *c) +{ + struct hwsim_chanctx_priv *cp = (void *)c->drv_priv; + cp->magic = HWSIM_CHANCTX_MAGIC; +} + +static inline void hwsim_clear_chanctx_magic(struct ieee80211_chanctx_conf *c) +{ + struct hwsim_chanctx_priv *cp = (void *)c->drv_priv; + cp->magic = 0; +} + static struct class *hwsim_class; static struct net_device *hwsim_mon; /* global monitor netdev */ @@ -299,6 +325,13 @@ struct mac80211_hwsim_data { struct mac_address addresses[2]; + struct ieee80211_channel *tmp_chan; + struct delayed_work roc_done; + struct delayed_work hw_scan; + struct cfg80211_scan_request *hw_scan_request; + struct ieee80211_vif *hw_scan_vif; + int scan_chan_idx; + struct ieee80211_channel *channel; unsigned long beacon_int; /* in jiffies unit */ unsigned int rx_filter; @@ -396,7 +429,8 @@ static void mac80211_hwsim_set_tsf(struct ieee80211_hw *hw, } static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw, - struct sk_buff *tx_skb) + struct sk_buff *tx_skb, + struct ieee80211_channel *chan) { struct mac80211_hwsim_data *data = hw->priv; struct sk_buff *skb; @@ -423,7 +457,7 @@ static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw, hdr->rt_tsft = __mac80211_hwsim_get_tsf(data); hdr->rt_flags = 0; hdr->rt_rate = txrate->bitrate / 5; - hdr->rt_channel = cpu_to_le16(data->channel->center_freq); + hdr->rt_channel = cpu_to_le16(chan->center_freq); flags = IEEE80211_CHAN_2GHZ; if (txrate->flags & IEEE80211_RATE_ERP_G) flags |= IEEE80211_CHAN_OFDM; @@ -441,9 +475,9 @@ static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw, } -static void mac80211_hwsim_monitor_ack(struct ieee80211_hw *hw, const u8 *addr) +static void mac80211_hwsim_monitor_ack(struct ieee80211_channel *chan, + const u8 *addr) { - struct mac80211_hwsim_data *data = hw->priv; struct sk_buff *skb; struct hwsim_radiotap_hdr *hdr; u16 flags; @@ -464,7 +498,7 @@ static void mac80211_hwsim_monitor_ack(struct ieee80211_hw *hw, const u8 *addr) (1 << IEEE80211_RADIOTAP_CHANNEL)); hdr->rt_flags = 0; hdr->rt_rate = 0; - hdr->rt_channel = cpu_to_le16(data->channel->center_freq); + hdr->rt_channel = cpu_to_le16(chan->center_freq); flags = IEEE80211_CHAN_2GHZ; hdr->rt_chbitmask = cpu_to_le16(flags); @@ -537,6 +571,7 @@ static bool mac80211_hwsim_addr_match(struct mac80211_hwsim_data *data, md.ret = false; md.addr = addr; ieee80211_iterate_active_interfaces_atomic(data->hw, + IEEE80211_IFACE_ITER_NORMAL, mac80211_hwsim_addr_iter, &md); @@ -556,12 +591,6 @@ static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw, int i; struct hwsim_tx_rate tx_attempts[IEEE80211_TX_MAX_RATES]; - if (data->idle) { - wiphy_debug(hw->wiphy, "Trying to TX when idle - reject\n"); - dev_kfree_skb(my_skb); - return; - } - if (data->ps != PS_DISABLED) hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); /* If the queue contains MAX_QUEUE skb's drop some */ @@ -629,8 +658,38 @@ nla_put_failure: printk(KERN_DEBUG "mac80211_hwsim: error occurred in %s\n", __func__); } +static bool hwsim_chans_compat(struct ieee80211_channel *c1, + struct ieee80211_channel *c2) +{ + if (!c1 || !c2) + return false; + + return c1->center_freq == c2->center_freq; +} + +struct tx_iter_data { + struct ieee80211_channel *channel; + bool receive; +}; + +static void mac80211_hwsim_tx_iter(void *_data, u8 *addr, + struct ieee80211_vif *vif) +{ + struct tx_iter_data *data = _data; + + if (!vif->chanctx_conf) + return; + + if (!hwsim_chans_compat(data->channel, + rcu_dereference(vif->chanctx_conf)->def.chan)) + return; + + data->receive = true; +} + static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw, - struct sk_buff *skb) + struct sk_buff *skb, + struct ieee80211_channel *chan) { struct mac80211_hwsim_data *data = hw->priv, *data2; bool ack = false; @@ -639,15 +698,10 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw, struct ieee80211_rx_status rx_status; struct ieee80211_rate *txrate = ieee80211_get_tx_rate(hw, info); - if (data->idle) { - wiphy_debug(hw->wiphy, "Trying to TX when idle - reject\n"); - return false; - } - memset(&rx_status, 0, sizeof(rx_status)); - rx_status.flag |= RX_FLAG_MACTIME_MPDU; - rx_status.freq = data->channel->center_freq; - rx_status.band = data->channel->band; + 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; if (info->control.rates[0].flags & IEEE80211_TX_RC_MCS) rx_status.flag |= RX_FLAG_HT; @@ -673,17 +727,35 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw, list_for_each_entry(data2, &hwsim_radios, list) { struct sk_buff *nskb; struct ieee80211_mgmt *mgmt; + struct tx_iter_data tx_iter_data = { + .receive = false, + .channel = chan, + }; if (data == data2) continue; - if (data2->idle || !data2->started || - !hwsim_ps_rx_ok(data2, skb) || !data2->channel || - data->channel->center_freq != data2->channel->center_freq || - !(data->group & data2->group)) + if (!data2->started || (data2->idle && !data2->tmp_chan) || + !hwsim_ps_rx_ok(data2, skb)) continue; - nskb = skb_copy(skb, GFP_ATOMIC); + if (!(data->group & data2->group)) + continue; + + if (!hwsim_chans_compat(chan, data2->tmp_chan) && + !hwsim_chans_compat(chan, data2->channel)) { + ieee80211_iterate_active_interfaces_atomic( + data2->hw, IEEE80211_IFACE_ITER_NORMAL, + mac80211_hwsim_tx_iter, &tx_iter_data); + if (!tx_iter_data.receive) + continue; + } + + /* + * 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; @@ -701,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); } @@ -713,18 +812,51 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct sk_buff *skb) { + struct mac80211_hwsim_data *data = hw->priv; + struct ieee80211_tx_info *txi = IEEE80211_SKB_CB(skb); + struct ieee80211_chanctx_conf *chanctx_conf; + struct ieee80211_channel *channel; bool ack; - struct ieee80211_tx_info *txi; u32 _portid; - mac80211_hwsim_monitor_rx(hw, skb); - - if (skb->len < 10) { + if (WARN_ON(skb->len < 10)) { /* Should not happen; just a sanity check for addr1 use */ dev_kfree_skb(skb); return; } + if (channels == 1) { + channel = data->channel; + } else if (txi->hw_queue == 4) { + channel = data->tmp_chan; + } else { + chanctx_conf = rcu_dereference(txi->control.vif->chanctx_conf); + if (chanctx_conf) + channel = chanctx_conf->def.chan; + else + channel = NULL; + } + + if (WARN(!channel, "TX w/o channel - queue = %d\n", txi->hw_queue)) { + dev_kfree_skb(skb); + return; + } + + if (data->idle && !data->tmp_chan) { + wiphy_debug(hw->wiphy, "Trying to TX when idle - reject\n"); + dev_kfree_skb(skb); + return; + } + + if (txi->control.vif) + hwsim_check_magic(txi->control.vif); + if (control->sta) + hwsim_check_sta_magic(control->sta); + + txi->rate_driver_data[0] = channel; + + mac80211_hwsim_monitor_rx(hw, skb, channel); + /* wmediumd mode check */ _portid = ACCESS_ONCE(wmediumd_portid); @@ -732,15 +864,13 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw, return mac80211_hwsim_tx_frame_nl(hw, skb, _portid); /* NO wmediumd detected, perfect medium simulation */ - ack = mac80211_hwsim_tx_frame_no_nl(hw, skb); + ack = mac80211_hwsim_tx_frame_no_nl(hw, skb, channel); if (ack && skb->len >= 16) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - mac80211_hwsim_monitor_ack(hw, hdr->addr2); + mac80211_hwsim_monitor_ack(channel, hdr->addr2); } - txi = IEEE80211_SKB_CB(skb); - ieee80211_tx_info_clear_status(txi); /* frame was transmitted at most favorable rate at first attempt */ @@ -778,6 +908,13 @@ static int mac80211_hwsim_add_interface(struct ieee80211_hw *hw, __func__, ieee80211_vif_type_p2p(vif), vif->addr); hwsim_set_magic(vif); + + vif->cab_queue = 0; + vif->hw_queue[IEEE80211_AC_VO] = 0; + vif->hw_queue[IEEE80211_AC_VI] = 1; + vif->hw_queue[IEEE80211_AC_BE] = 2; + vif->hw_queue[IEEE80211_AC_BK] = 3; + return 0; } @@ -807,14 +944,26 @@ static void mac80211_hwsim_remove_interface( hwsim_clear_magic(vif); } +static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, + struct sk_buff *skb, + struct ieee80211_channel *chan) +{ + u32 _pid = ACCESS_ONCE(wmediumd_portid); + + mac80211_hwsim_monitor_rx(hw, skb, chan); + + if (_pid) + return mac80211_hwsim_tx_frame_nl(hw, skb, _pid); + + mac80211_hwsim_tx_frame_no_nl(hw, skb, chan); + dev_kfree_skb(skb); +} static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac, struct ieee80211_vif *vif) { struct ieee80211_hw *hw = arg; struct sk_buff *skb; - struct ieee80211_tx_info *info; - u32 _portid; hwsim_check_magic(vif); @@ -826,18 +975,9 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac, skb = ieee80211_beacon_get(hw, vif); if (skb == NULL) return; - info = IEEE80211_SKB_CB(skb); - - mac80211_hwsim_monitor_rx(hw, skb); - - /* wmediumd mode check */ - _portid = ACCESS_ONCE(wmediumd_portid); - - if (_portid) - return mac80211_hwsim_tx_frame_nl(hw, skb, _portid); - mac80211_hwsim_tx_frame_no_nl(hw, skb); - dev_kfree_skb(skb); + mac80211_hwsim_tx_frame(hw, skb, + rcu_dereference(vif->chanctx_conf)->def.chan); } @@ -850,7 +990,8 @@ static void mac80211_hwsim_beacon(unsigned long arg) return; ieee80211_iterate_active_interfaces_atomic( - hw, mac80211_hwsim_beacon_tx, hw); + hw, IEEE80211_IFACE_ITER_NORMAL, + mac80211_hwsim_beacon_tx, hw); data->beacon_timer.expires = jiffies + data->beacon_int; add_timer(&data->beacon_timer); @@ -877,7 +1018,7 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed) wiphy_debug(hw->wiphy, "%s (freq=%d/%s idle=%d ps=%d smps=%s)\n", __func__, - conf->channel->center_freq, + conf->channel ? conf->channel->center_freq : 0, hwsim_chantypes[conf->channel_type], !!(conf->flags & IEEE80211_CONF_IDLE), !!(conf->flags & IEEE80211_CONF_PS), @@ -886,6 +1027,9 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed) data->idle = !!(conf->flags & IEEE80211_CONF_IDLE); data->channel = conf->channel; + + WARN_ON(data->channel && channels > 1); + data->power_level = conf->power_level; if (!data->started || !data->beacon_int) del_timer(&data->beacon_timer); @@ -963,15 +1107,17 @@ 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) { wiphy_debug(hw->wiphy, " BASIC_RATES: 0x%llx\n", (unsigned long long) info->basic_rates); } + + if (changed & BSS_CHANGED_TXPOWER) + wiphy_debug(hw->wiphy, " TX Power: %d dBm\n", info->txpower); } static int mac80211_hwsim_sta_add(struct ieee80211_hw *hw, @@ -1166,45 +1312,96 @@ static void mac80211_hwsim_flush(struct ieee80211_hw *hw, bool drop) /* Not implemented, queues only on kernel side */ } -struct hw_scan_done { - struct delayed_work w; - struct ieee80211_hw *hw; -}; - -static void hw_scan_done(struct work_struct *work) +static void hw_scan_work(struct work_struct *work) { - struct hw_scan_done *hsd = - container_of(work, struct hw_scan_done, w.work); + struct mac80211_hwsim_data *hwsim = + container_of(work, struct mac80211_hwsim_data, hw_scan.work); + struct cfg80211_scan_request *req = hwsim->hw_scan_request; + int dwell, i; + + mutex_lock(&hwsim->mutex); + if (hwsim->scan_chan_idx >= req->n_channels) { + wiphy_debug(hwsim->hw->wiphy, "hw scan complete\n"); + ieee80211_scan_completed(hwsim->hw, false); + hwsim->hw_scan_request = NULL; + hwsim->hw_scan_vif = NULL; + hwsim->tmp_chan = NULL; + mutex_unlock(&hwsim->mutex); + return; + } - ieee80211_scan_completed(hsd->hw, false); - kfree(hsd); + wiphy_debug(hwsim->hw->wiphy, "hw scan %d MHz\n", + req->channels[hwsim->scan_chan_idx]->center_freq); + + hwsim->tmp_chan = req->channels[hwsim->scan_chan_idx]; + if (hwsim->tmp_chan->flags & IEEE80211_CHAN_PASSIVE_SCAN || + !req->n_ssids) { + dwell = 120; + } else { + dwell = 30; + /* send probes */ + for (i = 0; i < req->n_ssids; i++) { + struct sk_buff *probe; + + probe = ieee80211_probereq_get(hwsim->hw, + hwsim->hw_scan_vif, + req->ssids[i].ssid, + req->ssids[i].ssid_len, + req->ie, req->ie_len); + if (!probe) + continue; + local_bh_disable(); + mac80211_hwsim_tx_frame(hwsim->hw, probe, + hwsim->tmp_chan); + local_bh_enable(); + } + } + ieee80211_queue_delayed_work(hwsim->hw, &hwsim->hw_scan, + msecs_to_jiffies(dwell)); + hwsim->scan_chan_idx++; + mutex_unlock(&hwsim->mutex); } static int mac80211_hwsim_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct cfg80211_scan_request *req) { - struct hw_scan_done *hsd = kzalloc(sizeof(*hsd), GFP_KERNEL); - int i; - - if (!hsd) - return -ENOMEM; + struct mac80211_hwsim_data *hwsim = hw->priv; - hsd->hw = hw; - INIT_DELAYED_WORK(&hsd->w, hw_scan_done); + mutex_lock(&hwsim->mutex); + if (WARN_ON(hwsim->tmp_chan || hwsim->hw_scan_request)) { + mutex_unlock(&hwsim->mutex); + return -EBUSY; + } + hwsim->hw_scan_request = req; + hwsim->hw_scan_vif = vif; + hwsim->scan_chan_idx = 0; + mutex_unlock(&hwsim->mutex); - printk(KERN_DEBUG "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); + wiphy_debug(hw->wiphy, "hwsim hw_scan request\n"); - ieee80211_queue_delayed_work(hw, &hsd->w, 2 * HZ); + ieee80211_queue_delayed_work(hwsim->hw, &hwsim->hw_scan, 0); return 0; } +static void mac80211_hwsim_cancel_hw_scan(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct mac80211_hwsim_data *hwsim = hw->priv; + + wiphy_debug(hw->wiphy, "hwsim cancel_hw_scan\n"); + + cancel_delayed_work_sync(&hwsim->hw_scan); + + mutex_lock(&hwsim->mutex); + ieee80211_scan_completed(hwsim->hw, true); + hwsim->tmp_chan = NULL; + hwsim->hw_scan_request = NULL; + hwsim->hw_scan_vif = NULL; + mutex_unlock(&hwsim->mutex); +} + static void mac80211_hwsim_sw_scan(struct ieee80211_hw *hw) { struct mac80211_hwsim_data *hwsim = hw->priv; @@ -1235,6 +1432,111 @@ static void mac80211_hwsim_sw_scan_complete(struct ieee80211_hw *hw) mutex_unlock(&hwsim->mutex); } +static void hw_roc_done(struct work_struct *work) +{ + struct mac80211_hwsim_data *hwsim = + container_of(work, struct mac80211_hwsim_data, roc_done.work); + + mutex_lock(&hwsim->mutex); + ieee80211_remain_on_channel_expired(hwsim->hw); + hwsim->tmp_chan = NULL; + mutex_unlock(&hwsim->mutex); + + wiphy_debug(hwsim->hw->wiphy, "hwsim ROC expired\n"); +} + +static int mac80211_hwsim_roc(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_channel *chan, + int duration) +{ + struct mac80211_hwsim_data *hwsim = hw->priv; + + mutex_lock(&hwsim->mutex); + if (WARN_ON(hwsim->tmp_chan || hwsim->hw_scan_request)) { + mutex_unlock(&hwsim->mutex); + return -EBUSY; + } + + hwsim->tmp_chan = chan; + mutex_unlock(&hwsim->mutex); + + wiphy_debug(hw->wiphy, "hwsim ROC (%d MHz, %d ms)\n", + chan->center_freq, duration); + + ieee80211_ready_on_channel(hw); + + ieee80211_queue_delayed_work(hw, &hwsim->roc_done, + msecs_to_jiffies(duration)); + return 0; +} + +static int mac80211_hwsim_croc(struct ieee80211_hw *hw) +{ + struct mac80211_hwsim_data *hwsim = hw->priv; + + cancel_delayed_work_sync(&hwsim->roc_done); + + mutex_lock(&hwsim->mutex); + hwsim->tmp_chan = NULL; + mutex_unlock(&hwsim->mutex); + + wiphy_debug(hw->wiphy, "hwsim ROC canceled\n"); + + return 0; +} + +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 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 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); +} + +static void mac80211_hwsim_change_chanctx(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *ctx, + u32 changed) +{ + hwsim_check_chanctx_magic(ctx); + 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, + struct ieee80211_vif *vif, + struct ieee80211_chanctx_conf *ctx) +{ + hwsim_check_magic(vif); + hwsim_check_chanctx_magic(ctx); + + return 0; +} + +static void mac80211_hwsim_unassign_vif_chanctx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_chanctx_conf *ctx) +{ + hwsim_check_magic(vif); + hwsim_check_chanctx_magic(ctx); +} + static struct ieee80211_ops mac80211_hwsim_ops = { .tx = mac80211_hwsim_tx, @@ -1315,7 +1617,6 @@ static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif) struct hwsim_vif_priv *vp = (void *)vif->drv_priv; struct sk_buff *skb; struct ieee80211_pspoll *pspoll; - u32 _portid; if (!vp->assoc) return; @@ -1335,25 +1636,18 @@ static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif) memcpy(pspoll->bssid, vp->bssid, ETH_ALEN); memcpy(pspoll->ta, mac, ETH_ALEN); - /* wmediumd mode check */ - _portid = ACCESS_ONCE(wmediumd_portid); - - if (_portid) - return mac80211_hwsim_tx_frame_nl(data->hw, skb, _portid); - - if (!mac80211_hwsim_tx_frame_no_nl(data->hw, skb)) - printk(KERN_DEBUG "%s: PS-poll frame not ack'ed\n", __func__); - dev_kfree_skb(skb); + rcu_read_lock(); + mac80211_hwsim_tx_frame(data->hw, skb, + rcu_dereference(vif->chanctx_conf)->def.chan); + rcu_read_unlock(); } - static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac, struct ieee80211_vif *vif, int ps) { struct hwsim_vif_priv *vp = (void *)vif->drv_priv; struct sk_buff *skb; struct ieee80211_hdr *hdr; - u32 _portid; if (!vp->assoc) return; @@ -1374,15 +1668,10 @@ static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac, memcpy(hdr->addr2, mac, ETH_ALEN); memcpy(hdr->addr3, vp->bssid, ETH_ALEN); - /* wmediumd mode check */ - _portid = ACCESS_ONCE(wmediumd_portid); - - if (_portid) - return mac80211_hwsim_tx_frame_nl(data->hw, skb, _portid); - - if (!mac80211_hwsim_tx_frame_no_nl(data->hw, skb)) - printk(KERN_DEBUG "%s: nullfunc frame not ack'ed\n", __func__); - dev_kfree_skb(skb); + rcu_read_lock(); + mac80211_hwsim_tx_frame(data->hw, skb, + rcu_dereference(vif->chanctx_conf)->def.chan); + rcu_read_unlock(); } @@ -1423,14 +1712,17 @@ static int hwsim_fops_ps_write(void *dat, u64 val) if (val == PS_MANUAL_POLL) { ieee80211_iterate_active_interfaces(data->hw, + IEEE80211_IFACE_ITER_NORMAL, hwsim_send_ps_poll, data); data->ps_poll_pending = true; } else if (old_ps == PS_DISABLED && val != PS_DISABLED) { ieee80211_iterate_active_interfaces(data->hw, + IEEE80211_IFACE_ITER_NORMAL, hwsim_send_nullfunc_ps, data); } else if (old_ps != PS_DISABLED && val == PS_DISABLED) { ieee80211_iterate_active_interfaces(data->hw, + IEEE80211_IFACE_ITER_NORMAL, hwsim_send_nullfunc_no_ps, data); } @@ -1551,7 +1843,8 @@ static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2, (hwsim_flags & HWSIM_TX_STAT_ACK)) { if (skb->len >= 16) { hdr = (struct ieee80211_hdr *) skb->data; - mac80211_hwsim_monitor_ack(data2->hw, hdr->addr2); + mac80211_hwsim_monitor_ack(txi->rate_driver_data[0], + hdr->addr2); } txi->flags |= IEEE80211_TX_STAT_ACK; } @@ -1566,7 +1859,7 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2, struct genl_info *info) { - struct mac80211_hwsim_data *data2; + struct mac80211_hwsim_data *data2; struct ieee80211_rx_status rx_status; struct mac_address *dst; int frame_data_len; @@ -1574,9 +1867,9 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2, struct sk_buff *skb = NULL; if (!info->attrs[HWSIM_ATTR_ADDR_RECEIVER] || - !info->attrs[HWSIM_ATTR_FRAME] || - !info->attrs[HWSIM_ATTR_RX_RATE] || - !info->attrs[HWSIM_ATTR_SIGNAL]) + !info->attrs[HWSIM_ATTR_FRAME] || + !info->attrs[HWSIM_ATTR_RX_RATE] || + !info->attrs[HWSIM_ATTR_SIGNAL]) goto out; dst = (struct mac_address *)nla_data( @@ -1604,7 +1897,7 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2, /* check if radio is configured properly */ - if (data2->idle || !data2->started || !data2->channel) + if (data2->idle || !data2->started) goto out; /*A frame is received from user space*/ @@ -1688,6 +1981,11 @@ static struct notifier_block hwsim_netlink_notifier = { static int hwsim_init_netlink(void) { int rc; + + /* userspace test API hasn't been adjusted for multi-channel */ + if (channels > 1) + return 0; + printk(KERN_INFO "mac80211_hwsim: initializing netlink\n"); rc = genl_register_family_with_ops(&hwsim_genl_family, @@ -1710,6 +2008,10 @@ static void hwsim_exit_netlink(void) { int ret; + /* userspace test API hasn't been adjusted for multi-channel */ + if (channels > 1) + return; + printk(KERN_INFO "mac80211_hwsim: closing netlink\n"); /* unregister the notifier */ netlink_unregister_notifier(&hwsim_netlink_notifier); @@ -1732,7 +2034,7 @@ static const struct ieee80211_iface_limit hwsim_if_limits[] = { { .max = 1, .types = BIT(NL80211_IFTYPE_P2P_DEVICE) }, }; -static const struct ieee80211_iface_combination hwsim_if_comb = { +static struct ieee80211_iface_combination hwsim_if_comb = { .limits = hwsim_if_limits, .n_limits = ARRAY_SIZE(hwsim_if_limits), .max_interfaces = 2048, @@ -1750,10 +2052,30 @@ static int __init init_mac80211_hwsim(void) if (radios < 1 || radios > 100) return -EINVAL; - if (fake_hw_scan) { + if (channels < 1) + return -EINVAL; + + if (channels > 1) { + hwsim_if_comb.num_different_channels = channels; mac80211_hwsim_ops.hw_scan = mac80211_hwsim_hw_scan; + mac80211_hwsim_ops.cancel_hw_scan = + mac80211_hwsim_cancel_hw_scan; mac80211_hwsim_ops.sw_scan_start = NULL; mac80211_hwsim_ops.sw_scan_complete = NULL; + mac80211_hwsim_ops.remain_on_channel = + mac80211_hwsim_roc; + mac80211_hwsim_ops.cancel_remain_on_channel = + mac80211_hwsim_croc; + mac80211_hwsim_ops.add_chanctx = + mac80211_hwsim_add_chanctx; + mac80211_hwsim_ops.remove_chanctx = + mac80211_hwsim_remove_chanctx; + mac80211_hwsim_ops.change_chanctx = + mac80211_hwsim_change_chanctx; + mac80211_hwsim_ops.assign_vif_chanctx = + mac80211_hwsim_assign_vif_chanctx; + mac80211_hwsim_ops.unassign_vif_chanctx = + mac80211_hwsim_unassign_vif_chanctx; } spin_lock_init(&hwsim_radio_lock); @@ -1803,13 +2125,18 @@ static int __init init_mac80211_hwsim(void) hw->wiphy->iface_combinations = &hwsim_if_comb; hw->wiphy->n_iface_combinations = 1; - if (fake_hw_scan) { + if (channels > 1) { hw->wiphy->max_scan_ssids = 255; hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; + hw->wiphy->max_remain_on_channel_duration = 1000; } + INIT_DELAYED_WORK(&data->roc_done, hw_roc_done); + INIT_DELAYED_WORK(&data->hw_scan, hw_scan_work); + hw->channel_change_time = 1; - hw->queues = 4; + hw->queues = 5; + hw->offchannel_tx_hw_queue = 4; hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP) | @@ -1824,7 +2151,8 @@ static int __init init_mac80211_hwsim(void) IEEE80211_HW_SUPPORTS_STATIC_SMPS | IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS | IEEE80211_HW_AMPDU_AGGREGATION | - IEEE80211_HW_WANT_MONITOR_VIF; + IEEE80211_HW_WANT_MONITOR_VIF | + IEEE80211_HW_QUEUE_CONTROL; hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; @@ -1874,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/Kconfig b/drivers/net/wireless/mwifiex/Kconfig index 8e384fae3e68..b2e27723f801 100644 --- a/drivers/net/wireless/mwifiex/Kconfig +++ b/drivers/net/wireless/mwifiex/Kconfig @@ -1,7 +1,6 @@ config MWIFIEX tristate "Marvell WiFi-Ex Driver" depends on CFG80211 - select LIB80211 ---help--- This adds support for wireless adapters based on Marvell 802.11n chipsets. diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index e29505c90cce..a875499f8945 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)); @@ -324,6 +318,7 @@ mwifiex_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, */ static int mwifiex_cfg80211_set_tx_power(struct wiphy *wiphy, + struct wireless_dev *wdev, enum nl80211_tx_power_setting type, int mbm) { @@ -1296,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; @@ -1683,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 { @@ -1708,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; @@ -1728,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); @@ -1764,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); @@ -1947,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 c9528b3e9e9a..5f438e6c2155 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 dda588b35570..4dc8e2e9a889 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 db57dd430e92..1b3cfc821940 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 4fbbd611f630..5a1c1d0e5599 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 5b0d71969ba7..41aafc7454ed 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 c8b50c70a03d..95e3ab531c93 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 bbe1f3518e4b..63ac9f2d11ae 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/mwl8k.c b/drivers/net/wireless/mwl8k.c index 3db495090e55..434d508f9e3e 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -3686,7 +3686,8 @@ struct mwl8k_cmd_bastream { } __packed; static int -mwl8k_check_ba(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream) +mwl8k_check_ba(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream, + struct ieee80211_vif *vif) { struct mwl8k_cmd_bastream *cmd; int rc; @@ -3709,7 +3710,7 @@ mwl8k_check_ba(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream) cpu_to_le32(BASTREAM_FLAG_IMMEDIATE_TYPE) | cpu_to_le32(BASTREAM_FLAG_DIRECTION_UPSTREAM); - rc = mwl8k_post_cmd(hw, &cmd->header); + rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); kfree(cmd); @@ -3718,7 +3719,7 @@ mwl8k_check_ba(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream) static int mwl8k_create_ba(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream, - u8 buf_size) + u8 buf_size, struct ieee80211_vif *vif) { struct mwl8k_cmd_bastream *cmd; int rc; @@ -3752,7 +3753,7 @@ mwl8k_create_ba(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream, cpu_to_le32(BASTREAM_FLAG_IMMEDIATE_TYPE | BASTREAM_FLAG_DIRECTION_UPSTREAM); - rc = mwl8k_post_cmd(hw, &cmd->header); + rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); wiphy_debug(hw->wiphy, "Created a BA stream for %pM : tid %d\n", stream->sta->addr, stream->tid); @@ -5144,7 +5145,7 @@ mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, return -EBUSY; } - rc = mwl8k_check_ba(hw, stream); + rc = mwl8k_check_ba(hw, stream, vif); /* If HW restart is in progress mwl8k_post_cmd will * return -EBUSY. Avoid retrying mwl8k_check_ba in @@ -5184,7 +5185,7 @@ mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, BUG_ON(stream == NULL); BUG_ON(stream->state != AMPDU_STREAM_IN_PROGRESS); spin_unlock(&priv->stream_lock); - rc = mwl8k_create_ba(hw, stream, buf_size); + rc = mwl8k_create_ba(hw, stream, buf_size, vif); spin_lock(&priv->stream_lock); if (!rc) stream->state = AMPDU_STREAM_ACTIVE; @@ -5872,11 +5873,6 @@ err_disable_device: return rc; } -static void __devexit mwl8k_shutdown(struct pci_dev *pdev) -{ - printk(KERN_ERR "===>%s(%u)\n", __func__, __LINE__); -} - static void __devexit mwl8k_remove(struct pci_dev *pdev) { struct ieee80211_hw *hw = pci_get_drvdata(pdev); @@ -5930,7 +5926,6 @@ static struct pci_driver mwl8k_driver = { .id_table = mwl8k_pci_id_table, .probe = mwl8k_probe, .remove = __devexit_p(mwl8k_remove), - .shutdown = __devexit_p(mwl8k_shutdown), }; module_pci_driver(mwl8k_driver); diff --git a/drivers/net/wireless/orinoco/cfg.c b/drivers/net/wireless/orinoco/cfg.c index 7b751fba7e1f..d01edd2c50c5 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/eeprom.c b/drivers/net/wireless/p54/eeprom.c index 1ef1bfe6a9d7..d43e3740e45d 100644 --- a/drivers/net/wireless/p54/eeprom.c +++ b/drivers/net/wireless/p54/eeprom.c @@ -541,8 +541,9 @@ static int p54_parse_rssical(struct ieee80211_hw *dev, entries = (len - offset) / sizeof(struct pda_rssi_cal_ext_entry); - if ((len - offset) % sizeof(struct pda_rssi_cal_ext_entry) || - entries <= 0) { + if (len < offset || + (len - offset) % sizeof(struct pda_rssi_cal_ext_entry) || + entries == 0) { wiphy_err(dev->wiphy, "invalid rssi database.\n"); goto err_data; } diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c index b4390797d78c..810c343e4e30 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 5861e13a6fd8..12f0a34477f2 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 bd1f0cb56085..abe1d039be81 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -490,9 +490,12 @@ static int rndis_scan(struct wiphy *wiphy, static int rndis_set_wiphy_params(struct wiphy *wiphy, u32 changed); static int rndis_set_tx_power(struct wiphy *wiphy, + struct wireless_dev *wdev, enum nl80211_tx_power_setting type, int mbm); -static int rndis_get_tx_power(struct wiphy *wiphy, int *dbm); +static int rndis_get_tx_power(struct wiphy *wiphy, + struct wireless_dev *wdev, + int *dbm); static int rndis_connect(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_connect_params *sme); @@ -1903,6 +1906,7 @@ static int rndis_set_wiphy_params(struct wiphy *wiphy, u32 changed) } static int rndis_set_tx_power(struct wiphy *wiphy, + struct wireless_dev *wdev, enum nl80211_tx_power_setting type, int mbm) { @@ -1930,7 +1934,9 @@ static int rndis_set_tx_power(struct wiphy *wiphy, return -ENOTSUPP; } -static int rndis_get_tx_power(struct wiphy *wiphy, int *dbm) +static int rndis_get_tx_power(struct wiphy *wiphy, + struct wireless_dev *wdev, + int *dbm) { struct rndis_wlan_private *priv = wiphy_priv(wiphy); struct usbnet *usbdev = priv->usbdev; @@ -2287,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/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h index 6d67c3ede651..4db1088a847f 100644 --- a/drivers/net/wireless/rt2x00/rt2800.h +++ b/drivers/net/wireless/rt2x00/rt2800.h @@ -1993,8 +1993,10 @@ struct mac_iveiv_entry { */ #define RFCSR3_K FIELD8(0x0f) /* Bits [7-4] for RF3320 (RT3370/RT3390), on other chipsets reserved */ -#define RFCSR3_PA1_BIAS_CCK FIELD8(0x70); -#define RFCSR3_PA2_CASCODE_BIAS_CCKK FIELD8(0x80); +#define RFCSR3_PA1_BIAS_CCK FIELD8(0x70) +#define RFCSR3_PA2_CASCODE_BIAS_CCKK FIELD8(0x80) +/* Bits for RF3290/RF5360/RF5370/RF5372/RF5390/RF5392 */ +#define RFCSR3_VCOCAL_EN FIELD8(0x80) /* * FRCSR 5: diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 3bc206d06cd1..d4d0c3664eb2 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -2173,7 +2173,7 @@ static void rt2800_config_channel_rf53xx(struct rt2x00_dev *rt2x00dev, rt2800_rfcsr_write(rt2x00dev, 59, r59_nonbt_rev[idx]); } else if (rt2x00_rt(rt2x00dev, RT5390) || - rt2x00_rt(rt2x00dev, RT5392)) { + rt2x00_rt(rt2x00dev, RT5392)) { static const char r59_non_bt[] = {0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8d, 0x8a, 0x88, 0x88, 0x87, 0x87, 0x86}; @@ -2243,7 +2243,7 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, rt2800_rfcsr_write(rt2x00dev, 30, rfcsr); rt2800_rfcsr_read(rt2x00dev, 3, &rfcsr); - rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 1); + rt2x00_set_field8(&rfcsr, RFCSR3_VCOCAL_EN, 1); rt2800_rfcsr_write(rt2x00dev, 3, rfcsr); } @@ -2264,7 +2264,7 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, if (rf->channel <= 14) { if (!rt2x00_rt(rt2x00dev, RT5390) && - !rt2x00_rt(rt2x00dev, RT5392)) { + !rt2x00_rt(rt2x00dev, RT5392)) { if (test_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags)) { rt2800_bbp_write(rt2x00dev, 82, 0x62); @@ -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; /* @@ -2804,7 +2804,7 @@ void rt2800_vco_calibration(struct rt2x00_dev *rt2x00dev) case RF5390: case RF5392: rt2800_rfcsr_read(rt2x00dev, 3, &rfcsr); - rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 1); + rt2x00_set_field8(&rfcsr, RFCSR3_VCOCAL_EN, 1); rt2800_rfcsr_write(rt2x00dev, 3, rfcsr); break; default: @@ -3592,8 +3592,8 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev) if (rt2x00_rt_rev(rt2x00dev, RT2860, REV_RT2860D)) rt2800_bbp_write(rt2x00dev, 84, 0x19); else if (rt2x00_rt(rt2x00dev, RT3290) || - rt2x00_rt(rt2x00dev, RT5390) || - rt2x00_rt(rt2x00dev, RT5392)) + rt2x00_rt(rt2x00dev, RT5390) || + rt2x00_rt(rt2x00dev, RT5392)) rt2800_bbp_write(rt2x00dev, 84, 0x9a); else rt2800_bbp_write(rt2x00dev, 84, 0x99); @@ -3652,7 +3652,7 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev) else if (rt2x00_rt(rt2x00dev, RT3352)) rt2800_bbp_write(rt2x00dev, 105, 0x34); else if (rt2x00_rt(rt2x00dev, RT5390) || - rt2x00_rt(rt2x00dev, RT5392)) + rt2x00_rt(rt2x00dev, RT5392)) rt2800_bbp_write(rt2x00dev, 105, 0x3c); else rt2800_bbp_write(rt2x00dev, 105, 0x05); @@ -3746,7 +3746,7 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev) } if (rt2x00_rt(rt2x00dev, RT5390) || - rt2x00_rt(rt2x00dev, RT5392)) { + rt2x00_rt(rt2x00dev, RT5392)) { int ant, div_mode; rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom); @@ -4220,66 +4220,66 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) rt2800_rfcsr_write(rt2x00dev, 61, 0xdd); rt2800_rfcsr_write(rt2x00dev, 62, 0x00); rt2800_rfcsr_write(rt2x00dev, 63, 0x00); - } else if (rt2x00_rt(rt2x00dev, RT5392)) { - rt2800_rfcsr_write(rt2x00dev, 1, 0x17); - rt2800_rfcsr_write(rt2x00dev, 2, 0x80); - rt2800_rfcsr_write(rt2x00dev, 3, 0x88); - rt2800_rfcsr_write(rt2x00dev, 5, 0x10); - rt2800_rfcsr_write(rt2x00dev, 6, 0xe0); - rt2800_rfcsr_write(rt2x00dev, 7, 0x00); - rt2800_rfcsr_write(rt2x00dev, 10, 0x53); - rt2800_rfcsr_write(rt2x00dev, 11, 0x4a); - rt2800_rfcsr_write(rt2x00dev, 12, 0x46); - rt2800_rfcsr_write(rt2x00dev, 13, 0x9f); - rt2800_rfcsr_write(rt2x00dev, 14, 0x00); - rt2800_rfcsr_write(rt2x00dev, 15, 0x00); - rt2800_rfcsr_write(rt2x00dev, 16, 0x00); - rt2800_rfcsr_write(rt2x00dev, 18, 0x03); - rt2800_rfcsr_write(rt2x00dev, 19, 0x4d); - rt2800_rfcsr_write(rt2x00dev, 20, 0x00); - rt2800_rfcsr_write(rt2x00dev, 21, 0x8d); - rt2800_rfcsr_write(rt2x00dev, 22, 0x20); - rt2800_rfcsr_write(rt2x00dev, 23, 0x0b); - rt2800_rfcsr_write(rt2x00dev, 24, 0x44); - rt2800_rfcsr_write(rt2x00dev, 25, 0x80); - rt2800_rfcsr_write(rt2x00dev, 26, 0x82); - rt2800_rfcsr_write(rt2x00dev, 27, 0x09); - rt2800_rfcsr_write(rt2x00dev, 28, 0x00); - rt2800_rfcsr_write(rt2x00dev, 29, 0x10); - rt2800_rfcsr_write(rt2x00dev, 30, 0x10); - rt2800_rfcsr_write(rt2x00dev, 31, 0x80); - rt2800_rfcsr_write(rt2x00dev, 32, 0x20); - rt2800_rfcsr_write(rt2x00dev, 33, 0xC0); - rt2800_rfcsr_write(rt2x00dev, 34, 0x07); - rt2800_rfcsr_write(rt2x00dev, 35, 0x12); - rt2800_rfcsr_write(rt2x00dev, 36, 0x00); - rt2800_rfcsr_write(rt2x00dev, 37, 0x08); - rt2800_rfcsr_write(rt2x00dev, 38, 0x89); - rt2800_rfcsr_write(rt2x00dev, 39, 0x1b); - rt2800_rfcsr_write(rt2x00dev, 40, 0x0f); - rt2800_rfcsr_write(rt2x00dev, 41, 0xbb); - rt2800_rfcsr_write(rt2x00dev, 42, 0xd5); - rt2800_rfcsr_write(rt2x00dev, 43, 0x9b); - rt2800_rfcsr_write(rt2x00dev, 44, 0x0e); - rt2800_rfcsr_write(rt2x00dev, 45, 0xa2); - rt2800_rfcsr_write(rt2x00dev, 46, 0x73); - rt2800_rfcsr_write(rt2x00dev, 47, 0x0c); - rt2800_rfcsr_write(rt2x00dev, 48, 0x10); - rt2800_rfcsr_write(rt2x00dev, 49, 0x94); - rt2800_rfcsr_write(rt2x00dev, 50, 0x94); - rt2800_rfcsr_write(rt2x00dev, 51, 0x3a); - rt2800_rfcsr_write(rt2x00dev, 52, 0x48); - rt2800_rfcsr_write(rt2x00dev, 53, 0x44); - rt2800_rfcsr_write(rt2x00dev, 54, 0x38); - rt2800_rfcsr_write(rt2x00dev, 55, 0x43); - rt2800_rfcsr_write(rt2x00dev, 56, 0xa1); - rt2800_rfcsr_write(rt2x00dev, 57, 0x00); - rt2800_rfcsr_write(rt2x00dev, 58, 0x39); - rt2800_rfcsr_write(rt2x00dev, 59, 0x07); - rt2800_rfcsr_write(rt2x00dev, 60, 0x45); - rt2800_rfcsr_write(rt2x00dev, 61, 0x91); - rt2800_rfcsr_write(rt2x00dev, 62, 0x39); - rt2800_rfcsr_write(rt2x00dev, 63, 0x07); + } else if (rt2x00_rt(rt2x00dev, RT5392)) { + rt2800_rfcsr_write(rt2x00dev, 1, 0x17); + rt2800_rfcsr_write(rt2x00dev, 2, 0x80); + rt2800_rfcsr_write(rt2x00dev, 3, 0x88); + rt2800_rfcsr_write(rt2x00dev, 5, 0x10); + rt2800_rfcsr_write(rt2x00dev, 6, 0xe0); + rt2800_rfcsr_write(rt2x00dev, 7, 0x00); + rt2800_rfcsr_write(rt2x00dev, 10, 0x53); + rt2800_rfcsr_write(rt2x00dev, 11, 0x4a); + rt2800_rfcsr_write(rt2x00dev, 12, 0x46); + rt2800_rfcsr_write(rt2x00dev, 13, 0x9f); + rt2800_rfcsr_write(rt2x00dev, 14, 0x00); + rt2800_rfcsr_write(rt2x00dev, 15, 0x00); + rt2800_rfcsr_write(rt2x00dev, 16, 0x00); + rt2800_rfcsr_write(rt2x00dev, 18, 0x03); + rt2800_rfcsr_write(rt2x00dev, 19, 0x4d); + rt2800_rfcsr_write(rt2x00dev, 20, 0x00); + rt2800_rfcsr_write(rt2x00dev, 21, 0x8d); + rt2800_rfcsr_write(rt2x00dev, 22, 0x20); + rt2800_rfcsr_write(rt2x00dev, 23, 0x0b); + rt2800_rfcsr_write(rt2x00dev, 24, 0x44); + rt2800_rfcsr_write(rt2x00dev, 25, 0x80); + rt2800_rfcsr_write(rt2x00dev, 26, 0x82); + rt2800_rfcsr_write(rt2x00dev, 27, 0x09); + rt2800_rfcsr_write(rt2x00dev, 28, 0x00); + rt2800_rfcsr_write(rt2x00dev, 29, 0x10); + rt2800_rfcsr_write(rt2x00dev, 30, 0x10); + rt2800_rfcsr_write(rt2x00dev, 31, 0x80); + rt2800_rfcsr_write(rt2x00dev, 32, 0x20); + rt2800_rfcsr_write(rt2x00dev, 33, 0xC0); + rt2800_rfcsr_write(rt2x00dev, 34, 0x07); + rt2800_rfcsr_write(rt2x00dev, 35, 0x12); + rt2800_rfcsr_write(rt2x00dev, 36, 0x00); + rt2800_rfcsr_write(rt2x00dev, 37, 0x08); + rt2800_rfcsr_write(rt2x00dev, 38, 0x89); + rt2800_rfcsr_write(rt2x00dev, 39, 0x1b); + rt2800_rfcsr_write(rt2x00dev, 40, 0x0f); + rt2800_rfcsr_write(rt2x00dev, 41, 0xbb); + rt2800_rfcsr_write(rt2x00dev, 42, 0xd5); + rt2800_rfcsr_write(rt2x00dev, 43, 0x9b); + rt2800_rfcsr_write(rt2x00dev, 44, 0x0e); + rt2800_rfcsr_write(rt2x00dev, 45, 0xa2); + rt2800_rfcsr_write(rt2x00dev, 46, 0x73); + rt2800_rfcsr_write(rt2x00dev, 47, 0x0c); + rt2800_rfcsr_write(rt2x00dev, 48, 0x10); + rt2800_rfcsr_write(rt2x00dev, 49, 0x94); + rt2800_rfcsr_write(rt2x00dev, 50, 0x94); + rt2800_rfcsr_write(rt2x00dev, 51, 0x3a); + rt2800_rfcsr_write(rt2x00dev, 52, 0x48); + rt2800_rfcsr_write(rt2x00dev, 53, 0x44); + rt2800_rfcsr_write(rt2x00dev, 54, 0x38); + rt2800_rfcsr_write(rt2x00dev, 55, 0x43); + rt2800_rfcsr_write(rt2x00dev, 56, 0xa1); + rt2800_rfcsr_write(rt2x00dev, 57, 0x00); + rt2800_rfcsr_write(rt2x00dev, 58, 0x39); + rt2800_rfcsr_write(rt2x00dev, 59, 0x07); + rt2800_rfcsr_write(rt2x00dev, 60, 0x45); + rt2800_rfcsr_write(rt2x00dev, 61, 0x91); + rt2800_rfcsr_write(rt2x00dev, 62, 0x39); + rt2800_rfcsr_write(rt2x00dev, 63, 0x07); } if (rt2x00_rt_rev_lt(rt2x00dev, RT3070, REV_RT3070F)) { @@ -4356,7 +4356,7 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) rt2800_bbp_read(rt2x00dev, 26, &drv_data->bbp26); if (!rt2x00_rt(rt2x00dev, RT5390) && - !rt2x00_rt(rt2x00dev, RT5392)) { + !rt2x00_rt(rt2x00dev, RT5392)) { /* * Set back to initial state */ @@ -4385,7 +4385,7 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) rt2800_register_write(rt2x00dev, OPT_14_CSR, reg); if (!rt2x00_rt(rt2x00dev, RT5390) && - !rt2x00_rt(rt2x00dev, RT5392)) { + !rt2x00_rt(rt2x00dev, RT5392)) { rt2800_rfcsr_read(rt2x00dev, 17, &rfcsr); rt2x00_set_field8(&rfcsr, RFCSR17_TX_LO1_EN, 0); if (rt2x00_rt(rt2x00dev, RT3070) || @@ -4457,7 +4457,7 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) } if (rt2x00_rt(rt2x00dev, RT5390) || - rt2x00_rt(rt2x00dev, RT5392)) { + rt2x00_rt(rt2x00dev, RT5392)) { rt2800_rfcsr_read(rt2x00dev, 38, &rfcsr); rt2x00_set_field8(&rfcsr, RFCSR38_RX_LO1_EN, 0); rt2800_rfcsr_write(rt2x00dev, 38, rfcsr); diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 69097d1faeb6..66b3b17b16d2 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -157,6 +157,7 @@ static void rt2x00lib_intf_scheduled(struct work_struct *work) * requested configurations. */ ieee80211_iterate_active_interfaces(rt2x00dev->hw, + IEEE80211_IFACE_ITER_RESUME_ALL, rt2x00lib_intf_scheduled_iter, rt2x00dev); } @@ -225,9 +226,9 @@ void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev) return; /* send buffered bc/mc frames out for every bssid */ - ieee80211_iterate_active_interfaces_atomic(rt2x00dev->hw, - rt2x00lib_bc_buffer_iter, - rt2x00dev); + ieee80211_iterate_active_interfaces_atomic( + rt2x00dev->hw, IEEE80211_IFACE_ITER_RESUME_ALL, + rt2x00lib_bc_buffer_iter, rt2x00dev); /* * Devices with pre tbtt interrupt don't need to update the beacon * here as they will fetch the next beacon directly prior to @@ -237,9 +238,9 @@ void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev) return; /* fetch next beacon */ - ieee80211_iterate_active_interfaces_atomic(rt2x00dev->hw, - rt2x00lib_beaconupdate_iter, - rt2x00dev); + ieee80211_iterate_active_interfaces_atomic( + rt2x00dev->hw, IEEE80211_IFACE_ITER_RESUME_ALL, + rt2x00lib_beaconupdate_iter, rt2x00dev); } EXPORT_SYMBOL_GPL(rt2x00lib_beacondone); @@ -249,9 +250,9 @@ void rt2x00lib_pretbtt(struct rt2x00_dev *rt2x00dev) return; /* fetch next beacon */ - ieee80211_iterate_active_interfaces_atomic(rt2x00dev->hw, - rt2x00lib_beaconupdate_iter, - rt2x00dev); + ieee80211_iterate_active_interfaces_atomic( + rt2x00dev->hw, IEEE80211_IFACE_ITER_RESUME_ALL, + rt2x00lib_beaconupdate_iter, rt2x00dev); } EXPORT_SYMBOL_GPL(rt2x00lib_pretbtt); @@ -1182,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/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 98a9e48f8e4a..ed7a1bb3f245 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -424,9 +424,9 @@ int rt2x00mac_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) return 0; - ieee80211_iterate_active_interfaces_atomic(rt2x00dev->hw, - rt2x00mac_set_tim_iter, - rt2x00dev); + ieee80211_iterate_active_interfaces_atomic( + rt2x00dev->hw, IEEE80211_IFACE_ITER_RESUME_ALL, + rt2x00mac_set_tim_iter, rt2x00dev); /* queue work to upodate the beacon template */ ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->intf_work); diff --git a/drivers/net/wireless/rtl818x/rtl8180/dev.c b/drivers/net/wireless/rtl818x/rtl8180/dev.c index 021d83e1b1d3..b4218a5f2066 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 7811b6315973..52e6bebcf089 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/cam.c b/drivers/net/wireless/rtlwifi/cam.c index ca69e35e50f1..0e510f73041a 100644 --- a/drivers/net/wireless/rtlwifi/cam.c +++ b/drivers/net/wireless/rtlwifi/cam.c @@ -337,7 +337,7 @@ void rtl_cam_del_entry(struct ieee80211_hw *hw, u8 *sta_addr) if (((bitmap & BIT(0)) == BIT(0)) && (memcmp(addr, sta_addr, ETH_ALEN) == 0)) { /* Remove from HW Security CAM */ - memset(rtlpriv->sec.hwsec_cam_sta_addr[i], 0, ETH_ALEN); + eth_zero_addr(rtlpriv->sec.hwsec_cam_sta_addr[i]); rtlpriv->sec.hwsec_cam_bitmap &= ~(BIT(0) << i); RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, "del CAM entry %d\n", i); diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c index a7c0e52869ba..be33aa14c8af 100644 --- a/drivers/net/wireless/rtlwifi/core.c +++ b/drivers/net/wireless/rtlwifi/core.c @@ -962,7 +962,6 @@ static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, int err = 0; u8 mac_addr[ETH_ALEN]; u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - u8 zero_addr[ETH_ALEN] = { 0 }; if (rtlpriv->cfg->mod_params->sw_crypto || rtlpriv->sec.use_sw_sec) { RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, @@ -1057,7 +1056,7 @@ static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, memcpy(rtlpriv->sec.key_buf[key_idx], key->key, key->keylen); rtlpriv->sec.key_len[key_idx] = key->keylen; - memcpy(mac_addr, zero_addr, ETH_ALEN); + eth_zero_addr(mac_addr); } else if (group_key) { /* group key */ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "set group key\n"); @@ -1108,7 +1107,7 @@ static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, } memset(rtlpriv->sec.key_buf[key_idx], 0, key->keylen); rtlpriv->sec.key_len[key_idx] = 0; - memcpy(mac_addr, zero_addr, ETH_ALEN); + eth_zero_addr(mac_addr); /* *mac80211 will delete entrys one by one, *so don't use rtl_cam_reset_all_entry diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c index f38e30a947bc..086140cba026 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 f71b12aa8cb4..7ea50a32bafb 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 60451eea4d82..49f663bd93ff 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 d7e1f0a7e48f..173424756149 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 9970c2b1b199..b7e6607e6b6d 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 6e66f04c363f..b6222eedb835 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 480862c07f92..e17f670d5c8e 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 35bb9da6196a..f9f3861046c1 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 20afec62ce05..2d255e02d795 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 bf79a52c8a52..e551fe5f9ccd 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 1d72779434ba..28526a7361f5 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 1886c2644a26..a8e068c76e47 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 ad4b4803482d..45c3443fccc8 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 1ad51e711a32..0e9f6ebf078a 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 0afdc240f2fd..18b0bc51766b 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 9719d541e380..87331d826d73 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 6af35265c900..23289d49dd31 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 4dfd533a81c1..a163b0900b77 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -687,7 +687,7 @@ static void wl12xx_get_vif_count(struct ieee80211_hw *hw, memset(data, 0, sizeof(*data)); data->cur_vif = cur_vif; - ieee80211_iterate_active_interfaces(hw, + ieee80211_iterate_active_interfaces(hw, IEEE80211_IFACE_ITER_RESUME_ALL, wl12xx_vif_count_iter, data); } @@ -2649,7 +2649,7 @@ static int wlcore_set_assoc(struct wl1271 *wl, struct wl12xx_vif *wlvif, int ret; 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; wlvif->wmm_enabled = bss_conf->qos; @@ -3857,7 +3857,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) { @@ -4121,7 +4121,7 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, if (sta_exists && (changed & BSS_CHANGED_HT)) { bool enabled = - 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, @@ -4234,8 +4234,8 @@ static int wlcore_op_add_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *ctx) { wl1271_debug(DEBUG_MAC80211, "mac80211 add chanctx %d (type %d)", - ieee80211_frequency_to_channel(ctx->channel->center_freq), - ctx->channel_type); + ieee80211_frequency_to_channel(ctx->def.chan->center_freq), + cfg80211_get_chandef_type(&ctx->def)); return 0; } @@ -4243,8 +4243,8 @@ static void wlcore_op_remove_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *ctx) { wl1271_debug(DEBUG_MAC80211, "mac80211 remove chanctx %d (type %d)", - ieee80211_frequency_to_channel(ctx->channel->center_freq), - ctx->channel_type); + ieee80211_frequency_to_channel(ctx->def.chan->center_freq), + cfg80211_get_chandef_type(&ctx->def)); } static void wlcore_op_change_chanctx(struct ieee80211_hw *hw, @@ -4253,8 +4253,8 @@ static void wlcore_op_change_chanctx(struct ieee80211_hw *hw, { wl1271_debug(DEBUG_MAC80211, "mac80211 change chanctx %d (type %d) changed 0x%x", - ieee80211_frequency_to_channel(ctx->channel->center_freq), - ctx->channel_type, changed); + ieee80211_frequency_to_channel(ctx->def.chan->center_freq), + cfg80211_get_chandef_type(&ctx->def), changed); } static int wlcore_op_assign_vif_chanctx(struct ieee80211_hw *hw, @@ -4264,17 +4264,17 @@ static int wlcore_op_assign_vif_chanctx(struct ieee80211_hw *hw, struct wl1271 *wl = hw->priv; struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); int channel = ieee80211_frequency_to_channel( - ctx->channel->center_freq); + ctx->def.chan->center_freq); wl1271_debug(DEBUG_MAC80211, "mac80211 assign chanctx (role %d) %d (type %d)", - wlvif->role_id, channel, ctx->channel_type); + wlvif->role_id, channel, cfg80211_get_chandef_type(&ctx->def)); mutex_lock(&wl->mutex); - wlvif->band = ctx->channel->band; + wlvif->band = ctx->def.chan->band; wlvif->channel = channel; - wlvif->channel_type = ctx->channel_type; + wlvif->channel_type = cfg80211_get_chandef_type(&ctx->def); /* update default rates according to the band */ wl1271_set_band_rate(wl, wlvif); @@ -4294,8 +4294,8 @@ static void wlcore_op_unassign_vif_chanctx(struct ieee80211_hw *hw, wl1271_debug(DEBUG_MAC80211, "mac80211 unassign chanctx (role %d) %d (type %d)", wlvif->role_id, - ieee80211_frequency_to_channel(ctx->channel->center_freq), - ctx->channel_type); + ieee80211_frequency_to_channel(ctx->def.chan->center_freq), + cfg80211_get_chandef_type(&ctx->def)); wl1271_tx_flush(wl); } @@ -4872,7 +4872,6 @@ static void wlcore_op_flush(struct ieee80211_hw *hw, bool drop) static int wlcore_op_remain_on_channel(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type, int duration) { struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index 18e279d3e836..ada681b01a17 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 fb430d882352..7da9071b68b6 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 b918ba922306..5bd05b136d22 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 fd15d9829705..93b1e091b1e9 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 85764a900731..f9c5a787d350 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" @@ -905,6 +922,38 @@ struct ieee80211_tdls_data { } u; } __packed; +/* + * Peer-to-Peer IE attribute related definitions. + */ +/** + * enum ieee80211_p2p_attr_id - identifies type of peer-to-peer attribute. + */ +enum ieee80211_p2p_attr_id { + IEEE80211_P2P_ATTR_STATUS = 0, + IEEE80211_P2P_ATTR_MINOR_REASON, + IEEE80211_P2P_ATTR_CAPABILITY, + IEEE80211_P2P_ATTR_DEVICE_ID, + IEEE80211_P2P_ATTR_GO_INTENT, + IEEE80211_P2P_ATTR_GO_CONFIG_TIMEOUT, + IEEE80211_P2P_ATTR_LISTEN_CHANNEL, + IEEE80211_P2P_ATTR_GROUP_BSSID, + IEEE80211_P2P_ATTR_EXT_LISTEN_TIMING, + IEEE80211_P2P_ATTR_INTENDED_IFACE_ADDR, + IEEE80211_P2P_ATTR_MANAGABILITY, + IEEE80211_P2P_ATTR_CHANNEL_LIST, + IEEE80211_P2P_ATTR_ABSENCE_NOTICE, + IEEE80211_P2P_ATTR_DEVICE_INFO, + IEEE80211_P2P_ATTR_GROUP_INFO, + IEEE80211_P2P_ATTR_GROUP_ID, + IEEE80211_P2P_ATTR_INTERFACE, + IEEE80211_P2P_ATTR_OPER_CHANNEL, + IEEE80211_P2P_ATTR_INVITE_FLAGS, + /* 19 - 220: Reserved */ + IEEE80211_P2P_ATTR_VENDOR_SPECIFIC = 221, + + IEEE80211_P2P_ATTR_MAX +}; + /** * struct ieee80211_bar - HT Block Ack Request * @@ -1114,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; @@ -1128,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 9890bbaf4328..000000000000 --- 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 000000000000..713bfd703342 --- /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 91161f0aa22b..2604efa7dc4d 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/linux/ssb/ssb_regs.h b/include/linux/ssb/ssb_regs.h index a0525019e1d1..6ecfa02ddbac 100644 --- a/include/linux/ssb/ssb_regs.h +++ b/include/linux/ssb/ssb_regs.h @@ -485,7 +485,7 @@ #define SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP_SHIFT 4 #define SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL 0x0020 #define SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL_SHIFT 5 -#define SSB_SPROM8_TEMPDELTA 0x00BA +#define SSB_SPROM8_TEMPDELTA 0x00BC #define SSB_SPROM8_TEMPDELTA_PHYCAL 0x00ff #define SSB_SPROM8_TEMPDELTA_PHYCAL_SHIFT 0 #define SSB_SPROM8_TEMPDELTA_PERIOD 0x0f00 diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 6c414f4302fe..45eee08157bb 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -154,7 +154,7 @@ enum { #define HCI_DISCONN_TIMEOUT msecs_to_jiffies(2000) /* 2 seconds */ #define HCI_PAIRING_TIMEOUT msecs_to_jiffies(60000) /* 60 seconds */ #define HCI_INIT_TIMEOUT msecs_to_jiffies(10000) /* 10 seconds */ -#define HCI_CMD_TIMEOUT msecs_to_jiffies(1000) /* 1 second */ +#define HCI_CMD_TIMEOUT msecs_to_jiffies(2000) /* 2 seconds */ #define HCI_ACL_TX_TIMEOUT msecs_to_jiffies(45000) /* 45 seconds */ #define HCI_AUTO_OFF_TIMEOUT msecs_to_jiffies(2000) /* 2 seconds */ @@ -319,6 +319,9 @@ enum { #define HCI_FLOW_CTL_MODE_PACKET_BASED 0x00 #define HCI_FLOW_CTL_MODE_BLOCK_BASED 0x01 +/* The core spec defines 127 as the "not available" value */ +#define HCI_TX_POWER_INVALID 127 + /* Extended Inquiry Response field types */ #define EIR_FLAGS 0x01 /* flags */ #define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */ @@ -335,6 +338,13 @@ enum { #define EIR_SSP_RAND_R 0x0F /* Simple Pairing Randomizer R */ #define EIR_DEVICE_ID 0x10 /* device ID */ +/* Low Energy Advertising Flags */ +#define LE_AD_LIMITED 0x01 /* Limited Discoverable */ +#define LE_AD_GENERAL 0x02 /* General Discoverable */ +#define LE_AD_NO_BREDR 0x04 /* BR/EDR not supported */ +#define LE_AD_SIM_LE_BREDR_CTRL 0x08 /* Simultaneous LE & BR/EDR Controller */ +#define LE_AD_SIM_LE_BREDR_HOST 0x10 /* Simultaneous LE & BR/EDR Host */ + /* ----- HCI Commands ---- */ #define HCI_OP_NOP 0x0000 @@ -939,6 +949,16 @@ struct hci_rp_le_read_adv_tx_power { __s8 tx_power; } __packed; +#define HCI_MAX_AD_LENGTH 31 + +#define HCI_OP_LE_SET_ADV_DATA 0x2008 +struct hci_cp_le_set_adv_data { + __u8 length; + __u8 data[HCI_MAX_AD_LENGTH]; +} __packed; + +#define HCI_OP_LE_SET_ADV_ENABLE 0x200a + #define HCI_OP_LE_SET_SCAN_PARAM 0x200b struct hci_cp_le_set_scan_param { __u8 type; diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index ce6dbeb6dfb6..014a2eaa5389 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -279,6 +279,8 @@ struct hci_dev { struct le_scan_params le_scan_params; __s8 adv_tx_power; + __u8 adv_data[HCI_MAX_AD_LENGTH]; + __u8 adv_data_len; int (*open)(struct hci_dev *hdev); int (*close)(struct hci_dev *hdev); @@ -374,7 +376,7 @@ extern int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt); extern int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags); -extern int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr); +extern int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags); extern void sco_connect_cfm(struct hci_conn *hcon, __u8 status); extern void sco_disconn_cfm(struct hci_conn *hcon, __u8 reason); extern int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb); @@ -575,6 +577,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst); int hci_conn_del(struct hci_conn *conn); void hci_conn_hash_flush(struct hci_dev *hdev); void hci_conn_check_pending(struct hci_dev *hdev); +void hci_conn_accept(struct hci_conn *conn, int mask); struct hci_chan *hci_chan_create(struct hci_conn *conn); void hci_chan_del(struct hci_chan *chan); @@ -734,6 +737,8 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash, u8 *randomizer); int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr); +int hci_update_ad(struct hci_dev *hdev); + void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb); int hci_recv_frame(struct sk_buff *skb); @@ -762,7 +767,7 @@ void hci_conn_del_sysfs(struct hci_conn *conn); #define lmp_sniffsubr_capable(dev) ((dev)->features[5] & LMP_SNIFF_SUBR) #define lmp_pause_enc_capable(dev) ((dev)->features[5] & LMP_PAUSE_ENC) #define lmp_ext_inq_capable(dev) ((dev)->features[6] & LMP_EXT_INQ) -#define lmp_le_br_capable(dev) ((dev)->features[6] & LMP_SIMUL_LE_BR) +#define lmp_le_br_capable(dev) !!((dev)->features[6] & LMP_SIMUL_LE_BR) #define lmp_ssp_capable(dev) ((dev)->features[6] & LMP_SIMPLE_PAIR) #define lmp_no_flush_capable(dev) ((dev)->features[6] & LMP_NO_FLUSH) #define lmp_lsto_capable(dev) ((dev)->features[7] & LMP_LSTO) @@ -771,12 +776,30 @@ void hci_conn_del_sysfs(struct hci_conn *conn); /* ----- Extended LMP capabilities ----- */ #define lmp_host_ssp_capable(dev) ((dev)->host_features[0] & LMP_HOST_SSP) -#define lmp_host_le_capable(dev) ((dev)->host_features[0] & LMP_HOST_LE) -#define lmp_host_le_br_capable(dev) ((dev)->host_features[0] & LMP_HOST_LE_BREDR) +#define lmp_host_le_capable(dev) !!((dev)->host_features[0] & LMP_HOST_LE) +#define lmp_host_le_br_capable(dev) !!((dev)->host_features[0] & LMP_HOST_LE_BREDR) + +/* returns true if at least one AMP active */ +static inline bool hci_amp_capable(void) +{ + struct hci_dev *hdev; + bool ret = false; + + read_lock(&hci_dev_list_lock); + list_for_each_entry(hdev, &hci_dev_list, list) + if (hdev->amp_type == HCI_AMP && + test_bit(HCI_UP, &hdev->flags)) + ret = true; + read_unlock(&hci_dev_list_lock); + + return ret; +} /* ----- HCI protocols ----- */ +#define HCI_PROTO_DEFER 0x01 + static inline int hci_proto_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, - __u8 type) + __u8 type, __u8 *flags) { switch (type) { case ACL_LINK: @@ -784,7 +807,7 @@ static inline int hci_proto_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, case SCO_LINK: case ESCO_LINK: - return sco_connect_ind(hdev, bdaddr); + return sco_connect_ind(hdev, bdaddr, flags); default: BT_ERR("unknown link type %d", type); diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index d65db459c843..7588ef44ebaf 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -611,7 +611,7 @@ enum { CONF_MTU_DONE, CONF_MODE_DONE, CONF_CONNECT_PEND, - CONF_NO_FCS_RECV, + CONF_RECV_NO_FCS, CONF_STATE2_DEVICE, CONF_EWS_RECV, CONF_LOC_CONF_PEND, @@ -811,6 +811,6 @@ void l2cap_send_conn_req(struct l2cap_chan *chan); void l2cap_move_start(struct l2cap_chan *chan); void l2cap_logical_cfm(struct l2cap_chan *chan, struct hci_chan *hchan, u8 status); -void l2cap_physical_cfm(struct l2cap_chan *chan, int result); +void __l2cap_physical_cfm(struct l2cap_chan *chan, int result); #endif /* __L2CAP_H */ diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index c6964572890f..e78db2cf3d1b 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; @@ -1545,13 +1631,19 @@ struct cfg80211_gtk_rekey_data { * to a merge. * @leave_ibss: Leave the IBSS. * + * @set_mcast_rate: Set the specified multicast rate (only if vif is in ADHOC or + * MESH mode) + * * @set_wiphy_params: Notify that wiphy parameters have changed; * @changed bitfield (see &enum wiphy_params_flags) describes which values * have changed. The actual parameter values are available in * struct wiphy. If returning an error, no value should be changed. * * @set_tx_power: set the transmit power according to the parameters, - * the power passed is in mBm, to get dBm use MBM_TO_DBM(). + * the power passed is in mBm, to get dBm use MBM_TO_DBM(). The + * wdev may be %NULL if power was set for the wiphy, and will + * always be %NULL unless the driver supports per-vif TX power + * (as advertised by the nl80211 feature flag.) * @get_tx_power: store the current TX power into the dbm variable; * return 0 if successful * @@ -1722,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); @@ -1746,11 +1837,15 @@ struct cfg80211_ops { struct cfg80211_ibss_params *params); int (*leave_ibss)(struct wiphy *wiphy, struct net_device *dev); + int (*set_mcast_rate)(struct wiphy *wiphy, struct net_device *dev, + int rate[IEEE80211_NUM_BANDS]); + int (*set_wiphy_params)(struct wiphy *wiphy, u32 changed); - int (*set_tx_power)(struct wiphy *wiphy, + int (*set_tx_power)(struct wiphy *wiphy, struct wireless_dev *wdev, enum nl80211_tx_power_setting type, int mbm); - int (*get_tx_power)(struct wiphy *wiphy, int *dbm); + int (*get_tx_power)(struct wiphy *wiphy, struct wireless_dev *wdev, + int *dbm); int (*set_wds_peer)(struct wiphy *wiphy, struct net_device *dev, const u8 *addr); @@ -1781,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, @@ -1790,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); @@ -1848,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); @@ -2459,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; @@ -3340,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); /** @@ -3355,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); @@ -3550,7 +3636,6 @@ void cfg80211_probe_status(struct net_device *dev, const u8 *addr, * @len: length of the frame * @freq: frequency the frame was received on * @sig_dbm: signal strength in mBm, or 0 if unknown - * @gfp: allocation flags * * Use this function to report to userspace when a beacon was * received. It is not useful to call this when there is no @@ -3558,31 +3643,47 @@ void cfg80211_probe_status(struct net_device *dev, const u8 *addr, */ void cfg80211_report_obss_beacon(struct wiphy *wiphy, const u8 *frame, size_t len, - int freq, int sig_dbm, gfp_t gfp); + 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) @@ -3608,6 +3709,26 @@ u32 cfg80211_calculate_bitrate(struct rate_info *rate); */ void cfg80211_unregister_wdev(struct wireless_dev *wdev); +/** + * cfg80211_get_p2p_attr - find and copy a P2P attribute from IE buffer + * @ies: the input IE buffer + * @len: the input length + * @attr: the attribute ID to find + * @buf: output buffer, can be %NULL if the data isn't needed, e.g. + * if the function is only called to get the needed buffer size + * @bufsize: size of the output buffer + * + * The function finds a given P2P attribute in the (vendor) IEs and + * copies its contents to the given buffer. + * + * The return value is a negative error code (-%EILSEQ or -%ENOENT) if + * the data is malformed or the attribute can't be found (respectively), + * or the length of the found attribute (which can be zero). + */ +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. */ /* wiphy_printk helpers, similar to dev_printk */ diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 00b7204708bd..db7680acd0da 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; @@ -207,6 +205,9 @@ struct ieee80211_chanctx_conf { * @BSS_CHANGED_SSID: SSID changed for this BSS (AP mode) * @BSS_CHANGED_AP_PROBE_RESP: Probe Response changed for this BSS (AP mode) * @BSS_CHANGED_PS: PS changed for this BSS (STA mode) + * @BSS_CHANGED_TXPOWER: TX power setting changed for this interface + * @BSS_CHANGED_P2P_PS: P2P powersave settings (CTWindow, opportunistic PS) + * changed (currently only in P2P client mode, GO mode will be later) */ enum ieee80211_bss_change { BSS_CHANGED_ASSOC = 1<<0, @@ -227,6 +228,8 @@ enum ieee80211_bss_change { BSS_CHANGED_SSID = 1<<15, BSS_CHANGED_AP_PROBE_RESP = 1<<16, BSS_CHANGED_PS = 1<<17, + BSS_CHANGED_TXPOWER = 1<<18, + BSS_CHANGED_P2P_PS = 1<<19, /* when adding here, make sure to change ieee80211_reconfig */ }; @@ -283,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 @@ -309,6 +311,9 @@ enum ieee80211_rssi_event { * @ssid: The SSID of the current vif. Only valid in AP-mode. * @ssid_len: Length of SSID given in @ssid. * @hidden_ssid: The SSID of the current vif is hidden. Only valid in AP-mode. + * @txpower: TX power in dBm + * @p2p_ctwindow: P2P CTWindow, only for P2P client interfaces + * @p2p_oppps: P2P opportunistic PS is enabled */ struct ieee80211_bss_conf { const u8 *bssid; @@ -331,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; @@ -341,6 +346,9 @@ struct ieee80211_bss_conf { u8 ssid[IEEE80211_MAX_SSID_LEN]; size_t ssid_len; bool hidden_ssid; + int txpower; + u8 p2p_ctwindow; + bool p2p_oppps; }; /** @@ -491,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. @@ -504,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), }; @@ -552,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 * @@ -700,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) @@ -734,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), @@ -748,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), }; /** @@ -768,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; }; /** @@ -884,7 +948,8 @@ enum ieee80211_smps_mode { * powersave documentation below. This variable is valid only when * the CONF_PS flag is set. * - * @power_level: requested transmit power (in dBm) + * @power_level: requested transmit power (in dBm), backward compatibility + * value only that is set to the minimum of all interfaces * * @channel: the channel to tune to * @channel_type: the channel (HT) type @@ -2180,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 @@ -2381,6 +2454,17 @@ enum ieee80211_rate_control_changed { * to vif. Possible use is for hw queue remapping. * @unassign_vif_chanctx: Notifies device driver about channel context being * unbound from vif. + * @start_ap: Start operation on the AP interface, this is called after all the + * information in bss_conf is set and beacon can be retrieved. A channel + * context is bound before this is called. Note that if the driver uses + * software scan or ROC, this (and @stop_ap) isn't called when the AP is + * just "paused" for scanning/ROC, which is indicated by the beacon being + * disabled/enabled via @bss_info_changed. + * @stop_ap: Stop operation on the AP interface. + * + * @restart_complete: Called after a call to ieee80211_restart_hw(), when the + * reconfiguration has completed. This can help the driver implement the + * reconfiguration step. This callback may sleep. */ struct ieee80211_ops { void (*tx)(struct ieee80211_hw *hw, @@ -2406,6 +2490,9 @@ struct ieee80211_ops { struct ieee80211_bss_conf *info, u32 changed); + int (*start_ap)(struct ieee80211_hw *hw, struct ieee80211_vif *vif); + void (*stop_ap)(struct ieee80211_hw *hw, struct ieee80211_vif *vif); + u64 (*prepare_multicast)(struct ieee80211_hw *hw, struct netdev_hw_addr_list *mc_list); void (*configure_filter)(struct ieee80211_hw *hw, @@ -2447,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, @@ -2488,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); @@ -2539,6 +2636,8 @@ struct ieee80211_ops { void (*unassign_vif_chanctx)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_chanctx_conf *ctx); + + void (*restart_complete)(struct ieee80211_hw *hw); }; /** @@ -3385,6 +3484,21 @@ void ieee80211_sched_scan_results(struct ieee80211_hw *hw); void ieee80211_sched_scan_stopped(struct ieee80211_hw *hw); /** + * enum ieee80211_interface_iteration_flags - interface iteration flags + * @IEEE80211_IFACE_ITER_NORMAL: Iterate over all interfaces that have + * been added to the driver; However, note that during hardware + * reconfiguration (after restart_hw) it will iterate over a new + * interface and over all the existing interfaces even if they + * haven't been re-added to the driver yet. + * @IEEE80211_IFACE_ITER_RESUME_ALL: During resume, iterate over all + * interfaces, even if they haven't been re-added to the driver yet. + */ +enum ieee80211_interface_iteration_flags { + IEEE80211_IFACE_ITER_NORMAL = 0, + IEEE80211_IFACE_ITER_RESUME_ALL = BIT(0), +}; + +/** * ieee80211_iterate_active_interfaces - iterate active interfaces * * This function iterates over the interfaces associated with a given @@ -3392,13 +3506,15 @@ void ieee80211_sched_scan_stopped(struct ieee80211_hw *hw); * This function allows the iterator function to sleep, when the iterator * function is atomic @ieee80211_iterate_active_interfaces_atomic can * be used. - * Does not iterate over a new interface during add_interface() + * Does not iterate over a new interface during add_interface(). * * @hw: the hardware struct of which the interfaces should be iterated over + * @iter_flags: iteration flags, see &enum ieee80211_interface_iteration_flags * @iterator: the iterator function to call * @data: first argument of the iterator function */ void ieee80211_iterate_active_interfaces(struct ieee80211_hw *hw, + u32 iter_flags, void (*iterator)(void *data, u8 *mac, struct ieee80211_vif *vif), void *data); @@ -3410,13 +3526,15 @@ void ieee80211_iterate_active_interfaces(struct ieee80211_hw *hw, * hardware that are currently active and calls the callback for them. * This function requires the iterator callback function to be atomic, * if that is not desired, use @ieee80211_iterate_active_interfaces instead. - * Does not iterate over a new interface during add_interface() + * Does not iterate over a new interface during add_interface(). * * @hw: the hardware struct of which the interfaces should be iterated over + * @iter_flags: iteration flags, see &enum ieee80211_interface_iteration_flags * @iterator: the iterator function to call, cannot sleep * @data: first argument of the iterator function */ void ieee80211_iterate_active_interfaces_atomic(struct ieee80211_hw *hw, + u32 iter_flags, void (*iterator)(void *data, u8 *mac, struct ieee80211_vif *vif), diff --git a/include/net/nfc/hci.h b/include/net/nfc/hci.h index 639f50af42df..671953e11575 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 617d0fbfc96f..33a417481ad8 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 @@ -578,6 +583,9 @@ * station, due to particular reason. %NL80211_ATTR_CONN_FAILED_REASON * is used for this. * + * @NL80211_CMD_SET_MCAST_RATE: Change the rate used to send multicast frames + * for IBSS or MESH vif. + * * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */ @@ -726,6 +734,8 @@ enum nl80211_commands { NL80211_CMD_CONN_FAILED, + NL80211_CMD_SET_MCAST_RATE, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ @@ -762,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 @@ -1544,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, @@ -1708,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 { @@ -1721,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, @@ -2429,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, @@ -2437,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 @@ -3051,6 +3122,10 @@ enum nl80211_ap_sme_features { * @NL80211_FEATURE_LOW_PRIORITY_SCAN: This driver supports low priority scan * @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, @@ -3062,6 +3137,8 @@ enum nl80211_feature_flags { NL80211_FEATURE_LOW_PRIORITY_SCAN = 1 << 6, 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/amp.c b/net/bluetooth/amp.c index 4b2fea6c1c2a..1b0d92c0643a 100644 --- a/net/bluetooth/amp.c +++ b/net/bluetooth/amp.c @@ -386,13 +386,17 @@ void amp_physical_cfm(struct hci_conn *bredr_hcon, struct hci_conn *hs_hcon) bredr_chan = mgr->bredr_chan; + l2cap_chan_lock(bredr_chan); + set_bit(FLAG_EFS_ENABLE, &bredr_chan->flags); bredr_chan->remote_amp_id = hs_hcon->remote_id; + bredr_chan->local_amp_id = hs_hcon->hdev->id; bredr_chan->hs_hcon = hs_hcon; bredr_chan->conn->mtu = hs_hcon->hdev->block_mtu; - bredr_chan->fcs = L2CAP_FCS_NONE; - l2cap_physical_cfm(bredr_chan, 0); + __l2cap_physical_cfm(bredr_chan, 0); + + l2cap_chan_unlock(bredr_chan); hci_dev_put(bredr_hdev); } diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 515d0c394f35..596660d37c5e 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -434,6 +434,8 @@ bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data, BT_DBG("cache %p, %pMR", cache, &data->bdaddr); + hci_remove_remote_oob_data(hdev, &data->bdaddr); + if (ssp) *ssp = data->ssp_mode; @@ -594,6 +596,99 @@ done: return err; } +static u8 create_ad(struct hci_dev *hdev, u8 *ptr) +{ + u8 ad_len = 0, flags = 0; + size_t name_len; + + if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags)) + flags |= LE_AD_GENERAL; + + if (!lmp_bredr_capable(hdev)) + flags |= LE_AD_NO_BREDR; + + if (lmp_le_br_capable(hdev)) + flags |= LE_AD_SIM_LE_BREDR_CTRL; + + if (lmp_host_le_br_capable(hdev)) + flags |= LE_AD_SIM_LE_BREDR_HOST; + + if (flags) { + BT_DBG("adv flags 0x%02x", flags); + + ptr[0] = 2; + ptr[1] = EIR_FLAGS; + ptr[2] = flags; + + ad_len += 3; + ptr += 3; + } + + if (hdev->adv_tx_power != HCI_TX_POWER_INVALID) { + ptr[0] = 2; + ptr[1] = EIR_TX_POWER; + ptr[2] = (u8) hdev->adv_tx_power; + + ad_len += 3; + ptr += 3; + } + + name_len = strlen(hdev->dev_name); + if (name_len > 0) { + size_t max_len = HCI_MAX_AD_LENGTH - ad_len - 2; + + if (name_len > max_len) { + name_len = max_len; + ptr[1] = EIR_NAME_SHORT; + } else + ptr[1] = EIR_NAME_COMPLETE; + + ptr[0] = name_len + 1; + + memcpy(ptr + 2, hdev->dev_name, name_len); + + ad_len += (name_len + 2); + ptr += (name_len + 2); + } + + return ad_len; +} + +int hci_update_ad(struct hci_dev *hdev) +{ + struct hci_cp_le_set_adv_data cp; + u8 len; + int err; + + hci_dev_lock(hdev); + + if (!lmp_le_capable(hdev)) { + err = -EINVAL; + goto unlock; + } + + memset(&cp, 0, sizeof(cp)); + + len = create_ad(hdev, cp.data); + + if (hdev->adv_data_len == len && + memcmp(cp.data, hdev->adv_data, len) == 0) { + err = 0; + goto unlock; + } + + memcpy(hdev->adv_data, cp.data, sizeof(cp.data)); + hdev->adv_data_len = len; + + cp.length = len; + err = hci_send_cmd(hdev, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp); + +unlock: + hci_dev_unlock(hdev); + + return err; +} + /* ---- HCI ioctl helpers ---- */ int hci_dev_open(__u16 dev) @@ -651,6 +746,7 @@ int hci_dev_open(__u16 dev) hci_dev_hold(hdev); set_bit(HCI_UP, &hdev->flags); hci_notify(hdev, HCI_DEV_UP); + hci_update_ad(hdev); if (!test_bit(HCI_SETUP, &hdev->dev_flags) && mgmt_valid_hdev(hdev)) { hci_dev_lock(hdev); @@ -765,6 +861,9 @@ static int hci_dev_do_close(struct hci_dev *hdev) /* Clear flags */ hdev->flags = 0; + /* Controller radio is available but is currently powered down */ + hdev->amp_status = 0; + memset(hdev->eir, 0, sizeof(hdev->eir)); memset(hdev->dev_class, 0, sizeof(hdev->dev_class)); @@ -1606,6 +1705,8 @@ struct hci_dev *hci_alloc_dev(void) hdev->esco_type = (ESCO_HV1); hdev->link_mode = (HCI_LM_ACCEPT); hdev->io_capability = 0x03; /* No Input No Output */ + hdev->inq_tx_power = HCI_TX_POWER_INVALID; + hdev->adv_tx_power = HCI_TX_POWER_INVALID; hdev->sniff_max_interval = 800; hdev->sniff_min_interval = 80; @@ -1717,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: @@ -1756,6 +1857,8 @@ void hci_unregister_dev(struct hci_dev *hdev) for (i = 0; i < NUM_REASSEMBLY; i++) kfree_skb(hdev->reassembly[i]); + cancel_work_sync(&hdev->power_on); + if (!test_bit(HCI_INIT, &hdev->flags) && !test_bit(HCI_SETUP, &hdev->dev_flags)) { hci_dev_lock(hdev); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index c08ac7c03711..705078a0cc39 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -202,6 +202,11 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb) BIT(HCI_PERIODIC_INQ)); hdev->discovery.state = DISCOVERY_STOPPED; + hdev->inq_tx_power = HCI_TX_POWER_INVALID; + hdev->adv_tx_power = HCI_TX_POWER_INVALID; + + memset(hdev->adv_data, 0, sizeof(hdev->adv_data)); + hdev->adv_data_len = 0; } static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb) @@ -224,6 +229,9 @@ static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb) hci_dev_unlock(hdev); + if (!status && !test_bit(HCI_INIT, &hdev->flags)) + hci_update_ad(hdev); + hci_req_complete(hdev, HCI_OP_WRITE_LOCAL_NAME, status); } @@ -786,10 +794,10 @@ static void hci_set_le_support(struct hci_dev *hdev) if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) { cp.le = 1; - cp.simul = !!lmp_le_br_capable(hdev); + cp.simul = lmp_le_br_capable(hdev); } - if (cp.le != !!lmp_host_le_capable(hdev)) + if (cp.le != lmp_host_le_capable(hdev)) hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(cp), &cp); } @@ -1089,8 +1097,11 @@ static void hci_cc_le_read_adv_tx_power(struct hci_dev *hdev, BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); - if (!rp->status) + if (!rp->status) { hdev->adv_tx_power = rp->tx_power; + if (!test_bit(HCI_INIT, &hdev->flags)) + hci_update_ad(hdev); + } hci_req_complete(hdev, HCI_OP_LE_READ_ADV_TX_POWER, rp->status); } @@ -1179,6 +1190,33 @@ static void hci_cc_read_local_oob_data_reply(struct hci_dev *hdev, hci_dev_unlock(hdev); } +static void hci_cc_le_set_adv_enable(struct hci_dev *hdev, struct sk_buff *skb) +{ + __u8 *sent, status = *((__u8 *) skb->data); + + BT_DBG("%s status 0x%2.2x", hdev->name, status); + + sent = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_ADV_ENABLE); + if (!sent) + return; + + hci_dev_lock(hdev); + + if (!status) { + if (*sent) + set_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags); + else + clear_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags); + } + + hci_dev_unlock(hdev); + + if (!test_bit(HCI_INIT, &hdev->flags)) + hci_update_ad(hdev); + + hci_req_complete(hdev, HCI_OP_LE_SET_ADV_ENABLE, status); +} + static void hci_cc_le_set_scan_param(struct hci_dev *hdev, struct sk_buff *skb) { __u8 status = *((__u8 *) skb->data); @@ -2009,15 +2047,53 @@ unlock: hci_conn_check_pending(hdev); } +void hci_conn_accept(struct hci_conn *conn, int mask) +{ + struct hci_dev *hdev = conn->hdev; + + BT_DBG("conn %p", conn); + + conn->state = BT_CONFIG; + + if (!lmp_esco_capable(hdev)) { + struct hci_cp_accept_conn_req cp; + + bacpy(&cp.bdaddr, &conn->dst); + + if (lmp_rswitch_capable(hdev) && (mask & HCI_LM_MASTER)) + cp.role = 0x00; /* Become master */ + else + cp.role = 0x01; /* Remain slave */ + + hci_send_cmd(hdev, HCI_OP_ACCEPT_CONN_REQ, sizeof(cp), &cp); + } else /* lmp_esco_capable(hdev)) */ { + struct hci_cp_accept_sync_conn_req cp; + + bacpy(&cp.bdaddr, &conn->dst); + cp.pkt_type = cpu_to_le16(conn->pkt_type); + + cp.tx_bandwidth = __constant_cpu_to_le32(0x00001f40); + cp.rx_bandwidth = __constant_cpu_to_le32(0x00001f40); + cp.max_latency = __constant_cpu_to_le16(0xffff); + cp.content_format = cpu_to_le16(hdev->voice_setting); + cp.retrans_effort = 0xff; + + hci_send_cmd(hdev, HCI_OP_ACCEPT_SYNC_CONN_REQ, + sizeof(cp), &cp); + } +} + static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_conn_request *ev = (void *) skb->data; int mask = hdev->link_mode; + __u8 flags = 0; BT_DBG("%s bdaddr %pMR type 0x%x", hdev->name, &ev->bdaddr, ev->link_type); - mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, ev->link_type); + mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, ev->link_type, + &flags); if ((mask & HCI_LM_ACCEPT) && !hci_blacklist_lookup(hdev, &ev->bdaddr)) { @@ -2043,12 +2119,13 @@ static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) } memcpy(conn->dev_class, ev->dev_class, 3); - conn->state = BT_CONNECT; hci_dev_unlock(hdev); - if (ev->link_type == ACL_LINK || !lmp_esco_capable(hdev)) { + if (ev->link_type == ACL_LINK || + (!(flags & HCI_PROTO_DEFER) && !lmp_esco_capable(hdev))) { struct hci_cp_accept_conn_req cp; + conn->state = BT_CONNECT; bacpy(&cp.bdaddr, &ev->bdaddr); @@ -2059,8 +2136,9 @@ static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) hci_send_cmd(hdev, HCI_OP_ACCEPT_CONN_REQ, sizeof(cp), &cp); - } else { + } else if (!(flags & HCI_PROTO_DEFER)) { struct hci_cp_accept_sync_conn_req cp; + conn->state = BT_CONNECT; bacpy(&cp.bdaddr, &ev->bdaddr); cp.pkt_type = cpu_to_le16(conn->pkt_type); @@ -2073,6 +2151,10 @@ static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) hci_send_cmd(hdev, HCI_OP_ACCEPT_SYNC_CONN_REQ, sizeof(cp), &cp); + } else { + conn->state = BT_CONNECT2; + hci_proto_connect_cfm(conn, 0); + hci_conn_put(conn); } } else { /* Connection rejected */ @@ -2574,6 +2656,10 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) hci_cc_le_set_scan_param(hdev, skb); break; + case HCI_OP_LE_SET_ADV_ENABLE: + hci_cc_le_set_adv_enable(hdev, skb); + break; + case HCI_OP_LE_SET_SCAN_ENABLE: hci_cc_le_set_scan_enable(hdev, skb); break; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index a1faaab41839..2c78208d793e 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -53,8 +53,7 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data); static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data); -static void l2cap_send_disconn_req(struct l2cap_conn *conn, - struct l2cap_chan *chan, int err); +static void l2cap_send_disconn_req(struct l2cap_chan *chan, int err); static void l2cap_tx(struct l2cap_chan *chan, struct l2cap_ctrl *control, struct sk_buff_head *skbs, u8 event); @@ -632,7 +631,7 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason) if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED && conn->hcon->type == ACL_LINK) { __set_chan_timer(chan, sk->sk_sndtimeo); - l2cap_send_disconn_req(conn, chan, reason); + l2cap_send_disconn_req(chan, reason); } else l2cap_chan_del(chan, reason); break; @@ -1014,6 +1013,7 @@ static bool __amp_capable(struct l2cap_chan *chan) struct l2cap_conn *conn = chan->conn; if (enable_hs && + hci_amp_capable() && chan->chan_policy == BT_CHANNEL_POLICY_AMP_PREFERRED && conn->fixed_chan_mask & L2CAP_FC_A2MP) return true; @@ -1180,10 +1180,10 @@ static inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask) } } -static void l2cap_send_disconn_req(struct l2cap_conn *conn, - struct l2cap_chan *chan, int err) +static void l2cap_send_disconn_req(struct l2cap_chan *chan, int err) { struct sock *sk = chan->sk; + struct l2cap_conn *conn = chan->conn; struct l2cap_disconn_req req; if (!conn) @@ -1960,7 +1960,7 @@ static void l2cap_ertm_resend(struct l2cap_chan *chan) if (chan->max_tx != 0 && bt_cb(skb)->control.retries > chan->max_tx) { BT_DBG("Retry limit exceeded (%d)", chan->max_tx); - l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); + l2cap_send_disconn_req(chan, ECONNRESET); l2cap_seq_list_clear(&chan->retrans_list); break; } @@ -2666,7 +2666,7 @@ static void l2cap_tx_state_wait_f(struct l2cap_chan *chan, __set_monitor_timer(chan); chan->retry_count++; } else { - l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED); + l2cap_send_disconn_req(chan, ECONNABORTED); } break; default: @@ -3106,18 +3106,17 @@ done: if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) l2cap_add_opt_efs(&ptr, chan); - if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS)) - break; - - if (chan->fcs == L2CAP_FCS_NONE || - test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) { - chan->fcs = L2CAP_FCS_NONE; - l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs); - } - if (test_bit(FLAG_EXT_CTRL, &chan->flags)) l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2, chan->tx_win); + + if (chan->conn->feat_mask & L2CAP_FEAT_FCS) + if (chan->fcs == L2CAP_FCS_NONE || + test_bit(CONF_RECV_NO_FCS, &chan->conf_state)) { + chan->fcs = L2CAP_FCS_NONE; + l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, + chan->fcs); + } break; case L2CAP_MODE_STREAMING: @@ -3139,14 +3138,13 @@ done: if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) l2cap_add_opt_efs(&ptr, chan); - if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS)) - break; - - if (chan->fcs == L2CAP_FCS_NONE || - test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) { - chan->fcs = L2CAP_FCS_NONE; - l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs); - } + if (chan->conn->feat_mask & L2CAP_FEAT_FCS) + if (chan->fcs == L2CAP_FCS_NONE || + test_bit(CONF_RECV_NO_FCS, &chan->conf_state)) { + chan->fcs = L2CAP_FCS_NONE; + l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, + chan->fcs); + } break; } @@ -3198,7 +3196,7 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data) case L2CAP_CONF_FCS: if (val == L2CAP_FCS_NONE) - set_bit(CONF_NO_FCS_RECV, &chan->conf_state); + set_bit(CONF_RECV_NO_FCS, &chan->conf_state); break; case L2CAP_CONF_EFS: @@ -3433,6 +3431,13 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS, sizeof(efs), (unsigned long) &efs); break; + + case L2CAP_CONF_FCS: + if (*result == L2CAP_CONF_PENDING) + if (val == L2CAP_FCS_NONE) + set_bit(CONF_RECV_NO_FCS, + &chan->conf_state); + break; } } @@ -3802,7 +3807,7 @@ static inline void set_default_fcs(struct l2cap_chan *chan) */ if (chan->mode != L2CAP_MODE_ERTM && chan->mode != L2CAP_MODE_STREAMING) chan->fcs = L2CAP_FCS_NONE; - else if (!test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) + else if (!test_bit(CONF_RECV_NO_FCS, &chan->conf_state)) chan->fcs = L2CAP_FCS_CRC16; } @@ -3877,7 +3882,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, /* Complete config. */ len = l2cap_parse_conf_req(chan, rsp); if (len < 0) { - l2cap_send_disconn_req(conn, chan, ECONNRESET); + l2cap_send_disconn_req(chan, ECONNRESET); goto unlock; } @@ -3899,7 +3904,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, err = l2cap_ertm_init(chan); if (err < 0) - l2cap_send_disconn_req(chan->conn, chan, -err); + l2cap_send_disconn_req(chan, -err); else l2cap_chan_ready(chan); @@ -3967,7 +3972,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, len = l2cap_parse_conf_rsp(chan, rsp->data, len, buf, &result); if (len < 0) { - l2cap_send_disconn_req(conn, chan, ECONNRESET); + l2cap_send_disconn_req(chan, ECONNRESET); goto done; } @@ -3988,7 +3993,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, char req[64]; if (len > sizeof(req) - sizeof(struct l2cap_conf_req)) { - l2cap_send_disconn_req(conn, chan, ECONNRESET); + l2cap_send_disconn_req(chan, ECONNRESET); goto done; } @@ -3997,7 +4002,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, len = l2cap_parse_conf_rsp(chan, rsp->data, len, req, &result); if (len < 0) { - l2cap_send_disconn_req(conn, chan, ECONNRESET); + l2cap_send_disconn_req(chan, ECONNRESET); goto done; } @@ -4013,7 +4018,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, l2cap_chan_set_err(chan, ECONNRESET); __set_chan_timer(chan, L2CAP_DISC_REJ_TIMEOUT); - l2cap_send_disconn_req(conn, chan, ECONNRESET); + l2cap_send_disconn_req(chan, ECONNRESET); goto done; } @@ -4030,7 +4035,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, err = l2cap_ertm_init(chan); if (err < 0) - l2cap_send_disconn_req(chan->conn, chan, -err); + l2cap_send_disconn_req(chan, -err); else l2cap_chan_ready(chan); } @@ -4284,9 +4289,9 @@ static int l2cap_create_channel_req(struct l2cap_conn *conn, BT_DBG("mgr %p bredr_chan %p hs_hcon %p", mgr, chan, hs_hcon); - chan->local_amp_id = req->amp_id; mgr->bredr_chan = chan; chan->hs_hcon = hs_hcon; + chan->fcs = L2CAP_FCS_NONE; conn->mtu = hdev->block_mtu; } @@ -4392,7 +4397,7 @@ static void l2cap_logical_fail(struct l2cap_chan *chan) /* Logical link setup failed */ if (chan->state != BT_CONNECTED) { /* Create channel failure, disconnect */ - l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); + l2cap_send_disconn_req(chan, ECONNRESET); return; } @@ -4435,7 +4440,7 @@ static void l2cap_logical_finish_create(struct l2cap_chan *chan, err = l2cap_ertm_init(chan); if (err < 0) - l2cap_send_disconn_req(chan->conn, chan, -err); + l2cap_send_disconn_req(chan, -err); else l2cap_chan_ready(chan); } @@ -4518,21 +4523,39 @@ void l2cap_move_start(struct l2cap_chan *chan) static void l2cap_do_create(struct l2cap_chan *chan, int result, u8 local_amp_id, u8 remote_amp_id) { - if (!test_bit(CONF_CONNECT_PEND, &chan->conf_state)) { + BT_DBG("chan %p state %s %u -> %u", chan, state_to_string(chan->state), + local_amp_id, remote_amp_id); + + chan->fcs = L2CAP_FCS_NONE; + + /* Outgoing channel on AMP */ + if (chan->state == BT_CONNECT) { + if (result == L2CAP_CR_SUCCESS) { + chan->local_amp_id = local_amp_id; + l2cap_send_create_chan_req(chan, remote_amp_id); + } else { + /* Revert to BR/EDR connect */ + l2cap_send_conn_req(chan); + } + + return; + } + + /* Incoming channel on AMP */ + if (__l2cap_no_conn_pending(chan)) { struct l2cap_conn_rsp rsp; char buf[128]; rsp.scid = cpu_to_le16(chan->dcid); rsp.dcid = cpu_to_le16(chan->scid); - /* Incoming channel on AMP */ if (result == L2CAP_CR_SUCCESS) { /* Send successful response */ - rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS); - rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); + rsp.result = __constant_cpu_to_le16(L2CAP_CR_SUCCESS); + rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO); } else { /* Send negative response */ - rsp.result = cpu_to_le16(L2CAP_CR_NO_MEM); - rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); + rsp.result = __constant_cpu_to_le16(L2CAP_CR_NO_MEM); + rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO); } l2cap_send_cmd(chan->conn, chan->ident, L2CAP_CREATE_CHAN_RSP, @@ -4546,15 +4569,6 @@ static void l2cap_do_create(struct l2cap_chan *chan, int result, l2cap_build_conf_req(chan, buf), buf); chan->num_conf_req++; } - } else { - /* Outgoing channel on AMP */ - if (result == L2CAP_CR_SUCCESS) { - chan->local_amp_id = local_amp_id; - l2cap_send_create_chan_req(chan, remote_amp_id); - } else { - /* Revert to BR/EDR connect */ - l2cap_send_conn_req(chan); - } } } @@ -4612,7 +4626,8 @@ static void l2cap_do_move_cancel(struct l2cap_chan *chan, int result) l2cap_ertm_send(chan); } -void l2cap_physical_cfm(struct l2cap_chan *chan, int result) +/* Invoke with locked chan */ +void __l2cap_physical_cfm(struct l2cap_chan *chan, int result) { u8 local_amp_id = chan->local_amp_id; u8 remote_amp_id = chan->remote_amp_id; @@ -4620,8 +4635,6 @@ void l2cap_physical_cfm(struct l2cap_chan *chan, int result) BT_DBG("chan %p, result %d, local_amp_id %d, remote_amp_id %d", chan, result, local_amp_id, remote_amp_id); - l2cap_chan_lock(chan); - if (chan->state == BT_DISCONN || chan->state == BT_CLOSED) { l2cap_chan_unlock(chan); return; @@ -4645,8 +4658,6 @@ void l2cap_physical_cfm(struct l2cap_chan *chan, int result) break; } } - - l2cap_chan_unlock(chan); } static inline int l2cap_move_channel_req(struct l2cap_conn *conn, @@ -5394,7 +5405,7 @@ static void l2cap_handle_srej(struct l2cap_chan *chan, if (control->reqseq == chan->next_tx_seq) { BT_DBG("Invalid reqseq %d, disconnecting", control->reqseq); - l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); + l2cap_send_disconn_req(chan, ECONNRESET); return; } @@ -5408,7 +5419,7 @@ static void l2cap_handle_srej(struct l2cap_chan *chan, if (chan->max_tx != 0 && bt_cb(skb)->control.retries >= chan->max_tx) { BT_DBG("Retry limit exceeded (%d)", chan->max_tx); - l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); + l2cap_send_disconn_req(chan, ECONNRESET); return; } @@ -5452,7 +5463,7 @@ static void l2cap_handle_rej(struct l2cap_chan *chan, if (control->reqseq == chan->next_tx_seq) { BT_DBG("Invalid reqseq %d, disconnecting", control->reqseq); - l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); + l2cap_send_disconn_req(chan, ECONNRESET); return; } @@ -5461,7 +5472,7 @@ static void l2cap_handle_rej(struct l2cap_chan *chan, if (chan->max_tx && skb && bt_cb(skb)->control.retries >= chan->max_tx) { BT_DBG("Retry limit exceeded (%d)", chan->max_tx); - l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); + l2cap_send_disconn_req(chan, ECONNRESET); return; } @@ -5645,8 +5656,7 @@ static int l2cap_rx_state_recv(struct l2cap_chan *chan, break; case L2CAP_TXSEQ_INVALID: default: - l2cap_send_disconn_req(chan->conn, chan, - ECONNRESET); + l2cap_send_disconn_req(chan, ECONNRESET); break; } break; @@ -5779,8 +5789,7 @@ static int l2cap_rx_state_srej_sent(struct l2cap_chan *chan, break; case L2CAP_TXSEQ_INVALID: default: - l2cap_send_disconn_req(chan->conn, chan, - ECONNRESET); + l2cap_send_disconn_req(chan, ECONNRESET); break; } break; @@ -5975,7 +5984,7 @@ static int l2cap_rx(struct l2cap_chan *chan, struct l2cap_ctrl *control, BT_DBG("Invalid reqseq %d (next_tx_seq %d, expected_ack_seq %d", control->reqseq, chan->next_tx_seq, chan->expected_ack_seq); - l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); + l2cap_send_disconn_req(chan, ECONNRESET); } return err; @@ -6044,7 +6053,7 @@ static int l2cap_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) len -= L2CAP_FCS_SIZE; if (len > chan->mps) { - l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); + l2cap_send_disconn_req(chan, ECONNRESET); goto drop; } @@ -6069,8 +6078,7 @@ static int l2cap_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) } if (err) - l2cap_send_disconn_req(chan->conn, chan, - ECONNRESET); + l2cap_send_disconn_req(chan, ECONNRESET); } else { const u8 rx_func_to_event[4] = { L2CAP_EV_RECV_RR, L2CAP_EV_RECV_REJ, @@ -6086,8 +6094,8 @@ static int l2cap_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) control->super); if (len != 0) { - BT_ERR("%d", len); - l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); + BT_ERR("Trailing bytes: %d in sframe", len); + l2cap_send_disconn_req(chan, ECONNRESET); goto drop; } @@ -6098,7 +6106,7 @@ static int l2cap_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) event = rx_func_to_event[control->super]; if (l2cap_rx(chan, control, skb, event)) - l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); + l2cap_send_disconn_req(chan, ECONNRESET); } return 0; @@ -6380,7 +6388,7 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) continue; } - if (test_bit(CONF_CONNECT_PEND, &chan->conf_state)) { + if (!__l2cap_no_conn_pending(chan)) { l2cap_chan_unlock(chan); continue; } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index a1a62baaaafb..f559b966279c 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, @@ -484,7 +485,7 @@ static void create_eir(struct hci_dev *hdev, u8 *data) ptr += (name_len + 2); } - if (hdev->inq_tx_power) { + if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) { ptr[0] = 2; ptr[1] = EIR_TX_POWER; ptr[2] = (u8) hdev->inq_tx_power; @@ -1225,7 +1226,7 @@ static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) } val = !!cp->val; - enabled = !!lmp_host_le_capable(hdev); + enabled = lmp_host_le_capable(hdev); if (!hdev_is_powered(hdev) || val == enabled) { bool changed = false; @@ -1261,7 +1262,7 @@ static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) if (val) { hci_cp.le = val; - hci_cp.simul = !!lmp_le_br_capable(hdev); + hci_cp.simul = lmp_le_br_capable(hdev); } err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp), @@ -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++; } @@ -2924,13 +2926,13 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered) struct hci_cp_write_le_host_supported cp; cp.le = 1; - cp.simul = !!lmp_le_br_capable(hdev); + cp.simul = lmp_le_br_capable(hdev); /* Check first if we already have the right * host state (host features set) */ - if (cp.le != !!lmp_host_le_capable(hdev) || - cp.simul != !!lmp_host_le_br_capable(hdev)) + if (cp.le != lmp_host_le_capable(hdev) || + cp.simul != lmp_host_le_br_capable(hdev)) hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(cp), &cp); diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index 4ddef57d03a7..ce3f6658f4b2 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -467,7 +467,7 @@ static int rfcomm_sock_accept(struct socket *sock, struct socket *newsock, int f long timeo; int err = 0; - lock_sock(sk); + lock_sock_nested(sk, SINGLE_DEPTH_NESTING); if (sk->sk_type != SOCK_STREAM) { err = -EINVAL; @@ -504,7 +504,7 @@ static int rfcomm_sock_accept(struct socket *sock, struct socket *newsock, int f release_sock(sk); timeo = schedule_timeout(timeo); - lock_sock(sk); + lock_sock_nested(sk, SINGLE_DEPTH_NESTING); } __set_current_state(TASK_RUNNING); remove_wait_queue(sk_sleep(sk), &wait); diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 450cdcd88e5c..531a93d613d4 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -131,15 +131,6 @@ static int sco_conn_del(struct hci_conn *hcon, int err) sco_sock_clear_timer(sk); sco_chan_del(sk, err); bh_unlock_sock(sk); - - sco_conn_lock(conn); - conn->sk = NULL; - sco_pi(sk)->conn = NULL; - sco_conn_unlock(conn); - - if (conn->hcon) - hci_conn_put(conn->hcon); - sco_sock_kill(sk); } @@ -397,6 +388,7 @@ static void sco_sock_init(struct sock *sk, struct sock *parent) if (parent) { sk->sk_type = parent->sk_type; + bt_sk(sk)->flags = bt_sk(parent)->flags; security_sk_clone(parent, sk); } } @@ -662,16 +654,57 @@ static int sco_sock_sendmsg(struct kiocb *iocb, struct socket *sock, return err; } +static int sco_sock_recvmsg(struct kiocb *iocb, struct socket *sock, + struct msghdr *msg, size_t len, int flags) +{ + struct sock *sk = sock->sk; + struct sco_pinfo *pi = sco_pi(sk); + + lock_sock(sk); + + if (sk->sk_state == BT_CONNECT2 && + test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) { + hci_conn_accept(pi->conn->hcon, 0); + sk->sk_state = BT_CONFIG; + + release_sock(sk); + return 0; + } + + release_sock(sk); + + return bt_sock_recvmsg(iocb, sock, msg, len, flags); +} + static int sco_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; int err = 0; + u32 opt; BT_DBG("sk %p", sk); lock_sock(sk); switch (optname) { + + case BT_DEFER_SETUP: + if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) { + err = -EINVAL; + break; + } + + if (get_user(opt, (u32 __user *) optval)) { + err = -EFAULT; + break; + } + + if (opt) + set_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags); + else + clear_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags); + break; + default: err = -ENOPROTOOPT; break; @@ -753,6 +786,19 @@ static int sco_sock_getsockopt(struct socket *sock, int level, int optname, char lock_sock(sk); switch (optname) { + + case BT_DEFER_SETUP: + if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) { + err = -EINVAL; + break; + } + + if (put_user(test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags), + (u32 __user *) optval)) + err = -EFAULT; + + break; + default: err = -ENOPROTOOPT; break; @@ -830,6 +876,16 @@ static void sco_chan_del(struct sock *sk, int err) BT_DBG("sk %p, conn %p, err %d", sk, conn, err); + if (conn) { + sco_conn_lock(conn); + conn->sk = NULL; + sco_pi(sk)->conn = NULL; + sco_conn_unlock(conn); + + if (conn->hcon) + hci_conn_put(conn->hcon); + } + sk->sk_state = BT_CLOSED; sk->sk_err = err; sk->sk_state_change(sk); @@ -874,7 +930,10 @@ static void sco_conn_ready(struct sco_conn *conn) hci_conn_hold(conn->hcon); __sco_chan_add(conn, sk, parent); - sk->sk_state = BT_CONNECTED; + if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(parent)->flags)) + sk->sk_state = BT_CONNECT2; + else + sk->sk_state = BT_CONNECTED; /* Wake up parent */ parent->sk_data_ready(parent, 1); @@ -887,7 +946,7 @@ done: } /* ----- SCO interface with lower layer (HCI) ----- */ -int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr) +int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags) { struct sock *sk; struct hlist_node *node; @@ -904,6 +963,9 @@ int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr) if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr) || !bacmp(&bt_sk(sk)->src, BDADDR_ANY)) { lm |= HCI_LM_ACCEPT; + + if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) + *flags |= HCI_PROTO_DEFER; break; } } @@ -992,7 +1054,7 @@ static const struct proto_ops sco_sock_ops = { .accept = sco_sock_accept, .getname = sco_sock_getname, .sendmsg = sco_sock_sendmsg, - .recvmsg = bt_sock_recvmsg, + .recvmsg = sco_sock_recvmsg, .poll = bt_sock_poll, .ioctl = bt_sock_ioctl, .mmap = sock_no_mmap, diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 9176bc17595c..68a9587c9694 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 bcf02f608cbf..017a8bacfb27 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/aes_cmac.c b/net/mac80211/aes_cmac.c index 493353534a0f..537488cbf941 100644 --- a/net/mac80211/aes_cmac.c +++ b/net/mac80211/aes_cmac.c @@ -10,6 +10,7 @@ #include <linux/kernel.h> #include <linux/types.h> #include <linux/crypto.h> +#include <linux/export.h> #include <linux/err.h> #include <crypto/aes.h> diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index 186d9919b043..808338a1bce5 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 3195a6307f50..4152ed1034b8 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 5eab1325a0f6..4965aa6424ec 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; @@ -922,6 +937,15 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, return err; changed |= err; + err = drv_start_ap(sdata->local, sdata); + if (err) { + old = rtnl_dereference(sdata->u.ap.beacon); + if (old) + kfree_rcu(old, rcu_head); + RCU_INIT_POINTER(sdata->u.ap.beacon, NULL); + return err; + } + ieee80211_bss_info_change_notify(sdata, changed); netif_carrier_on(dev); @@ -953,26 +977,38 @@ static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev, static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) { - struct ieee80211_sub_if_data *sdata, *vlan; - struct beacon_data *old; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_sub_if_data *vlan; + struct ieee80211_local *local = sdata->local; + struct beacon_data *old_beacon; + struct probe_resp *old_probe_resp; - old = rtnl_dereference(sdata->u.ap.beacon); - if (!old) + old_beacon = rtnl_dereference(sdata->u.ap.beacon); + if (!old_beacon) return -ENOENT; + old_probe_resp = rtnl_dereference(sdata->u.ap.probe_resp); + /* turn off carrier for this interface and dependent VLANs */ list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) netif_carrier_off(vlan->dev); netif_carrier_off(dev); + /* remove beacon and probe response */ RCU_INIT_POINTER(sdata->u.ap.beacon, NULL); + RCU_INIT_POINTER(sdata->u.ap.probe_resp, NULL); + kfree_rcu(old_beacon, rcu_head); + if (old_probe_resp) + kfree_rcu(old_probe_resp, rcu_head); - kfree_rcu(old, rcu_head); - - sta_info_flush(sdata->local, sdata); + sta_info_flush(local, sdata); ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); + drv_stop_ap(sdata->local, sdata); + + /* free all potentially still buffered bcast frames */ + local->total_ps_buffered -= skb_queue_len(&sdata->u.ap.ps.bc_buf); + skb_queue_purge(&sdata->u.ap.ps.bc_buf); + ieee80211_vif_release_channel(sdata); return 0; @@ -1686,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; @@ -1933,6 +1968,16 @@ static int ieee80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) return ieee80211_ibss_leave(IEEE80211_DEV_TO_SUB_IF(dev)); } +static int ieee80211_set_mcast_rate(struct wiphy *wiphy, struct net_device *dev, + int rate[IEEE80211_NUM_BANDS]) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + memcpy(sdata->vif.bss_conf.mcast_rate, rate, sizeof(rate)); + + return 0; +} + static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) { struct ieee80211_local *local = wiphy_priv(wiphy); @@ -1959,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); @@ -1971,45 +2022,65 @@ static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) } static int ieee80211_set_tx_power(struct wiphy *wiphy, + struct wireless_dev *wdev, enum nl80211_tx_power_setting type, int mbm) { struct ieee80211_local *local = wiphy_priv(wiphy); - struct ieee80211_channel *chan = local->_oper_channel; - u32 changes = 0; + struct ieee80211_sub_if_data *sdata; - /* FIXME */ - if (local->use_chanctx) - return -EOPNOTSUPP; + if (wdev) { + sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); + + switch (type) { + case NL80211_TX_POWER_AUTOMATIC: + sdata->user_power_level = IEEE80211_UNSET_POWER_LEVEL; + break; + case NL80211_TX_POWER_LIMITED: + case NL80211_TX_POWER_FIXED: + if (mbm < 0 || (mbm % 100)) + return -EOPNOTSUPP; + sdata->user_power_level = MBM_TO_DBM(mbm); + break; + } + + ieee80211_recalc_txpower(sdata); + + return 0; + } switch (type) { case NL80211_TX_POWER_AUTOMATIC: - local->user_power_level = -1; + local->user_power_level = IEEE80211_UNSET_POWER_LEVEL; break; case NL80211_TX_POWER_LIMITED: - if (mbm < 0 || (mbm % 100)) - return -EOPNOTSUPP; - local->user_power_level = MBM_TO_DBM(mbm); - break; case NL80211_TX_POWER_FIXED: if (mbm < 0 || (mbm % 100)) return -EOPNOTSUPP; - /* TODO: move to cfg80211 when it knows the channel */ - if (MBM_TO_DBM(mbm) > chan->max_power) - return -EINVAL; local->user_power_level = MBM_TO_DBM(mbm); break; } - ieee80211_hw_config(local, changes); + mutex_lock(&local->iflist_mtx); + list_for_each_entry(sdata, &local->interfaces, list) + sdata->user_power_level = local->user_power_level; + list_for_each_entry(sdata, &local->interfaces, list) + ieee80211_recalc_txpower(sdata); + mutex_unlock(&local->iflist_mtx); return 0; } -static int ieee80211_get_tx_power(struct wiphy *wiphy, int *dbm) +static int ieee80211_get_tx_power(struct wiphy *wiphy, + struct wireless_dev *wdev, + int *dbm) { struct ieee80211_local *local = wiphy_priv(wiphy); + struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); - *dbm = local->hw.conf.power_level; + if (!local->use_chanctx) + *dbm = local->hw.conf.power_level; + else + *dbm = sdata->vif.bss_conf.txpower; return 0; } @@ -2078,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; @@ -2185,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) { @@ -2203,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; @@ -2236,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; @@ -2247,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; /* @@ -2341,13 +2410,22 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local, list_add_tail(&roc->list, &local->roc_list); /* - * cookie is either the roc (for normal roc) + * cookie is either the roc cookie (for normal roc) * or the SKB (for mgmt TX) */ - if (txskb) + if (!txskb) { + /* local->mtx protects this */ + local->roc_cookie_counter++; + roc->cookie = local->roc_cookie_counter; + /* wow, you wrapped 64 bits ... more likely a bug */ + if (WARN_ON(roc->cookie == 0)) { + roc->cookie = 1; + local->roc_cookie_counter++; + } + *cookie = roc->cookie; + } else { *cookie = (unsigned long)txskb; - else - *cookie = (unsigned long)roc; + } return 0; } @@ -2355,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) { @@ -2364,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); @@ -2382,7 +2459,7 @@ static int ieee80211_cancel_roc(struct ieee80211_local *local, struct ieee80211_roc_work *dep, *tmp2; list_for_each_entry_safe(dep, tmp2, &roc->dependents, list) { - if (!mgmt_tx && (unsigned long)dep != cookie) + if (!mgmt_tx && dep->cookie != cookie) continue; else if (mgmt_tx && dep->mgmt_tx_cookie != cookie) continue; @@ -2394,7 +2471,7 @@ static int ieee80211_cancel_roc(struct ieee80211_local *local, return 0; } - if (!mgmt_tx && (unsigned long)roc != cookie) + if (!mgmt_tx && roc->cookie != cookie) continue; else if (mgmt_tx && roc->mgmt_tx_cookie != cookie) continue; @@ -2457,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; @@ -2529,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(); } @@ -2571,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); @@ -2613,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: @@ -3002,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); @@ -3059,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 @@ -3130,6 +3204,7 @@ struct cfg80211_ops mac80211_config_ops = { .disassoc = ieee80211_disassoc, .join_ibss = ieee80211_join_ibss, .leave_ibss = ieee80211_leave_ibss, + .set_mcast_rate = ieee80211_set_mcast_rate, .set_wiphy_params = ieee80211_set_wiphy_params, .set_tx_power = ieee80211_set_tx_power, .get_tx_power = ieee80211_get_tx_power, diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index f84b86028a9c..53f03120db55 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); @@ -173,44 +126,42 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata, rcu_assign_pointer(sdata->vif.chanctx_conf, &ctx->conf); ctx->refcount++; + ieee80211_recalc_txpower(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, @@ -335,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; @@ -348,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 090d08ff22c4..2d4235497f1b 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 3393ad5b8ab1..cbde5cc49a40 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -10,6 +10,7 @@ #include <linux/kernel.h> #include <linux/device.h> #include <linux/if.h> +#include <linux/if_ether.h> #include <linux/interrupt.h> #include <linux/netdevice.h> #include <linux/rtnetlink.h> @@ -167,7 +168,29 @@ 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); + +static ssize_t +ieee80211_if_fmt_hw_queues(const struct ieee80211_sub_if_data *sdata, + char *buf, int buflen) +{ + int len; + + len = scnprintf(buf, buflen, "AC queues: VO:%d VI:%d BE:%d BK:%d\n", + sdata->vif.hw_queue[IEEE80211_AC_VO], + sdata->vif.hw_queue[IEEE80211_AC_VI], + sdata->vif.hw_queue[IEEE80211_AC_BE], + sdata->vif.hw_queue[IEEE80211_AC_BK]); + + if (sdata->vif.type == NL80211_IFTYPE_AP) + len += scnprintf(buf + len, buflen - len, "cab queue: %d\n", + sdata->vif.cab_queue); + + return len; +} +__IEEE80211_IF_FILE(hw_queues, NULL); /* STA attributes */ IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC); @@ -245,27 +268,6 @@ static ssize_t ieee80211_if_fmt_tkip_mic_test( return -EOPNOTSUPP; } -static int hwaddr_aton(const char *txt, u8 *addr) -{ - int i; - - for (i = 0; i < ETH_ALEN; i++) { - int a, b; - - a = hex_to_bin(*txt++); - if (a < 0) - return -1; - b = hex_to_bin(*txt++); - if (b < 0) - return -1; - *addr++ = (a << 4) | b; - if (i < 5 && *txt++ != ':') - return -1; - } - - return 0; -} - static ssize_t ieee80211_if_parse_tkip_mic_test( struct ieee80211_sub_if_data *sdata, const char *buf, int buflen) { @@ -275,13 +277,7 @@ static ssize_t ieee80211_if_parse_tkip_mic_test( struct ieee80211_hdr *hdr; __le16 fc; - /* - * Assume colon-delimited MAC address with possible white space - * following. - */ - if (buflen < 3 * ETH_ALEN - 1) - return -EINVAL; - if (hwaddr_aton(buf, addr) < 0) + if (!mac_pton(buf, addr)) return -EINVAL; if (!ieee80211_sdata_running(sdata)) @@ -307,13 +303,16 @@ static ssize_t ieee80211_if_parse_tkip_mic_test( case NL80211_IFTYPE_STATION: fc |= cpu_to_le16(IEEE80211_FCTL_TODS); /* BSSID SA DA */ - if (sdata->vif.bss_conf.bssid == NULL) { + mutex_lock(&sdata->u.mgd.mtx); + if (!sdata->u.mgd.associated) { + mutex_unlock(&sdata->u.mgd.mtx); dev_kfree_skb(skb); return -ENOTCONN; } - memcpy(hdr->addr1, sdata->vif.bss_conf.bssid, ETH_ALEN); + memcpy(hdr->addr1, sdata->u.mgd.associated->bssid, ETH_ALEN); memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN); memcpy(hdr->addr3, addr, ETH_ALEN); + mutex_unlock(&sdata->u.mgd.mtx); break; default: dev_kfree_skb(skb); @@ -443,7 +442,7 @@ static ssize_t ieee80211_if_parse_tsf( } ret = kstrtoull(buf, 10, &tsf); if (ret < 0) - return -EINVAL; + return ret; if (tsf_is_delta) tsf = drv_get_tsf(local, sdata) + tsf_is_delta * tsf; if (local->ops->set_tsf) { @@ -531,6 +530,7 @@ static void add_common_files(struct ieee80211_sub_if_data *sdata) DEBUGFS_ADD(rc_rateidx_mask_5ghz); DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz); DEBUGFS_ADD(rc_rateidx_mcs_mask_5ghz); + DEBUGFS_ADD(hw_queues); } static void add_sta_files(struct ieee80211_sub_if_data *sdata) @@ -631,7 +631,9 @@ 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); if (sdata->vif.type != NL80211_IFTYPE_MONITOR) add_common_files(sdata); diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 5ccec2c1e9f6..89281d24b094 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 77407b31e1ff..c6560cc7a9d6 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; @@ -936,4 +968,39 @@ static inline void drv_unassign_vif_chanctx(struct ieee80211_local *local, trace_drv_return_void(local); } +static inline int drv_start_ap(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata) +{ + int ret = 0; + + check_sdata_in_driver(sdata); + + trace_drv_start_ap(local, sdata, &sdata->vif.bss_conf); + if (local->ops->start_ap) + ret = local->ops->start_ap(&local->hw, &sdata->vif); + trace_drv_return_int(local, ret); + return ret; +} + +static inline void drv_stop_ap(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata) +{ + check_sdata_in_driver(sdata); + + trace_drv_stop_ap(local, sdata); + if (local->ops->stop_ap) + local->ops->stop_ap(&local->hw, &sdata->vif); + trace_drv_return_void(local); +} + +static inline void drv_restart_complete(struct ieee80211_local *local) +{ + might_sleep(); + + trace_drv_restart_complete(local); + if (local->ops->restart_complete) + local->ops->restart_complete(&local->hw); + trace_drv_return_void(local); +} + #endif /* __MAC80211_DRIVER_OPS */ diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 4b4538d63925..a71d891794a4 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 c7386b2b767e..fa862b24a7e0 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 3026519b236a..5c0d5a6946c1 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -56,6 +56,9 @@ struct ieee80211_local; #define TU_TO_JIFFIES(x) (usecs_to_jiffies((x) * 1024)) #define TU_TO_EXP_TIME(x) (jiffies + TU_TO_JIFFIES(x)) +/* power level hasn't been configured (or set to automatic) */ +#define IEEE80211_UNSET_POWER_LEVEL INT_MIN + /* * Some APs experience problems when working with U-APSD. Decrease the * probability of that happening by using legacy mode for all ACs but VO. @@ -345,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; @@ -353,7 +355,7 @@ struct ieee80211_roc_work { u32 duration, req_duration; struct sk_buff *frame; - u64 mgmt_tx_cookie; + u64 cookie, mgmt_tx_cookie; }; /* flags used in struct ieee80211_if_managed.flags */ @@ -361,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), @@ -470,6 +472,8 @@ struct ieee80211_if_managed { u8 use_4addr; + u8 p2p_noa_index; + /* Signal strength from the last Beacon frame in the current BSS. */ int last_beacon_signal; @@ -743,6 +747,9 @@ struct ieee80211_sub_if_data { u8 needed_rx_chains; enum ieee80211_smps_mode smps_mode; + int user_power_level; /* in dBm */ + int ap_power_level; /* in dBm */ + /* * AP this belongs to: self in AP mode and * corresponding AP in VLAN mode, NULL for @@ -792,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; @@ -1040,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; @@ -1117,8 +1123,7 @@ struct ieee80211_local { int dynamic_ps_user_timeout; bool disable_dynamic_ps; - int user_power_level; /* in dBm */ - int ap_power_level; /* in dBm */ + int user_power_level; /* in dBm, for all interfaces */ enum ieee80211_smps_mode smps_mode; @@ -1137,6 +1142,7 @@ struct ieee80211_local { struct list_head roc_list; struct work_struct hw_roc_start, hw_roc_done; unsigned long hw_roc_start_time; + u64 roc_cookie_counter; struct idr ack_status_frames; spinlock_t ack_status_lock; @@ -1150,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 * @@ -1251,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, @@ -1365,6 +1381,9 @@ void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata, int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up); void ieee80211_sdata_stop(struct ieee80211_sub_if_data *sdata); +bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata); +void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata); + static inline bool ieee80211_sdata_running(struct ieee80211_sub_if_data *sdata) { return test_bit(SDATA_STATE_RUNNING, &sdata->state); @@ -1377,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, @@ -1494,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(); } @@ -1583,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); @@ -1596,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 bc3e3e1db093..5331662489f7 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -42,6 +42,41 @@ * by either the RTNL, the iflist_mtx or RCU. */ +bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_chanctx_conf *chanctx_conf; + int power; + + rcu_read_lock(); + chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + if (!chanctx_conf) { + rcu_read_unlock(); + return false; + } + + power = chanctx_conf->def.chan->max_power; + rcu_read_unlock(); + + if (sdata->user_power_level != IEEE80211_UNSET_POWER_LEVEL) + power = min(power, sdata->user_power_level); + + if (sdata->ap_power_level != IEEE80211_UNSET_POWER_LEVEL) + power = min(power, sdata->ap_power_level); + + if (power != sdata->vif.bss_conf.txpower) { + sdata->vif.bss_conf.txpower = power; + ieee80211_hw_config(sdata->local, 0); + return true; + } + + return false; +} + +void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata) +{ + if (__ieee80211_recalc_txpower(sdata)) + ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_TXPOWER); +} static u32 ieee80211_idle_off(struct ieee80211_local *local, const char *reason) @@ -380,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); @@ -744,31 +778,12 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, /* APs need special treatment */ if (sdata->vif.type == NL80211_IFTYPE_AP) { struct ieee80211_sub_if_data *vlan, *tmpsdata; - struct beacon_data *old_beacon = - rtnl_dereference(sdata->u.ap.beacon); - struct probe_resp *old_probe_resp = - rtnl_dereference(sdata->u.ap.probe_resp); - - /* sdata_running will return false, so this will disable */ - ieee80211_bss_info_change_notify(sdata, - BSS_CHANGED_BEACON_ENABLED); - - /* remove beacon and probe response */ - RCU_INIT_POINTER(sdata->u.ap.beacon, NULL); - RCU_INIT_POINTER(sdata->u.ap.probe_resp, NULL); - synchronize_rcu(); - kfree(old_beacon); - kfree(old_probe_resp); /* down all dependent devices, that is VLANs */ list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans, u.vlan.list) dev_close(vlan->dev); WARN_ON(!list_empty(&sdata->u.ap.vlans)); - - /* free all potentially still buffered bcast frames */ - local->total_ps_buffered -= skb_queue_len(&sdata->u.ap.ps.bc_buf); - skb_queue_purge(&sdata->u.ap.ps.bc_buf); } else if (sdata->vif.type == NL80211_IFTYPE_STATION) { ieee80211_mgd_stop(sdata); } @@ -1529,6 +1544,9 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, ieee80211_set_default_queues(sdata); + sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL; + sdata->user_power_level = local->user_power_level; + /* setup type-dependent data */ ieee80211_setup_sdata(sdata, type); diff --git a/net/mac80211/key.c b/net/mac80211/key.c index d27e61aaa71b..619c5d697999 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 7d4e31f037d7..7cff0d3a519c 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 fd8345c20051..f5e4c1f24bf2 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -95,11 +95,13 @@ static void ieee80211_reconfig_filter(struct work_struct *work) static u32 ieee80211_hw_conf_chan(struct ieee80211_local *local) { + struct ieee80211_sub_if_data *sdata; struct ieee80211_channel *chan; u32 changed = 0; int power; enum nl80211_channel_type channel_type; u32 offchannel_flag; + bool scanning = false; offchannel_flag = local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL; if (local->scan_channel) { @@ -113,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; @@ -146,16 +148,18 @@ static u32 ieee80211_hw_conf_chan(struct ieee80211_local *local) changed |= IEEE80211_CONF_CHANGE_SMPS; } - if (test_bit(SCAN_SW_SCANNING, &local->scanning) || - test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning) || - test_bit(SCAN_HW_SCANNING, &local->scanning) || - !local->ap_power_level) - power = chan->max_power; - else - power = min(chan->max_power, local->ap_power_level); + scanning = test_bit(SCAN_SW_SCANNING, &local->scanning) || + test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning) || + test_bit(SCAN_HW_SCANNING, &local->scanning); + power = chan->max_power; - if (local->user_power_level >= 0) - power = min(power, local->user_power_level); + rcu_read_lock(); + list_for_each_entry_rcu(sdata, &local->interfaces, list) { + if (!rcu_access_pointer(sdata->vif.chanctx_conf)) + continue; + power = min(power, sdata->vif.bss_conf.txpower); + } + rcu_read_unlock(); if (local->hw.conf.power_level != power) { changed |= IEEE80211_CONF_CHANGE_POWER; @@ -600,7 +604,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, wiphy->features |= NL80211_FEATURE_SK_TX_STATUS | NL80211_FEATURE_SAE | - NL80211_FEATURE_HT_IBSS; + NL80211_FEATURE_HT_IBSS | + NL80211_FEATURE_VIF_TXPOWER; if (!ops->hw_scan) wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN | @@ -633,7 +638,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, local->hw.radiotap_mcs_details = IEEE80211_RADIOTAP_MCS_HAVE_MCS | IEEE80211_RADIOTAP_MCS_HAVE_GI | IEEE80211_RADIOTAP_MCS_HAVE_BW; - local->user_power_level = -1; + local->user_power_level = IEEE80211_UNSET_POWER_LEVEL; wiphy->ht_capa_mod_mask = &mac80211_ht_capa_mod_mask; INIT_LIST_HEAD(&local->interfaces); @@ -793,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) @@ -879,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; @@ -920,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 a350cab4b339..1bf03f9ff3ba 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 9285f3f67e66..7c9215fb2ac8 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 234fe755968b..ca52dfdd5375 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 407c8705e10d..0f40086cce18 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 1d1fdf0791f0..d2a4f78b4b0f 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); @@ -820,10 +822,10 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, cbss->beacon_interval)); } -static void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, - struct ieee80211_channel *channel, - const u8 *country_ie, u8 country_ie_len, - const u8 *pwr_constr_elem) +static u32 ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, + struct ieee80211_channel *channel, + const u8 *country_ie, u8 country_ie_len, + const u8 *pwr_constr_elem) { struct ieee80211_country_ie_triplet *triplet; int chan = ieee80211_frequency_to_channel(channel->center_freq); @@ -832,7 +834,7 @@ static void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, /* Invalid IE */ if (country_ie_len % 2 || country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN) - return; + return 0; triplet = (void *)(country_ie + 3); country_ie_len -= 3; @@ -873,19 +875,21 @@ static void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, } if (!have_chan_pwr) - return; + return 0; new_ap_level = max_t(int, 0, chan_pwr - *pwr_constr_elem); - if (sdata->local->ap_power_level == new_ap_level) - return; + if (sdata->ap_power_level == new_ap_level) + return 0; sdata_info(sdata, "Limiting TX power to %d (%d - %d) dBm as advertised by %pM\n", new_ap_level, chan_pwr, *pwr_constr_elem, sdata->u.mgd.bssid); - sdata->local->ap_power_level = new_ap_level; - ieee80211_hw_config(sdata->local, 0); + sdata->ap_power_level = new_ap_level; + if (__ieee80211_recalc_txpower(sdata)) + return BSS_CHANGED_TXPOWER; + return 0; } void ieee80211_enable_dyn_ps(struct ieee80211_vif *vif) @@ -1363,6 +1367,22 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, sdata->u.mgd.flags |= IEEE80211_STA_RESET_SIGNAL_AVE; + if (sdata->vif.p2p) { + u8 noa[2]; + int ret; + + ret = cfg80211_get_p2p_attr(cbss->information_elements, + cbss->len_information_elements, + IEEE80211_P2P_ATTR_ABSENCE_NOTICE, + noa, sizeof(noa)); + if (ret >= 2) { + bss_conf->p2p_oppps = noa[1] & 0x80; + bss_conf->p2p_ctwindow = noa[1] & 0x7f; + bss_info_changed |= BSS_CHANGED_P2P_PS; + sdata->u.mgd.p2p_noa_index = noa[0]; + } + } + /* just to be sure */ ieee80211_stop_poll(sdata); @@ -1485,11 +1505,14 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, changed |= BSS_CHANGED_ASSOC; sdata->vif.bss_conf.assoc = false; + sdata->vif.bss_conf.p2p_ctwindow = 0; + sdata->vif.bss_conf.p2p_oppps = false; + /* on the next assoc, re-program HT parameters */ memset(&ifmgd->ht_capa, 0, sizeof(ifmgd->ht_capa)); memset(&ifmgd->ht_capa_mask, 0, sizeof(ifmgd->ht_capa_mask)); - local->ap_power_level = 0; + sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL; del_timer_sync(&local->dynamic_ps_timer); cancel_work_sync(&local->dynamic_ps_enable_work); @@ -1507,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); @@ -1518,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, @@ -1843,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); } @@ -2085,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); } @@ -2149,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); @@ -2201,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); @@ -2452,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 && @@ -2592,6 +2618,27 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, } } + if (sdata->vif.p2p) { + u8 noa[2]; + int ret; + + ret = cfg80211_get_p2p_attr(mgmt->u.beacon.variable, + len - baselen, + IEEE80211_P2P_ATTR_ABSENCE_NOTICE, + noa, sizeof(noa)); + if (ret >= 2 && sdata->u.mgd.p2p_noa_index != noa[0]) { + bss_conf->p2p_oppps = noa[1] & 0x80; + bss_conf->p2p_ctwindow = noa[1] & 0x7f; + changed |= BSS_CHANGED_P2P_PS; + sdata->u.mgd.p2p_noa_index = noa[0]; + /* + * make sure we update all information, the CRC + * mechanism doesn't look at P2P attributes. + */ + ifmgd->beacon_crc_valid = false; + } + } + if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid) return; ifmgd->beacon_crc = ncrc; @@ -2616,17 +2663,17 @@ 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); if (elems.country_elem && elems.pwr_constr_elem && mgmt->u.probe_resp.capab_info & cpu_to_le16(WLAN_CAPABILITY_SPECTRUM_MGMT)) - ieee80211_handle_pwr_constr(sdata, chan, - elems.country_elem, - elems.country_elem_len, - elems.pwr_constr_elem); + changed |= ieee80211_handle_pwr_constr(sdata, chan, + elems.country_elem, + elems.country_elem_len, + elems.pwr_constr_elem); ieee80211_bss_info_change_notify(sdata, changed); } @@ -3146,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]; @@ -3177,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 @@ -3195,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, @@ -3220,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); } @@ -3488,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; /* @@ -3508,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"); @@ -3516,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; } @@ -3524,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"); @@ -3569,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)) { @@ -3660,40 +3708,44 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; bool tx = !req->local_state_change; + bool sent_frame = false; mutex_lock(&ifmgd->mtx); - if (ifmgd->auth_data) { - ieee80211_destroy_auth_data(sdata, false); - mutex_unlock(&ifmgd->mtx); - return 0; - } - sdata_info(sdata, "deauthenticating from %pM by local choice (reason=%d)\n", req->bssid, req->reason_code); - if (ifmgd->associated && - ether_addr_equal(ifmgd->associated->bssid, req->bssid)) { - ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, - req->reason_code, tx, frame_buf); - } else { + if (ifmgd->auth_data) { drv_mgd_prepare_tx(sdata->local, sdata); ieee80211_send_deauth_disassoc(sdata, req->bssid, IEEE80211_STYPE_DEAUTH, req->reason_code, tx, frame_buf); + ieee80211_destroy_auth_data(sdata, false); + mutex_unlock(&ifmgd->mtx); + + sent_frame = tx; + goto out; } + if (ifmgd->associated && + ether_addr_equal(ifmgd->associated->bssid, req->bssid)) { + ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, + req->reason_code, tx, frame_buf); + sent_frame = tx; + } mutex_unlock(&ifmgd->mtx); - __cfg80211_send_deauth(sdata->dev, frame_buf, - IEEE80211_DEAUTH_FRAME_LEN); - + out: mutex_lock(&sdata->local->mtx); ieee80211_recalc_idle(sdata->local); mutex_unlock(&sdata->local->mtx); + if (sent_frame) + __cfg80211_send_deauth(sdata->dev, frame_buf, + IEEE80211_DEAUTH_FRAME_LEN); + return 0; } diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index c349f3aaf59e..5abddfe3e101 100644 --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c @@ -204,9 +204,9 @@ void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc) roc->frame = NULL; } } else { - cfg80211_ready_on_channel(&roc->sdata->wdev, (unsigned long)roc, - roc->chan, roc->chan_type, - roc->req_duration, GFP_KERNEL); + cfg80211_ready_on_channel(&roc->sdata->wdev, roc->cookie, + 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; @@ -320,8 +319,7 @@ void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc) if (!roc->mgmt_tx_cookie) cfg80211_remain_on_channel_expired(&roc->sdata->wdev, - (unsigned long)roc, - roc->chan, roc->chan_type, + roc->cookie, roc->chan, GFP_KERNEL); list_for_each_entry_safe(dep, tmp, &roc->dependents, list) @@ -360,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 9f404ac901ab..79a48f37d409 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; @@ -135,14 +136,55 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); - /* the interface is leaving the channel and is removed */ - ieee80211_vif_release_channel(sdata); + if (sdata->vif.type == NL80211_IFTYPE_AP && + rcu_access_pointer(sdata->u.ap.beacon)) + drv_stop_ap(local, 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 3313c117b322..dd88381c53b7 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 ec198ef6aa8a..301386dabf88 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 8c1f1527d671..825f33cf7bbc 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,20 +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) +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) && @@ -74,32 +81,48 @@ static inline int should_drop_frame(struct sk_buff *skb, } 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; } @@ -118,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); @@ -128,17 +156,30 @@ 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); + 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); - rthdr->it_present |= - cpu_to_le32(1 << IEEE80211_RADIOTAP_TSFT); + 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; } @@ -152,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, @@ -172,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) @@ -205,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); @@ -255,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; + } } /* @@ -283,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; } @@ -374,7 +430,6 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, return origskb; } - static void ieee80211_parse_qos(struct ieee80211_rx_data *rx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; @@ -403,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; } @@ -481,8 +536,7 @@ static int ieee80211_get_mmie_keyidx(struct sk_buff *skb) struct ieee80211_mgmt *hdr = (struct ieee80211_mgmt *) skb->data; struct ieee80211_mmie *mmie; - if (skb->len < 24 + sizeof(*mmie) || - !is_multicast_ether_addr(hdr->da)) + if (skb->len < 24 + sizeof(*mmie) || !is_multicast_ether_addr(hdr->da)) return -1; if (!ieee80211_is_robust_mgmt_frame((struct ieee80211_hdr *) hdr)) @@ -497,9 +551,7 @@ static int ieee80211_get_mmie_keyidx(struct sk_buff *skb) return le16_to_cpu(mmie->key_id); } - -static ieee80211_rx_result -ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) +static ieee80211_rx_result ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; char *dev_addr = rx->sdata->vif.addr; @@ -507,7 +559,7 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) if (ieee80211_is_data(hdr->frame_control)) { if (is_multicast_ether_addr(hdr->addr1)) { if (ieee80211_has_tods(hdr->frame_control) || - !ieee80211_has_fromds(hdr->frame_control)) + !ieee80211_has_fromds(hdr->frame_control)) return RX_DROP_MONITOR; if (ether_addr_equal(hdr->addr3, dev_addr)) return RX_DROP_MONITOR; @@ -539,7 +591,7 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) mgmt = (struct ieee80211_mgmt *)hdr; category = mgmt->u.action.category; if (category != WLAN_CATEGORY_MESH_ACTION && - category != WLAN_CATEGORY_SELF_PROTECTED) + category != WLAN_CATEGORY_SELF_PROTECTED) return RX_DROP_MONITOR; return RX_CONTINUE; } @@ -551,7 +603,6 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) return RX_CONTINUE; return RX_DROP_MONITOR; - } return RX_CONTINUE; @@ -575,7 +626,6 @@ static inline u16 seq_sub(u16 sq1, u16 sq2) return (sq1 - sq2) & SEQ_MASK; } - static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata, struct tid_ampdu_rx *tid_agg_rx, int index) @@ -1291,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)) { @@ -1313,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; } } @@ -1585,18 +1641,15 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) return RX_CONTINUE; } -static int -ieee80211_802_1x_port_control(struct ieee80211_rx_data *rx) +static int ieee80211_802_1x_port_control(struct ieee80211_rx_data *rx) { - if (unlikely(!rx->sta || - !test_sta_flag(rx->sta, WLAN_STA_AUTHORIZED))) + if (unlikely(!rx->sta || !test_sta_flag(rx->sta, WLAN_STA_AUTHORIZED))) return -EACCES; return 0; } -static int -ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc) +static int ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc) { struct sk_buff *skb = rx->skb; struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); @@ -1618,8 +1671,7 @@ ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc) return 0; } -static int -ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx) +static int ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); @@ -2003,7 +2055,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) } else { /* unable to resolve next hop */ mesh_path_error_tx(ifmsh->mshcfg.element_ttl, fwd_hdr->addr3, - 0, reason, fwd_hdr->addr2, sdata); + 0, reason, fwd_hdr->addr2, sdata); IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_no_route); kfree_skb(fwd_skb); return RX_DROP_MONITOR; @@ -2212,7 +2264,7 @@ ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx) cfg80211_report_obss_beacon(rx->local->hw.wiphy, rx->skb->data, rx->skb->len, - status->freq, sig, GFP_ATOMIC); + status->freq, sig); rx->flags |= IEEE80211_RX_BEACON_REPORTED; } @@ -2412,7 +2464,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) if (!ieee80211_vif_is_mesh(&sdata->vif)) break; if (mesh_action_is_path_sel(mgmt) && - (!mesh_path_sel_is_hwmp(sdata))) + !mesh_path_sel_is_hwmp(sdata)) break; goto queue; } @@ -2468,7 +2520,6 @@ ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx) return RX_QUEUED; } - return RX_CONTINUE; } @@ -2598,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)) @@ -2661,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); @@ -2828,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, @@ -3105,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 13d23299e696..f3340279aba3 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 f7bb54f9ab72..f3e502502fee 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 c88f161f8118..6835cea4e402 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 21fa5c72ea14..ab63237107c8 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -325,6 +325,75 @@ static void ieee80211_add_tx_radiotap_header(struct ieee80211_supported_band } +static void ieee80211_report_used_skb(struct ieee80211_local *local, + struct sk_buff *skb, bool dropped) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_hdr *hdr = (void *)skb->data; + bool acked = info->flags & IEEE80211_TX_STAT_ACK; + + if (dropped) + acked = false; + + if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) { + struct ieee80211_sub_if_data *sdata = NULL; + struct ieee80211_sub_if_data *iter_sdata; + u64 cookie = (unsigned long)skb; + + rcu_read_lock(); + + if (skb->dev) { + list_for_each_entry_rcu(iter_sdata, &local->interfaces, + list) { + if (!iter_sdata->dev) + continue; + + if (skb->dev == iter_sdata->dev) { + sdata = iter_sdata; + break; + } + } + } else { + sdata = rcu_dereference(local->p2p_sdata); + } + + if (!sdata) + skb->dev = NULL; + else if (ieee80211_is_nullfunc(hdr->frame_control) || + ieee80211_is_qos_nullfunc(hdr->frame_control)) { + cfg80211_probe_status(sdata->dev, hdr->addr1, + cookie, acked, GFP_ATOMIC); + } else { + cfg80211_mgmt_tx_status(&sdata->wdev, cookie, skb->data, + skb->len, acked, GFP_ATOMIC); + } + + rcu_read_unlock(); + } + + if (unlikely(info->ack_frame_id)) { + struct sk_buff *ack_skb; + unsigned long flags; + + spin_lock_irqsave(&local->ack_status_lock, flags); + ack_skb = idr_find(&local->ack_status_frames, + info->ack_frame_id); + if (ack_skb) + idr_remove(&local->ack_status_frames, + info->ack_frame_id); + spin_unlock_irqrestore(&local->ack_status_lock, flags); + + if (ack_skb) { + if (!dropped) { + /* consumes ack_skb */ + skb_complete_wifi_ack(ack_skb, acked); + } else { + dev_kfree_skb_any(ack_skb); + } + } + } +} + /* * Use a static threshold for now, best value to be determined * by testing ... @@ -516,62 +585,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) msecs_to_jiffies(10)); } - if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) { - u64 cookie = (unsigned long)skb; - bool found = false; - - acked = info->flags & IEEE80211_TX_STAT_ACK; - - rcu_read_lock(); - - list_for_each_entry_rcu(sdata, &local->interfaces, list) { - if (!sdata->dev) - continue; - - if (skb->dev != sdata->dev) - continue; - - found = true; - break; - } - - if (!skb->dev) { - sdata = rcu_dereference(local->p2p_sdata); - if (sdata) - found = true; - } - - if (!found) - skb->dev = NULL; - else if (ieee80211_is_nullfunc(hdr->frame_control) || - ieee80211_is_qos_nullfunc(hdr->frame_control)) { - cfg80211_probe_status(sdata->dev, hdr->addr1, - cookie, acked, GFP_ATOMIC); - } else { - cfg80211_mgmt_tx_status(&sdata->wdev, cookie, skb->data, - skb->len, acked, GFP_ATOMIC); - } - - rcu_read_unlock(); - } - - if (unlikely(info->ack_frame_id)) { - struct sk_buff *ack_skb; - unsigned long flags; - - spin_lock_irqsave(&local->ack_status_lock, flags); - ack_skb = idr_find(&local->ack_status_frames, - info->ack_frame_id); - if (ack_skb) - idr_remove(&local->ack_status_frames, - info->ack_frame_id); - spin_unlock_irqrestore(&local->ack_status_lock, flags); - - /* consumes ack_skb */ - if (ack_skb) - skb_complete_wifi_ack(ack_skb, - info->flags & IEEE80211_TX_STAT_ACK); - } + ieee80211_report_used_skb(local, skb, false); /* this was a transmitted frame, but now we want to reuse it */ skb_orphan(skb); @@ -647,25 +661,17 @@ EXPORT_SYMBOL(ieee80211_report_low_ack); void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb) { struct ieee80211_local *local = hw_to_local(hw); - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - - if (unlikely(info->ack_frame_id)) { - struct sk_buff *ack_skb; - unsigned long flags; - - spin_lock_irqsave(&local->ack_status_lock, flags); - ack_skb = idr_find(&local->ack_status_frames, - info->ack_frame_id); - if (ack_skb) - idr_remove(&local->ack_status_frames, - info->ack_frame_id); - spin_unlock_irqrestore(&local->ack_status_lock, flags); - - /* consumes ack_skb */ - if (ack_skb) - dev_kfree_skb_any(ack_skb); - } + ieee80211_report_used_skb(local, skb, true); 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 0638541b625f..a8270b441a6f 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); @@ -342,6 +348,9 @@ TRACE_EVENT(drv_bss_info_changed, __field(bool, ps); __dynamic_array(u8, ssid, info->ssid_len); __field(bool, hidden_ssid); + __field(int, txpower) + __field(u8, p2p_ctwindow) + __field(bool, p2p_oppps) ), TP_fast_assign( @@ -367,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; @@ -376,6 +386,9 @@ TRACE_EVENT(drv_bss_info_changed, __entry->ps = info->ps; memcpy(__get_dynamic_array(ssid), info->ssid, info->ssid_len); __entry->hidden_ssid = info->hidden_ssid; + __entry->txpower = info->txpower; + __entry->p2p_ctwindow = info->p2p_ctwindow; + __entry->p2p_oppps = info->p2p_oppps; ), TP_printk( @@ -1013,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 ) ); @@ -1043,34 +1059,6 @@ DEFINE_EVENT(local_only_evt, drv_cancel_remain_on_channel, TP_ARGS(local) ); -TRACE_EVENT(drv_offchannel_tx, - TP_PROTO(struct ieee80211_local *local, struct sk_buff *skb, - struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type, - unsigned int wait), - - TP_ARGS(local, skb, chan, channel_type, wait), - - TP_STRUCT__entry( - LOCAL_ENTRY - __field(int, center_freq) - __field(int, channel_type) - __field(unsigned int, wait) - ), - - TP_fast_assign( - LOCAL_ASSIGN; - __entry->center_freq = chan->center_freq; - __entry->channel_type = channel_type; - __entry->wait = wait; - ), - - TP_printk( - LOCAL_PR_FMT " freq:%dMHz, wait:%dms", - LOCAL_PR_ARG, __entry->center_freq, __entry->wait - ) -); - TRACE_EVENT(drv_set_ringparam, TP_PROTO(struct ieee80211_local *local, u32 tx, u32 rx), @@ -1396,6 +1384,48 @@ DEFINE_EVENT(local_sdata_chanctx, drv_unassign_vif_chanctx, TP_ARGS(local, sdata, ctx) ); +TRACE_EVENT(drv_start_ap, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + struct ieee80211_bss_conf *info), + + TP_ARGS(local, sdata, info), + + TP_STRUCT__entry( + LOCAL_ENTRY + VIF_ENTRY + __field(u8, dtimper) + __field(u16, bcnint) + __dynamic_array(u8, ssid, info->ssid_len); + __field(bool, hidden_ssid); + ), + + TP_fast_assign( + LOCAL_ASSIGN; + VIF_ASSIGN; + __entry->dtimper = info->dtim_period; + __entry->bcnint = info->beacon_int; + memcpy(__get_dynamic_array(ssid), info->ssid, info->ssid_len); + __entry->hidden_ssid = info->hidden_ssid; + ), + + TP_printk( + LOCAL_PR_FMT VIF_PR_FMT, + LOCAL_PR_ARG, VIF_PR_ARG + ) +); + +DEFINE_EVENT(local_sdata_evt, drv_stop_ap, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata), + TP_ARGS(local, sdata) +); + +DEFINE_EVENT(local_only_evt, drv_restart_complete, + TP_PROTO(struct ieee80211_local *local), + TP_ARGS(local) +); + /* * Tracing for API calls that drivers call. */ diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 065f81cb5618..d287a4f2c01b 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; @@ -2089,6 +2089,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, head_need = max_t(int, 0, head_need); if (ieee80211_skb_resize(sdata, skb, head_need, true)) { ieee80211_free_txskb(&local->hw, skb); + skb = NULL; goto fail_rcu; } } @@ -2160,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); + } } /* @@ -2190,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; @@ -2454,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) || @@ -2473,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); @@ -2753,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 9556391b05d7..08132ff98155 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -512,7 +512,7 @@ void ieee80211_wake_queues(struct ieee80211_hw *hw) EXPORT_SYMBOL(ieee80211_wake_queues); void ieee80211_iterate_active_interfaces( - struct ieee80211_hw *hw, + struct ieee80211_hw *hw, u32 iter_flags, void (*iterator)(void *data, u8 *mac, struct ieee80211_vif *vif), void *data) @@ -530,6 +530,9 @@ void ieee80211_iterate_active_interfaces( default: break; } + if (!(iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL) && + !(sdata->flags & IEEE80211_SDATA_IN_DRIVER)) + continue; if (ieee80211_sdata_running(sdata)) iterator(data, sdata->vif.addr, &sdata->vif); @@ -537,7 +540,9 @@ void ieee80211_iterate_active_interfaces( sdata = rcu_dereference_protected(local->monitor_sdata, lockdep_is_held(&local->iflist_mtx)); - if (sdata) + if (sdata && + (iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL || + sdata->flags & IEEE80211_SDATA_IN_DRIVER)) iterator(data, sdata->vif.addr, &sdata->vif); mutex_unlock(&local->iflist_mtx); @@ -545,7 +550,7 @@ void ieee80211_iterate_active_interfaces( EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces); void ieee80211_iterate_active_interfaces_atomic( - struct ieee80211_hw *hw, + struct ieee80211_hw *hw, u32 iter_flags, void (*iterator)(void *data, u8 *mac, struct ieee80211_vif *vif), void *data) @@ -563,13 +568,18 @@ void ieee80211_iterate_active_interfaces_atomic( default: break; } + if (!(iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL) && + !(sdata->flags & IEEE80211_SDATA_IN_DRIVER)) + continue; if (ieee80211_sdata_running(sdata)) iterator(data, sdata->vif.addr, &sdata->vif); } sdata = rcu_dereference(local->monitor_sdata); - if (sdata) + if (sdata && + (iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL || + sdata->flags & IEEE80211_SDATA_IN_DRIVER)) iterator(data, sdata->vif.addr, &sdata->vif); rcu_read_unlock(); @@ -888,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(); @@ -981,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 @@ -1407,10 +1417,44 @@ 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; + + if (!ieee80211_sdata_running(sdata)) + continue; + + 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); + } + + 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); @@ -1452,22 +1496,11 @@ int ieee80211_reconfig(struct ieee80211_local *local) /* Finally also reconfigure all the BSS information */ list_for_each_entry(sdata, &local->interfaces, list) { - struct ieee80211_chanctx_conf *ctx_conf; u32 changed; if (!ieee80211_sdata_running(sdata)) continue; - 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); - /* common change flags for all interface types */ changed = BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_ERP_PREAMBLE | @@ -1478,7 +1511,8 @@ int ieee80211_reconfig(struct ieee80211_local *local) BSS_CHANGED_BSSID | BSS_CHANGED_CQM | BSS_CHANGED_QOS | - BSS_CHANGED_IDLE; + BSS_CHANGED_IDLE | + BSS_CHANGED_TXPOWER; switch (sdata->vif.type) { case NL80211_IFTYPE_STATION: @@ -1495,9 +1529,13 @@ int ieee80211_reconfig(struct ieee80211_local *local) case NL80211_IFTYPE_AP: changed |= BSS_CHANGED_SSID; - if (sdata->vif.type == NL80211_IFTYPE_AP) + if (sdata->vif.type == NL80211_IFTYPE_AP) { changed |= BSS_CHANGED_AP_PROBE_RESP; + if (rcu_access_pointer(sdata->u.ap.beacon)) + drv_start_ap(local, sdata); + } + /* fall through */ case NL80211_IFTYPE_MESH_POINT: changed |= BSS_CHANGED_BEACON | @@ -1534,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); } @@ -1594,8 +1634,10 @@ int ieee80211_reconfig(struct ieee80211_local *local) * If this is for hw restart things are still running. * We may want to change that later, however. */ - if (!local->suspended) + if (!local->suspended) { + drv_restart_complete(local); return 0; + } #ifdef CONFIG_PM /* first set suspended false, then resuming */ @@ -1831,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; @@ -1840,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); @@ -1870,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: @@ -1892,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, @@ -1990,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 cea06e9f26f4..906f00cd6d2f 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 07659cfd6d7b..7d99410e6c1a 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 bc571b0efb92..7bea574d5934 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 ed2d17312d61..df24be48d4da 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 f6804532047a..2df87056c6df 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/Kconfig b/net/wireless/Kconfig index fe4adb12b3ef..16d08b399210 100644 --- a/net/wireless/Kconfig +++ b/net/wireless/Kconfig @@ -140,14 +140,13 @@ config CFG80211_WEXT extensions with cfg80211-based drivers. config LIB80211 - tristate "Common routines for IEEE802.11 drivers" + tristate default n help This options enables a library of common routines used by IEEE802.11 wireless LAN drivers. - Drivers should select this themselves if needed. Say Y if - you want this built into your kernel. + Drivers should select this themselves if needed. config LIB80211_CRYPT_WEP tristate diff --git a/net/wireless/ap.c b/net/wireless/ap.c index e143505f05bc..324e8d851dc4 100644 --- a/net/wireless/ap.c +++ b/net/wireless/ap.c @@ -28,6 +28,7 @@ static int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev, if (!err) { wdev->beacon_interval = 0; wdev->channel = NULL; + wdev->ssid_len = 0; } return err; diff --git a/net/wireless/chan.c b/net/wireless/chan.c index 48febd2160ba..bf2dfd54ff3b 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.c b/net/wireless/core.c index 26711f46a3be..14d990400354 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -326,6 +326,8 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) mutex_init(&rdev->devlist_mtx); mutex_init(&rdev->sched_scan_mtx); INIT_LIST_HEAD(&rdev->wdev_list); + INIT_LIST_HEAD(&rdev->beacon_registrations); + spin_lock_init(&rdev->beacon_registrations_lock); spin_lock_init(&rdev->bss_lock); INIT_LIST_HEAD(&rdev->bss_list); INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done); @@ -698,10 +700,15 @@ EXPORT_SYMBOL(wiphy_unregister); void cfg80211_dev_free(struct cfg80211_registered_device *rdev) { struct cfg80211_internal_bss *scan, *tmp; + struct cfg80211_beacon_registration *reg, *treg; rfkill_destroy(rdev->rfkill); mutex_destroy(&rdev->mtx); mutex_destroy(&rdev->devlist_mtx); mutex_destroy(&rdev->sched_scan_mtx); + list_for_each_entry_safe(reg, treg, &rdev->beacon_registrations, list) { + list_del(®->list); + kfree(reg); + } list_for_each_entry_safe(scan, tmp, &rdev->bss_list, list) cfg80211_put_bss(&scan->pub); kfree(rdev); diff --git a/net/wireless/core.h b/net/wireless/core.h index b8eb743fe7da..a0c8decf6a47 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -55,7 +55,8 @@ struct cfg80211_registered_device { int opencount; /* also protected by devlist_mtx */ wait_queue_head_t dev_wait; - u32 ap_beacons_nlportid; + struct list_head beacon_registrations; + spinlock_t beacon_registrations_lock; /* protected by RTNL only */ int num_running_ifaces; @@ -260,6 +261,10 @@ enum cfg80211_chan_mode { CHAN_MODE_EXCLUSIVE, }; +struct cfg80211_beacon_registration { + struct list_head list; + u32 nlportid; +}; /* free object */ extern void cfg80211_dev_free(struct cfg80211_registered_device *rdev); @@ -304,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, @@ -373,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); @@ -467,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, @@ -483,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 27941d5db72b..9b9551e4a6f9 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 966cfc4cd79d..3ee5a7282283 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 4bfd14f7c592..5e8123ee63fd 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 8c0857815a90..d038fa45ecd1 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 }, @@ -1110,6 +1115,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 portid, u32 seq, int flag goto nla_put_failure; } CMD(start_p2p_device, START_P2P_DEVICE); + CMD(set_mcast_rate, SET_MCAST_RATE); #ifdef CONFIG_NL80211_TESTMODE CMD(testmode_cmd, TESTMODE); @@ -1359,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) { @@ -1413,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; @@ -1516,10 +1606,8 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) result = 0; mutex_lock(&rdev->mtx); - } else if (nl80211_can_set_dev_channel(netdev->ieee80211_ptr)) + } else wdev = netdev->ieee80211_ptr; - else - wdev = NULL; /* * end workaround code, by now the rdev is available @@ -1579,15 +1667,21 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) } if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { - result = __nl80211_set_channel(rdev, wdev, info); + result = __nl80211_set_channel(rdev, + nl80211_can_set_dev_channel(wdev) ? wdev : NULL, + info); if (result) goto bad_res; } if (info->attrs[NL80211_ATTR_WIPHY_TX_POWER_SETTING]) { + struct wireless_dev *txp_wdev = wdev; enum nl80211_tx_power_setting type; int idx, mbm = 0; + if (!(rdev->wiphy.features & NL80211_FEATURE_VIF_TXPOWER)) + txp_wdev = NULL; + if (!rdev->ops->set_tx_power) { result = -EOPNOTSUPP; goto bad_res; @@ -1607,7 +1701,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) mbm = nla_get_u32(info->attrs[idx]); } - result = rdev_set_tx_power(rdev, type, mbm); + result = rdev_set_tx_power(rdev, txp_wdev, type, mbm); if (result) goto bad_res; } @@ -1744,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) @@ -1770,15 +1893,18 @@ 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))) + 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) { + if (nla_put(msg, NL80211_ATTR_SSID, wdev->ssid_len, wdev->ssid)) goto nla_put_failure; } @@ -2482,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; } @@ -2608,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); @@ -2640,10 +2754,11 @@ 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); } return err; } @@ -2775,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, @@ -5318,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; @@ -5354,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]; @@ -5393,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); @@ -5415,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; } @@ -5444,6 +5564,36 @@ static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info) return cfg80211_leave_ibss(rdev, dev, false); } +static int nl80211_set_mcast_rate(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + int mcast_rate[IEEE80211_NUM_BANDS]; + u32 nla_rate; + int err; + + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) + return -EOPNOTSUPP; + + if (!rdev->ops->set_mcast_rate) + return -EOPNOTSUPP; + + memset(mcast_rate, 0, sizeof(mcast_rate)); + + if (!info->attrs[NL80211_ATTR_MCAST_RATE]) + return -EINVAL; + + nla_rate = nla_get_u32(info->attrs[NL80211_ATTR_MCAST_RATE]); + if (!nl80211_parse_mcast_rate(rdev, mcast_rate, nla_rate)) + return -EINVAL; + + err = rdev->ops->set_mcast_rate(&rdev->wiphy, dev, mcast_rate); + + return err; +} + + #ifdef CONFIG_NL80211_TESTMODE static struct genl_multicast_group nl80211_testmode_mcgrp = { .name = "testmode", @@ -5906,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] || @@ -5932,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) @@ -5953,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; @@ -6173,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; @@ -6186,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) @@ -6222,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)) @@ -6235,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); @@ -6254,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); @@ -6519,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); @@ -6899,16 +7022,35 @@ static int nl80211_probe_client(struct sk_buff *skb, static int nl80211_register_beacons(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct cfg80211_beacon_registration *reg, *nreg; + int rv; if (!(rdev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS)) return -EOPNOTSUPP; - if (rdev->ap_beacons_nlportid) - return -EBUSY; + nreg = kzalloc(sizeof(*nreg), GFP_KERNEL); + if (!nreg) + return -ENOMEM; - rdev->ap_beacons_nlportid = info->snd_portid; + /* First, check if already registered. */ + spin_lock_bh(&rdev->beacon_registrations_lock); + list_for_each_entry(reg, &rdev->beacon_registrations, list) { + if (reg->nlportid == info->snd_portid) { + rv = -EALREADY; + goto out_err; + } + } + /* Add it to the list */ + nreg->nlportid = info->snd_portid; + list_add(&nreg->list, &rdev->beacon_registrations); + + spin_unlock_bh(&rdev->beacon_registrations_lock); return 0; +out_err: + spin_unlock_bh(&rdev->beacon_registrations_lock); + kfree(nreg); + return rv; } static int nl80211_start_p2p_device(struct sk_buff *skb, struct genl_info *info) @@ -7625,6 +7767,14 @@ static struct genl_ops nl80211_ops[] = { .internal_flags = NL80211_FLAG_NEED_WDEV_UP | NL80211_FLAG_NEED_RTNL, }, + { + .cmd = NL80211_CMD_SET_MCAST_RATE, + .doit = nl80211_set_mcast_rate, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, + }, }; static struct genl_multicast_group nl80211_mlme_mcgrp = { @@ -8326,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; @@ -8347,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; @@ -8369,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, @@ -8741,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; @@ -8757,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); @@ -8914,46 +9062,96 @@ EXPORT_SYMBOL(cfg80211_probe_status); void cfg80211_report_obss_beacon(struct wiphy *wiphy, const u8 *frame, size_t len, - int freq, int sig_dbm, gfp_t gfp) + int freq, int sig_dbm) { struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); struct sk_buff *msg; void *hdr; - u32 nlportid = ACCESS_ONCE(rdev->ap_beacons_nlportid); + struct cfg80211_beacon_registration *reg; trace_cfg80211_report_obss_beacon(wiphy, frame, len, freq, sig_dbm); - if (!nlportid) - return; + spin_lock_bh(&rdev->beacon_registrations_lock); + list_for_each_entry(reg, &rdev->beacon_registrations, list) { + msg = nlmsg_new(len + 100, GFP_ATOMIC); + if (!msg) { + spin_unlock_bh(&rdev->beacon_registrations_lock); + return; + } + + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME); + if (!hdr) + goto nla_put_failure; + + if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || + (freq && + nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq)) || + (sig_dbm && + nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) || + nla_put(msg, NL80211_ATTR_FRAME, len, frame)) + goto nla_put_failure; + + genlmsg_end(msg, hdr); - msg = nlmsg_new(len + 100, gfp); + genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, reg->nlportid); + } + spin_unlock_bh(&rdev->beacon_registrations_lock); + return; + + nla_put_failure: + spin_unlock_bh(&rdev->beacon_registrations_lock); + if (hdr) + genlmsg_cancel(msg, hdr); + nlmsg_free(msg); +} +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_FRAME); + 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) || - (freq && - nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq)) || - (sig_dbm && - nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) || - nla_put(msg, NL80211_ATTR_FRAME, len, frame)) + 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; - genlmsg_end(msg, hdr); + err = genlmsg_end(msg, hdr); + if (err < 0) { + nlmsg_free(msg); + return; + } - genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlportid); + 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_report_obss_beacon); +EXPORT_SYMBOL(cfg80211_tdls_oper_request); static int nl80211_netlink_notify(struct notifier_block * nb, unsigned long state, @@ -8962,6 +9160,7 @@ static int nl80211_netlink_notify(struct notifier_block * nb, struct netlink_notify *notify = _notify; struct cfg80211_registered_device *rdev; struct wireless_dev *wdev; + struct cfg80211_beacon_registration *reg, *tmp; if (state != NETLINK_URELEASE) return NOTIFY_DONE; @@ -8971,8 +9170,17 @@ static int nl80211_netlink_notify(struct notifier_block * nb, list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) { list_for_each_entry_rcu(wdev, &rdev->wdev_list, list) cfg80211_mlme_unregister_socket(wdev, notify->portid); - if (rdev->ap_beacons_nlportid == notify->portid) - rdev->ap_beacons_nlportid = 0; + + spin_lock_bh(&rdev->beacon_registrations_lock); + list_for_each_entry_safe(reg, tmp, &rdev->beacon_registrations, + list) { + if (reg->nlportid == notify->portid) { + list_del(®->list); + kfree(reg); + break; + } + } + spin_unlock_bh(&rdev->beacon_registrations_lock); } rcu_read_unlock(); diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index f6153516068c..2acba8477e9d 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 eb5f8974e148..6c0c8191f837 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; } @@ -476,21 +475,22 @@ rdev_set_wiphy_params(struct cfg80211_registered_device *rdev, u32 changed) } static inline int rdev_set_tx_power(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev, enum nl80211_tx_power_setting type, int mbm) { int ret; - trace_rdev_set_tx_power(&rdev->wiphy, type, mbm); - ret = rdev->ops->set_tx_power(&rdev->wiphy, type, mbm); + trace_rdev_set_tx_power(&rdev->wiphy, wdev, type, mbm); + ret = rdev->ops->set_tx_power(&rdev->wiphy, wdev, type, mbm); trace_rdev_return_int(&rdev->wiphy, ret); return ret; } static inline int rdev_get_tx_power(struct cfg80211_registered_device *rdev, - int *dbm) + struct wireless_dev *wdev, int *dbm) { int ret; - trace_rdev_get_tx_power(&rdev->wiphy); - ret = rdev->ops->get_tx_power(&rdev->wiphy, dbm); + trace_rdev_get_tx_power(&rdev->wiphy, wdev); + ret = rdev->ops->get_tx_power(&rdev->wiphy, wdev, dbm); trace_rdev_return_int_int(&rdev->wiphy, ret, *dbm); return ret; } @@ -599,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; } @@ -625,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; } @@ -847,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 bcc7d7ee5a51..b75756b05af7 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 7f97a087f452..9596015975d2 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 0ca71caf85fb..2134576f426e 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->identifier) -#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) \ @@ -260,11 +285,6 @@ DEFINE_EVENT(wiphy_only_evt, rdev_get_antenna, TP_ARGS(wiphy) ); -DEFINE_EVENT(wiphy_only_evt, rdev_get_tx_power, - TP_PROTO(struct wiphy *wiphy), - TP_ARGS(wiphy) -); - DEFINE_EVENT(wiphy_only_evt, rdev_rfkill_poll, TP_PROTO(struct wiphy *wiphy), TP_ARGS(wiphy) @@ -318,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, @@ -345,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) ); @@ -367,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)) ); @@ -408,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)) @@ -427,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) ); @@ -438,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) @@ -451,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; @@ -462,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, @@ -515,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, @@ -529,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, @@ -607,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", @@ -643,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)) ); @@ -683,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) ); @@ -721,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)) ); @@ -762,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)) @@ -839,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) ); @@ -858,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) ); @@ -884,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, @@ -914,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) ); @@ -933,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, @@ -974,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)) ); @@ -1002,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), @@ -1025,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) ); @@ -1051,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, @@ -1072,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) ); @@ -1092,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) ); @@ -1122,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, @@ -1147,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) @@ -1171,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) ); @@ -1190,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) ); @@ -1211,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) ); @@ -1230,22 +1248,29 @@ TRACE_EVENT(rdev_set_wiphy_params, WIPHY_PR_ARG, __entry->changed) ); +DEFINE_EVENT(wiphy_wdev_evt, rdev_get_tx_power, + TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev), + TP_ARGS(wiphy, wdev) +); + TRACE_EVENT(rdev_set_tx_power, - TP_PROTO(struct wiphy *wiphy, enum nl80211_tx_power_setting type, - int mbm), - TP_ARGS(wiphy, type, mbm), + TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, + enum nl80211_tx_power_setting type, int mbm), + TP_ARGS(wiphy, wdev, type, mbm), TP_STRUCT__entry( WIPHY_ENTRY + WDEV_ENTRY __field(enum nl80211_tx_power_setting, type) __field(int, mbm) ), TP_fast_assign( WIPHY_ASSIGN; + WDEV_ASSIGN; __entry->type = type; __entry->mbm = mbm; ), - TP_printk(WIPHY_PR_FMT ", type: %d, mbm: %d", - WIPHY_PR_ARG, __entry->type, __entry->mbm) + TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", type: %u, mbm: %d", + WIPHY_PR_ARG, WDEV_PR_ARG,__entry->type, __entry->mbm) ); TRACE_EVENT(rdev_return_int_int, @@ -1305,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)) ); @@ -1325,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") ); @@ -1411,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) ); @@ -1439,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, @@ -1459,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) ); @@ -1516,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) ); @@ -1534,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)) ); @@ -1552,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)) ); @@ -1571,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, @@ -1622,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) @@ -1650,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)) ); @@ -1680,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) ); @@ -1697,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) ); @@ -1714,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) ); @@ -1723,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, @@ -1817,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) ); @@ -1884,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) ); @@ -1892,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, @@ -1949,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)) ); @@ -2008,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, @@ -2055,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, @@ -2089,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)) ); @@ -2155,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), @@ -2216,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) @@ -2240,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) ); @@ -2255,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 5b6c1df72f31..3cce6e486219 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,6 +1052,106 @@ u32 cfg80211_calculate_bitrate(struct rate_info *rate) } EXPORT_SYMBOL(cfg80211_calculate_bitrate); +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; + bool desired_attr = false; + u16 desired_len = 0; + + while (len > 0) { + unsigned int iedatalen; + unsigned int copy; + const u8 *iedata; + + if (len < 2) + return -EILSEQ; + iedatalen = ies[1]; + if (iedatalen + 2 > len) + return -EILSEQ; + + if (ies[0] != WLAN_EID_VENDOR_SPECIFIC) + goto cont; + + if (iedatalen < 4) + goto cont; + + iedata = ies + 2; + + /* check WFA OUI, P2P subtype */ + if (iedata[0] != 0x50 || iedata[1] != 0x6f || + iedata[2] != 0x9a || iedata[3] != 0x09) + goto cont; + + iedatalen -= 4; + iedata += 4; + + /* check attribute continuation into this IE */ + copy = min_t(unsigned int, attr_remaining, iedatalen); + if (copy && desired_attr) { + desired_len += copy; + if (out) { + memcpy(out, iedata, min(bufsize, copy)); + out += min(bufsize, copy); + bufsize -= min(bufsize, copy); + } + + + if (copy == attr_remaining) + return desired_len; + } + + attr_remaining -= copy; + if (attr_remaining) + goto cont; + + iedatalen -= copy; + iedata += copy; + + while (iedatalen > 0) { + u16 attr_len; + + /* P2P attribute ID & size must fit */ + if (iedatalen < 3) + return -EILSEQ; + desired_attr = iedata[0] == attr; + attr_len = get_unaligned_le16(iedata + 1); + iedatalen -= 3; + iedata += 3; + + copy = min_t(unsigned int, attr_len, iedatalen); + + if (desired_attr) { + desired_len += copy; + if (out) { + memcpy(out, iedata, min(bufsize, copy)); + out += min(bufsize, copy); + bufsize -= min(bufsize, copy); + } + + if (copy == attr_len) + return desired_len; + } + + iedata += copy; + iedatalen -= copy; + attr_remaining = attr_len - copy; + } + + cont: + len -= ies[1] + 2; + ies += ies[1] + 2; + } + + if (attr_remaining && desired_attr) + return -EILSEQ; + + return -ENOENT; +} +EXPORT_SYMBOL(cfg80211_get_p2p_attr); + int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, u32 beacon_int) { diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 6488d2dbc1d7..f9680c9cf9b3 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: @@ -895,7 +905,7 @@ static int cfg80211_wext_siwtxpower(struct net_device *dev, return 0; } - return rdev_set_tx_power(rdev, type, DBM_TO_MBM(dbm)); + return rdev_set_tx_power(rdev, wdev, type, DBM_TO_MBM(dbm)); } static int cfg80211_wext_giwtxpower(struct net_device *dev, @@ -914,7 +924,7 @@ static int cfg80211_wext_giwtxpower(struct net_device *dev, if (!rdev->ops->get_tx_power) return -EOPNOTSUPP; - err = rdev_get_tx_power(rdev, &val); + err = rdev_get_tx_power(rdev, wdev, &val); if (err) return err; diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c index 1f773f668d1a..873af63187c0 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; } |