Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless
authorJohn W. Linville <linville@tuxdriver.com>
Mon, 18 Mar 2013 13:39:21 +0000 (09:39 -0400)
committerJohn W. Linville <linville@tuxdriver.com>
Mon, 18 Mar 2013 13:39:21 +0000 (09:39 -0400)
Conflicts:
net/nfc/llcp/llcp.c

243 files changed:
MAINTAINERS
drivers/bcma/core.c
drivers/bcma/main.c
drivers/net/wireless/ath/ath5k/ath5k.h
drivers/net/wireless/ath/ath5k/eeprom.c
drivers/net/wireless/ath/ath5k/eeprom.h
drivers/net/wireless/ath/ath5k/phy.c
drivers/net/wireless/ath/ath5k/reset.c
drivers/net/wireless/ath/ath6kl/cfg80211.c
drivers/net/wireless/ath/ath6kl/htc_pipe.c
drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h
drivers/net/wireless/ath/ath9k/calib.c
drivers/net/wireless/ath/ath9k/common.h
drivers/net/wireless/ath/ath9k/debug.c
drivers/net/wireless/ath/ath9k/debug.h
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/ath/ath9k/hw.h
drivers/net/wireless/ath/carl9170/tx.c
drivers/net/wireless/ath/wil6210/Makefile
drivers/net/wireless/ath/wil6210/cfg80211.c
drivers/net/wireless/ath/wil6210/dbg_hexdump.h [deleted file]
drivers/net/wireless/ath/wil6210/debugfs.c
drivers/net/wireless/ath/wil6210/interrupt.c
drivers/net/wireless/ath/wil6210/main.c
drivers/net/wireless/ath/wil6210/netdev.c
drivers/net/wireless/ath/wil6210/pcie_bus.c
drivers/net/wireless/ath/wil6210/txrx.c
drivers/net/wireless/ath/wil6210/wil6210.h
drivers/net/wireless/ath/wil6210/wmi.c
drivers/net/wireless/ath/wil6210/wmi.h
drivers/net/wireless/b43/Kconfig
drivers/net/wireless/b43/b43.h
drivers/net/wireless/b43/main.c
drivers/net/wireless/b43/phy_ht.c
drivers/net/wireless/b43/phy_ht.h
drivers/net/wireless/brcm80211/Kconfig
drivers/net/wireless/brcm80211/brcmfmac/Makefile
drivers/net/wireless/brcm80211/brcmfmac/dhd.h
drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h
drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c
drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c
drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c
drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h
drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
drivers/net/wireless/brcm80211/brcmfmac/dhd_proto.h
drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c [new file with mode: 0644]
drivers/net/wireless/brcm80211/brcmfmac/fwsignal.h [new file with mode: 0644]
drivers/net/wireless/brcm80211/brcmfmac/tracepoint.c [new file with mode: 0644]
drivers/net/wireless/brcm80211/brcmfmac/tracepoint.h [new file with mode: 0644]
drivers/net/wireless/brcm80211/brcmfmac/usb.c
drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
drivers/net/wireless/brcm80211/brcmsmac/Makefile
drivers/net/wireless/brcm80211/brcmsmac/led.c [new file with mode: 0644]
drivers/net/wireless/brcm80211/brcmsmac/led.h [new file with mode: 0644]
drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.h
drivers/net/wireless/brcm80211/brcmsmac/main.c
drivers/net/wireless/brcm80211/brcmutil/utils.c
drivers/net/wireless/brcm80211/include/brcmu_utils.h
drivers/net/wireless/iwlegacy/3945-mac.c
drivers/net/wireless/iwlegacy/3945.h
drivers/net/wireless/iwlegacy/4965-mac.c
drivers/net/wireless/iwlegacy/common.c
drivers/net/wireless/iwlegacy/common.h
drivers/net/wireless/iwlwifi/Kconfig
drivers/net/wireless/iwlwifi/Makefile
drivers/net/wireless/iwlwifi/dvm/agn.h
drivers/net/wireless/iwlwifi/dvm/calib.c
drivers/net/wireless/iwlwifi/dvm/calib.h
drivers/net/wireless/iwlwifi/dvm/commands.h
drivers/net/wireless/iwlwifi/dvm/debugfs.c
drivers/net/wireless/iwlwifi/dvm/lib.c
drivers/net/wireless/iwlwifi/dvm/mac80211.c
drivers/net/wireless/iwlwifi/dvm/scan.c
drivers/net/wireless/iwlwifi/dvm/testmode.c
drivers/net/wireless/iwlwifi/dvm/tx.c
drivers/net/wireless/iwlwifi/dvm/ucode.c
drivers/net/wireless/iwlwifi/iwl-1000.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/iwl-2000.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/iwl-5000.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/iwl-6000.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/iwl-7000.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/iwl-agn-hw.h
drivers/net/wireless/iwlwifi/iwl-config.h
drivers/net/wireless/iwlwifi/iwl-csr.h
drivers/net/wireless/iwlwifi/iwl-debug.c
drivers/net/wireless/iwlwifi/iwl-devtrace.h
drivers/net/wireless/iwlwifi/iwl-drv.c
drivers/net/wireless/iwlwifi/iwl-drv.h
drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c
drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h
drivers/net/wireless/iwlwifi/iwl-eeprom-read.c
drivers/net/wireless/iwlwifi/iwl-eeprom-read.h
drivers/net/wireless/iwlwifi/iwl-fh.h
drivers/net/wireless/iwlwifi/iwl-fw-file.h
drivers/net/wireless/iwlwifi/iwl-fw.h
drivers/net/wireless/iwlwifi/iwl-io.c
drivers/net/wireless/iwlwifi/iwl-modparams.h
drivers/net/wireless/iwlwifi/iwl-notif-wait.c
drivers/net/wireless/iwlwifi/iwl-notif-wait.h
drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
drivers/net/wireless/iwlwifi/iwl-nvm-parse.h
drivers/net/wireless/iwlwifi/iwl-op-mode.h
drivers/net/wireless/iwlwifi/iwl-phy-db.c
drivers/net/wireless/iwlwifi/iwl-phy-db.h
drivers/net/wireless/iwlwifi/iwl-prph.h
drivers/net/wireless/iwlwifi/iwl-test.c
drivers/net/wireless/iwlwifi/iwl-test.h
drivers/net/wireless/iwlwifi/iwl-testmode.h
drivers/net/wireless/iwlwifi/iwl-trans.h
drivers/net/wireless/iwlwifi/mvm/Makefile
drivers/net/wireless/iwlwifi/mvm/binding.c
drivers/net/wireless/iwlwifi/mvm/bt-coex.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/mvm/d3.c
drivers/net/wireless/iwlwifi/mvm/debugfs.c
drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h [new file with mode: 0644]
drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h
drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h
drivers/net/wireless/iwlwifi/mvm/fw-api-power.h
drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h
drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h
drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h
drivers/net/wireless/iwlwifi/mvm/fw-api.h
drivers/net/wireless/iwlwifi/mvm/fw.c
drivers/net/wireless/iwlwifi/mvm/led.c
drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
drivers/net/wireless/iwlwifi/mvm/mac80211.c
drivers/net/wireless/iwlwifi/mvm/mvm.h
drivers/net/wireless/iwlwifi/mvm/nvm.c
drivers/net/wireless/iwlwifi/mvm/ops.c
drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c
drivers/net/wireless/iwlwifi/mvm/power.c
drivers/net/wireless/iwlwifi/mvm/quota.c
drivers/net/wireless/iwlwifi/mvm/rs.c
drivers/net/wireless/iwlwifi/mvm/rx.c
drivers/net/wireless/iwlwifi/mvm/scan.c
drivers/net/wireless/iwlwifi/mvm/sta.c
drivers/net/wireless/iwlwifi/mvm/sta.h
drivers/net/wireless/iwlwifi/mvm/time-event.c
drivers/net/wireless/iwlwifi/mvm/time-event.h
drivers/net/wireless/iwlwifi/mvm/tx.c
drivers/net/wireless/iwlwifi/mvm/utils.c
drivers/net/wireless/iwlwifi/pcie/1000.c [deleted file]
drivers/net/wireless/iwlwifi/pcie/2000.c [deleted file]
drivers/net/wireless/iwlwifi/pcie/5000.c [deleted file]
drivers/net/wireless/iwlwifi/pcie/6000.c [deleted file]
drivers/net/wireless/iwlwifi/pcie/7000.c [deleted file]
drivers/net/wireless/iwlwifi/pcie/cfg.h [deleted file]
drivers/net/wireless/iwlwifi/pcie/drv.c
drivers/net/wireless/iwlwifi/pcie/trans.c
drivers/net/wireless/iwlwifi/pcie/tx.c
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/mwifiex/Makefile
drivers/net/wireless/mwifiex/cfg80211.c
drivers/net/wireless/mwifiex/cmdevt.c
drivers/net/wireless/mwifiex/ethtool.c [new file with mode: 0644]
drivers/net/wireless/mwifiex/fw.h
drivers/net/wireless/mwifiex/init.c
drivers/net/wireless/mwifiex/ioctl.h
drivers/net/wireless/mwifiex/main.c
drivers/net/wireless/mwifiex/main.h
drivers/net/wireless/mwifiex/pcie.c
drivers/net/wireless/mwifiex/sta_cmd.c
drivers/net/wireless/mwifiex/sta_cmdresp.c
drivers/net/wireless/mwifiex/sta_ioctl.c
drivers/net/wireless/mwifiex/txrx.c
drivers/net/wireless/mwifiex/util.c
drivers/net/wireless/mwl8k.c
drivers/net/wireless/orinoco/orinoco_usb.c
drivers/net/wireless/ray_cs.c
drivers/net/wireless/rndis_wlan.c
drivers/net/wireless/rt2x00/rt2x00pci.c
drivers/net/wireless/rtlwifi/usb.c
drivers/net/wireless/rtlwifi/wifi.h
drivers/net/wireless/ti/wlcore/main.c
drivers/nfc/microread/mei.c
drivers/ssb/driver_chipcommon.c
drivers/ssb/driver_chipcommon_pmu.c
drivers/ssb/driver_mipscore.c
drivers/ssb/driver_pcicore.c
drivers/ssb/embedded.c
drivers/ssb/main.c
drivers/ssb/pci.c
drivers/ssb/pcmcia.c
drivers/ssb/scan.c
drivers/ssb/sprom.c
drivers/ssb/ssb_private.h
include/linux/ieee80211.h
include/linux/socket.h
include/linux/ssb/ssb.h
include/net/cfg80211.h
include/net/mac80211.h
include/uapi/linux/nfc.h
include/uapi/linux/nl80211.h
net/mac80211/cfg.c
net/mac80211/debugfs_sta.c
net/mac80211/driver-ops.h
net/mac80211/ht.c
net/mac80211/ibss.c
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/key.c
net/mac80211/key.h
net/mac80211/main.c
net/mac80211/mesh.c
net/mac80211/mesh.h
net/mac80211/mesh_plink.c
net/mac80211/mlme.c
net/mac80211/offchannel.c
net/mac80211/pm.c
net/mac80211/rc80211_minstrel.c
net/mac80211/rc80211_minstrel.h
net/mac80211/rc80211_minstrel_debugfs.c
net/mac80211/rc80211_minstrel_ht.c
net/mac80211/rc80211_minstrel_ht.h
net/mac80211/rx.c
net/mac80211/sta_info.c
net/mac80211/sta_info.h
net/mac80211/trace.h
net/mac80211/util.c
net/mac80211/vht.c
net/nfc/llcp/commands.c
net/nfc/llcp/llcp.c
net/nfc/llcp/llcp.h
net/nfc/llcp/sock.c
net/nfc/netlink.c
net/nfc/nfc.h
net/rfkill/rfkill-regulator.c
net/wireless/ap.c
net/wireless/core.c
net/wireless/core.h
net/wireless/mesh.c
net/wireless/mlme.c
net/wireless/nl80211.c
net/wireless/nl80211.h
net/wireless/rdev-ops.h
net/wireless/reg.c
net/wireless/sme.c
net/wireless/sysfs.c
net/wireless/trace.h

index 9561658..143507e 100644 (file)
@@ -8486,7 +8486,7 @@ F:        drivers/usb/gadget/*uvc*.c
 F:     drivers/usb/gadget/webcam.c
 
 USB WIRELESS RNDIS DRIVER (rndis_wlan)
-M:     Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
+M:     Jussi Kivilinna <jussi.kivilinna@iki.fi>
 L:     linux-wireless@vger.kernel.org
 S:     Maintained
 F:     drivers/net/wireless/rndis_wlan.c
index 03bbe10..17b26ce 100644 (file)
@@ -104,7 +104,13 @@ void bcma_core_pll_ctl(struct bcma_device *core, u32 req, u32 status, bool on)
                if (i)
                        bcma_err(core->bus, "PLL enable timeout\n");
        } else {
-               bcma_warn(core->bus, "Disabling PLL not supported yet!\n");
+               /*
+                * Mask the PLL but don't wait for it to be disabled. PLL may be
+                * shared between cores and will be still up if there is another
+                * core using it.
+                */
+               bcma_mask32(core, BCMA_CLKCTLST, ~req);
+               bcma_read32(core, BCMA_CLKCTLST);
        }
 }
 EXPORT_SYMBOL_GPL(bcma_core_pll_ctl);
index 9a6188a..f72f52b 100644 (file)
@@ -120,6 +120,11 @@ static int bcma_register_cores(struct bcma_bus *bus)
                        continue;
                }
 
+               /* Only first GMAC core on BCM4706 is connected and working */
+               if (core->id.id == BCMA_CORE_4706_MAC_GBIT &&
+                   core->core_unit > 0)
+                       continue;
+
                core->dev.release = bcma_release_core_dev;
                core->dev.bus = &bcma_bus_type;
                dev_set_name(&core->dev, "bcma%d:%d", bus->num, dev_id);
index 3150def..2d691b8 100644 (file)
@@ -1523,7 +1523,8 @@ int ath5k_hw_dma_stop(struct ath5k_hw *ah);
 /* EEPROM access functions */
 int ath5k_eeprom_init(struct ath5k_hw *ah);
 void ath5k_eeprom_detach(struct ath5k_hw *ah);
-
+int ath5k_eeprom_mode_from_channel(struct ath5k_hw *ah,
+               struct ieee80211_channel *channel);
 
 /* Protocol Control Unit Functions */
 /* Helpers */
index b7e0258..94d34ee 100644 (file)
@@ -1779,7 +1779,8 @@ ath5k_eeprom_detach(struct ath5k_hw *ah)
 }
 
 int
-ath5k_eeprom_mode_from_channel(struct ieee80211_channel *channel)
+ath5k_eeprom_mode_from_channel(struct ath5k_hw *ah,
+               struct ieee80211_channel *channel)
 {
        switch (channel->hw_value) {
        case AR5K_MODE_11A:
@@ -1789,6 +1790,7 @@ ath5k_eeprom_mode_from_channel(struct ieee80211_channel *channel)
        case AR5K_MODE_11B:
                return AR5K_EEPROM_MODE_11B;
        default:
-               return -1;
+               ATH5K_WARN(ah, "channel is not A/B/G!");
+               return AR5K_EEPROM_MODE_11A;
        }
 }
index 94a9bbe..693296e 100644 (file)
@@ -493,6 +493,3 @@ struct ath5k_eeprom_info {
        /* Antenna raw switch tables */
        u32     ee_antenna[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX];
 };
-
-int
-ath5k_eeprom_mode_from_channel(struct ieee80211_channel *channel);
index a78afa9..d6bc7cb 100644 (file)
@@ -1612,11 +1612,7 @@ ath5k_hw_update_noise_floor(struct ath5k_hw *ah)
 
        ah->ah_cal_mask |= AR5K_CALIBRATION_NF;
 
-       ee_mode = ath5k_eeprom_mode_from_channel(ah->ah_current_channel);
-       if (WARN_ON(ee_mode < 0)) {
-               ah->ah_cal_mask &= ~AR5K_CALIBRATION_NF;
-               return;
-       }
+       ee_mode = ath5k_eeprom_mode_from_channel(ah, ah->ah_current_channel);
 
        /* completed NF calibration, test threshold */
        nf = ath5k_hw_read_measured_noise_floor(ah);
@@ -2317,12 +2313,7 @@ ath5k_hw_set_antenna_mode(struct ath5k_hw *ah, u8 ant_mode)
 
        def_ant = ah->ah_def_ant;
 
-       ee_mode = ath5k_eeprom_mode_from_channel(channel);
-       if (ee_mode < 0) {
-               ATH5K_ERR(ah,
-                       "invalid channel: %d\n", channel->center_freq);
-               return;
-       }
+       ee_mode = ath5k_eeprom_mode_from_channel(ah, channel);
 
        switch (ant_mode) {
        case AR5K_ANTMODE_DEFAULT:
@@ -3622,12 +3613,7 @@ ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel,
                return -EINVAL;
        }
 
-       ee_mode = ath5k_eeprom_mode_from_channel(channel);
-       if (ee_mode < 0) {
-               ATH5K_ERR(ah,
-                       "invalid channel: %d\n", channel->center_freq);
-               return -EINVAL;
-       }
+       ee_mode = ath5k_eeprom_mode_from_channel(ah, channel);
 
        /* Initialize TX power table */
        switch (ah->ah_radio) {
index e2d8b2c..a3399c4 100644 (file)
@@ -984,9 +984,7 @@ ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah,
        if (ah->ah_version == AR5K_AR5210)
                return;
 
-       ee_mode = ath5k_eeprom_mode_from_channel(channel);
-       if (WARN_ON(ee_mode < 0))
-               return;
+       ee_mode = ath5k_eeprom_mode_from_channel(ah, channel);
 
        /* Adjust power delta for channel 14 */
        if (channel->center_freq == 2484)
index 752ffc4..28c413f 100644 (file)
@@ -2990,13 +2990,15 @@ static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev,
 {
        struct ath6kl *ar = ath6kl_priv(dev);
        struct ath6kl_vif *vif = netdev_priv(dev);
+       int err;
 
        if (vif->nw_type != AP_NETWORK)
                return -EOPNOTSUPP;
 
-       /* Use this only for authorizing/unauthorizing a station */
-       if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
-               return -EOPNOTSUPP;
+       err = cfg80211_check_station_change(wiphy, params,
+                                           CFG80211_STA_AP_MLME_CLIENT);
+       if (err)
+               return err;
 
        if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))
                return ath6kl_wmi_ap_set_mlme(ar->wmi, vif->fw_vif_idx,
index 2813901..9adb567 100644 (file)
@@ -988,8 +988,6 @@ static int ath6kl_htc_pipe_rx_complete(struct ath6kl *ar, struct sk_buff *skb,
 
        htc_hdr = (struct htc_frame_hdr *) netdata;
 
-       ep = &target->endpoint[htc_hdr->eid];
-
        if (htc_hdr->eid >= ENDPOINT_MAX) {
                ath6kl_dbg(ATH6KL_DBG_HTC,
                           "HTC Rx: invalid EndpointID=%d\n",
@@ -997,6 +995,7 @@ static int ath6kl_htc_pipe_rx_complete(struct ath6kl *ar, struct sk_buff *skb,
                status = -EINVAL;
                goto free_skb;
        }
+       ep = &target->endpoint[htc_hdr->eid];
 
        payload_len = le16_to_cpu(get_unaligned(&htc_hdr->payld_len));
 
index 881e989..e6b92ff 100644 (file)
@@ -3606,6 +3606,12 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz)
        value = ar9003_hw_ant_ctrl_common_2_get(ah, is2ghz);
        REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM_2, AR_SWITCH_TABLE_COM2_ALL, value);
 
+       if ((AR_SREV_9462(ah)) && (ah->rxchainmask == 0x2)) {
+               value = ar9003_hw_ant_ctrl_chain_get(ah, 1, is2ghz);
+               REG_RMW_FIELD(ah, switch_chain_reg[0],
+                             AR_SWITCH_TABLE_ALL, value);
+       }
+
        for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
                if ((ah->rxchainmask & BIT(chain)) ||
                    (ah->txchainmask & BIT(chain))) {
@@ -3772,6 +3778,17 @@ static void ar9003_hw_atten_apply(struct ath_hw *ah, struct ath9k_channel *chan)
                                          AR_PHY_EXT_ATTEN_CTL_2,
                                         };
 
+       if ((AR_SREV_9462(ah)) && (ah->rxchainmask == 0x2)) {
+               value = ar9003_hw_atten_chain_get(ah, 1, chan);
+               REG_RMW_FIELD(ah, ext_atten_reg[0],
+                             AR_PHY_EXT_ATTEN_CTL_XATTEN1_DB, value);
+
+               value = ar9003_hw_atten_chain_get_margin(ah, 1, chan);
+               REG_RMW_FIELD(ah, ext_atten_reg[0],
+                             AR_PHY_EXT_ATTEN_CTL_XATTEN1_MARGIN,
+                             value);
+       }
+
        /* Test value. if 0 then attenuation is unused. Don't load anything. */
        for (i = 0; i < 3; i++) {
                if (ah->txchainmask & BIT(i)) {
index ccc42a7..999ab08 100644 (file)
@@ -37,28 +37,28 @@ static const u32 ar9462_pciephy_clkreq_enable_L1_2p0[][2] = {
        /* Addr      allmodes  */
        {0x00018c00, 0x18253ede},
        {0x00018c04, 0x000801d8},
-       {0x00018c08, 0x0003580c},
+       {0x00018c08, 0x0003780c},
 };
 
 static const u32 ar9462_2p0_baseband_postamble[][5] = {
        /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
        {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a800d},
        {0x00009820, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a01ae},
-       {0x00009824, 0x5ac640de, 0x5ac640d0, 0x5ac640d0, 0x63c640da},
+       {0x00009824, 0x63c640de, 0x5ac640d0, 0x5ac640d0, 0x63c640da},
        {0x00009828, 0x0796be89, 0x0696b081, 0x0696b881, 0x09143e81},
        {0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
        {0x00009830, 0x0000059c, 0x0000059c, 0x0000119c, 0x0000119c},
        {0x00009c00, 0x000000c4, 0x000000c4, 0x000000c4, 0x000000c4},
-       {0x00009e00, 0x0372111a, 0x0372111a, 0x037216a0, 0x037216a0},
+       {0x00009e00, 0x0372111a, 0x0372111a, 0x037216a0, 0x037216a2},
        {0x00009e04, 0x001c2020, 0x001c2020, 0x001c2020, 0x001c2020},
        {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000d8},
        {0x00009e10, 0x92c88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec86d2e},
-       {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3376605e, 0x32395d5e},
+       {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3236605e, 0x32365a5e},
        {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
        {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
        {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce},
        {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021},
-       {0x00009e3c, 0xcf946222, 0xcf946222, 0xcfd5c782, 0xcfd5c282},
+       {0x00009e3c, 0xcf946220, 0xcf946220, 0xcfd5c782, 0xcfd5c282},
        {0x00009e44, 0x62321e27, 0x62321e27, 0xfe291e27, 0xfe291e27},
        {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012},
        {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000},
@@ -82,9 +82,9 @@ static const u32 ar9462_2p0_baseband_postamble[][5] = {
        {0x0000a2d0, 0x00041981, 0x00041981, 0x00041981, 0x00041982},
        {0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b},
        {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a3a4, 0x00000010, 0x00000010, 0x00000000, 0x00000000},
+       {0x0000a3a4, 0x00000050, 0x00000050, 0x00000000, 0x00000000},
        {0x0000a3a8, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa},
-       {0x0000a3ac, 0xaaaaaa00, 0xaaaaaa30, 0xaaaaaa00, 0xaaaaaa00},
+       {0x0000a3ac, 0xaaaaaa00, 0xaa30aa30, 0xaaaaaa00, 0xaaaaaa00},
        {0x0000a41c, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce},
        {0x0000a420, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce},
        {0x0000a424, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce},
@@ -363,14 +363,14 @@ static const u32 ar9462_pciephy_clkreq_disable_L1_2p0[][2] = {
        /* Addr      allmodes  */
        {0x00018c00, 0x18213ede},
        {0x00018c04, 0x000801d8},
-       {0x00018c08, 0x0003580c},
+       {0x00018c08, 0x0003780c},
 };
 
 static const u32 ar9462_pciephy_pll_on_clkreq_disable_L1_2p0[][2] = {
        /* Addr      allmodes  */
        {0x00018c00, 0x18212ede},
        {0x00018c04, 0x000801d8},
-       {0x00018c08, 0x0003580c},
+       {0x00018c08, 0x0003780c},
 };
 
 static const u32 ar9462_2p0_radio_postamble_sys2ant[][5] = {
@@ -775,7 +775,7 @@ static const u32 ar9462_2p0_baseband_core[][2] = {
        {0x00009fc0, 0x803e4788},
        {0x00009fc4, 0x0001efb5},
        {0x00009fcc, 0x40000014},
-       {0x00009fd0, 0x01193b93},
+       {0x00009fd0, 0x0a193b93},
        {0x0000a20c, 0x00000000},
        {0x0000a220, 0x00000000},
        {0x0000a224, 0x00000000},
@@ -850,7 +850,7 @@ static const u32 ar9462_2p0_baseband_core[][2] = {
        {0x0000a7cc, 0x00000000},
        {0x0000a7d0, 0x00000000},
        {0x0000a7d4, 0x00000004},
-       {0x0000a7dc, 0x00000001},
+       {0x0000a7dc, 0x00000000},
        {0x0000a7f0, 0x80000000},
        {0x0000a8d0, 0x004b6a8e},
        {0x0000a8d4, 0x00000820},
@@ -886,7 +886,7 @@ static const u32 ar9462_modes_high_ob_db_tx_gain_table_2p0[][5] = {
        {0x0000a2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584},
        {0x0000a2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800},
        {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
-       {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
+       {0x0000a410, 0x000050da, 0x000050da, 0x000050de, 0x000050de},
        {0x0000a458, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
        {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000},
        {0x0000a504, 0x06002223, 0x06002223, 0x04000002, 0x04000002},
@@ -906,20 +906,20 @@ static const u32 ar9462_modes_high_ob_db_tx_gain_table_2p0[][5] = {
        {0x0000a53c, 0x41025e4a, 0x41025e4a, 0x34001640, 0x34001640},
        {0x0000a540, 0x48025e6c, 0x48025e6c, 0x38001660, 0x38001660},
        {0x0000a544, 0x4e025e8e, 0x4e025e8e, 0x3b001861, 0x3b001861},
-       {0x0000a548, 0x53025eb2, 0x53025eb2, 0x3e001a81, 0x3e001a81},
-       {0x0000a54c, 0x59025eb6, 0x59025eb6, 0x42001a83, 0x42001a83},
-       {0x0000a550, 0x5d025ef6, 0x5d025ef6, 0x44001c84, 0x44001c84},
+       {0x0000a548, 0x55025eb3, 0x55025eb3, 0x3e001a81, 0x3e001a81},
+       {0x0000a54c, 0x58025ef3, 0x58025ef3, 0x42001a83, 0x42001a83},
+       {0x0000a550, 0x5d025ef6, 0x5d025ef6, 0x44001a84, 0x44001a84},
        {0x0000a554, 0x62025f56, 0x62025f56, 0x48001ce3, 0x48001ce3},
        {0x0000a558, 0x66027f56, 0x66027f56, 0x4c001ce5, 0x4c001ce5},
        {0x0000a55c, 0x6a029f56, 0x6a029f56, 0x50001ce9, 0x50001ce9},
        {0x0000a560, 0x70049f56, 0x70049f56, 0x54001ceb, 0x54001ceb},
-       {0x0000a564, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-       {0x0000a568, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-       {0x0000a56c, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-       {0x0000a570, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-       {0x0000a574, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-       {0x0000a578, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-       {0x0000a57c, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
+       {0x0000a564, 0x751ffff6, 0x751ffff6, 0x56001eec, 0x56001eec},
+       {0x0000a568, 0x751ffff6, 0x751ffff6, 0x58001ef0, 0x58001ef0},
+       {0x0000a56c, 0x751ffff6, 0x751ffff6, 0x5a001ef4, 0x5a001ef4},
+       {0x0000a570, 0x751ffff6, 0x751ffff6, 0x5c001ff6, 0x5c001ff6},
+       {0x0000a574, 0x751ffff6, 0x751ffff6, 0x5c001ff6, 0x5c001ff6},
+       {0x0000a578, 0x751ffff6, 0x751ffff6, 0x5c001ff6, 0x5c001ff6},
+       {0x0000a57c, 0x751ffff6, 0x751ffff6, 0x5c001ff6, 0x5c001ff6},
        {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
        {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
        {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
@@ -1053,7 +1053,6 @@ static const u32 ar9462_2p0_mac_core[][2] = {
        {0x00008044, 0x00000000},
        {0x00008048, 0x00000000},
        {0x0000804c, 0xffffffff},
-       {0x00008050, 0xffffffff},
        {0x00008054, 0x00000000},
        {0x00008058, 0x00000000},
        {0x0000805c, 0x000fc78f},
@@ -1117,9 +1116,9 @@ static const u32 ar9462_2p0_mac_core[][2] = {
        {0x000081f8, 0x00000000},
        {0x000081fc, 0x00000000},
        {0x00008240, 0x00100000},
-       {0x00008244, 0x0010f424},
+       {0x00008244, 0x0010f400},
        {0x00008248, 0x00000800},
-       {0x0000824c, 0x0001e848},
+       {0x0000824c, 0x0001e800},
        {0x00008250, 0x00000000},
        {0x00008254, 0x00000000},
        {0x00008258, 0x00000000},
index 1e85085..7bdd726 100644 (file)
@@ -369,7 +369,6 @@ bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan)
        struct ieee80211_channel *c = chan->chan;
        struct ath9k_hw_cal_data *caldata = ah->caldata;
 
-       chan->channelFlags &= (~CHANNEL_CW_INT);
        if (REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) {
                ath_dbg(common, CALIBRATE,
                        "NF did not complete in calibration window\n");
@@ -384,7 +383,6 @@ bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan)
                ath_dbg(common, CALIBRATE,
                        "noise floor failed detected; detected %d, threshold %d\n",
                        nf, nfThresh);
-               chan->channelFlags |= CHANNEL_CW_INT;
        }
 
        if (!caldata) {
@@ -410,7 +408,7 @@ void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah,
        int i, j;
 
        ah->caldata->channel = chan->channel;
-       ah->caldata->channelFlags = chan->channelFlags & ~CHANNEL_CW_INT;
+       ah->caldata->channelFlags = chan->channelFlags;
        ah->caldata->chanmode = chan->chanmode;
        h = ah->caldata->nfCalHist;
        default_nf = ath9k_hw_get_default_nf(ah, chan);
index 050ca4a..6102476 100644 (file)
@@ -40,7 +40,7 @@
        x = ATH_LPF_RSSI((x), ATH_RSSI_IN((y)), ATH_RSSI_LPF_LEN);      \
 } while (0)
 #define ATH_EP_RND(x, mul)                                             \
-       ((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul))
+       (((x) + ((mul)/2)) / (mul))
 
 int ath9k_cmn_padpos(__le16 frame_control);
 int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb);
index 3714b97..67a2a4b 100644 (file)
@@ -537,6 +537,7 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
        PR("AMPDUs Completed:", a_completed);
        PR("AMPDUs Retried:  ", a_retries);
        PR("AMPDUs XRetried: ", a_xretries);
+       PR("TXERR Filtered:  ", txerr_filtered);
        PR("FIFO Underrun:   ", fifo_underrun);
        PR("TXOP Exceeded:   ", xtxop);
        PR("TXTIMER Expiry:  ", timer_exp);
@@ -756,6 +757,8 @@ void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf,
                        TX_STAT_INC(qnum, completed);
        }
 
+       if (ts->ts_status & ATH9K_TXERR_FILT)
+               TX_STAT_INC(qnum, txerr_filtered);
        if (ts->ts_status & ATH9K_TXERR_FIFO)
                TX_STAT_INC(qnum, fifo_underrun);
        if (ts->ts_status & ATH9K_TXERR_XTXOP)
@@ -1909,6 +1912,7 @@ static const char ath9k_gstrings_stats[][ETH_GSTRING_LEN] = {
        AMKSTR(d_tx_desc_cfg_err),
        AMKSTR(d_tx_data_underrun),
        AMKSTR(d_tx_delim_underrun),
+       "d_rx_crc_err",
        "d_rx_decrypt_crc_err",
        "d_rx_phy_err",
        "d_rx_mic_err",
@@ -1989,6 +1993,7 @@ void ath9k_get_et_stats(struct ieee80211_hw *hw,
        AWDATA(data_underrun);
        AWDATA(delim_underrun);
 
+       AWDATA_RX(crc_err);
        AWDATA_RX(decrypt_crc_err);
        AWDATA_RX(phy_err);
        AWDATA_RX(mic_err);
index 410d6d8..794a7ec 100644 (file)
@@ -142,6 +142,7 @@ struct ath_interrupt_stats {
  * @a_completed: Total AMPDUs completed
  * @a_retries: No. of AMPDUs retried (SW)
  * @a_xretries: No. of AMPDUs dropped due to xretries
+ * @txerr_filtered: No. of frames with TXERR_FILT flag set.
  * @fifo_underrun: FIFO underrun occurrences
        Valid only for:
                - non-aggregate condition.
@@ -168,6 +169,7 @@ struct ath_tx_stats {
        u32 a_completed;
        u32 a_retries;
        u32 a_xretries;
+       u32 txerr_filtered;
        u32 fifo_underrun;
        u32 xtxop;
        u32 timer_exp;
index 07e2526..4fa2bb1 100644 (file)
@@ -1669,6 +1669,104 @@ bool ath9k_hw_check_alive(struct ath_hw *ah)
 }
 EXPORT_SYMBOL(ath9k_hw_check_alive);
 
+static void ath9k_hw_init_mfp(struct ath_hw *ah)
+{
+       /* Setup MFP options for CCMP */
+       if (AR_SREV_9280_20_OR_LATER(ah)) {
+               /* Mask Retry(b11), PwrMgt(b12), MoreData(b13) to 0 in mgmt
+                * frames when constructing CCMP AAD. */
+               REG_RMW_FIELD(ah, AR_AES_MUTE_MASK1, AR_AES_MUTE_MASK1_FC_MGMT,
+                             0xc7ff);
+               ah->sw_mgmt_crypto = false;
+       } else if (AR_SREV_9160_10_OR_LATER(ah)) {
+               /* Disable hardware crypto for management frames */
+               REG_CLR_BIT(ah, AR_PCU_MISC_MODE2,
+                           AR_PCU_MISC_MODE2_MGMT_CRYPTO_ENABLE);
+               REG_SET_BIT(ah, AR_PCU_MISC_MODE2,
+                           AR_PCU_MISC_MODE2_NO_CRYPTO_FOR_NON_DATA_PKT);
+               ah->sw_mgmt_crypto = true;
+       } else {
+               ah->sw_mgmt_crypto = true;
+       }
+}
+
+static void ath9k_hw_reset_opmode(struct ath_hw *ah,
+                                 u32 macStaId1, u32 saveDefAntenna)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+
+       ENABLE_REGWRITE_BUFFER(ah);
+
+       REG_WRITE(ah, AR_STA_ID0, get_unaligned_le32(common->macaddr));
+       REG_WRITE(ah, AR_STA_ID1, get_unaligned_le16(common->macaddr + 4)
+                 | macStaId1
+                 | AR_STA_ID1_RTS_USE_DEF
+                 | (ah->config.ack_6mb ? AR_STA_ID1_ACKCTS_6MB : 0)
+                 | ah->sta_id1_defaults);
+       ath_hw_setbssidmask(common);
+       REG_WRITE(ah, AR_DEF_ANTENNA, saveDefAntenna);
+       ath9k_hw_write_associd(ah);
+       REG_WRITE(ah, AR_ISR, ~0);
+       REG_WRITE(ah, AR_RSSI_THR, INIT_RSSI_THR);
+
+       REGWRITE_BUFFER_FLUSH(ah);
+
+       ath9k_hw_set_operating_mode(ah, ah->opmode);
+}
+
+static void ath9k_hw_init_queues(struct ath_hw *ah)
+{
+       int i;
+
+       ENABLE_REGWRITE_BUFFER(ah);
+
+       for (i = 0; i < AR_NUM_DCU; i++)
+               REG_WRITE(ah, AR_DQCUMASK(i), 1 << i);
+
+       REGWRITE_BUFFER_FLUSH(ah);
+
+       ah->intr_txqs = 0;
+       for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
+               ath9k_hw_resettxqueue(ah, i);
+}
+
+/*
+ * For big endian systems turn on swapping for descriptors
+ */
+static void ath9k_hw_init_desc(struct ath_hw *ah)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+
+       if (AR_SREV_9100(ah)) {
+               u32 mask;
+               mask = REG_READ(ah, AR_CFG);
+               if (mask & (AR_CFG_SWRB | AR_CFG_SWTB | AR_CFG_SWRG)) {
+                       ath_dbg(common, RESET, "CFG Byte Swap Set 0x%x\n",
+                               mask);
+               } else {
+                       mask = INIT_CONFIG_STATUS | AR_CFG_SWRB | AR_CFG_SWTB;
+                       REG_WRITE(ah, AR_CFG, mask);
+                       ath_dbg(common, RESET, "Setting CFG 0x%x\n",
+                               REG_READ(ah, AR_CFG));
+               }
+       } else {
+               if (common->bus_ops->ath_bus_type == ATH_USB) {
+                       /* Configure AR9271 target WLAN */
+                       if (AR_SREV_9271(ah))
+                               REG_WRITE(ah, AR_CFG, AR_CFG_SWRB | AR_CFG_SWTB);
+                       else
+                               REG_WRITE(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD);
+               }
+#ifdef __BIG_ENDIAN
+               else if (AR_SREV_9330(ah) || AR_SREV_9340(ah) ||
+                        AR_SREV_9550(ah))
+                       REG_RMW(ah, AR_CFG, AR_CFG_SWRB | AR_CFG_SWTB, 0);
+               else
+                       REG_WRITE(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD);
+#endif
+       }
+}
+
 /*
  * Fast channel change:
  * (Change synthesizer based on channel freq without resetting chip)
@@ -1746,7 +1844,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        u32 saveDefAntenna;
        u32 macStaId1;
        u64 tsf = 0;
-       int i, r;
+       int r;
        bool start_mci_reset = false;
        bool save_fullsleep = ah->chip_fullsleep;
 
@@ -1763,10 +1861,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
                ath9k_hw_getnf(ah, ah->curchan);
 
        ah->caldata = caldata;
-       if (caldata &&
-           (chan->channel != caldata->channel ||
-            (chan->channelFlags & ~CHANNEL_CW_INT) !=
-            (caldata->channelFlags & ~CHANNEL_CW_INT))) {
+       if (caldata && (chan->channel != caldata->channel ||
+                       chan->channelFlags != caldata->channelFlags)) {
                /* Operating channel changed, reset channel calibration data */
                memset(caldata, 0, sizeof(*caldata));
                ath9k_init_nfcal_hist_buffer(ah, chan);
@@ -1853,22 +1949,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
                ath9k_hw_settsf64(ah, tsf);
        }
 
-       /* Setup MFP options for CCMP */
-       if (AR_SREV_9280_20_OR_LATER(ah)) {
-               /* Mask Retry(b11), PwrMgt(b12), MoreData(b13) to 0 in mgmt
-                * frames when constructing CCMP AAD. */
-               REG_RMW_FIELD(ah, AR_AES_MUTE_MASK1, AR_AES_MUTE_MASK1_FC_MGMT,
-                             0xc7ff);
-               ah->sw_mgmt_crypto = false;
-       } else if (AR_SREV_9160_10_OR_LATER(ah)) {
-               /* Disable hardware crypto for management frames */
-               REG_CLR_BIT(ah, AR_PCU_MISC_MODE2,
-                           AR_PCU_MISC_MODE2_MGMT_CRYPTO_ENABLE);
-               REG_SET_BIT(ah, AR_PCU_MISC_MODE2,
-                           AR_PCU_MISC_MODE2_NO_CRYPTO_FOR_NON_DATA_PKT);
-               ah->sw_mgmt_crypto = true;
-       } else
-               ah->sw_mgmt_crypto = true;
+       ath9k_hw_init_mfp(ah);
 
        if (IS_CHAN_OFDM(chan) || IS_CHAN_HT(chan))
                ath9k_hw_set_delta_slope(ah, chan);
@@ -1876,24 +1957,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        ath9k_hw_spur_mitigate_freq(ah, chan);
        ah->eep_ops->set_board_values(ah, chan);
 
-       ENABLE_REGWRITE_BUFFER(ah);
-
-       REG_WRITE(ah, AR_STA_ID0, get_unaligned_le32(common->macaddr));
-       REG_WRITE(ah, AR_STA_ID1, get_unaligned_le16(common->macaddr + 4)
-                 | macStaId1
-                 | AR_STA_ID1_RTS_USE_DEF
-                 | (ah->config.
-                    ack_6mb ? AR_STA_ID1_ACKCTS_6MB : 0)
-                 | ah->sta_id1_defaults);
-       ath_hw_setbssidmask(common);
-       REG_WRITE(ah, AR_DEF_ANTENNA, saveDefAntenna);
-       ath9k_hw_write_associd(ah);
-       REG_WRITE(ah, AR_ISR, ~0);
-       REG_WRITE(ah, AR_RSSI_THR, INIT_RSSI_THR);
-
-       REGWRITE_BUFFER_FLUSH(ah);
-
-       ath9k_hw_set_operating_mode(ah, ah->opmode);
+       ath9k_hw_reset_opmode(ah, macStaId1, saveDefAntenna);
 
        r = ath9k_hw_rf_set_freq(ah, chan);
        if (r)
@@ -1901,17 +1965,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 
        ath9k_hw_set_clockrate(ah);
 
-       ENABLE_REGWRITE_BUFFER(ah);
-
-       for (i = 0; i < AR_NUM_DCU; i++)
-               REG_WRITE(ah, AR_DQCUMASK(i), 1 << i);
-
-       REGWRITE_BUFFER_FLUSH(ah);
-
-       ah->intr_txqs = 0;
-       for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
-               ath9k_hw_resettxqueue(ah, i);
-
+       ath9k_hw_init_queues(ah);
        ath9k_hw_init_interrupt_masks(ah, ah->opmode);
        ath9k_hw_ani_cache_ini_regs(ah);
        ath9k_hw_init_qos(ah);
@@ -1966,38 +2020,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 
        REGWRITE_BUFFER_FLUSH(ah);
 
-       /*
-        * For big endian systems turn on swapping for descriptors
-        */
-       if (AR_SREV_9100(ah)) {
-               u32 mask;
-               mask = REG_READ(ah, AR_CFG);
-               if (mask & (AR_CFG_SWRB | AR_CFG_SWTB | AR_CFG_SWRG)) {
-                       ath_dbg(common, RESET, "CFG Byte Swap Set 0x%x\n",
-                               mask);
-               } else {
-                       mask =
-                               INIT_CONFIG_STATUS | AR_CFG_SWRB | AR_CFG_SWTB;
-                       REG_WRITE(ah, AR_CFG, mask);
-                       ath_dbg(common, RESET, "Setting CFG 0x%x\n",
-                               REG_READ(ah, AR_CFG));
-               }
-       } else {
-               if (common->bus_ops->ath_bus_type == ATH_USB) {
-                       /* Configure AR9271 target WLAN */
-                       if (AR_SREV_9271(ah))
-                               REG_WRITE(ah, AR_CFG, AR_CFG_SWRB | AR_CFG_SWTB);
-                       else
-                               REG_WRITE(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD);
-               }
-#ifdef __BIG_ENDIAN
-               else if (AR_SREV_9330(ah) || AR_SREV_9340(ah) ||
-                        AR_SREV_9550(ah))
-                       REG_RMW(ah, AR_CFG, AR_CFG_SWRB | AR_CFG_SWTB, 0);
-               else
-                       REG_WRITE(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD);
-#endif
-       }
+       ath9k_hw_init_desc(ah);
 
        if (ath9k_hw_btcoex_is_enabled(ah))
                ath9k_hw_btcoex_enable(ah);
@@ -2010,7 +2033,6 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 
        if (AR_SREV_9300_20_OR_LATER(ah)) {
                ar9003_hw_bb_watchdog_config(ah);
-
                ar9003_hw_disable_phy_restart(ah);
        }
 
index 784e81c..30e62d9 100644 (file)
@@ -363,7 +363,6 @@ enum ath9k_int {
        ATH9K_INT_NOCARD = 0xffffffff
 };
 
-#define CHANNEL_CW_INT    0x00002
 #define CHANNEL_CCK       0x00020
 #define CHANNEL_OFDM      0x00040
 #define CHANNEL_2GHZ      0x00080
index 9c0b150..c61cafa 100644 (file)
@@ -387,8 +387,7 @@ static void carl9170_tx_status_process_ampdu(struct ar9170 *ar,
        u8 tid;
 
        if (!(txinfo->flags & IEEE80211_TX_CTL_AMPDU) ||
-           txinfo->flags & IEEE80211_TX_CTL_INJECTED ||
-          (!(super->f.mac_control & cpu_to_le16(AR9170_TX_MAC_AGGR))))
+           txinfo->flags & IEEE80211_TX_CTL_INJECTED)
                return;
 
        rcu_read_lock();
@@ -981,30 +980,6 @@ static int carl9170_tx_prepare(struct ar9170 *ar,
 
                SET_VAL(CARL9170_TX_SUPER_AMPDU_FACTOR,
                        txc->s.ampdu_settings, factor);
-
-               for (i = 0; i < CARL9170_TX_MAX_RATES; i++) {
-                       txrate = &info->control.rates[i];
-                       if (txrate->idx >= 0) {
-                               txc->s.ri[i] =
-                                       CARL9170_TX_SUPER_RI_AMPDU;
-
-                               if (WARN_ON(!(txrate->flags &
-                                             IEEE80211_TX_RC_MCS))) {
-                                       /*
-                                        * Not sure if it's even possible
-                                        * to aggregate non-ht rates with
-                                        * this HW.
-                                        */
-                                       goto err_out;
-                               }
-                               continue;
-                       }
-
-                       txrate->idx = 0;
-                       txrate->count = ar->hw->max_rate_tries;
-               }
-
-               mac_tmp |= cpu_to_le16(AR9170_TX_MAC_AGGR);
        }
 
        /*
@@ -1012,11 +987,31 @@ static int carl9170_tx_prepare(struct ar9170 *ar,
         * taken from mac_control. For all fallback rate, the firmware
         * updates the mac_control flags from the rate info field.
         */
-       for (i = 1; i < CARL9170_TX_MAX_RATES; i++) {
+       for (i = 0; i < CARL9170_TX_MAX_RATES; i++) {
+               __le32 phy_set;
                txrate = &info->control.rates[i];
                if (txrate->idx < 0)
                        break;
 
+               phy_set = carl9170_tx_physet(ar, info, txrate);
+               if (i == 0) {
+                       /* first rate - part of the hw's frame header */
+                       txc->f.phy_control = phy_set;
+
+                       if (ampdu && txrate->flags & IEEE80211_TX_RC_MCS)
+                               mac_tmp |= cpu_to_le16(AR9170_TX_MAC_AGGR);
+                       if (carl9170_tx_rts_check(ar, txrate, ampdu, no_ack))
+                               mac_tmp |= cpu_to_le16(AR9170_TX_MAC_PROT_RTS);
+                       else if (carl9170_tx_cts_check(ar, txrate))
+                               mac_tmp |= cpu_to_le16(AR9170_TX_MAC_PROT_CTS);
+
+               } else {
+                       /* fallback rates are stored in the firmware's
+                        * retry rate set array.
+                        */
+                       txc->s.rr[i - 1] = phy_set;
+               }
+
                SET_VAL(CARL9170_TX_SUPER_RI_TRIES, txc->s.ri[i],
                        txrate->count);
 
@@ -1027,21 +1022,13 @@ static int carl9170_tx_prepare(struct ar9170 *ar,
                        txc->s.ri[i] |= (AR9170_TX_MAC_PROT_CTS <<
                                CARL9170_TX_SUPER_RI_ERP_PROT_S);
 
-               txc->s.rr[i - 1] = carl9170_tx_physet(ar, info, txrate);
+               if (ampdu && (txrate->flags & IEEE80211_TX_RC_MCS))
+                       txc->s.ri[i] |= CARL9170_TX_SUPER_RI_AMPDU;
        }
 
-       txrate = &info->control.rates[0];
-       SET_VAL(CARL9170_TX_SUPER_RI_TRIES, txc->s.ri[0], txrate->count);
-
-       if (carl9170_tx_rts_check(ar, txrate, ampdu, no_ack))
-               mac_tmp |= cpu_to_le16(AR9170_TX_MAC_PROT_RTS);
-       else if (carl9170_tx_cts_check(ar, txrate))
-               mac_tmp |= cpu_to_le16(AR9170_TX_MAC_PROT_CTS);
-
        txc->s.len = cpu_to_le16(skb->len);
        txc->f.length = cpu_to_le16(len + FCS_LEN);
        txc->f.mac_control = mac_tmp;
-       txc->f.phy_control = carl9170_tx_physet(ar, info, txrate);
 
        arinfo = (void *)info->rate_driver_data;
        arinfo->timeout = jiffies;
@@ -1381,9 +1368,9 @@ static void carl9170_tx(struct ar9170 *ar)
 }
 
 static bool carl9170_tx_ampdu_queue(struct ar9170 *ar,
-       struct ieee80211_sta *sta, struct sk_buff *skb)
+       struct ieee80211_sta *sta, struct sk_buff *skb,
+       struct ieee80211_tx_info *txinfo)
 {
-       struct _carl9170_tx_superframe *super = (void *) skb->data;
        struct carl9170_sta_info *sta_info;
        struct carl9170_sta_tid *agg;
        struct sk_buff *iter;
@@ -1450,7 +1437,7 @@ err_unlock:
 
 err_unlock_rcu:
        rcu_read_unlock();
-       super->f.mac_control &= ~cpu_to_le16(AR9170_TX_MAC_AGGR);
+       txinfo->flags &= ~IEEE80211_TX_CTL_AMPDU;
        carl9170_tx_status(ar, skb, false);
        ar->tx_dropped++;
        return false;
@@ -1492,7 +1479,7 @@ void carl9170_op_tx(struct ieee80211_hw *hw,
                 * sta == NULL checks are redundant in this
                 * special case.
                 */
-               run = carl9170_tx_ampdu_queue(ar, sta, skb);
+               run = carl9170_tx_ampdu_queue(ar, sta, skb, info);
                if (run)
                        carl9170_tx_ampdu(ar);
 
index 9396dc9..d288eea 100644 (file)
@@ -9,5 +9,7 @@ wil6210-objs += wmi.o
 wil6210-objs += interrupt.o
 wil6210-objs += txrx.o
 
-subdir-ccflags-y += -Werror
+ifeq (, $(findstring -W,$(EXTRA_CFLAGS)))
+       subdir-ccflags-y += -Werror
+endif
 subdir-ccflags-y += -D__CHECK_ENDIAN__
index 9ecc196..c5d4a87 100644 (file)
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <linux/kernel.h>
-#include <linux/netdevice.h>
-#include <linux/sched.h>
-#include <linux/etherdevice.h>
-#include <linux/wireless.h>
-#include <linux/ieee80211.h>
-#include <linux/slab.h>
-#include <linux/version.h>
-#include <net/cfg80211.h>
-
 #include "wil6210.h"
 #include "wmi.h"
 
@@ -292,7 +282,7 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
 
        /* WMI_CONNECT_CMD */
        memset(&conn, 0, sizeof(conn));
-       switch (bss->capability & 0x03) {
+       switch (bss->capability & WLAN_CAPABILITY_DMG_TYPE_MASK) {
        case WLAN_CAPABILITY_DMG_TYPE_AP:
                conn.network_type = WMI_NETTYPE_INFRA;
                break;
@@ -437,17 +427,18 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
        if (rc)
                return rc;
 
-       rc = wmi_set_channel(wil, channel->hw_value);
-       if (rc)
-               return rc;
-
        /* MAC address - pre-requisite for other commands */
        wmi_set_mac_address(wil, ndev->dev_addr);
 
        /* IE's */
        /* bcon 'head IE's are not relevant for 60g band */
-       wmi_set_ie(wil, WMI_FRAME_BEACON, bcon->beacon_ies_len,
-                  bcon->beacon_ies);
+       /*
+        * FW do not form regular beacon, so bcon IE's are not set
+        * For the DMG bcon, when it will be supported, bcon IE's will
+        * be reused; add something like:
+        * wmi_set_ie(wil, WMI_FRAME_BEACON, bcon->beacon_ies_len,
+        * bcon->beacon_ies);
+        */
        wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, bcon->proberesp_ies_len,
                   bcon->proberesp_ies);
        wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP, bcon->assocresp_ies_len,
@@ -455,7 +446,8 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
 
        wil->secure_pcp = info->privacy;
 
-       rc = wmi_set_bcon(wil, info->beacon_interval, wmi_nettype);
+       rc = wmi_pcp_start(wil, info->beacon_interval, wmi_nettype,
+                          channel->hw_value);
        if (rc)
                return rc;
 
@@ -472,11 +464,8 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy,
 {
        int rc = 0;
        struct wil6210_priv *wil = wiphy_to_wil(wiphy);
-       struct wireless_dev *wdev = ndev->ieee80211_ptr;
-       u8 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype);
 
-       /* To stop beaconing, set BI to 0 */
-       rc = wmi_set_bcon(wil, 0, wmi_nettype);
+       rc = wmi_pcp_stop(wil);
 
        return rc;
 }
diff --git a/drivers/net/wireless/ath/wil6210/dbg_hexdump.h b/drivers/net/wireless/ath/wil6210/dbg_hexdump.h
deleted file mode 100644 (file)
index e5712f0..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef WIL_DBG_HEXDUMP_H_
-#define WIL_DBG_HEXDUMP_H_
-
-#include <linux/printk.h>
-#include <linux/dynamic_debug.h>
-
-#if defined(CONFIG_DYNAMIC_DEBUG)
-#define wil_print_hex_dump_debug(prefix_str, prefix_type, rowsize,     \
-                                groupsize, buf, len, ascii)            \
-       dynamic_hex_dump(prefix_str, prefix_type, rowsize,              \
-                            groupsize, buf, len, ascii)
-
-#else /* defined(CONFIG_DYNAMIC_DEBUG) */
-#define wil_print_hex_dump_debug(prefix_str, prefix_type, rowsize,     \
-                                groupsize, buf, len, ascii)            \
-       print_hex_dump(KERN_DEBUG, prefix_str, prefix_type, rowsize,    \
-                      groupsize, buf, len, ascii)
-#endif /* defined(CONFIG_DYNAMIC_DEBUG) */
-
-#endif /* WIL_DBG_HEXDUMP_H_ */
index 65fc968..4be07f5 100644 (file)
@@ -312,14 +312,6 @@ static const struct file_operations fops_memread = {
        .llseek         = seq_lseek,
 };
 
-static int wil_default_open(struct inode *inode, struct file *file)
-{
-       if (inode->i_private)
-               file->private_data = inode->i_private;
-
-       return 0;
-}
-
 static ssize_t wil_read_file_ioblob(struct file *file, char __user *user_buf,
                                size_t count, loff_t *ppos)
 {
@@ -361,7 +353,7 @@ static ssize_t wil_read_file_ioblob(struct file *file, char __user *user_buf,
 
 static const struct file_operations fops_ioblob = {
        .read =         wil_read_file_ioblob,
-       .open =         wil_default_open,
+       .open =         simple_open,
        .llseek =       default_llseek,
 };
 
@@ -396,7 +388,7 @@ static ssize_t wil_write_file_reset(struct file *file, const char __user *buf,
 
 static const struct file_operations fops_reset = {
        .write = wil_write_file_reset,
-       .open  = wil_default_open,
+       .open  = simple_open,
 };
 /*---------Tx descriptor------------*/
 
@@ -526,7 +518,50 @@ static ssize_t wil_write_file_ssid(struct file *file, const char __user *buf,
 static const struct file_operations fops_ssid = {
        .read = wil_read_file_ssid,
        .write = wil_write_file_ssid,
-       .open  = wil_default_open,
+       .open  = simple_open,
+};
+
+/*---------temp------------*/
+static void print_temp(struct seq_file *s, const char *prefix, u32 t)
+{
+       switch (t) {
+       case 0:
+       case ~(u32)0:
+               seq_printf(s, "%s N/A\n", prefix);
+       break;
+       default:
+               seq_printf(s, "%s %d.%03d\n", prefix, t / 1000, t % 1000);
+               break;
+       }
+}
+
+static int wil_temp_debugfs_show(struct seq_file *s, void *data)
+{
+       struct wil6210_priv *wil = s->private;
+       u32 t_m, t_r;
+
+       int rc = wmi_get_temperature(wil, &t_m, &t_r);
+       if (rc) {
+               seq_printf(s, "Failed\n");
+               return 0;
+       }
+
+       print_temp(s, "MAC temperature   :", t_m);
+       print_temp(s, "Radio temperature :", t_r);
+
+       return 0;
+}
+
+static int wil_temp_seq_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, wil_temp_debugfs_show, inode->i_private);
+}
+
+static const struct file_operations fops_temp = {
+       .open           = wil_temp_seq_open,
+       .release        = single_release,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
 };
 
 /*----------------*/
@@ -563,6 +598,7 @@ int wil6210_debugfs_init(struct wil6210_priv *wil)
        debugfs_create_file("mem_val", S_IRUGO, dbg, wil, &fops_memread);
 
        debugfs_create_file("reset", S_IWUSR, dbg, wil, &fops_reset);
+       debugfs_create_file("temp", S_IRUGO, dbg, wil, &fops_temp);
 
        wil->rgf_blob.data = (void * __force)wil->csr + 0;
        wil->rgf_blob.size = 0xa000;
index dc97e7b..e3c1e76 100644 (file)
@@ -240,6 +240,15 @@ static void wil_notify_fw_error(struct wil6210_priv *wil)
        kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
 }
 
+static void wil_cache_mbox_regs(struct wil6210_priv *wil)
+{
+       /* make shadow copy of registers that should not change on run time */
+       wil_memcpy_fromio_32(&wil->mbox_ctl, wil->csr + HOST_MBOX,
+                            sizeof(struct wil6210_mbox_ctl));
+       wil_mbox_ring_le2cpus(&wil->mbox_ctl.rx);
+       wil_mbox_ring_le2cpus(&wil->mbox_ctl.tx);
+}
+
 static irqreturn_t wil6210_irq_misc(int irq, void *cookie)
 {
        struct wil6210_priv *wil = cookie;
@@ -257,14 +266,19 @@ static irqreturn_t wil6210_irq_misc(int irq, void *cookie)
        wil6210_mask_irq_misc(wil);
 
        if (isr & ISR_MISC_FW_ERROR) {
-               wil_dbg_irq(wil, "IRQ: Firmware error\n");
+               wil_err(wil, "Firmware error detected\n");
                clear_bit(wil_status_fwready, &wil->status);
-               wil_notify_fw_error(wil);
-               isr &= ~ISR_MISC_FW_ERROR;
+               /*
+                * do not clear @isr here - we do 2-nd part in thread
+                * there, user space get notified, and it should be done
+                * in non-atomic context
+                */
        }
 
        if (isr & ISR_MISC_FW_READY) {
                wil_dbg_irq(wil, "IRQ: FW ready\n");
+               wil_cache_mbox_regs(wil);
+               set_bit(wil_status_reset_done, &wil->status);
                /**
                 * Actual FW ready indicated by the
                 * WMI_FW_READY_EVENTID
@@ -289,6 +303,11 @@ static irqreturn_t wil6210_irq_misc_thread(int irq, void *cookie)
 
        wil_dbg_irq(wil, "Thread ISR MISC 0x%08x\n", isr);
 
+       if (isr & ISR_MISC_FW_ERROR) {
+               wil_notify_fw_error(wil);
+               isr &= ~ISR_MISC_FW_ERROR;
+       }
+
        if (isr & ISR_MISC_MBOX_EVT) {
                wil_dbg_irq(wil, "MBOX event\n");
                wmi_recv_cmd(wil);
index 761c389..a0478e2 100644 (file)
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <linux/kernel.h>
-#include <linux/netdevice.h>
-#include <linux/sched.h>
-#include <linux/ieee80211.h>
-#include <linux/wireless.h>
-#include <linux/slab.h>
 #include <linux/moduleparam.h>
 #include <linux/if_arp.h>
 
@@ -109,13 +103,24 @@ static void wil_connect_timer_fn(ulong x)
        schedule_work(&wil->disconnect_worker);
 }
 
-static void wil_cache_mbox_regs(struct wil6210_priv *wil)
+static void wil_connect_worker(struct work_struct *work)
 {
-       /* make shadow copy of registers that should not change on run time */
-       wil_memcpy_fromio_32(&wil->mbox_ctl, wil->csr + HOST_MBOX,
-                            sizeof(struct wil6210_mbox_ctl));
-       wil_mbox_ring_le2cpus(&wil->mbox_ctl.rx);
-       wil_mbox_ring_le2cpus(&wil->mbox_ctl.tx);
+       int rc;
+       struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
+                                               connect_worker);
+       int cid = wil->pending_connect_cid;
+
+       if (cid < 0) {
+               wil_err(wil, "No connection pending\n");
+               return;
+       }
+
+       wil_dbg_wmi(wil, "Configure for connection CID %d\n", cid);
+
+       rc = wil_vring_init_tx(wil, 0, WIL6210_TX_RING_SIZE, cid, 0);
+       wil->pending_connect_cid = -1;
+       if (rc == 0)
+               wil_link_on(wil);
 }
 
 int wil_priv_init(struct wil6210_priv *wil)
@@ -130,7 +135,7 @@ int wil_priv_init(struct wil6210_priv *wil)
        wil->pending_connect_cid = -1;
        setup_timer(&wil->connect_timer, wil_connect_timer_fn, (ulong)wil);
 
-       INIT_WORK(&wil->wmi_connect_worker, wmi_connect_worker);
+       INIT_WORK(&wil->connect_worker, wil_connect_worker);
        INIT_WORK(&wil->disconnect_worker, wil_disconnect_worker);
        INIT_WORK(&wil->wmi_event_worker, wmi_event_worker);
 
@@ -147,8 +152,6 @@ int wil_priv_init(struct wil6210_priv *wil)
                return -EAGAIN;
        }
 
-       wil_cache_mbox_regs(wil);
-
        return 0;
 }
 
@@ -185,15 +188,11 @@ static void wil_target_reset(struct wil6210_priv *wil)
        W(RGF_USER_MAC_CPU_0,  BIT(1)); /* mac_cpu_man_rst */
        W(RGF_USER_USER_CPU_0, BIT(1)); /* user_cpu_man_rst */
 
-       msleep(100);
-
        W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0xFE000000);
        W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0x0000003F);
        W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000170);
        W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0xFFE7FC00);
 
-       msleep(100);
-
        W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0);
        W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0);
        W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0);
@@ -203,12 +202,6 @@ static void wil_target_reset(struct wil6210_priv *wil)
        W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00000080);
        W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0);
 
-       msleep(2000);
-
-       W(RGF_USER_USER_CPU_0, BIT(0)); /* user_cpu_man_de_rst */
-
-       msleep(2000);
-
        wil_dbg_misc(wil, "Reset completed\n");
 
 #undef W
@@ -265,8 +258,6 @@ int wil_reset(struct wil6210_priv *wil)
        wil->pending_connect_cid = -1;
        INIT_COMPLETION(wil->wmi_ready);
 
-       wil_cache_mbox_regs(wil);
-
        /* TODO: release MAC reset */
        wil6210_enable_irq(wil);
 
@@ -352,9 +343,9 @@ static int __wil_up(struct wil6210_priv *wil)
                        wil_err(wil, "SSID not set\n");
                        return -EINVAL;
                }
-               wmi_set_ssid(wil, wdev->ssid_len, wdev->ssid);
-               if (channel)
-                       wmi_set_channel(wil, channel->hw_value);
+               rc = wmi_set_ssid(wil, wdev->ssid_len, wdev->ssid);
+               if (rc)
+                       return rc;
                break;
        default:
                break;
@@ -364,9 +355,12 @@ static int __wil_up(struct wil6210_priv *wil)
        wmi_set_mac_address(wil, ndev->dev_addr);
 
        /* Set up beaconing if required. */
-       rc = wmi_set_bcon(wil, bi, wmi_nettype);
-       if (rc)
-               return rc;
+       if (bi > 0) {
+               rc = wmi_pcp_start(wil, bi, wmi_nettype,
+                                  (channel ? channel->hw_value : 0));
+               if (rc)
+                       return rc;
+       }
 
        /* Rx VRING. After MAC and beacon */
        wil_rx_init(wil);
index 8ce2e33..098a8ec 100644 (file)
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <linux/module.h>
-#include <linux/netdevice.h>
 #include <linux/etherdevice.h>
-#include <linux/slab.h>
 
 #include "wil6210.h"
 
index 81c35c6..eb1dc7a 100644 (file)
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/netdevice.h>
 #include <linux/debugfs.h>
 #include <linux/pci.h>
 #include <linux/moduleparam.h>
index d1315b4..1bfa736 100644 (file)
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <linux/kernel.h>
-#include <linux/netdevice.h>
 #include <linux/etherdevice.h>
-#include <linux/hardirq.h>
 #include <net/ieee80211_radiotap.h>
 #include <linux/if_arp.h>
 #include <linux/moduleparam.h>
@@ -560,7 +557,7 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
        if (rc)
                goto out_free;
 
-       if (reply.cmd.status != WMI_VRING_CFG_SUCCESS) {
+       if (reply.cmd.status != WMI_FW_STATUS_SUCCESS) {
                wil_err(wil, "Tx config failed, status 0x%02x\n",
                        reply.cmd.status);
                rc = -EINVAL;
index aea961f..8f76ecd 100644 (file)
@@ -21,8 +21,6 @@
 #include <linux/wireless.h>
 #include <net/cfg80211.h>
 
-#include "dbg_hexdump.h"
-
 #define WIL_NAME "wil6210"
 
 /**
@@ -188,6 +186,7 @@ enum { /* for wil6210_priv.status */
        wil_status_fwready = 0,
        wil_status_fwconnected,
        wil_status_dontscan,
+       wil_status_reset_done,
        wil_status_irqen, /* FIXME: interrupts enabled - for debug */
 };
 
@@ -210,6 +209,8 @@ struct wil6210_priv {
        struct wireless_dev *wdev;
        void __iomem *csr;
        ulong status;
+       u32 fw_version;
+       u8 n_mids; /* number of additional MIDs as reported by FW */
        /* profile */
        u32 monitor_flags;
        u32 secure_pcp; /* create secure PCP? */
@@ -227,7 +228,7 @@ struct wil6210_priv {
        struct workqueue_struct *wmi_wq; /* for deferred calls */
        struct work_struct wmi_event_worker;
        struct workqueue_struct *wmi_wq_conn; /* for connect worker */
-       struct work_struct wmi_connect_worker;
+       struct work_struct connect_worker;
        struct work_struct disconnect_worker;
        struct timer_list connect_timer;
        int pending_connect_cid;
@@ -277,13 +278,13 @@ struct wil6210_priv {
 
 #define wil_hex_dump_txrx(prefix_str, prefix_type, rowsize,    \
                          groupsize, buf, len, ascii)           \
-                         wil_print_hex_dump_debug("DBG[TXRX]" prefix_str,\
+                         print_hex_dump_debug("DBG[TXRX]" prefix_str,\
                                         prefix_type, rowsize,  \
                                         groupsize, buf, len, ascii)
 
 #define wil_hex_dump_wmi(prefix_str, prefix_type, rowsize,     \
                         groupsize, buf, len, ascii)            \
-                        wil_print_hex_dump_debug("DBG[ WMI]" prefix_str,\
+                        print_hex_dump_debug("DBG[ WMI]" prefix_str,\
                                        prefix_type, rowsize,   \
                                        groupsize, buf, len, ascii)
 
@@ -313,7 +314,6 @@ int wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len);
 void wmi_recv_cmd(struct wil6210_priv *wil);
 int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len,
             u16 reply_id, void *reply, u8 reply_size, int to_msec);
-void wmi_connect_worker(struct work_struct *work);
 void wmi_event_worker(struct work_struct *work);
 void wmi_event_flush(struct wil6210_priv *wil);
 int wmi_set_ssid(struct wil6210_priv *wil, u8 ssid_len, const void *ssid);
@@ -328,6 +328,8 @@ int wmi_add_cipher_key(struct wil6210_priv *wil, u8 key_index,
 int wmi_echo(struct wil6210_priv *wil);
 int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie);
 int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring);
+int wmi_p2p_cfg(struct wil6210_priv *wil, int channel);
+int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r);
 
 int wil6210_init_irq(struct wil6210_priv *wil, int irq);
 void wil6210_fini_irq(struct wil6210_priv *wil, int irq);
@@ -341,7 +343,8 @@ struct wireless_dev *wil_cfg80211_init(struct device *dev);
 void wil_wdev_free(struct wil6210_priv *wil);
 
 int wmi_set_mac_address(struct wil6210_priv *wil, void *addr);
-int wmi_set_bcon(struct wil6210_priv *wil, int bi, u8 wmi_nettype);
+int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan);
+int wmi_pcp_stop(struct wil6210_priv *wil);
 void wil6210_disconnect(struct wil6210_priv *wil, void *bssid);
 
 int wil_rx_init(struct wil6210_priv *wil);
index 0bb3b76..45b04e3 100644 (file)
@@ -14,9 +14,6 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <linux/pci.h>
-#include <linux/io.h>
-#include <linux/list.h>
 #include <linux/etherdevice.h>
 #include <linux/if_arp.h>
 
@@ -272,16 +269,18 @@ static void wmi_evt_ready(struct wil6210_priv *wil, int id, void *d, int len)
        struct net_device *ndev = wil_to_ndev(wil);
        struct wireless_dev *wdev = wil->wdev;
        struct wmi_ready_event *evt = d;
-       u32 ver = le32_to_cpu(evt->sw_version);
+       wil->fw_version = le32_to_cpu(evt->sw_version);
+       wil->n_mids = evt->numof_additional_mids;
 
-       wil_dbg_wmi(wil, "FW ver. %d; MAC %pM\n", ver, evt->mac);
+       wil_dbg_wmi(wil, "FW ver. %d; MAC %pM; %d MID's\n", wil->fw_version,
+                   evt->mac, wil->n_mids);
 
        if (!is_valid_ether_addr(ndev->dev_addr)) {
                memcpy(ndev->dev_addr, evt->mac, ETH_ALEN);
                memcpy(ndev->perm_addr, evt->mac, ETH_ALEN);
        }
        snprintf(wdev->wiphy->fw_version, sizeof(wdev->wiphy->fw_version),
-                "%d", ver);
+                "%d", wil->fw_version);
 }
 
 static void wmi_evt_fw_ready(struct wil6210_priv *wil, int id, void *d,
@@ -324,17 +323,9 @@ static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len)
 
        if (ieee80211_is_beacon(fc) || ieee80211_is_probe_resp(fc)) {
                struct cfg80211_bss *bss;
-               u64 tsf = le64_to_cpu(rx_mgmt_frame->u.beacon.timestamp);
-               u16 cap = le16_to_cpu(rx_mgmt_frame->u.beacon.capab_info);
-               u16 bi = le16_to_cpu(rx_mgmt_frame->u.beacon.beacon_int);
-               const u8 *ie_buf = rx_mgmt_frame->u.beacon.variable;
-               size_t ie_len = d_len - offsetof(struct ieee80211_mgmt,
-                                                u.beacon.variable);
-               wil_dbg_wmi(wil, "Capability info : 0x%04x\n", cap);
-
-               bss = cfg80211_inform_bss(wiphy, channel, rx_mgmt_frame->bssid,
-                                         tsf, cap, bi, ie_buf, ie_len,
-                                         signal, GFP_KERNEL);
+
+               bss = cfg80211_inform_bss_frame(wiphy, channel, rx_mgmt_frame,
+                                               d_len, signal, GFP_KERNEL);
                if (bss) {
                        wil_dbg_wmi(wil, "Added BSS %pM\n",
                                    rx_mgmt_frame->bssid);
@@ -342,6 +333,9 @@ static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len)
                } else {
                        wil_err(wil, "cfg80211_inform_bss() failed\n");
                }
+       } else {
+               cfg80211_rx_mgmt(wil->wdev, freq, signal,
+                                (void *)rx_mgmt_frame, d_len, GFP_KERNEL);
        }
 }
 
@@ -443,7 +437,7 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
        memcpy(wil->dst_addr[0], evt->bssid, ETH_ALEN);
 
        wil->pending_connect_cid = evt->cid;
-       queue_work(wil->wmi_wq_conn, &wil->wmi_connect_worker);
+       queue_work(wil->wmi_wq_conn, &wil->connect_worker);
 }
 
 static void wmi_evt_disconnect(struct wil6210_priv *wil, int id,
@@ -528,6 +522,37 @@ static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id,
        }
 }
 
+static void wmi_evt_linkup(struct wil6210_priv *wil, int id, void *d, int len)
+{
+       struct net_device *ndev = wil_to_ndev(wil);
+       struct wmi_data_port_open_event *evt = d;
+
+       wil_dbg_wmi(wil, "Link UP for CID %d\n", evt->cid);
+
+       netif_carrier_on(ndev);
+}
+
+static void wmi_evt_linkdown(struct wil6210_priv *wil, int id, void *d, int len)
+{
+       struct net_device *ndev = wil_to_ndev(wil);
+       struct wmi_wbe_link_down_event *evt = d;
+
+       wil_dbg_wmi(wil, "Link DOWN for CID %d, reason %d\n",
+                   evt->cid, le32_to_cpu(evt->reason));
+
+       netif_carrier_off(ndev);
+}
+
+static void wmi_evt_ba_status(struct wil6210_priv *wil, int id, void *d,
+                             int len)
+{
+       struct wmi_vring_ba_status_event *evt = d;
+
+       wil_dbg_wmi(wil, "BACK[%d] %s {%d} timeout %d\n",
+                   evt->ringid, evt->status ? "N/A" : "OK", evt->agg_wsize,
+                   __le16_to_cpu(evt->ba_timeout));
+}
+
 static const struct {
        int eventid;
        void (*handler)(struct wil6210_priv *wil, int eventid,
@@ -541,6 +566,9 @@ static const struct {
        {WMI_DISCONNECT_EVENTID,        wmi_evt_disconnect},
        {WMI_NOTIFY_REQ_DONE_EVENTID,   wmi_evt_notify},
        {WMI_EAPOL_RX_EVENTID,          wmi_evt_eapol_rx},
+       {WMI_DATA_PORT_OPEN_EVENTID,    wmi_evt_linkup},
+       {WMI_WBE_LINKDOWN_EVENTID,      wmi_evt_linkdown},
+       {WMI_BA_STATUS_EVENTID,         wmi_evt_ba_status},
 };
 
 /*
@@ -559,6 +587,11 @@ void wmi_recv_cmd(struct wil6210_priv *wil)
        void __iomem *src;
        ulong flags;
 
+       if (!test_bit(wil_status_reset_done, &wil->status)) {
+               wil_err(wil, "Reset not completed\n");
+               return;
+       }
+
        for (;;) {
                u16 len;
 
@@ -683,18 +716,39 @@ int wmi_set_mac_address(struct wil6210_priv *wil, void *addr)
        return wmi_send(wil, WMI_SET_MAC_ADDRESS_CMDID, &cmd, sizeof(cmd));
 }
 
-int wmi_set_bcon(struct wil6210_priv *wil, int bi, u8 wmi_nettype)
+int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan)
 {
-       struct wmi_bcon_ctrl_cmd cmd = {
+       int rc;
+
+       struct wmi_pcp_start_cmd cmd = {
                .bcon_interval = cpu_to_le16(bi),
                .network_type = wmi_nettype,
                .disable_sec_offload = 1,
+               .channel = chan,
        };
+       struct {
+               struct wil6210_mbox_hdr_wmi wmi;
+               struct wmi_pcp_started_event evt;
+       } __packed reply;
 
        if (!wil->secure_pcp)
                cmd.disable_sec = 1;
 
-       return wmi_send(wil, WMI_BCON_CTRL_CMDID, &cmd, sizeof(cmd));
+       rc = wmi_call(wil, WMI_PCP_START_CMDID, &cmd, sizeof(cmd),
+                     WMI_PCP_STARTED_EVENTID, &reply, sizeof(reply), 100);
+       if (rc)
+               return rc;
+
+       if (reply.evt.status != WMI_FW_STATUS_SUCCESS)
+               rc = -EINVAL;
+
+       return rc;
+}
+
+int wmi_pcp_stop(struct wil6210_priv *wil)
+{
+       return wmi_call(wil, WMI_PCP_STOP_CMDID, NULL, 0,
+                       WMI_PCP_STOPPED_EVENTID, NULL, 0, 20);
 }
 
 int wmi_set_ssid(struct wil6210_priv *wil, u8 ssid_len, const void *ssid)
@@ -765,6 +819,16 @@ int wmi_get_channel(struct wil6210_priv *wil, int *channel)
        return 0;
 }
 
+int wmi_p2p_cfg(struct wil6210_priv *wil, int channel)
+{
+       struct wmi_p2p_cfg_cmd cmd = {
+               .discovery_mode = WMI_DISCOVERY_MODE_NON_OFFLOAD,
+               .channel = channel - 1,
+       };
+
+       return wmi_send(wil, WMI_P2P_CFG_CMDID, &cmd, sizeof(cmd));
+}
+
 int wmi_tx_eapol(struct wil6210_priv *wil, struct sk_buff *skb)
 {
        struct wmi_eapol_tx_cmd *cmd;
@@ -843,7 +907,7 @@ int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie)
        /* BUG: FW API define ieLen as u8. Will fix FW */
        cmd->ie_len = cpu_to_le16(ie_len);
        memcpy(cmd->ie_info, ie, ie_len);
-       rc = wmi_send(wil, WMI_SET_APPIE_CMDID, &cmd, len);
+       rc = wmi_send(wil, WMI_SET_APPIE_CMDID, cmd, len);
        kfree(cmd);
 
        return rc;
@@ -898,6 +962,31 @@ int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring)
        return rc;
 }
 
+int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r)
+{
+       int rc;
+       struct wmi_temp_sense_cmd cmd = {
+               .measure_marlon_m_en = cpu_to_le32(!!t_m),
+               .measure_marlon_r_en = cpu_to_le32(!!t_r),
+       };
+       struct {
+               struct wil6210_mbox_hdr_wmi wmi;
+               struct wmi_temp_sense_done_event evt;
+       } __packed reply;
+
+       rc = wmi_call(wil, WMI_TEMP_SENSE_CMDID, &cmd, sizeof(cmd),
+                     WMI_TEMP_SENSE_DONE_EVENTID, &reply, sizeof(reply), 100);
+       if (rc)
+               return rc;
+
+       if (t_m)
+               *t_m = le32_to_cpu(reply.evt.marlon_m_t1000);
+       if (t_r)
+               *t_r = le32_to_cpu(reply.evt.marlon_r_t1000);
+
+       return 0;
+}
+
 void wmi_event_flush(struct wil6210_priv *wil)
 {
        struct pending_wmi_event *evt, *t;
@@ -997,24 +1086,3 @@ void wmi_event_worker(struct work_struct *work)
                kfree(evt);
        }
 }
-
-void wmi_connect_worker(struct work_struct *work)
-{
-       int rc;
-       struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
-                                               wmi_connect_worker);
-
-       if (wil->pending_connect_cid < 0) {
-               wil_err(wil, "No connection pending\n");
-               return;
-       }
-
-       wil_dbg_wmi(wil, "Configure for connection CID %d\n",
-                   wil->pending_connect_cid);
-
-       rc = wil_vring_init_tx(wil, 0, WIL6210_TX_RING_SIZE,
-                              wil->pending_connect_cid, 0);
-       wil->pending_connect_cid = -1;
-       if (rc == 0)
-               wil_link_on(wil);
-}
index 3bbf875..50b8528 100644 (file)
@@ -36,6 +36,7 @@
 enum wmi_command_id {
        WMI_CONNECT_CMDID               = 0x0001,
        WMI_DISCONNECT_CMDID            = 0x0003,
+       WMI_DISCONNECT_STA_CMDID        = 0x0004,
        WMI_START_SCAN_CMDID            = 0x0007,
        WMI_SET_BSS_FILTER_CMDID        = 0x0009,
        WMI_SET_PROBED_SSID_CMDID       = 0x000a,
@@ -44,7 +45,6 @@ enum wmi_command_id {
        WMI_ADD_CIPHER_KEY_CMDID        = 0x0016,
        WMI_DELETE_CIPHER_KEY_CMDID     = 0x0017,
        WMI_SET_APPIE_CMDID             = 0x003f,
-       WMI_GET_APPIE_CMDID             = 0x0040,
        WMI_SET_WSC_STATUS_CMDID        = 0x0041,
        WMI_PXMT_RANGE_CFG_CMDID        = 0x0042,
        WMI_PXMT_SNR2_RANGE_CFG_CMDID   = 0x0043,
@@ -55,11 +55,11 @@ enum wmi_command_id {
        WMI_DEEP_ECHO_CMDID             = 0x0804,
        WMI_CONFIG_MAC_CMDID            = 0x0805,
        WMI_CONFIG_PHY_DEBUG_CMDID      = 0x0806,
-       WMI_ADD_STATION_CMDID           = 0x0807,
        WMI_ADD_DEBUG_TX_PCKT_CMDID     = 0x0808,
        WMI_PHY_GET_STATISTICS_CMDID    = 0x0809,
        WMI_FS_TUNE_CMDID               = 0x080a,
        WMI_CORR_MEASURE_CMDID          = 0x080b,
+       WMI_READ_RSSI_CMDID             = 0x080c,
        WMI_TEMP_SENSE_CMDID            = 0x080e,
        WMI_DC_CALIB_CMDID              = 0x080f,
        WMI_SEND_TONE_CMDID             = 0x0810,
@@ -75,9 +75,9 @@ enum wmi_command_id {
        MAC_IO_STATIC_PARAMS_CMDID      = 0x081b,
        MAC_IO_DYNAMIC_PARAMS_CMDID     = 0x081c,
        WMI_SILENT_RSSI_CALIB_CMDID     = 0x081d,
+       WMI_RF_RX_TEST_CMDID            = 0x081e,
        WMI_CFG_RX_CHAIN_CMDID          = 0x0820,
        WMI_VRING_CFG_CMDID             = 0x0821,
-       WMI_RX_ON_CMDID                 = 0x0822,
        WMI_VRING_BA_EN_CMDID           = 0x0823,
        WMI_VRING_BA_DIS_CMDID          = 0x0824,
        WMI_RCP_ADDBA_RESP_CMDID        = 0x0825,
@@ -87,7 +87,6 @@ enum wmi_command_id {
        WMI_SET_PCP_CHANNEL_CMDID       = 0x0829,
        WMI_GET_PCP_CHANNEL_CMDID       = 0x082a,
        WMI_SW_TX_REQ_CMDID             = 0x082b,
-       WMI_RX_OFF_CMDID                = 0x082c,
        WMI_READ_MAC_RXQ_CMDID          = 0x0830,
        WMI_READ_MAC_TXQ_CMDID          = 0x0831,
        WMI_WRITE_MAC_RXQ_CMDID         = 0x0832,
@@ -112,6 +111,18 @@ enum wmi_command_id {
        WMI_FLASH_READ_CMDID            = 0x0902,
        WMI_FLASH_WRITE_CMDID           = 0x0903,
        WMI_SECURITY_UNIT_TEST_CMDID    = 0x0904,
+       /*P2P*/
+       WMI_P2P_CFG_CMDID               = 0x0910,
+       WMI_PORT_ALLOCATE_CMDID         = 0x0911,
+       WMI_PORT_DELETE_CMDID           = 0x0912,
+       WMI_POWER_MGMT_CFG_CMDID        = 0x0913,
+       WMI_START_LISTEN_CMDID          = 0x0914,
+       WMI_START_SEARCH_CMDID          = 0x0915,
+       WMI_DISCOVERY_START_CMDID       = 0x0916,
+       WMI_DISCOVERY_STOP_CMDID        = 0x0917,
+       WMI_PCP_START_CMDID             = 0x0918,
+       WMI_PCP_STOP_CMDID              = 0x0919,
+       WMI_GET_PCP_FACTOR_CMDID        = 0x091b,
 
        WMI_SET_MAC_ADDRESS_CMDID       = 0xf003,
        WMI_ABORT_SCAN_CMDID            = 0xf007,
@@ -131,18 +142,6 @@ enum wmi_command_id {
  * Commands data structures
  */
 
-/*
- * Frame Types
- */
-enum wmi_mgmt_frame_type {
-       WMI_FRAME_BEACON        = 0,
-       WMI_FRAME_PROBE_REQ     = 1,
-       WMI_FRAME_PROBE_RESP    = 2,
-       WMI_FRAME_ASSOC_REQ     = 3,
-       WMI_FRAME_ASSOC_RESP    = 4,
-       WMI_NUM_MGMT_FRAME,
-};
-
 /*
  * WMI_CONNECT_CMDID
  */
@@ -184,7 +183,7 @@ enum wmi_crypto_type {
 enum wmi_connect_ctrl_flag_bits {
        WMI_CONNECT_ASSOC_POLICY_USER           = 0x0001,
        WMI_CONNECT_SEND_REASSOC                = 0x0002,
-       WMI_CONNECT_IGNORE_WPAx_GROUP_CIPHER    = 0x0004,
+       WMI_CONNECT_IGNORE_WPA_GROUP_CIPHER     = 0x0004,
        WMI_CONNECT_PROFILE_MATCH_DONE          = 0x0008,
        WMI_CONNECT_IGNORE_AAC_BEACON           = 0x0010,
        WMI_CONNECT_CSA_FOLLOW_BSS              = 0x0020,
@@ -212,6 +211,13 @@ struct wmi_connect_cmd {
        u8 reserved1[2];
 } __packed;
 
+/*
+ * WMI_DISCONNECT_STA_CMDID
+ */
+struct wmi_disconnect_sta_cmd {
+       u8 dst_mac[WMI_MAC_LEN];
+       __le16 disconnect_reason;
+} __packed;
 
 /*
  * WMI_RECONNECT_CMDID
@@ -289,10 +295,12 @@ struct wmi_delete_cipher_key_cmd {
 enum wmi_scan_type {
        WMI_LONG_SCAN           = 0,
        WMI_SHORT_SCAN          = 1,
+       WMI_PBC_SCAN            = 2,
 };
 
 struct wmi_start_scan_cmd {
        u8 reserved[8];
+
        __le32 home_dwell_time; /* Max duration in the home channel(ms) */
        __le32 force_scan_interval;     /* Time interval between scans (ms)*/
        u8 scan_type;           /* wmi_scan_type */
@@ -309,7 +317,7 @@ struct wmi_start_scan_cmd {
 /*
  * WMI_SET_PROBED_SSID_CMDID
  */
-#define MAX_PROBED_SSID_INDEX   (15)
+#define MAX_PROBED_SSID_INDEX  (3)
 
 enum wmi_ssid_flag {
        WMI_SSID_FLAG_DISABLE   = 0,    /* disables entry */
@@ -328,6 +336,20 @@ struct wmi_probed_ssid_cmd {
  * WMI_SET_APPIE_CMDID
  * Add Application specified IE to a management frame
  */
+#define WMI_MAX_IE_LEN         (1024)
+
+/*
+ * Frame Types
+ */
+enum wmi_mgmt_frame_type {
+       WMI_FRAME_BEACON        = 0,
+       WMI_FRAME_PROBE_REQ     = 1,
+       WMI_FRAME_PROBE_RESP    = 2,
+       WMI_FRAME_ASSOC_REQ     = 3,
+       WMI_FRAME_ASSOC_RESP    = 4,
+       WMI_NUM_MGMT_FRAME,
+};
+
 struct wmi_set_appie_cmd {
        u8 mgmt_frm_type;       /* enum wmi_mgmt_frame_type */
        u8 reserved;
@@ -335,13 +357,18 @@ struct wmi_set_appie_cmd {
        u8 ie_info[0];
 } __packed;
 
-#define WMI_MAX_IE_LEN (1024)
 
+/*
+ * WMI_PXMT_RANGE_CFG_CMDID
+ */
 struct wmi_pxmt_range_cfg_cmd {
        u8 dst_mac[WMI_MAC_LEN];
        __le16 range;
 } __packed;
 
+/*
+ * WMI_PXMT_SNR2_RANGE_CFG_CMDID
+ */
 struct wmi_pxmt_snr2_range_cfg_cmd {
        s8 snr2range_arr[WMI_PROX_RANGE_NUM-1];
 } __packed;
@@ -359,6 +386,23 @@ struct wmi_rf_mgmt_cmd {
        __le32 rf_mgmt_type;
 } __packed;
 
+
+/*
+ * WMI_RF_RX_TEST_CMDID
+ */
+struct wmi_rf_rx_test_cmd {
+       __le32 sector;
+} __packed;
+
+/*
+ * WMI_CORR_MEASURE_CMDID
+ */
+struct wmi_corr_measure_cmd {
+       s32 freq_mhz;
+       __le32 length_samples;
+       __le32 iterations;
+} __packed;
+
 /*
  * WMI_SET_SSID_CMDID
  */
@@ -388,6 +432,74 @@ struct wmi_bcon_ctrl_cmd {
        u8 disable_sec;
 } __packed;
 
+
+/******* P2P ***********/
+
+/*
+ * WMI_PORT_ALLOCATE_CMDID
+ */
+enum wmi_port_role {
+       WMI_PORT_STA            = 0,
+       WMI_PORT_PCP            = 1,
+       WMI_PORT_AP             = 2,
+       WMI_PORT_P2P_DEV        = 3,
+       WMI_PORT_P2P_CLIENT     = 4,
+       WMI_PORT_P2P_GO         = 5,
+};
+
+struct wmi_port_allocate_cmd {
+       u8 mac[WMI_MAC_LEN];
+       u8 port_role;
+       u8 midid;
+} __packed;
+
+/*
+ * WMI_PORT_DELETE_CMDID
+ */
+struct wmi_delete_port_cmd {
+       u8 mid;
+       u8 reserved[3];
+} __packed;
+
+/*
+ * WMI_P2P_CFG_CMDID
+ */
+enum wmi_discovery_mode {
+       WMI_DISCOVERY_MODE_NON_OFFLOAD  = 0,
+       WMI_DISCOVERY_MODE_OFFLOAD      = 1,
+};
+
+struct wmi_p2p_cfg_cmd {
+       u8 discovery_mode;      /* wmi_discovery_mode */
+       u8 channel;
+       __le16 bcon_interval; /* base to listen/search duration calculation */
+} __packed;
+
+/*
+ * WMI_POWER_MGMT_CFG_CMDID
+ */
+enum wmi_power_source_type {
+       WMI_POWER_SOURCE_BATTERY        = 0,
+       WMI_POWER_SOURCE_OTHER          = 1,
+};
+
+struct wmi_power_mgmt_cfg_cmd {
+       u8 power_source;        /* wmi_power_source_type */
+       u8 reserved[3];
+} __packed;
+
+/*
+ * WMI_PCP_START_CMDID
+ */
+struct wmi_pcp_start_cmd {
+       __le16 bcon_interval;
+       u8 reserved0[10];
+       u8 network_type;
+       u8 channel;
+       u8 disable_sec_offload;
+       u8 disable_sec;
+} __packed;
+
 /*
  * WMI_SW_TX_REQ_CMDID
  */
@@ -435,16 +547,17 @@ enum wmi_vring_cfg_schd_params_priority {
        WMI_SCH_PRIO_HIGH                       = 1,
 };
 
+#define CIDXTID_CID_POS (0)
+#define CIDXTID_CID_LEN (4)
+#define CIDXTID_CID_MSK (0xF)
+#define CIDXTID_TID_POS (4)
+#define CIDXTID_TID_LEN (4)
+#define CIDXTID_TID_MSK (0xF0)
+
 struct wmi_vring_cfg {
        struct wmi_sw_ring_cfg tx_sw_ring;
        u8 ringid;                              /* 0-23 vrings */
 
-       #define CIDXTID_CID_POS (0)
-       #define CIDXTID_CID_LEN (4)
-       #define CIDXTID_CID_MSK (0xF)
-       #define CIDXTID_TID_POS (4)
-       #define CIDXTID_TID_LEN (4)
-       #define CIDXTID_TID_MSK (0xF0)
        u8 cidxtid;
 
        u8 encap_trans_type;
@@ -501,8 +614,14 @@ struct wmi_vring_ba_dis_cmd {
  */
 struct wmi_notify_req_cmd {
        u8 cid;
-       u8 reserved[3];
+       u8 year;
+       u8 month;
+       u8 day;
        __le32 interval_usec;
+       u8 hour;
+       u8 minute;
+       u8 second;
+       u8 miliseconds;
 } __packed;
 
 /*
@@ -548,6 +667,11 @@ enum wmi_cfg_rx_chain_cmd_nwifi_ds_trans_type {
        WMI_NWIFI_RX_TRANS_MODE_PBSS2STA        = 2,
 };
 
+enum wmi_cfg_rx_chain_cmd_reorder_type {
+       WMI_RX_HW_REORDER = 0,
+       WMI_RX_SW_REORDER = 1,
+};
+
 struct wmi_cfg_rx_chain_cmd {
        __le32 action;
        struct wmi_sw_ring_cfg rx_sw_ring;
@@ -596,7 +720,8 @@ struct wmi_cfg_rx_chain_cmd {
        __le16 wb_thrsh;
        __le32 itr_value;
        __le16 host_thrsh;
-       u8 reserved[2];
+       u8 reorder_type;
+       u8 reserved;
        struct wmi_sniffer_cfg sniffer_cfg;
 } __packed;
 
@@ -604,15 +729,7 @@ struct wmi_cfg_rx_chain_cmd {
  * WMI_RCP_ADDBA_RESP_CMDID
  */
 struct wmi_rcp_addba_resp_cmd {
-
-       #define CIDXTID_CID_POS (0)
-       #define CIDXTID_CID_LEN (4)
-       #define CIDXTID_CID_MSK (0xF)
-       #define CIDXTID_TID_POS (4)
-       #define CIDXTID_TID_LEN (4)
-       #define CIDXTID_TID_MSK (0xF0)
        u8 cidxtid;
-
        u8 dialog_token;
        __le16 status_code;
        __le16 ba_param_set;    /* ieee80211_ba_parameterset field to send */
@@ -623,15 +740,7 @@ struct wmi_rcp_addba_resp_cmd {
  * WMI_RCP_DELBA_CMDID
  */
 struct wmi_rcp_delba_cmd {
-
-       #define CIDXTID_CID_POS (0)
-       #define CIDXTID_CID_LEN (4)
-       #define CIDXTID_CID_MSK (0xF)
-       #define CIDXTID_TID_POS (4)
-       #define CIDXTID_TID_LEN (4)
-       #define CIDXTID_TID_MSK (0xF0)
        u8 cidxtid;
-
        u8 reserved;
        __le16 reason;
 } __packed;
@@ -640,15 +749,7 @@ struct wmi_rcp_delba_cmd {
  * WMI_RCP_ADDBA_REQ_CMDID
  */
 struct wmi_rcp_addba_req_cmd {
-
-       #define CIDXTID_CID_POS (0)
-       #define CIDXTID_CID_LEN (4)
-       #define CIDXTID_CID_MSK (0xF)
-       #define CIDXTID_TID_POS (4)
-       #define CIDXTID_TID_LEN (4)
-       #define CIDXTID_TID_MSK (0xF0)
        u8 cidxtid;
-
        u8 dialog_token;
        /* ieee80211_ba_parameterset field as it received */
        __le16 ba_param_set;
@@ -665,7 +766,6 @@ struct wmi_set_mac_address_cmd {
        u8 reserved[2];
 } __packed;
 
-
 /*
 * WMI_EAPOL_TX_CMDID
 */
@@ -691,6 +791,17 @@ struct wmi_echo_cmd {
        __le32 value;
 } __packed;
 
+/*
+ * WMI_TEMP_SENSE_CMDID
+ *
+ * Measure MAC and radio temperatures
+ */
+struct wmi_temp_sense_cmd {
+       __le32 measure_marlon_m_en;
+       __le32 measure_marlon_r_en;
+} __packed;
+
+
 /*
  * WMI Events
  */
@@ -699,7 +810,6 @@ struct wmi_echo_cmd {
  * List of Events (target to host)
  */
 enum wmi_event_id {
-       WMI_IMM_RSP_EVENTID                     = 0x0000,
        WMI_READY_EVENTID                       = 0x1001,
        WMI_CONNECT_EVENTID                     = 0x1002,
        WMI_DISCONNECT_EVENTID                  = 0x1003,
@@ -709,13 +819,9 @@ enum wmi_event_id {
        WMI_FW_READY_EVENTID                    = 0x1801,
        WMI_EXIT_FAST_MEM_ACC_MODE_EVENTID      = 0x0200,
        WMI_ECHO_RSP_EVENTID                    = 0x1803,
-       WMI_CONFIG_MAC_DONE_EVENTID             = 0x1805,
-       WMI_CONFIG_PHY_DEBUG_DONE_EVENTID       = 0x1806,
-       WMI_ADD_STATION_DONE_EVENTID            = 0x1807,
-       WMI_ADD_DEBUG_TX_PCKT_DONE_EVENTID      = 0x1808,
-       WMI_PHY_GET_STATISTICS_EVENTID          = 0x1809,
        WMI_FS_TUNE_DONE_EVENTID                = 0x180a,
-       WMI_CORR_MEASURE_DONE_EVENTID           = 0x180b,
+       WMI_CORR_MEASURE_EVENTID                = 0x180b,
+       WMI_READ_RSSI_EVENTID                   = 0x180c,
        WMI_TEMP_SENSE_DONE_EVENTID             = 0x180e,
        WMI_DC_CALIB_DONE_EVENTID               = 0x180f,
        WMI_IQ_TX_CALIB_DONE_EVENTID            = 0x1811,
@@ -727,10 +833,9 @@ enum wmi_event_id {
        WMI_MARLON_R_WRITE_DONE_EVENTID         = 0x1819,
        WMI_MARLON_R_TXRX_SEL_DONE_EVENTID      = 0x181a,
        WMI_SILENT_RSSI_CALIB_DONE_EVENTID      = 0x181d,
-
+       WMI_RF_RX_TEST_DONE_EVENTID             = 0x181e,
        WMI_CFG_RX_CHAIN_DONE_EVENTID           = 0x1820,
        WMI_VRING_CFG_DONE_EVENTID              = 0x1821,
-       WMI_RX_ON_DONE_EVENTID                  = 0x1822,
        WMI_BA_STATUS_EVENTID                   = 0x1823,
        WMI_RCP_ADDBA_REQ_EVENTID               = 0x1824,
        WMI_ADDBA_RESP_SENT_EVENTID             = 0x1825,
@@ -738,7 +843,6 @@ enum wmi_event_id {
        WMI_GET_SSID_EVENTID                    = 0x1828,
        WMI_GET_PCP_CHANNEL_EVENTID             = 0x182a,
        WMI_SW_TX_COMPLETE_EVENTID              = 0x182b,
-       WMI_RX_OFF_DONE_EVENTID                 = 0x182c,
 
        WMI_READ_MAC_RXQ_EVENTID                = 0x1830,
        WMI_READ_MAC_TXQ_EVENTID                = 0x1831,
@@ -765,7 +869,16 @@ enum wmi_event_id {
        WMI_UNIT_TEST_EVENTID                   = 0x1900,
        WMI_FLASH_READ_DONE_EVENTID             = 0x1902,
        WMI_FLASH_WRITE_DONE_EVENTID            = 0x1903,
-
+       /*P2P*/
+       WMI_PORT_ALLOCATED_EVENTID              = 0x1911,
+       WMI_PORT_DELETED_EVENTID                = 0x1912,
+       WMI_LISTEN_STARTED_EVENTID              = 0x1914,
+       WMI_SEARCH_STARTED_EVENTID              = 0x1915,
+       WMI_DISCOVERY_STARTED_EVENTID           = 0x1916,
+       WMI_DISCOVERY_STOPPED_EVENTID           = 0x1917,
+       WMI_PCP_STARTED_EVENTID                 = 0x1918,
+       WMI_PCP_STOPPED_EVENTID                 = 0x1919,
+       WMI_PCP_FACTOR_EVENTID                  = 0x191a,
        WMI_SET_CHANNEL_EVENTID                 = 0x9000,
        WMI_ASSOC_REQ_EVENTID                   = 0x9001,
        WMI_EAPOL_RX_EVENTID                    = 0x9002,
@@ -777,6 +890,12 @@ enum wmi_event_id {
  * Events data structures
  */
 
+
+enum wmi_fw_status {
+       WMI_FW_STATUS_SUCCESS,
+       WMI_FW_STATUS_FAILURE,
+};
+
 /*
  * WMI_RF_MGMT_STATUS_EVENTID
  */
@@ -857,7 +976,7 @@ struct wmi_ready_event {
        __le32 abi_version;
        u8 mac[WMI_MAC_LEN];
        u8 phy_capability;              /* enum wmi_phy_capability */
-       u8 reserved;
+       u8 numof_additional_mids;
 } __packed;
 
 /*
@@ -876,6 +995,8 @@ struct wmi_notify_req_done_event {
        __le16 other_rx_sector;
        __le16 other_tx_sector;
        __le16 range;
+       u8 sqi;
+       u8 reserved[3];
 } __packed;
 
 /*
@@ -951,27 +1072,15 @@ struct wmi_vring_ba_status_event {
  * WMI_DELBA_EVENTID
  */
 struct wmi_delba_event {
-
-       #define CIDXTID_CID_POS (0)
-       #define CIDXTID_CID_LEN (4)
-       #define CIDXTID_CID_MSK (0xF)
-       #define CIDXTID_TID_POS (4)
-       #define CIDXTID_TID_LEN (4)
-       #define CIDXTID_TID_MSK (0xF0)
        u8 cidxtid;
-
        u8 from_initiator;
        __le16 reason;
 } __packed;
 
+
 /*
  * WMI_VRING_CFG_DONE_EVENTID
  */
-enum wmi_vring_cfg_done_event_status {
-       WMI_VRING_CFG_SUCCESS           = 0,
-       WMI_VRING_CFG_FAILURE           = 1,
-};
-
 struct wmi_vring_cfg_done_event {
        u8 ringid;
        u8 status;
@@ -982,21 +1091,8 @@ struct wmi_vring_cfg_done_event {
 /*
  * WMI_ADDBA_RESP_SENT_EVENTID
  */
-enum wmi_rcp_addba_resp_sent_event_status {
-       WMI_ADDBA_SUCCESS               = 0,
-       WMI_ADDBA_FAIL                  = 1,
-};
-
 struct wmi_rcp_addba_resp_sent_event {
-
-       #define CIDXTID_CID_POS (0)
-       #define CIDXTID_CID_LEN (4)
-       #define CIDXTID_CID_MSK (0xF)
-       #define CIDXTID_TID_POS (4)
-       #define CIDXTID_TID_LEN (4)
-       #define CIDXTID_TID_MSK (0xF0)
        u8 cidxtid;
-
        u8 reserved;
        __le16 status;
 } __packed;
@@ -1005,15 +1101,7 @@ struct wmi_rcp_addba_resp_sent_event {
  * WMI_RCP_ADDBA_REQ_EVENTID
  */
 struct wmi_rcp_addba_req_event {
-
-       #define CIDXTID_CID_POS (0)
-       #define CIDXTID_CID_LEN (4)
-       #define CIDXTID_CID_MSK (0xF)
-       #define CIDXTID_TID_POS (4)
-       #define CIDXTID_TID_LEN (4)
-       #define CIDXTID_TID_MSK (0xF0)
        u8 cidxtid;
-
        u8 dialog_token;
        __le16 ba_param_set;    /* ieee80211_ba_parameterset as it received */
        __le16 ba_timeout;
@@ -1055,6 +1143,7 @@ struct wmi_data_port_open_event {
        u8 reserved[3];
 } __packed;
 
+
 /*
  * WMI_GET_PCP_CHANNEL_EVENTID
  */
@@ -1063,6 +1152,54 @@ struct wmi_get_pcp_channel_event {
        u8 reserved[3];
 } __packed;
 
+
+/*
+* WMI_PORT_ALLOCATED_EVENTID
+*/
+struct wmi_port_allocated_event {
+       u8 status;      /* wmi_fw_status */
+       u8 reserved[3];
+} __packed;
+
+/*
+* WMI_PORT_DELETED_EVENTID
+*/
+struct wmi_port_deleted_event {
+       u8 status;      /* wmi_fw_status */
+       u8 reserved[3];
+} __packed;
+
+/*
+ * WMI_LISTEN_STARTED_EVENTID
+ */
+struct wmi_listen_started_event {
+       u8 status;      /* wmi_fw_status */
+       u8 reserved[3];
+} __packed;
+
+/*
+ * WMI_SEARCH_STARTED_EVENTID
+ */
+struct wmi_search_started_event {
+       u8 status;      /* wmi_fw_status */
+       u8 reserved[3];
+} __packed;
+
+/*
+ * WMI_PCP_STARTED_EVENTID
+ */
+struct wmi_pcp_started_event {
+       u8 status;      /* wmi_fw_status */
+       u8 reserved[3];
+} __packed;
+
+/*
+ * WMI_PCP_FACTOR_EVENTID
+ */
+struct wmi_pcp_factor_event {
+       __le32 pcp_factor;
+} __packed;
+
 /*
  * WMI_SW_TX_COMPLETE_EVENTID
  */
@@ -1077,6 +1214,23 @@ struct wmi_sw_tx_complete_event {
        u8 reserved[3];
 } __packed;
 
+/*
+ * WMI_CORR_MEASURE_EVENTID
+ */
+struct wmi_corr_measure_event {
+       s32 i;
+       s32 q;
+       s32 image_i;
+       s32 image_q;
+} __packed;
+
+/*
+ * WMI_READ_RSSI_EVENTID
+ */
+struct wmi_read_rssi_event {
+       __le32 ina_rssi_adc_dbm;
+} __packed;
+
 /*
  * WMI_GET_SSID_EVENTID
  */
@@ -1091,7 +1245,8 @@ struct wmi_get_ssid_event {
 struct wmi_rx_mgmt_info {
        u8 mcs;
        s8 snr;
-       __le16 range;
+       u8 range;
+       u8 sqi;
        __le16 stype;
        __le16 status;
        __le32 len;
@@ -1113,4 +1268,14 @@ struct wmi_echo_event {
        __le32 echoed_value;
 } __packed;
 
+/*
+ * WMI_TEMP_SENSE_DONE_EVENTID
+ *
+ * Measure MAC and radio temperatures
+ */
+struct wmi_temp_sense_done_event {
+       __le32 marlon_m_t1000;
+       __le32 marlon_r_t1000;
+} __packed;
+
 #endif /* __WILOCITY_WMI_H__ */
index 287c6b6..078e6f3 100644 (file)
@@ -131,7 +131,7 @@ config B43_PHY_LP
 
 config B43_PHY_HT
        bool "Support for HT-PHY (high throughput) devices"
-       depends on B43
+       depends on B43 && B43_BCMA
        ---help---
          Support for the HT-PHY.
 
@@ -166,8 +166,8 @@ config B43_DEBUG
          Broadcom 43xx debugging.
 
          This adds additional runtime sanity checks and statistics to the driver.
-         These checks and statistics might me expensive and hurt runtime performance
-         of your system.
+         These checks and statistics might be expensive and hurt the runtime
+         performance of your system.
          This also adds the b43 debugfs interface.
 
          Do not enable this, unless you are debugging the driver.
index 10e288d..fe4a77e 100644 (file)
@@ -473,6 +473,12 @@ enum {
 #define B43_MACCMD_CCA                 0x00000008      /* Clear channel assessment */
 #define B43_MACCMD_BGNOISE             0x00000010      /* Background noise */
 
+/* See BCMA_CLKCTLST_EXTRESREQ and BCMA_CLKCTLST_EXTRESST */
+#define B43_BCMA_CLKCTLST_80211_PLL_REQ        0x00000100
+#define B43_BCMA_CLKCTLST_PHY_PLL_REQ  0x00000200
+#define B43_BCMA_CLKCTLST_80211_PLL_ST 0x01000000
+#define B43_BCMA_CLKCTLST_PHY_PLL_ST   0x02000000
+
 /* BCMA 802.11 core specific IO Control (BCMA_IOCTL) flags */
 #define B43_BCMA_IOCTL_PHY_CLKEN       0x00000004      /* PHY Clock Enable */
 #define B43_BCMA_IOCTL_PHY_RESET       0x00000008      /* PHY Reset */
index 0568273..c4d0cc5 100644 (file)
@@ -1189,10 +1189,15 @@ static void b43_bcma_phy_reset(struct b43_wldev *dev)
 
 static void b43_bcma_wireless_core_reset(struct b43_wldev *dev, bool gmode)
 {
+       u32 req = B43_BCMA_CLKCTLST_80211_PLL_REQ |
+                 B43_BCMA_CLKCTLST_PHY_PLL_REQ;
+       u32 status = B43_BCMA_CLKCTLST_80211_PLL_ST |
+                    B43_BCMA_CLKCTLST_PHY_PLL_ST;
+
        b43_device_enable(dev, B43_BCMA_IOCTL_PHY_CLKEN);
        bcma_core_set_clockmode(dev->dev->bdev, BCMA_CLKMODE_FAST);
        b43_bcma_phy_reset(dev);
-       bcma_core_pll_ctl(dev->dev->bdev, 0x300, 0x3000000, true);
+       bcma_core_pll_ctl(dev->dev->bdev, req, status, true);
 }
 #endif
 
index 7416c5e..b866770 100644 (file)
@@ -153,10 +153,85 @@ static void b43_radio_2059_init(struct b43_wldev *dev)
        b43_radio_mask(dev, 0x11, ~0x0008);
 }
 
+/**************************************************
+ * RF
+ **************************************************/
+
+static void b43_phy_ht_force_rf_sequence(struct b43_wldev *dev, u16 rf_seq)
+{
+       u8 i;
+
+       u16 save_seq_mode = b43_phy_read(dev, B43_PHY_HT_RF_SEQ_MODE);
+       b43_phy_set(dev, B43_PHY_HT_RF_SEQ_MODE, 0x3);
+
+       b43_phy_set(dev, B43_PHY_HT_RF_SEQ_TRIG, rf_seq);
+       for (i = 0; i < 200; i++) {
+               if (!(b43_phy_read(dev, B43_PHY_HT_RF_SEQ_STATUS) & rf_seq)) {
+                       i = 0;
+                       break;
+               }
+               msleep(1);
+       }
+       if (i)
+               b43err(dev->wl, "Forcing RF sequence timeout\n");
+
+       b43_phy_write(dev, B43_PHY_HT_RF_SEQ_MODE, save_seq_mode);
+}
+
+static void b43_phy_ht_pa_override(struct b43_wldev *dev, bool enable)
+{
+       struct b43_phy_ht *htphy = dev->phy.ht;
+       static const u16 regs[3] = { B43_PHY_HT_RF_CTL_INT_C1,
+                                    B43_PHY_HT_RF_CTL_INT_C2,
+                                    B43_PHY_HT_RF_CTL_INT_C3 };
+       int i;
+
+       if (enable) {
+               for (i = 0; i < 3; i++)
+                       b43_phy_write(dev, regs[i], htphy->rf_ctl_int_save[i]);
+       } else {
+               for (i = 0; i < 3; i++)
+                       htphy->rf_ctl_int_save[i] = b43_phy_read(dev, regs[i]);
+               /* TODO: Does 5GHz band use different value (not 0x0400)? */
+               for (i = 0; i < 3; i++)
+                       b43_phy_write(dev, regs[i], 0x0400);
+       }
+}
+
 /**************************************************
  * Various PHY ops
  **************************************************/
 
+static u16 b43_phy_ht_classifier(struct b43_wldev *dev, u16 mask, u16 val)
+{
+       u16 tmp;
+       u16 allowed = B43_PHY_HT_CLASS_CTL_CCK_EN |
+                     B43_PHY_HT_CLASS_CTL_OFDM_EN |
+                     B43_PHY_HT_CLASS_CTL_WAITED_EN;
+
+       tmp = b43_phy_read(dev, B43_PHY_HT_CLASS_CTL);
+       tmp &= allowed;
+       tmp &= ~mask;
+       tmp |= (val & mask);
+       b43_phy_maskset(dev, B43_PHY_HT_CLASS_CTL, ~allowed, tmp);
+
+       return tmp;
+}
+
+static void b43_phy_ht_reset_cca(struct b43_wldev *dev)
+{
+       u16 bbcfg;
+
+       b43_phy_force_clock(dev, true);
+       bbcfg = b43_phy_read(dev, B43_PHY_HT_BBCFG);
+       b43_phy_write(dev, B43_PHY_HT_BBCFG, bbcfg | B43_PHY_HT_BBCFG_RSTCCA);
+       udelay(1);
+       b43_phy_write(dev, B43_PHY_HT_BBCFG, bbcfg & ~B43_PHY_HT_BBCFG_RSTCCA);
+       b43_phy_force_clock(dev, false);
+
+       b43_phy_ht_force_rf_sequence(dev, B43_PHY_HT_RF_SEQ_TRIG_RST2RX);
+}
+
 static void b43_phy_ht_zero_extg(struct b43_wldev *dev)
 {
        u8 i, j;
@@ -176,10 +251,10 @@ static void b43_phy_ht_afe_unk1(struct b43_wldev *dev)
 {
        u8 i;
 
-       const u16 ctl_regs[3][2] = {
-               { B43_PHY_HT_AFE_CTL1, B43_PHY_HT_AFE_CTL2 },
-               { B43_PHY_HT_AFE_CTL3, B43_PHY_HT_AFE_CTL4 },
-               { B43_PHY_HT_AFE_CTL5, B43_PHY_HT_AFE_CTL6},
+       static const u16 ctl_regs[3][2] = {
+               { B43_PHY_HT_AFE_C1_OVER, B43_PHY_HT_AFE_C1 },
+               { B43_PHY_HT_AFE_C2_OVER, B43_PHY_HT_AFE_C2 },
+               { B43_PHY_HT_AFE_C3_OVER, B43_PHY_HT_AFE_C3},
        };
 
        for (i = 0; i < 3; i++) {
@@ -193,27 +268,6 @@ static void b43_phy_ht_afe_unk1(struct b43_wldev *dev)
        }
 }
 
-static void b43_phy_ht_force_rf_sequence(struct b43_wldev *dev, u16 rf_seq)
-{
-       u8 i;
-
-       u16 save_seq_mode = b43_phy_read(dev, B43_PHY_HT_RF_SEQ_MODE);
-       b43_phy_set(dev, B43_PHY_HT_RF_SEQ_MODE, 0x3);
-
-       b43_phy_set(dev, B43_PHY_HT_RF_SEQ_TRIG, rf_seq);
-       for (i = 0; i < 200; i++) {
-               if (!(b43_phy_read(dev, B43_PHY_HT_RF_SEQ_STATUS) & rf_seq)) {
-                       i = 0;
-                       break;
-               }
-               msleep(1);
-       }
-       if (i)
-               b43err(dev->wl, "Forcing RF sequence timeout\n");
-
-       b43_phy_write(dev, B43_PHY_HT_RF_SEQ_MODE, save_seq_mode);
-}
-
 static void b43_phy_ht_read_clip_detection(struct b43_wldev *dev, u16 *clip_st)
 {
        clip_st[0] = b43_phy_read(dev, B43_PHY_HT_C1_CLIP1THRES);
@@ -239,16 +293,427 @@ static void b43_phy_ht_bphy_init(struct b43_wldev *dev)
        b43_phy_write(dev, B43_PHY_N_BMODE(0x38), 0x668);
 }
 
+/**************************************************
+ * Samples
+ **************************************************/
+
+static void b43_phy_ht_stop_playback(struct b43_wldev *dev)
+{
+       struct b43_phy_ht *phy_ht = dev->phy.ht;
+       u16 tmp;
+       int i;
+
+       tmp = b43_phy_read(dev, B43_PHY_HT_SAMP_STAT);
+       if (tmp & 0x1)
+               b43_phy_set(dev, B43_PHY_HT_SAMP_CMD, B43_PHY_HT_SAMP_CMD_STOP);
+       else if (tmp & 0x2)
+               b43_phy_mask(dev, B43_PHY_HT_IQLOCAL_CMDGCTL, 0x7FFF);
+
+       b43_phy_mask(dev, B43_PHY_HT_SAMP_CMD, ~0x0004);
+
+       for (i = 0; i < 3; i++) {
+               if (phy_ht->bb_mult_save[i] >= 0) {
+                       b43_httab_write(dev, B43_HTTAB16(13, 0x63 + i * 4),
+                                       phy_ht->bb_mult_save[i]);
+                       b43_httab_write(dev, B43_HTTAB16(13, 0x67 + i * 4),
+                                       phy_ht->bb_mult_save[i]);
+               }
+       }
+}
+
+static u16 b43_phy_ht_load_samples(struct b43_wldev *dev)
+{
+       int i;
+       u16 len = 20 << 3;
+
+       b43_phy_write(dev, B43_PHY_HT_TABLE_ADDR, 0x4400);
+
+       for (i = 0; i < len; i++) {
+               b43_phy_write(dev, B43_PHY_HT_TABLE_DATAHI, 0);
+               b43_phy_write(dev, B43_PHY_HT_TABLE_DATALO, 0);
+       }
+
+       return len;
+}
+
+static void b43_phy_ht_run_samples(struct b43_wldev *dev, u16 samps, u16 loops,
+                                  u16 wait)
+{
+       struct b43_phy_ht *phy_ht = dev->phy.ht;
+       u16 save_seq_mode;
+       int i;
+
+       for (i = 0; i < 3; i++) {
+               if (phy_ht->bb_mult_save[i] < 0)
+                       phy_ht->bb_mult_save[i] = b43_httab_read(dev, B43_HTTAB16(13, 0x63 + i * 4));
+       }
+
+       b43_phy_write(dev, B43_PHY_HT_SAMP_DEP_CNT, samps - 1);
+       if (loops != 0xFFFF)
+               loops--;
+       b43_phy_write(dev, B43_PHY_HT_SAMP_LOOP_CNT, loops);
+       b43_phy_write(dev, B43_PHY_HT_SAMP_WAIT_CNT, wait);
+
+       save_seq_mode = b43_phy_read(dev, B43_PHY_HT_RF_SEQ_MODE);
+       b43_phy_set(dev, B43_PHY_HT_RF_SEQ_MODE,
+                   B43_PHY_HT_RF_SEQ_MODE_CA_OVER);
+
+       /* TODO: find out mask bits! Do we need more function arguments? */
+       b43_phy_mask(dev, B43_PHY_HT_SAMP_CMD, ~0);
+       b43_phy_mask(dev, B43_PHY_HT_SAMP_CMD, ~0);
+       b43_phy_mask(dev, B43_PHY_HT_IQLOCAL_CMDGCTL, ~0);
+       b43_phy_set(dev, B43_PHY_HT_SAMP_CMD, 0x1);
+
+       for (i = 0; i < 100; i++) {
+               if (!(b43_phy_read(dev, B43_PHY_HT_RF_SEQ_STATUS) & 1)) {
+                       i = 0;
+                       break;
+               }
+               udelay(10);
+       }
+       if (i)
+               b43err(dev->wl, "run samples timeout\n");
+
+       b43_phy_write(dev, B43_PHY_HT_RF_SEQ_MODE, save_seq_mode);
+}
+
+static void b43_phy_ht_tx_tone(struct b43_wldev *dev)
+{
+       u16 samp;
+
+       samp = b43_phy_ht_load_samples(dev);
+       b43_phy_ht_run_samples(dev, samp, 0xFFFF, 0);
+}
+
+/**************************************************
+ * RSSI
+ **************************************************/
+
+static void b43_phy_ht_rssi_select(struct b43_wldev *dev, u8 core_sel,
+                                  u8 rssi_type)
+{
+       static const u16 ctl_regs[3][2] = {
+               { B43_PHY_HT_AFE_C1, B43_PHY_HT_AFE_C1_OVER, },
+               { B43_PHY_HT_AFE_C2, B43_PHY_HT_AFE_C2_OVER, },
+               { B43_PHY_HT_AFE_C3, B43_PHY_HT_AFE_C3_OVER, },
+       };
+       static const u16 radio_r[] = { R2059_SYN, R2059_TXRX0, R2059_RXRX1, };
+       int core;
+
+       if (core_sel == 0) {
+               b43err(dev->wl, "RSSI selection for core off not implemented yet\n");
+       } else {
+               for (core = 0; core < 3; core++) {
+                       /* Check if caller requested a one specific core */
+                       if ((core_sel == 1 && core != 0) ||
+                           (core_sel == 2 && core != 1) ||
+                           (core_sel == 3 && core != 2))
+                               continue;
+
+                       switch (rssi_type) {
+                       case 4:
+                               b43_phy_set(dev, ctl_regs[core][0], 0x3 << 8);
+                               b43_phy_set(dev, ctl_regs[core][0], 0x3 << 10);
+                               b43_phy_set(dev, ctl_regs[core][1], 0x1 << 9);
+                               b43_phy_set(dev, ctl_regs[core][1], 0x1 << 10);
+
+                               b43_radio_set(dev, R2059_RXRX1 | 0xbf, 0x1);
+                               b43_radio_write(dev, radio_r[core] | 0x159,
+                                               0x11);
+                               break;
+                       default:
+                               b43err(dev->wl, "RSSI selection for type %d not implemented yet\n",
+                                      rssi_type);
+                       }
+               }
+       }
+}
+
+static void b43_phy_ht_poll_rssi(struct b43_wldev *dev, u8 type, s32 *buf,
+                                u8 nsamp)
+{
+       u16 phy_regs_values[12];
+       static const u16 phy_regs_to_save[] = {
+               B43_PHY_HT_AFE_C1, B43_PHY_HT_AFE_C1_OVER,
+               0x848, 0x841,
+               B43_PHY_HT_AFE_C2, B43_PHY_HT_AFE_C2_OVER,
+               0x868, 0x861,
+               B43_PHY_HT_AFE_C3, B43_PHY_HT_AFE_C3_OVER,
+               0x888, 0x881,
+       };
+       u16 tmp[3];
+       int i;
+
+       for (i = 0; i < 12; i++)
+               phy_regs_values[i] = b43_phy_read(dev, phy_regs_to_save[i]);
+
+       b43_phy_ht_rssi_select(dev, 5, type);
+
+       for (i = 0; i < 6; i++)
+               buf[i] = 0;
+
+       for (i = 0; i < nsamp; i++) {
+               tmp[0] = b43_phy_read(dev, B43_PHY_HT_RSSI_C1);
+               tmp[1] = b43_phy_read(dev, B43_PHY_HT_RSSI_C2);
+               tmp[2] = b43_phy_read(dev, B43_PHY_HT_RSSI_C3);
+
+               buf[0] += ((s8)((tmp[0] & 0x3F) << 2)) >> 2;
+               buf[1] += ((s8)(((tmp[0] >> 8) & 0x3F) << 2)) >> 2;
+               buf[2] += ((s8)((tmp[1] & 0x3F) << 2)) >> 2;
+               buf[3] += ((s8)(((tmp[1] >> 8) & 0x3F) << 2)) >> 2;
+               buf[4] += ((s8)((tmp[2] & 0x3F) << 2)) >> 2;
+               buf[5] += ((s8)(((tmp[2] >> 8) & 0x3F) << 2)) >> 2;
+       }
+
+       for (i = 0; i < 12; i++)
+               b43_phy_write(dev, phy_regs_to_save[i], phy_regs_values[i]);
+}
+
+/**************************************************
+ * Tx/Rx
+ **************************************************/
+
+static void b43_phy_ht_tx_power_fix(struct b43_wldev *dev)
+{
+       int i;
+
+       for (i = 0; i < 3; i++) {
+               u16 mask;
+               u32 tmp = b43_httab_read(dev, B43_HTTAB32(26, 0xE8));
+
+               if (0) /* FIXME */
+                       mask = 0x2 << (i * 4);
+               else
+                       mask = 0;
+               b43_phy_mask(dev, B43_PHY_EXTG(0x108), mask);
+
+               b43_httab_write(dev, B43_HTTAB16(7, 0x110 + i), tmp >> 16);
+               b43_httab_write(dev, B43_HTTAB8(13, 0x63 + (i * 4)),
+                               tmp & 0xFF);
+               b43_httab_write(dev, B43_HTTAB8(13, 0x73 + (i * 4)),
+                               tmp & 0xFF);
+       }
+}
+
+static void b43_phy_ht_tx_power_ctl(struct b43_wldev *dev, bool enable)
+{
+       struct b43_phy_ht *phy_ht = dev->phy.ht;
+       u16 en_bits = B43_PHY_HT_TXPCTL_CMD_C1_COEFF |
+                     B43_PHY_HT_TXPCTL_CMD_C1_HWPCTLEN |
+                     B43_PHY_HT_TXPCTL_CMD_C1_PCTLEN;
+       static const u16 cmd_regs[3] = { B43_PHY_HT_TXPCTL_CMD_C1,
+                                        B43_PHY_HT_TXPCTL_CMD_C2,
+                                        B43_PHY_HT_TXPCTL_CMD_C3 };
+       int i;
+
+       if (!enable) {
+               if (b43_phy_read(dev, B43_PHY_HT_TXPCTL_CMD_C1) & en_bits) {
+                       /* We disable enabled TX pwr ctl, save it's state */
+                       /*
+                        * TODO: find the registers. On N-PHY they were 0x1ed
+                        * and 0x1ee, we need 3 such a registers for HT-PHY
+                        */
+               }
+               b43_phy_mask(dev, B43_PHY_HT_TXPCTL_CMD_C1, ~en_bits);
+       } else {
+               b43_phy_set(dev, B43_PHY_HT_TXPCTL_CMD_C1, en_bits);
+
+               if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) {
+                       for (i = 0; i < 3; i++)
+                               b43_phy_write(dev, cmd_regs[i], 0x32);
+               }
+
+               for (i = 0; i < 3; i++)
+                       if (phy_ht->tx_pwr_idx[i] <=
+                           B43_PHY_HT_TXPCTL_CMD_C1_INIT)
+                               b43_phy_write(dev, cmd_regs[i],
+                                             phy_ht->tx_pwr_idx[i]);
+       }
+
+       phy_ht->tx_pwr_ctl = enable;
+}
+
+static void b43_phy_ht_tx_power_ctl_idle_tssi(struct b43_wldev *dev)
+{
+       struct b43_phy_ht *phy_ht = dev->phy.ht;
+       s32 rssi_buf[6];
+
+       /* TODO */
+
+       b43_phy_ht_tx_tone(dev);
+       udelay(20);
+       b43_phy_ht_poll_rssi(dev, 4, rssi_buf, 1);
+       b43_phy_ht_stop_playback(dev);
+       b43_phy_ht_reset_cca(dev);
+
+       phy_ht->idle_tssi[0] = rssi_buf[0] & 0xff;
+       phy_ht->idle_tssi[1] = rssi_buf[2] & 0xff;
+       phy_ht->idle_tssi[2] = rssi_buf[4] & 0xff;
+
+       /* TODO */
+}
+
+static void b43_phy_ht_tx_power_ctl_setup(struct b43_wldev *dev)
+{
+       struct b43_phy_ht *phy_ht = dev->phy.ht;
+       struct ssb_sprom *sprom = dev->dev->bus_sprom;
+
+       u8 *idle = phy_ht->idle_tssi;
+       u8 target[3];
+       s16 a1[3], b0[3], b1[3];
+
+       u16 freq = dev->phy.channel_freq;
+       int i, c;
+
+       if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+               for (c = 0; c < 3; c++) {
+                       target[c] = sprom->core_pwr_info[c].maxpwr_2g;
+                       a1[c] = sprom->core_pwr_info[c].pa_2g[0];
+                       b0[c] = sprom->core_pwr_info[c].pa_2g[1];
+                       b1[c] = sprom->core_pwr_info[c].pa_2g[2];
+               }
+       } else if (freq >= 4900 && freq < 5100) {
+               for (c = 0; c < 3; c++) {
+                       target[c] = sprom->core_pwr_info[c].maxpwr_5gl;
+                       a1[c] = sprom->core_pwr_info[c].pa_5gl[0];
+                       b0[c] = sprom->core_pwr_info[c].pa_5gl[1];
+                       b1[c] = sprom->core_pwr_info[c].pa_5gl[2];
+               }
+       } else if (freq >= 5100 && freq < 5500) {
+               for (c = 0; c < 3; c++) {
+                       target[c] = sprom->core_pwr_info[c].maxpwr_5g;
+                       a1[c] = sprom->core_pwr_info[c].pa_5g[0];
+                       b0[c] = sprom->core_pwr_info[c].pa_5g[1];
+                       b1[c] = sprom->core_pwr_info[c].pa_5g[2];
+               }
+       } else if (freq >= 5500) {
+               for (c = 0; c < 3; c++) {
+                       target[c] = sprom->core_pwr_info[c].maxpwr_5gh;
+                       a1[c] = sprom->core_pwr_info[c].pa_5gh[0];
+                       b0[c] = sprom->core_pwr_info[c].pa_5gh[1];
+                       b1[c] = sprom->core_pwr_info[c].pa_5gh[2];
+               }
+       } else {
+               target[0] = target[1] = target[2] = 52;
+               a1[0] = a1[1] = a1[2] = -424;
+               b0[0] = b0[1] = b0[2] = 5612;
+               b1[0] = b1[1] = b1[2] = -1393;
+       }
+
+       b43_phy_set(dev, B43_PHY_HT_TSSIMODE, B43_PHY_HT_TSSIMODE_EN);
+       b43_phy_mask(dev, B43_PHY_HT_TXPCTL_CMD_C1,
+                    ~B43_PHY_HT_TXPCTL_CMD_C1_PCTLEN & 0xFFFF);
+
+       /* TODO: Does it depend on sprom->fem.ghz2.tssipos? */
+       b43_phy_set(dev, B43_PHY_HT_TXPCTL_IDLE_TSSI, 0x4000);
+
+       b43_phy_maskset(dev, B43_PHY_HT_TXPCTL_CMD_C1,
+                       ~B43_PHY_HT_TXPCTL_CMD_C1_INIT, 0x19);
+       b43_phy_maskset(dev, B43_PHY_HT_TXPCTL_CMD_C2,
+                       ~B43_PHY_HT_TXPCTL_CMD_C2_INIT, 0x19);
+       b43_phy_maskset(dev, B43_PHY_HT_TXPCTL_CMD_C3,
+                       ~B43_PHY_HT_TXPCTL_CMD_C3_INIT, 0x19);
+
+       b43_phy_set(dev, B43_PHY_HT_TXPCTL_IDLE_TSSI,
+                   B43_PHY_HT_TXPCTL_IDLE_TSSI_BINF);
+
+       b43_phy_maskset(dev, B43_PHY_HT_TXPCTL_IDLE_TSSI,
+                       ~B43_PHY_HT_TXPCTL_IDLE_TSSI_C1,
+                       idle[0] << B43_PHY_HT_TXPCTL_IDLE_TSSI_C1_SHIFT);
+       b43_phy_maskset(dev, B43_PHY_HT_TXPCTL_IDLE_TSSI,
+                       ~B43_PHY_HT_TXPCTL_IDLE_TSSI_C2,
+                       idle[1] << B43_PHY_HT_TXPCTL_IDLE_TSSI_C2_SHIFT);
+       b43_phy_maskset(dev, B43_PHY_HT_TXPCTL_IDLE_TSSI2,
+                       ~B43_PHY_HT_TXPCTL_IDLE_TSSI2_C3,
+                       idle[2] << B43_PHY_HT_TXPCTL_IDLE_TSSI2_C3_SHIFT);
+
+       b43_phy_maskset(dev, B43_PHY_HT_TXPCTL_N, ~B43_PHY_HT_TXPCTL_N_TSSID,
+                       0xf0);
+       b43_phy_maskset(dev, B43_PHY_HT_TXPCTL_N, ~B43_PHY_HT_TXPCTL_N_NPTIL2,
+                       0x3 << B43_PHY_HT_TXPCTL_N_NPTIL2_SHIFT);
+#if 0
+       /* TODO: what to mask/set? */
+       b43_phy_maskset(dev, B43_PHY_HT_TXPCTL_CMD_C1, 0x800, 0)
+       b43_phy_maskset(dev, B43_PHY_HT_TXPCTL_CMD_C1, 0x400, 0)
+#endif
+
+       b43_phy_maskset(dev, B43_PHY_HT_TXPCTL_TARG_PWR,
+                       ~B43_PHY_HT_TXPCTL_TARG_PWR_C1,
+                       target[0] << B43_PHY_HT_TXPCTL_TARG_PWR_C1_SHIFT);
+       b43_phy_maskset(dev, B43_PHY_HT_TXPCTL_TARG_PWR,
+                       ~B43_PHY_HT_TXPCTL_TARG_PWR_C2 & 0xFFFF,
+                       target[1] << B43_PHY_HT_TXPCTL_TARG_PWR_C2_SHIFT);
+       b43_phy_maskset(dev, B43_PHY_HT_TXPCTL_TARG_PWR2,
+                       ~B43_PHY_HT_TXPCTL_TARG_PWR2_C3,
+                       target[2] << B43_PHY_HT_TXPCTL_TARG_PWR2_C3_SHIFT);
+
+       for (c = 0; c < 3; c++) {
+               s32 num, den, pwr;
+               u32 regval[64];
+
+               for (i = 0; i < 64; i++) {
+                       num = 8 * (16 * b0[c] + b1[c] * i);
+                       den = 32768 + a1[c] * i;
+                       pwr = max((4 * num + den / 2) / den, -8);
+                       regval[i] = pwr;
+               }
+               b43_httab_write_bulk(dev, B43_HTTAB16(26 + c, 0), 64, regval);
+       }
+}
+
 /**************************************************
  * Channel switching ops.
  **************************************************/
 
+static void b43_phy_ht_spur_avoid(struct b43_wldev *dev,
+                                 struct ieee80211_channel *new_channel)
+{
+       struct bcma_device *core = dev->dev->bdev;
+       int spuravoid = 0;
+       u16 tmp;
+
+       /* Check for 13 and 14 is just a guess, we don't have enough logs. */
+       if (new_channel->hw_value == 13 || new_channel->hw_value == 14)
+               spuravoid = 1;
+       bcma_core_pll_ctl(core, B43_BCMA_CLKCTLST_PHY_PLL_REQ, 0, false);
+       bcma_pmu_spuravoid_pllupdate(&core->bus->drv_cc, spuravoid);
+       bcma_core_pll_ctl(core,
+                         B43_BCMA_CLKCTLST_80211_PLL_REQ |
+                         B43_BCMA_CLKCTLST_PHY_PLL_REQ,
+                         B43_BCMA_CLKCTLST_80211_PLL_ST |
+                         B43_BCMA_CLKCTLST_PHY_PLL_ST, false);
+
+       /* Values has been taken from wlc_bmac_switch_macfreq comments */
+       switch (spuravoid) {
+       case 2: /* 126MHz */
+               tmp = 0x2082;
+               break;
+       case 1: /* 123MHz */
+               tmp = 0x5341;
+               break;
+       default: /* 120MHz */
+               tmp = 0x8889;
+       }
+
+       b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, tmp);
+       b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x8);
+
+       /* TODO: reset PLL */
+
+       if (spuravoid)
+               b43_phy_set(dev, B43_PHY_HT_BBCFG, B43_PHY_HT_BBCFG_RSTRX);
+       else
+               b43_phy_mask(dev, B43_PHY_HT_BBCFG,
+                               ~B43_PHY_HT_BBCFG_RSTRX & 0xFFFF);
+
+       b43_phy_ht_reset_cca(dev);
+}
+
 static void b43_phy_ht_channel_setup(struct b43_wldev *dev,
                                const struct b43_phy_ht_channeltab_e_phy *e,
                                struct ieee80211_channel *new_channel)
 {
        bool old_band_5ghz;
-       u8 i;
 
        old_band_5ghz = b43_phy_read(dev, B43_PHY_HT_BANDCTL) & 0; /* FIXME */
        if (new_channel->band == IEEE80211_BAND_5GHZ && !old_band_5ghz) {
@@ -264,25 +729,20 @@ static void b43_phy_ht_channel_setup(struct b43_wldev *dev,
        b43_phy_write(dev, B43_PHY_HT_BW5, e->bw5);
        b43_phy_write(dev, B43_PHY_HT_BW6, e->bw6);
 
-       /* TODO: some ops on PHY regs 0x0B0 and 0xC0A */
+       if (new_channel->hw_value == 14) {
+               b43_phy_ht_classifier(dev, B43_PHY_HT_CLASS_CTL_OFDM_EN, 0);
+               b43_phy_set(dev, B43_PHY_HT_TEST, 0x0800);
+       } else {
+               b43_phy_ht_classifier(dev, B43_PHY_HT_CLASS_CTL_OFDM_EN,
+                                     B43_PHY_HT_CLASS_CTL_OFDM_EN);
+               if (new_channel->band == IEEE80211_BAND_2GHZ)
+                       b43_phy_mask(dev, B43_PHY_HT_TEST, ~0x840);
+       }
 
-       /* TODO: separated function? */
-       for (i = 0; i < 3; i++) {
-               u16 mask;
-               u32 tmp = b43_httab_read(dev, B43_HTTAB32(26, 0xE8));
+       if (1) /* TODO: On N it's for early devices only, what about HT? */
+               b43_phy_ht_tx_power_fix(dev);
 
-               if (0) /* FIXME */
-                       mask = 0x2 << (i * 4);
-               else
-                       mask = 0;
-               b43_phy_mask(dev, B43_PHY_EXTG(0x108), mask);
-
-               b43_httab_write(dev, B43_HTTAB16(7, 0x110 + i), tmp >> 16);
-               b43_httab_write(dev, B43_HTTAB8(13, 0x63 + (i * 4)),
-                               tmp & 0xFF);
-               b43_httab_write(dev, B43_HTTAB8(13, 0x73 + (i * 4)),
-                               tmp & 0xFF);
-       }
+       b43_phy_ht_spur_avoid(dev, new_channel);
 
        b43_phy_write(dev, 0x017e, 0x3830);
 }
@@ -337,14 +797,29 @@ static void b43_phy_ht_op_prepare_structs(struct b43_wldev *dev)
 {
        struct b43_phy *phy = &dev->phy;
        struct b43_phy_ht *phy_ht = phy->ht;
+       int i;
 
        memset(phy_ht, 0, sizeof(*phy_ht));
+
+       phy_ht->tx_pwr_ctl = true;
+       for (i = 0; i < 3; i++)
+               phy_ht->tx_pwr_idx[i] = B43_PHY_HT_TXPCTL_CMD_C1_INIT + 1;
+
+       for (i = 0; i < 3; i++)
+               phy_ht->bb_mult_save[i] = -1;
 }
 
 static int b43_phy_ht_op_init(struct b43_wldev *dev)
 {
+       struct b43_phy_ht *phy_ht = dev->phy.ht;
        u16 tmp;
        u16 clip_state[3];
+       bool saved_tx_pwr_ctl;
+
+       if (dev->dev->bus_type != B43_BUS_BCMA) {
+               b43err(dev->wl, "HT-PHY is supported only on BCMA bus!\n");
+               return -EOPNOTSUPP;
+       }
 
        b43_phy_ht_tables_init(dev);
 
@@ -357,9 +832,9 @@ static int b43_phy_ht_op_init(struct b43_wldev *dev)
 
        b43_phy_mask(dev, B43_PHY_EXTG(0), ~0x3);
 
-       b43_phy_write(dev, B43_PHY_HT_AFE_CTL1, 0);
-       b43_phy_write(dev, B43_PHY_HT_AFE_CTL3, 0);
-       b43_phy_write(dev, B43_PHY_HT_AFE_CTL5, 0);
+       b43_phy_write(dev, B43_PHY_HT_AFE_C1_OVER, 0);
+       b43_phy_write(dev, B43_PHY_HT_AFE_C2_OVER, 0);
+       b43_phy_write(dev, B43_PHY_HT_AFE_C3_OVER, 0);
 
        b43_phy_write(dev, B43_PHY_EXTG(0x103), 0x20);
        b43_phy_write(dev, B43_PHY_EXTG(0x101), 0x20);
@@ -371,8 +846,11 @@ static int b43_phy_ht_op_init(struct b43_wldev *dev)
        if (0) /* TODO: condition */
                ; /* TODO: PHY op on reg 0x217 */
 
-       b43_phy_read(dev, 0xb0); /* TODO: what for? */
-       b43_phy_set(dev, 0xb0, 0x1);
+       if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ)
+               b43_phy_ht_classifier(dev, B43_PHY_HT_CLASS_CTL_CCK_EN, 0);
+       else
+               b43_phy_ht_classifier(dev, B43_PHY_HT_CLASS_CTL_CCK_EN,
+                                     B43_PHY_HT_CLASS_CTL_CCK_EN);
 
        b43_phy_set(dev, 0xb1, 0x91);
        b43_phy_write(dev, 0x32f, 0x0003);
@@ -448,12 +926,13 @@ static int b43_phy_ht_op_init(struct b43_wldev *dev)
 
        b43_mac_phy_clock_set(dev, true);
 
+       b43_phy_ht_pa_override(dev, false);
        b43_phy_ht_force_rf_sequence(dev, B43_PHY_HT_RF_SEQ_TRIG_RX2TX);
        b43_phy_ht_force_rf_sequence(dev, B43_PHY_HT_RF_SEQ_TRIG_RST2RX);
-
-       /* TODO: PHY op on reg 0xb0 */
+       b43_phy_ht_pa_override(dev, true);
 
        /* TODO: Should we restore it? Or store it in global PHY info? */
+       b43_phy_ht_classifier(dev, 0, 0);
        b43_phy_ht_read_clip_detection(dev, clip_state);
 
        if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
@@ -462,6 +941,13 @@ static int b43_phy_ht_op_init(struct b43_wldev *dev)
        b43_httab_write_bulk(dev, B43_HTTAB32(0x1a, 0xc0),
                        B43_HTTAB_1A_C0_LATE_SIZE, b43_httab_0x1a_0xc0_late);
 
+       saved_tx_pwr_ctl = phy_ht->tx_pwr_ctl;
+       b43_phy_ht_tx_power_fix(dev);
+       b43_phy_ht_tx_power_ctl(dev, false);
+       b43_phy_ht_tx_power_ctl_idle_tssi(dev);
+       b43_phy_ht_tx_power_ctl_setup(dev);
+       b43_phy_ht_tx_power_ctl(dev, saved_tx_pwr_ctl);
+
        return 0;
 }
 
@@ -506,19 +992,19 @@ static void b43_phy_ht_op_software_rfkill(struct b43_wldev *dev,
 static void b43_phy_ht_op_switch_analog(struct b43_wldev *dev, bool on)
 {
        if (on) {
-               b43_phy_write(dev, B43_PHY_HT_AFE_CTL2, 0x00cd);
-               b43_phy_write(dev, B43_PHY_HT_AFE_CTL1, 0x0000);
-               b43_phy_write(dev, B43_PHY_HT_AFE_CTL4, 0x00cd);
-               b43_phy_write(dev, B43_PHY_HT_AFE_CTL3, 0x0000);
-               b43_phy_write(dev, B43_PHY_HT_AFE_CTL6, 0x00cd);
-               b43_phy_write(dev, B43_PHY_HT_AFE_CTL5, 0x0000);
+               b43_phy_write(dev, B43_PHY_HT_AFE_C1, 0x00cd);
+               b43_phy_write(dev, B43_PHY_HT_AFE_C1_OVER, 0x0000);
+               b43_phy_write(dev, B43_PHY_HT_AFE_C2, 0x00cd);
+               b43_phy_write(dev, B43_PHY_HT_AFE_C2_OVER, 0x0000);
+               b43_phy_write(dev, B43_PHY_HT_AFE_C3, 0x00cd);
+               b43_phy_write(dev, B43_PHY_HT_AFE_C3_OVER, 0x0000);
        } else {
-               b43_phy_write(dev, B43_PHY_HT_AFE_CTL1, 0x07ff);
-               b43_phy_write(dev, B43_PHY_HT_AFE_CTL2, 0x00fd);
-               b43_phy_write(dev, B43_PHY_HT_AFE_CTL3, 0x07ff);
-               b43_phy_write(dev, B43_PHY_HT_AFE_CTL4, 0x00fd);
-               b43_phy_write(dev, B43_PHY_HT_AFE_CTL5, 0x07ff);
-               b43_phy_write(dev, B43_PHY_HT_AFE_CTL6, 0x00fd);
+               b43_phy_write(dev, B43_PHY_HT_AFE_C1_OVER, 0x07ff);
+               b43_phy_write(dev, B43_PHY_HT_AFE_C1, 0x00fd);
+               b43_phy_write(dev, B43_PHY_HT_AFE_C2_OVER, 0x07ff);
+               b43_phy_write(dev, B43_PHY_HT_AFE_C2, 0x00fd);
+               b43_phy_write(dev, B43_PHY_HT_AFE_C3_OVER, 0x07ff);
+               b43_phy_write(dev, B43_PHY_HT_AFE_C3, 0x00fd);
        }
 }
 
index 6544c42..9b2408e 100644 (file)
 #define B43_PHY_HT_TABLE_ADDR                  0x072 /* Table address */
 #define B43_PHY_HT_TABLE_DATALO                        0x073 /* Table data low */
 #define B43_PHY_HT_TABLE_DATAHI                        0x074 /* Table data high */
+#define B43_PHY_HT_CLASS_CTL                   0x0B0 /* Classifier control */
+#define  B43_PHY_HT_CLASS_CTL_CCK_EN           0x0001 /* CCK enable */
+#define  B43_PHY_HT_CLASS_CTL_OFDM_EN          0x0002 /* OFDM enable */
+#define  B43_PHY_HT_CLASS_CTL_WAITED_EN                0x0004 /* Waited enable */
+#define B43_PHY_HT_IQLOCAL_CMDGCTL             0x0C2   /* I/Q LO cal command G control */
+#define B43_PHY_HT_SAMP_CMD                    0x0C3   /* Sample command */
+#define  B43_PHY_HT_SAMP_CMD_STOP              0x0002  /* Stop */
+#define B43_PHY_HT_SAMP_LOOP_CNT               0x0C4   /* Sample loop count */
+#define B43_PHY_HT_SAMP_WAIT_CNT               0x0C5   /* Sample wait count */
+#define B43_PHY_HT_SAMP_DEP_CNT                        0x0C6   /* Sample depth count */
+#define B43_PHY_HT_SAMP_STAT                   0x0C7   /* Sample status */
+#define B43_PHY_HT_TSSIMODE                    0x122   /* TSSI mode */
+#define  B43_PHY_HT_TSSIMODE_EN                        0x0001  /* TSSI enable */
+#define  B43_PHY_HT_TSSIMODE_PDEN              0x0002  /* Power det enable */
 #define B43_PHY_HT_BW1                         0x1CE
 #define B43_PHY_HT_BW2                         0x1CF
 #define B43_PHY_HT_BW3                         0x1D0
 #define B43_PHY_HT_BW4                         0x1D1
 #define B43_PHY_HT_BW5                         0x1D2
 #define B43_PHY_HT_BW6                         0x1D3
+#define B43_PHY_HT_TXPCTL_CMD_C1               0x1E7   /* TX power control command */
+#define  B43_PHY_HT_TXPCTL_CMD_C1_INIT         0x007F  /* Init */
+#define  B43_PHY_HT_TXPCTL_CMD_C1_COEFF                0x2000  /* Power control coefficients */
+#define  B43_PHY_HT_TXPCTL_CMD_C1_HWPCTLEN     0x4000  /* Hardware TX power control enable */
+#define  B43_PHY_HT_TXPCTL_CMD_C1_PCTLEN       0x8000  /* TX power control enable */
+#define B43_PHY_HT_TXPCTL_N                    0x1E8   /* TX power control N num */
+#define  B43_PHY_HT_TXPCTL_N_TSSID             0x00FF  /* N TSSI delay */
+#define  B43_PHY_HT_TXPCTL_N_TSSID_SHIFT       0
+#define  B43_PHY_HT_TXPCTL_N_NPTIL2            0x0700  /* N PT integer log2 */
+#define  B43_PHY_HT_TXPCTL_N_NPTIL2_SHIFT      8
+#define B43_PHY_HT_TXPCTL_IDLE_TSSI            0x1E9   /* TX power control idle TSSI */
+#define  B43_PHY_HT_TXPCTL_IDLE_TSSI_C1                0x003F
+#define  B43_PHY_HT_TXPCTL_IDLE_TSSI_C1_SHIFT  0
+#define  B43_PHY_HT_TXPCTL_IDLE_TSSI_C2                0x3F00
+#define  B43_PHY_HT_TXPCTL_IDLE_TSSI_C2_SHIFT  8
+#define  B43_PHY_HT_TXPCTL_IDLE_TSSI_BINF      0x8000  /* Raw TSSI offset bin format */
+#define B43_PHY_HT_TXPCTL_TARG_PWR             0x1EA   /* TX power control target power */
+#define  B43_PHY_HT_TXPCTL_TARG_PWR_C1         0x00FF  /* Power 0 */
+#define  B43_PHY_HT_TXPCTL_TARG_PWR_C1_SHIFT   0
+#define  B43_PHY_HT_TXPCTL_TARG_PWR_C2         0xFF00  /* Power 1 */
+#define  B43_PHY_HT_TXPCTL_TARG_PWR_C2_SHIFT   8
+#define B43_PHY_HT_TXPCTL_CMD_C2               0x222
+#define  B43_PHY_HT_TXPCTL_CMD_C2_INIT         0x007F
+#define B43_PHY_HT_RSSI_C1                     0x219
+#define B43_PHY_HT_RSSI_C2                     0x21A
+#define B43_PHY_HT_RSSI_C3                     0x21B
 
 #define B43_PHY_HT_C1_CLIP1THRES               B43_PHY_OFDM(0x00E)
 #define B43_PHY_HT_C2_CLIP1THRES               B43_PHY_OFDM(0x04E)
 #define B43_PHY_HT_C3_CLIP1THRES               B43_PHY_OFDM(0x08E)
 
 #define B43_PHY_HT_RF_SEQ_MODE                 B43_PHY_EXTG(0x000)
+#define  B43_PHY_HT_RF_SEQ_MODE_CA_OVER                0x0001  /* Core active override */
+#define  B43_PHY_HT_RF_SEQ_MODE_TR_OVER                0x0002  /* Trigger override */
 #define B43_PHY_HT_RF_SEQ_TRIG                 B43_PHY_EXTG(0x003)
 #define  B43_PHY_HT_RF_SEQ_TRIG_RX2TX          0x0001 /* RX2TX */
 #define  B43_PHY_HT_RF_SEQ_TRIG_TX2RX          0x0002 /* TX2RX */
 
 #define B43_PHY_HT_RF_CTL1                     B43_PHY_EXTG(0x010)
 
-#define B43_PHY_HT_AFE_CTL1                    B43_PHY_EXTG(0x110)
-#define B43_PHY_HT_AFE_CTL2                    B43_PHY_EXTG(0x111)
-#define B43_PHY_HT_AFE_CTL3                    B43_PHY_EXTG(0x114)
-#define B43_PHY_HT_AFE_CTL4                    B43_PHY_EXTG(0x115)
-#define B43_PHY_HT_AFE_CTL5                    B43_PHY_EXTG(0x118)
-#define B43_PHY_HT_AFE_CTL6                    B43_PHY_EXTG(0x119)
+#define B43_PHY_HT_RF_CTL_INT_C1               B43_PHY_EXTG(0x04c)
+#define B43_PHY_HT_RF_CTL_INT_C2               B43_PHY_EXTG(0x06c)
+#define B43_PHY_HT_RF_CTL_INT_C3               B43_PHY_EXTG(0x08c)
+
+#define B43_PHY_HT_AFE_C1_OVER                 B43_PHY_EXTG(0x110)
+#define B43_PHY_HT_AFE_C1                      B43_PHY_EXTG(0x111)
+#define B43_PHY_HT_AFE_C2_OVER                 B43_PHY_EXTG(0x114)
+#define B43_PHY_HT_AFE_C2                      B43_PHY_EXTG(0x115)
+#define B43_PHY_HT_AFE_C3_OVER                 B43_PHY_EXTG(0x118)
+#define B43_PHY_HT_AFE_C3                      B43_PHY_EXTG(0x119)
+
+#define B43_PHY_HT_TXPCTL_CMD_C3               B43_PHY_EXTG(0x164)
+#define  B43_PHY_HT_TXPCTL_CMD_C3_INIT         0x007F
+#define B43_PHY_HT_TXPCTL_IDLE_TSSI2           B43_PHY_EXTG(0x165)     /* TX power control idle TSSI */
+#define  B43_PHY_HT_TXPCTL_IDLE_TSSI2_C3       0x003F
+#define  B43_PHY_HT_TXPCTL_IDLE_TSSI2_C3_SHIFT 0
+#define B43_PHY_HT_TXPCTL_TARG_PWR2            B43_PHY_EXTG(0x166)     /* TX power control target power */
+#define  B43_PHY_HT_TXPCTL_TARG_PWR2_C3                0x00FF
+#define  B43_PHY_HT_TXPCTL_TARG_PWR2_C3_SHIFT  0
+
+#define B43_PHY_HT_TEST                                B43_PHY_N_BMODE(0x00A)
 
 
 /* Values for PHY registers used on channel switching */
@@ -56,6 +113,14 @@ struct b43_phy_ht_channeltab_e_phy {
 
 
 struct b43_phy_ht {
+       u16 rf_ctl_int_save[3];
+
+       bool tx_pwr_ctl;
+       u8 tx_pwr_idx[3];
+
+       s32 bb_mult_save[3];
+
+       u8 idle_tssi[3];
 };
 
 
index 1d92d87..747e931 100644 (file)
@@ -12,8 +12,9 @@ config BRCMSMAC
        select CORDIC
        ---help---
          This module adds support for PCIe wireless adapters based on Broadcom
-         IEEE802.11n SoftMAC chipsets.  If you choose to build a module, it'll
-         be called brcmsmac.ko.
+         IEEE802.11n SoftMAC chipsets. It also has WLAN led support, which will
+         be available if you select BCMA_DRIVER_GPIO. If you choose to build a
+         module, the driver will be called brcmsmac.ko.
 
 config BRCMFMAC
        tristate "Broadcom IEEE802.11n embedded FullMAC WLAN driver"
index 756e19f..598c8e2 100644 (file)
@@ -26,6 +26,7 @@ brcmfmac-objs += \
                wl_cfg80211.o \
                fwil.o \
                fweh.o \
+               fwsignal.o \
                p2p.o \
                dhd_cdc.o \
                dhd_common.o \
@@ -39,3 +40,5 @@ brcmfmac-$(CONFIG_BRCMFMAC_USB) += \
                usb.o
 brcmfmac-$(CONFIG_BRCMDBG) += \
                dhd_dbg.o
+brcmfmac-$(CONFIG_BRCM_TRACING) += \
+               tracepoint.o
index ef6f23b..c7fa208 100644 (file)
@@ -501,6 +501,7 @@ struct brcmf_dcmd {
 /* Forward decls for struct brcmf_pub (see below) */
 struct brcmf_proto;    /* device communication protocol info */
 struct brcmf_cfg80211_dev; /* cfg80211 device info */
+struct brcmf_fws_info; /* firmware signalling info */
 
 /* Common structure for module and instance linkage */
 struct brcmf_pub {
@@ -527,6 +528,10 @@ struct brcmf_pub {
        unsigned char proto_buf[BRCMF_DCMD_MAXLEN];
 
        struct brcmf_fweh_info fweh;
+
+       bool fw_signals;
+       struct brcmf_fws_info *fws;
+       spinlock_t fws_spinlock;
 #ifdef DEBUG
        struct dentry *dbgfs_dir;
 #endif
@@ -582,7 +587,7 @@ extern int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,
                                    void *buf, uint len);
 
 /* Remove any protocol-specific data header. */
-extern int brcmf_proto_hdrpull(struct brcmf_pub *drvr, u8 *ifidx,
+extern int brcmf_proto_hdrpull(struct brcmf_pub *drvr, bool do_fws, u8 *ifidx,
                               struct sk_buff *rxp);
 
 extern int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked);
index ad25c34..883ef90 100644 (file)
@@ -134,7 +134,7 @@ extern void brcmf_dev_reset(struct device *dev);
 /* Indication from bus module to change flow-control state */
 extern void brcmf_txflowblock(struct device *dev, bool state);
 
-/* Notify tx completion */
+/* Notify the bus has transferred the tx packet to firmware */
 extern void brcmf_txcomplete(struct device *dev, struct sk_buff *txp,
                             bool success);
 
index a2354d9..e224bcb 100644 (file)
@@ -28,6 +28,7 @@
 #include "dhd.h"
 #include "dhd_proto.h"
 #include "dhd_bus.h"
+#include "fwsignal.h"
 #include "dhd_dbg.h"
 
 struct brcmf_proto_cdc_dcmd {
@@ -71,13 +72,26 @@ struct brcmf_proto_cdc_dcmd {
        ((hdr)->flags2 = (((hdr)->flags2 & ~BDC_FLAG2_IF_MASK) | \
        ((idx) << BDC_FLAG2_IF_SHIFT)))
 
+/**
+ * struct brcmf_proto_bdc_header - BDC header format
+ *
+ * @flags: flags contain protocol and checksum info.
+ * @priority: 802.1d priority and USB flow control info (bit 4:7).
+ * @flags2: additional flags containing dongle interface index.
+ * @data_offset: start of packet data. header is following by firmware signals.
+ */
 struct brcmf_proto_bdc_header {
        u8 flags;
-       u8 priority;    /* 802.1d Priority, 4:7 flow control info for usb */
+       u8 priority;
        u8 flags2;
        u8 data_offset;
 };
 
+/*
+ * maximum length of firmware signal data between
+ * the BDC header and packet data in the tx path.
+ */
+#define BRCMF_PROT_FW_SIGNAL_MAX_TXBYTES       12
 
 #define RETRIES 2 /* # of retries to retrieve matching dcmd response */
 #define BUS_HEADER_LEN (16+64)         /* Must be atleast SDPCM_RESERVE
@@ -258,7 +272,7 @@ static void pkt_set_sum_good(struct sk_buff *skb, bool x)
        skb->ip_summed = (x ? CHECKSUM_UNNECESSARY : CHECKSUM_NONE);
 }
 
-void brcmf_proto_hdrpush(struct brcmf_pub *drvr, int ifidx,
+void brcmf_proto_hdrpush(struct brcmf_pub *drvr, int ifidx, u8 offset,
                         struct sk_buff *pktbuf)
 {
        struct brcmf_proto_bdc_header *h;
@@ -266,7 +280,6 @@ void brcmf_proto_hdrpush(struct brcmf_pub *drvr, int ifidx,
        brcmf_dbg(CDC, "Enter\n");
 
        /* Push BDC header used to convey priority for buses that don't */
-
        skb_push(pktbuf, BDC_HEADER_LEN);
 
        h = (struct brcmf_proto_bdc_header *)(pktbuf->data);
@@ -277,11 +290,11 @@ void brcmf_proto_hdrpush(struct brcmf_pub *drvr, int ifidx,
 
        h->priority = (pktbuf->priority & BDC_PRIORITY_MASK);
        h->flags2 = 0;
-       h->data_offset = 0;
+       h->data_offset = offset;
        BDC_SET_IF_IDX(h, ifidx);
 }
 
-int brcmf_proto_hdrpull(struct brcmf_pub *drvr, u8 *ifidx,
+int brcmf_proto_hdrpull(struct brcmf_pub *drvr, bool do_fws, u8 *ifidx,
                        struct sk_buff *pktbuf)
 {
        struct brcmf_proto_bdc_header *h;
@@ -328,7 +341,10 @@ int brcmf_proto_hdrpull(struct brcmf_pub *drvr, u8 *ifidx,
        pktbuf->priority = h->priority & BDC_PRIORITY_MASK;
 
        skb_pull(pktbuf, BDC_HEADER_LEN);
-       skb_pull(pktbuf, h->data_offset << 2);
+       if (do_fws)
+               brcmf_fws_hdrpull(drvr, *ifidx, h->data_offset << 2, pktbuf);
+       else
+               skb_pull(pktbuf, h->data_offset << 2);
 
        if (pktbuf->len == 0)
                return -ENODATA;
@@ -350,7 +366,7 @@ int brcmf_proto_attach(struct brcmf_pub *drvr)
        }
 
        drvr->prot = cdc;
-       drvr->hdrlen += BDC_HEADER_LEN;
+       drvr->hdrlen += BDC_HEADER_LEN + BRCMF_PROT_FW_SIGNAL_MAX_TXBYTES;
        drvr->bus_if->maxctl = BRCMF_DCMD_MAXLEN +
                        sizeof(struct brcmf_proto_cdc_dcmd) + ROUND_UP_MARGIN;
        return 0;
index 4544342..be0787c 100644 (file)
@@ -24,6 +24,7 @@
 #include "dhd_proto.h"
 #include "dhd_dbg.h"
 #include "fwil.h"
+#include "tracepoint.h"
 
 #define PKTFILTER_BUF_SIZE             128
 #define BRCMF_ARPOL_MODE               0xb     /* agent|snoop|peer_autoreply */
@@ -373,3 +374,35 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
 done:
        return err;
 }
+
+#ifdef CONFIG_BRCM_TRACING
+void __brcmf_err(const char *func, const char *fmt, ...)
+{
+       struct va_format vaf = {
+               .fmt = fmt,
+       };
+       va_list args;
+
+       va_start(args, fmt);
+       vaf.va = &args;
+       pr_err("%s: %pV", func, &vaf);
+       trace_brcmf_err(func, &vaf);
+       va_end(args);
+}
+#endif
+#if defined(CONFIG_BRCM_TRACING) || defined(CONFIG_BRCMDBG)
+void __brcmf_dbg(u32 level, const char *func, const char *fmt, ...)
+{
+       struct va_format vaf = {
+               .fmt = fmt,
+       };
+       va_list args;
+
+       va_start(args, fmt);
+       vaf.va = &args;
+       if (brcmf_msg_level & level)
+               pr_debug("%s %pV", func, &vaf);
+       trace_brcmf_dbg(level, func, &vaf);
+       va_end(args);
+}
+#endif
index 57671ed..ac79249 100644 (file)
@@ -22,6 +22,7 @@
 #include "dhd.h"
 #include "dhd_bus.h"
 #include "dhd_dbg.h"
+#include "tracepoint.h"
 
 static struct dentry *root_folder;
 
@@ -123,3 +124,44 @@ void brcmf_debugfs_create_sdio_count(struct brcmf_pub *drvr,
                debugfs_create_file("counters", S_IRUGO, dentry,
                                    sdcnt, &brcmf_debugfs_sdio_counter_ops);
 }
+
+static
+ssize_t brcmf_debugfs_fws_stats_read(struct file *f, char __user *data,
+                                    size_t count, loff_t *ppos)
+{
+       struct brcmf_fws_stats *fwstats = f->private_data;
+       char buf[100];
+       int res;
+
+       /* only allow read from start */
+       if (*ppos > 0)
+               return 0;
+
+       res = scnprintf(buf, sizeof(buf),
+                       "header_pulls:     %u\n"
+                       "header_only_pkt:  %u\n"
+                       "tlv_parse_failed: %u\n"
+                       "tlv_invalid_type: %u\n",
+                       fwstats->header_pulls,
+                       fwstats->header_only_pkt,
+                       fwstats->tlv_parse_failed,
+                       fwstats->tlv_invalid_type);
+
+       return simple_read_from_buffer(data, count, ppos, buf, res);
+}
+
+static const struct file_operations brcmf_debugfs_fws_stats_ops = {
+       .owner = THIS_MODULE,
+       .open = simple_open,
+       .read = brcmf_debugfs_fws_stats_read
+};
+
+void brcmf_debugfs_create_fws_stats(struct brcmf_pub *drvr,
+                                   struct brcmf_fws_stats *stats)
+{
+       struct dentry *dentry =  drvr->dbgfs_dir;
+
+       if (!IS_ERR_OR_NULL(dentry))
+               debugfs_create_file("fws_stats", S_IRUGO, dentry,
+                                   stats, &brcmf_debugfs_fws_stats_ops);
+}
index bc013cb..4bc646b 100644 (file)
@@ -43,6 +43,7 @@
  * debugging is not selected. When debugging the driver error
  * messages are as important as other tracing or even more so.
  */
+#ifndef CONFIG_BRCM_TRACING
 #ifdef CONFIG_BRCMDBG
 #define brcmf_err(fmt, ...)    pr_err("%s: " fmt, __func__, ##__VA_ARGS__)
 #else
                        pr_err("%s: " fmt, __func__, ##__VA_ARGS__);    \
        } while (0)
 #endif
+#else
+__printf(2, 3)
+void __brcmf_err(const char *func, const char *fmt, ...);
+#define brcmf_err(fmt, ...) \
+       __brcmf_err(__func__, fmt, ##__VA_ARGS__)
+#endif
 
-#if defined(DEBUG)
-
+#if defined(DEBUG) || defined(CONFIG_BRCM_TRACING)
+__printf(3, 4)
+void __brcmf_dbg(u32 level, const char *func, const char *fmt, ...);
 #define brcmf_dbg(level, fmt, ...)                             \
 do {                                                           \
-       if (brcmf_msg_level & BRCMF_##level##_VAL)              \
-               pr_debug("%s: " fmt, __func__, ##__VA_ARGS__);  \
+       __brcmf_dbg(BRCMF_##level##_VAL, __func__,              \
+                   fmt, ##__VA_ARGS__);                        \
 } while (0)
-
 #define BRCMF_DATA_ON()                (brcmf_msg_level & BRCMF_DATA_VAL)
 #define BRCMF_CTL_ON()         (brcmf_msg_level & BRCMF_CTL_VAL)
 #define BRCMF_HDRS_ON()                (brcmf_msg_level & BRCMF_HDRS_VAL)
@@ -69,7 +76,7 @@ do {                                                          \
 #define BRCMF_EVENT_ON()       (brcmf_msg_level & BRCMF_EVENT_VAL)
 #define BRCMF_FIL_ON()         (brcmf_msg_level & BRCMF_FIL_VAL)
 
-#else  /* (defined DEBUG) || (defined DEBUG) */
+#else /* defined(DEBUG) || defined(CONFIG_BRCM_TRACING) */
 
 #define brcmf_dbg(level, fmt, ...) no_printk(fmt, ##__VA_ARGS__)
 
@@ -81,7 +88,7 @@ do {                                                          \
 #define BRCMF_EVENT_ON()       0
 #define BRCMF_FIL_ON()         0
 
-#endif                         /* defined(DEBUG) */
+#endif /* defined(DEBUG) || defined(CONFIG_BRCM_TRACING) */
 
 #define brcmf_dbg_hex_dump(test, data, len, fmt, ...)                  \
 do {                                                                   \
@@ -125,6 +132,13 @@ struct brcmf_sdio_count {
        ulong rx_readahead_cnt; /* packets where header read-ahead was used */
 };
 
+struct brcmf_fws_stats {
+       u32 tlv_parse_failed;
+       u32 tlv_invalid_type;
+       u32 header_only_pkt;
+       u32 header_pulls;
+};
+
 struct brcmf_pub;
 #ifdef DEBUG
 void brcmf_debugfs_init(void);
@@ -134,6 +148,8 @@ void brcmf_debugfs_detach(struct brcmf_pub *drvr);
 struct dentry *brcmf_debugfs_get_devdir(struct brcmf_pub *drvr);
 void brcmf_debugfs_create_sdio_count(struct brcmf_pub *drvr,
                                     struct brcmf_sdio_count *sdcnt);
+void brcmf_debugfs_create_fws_stats(struct brcmf_pub *drvr,
+                                   struct brcmf_fws_stats *stats);
 #else
 static inline void brcmf_debugfs_init(void)
 {
@@ -148,6 +164,10 @@ static inline int brcmf_debugfs_attach(struct brcmf_pub *drvr)
 static inline void brcmf_debugfs_detach(struct brcmf_pub *drvr)
 {
 }
+static inline void brcmf_debugfs_create_fws_stats(struct brcmf_pub *drvr,
+                                                 struct brcmf_fws_stats *stats)
+{
+}
 #endif
 
 #endif                         /* _BRCMF_DBG_H_ */
index c06cea8..fa5a2af 100644 (file)
 #include "p2p.h"
 #include "wl_cfg80211.h"
 #include "fwil.h"
+#include "fwsignal.h"
 
 MODULE_AUTHOR("Broadcom Corporation");
 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 */
 
 /* Error bits */
 int brcmf_msg_level;
-module_param(brcmf_msg_level, int, 0);
+module_param_named(debug, brcmf_msg_level, int, S_IRUSR | S_IWUSR);
+MODULE_PARM_DESC(debug, "level of debug output");
 
 /* P2P0 enable */
 static int brcmf_p2p_enable;
@@ -230,7 +231,7 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb,
                atomic_inc(&ifp->pend_8021x_cnt);
 
        /* If the protocol uses a data header, apply it */
-       brcmf_proto_hdrpush(drvr, ifp->ifidx, skb);
+       brcmf_proto_hdrpush(drvr, ifp->ifidx, 0, skb);
 
        /* Use bus module to send data frame */
        ret =  brcmf_bus_txdata(drvr->bus_if, skb);
@@ -283,7 +284,7 @@ void brcmf_rx_frames(struct device *dev, struct sk_buff_head *skb_list)
                skb_unlink(skb, skb_list);
 
                /* process and remove protocol-specific header */
-               ret = brcmf_proto_hdrpull(drvr, &ifidx, skb);
+               ret = brcmf_proto_hdrpull(drvr, drvr->fw_signals, &ifidx, skb);
                ifp = drvr->iflist[ifidx];
 
                if (ret || !ifp || !ifp->ndev) {
@@ -357,23 +358,29 @@ void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success)
        struct brcmf_bus *bus_if = dev_get_drvdata(dev);
        struct brcmf_pub *drvr = bus_if->drvr;
        struct brcmf_if *ifp;
+       int res;
 
-       brcmf_proto_hdrpull(drvr, &ifidx, txp);
+       res = brcmf_proto_hdrpull(drvr, false, &ifidx, txp);
 
        ifp = drvr->iflist[ifidx];
        if (!ifp)
-               return;
+               goto done;
 
-       eh = (struct ethhdr *)(txp->data);
-       type = ntohs(eh->h_proto);
+       if (res == 0) {
+               eh = (struct ethhdr *)(txp->data);
+               type = ntohs(eh->h_proto);
 
-       if (type == ETH_P_PAE) {
-               atomic_dec(&ifp->pend_8021x_cnt);
-               if (waitqueue_active(&ifp->pend_8021x_wait))
-                       wake_up(&ifp->pend_8021x_wait);
+               if (type == ETH_P_PAE) {
+                       atomic_dec(&ifp->pend_8021x_cnt);
+                       if (waitqueue_active(&ifp->pend_8021x_wait))
+                               wake_up(&ifp->pend_8021x_wait);
+               }
        }
        if (!success)
                ifp->stats.tx_errors++;
+
+done:
+       brcmu_pkt_buf_free_skb(txp);
 }
 
 static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *ndev)
@@ -873,6 +880,9 @@ int brcmf_bus_start(struct device *dev)
        if (ret < 0)
                goto fail;
 
+       drvr->fw_signals = true;
+       (void)brcmf_fws_init(drvr);
+
        drvr->config = brcmf_cfg80211_attach(drvr, bus_if->dev);
        if (drvr->config == NULL) {
                ret = -ENOMEM;
@@ -889,6 +899,8 @@ fail:
                brcmf_err("failed: %d\n", ret);
                if (drvr->config)
                        brcmf_cfg80211_detach(drvr->config);
+               if (drvr->fws)
+                       brcmf_fws_deinit(drvr);
                free_netdev(ifp->ndev);
                drvr->iflist[0] = NULL;
                if (p2p_ifp) {
@@ -952,6 +964,9 @@ void brcmf_detach(struct device *dev)
        if (drvr->prot)
                brcmf_proto_detach(drvr);
 
+       if (drvr->fws)
+               brcmf_fws_deinit(drvr);
+
        brcmf_debugfs_detach(drvr);
        bus_if->drvr = NULL;
        kfree(drvr);
index 48fa703..ef91798 100644 (file)
@@ -33,7 +33,7 @@ extern void brcmf_proto_stop(struct brcmf_pub *drvr);
 /* Add any protocol-specific data header.
  * Caller must reserve prot_hdrlen prepend space.
  */
-extern void brcmf_proto_hdrpush(struct brcmf_pub *, int ifidx,
+extern void brcmf_proto_hdrpush(struct brcmf_pub *, int ifidx, u8 offset,
                                struct sk_buff *txp);
 
 /* Sets dongle media info (drv_version, mac address). */
index 4469321..9a2edd3 100644 (file)
@@ -1546,7 +1546,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
        struct sk_buff_head pktlist;    /* needed for bus interface */
        u16 pad;                /* Number of pad bytes to read */
        uint rxleft = 0;        /* Remaining number of frames allowed */
-       int sdret;              /* Return code from calls */
+       int ret;                /* Return code from calls */
        uint rxcount = 0;       /* Total frames read */
        struct brcmf_sdio_read *rd = &bus->cur_read, rd_new;
        u8 head_read = 0;
@@ -1577,15 +1577,15 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
                /* read header first for unknow frame length */
                sdio_claim_host(bus->sdiodev->func[1]);
                if (!rd->len) {
-                       sdret = brcmf_sdcard_recv_buf(bus->sdiodev,
+                       ret = brcmf_sdcard_recv_buf(bus->sdiodev,
                                                      bus->sdiodev->sbwad,
                                                      SDIO_FUNC_2, F2SYNC,
                                                      bus->rxhdr,
                                                      BRCMF_FIRSTREAD);
                        bus->sdcnt.f2rxhdrs++;
-                       if (sdret < 0) {
+                       if (ret < 0) {
                                brcmf_err("RXHEADER FAILED: %d\n",
-                                         sdret);
+                                         ret);
                                bus->sdcnt.rx_hdrfail++;
                                brcmf_sdbrcm_rxfail(bus, true, true);
                                sdio_release_host(bus->sdiodev->func[1]);
@@ -1637,14 +1637,14 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
                skb_pull(pkt, head_read);
                pkt_align(pkt, rd->len_left, BRCMF_SDALIGN);
 
-               sdret = brcmf_sdcard_recv_pkt(bus->sdiodev, bus->sdiodev->sbwad,
+               ret = brcmf_sdcard_recv_pkt(bus->sdiodev, bus->sdiodev->sbwad,
                                              SDIO_FUNC_2, F2SYNC, pkt);
                bus->sdcnt.f2rxdata++;
                sdio_release_host(bus->sdiodev->func[1]);
 
-               if (sdret < 0) {
+               if (ret < 0) {
                        brcmf_err("read %d bytes from channel %d failed: %d\n",
-                                 rd->len, rd->channel, sdret);
+                                 rd->len, rd->channel, ret);
                        brcmu_pkt_buf_free_skb(pkt);
                        sdio_claim_host(bus->sdiodev->func[1]);
                        brcmf_sdbrcm_rxfail(bus, true,
@@ -1775,7 +1775,7 @@ brcmf_sdbrcm_wait_event_wakeup(struct brcmf_sdio *bus)
 /* Writes a HW/SW header into the packet and sends it. */
 /* Assumes: (a) header space already there, (b) caller holds lock */
 static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff *pkt,
-                             uint chan, bool free_pkt)
+                             uint chan)
 {
        int ret;
        u8 *frame;
@@ -1805,10 +1805,7 @@ static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff *pkt,
 
                        pkt_align(new, pkt->len, BRCMF_SDALIGN);
                        memcpy(new->data, pkt->data, pkt->len);
-                       if (free_pkt)
-                               brcmu_pkt_buf_free_skb(pkt);
-                       /* free the pkt if canned one is not used */
-                       free_pkt = true;
+                       brcmu_pkt_buf_free_skb(pkt);
                        pkt = new;
                        frame = (u8 *) (pkt->data);
                        /* precondition: (frame % BRCMF_SDALIGN) == 0) */
@@ -1901,10 +1898,6 @@ done:
        /* restore pkt buffer pointer before calling tx complete routine */
        skb_pull(pkt, SDPCM_HDRLEN + pad);
        brcmf_txcomplete(bus->sdiodev->dev, pkt, ret != 0);
-
-       if (free_pkt)
-               brcmu_pkt_buf_free_skb(pkt);
-
        return ret;
 }
 
@@ -1932,7 +1925,7 @@ static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes)
                spin_unlock_bh(&bus->txqlock);
                datalen = pkt->len - SDPCM_HDRLEN;
 
-               ret = brcmf_sdbrcm_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, true);
+               ret = brcmf_sdbrcm_txpkt(bus, pkt, SDPCM_DATA_CHANNEL);
 
                /* In poll mode, need to check for other events */
                if (!bus->intr && cnt) {
@@ -2343,7 +2336,6 @@ static int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt)
        if (!brcmf_c_prec_enq(bus->sdiodev->dev, &bus->txq, pkt, prec)) {
                skb_pull(pkt, SDPCM_HDRLEN);
                brcmf_txcomplete(bus->sdiodev->dev, pkt, false);
-               brcmu_pkt_buf_free_skb(pkt);
                brcmf_err("out of bus->txq !!!\n");
                ret = -ENOSR;
        } else {
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
new file mode 100644 (file)
index 0000000..071d55f
--- /dev/null
@@ -0,0 +1,382 @@
+/*
+ * Copyright (c) 2010 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/types.h>
+#include <linux/if_ether.h>
+#include <linux/spinlock.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/err.h>
+#include <uapi/linux/nl80211.h>
+
+#include <brcmu_utils.h>
+#include <brcmu_wifi.h>
+#include "dhd.h"
+#include "dhd_dbg.h"
+#include "fwil.h"
+#include "fweh.h"
+#include "fwsignal.h"
+
+/**
+ * DOC: Firmware Signalling
+ *
+ * Firmware can send signals to host and vice versa, which are passed in the
+ * data packets using TLV based header. This signalling layer is on top of the
+ * BDC bus protocol layer.
+ */
+
+/*
+ * single definition for firmware-driver flow control tlv's.
+ *
+ * each tlv is specified by BRCMF_FWS_TLV_DEF(name, ID, length).
+ * A length value 0 indicates variable length tlv.
+ */
+#define BRCMF_FWS_TLV_DEFLIST \
+       BRCMF_FWS_TLV_DEF(MAC_OPEN, 1, 1) \
+       BRCMF_FWS_TLV_DEF(MAC_CLOSE, 2, 1) \
+       BRCMF_FWS_TLV_DEF(MAC_REQUEST_CREDIT, 3, 2) \
+       BRCMF_FWS_TLV_DEF(TXSTATUS, 4, 4) \
+       BRCMF_FWS_TLV_DEF(PKTTAG, 5, 4) \
+       BRCMF_FWS_TLV_DEF(MACDESC_ADD,  6, 8) \
+       BRCMF_FWS_TLV_DEF(MACDESC_DEL, 7, 8) \
+       BRCMF_FWS_TLV_DEF(RSSI, 8, 1) \
+       BRCMF_FWS_TLV_DEF(INTERFACE_OPEN, 9, 1) \
+       BRCMF_FWS_TLV_DEF(INTERFACE_CLOSE, 10, 1) \
+       BRCMF_FWS_TLV_DEF(FIFO_CREDITBACK, 11, 8) \
+       BRCMF_FWS_TLV_DEF(PENDING_TRAFFIC_BMP, 12, 2) \
+       BRCMF_FWS_TLV_DEF(MAC_REQUEST_PACKET, 13, 3) \
+       BRCMF_FWS_TLV_DEF(HOST_REORDER_RXPKTS, 14, 10) \
+       BRCMF_FWS_TLV_DEF(TRANS_ID, 18, 6) \
+       BRCMF_FWS_TLV_DEF(COMP_TXSTATUS, 19, 1) \
+       BRCMF_FWS_TLV_DEF(FILLER, 255, 0)
+
+/**
+ * enum brcmf_fws_tlv_type - definition of tlv identifiers.
+ */
+#define BRCMF_FWS_TLV_DEF(name, id, len) \
+       BRCMF_FWS_TYPE_ ## name =  id,
+enum brcmf_fws_tlv_type {
+       BRCMF_FWS_TLV_DEFLIST
+       BRCMF_FWS_TYPE_INVALID
+};
+#undef BRCMF_FWS_TLV_DEF
+
+/**
+ * enum brcmf_fws_tlv_len - length values for tlvs.
+ */
+#define BRCMF_FWS_TLV_DEF(name, id, len) \
+       BRCMF_FWS_TYPE_ ## name ## _LEN = len,
+enum brcmf_fws_tlv_len {
+       BRCMF_FWS_TLV_DEFLIST
+};
+#undef BRCMF_FWS_TLV_DEF
+
+#ifdef DEBUG
+/**
+ * brcmf_fws_tlv_names - array of tlv names.
+ */
+#define BRCMF_FWS_TLV_DEF(name, id, len) \
+       { id, #name },
+static struct {
+       enum brcmf_fws_tlv_type id;
+       const char *name;
+} brcmf_fws_tlv_names[] = {
+       BRCMF_FWS_TLV_DEFLIST
+};
+#undef BRCMF_FWS_TLV_DEF
+
+static const char *brcmf_fws_get_tlv_name(enum brcmf_fws_tlv_type id)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(brcmf_fws_tlv_names); i++)
+               if (brcmf_fws_tlv_names[i].id == id)
+                       return brcmf_fws_tlv_names[i].name;
+
+       return "INVALID";
+}
+#else
+static const char *brcmf_fws_get_tlv_name(enum brcmf_fws_tlv_type id)
+{
+       return "NODEBUG";
+}
+#endif /* DEBUG */
+
+/**
+ * flags used to enable tlv signalling from firmware.
+ */
+#define BRCMF_FWS_FLAGS_RSSI_SIGNALS                           0x0001
+#define BRCMF_FWS_FLAGS_XONXOFF_SIGNALS                                0x0002
+#define BRCMF_FWS_FLAGS_CREDIT_STATUS_SIGNALS                  0x0004
+#define BRCMF_FWS_FLAGS_HOST_PROPTXSTATUS_ACTIVE               0x0008
+#define BRCMF_FWS_FLAGS_PSQ_GENERATIONFSM_ENABLE               0x0010
+#define BRCMF_FWS_FLAGS_PSQ_ZERO_BUFFER_ENABLE                 0x0020
+#define BRCMF_FWS_FLAGS_HOST_RXREORDER_ACTIVE                  0x0040
+
+#define BRCMF_FWS_HANGER_MAXITEMS                              1024
+#define BRCMF_FWS_HANGER_ITEM_STATE_FREE                       1
+#define BRCMF_FWS_HANGER_ITEM_STATE_INUSE                      2
+#define BRCMF_FWS_HANGER_ITEM_STATE_INUSE_SUPPRESSED           3
+
+#define BRCMF_FWS_STATE_OPEN                                   1
+#define BRCMF_FWS_STATE_CLOSE                          2
+
+#define BRCMF_FWS_FCMODE_NONE                          0
+#define BRCMF_FWS_FCMODE_IMPLIED_CREDIT                        1
+#define BRCMF_FWS_FCMODE_EXPLICIT_CREDIT                       2
+
+#define BRCMF_FWS_MAC_DESC_TABLE_SIZE                  32
+#define BRCMF_FWS_MAX_IFNUM                                    16
+#define BRCMF_FWS_MAC_DESC_ID_INVALID                  0xff
+
+#define BRCMF_FWS_HOSTIF_FLOWSTATE_OFF                 0
+#define BRCMF_FWS_HOSTIF_FLOWSTATE_ON                  1
+
+/**
+ * FWFC packet identifier
+ *
+ * 32-bit packet identifier used in PKTTAG tlv from host to dongle.
+ *
+ * - Generated at the host (e.g. dhd)
+ * - Seen as a generic sequence number by wlc except the flags field
+ *
+ * Generation  : b[31] => generation number for this packet [host->fw]
+ *                        OR, current generation number [fw->host]
+ * Flags       : b[30:27] => command, status flags
+ * FIFO-AC     : b[26:24] => AC-FIFO id
+ * h-slot      : b[23:8] => hanger-slot
+ * freerun     : b[7:0] => A free running counter
+ */
+#define BRCMF_FWS_PKTTAG_GENERATION_MASK               0x80000000
+#define BRCMF_FWS_PKTTAG_GENERATION_SHIFT              31
+#define BRCMF_FWS_PKTTAG_FLAGS_MASK                    0x78000000
+#define BRCMF_FWS_PKTTAG_FLAGS_SHIFT                   27
+#define BRCMF_FWS_PKTTAG_FIFO_MASK                     0x07000000
+#define BRCMF_FWS_PKTTAG_FIFO_SHIFT                    24
+#define BRCMF_FWS_PKTTAG_HSLOT_MASK                    0x00ffff00
+#define BRCMF_FWS_PKTTAG_HSLOT_SHIFT                   8
+#define BRCMF_FWS_PKTTAG_FREERUN_MASK                  0x000000ff
+#define BRCMF_FWS_PKTTAG_FREERUN_SHIFT                 0
+
+#define brcmf_fws_pkttag_set_field(var, field, value) \
+       brcmu_maskset32((var), BRCMF_FWS_PKTTAG_ ## field ## _MASK, \
+                            BRCMF_FWS_PKTTAG_ ## field ## _SHIFT, (value))
+#define brcmf_fws_pkttag_get_field(var, field) \
+       brcmu_maskget32((var), BRCMF_FWS_PKTTAG_ ## field ## _MASK, \
+                            BRCMF_FWS_PKTTAG_ ## field ## _SHIFT)
+
+struct brcmf_fws_info {
+       struct brcmf_pub *drvr;
+       struct brcmf_fws_stats stats;
+};
+
+static int brcmf_fws_rssi_indicate(struct brcmf_fws_info *fws, s8 rssi)
+{
+       brcmf_dbg(CTL, "rssi %d\n", rssi);
+       return 0;
+}
+
+static int brcmf_fws_dbg_seqnum_check(struct brcmf_fws_info *fws, u8 *data)
+{
+       __le32 timestamp;
+
+       memcpy(&timestamp, &data[2], sizeof(timestamp));
+       brcmf_dbg(INFO, "received: seq %d, timestamp %d\n", data[1],
+                 le32_to_cpu(timestamp));
+       return 0;
+}
+
+/* using macro so sparse checking does not complain
+ * about locking imbalance.
+ */
+#define brcmf_fws_lock(drvr, flags)                            \
+do {                                                           \
+       flags = 0;                                              \
+       spin_lock_irqsave(&((drvr)->fws_spinlock), (flags));    \
+} while (0)
+
+/* using macro so sparse checking does not complain
+ * about locking imbalance.
+ */
+#define brcmf_fws_unlock(drvr, flags) \
+       spin_unlock_irqrestore(&((drvr)->fws_spinlock), (flags))
+
+int brcmf_fws_init(struct brcmf_pub *drvr)
+{
+       u32 tlv;
+       int rc;
+
+       /* enable rssi signals */
+       tlv = drvr->fw_signals ? BRCMF_FWS_FLAGS_RSSI_SIGNALS : 0;
+
+       spin_lock_init(&drvr->fws_spinlock);
+
+       drvr->fws = kzalloc(sizeof(*(drvr->fws)), GFP_KERNEL);
+       if (!drvr->fws) {
+               rc = -ENOMEM;
+               goto fail;
+       }
+
+       /* enable proptxtstatus signaling by default */
+       rc = brcmf_fil_iovar_int_set(drvr->iflist[0], "tlv", tlv);
+       if (rc < 0) {
+               brcmf_err("failed to set bdcv2 tlv signaling\n");
+               goto fail;
+       }
+       /* set linkage back */
+       drvr->fws->drvr = drvr;
+
+       /* create debugfs file for statistics */
+       brcmf_debugfs_create_fws_stats(drvr, &drvr->fws->stats);
+
+       /* TODO: remove upon feature delivery */
+       brcmf_err("%s bdcv2 tlv signaling [%x]\n",
+                 drvr->fw_signals ? "enabled" : "disabled", tlv);
+       return 0;
+
+fail:
+       /* disable flow control entirely */
+       drvr->fw_signals = false;
+       brcmf_fws_deinit(drvr);
+       return rc;
+}
+
+void brcmf_fws_deinit(struct brcmf_pub *drvr)
+{
+       /* free top structure */
+       kfree(drvr->fws);
+       drvr->fws = NULL;
+}
+
+int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len,
+                     struct sk_buff *skb)
+{
+       struct brcmf_fws_info *fws = drvr->fws;
+       ulong flags;
+       u8 *signal_data;
+       s16 data_len;
+       u8 type;
+       u8 len;
+       u8 *data;
+
+       brcmf_dbg(TRACE, "enter: ifidx %d, skblen %u, sig %d\n",
+                 ifidx, skb->len, signal_len);
+
+       WARN_ON(signal_len > skb->len);
+
+       /* if flow control disabled, skip to packet data and leave */
+       if (!signal_len || !drvr->fw_signals) {
+               skb_pull(skb, signal_len);
+               return 0;
+       }
+
+       /* lock during tlv parsing */
+       brcmf_fws_lock(drvr, flags);
+
+       fws->stats.header_pulls++;
+       data_len = signal_len;
+       signal_data = skb->data;
+
+       while (data_len > 0) {
+               /* extract tlv info */
+               type = signal_data[0];
+
+               /* FILLER type is actually not a TLV, but
+                * a single byte that can be skipped.
+                */
+               if (type == BRCMF_FWS_TYPE_FILLER) {
+                       signal_data += 1;
+                       data_len -= 1;
+                       continue;
+               }
+               len = signal_data[1];
+               data = signal_data + 2;
+
+               /* abort parsing when length invalid */
+               if (data_len < len + 2)
+                       break;
+
+               brcmf_dbg(INFO, "tlv type=%d (%s), len=%d\n", type,
+                         brcmf_fws_get_tlv_name(type), len);
+               switch (type) {
+               case BRCMF_FWS_TYPE_MAC_OPEN:
+               case BRCMF_FWS_TYPE_MAC_CLOSE:
+                       WARN_ON(len != BRCMF_FWS_TYPE_MAC_OPEN_LEN);
+                       break;
+               case BRCMF_FWS_TYPE_MAC_REQUEST_CREDIT:
+                       WARN_ON(len != BRCMF_FWS_TYPE_MAC_REQUEST_CREDIT_LEN);
+                       break;
+               case BRCMF_FWS_TYPE_TXSTATUS:
+                       WARN_ON(len != BRCMF_FWS_TYPE_TXSTATUS_LEN);
+                       break;
+               case BRCMF_FWS_TYPE_PKTTAG:
+                       WARN_ON(len != BRCMF_FWS_TYPE_PKTTAG_LEN);
+                       break;
+               case BRCMF_FWS_TYPE_MACDESC_ADD:
+               case BRCMF_FWS_TYPE_MACDESC_DEL:
+                       WARN_ON(len != BRCMF_FWS_TYPE_MACDESC_ADD_LEN);
+                       break;
+               case BRCMF_FWS_TYPE_RSSI:
+                       WARN_ON(len != BRCMF_FWS_TYPE_RSSI_LEN);
+                       brcmf_fws_rssi_indicate(fws, *(s8 *)data);
+                       break;
+               case BRCMF_FWS_TYPE_INTERFACE_OPEN:
+               case BRCMF_FWS_TYPE_INTERFACE_CLOSE:
+                       WARN_ON(len != BRCMF_FWS_TYPE_INTERFACE_OPEN_LEN);
+                       break;
+               case BRCMF_FWS_TYPE_FIFO_CREDITBACK:
+                       WARN_ON(len != BRCMF_FWS_TYPE_FIFO_CREDITBACK_LEN);
+                       break;
+               case BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP:
+                       WARN_ON(len != BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP_LEN);
+                       break;
+               case BRCMF_FWS_TYPE_MAC_REQUEST_PACKET:
+                       WARN_ON(len != BRCMF_FWS_TYPE_MAC_REQUEST_PACKET_LEN);
+                       break;
+               case BRCMF_FWS_TYPE_HOST_REORDER_RXPKTS:
+                       WARN_ON(len != BRCMF_FWS_TYPE_HOST_REORDER_RXPKTS_LEN);
+                       break;
+               case BRCMF_FWS_TYPE_TRANS_ID:
+                       WARN_ON(len != BRCMF_FWS_TYPE_TRANS_ID_LEN);
+                       brcmf_fws_dbg_seqnum_check(fws, data);
+                       break;
+               case BRCMF_FWS_TYPE_COMP_TXSTATUS:
+                       WARN_ON(len != BRCMF_FWS_TYPE_COMP_TXSTATUS_LEN);
+                       break;
+               default:
+                       fws->stats.tlv_invalid_type++;
+                       break;
+               }
+
+               signal_data += len + 2;
+               data_len -= len + 2;
+       }
+
+       if (data_len != 0)
+               fws->stats.tlv_parse_failed++;
+
+       /* signalling processing result does
+        * not affect the actual ethernet packet.
+        */
+       skb_pull(skb, signal_len);
+
+       /* this may be a signal-only packet
+        */
+       if (skb->len == 0)
+               fws->stats.header_only_pkt++;
+
+       brcmf_fws_unlock(drvr, flags);
+       return 0;
+}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.h b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.h
new file mode 100644 (file)
index 0000000..e728eea
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * 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 FWSIGNAL_H_
+#define FWSIGNAL_H_
+
+int brcmf_fws_init(struct brcmf_pub *drvr);
+void brcmf_fws_deinit(struct brcmf_pub *drvr);
+int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len,
+                     struct sk_buff *skb);
+#endif /* FWSIGNAL_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/tracepoint.c b/drivers/net/wireless/brcm80211/brcmfmac/tracepoint.c
new file mode 100644 (file)
index 0000000..b505db4
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * 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/module.h> /* bug in tracepoint.h, it should include this */
+
+#ifndef __CHECKER__
+#define CREATE_TRACE_POINTS
+#include "tracepoint.h"
+#endif
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/tracepoint.h b/drivers/net/wireless/brcm80211/brcmfmac/tracepoint.h
new file mode 100644 (file)
index 0000000..35efc7a
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2013 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.
+ */
+#if !defined(BRCMF_TRACEPOINT_H_) || defined(TRACE_HEADER_MULTI_READ)
+#define BRCMF_TRACEPOINT_H_
+
+#include <linux/types.h>
+#include <linux/tracepoint.h>
+
+#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 /* CONFIG_BRCM_TRACING */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM   brcmfmac
+
+#define MAX_MSG_LEN            100
+
+TRACE_EVENT(brcmf_err,
+       TP_PROTO(const char *func, struct va_format *vaf),
+       TP_ARGS(func, vaf),
+       TP_STRUCT__entry(
+               __string(func, func)
+               __dynamic_array(char, msg, MAX_MSG_LEN)
+       ),
+       TP_fast_assign(
+               __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))
+);
+
+TRACE_EVENT(brcmf_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))
+);
+
+#ifdef CONFIG_BRCM_TRACING
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE tracepoint
+
+#include <trace/define_trace.h>
+
+#endif /* CONFIG_BRCM_TRACING */
+
+#endif /* BRCMF_TRACEPOINT_H_ */
index 42289e9..01aed7a 100644 (file)
@@ -112,11 +112,6 @@ struct brcmf_usbdev_info {
 static void brcmf_usb_rx_refill(struct brcmf_usbdev_info *devinfo,
                                struct brcmf_usbreq  *req);
 
-MODULE_AUTHOR("Broadcom Corporation");
-MODULE_DESCRIPTION("Broadcom 802.11n wireless LAN fullmac usb driver.");
-MODULE_SUPPORTED_DEVICE("Broadcom 802.11n WLAN fullmac usb cards");
-MODULE_LICENSE("Dual BSD/GPL");
-
 static struct brcmf_usbdev *brcmf_usb_get_buspub(struct device *dev)
 {
        struct brcmf_bus *bus_if = dev_get_drvdata(dev);
@@ -422,8 +417,6 @@ static void brcmf_usb_tx_complete(struct urb *urb)
        brcmf_usb_del_fromq(devinfo, req);
 
        brcmf_txcomplete(devinfo->dev, req->skb, urb->status == 0);
-
-       brcmu_pkt_buf_free_skb(req->skb);
        req->skb = NULL;
        brcmf_usb_enq(devinfo, &devinfo->tx_freeq, req, &devinfo->tx_freecount);
        if (devinfo->tx_freecount > devinfo->tx_high_watermark &&
@@ -577,15 +570,17 @@ 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 != BRCMFMAC_USB_STATE_UP)
-               return -EIO;
+       if (devinfo->bus_pub.state != BRCMFMAC_USB_STATE_UP) {
+               ret = -EIO;
+               goto fail;
+       }
 
        req = brcmf_usb_deq(devinfo, &devinfo->tx_freeq,
                                        &devinfo->tx_freecount);
        if (!req) {
-               brcmu_pkt_buf_free_skb(skb);
                brcmf_err("no req to send\n");
-               return -ENOMEM;
+               ret = -ENOMEM;
+               goto fail;
        }
 
        req->skb = skb;
@@ -598,18 +593,21 @@ static int brcmf_usb_tx(struct device *dev, struct sk_buff *skb)
        if (ret) {
                brcmf_err("brcmf_usb_tx usb_submit_urb FAILED\n");
                brcmf_usb_del_fromq(devinfo, req);
-               brcmu_pkt_buf_free_skb(req->skb);
                req->skb = NULL;
                brcmf_usb_enq(devinfo, &devinfo->tx_freeq, req,
-                                               &devinfo->tx_freecount);
-       } else {
-               if (devinfo->tx_freecount < devinfo->tx_low_watermark &&
-                       !devinfo->tx_flowblock) {
-                       brcmf_txflowblock(dev, true);
-                       devinfo->tx_flowblock = true;
-               }
+                             &devinfo->tx_freecount);
+               goto fail;
        }
 
+       if (devinfo->tx_freecount < devinfo->tx_low_watermark &&
+           !devinfo->tx_flowblock) {
+               brcmf_txflowblock(dev, true);
+               devinfo->tx_flowblock = true;
+       }
+       return 0;
+
+fail:
+       brcmf_txcomplete(dev, skb, false);
        return ret;
 }
 
@@ -1485,6 +1483,7 @@ static struct usb_device_id brcmf_usb_devid_table[] = {
        { USB_DEVICE(BRCMF_USB_VENDOR_ID_BROADCOM, BRCMF_USB_DEVICE_ID_BCMFW) },
        { }
 };
+
 MODULE_DEVICE_TABLE(usb, brcmf_usb_devid_table);
 MODULE_FIRMWARE(BRCMF_USB_43143_FW_NAME);
 MODULE_FIRMWARE(BRCMF_USB_43236_FW_NAME);
index 2af9c0f..804473f 100644 (file)
@@ -3052,16 +3052,16 @@ brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,
        int i;
        int ret = 0;
 
-       brcmf_dbg(SCAN, "Enter n_match_sets:%d   n_ssids:%d\n",
+       brcmf_dbg(SCAN, "Enter n_match_sets:%d n_ssids:%d\n",
                  request->n_match_sets, request->n_ssids);
        if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
                brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
                return -EAGAIN;
        }
 
-       if (!request || !request->n_ssids || !request->n_match_sets) {
+       if (!request->n_ssids || !request->n_match_sets) {
                brcmf_err("Invalid sched scan req!! n_ssids:%d\n",
-                         request ? request->n_ssids : 0);
+                         request->n_ssids);
                return -EINVAL;
        }
 
index d3d4151..cba19d8 100644 (file)
@@ -43,6 +43,10 @@ BRCMSMAC_OFILES := \
        brcms_trace_events.o \
        debug.o
 
+ifdef CONFIG_BCMA_DRIVER_GPIO
+BRCMSMAC_OFILES += led.o
+endif
+
 MODULEPFX := brcmsmac
 
 obj-$(CONFIG_BRCMSMAC) += $(MODULEPFX).o
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/led.c b/drivers/net/wireless/brcm80211/brcmsmac/led.c
new file mode 100644 (file)
index 0000000..74b17ce
--- /dev/null
@@ -0,0 +1,126 @@
+#include <net/mac80211.h>
+#include <linux/bcma/bcma_driver_chipcommon.h>
+#include <linux/gpio.h>
+
+#include "mac80211_if.h"
+#include "pub.h"
+#include "main.h"
+#include "led.h"
+
+       /* number of leds */
+#define  BRCMS_LED_NO          4
+       /* behavior mask */
+#define  BRCMS_LED_BEH_MASK    0x7f
+       /* activelow (polarity) bit */
+#define  BRCMS_LED_AL_MASK     0x80
+       /* radio enabled */
+#define  BRCMS_LED_RADIO       3
+
+static void brcms_radio_led_ctrl(struct brcms_info *wl, bool state)
+{
+       if (wl->radio_led.gpio == -1)
+               return;
+
+       if (wl->radio_led.active_low)
+               state = !state;
+
+       if (state)
+               gpio_set_value(wl->radio_led.gpio, 1);
+       else
+               gpio_set_value(wl->radio_led.gpio, 0);
+}
+
+
+/* Callback from the LED subsystem. */
+static void brcms_led_brightness_set(struct led_classdev *led_dev,
+                                  enum led_brightness brightness)
+{
+       struct brcms_info *wl = container_of(led_dev,
+               struct brcms_info, led_dev);
+       brcms_radio_led_ctrl(wl, brightness);
+}
+
+void brcms_led_unregister(struct brcms_info *wl)
+{
+       if (wl->led_dev.dev)
+               led_classdev_unregister(&wl->led_dev);
+       if (wl->radio_led.gpio != -1)
+               gpio_free(wl->radio_led.gpio);
+}
+
+int brcms_led_register(struct brcms_info *wl)
+{
+       int i, err;
+       struct brcms_led *radio_led = &wl->radio_led;
+       /* get CC core */
+       struct bcma_drv_cc *cc_drv  = &wl->wlc->hw->d11core->bus->drv_cc;
+       struct gpio_chip *bcma_gpio = &cc_drv->gpio;
+       struct ssb_sprom *sprom = &wl->wlc->hw->d11core->bus->sprom;
+       u8 *leds[] = { &sprom->gpio0,
+               &sprom->gpio1,
+               &sprom->gpio2,
+               &sprom->gpio3 };
+       unsigned gpio = -1;
+       bool active_low = false;
+
+       /* none by default */
+       radio_led->gpio = -1;
+       radio_led->active_low = false;
+
+       if (!bcma_gpio || !gpio_is_valid(bcma_gpio->base))
+               return -ENODEV;
+
+       /* find radio enabled LED */
+       for (i = 0; i < BRCMS_LED_NO; i++) {
+               u8 led = *leds[i];
+               if ((led & BRCMS_LED_BEH_MASK) == BRCMS_LED_RADIO) {
+                       gpio = bcma_gpio->base + i;
+                       if (led & BRCMS_LED_AL_MASK)
+                               active_low = true;
+                       break;
+               }
+       }
+
+       if (gpio == -1 || !gpio_is_valid(gpio))
+               return -ENODEV;
+
+       /* request and configure LED gpio */
+       err = gpio_request_one(gpio,
+                               active_low ? GPIOF_OUT_INIT_HIGH
+                                       : GPIOF_OUT_INIT_LOW,
+                               "radio on");
+       if (err) {
+               wiphy_err(wl->wiphy, "requesting led gpio %d failed (err: %d)\n",
+                         gpio, err);
+               return err;
+       }
+       err = gpio_direction_output(gpio, 1);
+       if (err) {
+               wiphy_err(wl->wiphy, "cannot set led gpio %d to output (err: %d)\n",
+                         gpio, err);
+               return err;
+       }
+
+       snprintf(wl->radio_led.name, sizeof(wl->radio_led.name),
+                "brcmsmac-%s:radio", wiphy_name(wl->wiphy));
+
+       wl->led_dev.name = wl->radio_led.name;
+       wl->led_dev.default_trigger =
+               ieee80211_get_radio_led_name(wl->pub->ieee_hw);
+       wl->led_dev.brightness_set = brcms_led_brightness_set;
+       err = led_classdev_register(wiphy_dev(wl->wiphy), &wl->led_dev);
+
+       if (err) {
+               wiphy_err(wl->wiphy, "cannot register led device: %s (err: %d)\n",
+                         wl->radio_led.name, err);
+               return err;
+       }
+
+       wiphy_info(wl->wiphy, "registered radio enabled led device: %s gpio: %d\n",
+                  wl->radio_led.name,
+                  gpio);
+       radio_led->gpio = gpio;
+       radio_led->active_low = active_low;
+
+       return 0;
+}
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/led.h b/drivers/net/wireless/brcm80211/brcmsmac/led.h
new file mode 100644 (file)
index 0000000..17a0b1f
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * 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 _BRCM_LED_H_
+#define _BRCM_LED_H_
+struct brcms_led {
+       char name[32];
+       unsigned gpio;
+       bool active_low;
+};
+
+#ifdef CONFIG_BCMA_DRIVER_GPIO
+void brcms_led_unregister(struct brcms_info *wl);
+int brcms_led_register(struct brcms_info *wl);
+#else
+static inline void brcms_led_unregister(struct brcms_info *wl) {};
+static inline int brcms_led_register(struct brcms_info *wl)
+{
+       return -ENOTSUPP;
+};
+#endif
+
+#endif /* _BRCM_LED_H_ */
index c6451c6..c70cf7b 100644 (file)
@@ -34,6 +34,7 @@
 #include "mac80211_if.h"
 #include "main.h"
 #include "debug.h"
+#include "led.h"
 
 #define N_TX_QUEUES    4 /* #tx queues on mac80211<->driver interface */
 #define BRCMS_FLUSH_TIMEOUT    500 /* msec */
@@ -904,6 +905,7 @@ static void brcms_remove(struct bcma_device *pdev)
        struct brcms_info *wl = hw->priv;
 
        if (wl->wlc) {
+               brcms_led_unregister(wl);
                wiphy_rfkill_set_hw_state(wl->pub->ieee_hw->wiphy, false);
                wiphy_rfkill_stop_polling(wl->pub->ieee_hw->wiphy);
                ieee80211_unregister_hw(hw);
@@ -1151,6 +1153,8 @@ static int brcms_bcma_probe(struct bcma_device *pdev)
                pr_err("%s: brcms_attach failed!\n", __func__);
                return -ENODEV;
        }
+       brcms_led_register(wl);
+
        return 0;
 }
 
index 947ccac..4090032 100644 (file)
 #include <linux/timer.h>
 #include <linux/interrupt.h>
 #include <linux/workqueue.h>
+#include <linux/leds.h>
 
 #include "ucode_loader.h"
+#include "led.h"
 /*
  * Starting index for 5G rates in the
  * legacy rate table.
@@ -81,6 +83,8 @@ struct brcms_info {
        struct wiphy *wiphy;
        struct brcms_ucode ucode;
        bool mute_tx;
+       struct brcms_led radio_led;
+       struct led_classdev led_dev;
 };
 
 /* misc callbacks */
index 8ef02dc..0c8e998 100644 (file)
@@ -7810,9 +7810,14 @@ void brcms_c_init(struct brcms_c_info *wlc, bool mute_tx)
 
        /* read the ucode version if we have not yet done so */
        if (wlc->ucode_rev == 0) {
-               wlc->ucode_rev =
-                   brcms_b_read_shm(wlc->hw, M_BOM_REV_MAJOR) << NBITS(u16);
-               wlc->ucode_rev |= brcms_b_read_shm(wlc->hw, M_BOM_REV_MINOR);
+               u16 rev;
+               u16 patch;
+
+               rev = brcms_b_read_shm(wlc->hw, M_BOM_REV_MAJOR);
+               patch = brcms_b_read_shm(wlc->hw, M_BOM_REV_MINOR);
+               wlc->ucode_rev = (rev << NBITS(u16)) | patch;
+               snprintf(wlc->wiphy->fw_version,
+                        sizeof(wlc->wiphy->fw_version), "%u.%u", rev, patch);
        }
 
        /* ..now really unleash hell (allow the MAC out of suspend) */
index 3e6405e..bf5e50f 100644 (file)
@@ -116,6 +116,31 @@ struct sk_buff *brcmu_pktq_pdeq(struct pktq *pq, int prec)
 }
 EXPORT_SYMBOL(brcmu_pktq_pdeq);
 
+/*
+ * precedence based dequeue with match function. Passing a NULL pointer
+ * for the match function parameter is considered to be a wildcard so
+ * any packet on the queue is returned. In that case it is no different
+ * from brcmu_pktq_pdeq() above.
+ */
+struct sk_buff *brcmu_pktq_pdeq_match(struct pktq *pq, int prec,
+                                     bool (*match_fn)(struct sk_buff *skb,
+                                                      void *arg), void *arg)
+{
+       struct sk_buff_head *q;
+       struct sk_buff *p, *next;
+
+       q = &pq->q[prec].skblist;
+       skb_queue_walk_safe(q, p, next) {
+               if (match_fn == NULL || match_fn(p, arg)) {
+                       skb_unlink(p, q);
+                       pq->len--;
+                       return p;
+               }
+       }
+       return NULL;
+}
+EXPORT_SYMBOL(brcmu_pktq_pdeq_match);
+
 struct sk_buff *brcmu_pktq_pdeq_tail(struct pktq *pq, int prec)
 {
        struct sk_buff_head *q;
index 477b92a..898cacb 100644 (file)
@@ -120,6 +120,10 @@ extern struct sk_buff *brcmu_pktq_penq_head(struct pktq *pq, int prec,
                                      struct sk_buff *p);
 extern struct sk_buff *brcmu_pktq_pdeq(struct pktq *pq, int prec);
 extern struct sk_buff *brcmu_pktq_pdeq_tail(struct pktq *pq, int prec);
+extern struct sk_buff *brcmu_pktq_pdeq_match(struct pktq *pq, int prec,
+                                            bool (*match_fn)(struct sk_buff *p,
+                                                             void *arg),
+                                            void *arg);
 
 /* packet primitives */
 extern struct sk_buff *brcmu_pkt_buf_get_skb(uint len);
@@ -173,6 +177,29 @@ extern void brcmu_pktq_flush(struct pktq *pq, bool dir,
 /* ip address */
 struct ipv4_addr;
 
+/*
+ * bitfield macros using masking and shift
+ *
+ * remark: the mask parameter should be a shifted mask.
+ */
+static inline void brcmu_maskset32(u32 *var, u32 mask, u8 shift, u32 value)
+{
+       value = (value << shift) & mask;
+       *var = (*var & ~mask) | value;
+}
+static inline u32 brcmu_maskget32(u32 var, u32 mask, u8 shift)
+{
+       return (var & mask) >> shift;
+}
+static inline void brcmu_maskset16(u16 *var, u16 mask, u8 shift, u16 value)
+{
+       value = (value << shift) & mask;
+       *var = (*var & ~mask) | value;
+}
+static inline u16 brcmu_maskget16(u16 var, u16 mask, u8 shift)
+{
+       return (var & mask) >> shift;
+}
 
 /* externs */
 /* format/print */
index 3630a41..df5a57c 100644 (file)
@@ -3475,7 +3475,7 @@ static struct attribute_group il3945_attribute_group = {
        .attrs = il3945_sysfs_entries,
 };
 
-struct ieee80211_ops il3945_mac_ops = {
+static struct ieee80211_ops il3945_mac_ops __read_mostly = {
        .tx = il3945_mac_tx,
        .start = il3945_mac_start,
        .stop = il3945_mac_stop,
index 1d45075..9a8703d 100644 (file)
@@ -150,10 +150,6 @@ struct il3945_frame {
        struct list_head list;
 };
 
-#define SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4)
-#define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ)
-#define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4)
-
 #define SUP_RATE_11A_MAX_NUM_CHANNELS  8
 #define SUP_RATE_11B_MAX_NUM_CHANNELS  4
 #define SUP_RATE_11G_MAX_NUM_CHANNELS  12
index 7941eb3..5bc995a 100644 (file)
@@ -612,7 +612,7 @@ il4965_pass_packet_to_mac80211(struct il_priv *il, struct ieee80211_hdr *hdr,
 
 /* Called for N_RX (legacy ABG frames), or
  * N_RX_MPDU (HT high-throughput N frames). */
-void
+static void
 il4965_hdl_rx(struct il_priv *il, struct il_rx_buf *rxb)
 {
        struct ieee80211_hdr *header;
@@ -744,7 +744,7 @@ il4965_hdl_rx(struct il_priv *il, struct il_rx_buf *rxb)
 
 /* Cache phy data (Rx signal strength, etc) for HT frame (N_RX_PHY).
  * This will be used later in il_hdl_rx() for N_RX_MPDU. */
-void
+static void
 il4965_hdl_rx_phy(struct il_priv *il, struct il_rx_buf *rxb)
 {
        struct il_rx_pkt *pkt = rxb_addr(rxb);
@@ -1250,7 +1250,7 @@ il4965_dump_fh(struct il_priv *il, char **buf, bool display)
        return 0;
 }
 
-void
+static void
 il4965_hdl_missed_beacon(struct il_priv *il, struct il_rx_buf *rxb)
 {
        struct il_rx_pkt *pkt = rxb_addr(rxb);
@@ -1357,7 +1357,7 @@ il4965_accumulative_stats(struct il_priv *il, __le32 * stats)
 }
 #endif
 
-void
+static void
 il4965_hdl_stats(struct il_priv *il, struct il_rx_buf *rxb)
 {
        const int recalib_seconds = 60;
@@ -1399,7 +1399,7 @@ il4965_hdl_stats(struct il_priv *il, struct il_rx_buf *rxb)
                il4965_temperature_calib(il);
 }
 
-void
+static void
 il4965_hdl_c_stats(struct il_priv *il, struct il_rx_buf *rxb)
 {
        struct il_rx_pkt *pkt = rxb_addr(rxb);
@@ -2050,7 +2050,7 @@ il4965_txq_ctx_reset(struct il_priv *il)
                il_tx_queue_reset(il, txq_id);
 }
 
-void
+static void
 il4965_txq_ctx_unmap(struct il_priv *il)
 {
        int txq_id;
@@ -2258,7 +2258,7 @@ il4965_tx_agg_start(struct il_priv *il, struct ieee80211_vif *vif,
 
        spin_lock_irqsave(&il->sta_lock, flags);
        tid_data = &il->stations[sta_id].tid[tid];
-       *ssn = SEQ_TO_SN(tid_data->seq_number);
+       *ssn = IEEE80211_SEQ_TO_SN(tid_data->seq_number);
        tid_data->agg.txq_id = txq_id;
        il_set_swq_id(&il->txq[txq_id], il4965_get_ac_from_tid(tid), txq_id);
        spin_unlock_irqrestore(&il->sta_lock, flags);
@@ -2408,7 +2408,7 @@ il4965_txq_check_empty(struct il_priv *il, int sta_id, u8 tid, int txq_id)
                /* aggregated HW queue */
                if (txq_id == tid_data->agg.txq_id &&
                    q->read_ptr == q->write_ptr) {
-                       u16 ssn = SEQ_TO_SN(tid_data->seq_number);
+                       u16 ssn = IEEE80211_SEQ_TO_SN(tid_data->seq_number);
                        int tx_fifo = il4965_get_fifo_from_tid(tid);
                        D_HT("HW queue empty: continue DELBA flow\n");
                        il4965_txq_agg_disable(il, txq_id, ssn, tx_fifo);
@@ -2627,7 +2627,8 @@ il4965_get_ra_sta_id(struct il_priv *il, struct ieee80211_hdr *hdr)
 static inline u32
 il4965_get_scd_ssn(struct il4965_tx_resp *tx_resp)
 {
-       return le32_to_cpup(&tx_resp->u.status + tx_resp->frame_count) & MAX_SN;
+       return le32_to_cpup(&tx_resp->u.status +
+                           tx_resp->frame_count) & IEEE80211_MAX_SN;
 }
 
 static inline u32
@@ -2717,15 +2718,15 @@ il4965_tx_status_reply_tx(struct il_priv *il, struct il_ht_agg *agg,
                        hdr = (struct ieee80211_hdr *) skb->data;
 
                        sc = le16_to_cpu(hdr->seq_ctrl);
-                       if (idx != (SEQ_TO_SN(sc) & 0xff)) {
+                       if (idx != (IEEE80211_SEQ_TO_SN(sc) & 0xff)) {
                                IL_ERR("BUG_ON idx doesn't match seq control"
                                       " idx=%d, seq_idx=%d, seq=%d\n", idx,
-                                      SEQ_TO_SN(sc), hdr->seq_ctrl);
+                                      IEEE80211_SEQ_TO_SN(sc), hdr->seq_ctrl);
                                return -1;
                        }
 
                        D_TX_REPLY("AGG Frame i=%d idx %d seq=%d\n", i, idx,
-                                  SEQ_TO_SN(sc));
+                                  IEEE80211_SEQ_TO_SN(sc));
 
                        sh = idx - start;
                        if (sh > 64) {
@@ -2895,7 +2896,7 @@ il4965_hwrate_to_tx_control(struct il_priv *il, u32 rate_n_flags,
  * Handles block-acknowledge notification from device, which reports success
  * of frames sent via aggregation.
  */
-void
+static void
 il4965_hdl_compressed_ba(struct il_priv *il, struct il_rx_buf *rxb)
 {
        struct il_rx_pkt *pkt = rxb_addr(rxb);
@@ -6316,7 +6317,7 @@ il4965_tx_queue_set_status(struct il_priv *il, struct il_tx_queue *txq,
               scd_retry ? "BA" : "AC", txq_id, tx_fifo_id);
 }
 
-const struct ieee80211_ops il4965_mac_ops = {
+static const struct ieee80211_ops il4965_mac_ops = {
        .tx = il4965_mac_tx,
        .start = il4965_mac_start,
        .stop = il4965_mac_stop,
index e006ea8..bc465da 100644 (file)
@@ -1122,7 +1122,7 @@ il_set_power(struct il_priv *il, struct il_powertable_cmd *cmd)
                               sizeof(struct il_powertable_cmd), cmd);
 }
 
-int
+static int
 il_power_set_mode(struct il_priv *il, struct il_powertable_cmd *cmd, bool force)
 {
        int ret;
index 96f2025..73bd3ef 100644 (file)
@@ -541,10 +541,6 @@ struct il_frame {
        struct list_head list;
 };
 
-#define SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4)
-#define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ)
-#define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4)
-
 enum {
        CMD_SYNC = 0,
        CMD_SIZE_NORMAL = 0,
index ba319cb..56c2040 100644 (file)
@@ -6,7 +6,6 @@ config IWLWIFI
        select LEDS_CLASS
        select LEDS_TRIGGERS
        select MAC80211_LEDS
-       select IWLDVM
        ---help---
          Select to build the driver supporting the:
 
@@ -45,6 +44,7 @@ config IWLWIFI
 config IWLDVM
        tristate "Intel Wireless WiFi DVM Firmware support"
        depends on IWLWIFI
+       default IWLWIFI
        help
          This is the driver supporting the DVM firmware which is
          currently the only firmware available for existing devices.
@@ -58,6 +58,15 @@ config IWLMVM
 
          Say yes if you have such a device.
 
+# don't call it _MODULE -- will confuse Kconfig/fixdep/...
+config IWLWIFI_OPMODE_MODULAR
+       bool
+       default y if IWLDVM=m
+       default y if IWLMVM=m
+
+comment "WARNING: iwlwifi is useless without IWLDVM or IWLMVM"
+       depends on IWLWIFI && IWLDVM=n && IWLMVM=n
+
 menu "Debugging Options"
        depends on IWLWIFI
 
index 6c78000..3b5613e 100644 (file)
@@ -7,8 +7,7 @@ iwlwifi-objs            += iwl-notif-wait.o
 iwlwifi-objs           += iwl-eeprom-read.o iwl-eeprom-parse.o
 iwlwifi-objs           += iwl-phy-db.o iwl-nvm-parse.o
 iwlwifi-objs           += pcie/drv.o pcie/rx.o pcie/tx.o pcie/trans.o
-iwlwifi-objs           += pcie/1000.o pcie/2000.o pcie/5000.o pcie/6000.o
-iwlwifi-objs           += pcie/7000.o
+iwlwifi-objs           += iwl-1000.o iwl-2000.o iwl-5000.o iwl-6000.o iwl-7000.o
 
 iwlwifi-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o
 iwlwifi-$(CONFIG_IWLWIFI_DEVICE_TESTMODE) += iwl-test.o
index 41ec27c..019d433 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
index 6468de8..d6c4cf2 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
index 65e920c..cfddde1 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
index 84e2c0f..95ca026 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
@@ -1526,6 +1526,7 @@ struct iwl_compressed_ba_resp {
        __le16 scd_ssn;
        u8 txed;        /* number of frames sent */
        u8 txed_2_done; /* number of frames acked */
+       __le16 reserved1;
 } __packed;
 
 /*
index 20806ca..7b8178b 100644 (file)
@@ -19,7 +19,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
@@ -2324,6 +2324,28 @@ static ssize_t iwl_dbgfs_calib_disabled_write(struct file *file,
        return count;
 }
 
+static ssize_t iwl_dbgfs_fw_restart_write(struct file *file,
+                                         const char __user *user_buf,
+                                         size_t count, loff_t *ppos)
+{
+       struct iwl_priv *priv = file->private_data;
+       bool restart_fw = iwlwifi_mod_params.restart_fw;
+       int ret;
+
+       iwlwifi_mod_params.restart_fw = true;
+
+       mutex_lock(&priv->mutex);
+
+       /* take the return value to make compiler happy - it will fail anyway */
+       ret = iwl_dvm_send_cmd_pdu(priv, REPLY_ERROR, CMD_SYNC, 0, NULL);
+
+       mutex_unlock(&priv->mutex);
+
+       iwlwifi_mod_params.restart_fw = restart_fw;
+
+       return count;
+}
+
 DEBUGFS_READ_FILE_OPS(ucode_rx_stats);
 DEBUGFS_READ_FILE_OPS(ucode_tx_stats);
 DEBUGFS_READ_FILE_OPS(ucode_general_stats);
@@ -2343,6 +2365,7 @@ DEBUGFS_READ_FILE_OPS(bt_traffic);
 DEBUGFS_READ_WRITE_FILE_OPS(protection_mode);
 DEBUGFS_READ_FILE_OPS(reply_tx_error);
 DEBUGFS_WRITE_FILE_OPS(echo_test);
+DEBUGFS_WRITE_FILE_OPS(fw_restart);
 #ifdef CONFIG_IWLWIFI_DEBUG
 DEBUGFS_READ_WRITE_FILE_OPS(log_event);
 #endif
@@ -2400,6 +2423,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, struct dentry *dbgfs_dir)
        DEBUGFS_ADD_FILE(rxon_flags, dir_debug, S_IWUSR);
        DEBUGFS_ADD_FILE(rxon_filter_flags, dir_debug, S_IWUSR);
        DEBUGFS_ADD_FILE(echo_test, dir_debug, S_IWUSR);
+       DEBUGFS_ADD_FILE(fw_restart, dir_debug, S_IWUSR);
 #ifdef CONFIG_IWLWIFI_DEBUG
        DEBUGFS_ADD_FILE(log_event, dir_debug, S_IWUSR | S_IRUSR);
 #endif
index 86ea5f4..cddf77c 100644 (file)
@@ -19,7 +19,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
index 323e4a3..c7cd2df 100644 (file)
@@ -1137,7 +1137,8 @@ done:
 static int iwlagn_mac_remain_on_channel(struct ieee80211_hw *hw,
                                     struct ieee80211_vif *vif,
                                     struct ieee80211_channel *channel,
-                                    int duration)
+                                    int duration,
+                                    enum ieee80211_roc_type type)
 {
        struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
        struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_PAN];
index 3a4aa52..d69b558 100644 (file)
@@ -19,7 +19,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
index dc6f965..b89b9d9 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
index 6aec2df..cc1e0c1 100644 (file)
@@ -19,7 +19,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
@@ -418,7 +418,8 @@ int iwlagn_tx_skb(struct iwl_priv *priv,
                                " Tx flags = 0x%08x, agg.state = %d",
                                info->flags, tid_data->agg.state);
                        IWL_ERR(priv, "sta_id = %d, tid = %d seq_num = %d",
-                               sta_id, tid, SEQ_TO_SN(tid_data->seq_number));
+                               sta_id, tid,
+                               IEEE80211_SEQ_TO_SN(tid_data->seq_number));
                        goto drop_unlock_sta;
                }
 
@@ -569,7 +570,7 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
                return 0;
        }
 
-       tid_data->agg.ssn = SEQ_TO_SN(tid_data->seq_number);
+       tid_data->agg.ssn = IEEE80211_SEQ_TO_SN(tid_data->seq_number);
 
        /* There are still packets for this RA / TID in the HW */
        if (!test_bit(txq_id, priv->agg_q_alloc)) {
@@ -651,7 +652,7 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif,
 
        spin_lock_bh(&priv->sta_lock);
        tid_data = &priv->tid_data[sta_id][tid];
-       tid_data->agg.ssn = SEQ_TO_SN(tid_data->seq_number);
+       tid_data->agg.ssn = IEEE80211_SEQ_TO_SN(tid_data->seq_number);
        tid_data->agg.txq_id = txq_id;
 
        *ssn = tid_data->agg.ssn;
@@ -911,7 +912,7 @@ static void iwlagn_count_agg_tx_err_status(struct iwl_priv *priv, u16 status)
 static inline u32 iwlagn_get_scd_ssn(struct iwlagn_tx_resp *tx_resp)
 {
        return le32_to_cpup((__le32 *)&tx_resp->status +
-                           tx_resp->frame_count) & MAX_SN;
+                           tx_resp->frame_count) & IEEE80211_MAX_SN;
 }
 
 static void iwl_rx_reply_tx_agg(struct iwl_priv *priv,
@@ -1148,7 +1149,7 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
 
        if (tx_resp->frame_count == 1) {
                u16 next_reclaimed = le16_to_cpu(tx_resp->seq_ctl);
-               next_reclaimed = SEQ_TO_SN(next_reclaimed + 0x10);
+               next_reclaimed = IEEE80211_SEQ_TO_SN(next_reclaimed + 0x10);
 
                if (is_agg) {
                        /* If this is an aggregation queue, we can rely on the
index 736fe9b..166019a 100644 (file)
@@ -19,7 +19,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c
new file mode 100644 (file)
index 0000000..c080ae3
--- /dev/null
@@ -0,0 +1,140 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#include <linux/module.h>
+#include <linux/stringify.h>
+#include "iwl-config.h"
+#include "iwl-csr.h"
+#include "iwl-agn-hw.h"
+
+/* Highest firmware API version supported */
+#define IWL1000_UCODE_API_MAX 5
+#define IWL100_UCODE_API_MAX 5
+
+/* Oldest version we won't warn about */
+#define IWL1000_UCODE_API_OK 5
+#define IWL100_UCODE_API_OK 5
+
+/* Lowest firmware API version supported */
+#define IWL1000_UCODE_API_MIN 1
+#define IWL100_UCODE_API_MIN 5
+
+/* EEPROM version */
+#define EEPROM_1000_TX_POWER_VERSION   (4)
+#define EEPROM_1000_EEPROM_VERSION     (0x15C)
+
+#define IWL1000_FW_PRE "iwlwifi-1000-"
+#define IWL1000_MODULE_FIRMWARE(api) IWL1000_FW_PRE __stringify(api) ".ucode"
+
+#define IWL100_FW_PRE "iwlwifi-100-"
+#define IWL100_MODULE_FIRMWARE(api) IWL100_FW_PRE __stringify(api) ".ucode"
+
+
+static const struct iwl_base_params iwl1000_base_params = {
+       .num_of_queues = IWLAGN_NUM_QUEUES,
+       .eeprom_size = OTP_LOW_IMAGE_SIZE,
+       .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
+       .max_ll_items = OTP_MAX_LL_ITEMS_1000,
+       .shadow_ram_support = false,
+       .led_compensation = 51,
+       .support_ct_kill_exit = true,
+       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF,
+       .chain_noise_scale = 1000,
+       .wd_timeout = IWL_WATCHDOG_DISABLED,
+       .max_event_log_size = 128,
+};
+
+static const struct iwl_ht_params iwl1000_ht_params = {
+       .ht_greenfield_support = true,
+       .use_rts_for_aggregation = true, /* use rts/cts protection */
+       .ht40_bands = BIT(IEEE80211_BAND_2GHZ),
+};
+
+static const struct iwl_eeprom_params iwl1000_eeprom_params = {
+       .regulatory_bands = {
+               EEPROM_REG_BAND_1_CHANNELS,
+               EEPROM_REG_BAND_2_CHANNELS,
+               EEPROM_REG_BAND_3_CHANNELS,
+               EEPROM_REG_BAND_4_CHANNELS,
+               EEPROM_REG_BAND_5_CHANNELS,
+               EEPROM_REG_BAND_24_HT40_CHANNELS,
+               EEPROM_REGULATORY_BAND_NO_HT40,
+       }
+};
+
+#define IWL_DEVICE_1000                                                \
+       .fw_name_pre = IWL1000_FW_PRE,                          \
+       .ucode_api_max = IWL1000_UCODE_API_MAX,                 \
+       .ucode_api_ok = IWL1000_UCODE_API_OK,                   \
+       .ucode_api_min = IWL1000_UCODE_API_MIN,                 \
+       .device_family = IWL_DEVICE_FAMILY_1000,                \
+       .max_inst_size = IWLAGN_RTC_INST_SIZE,                  \
+       .max_data_size = IWLAGN_RTC_DATA_SIZE,                  \
+       .nvm_ver = EEPROM_1000_EEPROM_VERSION,          \
+       .nvm_calib_ver = EEPROM_1000_TX_POWER_VERSION,  \
+       .base_params = &iwl1000_base_params,                    \
+       .eeprom_params = &iwl1000_eeprom_params,                \
+       .led_mode = IWL_LED_BLINK
+
+const struct iwl_cfg iwl1000_bgn_cfg = {
+       .name = "Intel(R) Centrino(R) Wireless-N 1000 BGN",
+       IWL_DEVICE_1000,
+       .ht_params = &iwl1000_ht_params,
+};
+
+const struct iwl_cfg iwl1000_bg_cfg = {
+       .name = "Intel(R) Centrino(R) Wireless-N 1000 BG",
+       IWL_DEVICE_1000,
+};
+
+#define IWL_DEVICE_100                                         \
+       .fw_name_pre = IWL100_FW_PRE,                           \
+       .ucode_api_max = IWL100_UCODE_API_MAX,                  \
+       .ucode_api_ok = IWL100_UCODE_API_OK,                    \
+       .ucode_api_min = IWL100_UCODE_API_MIN,                  \
+       .device_family = IWL_DEVICE_FAMILY_100,                 \
+       .max_inst_size = IWLAGN_RTC_INST_SIZE,                  \
+       .max_data_size = IWLAGN_RTC_DATA_SIZE,                  \
+       .nvm_ver = EEPROM_1000_EEPROM_VERSION,          \
+       .nvm_calib_ver = EEPROM_1000_TX_POWER_VERSION,  \
+       .base_params = &iwl1000_base_params,                    \
+       .eeprom_params = &iwl1000_eeprom_params,                \
+       .led_mode = IWL_LED_RF_STATE,                           \
+       .rx_with_siso_diversity = true
+
+const struct iwl_cfg iwl100_bgn_cfg = {
+       .name = "Intel(R) Centrino(R) Wireless-N 100 BGN",
+       IWL_DEVICE_100,
+       .ht_params = &iwl1000_ht_params,
+};
+
+const struct iwl_cfg iwl100_bg_cfg = {
+       .name = "Intel(R) Centrino(R) Wireless-N 100 BG",
+       IWL_DEVICE_100,
+};
+
+MODULE_FIRMWARE(IWL1000_MODULE_FIRMWARE(IWL1000_UCODE_API_OK));
+MODULE_FIRMWARE(IWL100_MODULE_FIRMWARE(IWL100_UCODE_API_OK));
diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c
new file mode 100644 (file)
index 0000000..a6ddd2f
--- /dev/null
@@ -0,0 +1,242 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#include <linux/module.h>
+#include <linux/stringify.h>
+#include "iwl-config.h"
+#include "iwl-agn-hw.h"
+#include "dvm/commands.h" /* needed for BT for now */
+
+/* Highest firmware API version supported */
+#define IWL2030_UCODE_API_MAX 6
+#define IWL2000_UCODE_API_MAX 6
+#define IWL105_UCODE_API_MAX 6
+#define IWL135_UCODE_API_MAX 6
+
+/* Oldest version we won't warn about */
+#define IWL2030_UCODE_API_OK 6
+#define IWL2000_UCODE_API_OK 6
+#define IWL105_UCODE_API_OK 6
+#define IWL135_UCODE_API_OK 6
+
+/* Lowest firmware API version supported */
+#define IWL2030_UCODE_API_MIN 5
+#define IWL2000_UCODE_API_MIN 5
+#define IWL105_UCODE_API_MIN 5
+#define IWL135_UCODE_API_MIN 5
+
+/* EEPROM version */
+#define EEPROM_2000_TX_POWER_VERSION   (6)
+#define EEPROM_2000_EEPROM_VERSION     (0x805)
+
+
+#define IWL2030_FW_PRE "iwlwifi-2030-"
+#define IWL2030_MODULE_FIRMWARE(api) IWL2030_FW_PRE __stringify(api) ".ucode"
+
+#define IWL2000_FW_PRE "iwlwifi-2000-"
+#define IWL2000_MODULE_FIRMWARE(api) IWL2000_FW_PRE __stringify(api) ".ucode"
+
+#define IWL105_FW_PRE "iwlwifi-105-"
+#define IWL105_MODULE_FIRMWARE(api) IWL105_FW_PRE __stringify(api) ".ucode"
+
+#define IWL135_FW_PRE "iwlwifi-135-"
+#define IWL135_MODULE_FIRMWARE(api) IWL135_FW_PRE __stringify(api) ".ucode"
+
+static const struct iwl_base_params iwl2000_base_params = {
+       .eeprom_size = OTP_LOW_IMAGE_SIZE,
+       .num_of_queues = IWLAGN_NUM_QUEUES,
+       .pll_cfg_val = 0,
+       .max_ll_items = OTP_MAX_LL_ITEMS_2x00,
+       .shadow_ram_support = true,
+       .led_compensation = 51,
+       .adv_thermal_throttle = true,
+       .support_ct_kill_exit = true,
+       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+       .chain_noise_scale = 1000,
+       .wd_timeout = IWL_DEF_WD_TIMEOUT,
+       .max_event_log_size = 512,
+       .shadow_reg_enable = false, /* TODO: fix bugs using this feature */
+       .hd_v2 = true,
+};
+
+
+static const struct iwl_base_params iwl2030_base_params = {
+       .eeprom_size = OTP_LOW_IMAGE_SIZE,
+       .num_of_queues = IWLAGN_NUM_QUEUES,
+       .pll_cfg_val = 0,
+       .max_ll_items = OTP_MAX_LL_ITEMS_2x00,
+       .shadow_ram_support = true,
+       .led_compensation = 57,
+       .adv_thermal_throttle = true,
+       .support_ct_kill_exit = true,
+       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+       .chain_noise_scale = 1000,
+       .wd_timeout = IWL_LONG_WD_TIMEOUT,
+       .max_event_log_size = 512,
+       .shadow_reg_enable = false, /* TODO: fix bugs using this feature */
+       .hd_v2 = true,
+};
+
+static const struct iwl_ht_params iwl2000_ht_params = {
+       .ht_greenfield_support = true,
+       .use_rts_for_aggregation = true, /* use rts/cts protection */
+       .ht40_bands = BIT(IEEE80211_BAND_2GHZ),
+};
+
+static const struct iwl_bt_params iwl2030_bt_params = {
+       /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
+       .advanced_bt_coexist = true,
+       .agg_time_limit = BT_AGG_THRESHOLD_DEF,
+       .bt_init_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_NONE,
+       .bt_prio_boost = IWLAGN_BT_PRIO_BOOST_DEFAULT32,
+       .bt_sco_disable = true,
+       .bt_session_2 = true,
+};
+
+static const struct iwl_eeprom_params iwl20x0_eeprom_params = {
+       .regulatory_bands = {
+               EEPROM_REG_BAND_1_CHANNELS,
+               EEPROM_REG_BAND_2_CHANNELS,
+               EEPROM_REG_BAND_3_CHANNELS,
+               EEPROM_REG_BAND_4_CHANNELS,
+               EEPROM_REG_BAND_5_CHANNELS,
+               EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
+               EEPROM_REGULATORY_BAND_NO_HT40,
+       },
+       .enhanced_txpower = true,
+};
+
+#define IWL_DEVICE_2000                                                \
+       .fw_name_pre = IWL2000_FW_PRE,                          \
+       .ucode_api_max = IWL2000_UCODE_API_MAX,                 \
+       .ucode_api_ok = IWL2000_UCODE_API_OK,                   \
+       .ucode_api_min = IWL2000_UCODE_API_MIN,                 \
+       .device_family = IWL_DEVICE_FAMILY_2000,                \
+       .max_inst_size = IWL60_RTC_INST_SIZE,                   \
+       .max_data_size = IWL60_RTC_DATA_SIZE,                   \
+       .nvm_ver = EEPROM_2000_EEPROM_VERSION,          \
+       .nvm_calib_ver = EEPROM_2000_TX_POWER_VERSION,  \
+       .base_params = &iwl2000_base_params,                    \
+       .eeprom_params = &iwl20x0_eeprom_params,                \
+       .need_temp_offset_calib = true,                         \
+       .temp_offset_v2 = true,                                 \
+       .led_mode = IWL_LED_RF_STATE
+
+const struct iwl_cfg iwl2000_2bgn_cfg = {
+       .name = "Intel(R) Centrino(R) Wireless-N 2200 BGN",
+       IWL_DEVICE_2000,
+       .ht_params = &iwl2000_ht_params,
+};
+
+const struct iwl_cfg iwl2000_2bgn_d_cfg = {
+       .name = "Intel(R) Centrino(R) Wireless-N 2200D BGN",
+       IWL_DEVICE_2000,
+       .ht_params = &iwl2000_ht_params,
+};
+
+#define IWL_DEVICE_2030                                                \
+       .fw_name_pre = IWL2030_FW_PRE,                          \
+       .ucode_api_max = IWL2030_UCODE_API_MAX,                 \
+       .ucode_api_ok = IWL2030_UCODE_API_OK,                   \
+       .ucode_api_min = IWL2030_UCODE_API_MIN,                 \
+       .device_family = IWL_DEVICE_FAMILY_2030,                \
+       .max_inst_size = IWL60_RTC_INST_SIZE,                   \
+       .max_data_size = IWL60_RTC_DATA_SIZE,                   \
+       .nvm_ver = EEPROM_2000_EEPROM_VERSION,          \
+       .nvm_calib_ver = EEPROM_2000_TX_POWER_VERSION,  \
+       .base_params = &iwl2030_base_params,                    \
+       .bt_params = &iwl2030_bt_params,                        \
+       .eeprom_params = &iwl20x0_eeprom_params,                \
+       .need_temp_offset_calib = true,                         \
+       .temp_offset_v2 = true,                                 \
+       .led_mode = IWL_LED_RF_STATE,                           \
+       .adv_pm = true
+
+const struct iwl_cfg iwl2030_2bgn_cfg = {
+       .name = "Intel(R) Centrino(R) Wireless-N 2230 BGN",
+       IWL_DEVICE_2030,
+       .ht_params = &iwl2000_ht_params,
+};
+
+#define IWL_DEVICE_105                                         \
+       .fw_name_pre = IWL105_FW_PRE,                           \
+       .ucode_api_max = IWL105_UCODE_API_MAX,                  \
+       .ucode_api_ok = IWL105_UCODE_API_OK,                    \
+       .ucode_api_min = IWL105_UCODE_API_MIN,                  \
+       .device_family = IWL_DEVICE_FAMILY_105,                 \
+       .max_inst_size = IWL60_RTC_INST_SIZE,                   \
+       .max_data_size = IWL60_RTC_DATA_SIZE,                   \
+       .nvm_ver = EEPROM_2000_EEPROM_VERSION,          \
+       .nvm_calib_ver = EEPROM_2000_TX_POWER_VERSION,  \
+       .base_params = &iwl2000_base_params,                    \
+       .eeprom_params = &iwl20x0_eeprom_params,                \
+       .need_temp_offset_calib = true,                         \
+       .temp_offset_v2 = true,                                 \
+       .led_mode = IWL_LED_RF_STATE,                           \
+       .adv_pm = true,                                         \
+       .rx_with_siso_diversity = true
+
+const struct iwl_cfg iwl105_bgn_cfg = {
+       .name = "Intel(R) Centrino(R) Wireless-N 105 BGN",
+       IWL_DEVICE_105,
+       .ht_params = &iwl2000_ht_params,
+};
+
+const struct iwl_cfg iwl105_bgn_d_cfg = {
+       .name = "Intel(R) Centrino(R) Wireless-N 105D BGN",
+       IWL_DEVICE_105,
+       .ht_params = &iwl2000_ht_params,
+};
+
+#define IWL_DEVICE_135                                         \
+       .fw_name_pre = IWL135_FW_PRE,                           \
+       .ucode_api_max = IWL135_UCODE_API_MAX,                  \
+       .ucode_api_ok = IWL135_UCODE_API_OK,                    \
+       .ucode_api_min = IWL135_UCODE_API_MIN,                  \
+       .device_family = IWL_DEVICE_FAMILY_135,                 \
+       .max_inst_size = IWL60_RTC_INST_SIZE,                   \
+       .max_data_size = IWL60_RTC_DATA_SIZE,                   \
+       .nvm_ver = EEPROM_2000_EEPROM_VERSION,          \
+       .nvm_calib_ver = EEPROM_2000_TX_POWER_VERSION,  \
+       .base_params = &iwl2030_base_params,                    \
+       .bt_params = &iwl2030_bt_params,                        \
+       .eeprom_params = &iwl20x0_eeprom_params,                \
+       .need_temp_offset_calib = true,                         \
+       .temp_offset_v2 = true,                                 \
+       .led_mode = IWL_LED_RF_STATE,                           \
+       .adv_pm = true,                                         \
+       .rx_with_siso_diversity = true
+
+const struct iwl_cfg iwl135_bgn_cfg = {
+       .name = "Intel(R) Centrino(R) Wireless-N 135 BGN",
+       IWL_DEVICE_135,
+       .ht_params = &iwl2000_ht_params,
+};
+
+MODULE_FIRMWARE(IWL2000_MODULE_FIRMWARE(IWL2000_UCODE_API_OK));
+MODULE_FIRMWARE(IWL2030_MODULE_FIRMWARE(IWL2030_UCODE_API_OK));
+MODULE_FIRMWARE(IWL105_MODULE_FIRMWARE(IWL105_UCODE_API_OK));
+MODULE_FIRMWARE(IWL135_MODULE_FIRMWARE(IWL135_UCODE_API_OK));
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
new file mode 100644 (file)
index 0000000..403f3f2
--- /dev/null
@@ -0,0 +1,179 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#include <linux/module.h>
+#include <linux/stringify.h>
+#include "iwl-config.h"
+#include "iwl-agn-hw.h"
+#include "iwl-csr.h"
+
+/* Highest firmware API version supported */
+#define IWL5000_UCODE_API_MAX 5
+#define IWL5150_UCODE_API_MAX 2
+
+/* Oldest version we won't warn about */
+#define IWL5000_UCODE_API_OK 5
+#define IWL5150_UCODE_API_OK 2
+
+/* Lowest firmware API version supported */
+#define IWL5000_UCODE_API_MIN 1
+#define IWL5150_UCODE_API_MIN 1
+
+/* EEPROM versions */
+#define EEPROM_5000_TX_POWER_VERSION   (4)
+#define EEPROM_5000_EEPROM_VERSION     (0x11A)
+#define EEPROM_5050_TX_POWER_VERSION   (4)
+#define EEPROM_5050_EEPROM_VERSION     (0x21E)
+
+#define IWL5000_FW_PRE "iwlwifi-5000-"
+#define IWL5000_MODULE_FIRMWARE(api) IWL5000_FW_PRE __stringify(api) ".ucode"
+
+#define IWL5150_FW_PRE "iwlwifi-5150-"
+#define IWL5150_MODULE_FIRMWARE(api) IWL5150_FW_PRE __stringify(api) ".ucode"
+
+static const struct iwl_base_params iwl5000_base_params = {
+       .eeprom_size = IWLAGN_EEPROM_IMG_SIZE,
+       .num_of_queues = IWLAGN_NUM_QUEUES,
+       .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
+       .led_compensation = 51,
+       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
+       .chain_noise_scale = 1000,
+       .wd_timeout = IWL_WATCHDOG_DISABLED,
+       .max_event_log_size = 512,
+       .no_idle_support = true,
+};
+
+static const struct iwl_ht_params iwl5000_ht_params = {
+       .ht_greenfield_support = true,
+       .ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ),
+};
+
+static const struct iwl_eeprom_params iwl5000_eeprom_params = {
+       .regulatory_bands = {
+               EEPROM_REG_BAND_1_CHANNELS,
+               EEPROM_REG_BAND_2_CHANNELS,
+               EEPROM_REG_BAND_3_CHANNELS,
+               EEPROM_REG_BAND_4_CHANNELS,
+               EEPROM_REG_BAND_5_CHANNELS,
+               EEPROM_REG_BAND_24_HT40_CHANNELS,
+               EEPROM_REG_BAND_52_HT40_CHANNELS
+       },
+};
+
+#define IWL_DEVICE_5000                                                \
+       .fw_name_pre = IWL5000_FW_PRE,                          \
+       .ucode_api_max = IWL5000_UCODE_API_MAX,                 \
+       .ucode_api_ok = IWL5000_UCODE_API_OK,                   \
+       .ucode_api_min = IWL5000_UCODE_API_MIN,                 \
+       .device_family = IWL_DEVICE_FAMILY_5000,                \
+       .max_inst_size = IWLAGN_RTC_INST_SIZE,                  \
+       .max_data_size = IWLAGN_RTC_DATA_SIZE,                  \
+       .nvm_ver = EEPROM_5000_EEPROM_VERSION,          \
+       .nvm_calib_ver = EEPROM_5000_TX_POWER_VERSION,  \
+       .base_params = &iwl5000_base_params,                    \
+       .eeprom_params = &iwl5000_eeprom_params,                \
+       .led_mode = IWL_LED_BLINK
+
+const struct iwl_cfg iwl5300_agn_cfg = {
+       .name = "Intel(R) Ultimate N WiFi Link 5300 AGN",
+       IWL_DEVICE_5000,
+       /* at least EEPROM 0x11A has wrong info */
+       .valid_tx_ant = ANT_ABC,        /* .cfg overwrite */
+       .valid_rx_ant = ANT_ABC,        /* .cfg overwrite */
+       .ht_params = &iwl5000_ht_params,
+};
+
+const struct iwl_cfg iwl5100_bgn_cfg = {
+       .name = "Intel(R) WiFi Link 5100 BGN",
+       IWL_DEVICE_5000,
+       .valid_tx_ant = ANT_B,          /* .cfg overwrite */
+       .valid_rx_ant = ANT_AB,         /* .cfg overwrite */
+       .ht_params = &iwl5000_ht_params,
+};
+
+const struct iwl_cfg iwl5100_abg_cfg = {
+       .name = "Intel(R) WiFi Link 5100 ABG",
+       IWL_DEVICE_5000,
+       .valid_tx_ant = ANT_B,          /* .cfg overwrite */
+       .valid_rx_ant = ANT_AB,         /* .cfg overwrite */
+};
+
+const struct iwl_cfg iwl5100_agn_cfg = {
+       .name = "Intel(R) WiFi Link 5100 AGN",
+       IWL_DEVICE_5000,
+       .valid_tx_ant = ANT_B,          /* .cfg overwrite */
+       .valid_rx_ant = ANT_AB,         /* .cfg overwrite */
+       .ht_params = &iwl5000_ht_params,
+};
+
+const struct iwl_cfg iwl5350_agn_cfg = {
+       .name = "Intel(R) WiMAX/WiFi Link 5350 AGN",
+       .fw_name_pre = IWL5000_FW_PRE,
+       .ucode_api_max = IWL5000_UCODE_API_MAX,
+       .ucode_api_ok = IWL5000_UCODE_API_OK,
+       .ucode_api_min = IWL5000_UCODE_API_MIN,
+       .device_family = IWL_DEVICE_FAMILY_5000,
+       .max_inst_size = IWLAGN_RTC_INST_SIZE,
+       .max_data_size = IWLAGN_RTC_DATA_SIZE,
+       .nvm_ver = EEPROM_5050_EEPROM_VERSION,
+       .nvm_calib_ver = EEPROM_5050_TX_POWER_VERSION,
+       .base_params = &iwl5000_base_params,
+       .eeprom_params = &iwl5000_eeprom_params,
+       .ht_params = &iwl5000_ht_params,
+       .led_mode = IWL_LED_BLINK,
+       .internal_wimax_coex = true,
+};
+
+#define IWL_DEVICE_5150                                                \
+       .fw_name_pre = IWL5150_FW_PRE,                          \
+       .ucode_api_max = IWL5150_UCODE_API_MAX,                 \
+       .ucode_api_ok = IWL5150_UCODE_API_OK,                   \
+       .ucode_api_min = IWL5150_UCODE_API_MIN,                 \
+       .device_family = IWL_DEVICE_FAMILY_5150,                \
+       .max_inst_size = IWLAGN_RTC_INST_SIZE,                  \
+       .max_data_size = IWLAGN_RTC_DATA_SIZE,                  \
+       .nvm_ver = EEPROM_5050_EEPROM_VERSION,          \
+       .nvm_calib_ver = EEPROM_5050_TX_POWER_VERSION,  \
+       .base_params = &iwl5000_base_params,                    \
+       .eeprom_params = &iwl5000_eeprom_params,                \
+       .no_xtal_calib = true,                                  \
+       .led_mode = IWL_LED_BLINK,                              \
+       .internal_wimax_coex = true
+
+const struct iwl_cfg iwl5150_agn_cfg = {
+       .name = "Intel(R) WiMAX/WiFi Link 5150 AGN",
+       IWL_DEVICE_5150,
+       .ht_params = &iwl5000_ht_params,
+
+};
+
+const struct iwl_cfg iwl5150_abg_cfg = {
+       .name = "Intel(R) WiMAX/WiFi Link 5150 ABG",
+       IWL_DEVICE_5150,
+};
+
+MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_OK));
+MODULE_FIRMWARE(IWL5150_MODULE_FIRMWARE(IWL5150_UCODE_API_OK));
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c
new file mode 100644 (file)
index 0000000..b5ab8d1
--- /dev/null
@@ -0,0 +1,402 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#include <linux/module.h>
+#include <linux/stringify.h>
+#include "iwl-config.h"
+#include "iwl-agn-hw.h"
+#include "dvm/commands.h" /* needed for BT for now */
+
+/* Highest firmware API version supported */
+#define IWL6000_UCODE_API_MAX 6
+#define IWL6050_UCODE_API_MAX 5
+#define IWL6000G2_UCODE_API_MAX 6
+#define IWL6035_UCODE_API_MAX 6
+
+/* Oldest version we won't warn about */
+#define IWL6000_UCODE_API_OK 4
+#define IWL6000G2_UCODE_API_OK 5
+#define IWL6050_UCODE_API_OK 5
+#define IWL6000G2B_UCODE_API_OK 6
+#define IWL6035_UCODE_API_OK 6
+
+/* Lowest firmware API version supported */
+#define IWL6000_UCODE_API_MIN 4
+#define IWL6050_UCODE_API_MIN 4
+#define IWL6000G2_UCODE_API_MIN 5
+#define IWL6035_UCODE_API_MIN 6
+
+/* EEPROM versions */
+#define EEPROM_6000_TX_POWER_VERSION   (4)
+#define EEPROM_6000_EEPROM_VERSION     (0x423)
+#define EEPROM_6050_TX_POWER_VERSION   (4)
+#define EEPROM_6050_EEPROM_VERSION     (0x532)
+#define EEPROM_6150_TX_POWER_VERSION   (6)
+#define EEPROM_6150_EEPROM_VERSION     (0x553)
+#define EEPROM_6005_TX_POWER_VERSION   (6)
+#define EEPROM_6005_EEPROM_VERSION     (0x709)
+#define EEPROM_6030_TX_POWER_VERSION   (6)
+#define EEPROM_6030_EEPROM_VERSION     (0x709)
+#define EEPROM_6035_TX_POWER_VERSION   (6)
+#define EEPROM_6035_EEPROM_VERSION     (0x753)
+
+#define IWL6000_FW_PRE "iwlwifi-6000-"
+#define IWL6000_MODULE_FIRMWARE(api) IWL6000_FW_PRE __stringify(api) ".ucode"
+
+#define IWL6050_FW_PRE "iwlwifi-6050-"
+#define IWL6050_MODULE_FIRMWARE(api) IWL6050_FW_PRE __stringify(api) ".ucode"
+
+#define IWL6005_FW_PRE "iwlwifi-6000g2a-"
+#define IWL6005_MODULE_FIRMWARE(api) IWL6005_FW_PRE __stringify(api) ".ucode"
+
+#define IWL6030_FW_PRE "iwlwifi-6000g2b-"
+#define IWL6030_MODULE_FIRMWARE(api) IWL6030_FW_PRE __stringify(api) ".ucode"
+
+static const struct iwl_base_params iwl6000_base_params = {
+       .eeprom_size = OTP_LOW_IMAGE_SIZE,
+       .num_of_queues = IWLAGN_NUM_QUEUES,
+       .pll_cfg_val = 0,
+       .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+       .shadow_ram_support = true,
+       .led_compensation = 51,
+       .adv_thermal_throttle = true,
+       .support_ct_kill_exit = true,
+       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+       .chain_noise_scale = 1000,
+       .wd_timeout = IWL_DEF_WD_TIMEOUT,
+       .max_event_log_size = 512,
+       .shadow_reg_enable = false, /* TODO: fix bugs using this feature */
+};
+
+static const struct iwl_base_params iwl6050_base_params = {
+       .eeprom_size = OTP_LOW_IMAGE_SIZE,
+       .num_of_queues = IWLAGN_NUM_QUEUES,
+       .pll_cfg_val = 0,
+       .max_ll_items = OTP_MAX_LL_ITEMS_6x50,
+       .shadow_ram_support = true,
+       .led_compensation = 51,
+       .adv_thermal_throttle = true,
+       .support_ct_kill_exit = true,
+       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+       .chain_noise_scale = 1500,
+       .wd_timeout = IWL_DEF_WD_TIMEOUT,
+       .max_event_log_size = 1024,
+       .shadow_reg_enable = false, /* TODO: fix bugs using this feature */
+};
+
+static const struct iwl_base_params iwl6000_g2_base_params = {
+       .eeprom_size = OTP_LOW_IMAGE_SIZE,
+       .num_of_queues = IWLAGN_NUM_QUEUES,
+       .pll_cfg_val = 0,
+       .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+       .shadow_ram_support = true,
+       .led_compensation = 57,
+       .adv_thermal_throttle = true,
+       .support_ct_kill_exit = true,
+       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+       .chain_noise_scale = 1000,
+       .wd_timeout = IWL_LONG_WD_TIMEOUT,
+       .max_event_log_size = 512,
+       .shadow_reg_enable = false, /* TODO: fix bugs using this feature */
+};
+
+static const struct iwl_ht_params iwl6000_ht_params = {
+       .ht_greenfield_support = true,
+       .use_rts_for_aggregation = true, /* use rts/cts protection */
+       .ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ),
+};
+
+static const struct iwl_bt_params iwl6000_bt_params = {
+       /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
+       .advanced_bt_coexist = true,
+       .agg_time_limit = BT_AGG_THRESHOLD_DEF,
+       .bt_init_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_NONE,
+       .bt_prio_boost = IWLAGN_BT_PRIO_BOOST_DEFAULT,
+       .bt_sco_disable = true,
+};
+
+static const struct iwl_eeprom_params iwl6000_eeprom_params = {
+       .regulatory_bands = {
+               EEPROM_REG_BAND_1_CHANNELS,
+               EEPROM_REG_BAND_2_CHANNELS,
+               EEPROM_REG_BAND_3_CHANNELS,
+               EEPROM_REG_BAND_4_CHANNELS,
+               EEPROM_REG_BAND_5_CHANNELS,
+               EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
+               EEPROM_REG_BAND_52_HT40_CHANNELS
+       },
+       .enhanced_txpower = true,
+};
+
+#define IWL_DEVICE_6005                                                \
+       .fw_name_pre = IWL6005_FW_PRE,                          \
+       .ucode_api_max = IWL6000G2_UCODE_API_MAX,               \
+       .ucode_api_ok = IWL6000G2_UCODE_API_OK,                 \
+       .ucode_api_min = IWL6000G2_UCODE_API_MIN,               \
+       .device_family = IWL_DEVICE_FAMILY_6005,                \
+       .max_inst_size = IWL60_RTC_INST_SIZE,                   \
+       .max_data_size = IWL60_RTC_DATA_SIZE,                   \
+       .nvm_ver = EEPROM_6005_EEPROM_VERSION,          \
+       .nvm_calib_ver = EEPROM_6005_TX_POWER_VERSION,  \
+       .base_params = &iwl6000_g2_base_params,                 \
+       .eeprom_params = &iwl6000_eeprom_params,                \
+       .need_temp_offset_calib = true,                         \
+       .led_mode = IWL_LED_RF_STATE
+
+const struct iwl_cfg iwl6005_2agn_cfg = {
+       .name = "Intel(R) Centrino(R) Advanced-N 6205 AGN",
+       IWL_DEVICE_6005,
+       .ht_params = &iwl6000_ht_params,
+};
+
+const struct iwl_cfg iwl6005_2abg_cfg = {
+       .name = "Intel(R) Centrino(R) Advanced-N 6205 ABG",
+       IWL_DEVICE_6005,
+};
+
+const struct iwl_cfg iwl6005_2bg_cfg = {
+       .name = "Intel(R) Centrino(R) Advanced-N 6205 BG",
+       IWL_DEVICE_6005,
+};
+
+const struct iwl_cfg iwl6005_2agn_sff_cfg = {
+       .name = "Intel(R) Centrino(R) Advanced-N 6205S AGN",
+       IWL_DEVICE_6005,
+       .ht_params = &iwl6000_ht_params,
+};
+
+const struct iwl_cfg iwl6005_2agn_d_cfg = {
+       .name = "Intel(R) Centrino(R) Advanced-N 6205D AGN",
+       IWL_DEVICE_6005,
+       .ht_params = &iwl6000_ht_params,
+};
+
+const struct iwl_cfg iwl6005_2agn_mow1_cfg = {
+       .name = "Intel(R) Centrino(R) Advanced-N 6206 AGN",
+       IWL_DEVICE_6005,
+       .ht_params = &iwl6000_ht_params,
+};
+
+const struct iwl_cfg iwl6005_2agn_mow2_cfg = {
+       .name = "Intel(R) Centrino(R) Advanced-N 6207 AGN",
+       IWL_DEVICE_6005,
+       .ht_params = &iwl6000_ht_params,
+};
+
+#define IWL_DEVICE_6030                                                \
+       .fw_name_pre = IWL6030_FW_PRE,                          \
+       .ucode_api_max = IWL6000G2_UCODE_API_MAX,               \
+       .ucode_api_ok = IWL6000G2B_UCODE_API_OK,                \
+       .ucode_api_min = IWL6000G2_UCODE_API_MIN,               \
+       .device_family = IWL_DEVICE_FAMILY_6030,                \
+       .max_inst_size = IWL60_RTC_INST_SIZE,                   \
+       .max_data_size = IWL60_RTC_DATA_SIZE,                   \
+       .nvm_ver = EEPROM_6030_EEPROM_VERSION,          \
+       .nvm_calib_ver = EEPROM_6030_TX_POWER_VERSION,  \
+       .base_params = &iwl6000_g2_base_params,                 \
+       .bt_params = &iwl6000_bt_params,                        \
+       .eeprom_params = &iwl6000_eeprom_params,                \
+       .need_temp_offset_calib = true,                         \
+       .led_mode = IWL_LED_RF_STATE,                           \
+       .adv_pm = true                                          \
+
+const struct iwl_cfg iwl6030_2agn_cfg = {
+       .name = "Intel(R) Centrino(R) Advanced-N 6230 AGN",
+       IWL_DEVICE_6030,
+       .ht_params = &iwl6000_ht_params,
+};
+
+const struct iwl_cfg iwl6030_2abg_cfg = {
+       .name = "Intel(R) Centrino(R) Advanced-N 6230 ABG",
+       IWL_DEVICE_6030,
+};
+
+const struct iwl_cfg iwl6030_2bgn_cfg = {
+       .name = "Intel(R) Centrino(R) Advanced-N 6230 BGN",
+       IWL_DEVICE_6030,
+       .ht_params = &iwl6000_ht_params,
+};
+
+const struct iwl_cfg iwl6030_2bg_cfg = {
+       .name = "Intel(R) Centrino(R) Advanced-N 6230 BG",
+       IWL_DEVICE_6030,
+};
+
+#define IWL_DEVICE_6035                                                \
+       .fw_name_pre = IWL6030_FW_PRE,                          \
+       .ucode_api_max = IWL6035_UCODE_API_MAX,                 \
+       .ucode_api_ok = IWL6035_UCODE_API_OK,                   \
+       .ucode_api_min = IWL6035_UCODE_API_MIN,                 \
+       .device_family = IWL_DEVICE_FAMILY_6030,                \
+       .max_inst_size = IWL60_RTC_INST_SIZE,                   \
+       .max_data_size = IWL60_RTC_DATA_SIZE,                   \
+       .nvm_ver = EEPROM_6030_EEPROM_VERSION,          \
+       .nvm_calib_ver = EEPROM_6030_TX_POWER_VERSION,  \
+       .base_params = &iwl6000_g2_base_params,                 \
+       .bt_params = &iwl6000_bt_params,                        \
+       .eeprom_params = &iwl6000_eeprom_params,                \
+       .need_temp_offset_calib = true,                         \
+       .led_mode = IWL_LED_RF_STATE,                           \
+       .adv_pm = true
+
+const struct iwl_cfg iwl6035_2agn_cfg = {
+       .name = "Intel(R) Centrino(R) Advanced-N 6235 AGN",
+       IWL_DEVICE_6035,
+       .ht_params = &iwl6000_ht_params,
+};
+
+const struct iwl_cfg iwl1030_bgn_cfg = {
+       .name = "Intel(R) Centrino(R) Wireless-N 1030 BGN",
+       IWL_DEVICE_6030,
+       .ht_params = &iwl6000_ht_params,
+};
+
+const struct iwl_cfg iwl1030_bg_cfg = {
+       .name = "Intel(R) Centrino(R) Wireless-N 1030 BG",
+       IWL_DEVICE_6030,
+};
+
+const struct iwl_cfg iwl130_bgn_cfg = {
+       .name = "Intel(R) Centrino(R) Wireless-N 130 BGN",
+       IWL_DEVICE_6030,
+       .ht_params = &iwl6000_ht_params,
+       .rx_with_siso_diversity = true,
+};
+
+const struct iwl_cfg iwl130_bg_cfg = {
+       .name = "Intel(R) Centrino(R) Wireless-N 130 BG",
+       IWL_DEVICE_6030,
+       .rx_with_siso_diversity = true,
+};
+
+/*
+ * "i": Internal configuration, use internal Power Amplifier
+ */
+#define IWL_DEVICE_6000i                                       \
+       .fw_name_pre = IWL6000_FW_PRE,                          \
+       .ucode_api_max = IWL6000_UCODE_API_MAX,                 \
+       .ucode_api_ok = IWL6000_UCODE_API_OK,                   \
+       .ucode_api_min = IWL6000_UCODE_API_MIN,                 \
+       .device_family = IWL_DEVICE_FAMILY_6000i,               \
+       .max_inst_size = IWL60_RTC_INST_SIZE,                   \
+       .max_data_size = IWL60_RTC_DATA_SIZE,                   \
+       .valid_tx_ant = ANT_BC,         /* .cfg overwrite */    \
+       .valid_rx_ant = ANT_BC,         /* .cfg overwrite */    \
+       .nvm_ver = EEPROM_6000_EEPROM_VERSION,          \
+       .nvm_calib_ver = EEPROM_6000_TX_POWER_VERSION,  \
+       .base_params = &iwl6000_base_params,                    \
+       .eeprom_params = &iwl6000_eeprom_params,                \
+       .led_mode = IWL_LED_BLINK
+
+const struct iwl_cfg iwl6000i_2agn_cfg = {
+       .name = "Intel(R) Centrino(R) Advanced-N 6200 AGN",
+       IWL_DEVICE_6000i,
+       .ht_params = &iwl6000_ht_params,
+};
+
+const struct iwl_cfg iwl6000i_2abg_cfg = {
+       .name = "Intel(R) Centrino(R) Advanced-N 6200 ABG",
+       IWL_DEVICE_6000i,
+};
+
+const struct iwl_cfg iwl6000i_2bg_cfg = {
+       .name = "Intel(R) Centrino(R) Advanced-N 6200 BG",
+       IWL_DEVICE_6000i,
+};
+
+#define IWL_DEVICE_6050                                                \
+       .fw_name_pre = IWL6050_FW_PRE,                          \
+       .ucode_api_max = IWL6050_UCODE_API_MAX,                 \
+       .ucode_api_min = IWL6050_UCODE_API_MIN,                 \
+       .device_family = IWL_DEVICE_FAMILY_6050,                \
+       .max_inst_size = IWL60_RTC_INST_SIZE,                   \
+       .max_data_size = IWL60_RTC_DATA_SIZE,                   \
+       .valid_tx_ant = ANT_AB,         /* .cfg overwrite */    \
+       .valid_rx_ant = ANT_AB,         /* .cfg overwrite */    \
+       .nvm_ver = EEPROM_6050_EEPROM_VERSION,          \
+       .nvm_calib_ver = EEPROM_6050_TX_POWER_VERSION,  \
+       .base_params = &iwl6050_base_params,                    \
+       .eeprom_params = &iwl6000_eeprom_params,                \
+       .led_mode = IWL_LED_BLINK,                              \
+       .internal_wimax_coex = true
+
+const struct iwl_cfg iwl6050_2agn_cfg = {
+       .name = "Intel(R) Centrino(R) Advanced-N + WiMAX 6250 AGN",
+       IWL_DEVICE_6050,
+       .ht_params = &iwl6000_ht_params,
+};
+
+const struct iwl_cfg iwl6050_2abg_cfg = {
+       .name = "Intel(R) Centrino(R) Advanced-N + WiMAX 6250 ABG",
+       IWL_DEVICE_6050,
+};
+
+#define IWL_DEVICE_6150                                                \
+       .fw_name_pre = IWL6050_FW_PRE,                          \
+       .ucode_api_max = IWL6050_UCODE_API_MAX,                 \
+       .ucode_api_min = IWL6050_UCODE_API_MIN,                 \
+       .device_family = IWL_DEVICE_FAMILY_6150,                \
+       .max_inst_size = IWL60_RTC_INST_SIZE,                   \
+       .max_data_size = IWL60_RTC_DATA_SIZE,                   \
+       .nvm_ver = EEPROM_6150_EEPROM_VERSION,          \
+       .nvm_calib_ver = EEPROM_6150_TX_POWER_VERSION,  \
+       .base_params = &iwl6050_base_params,                    \
+       .eeprom_params = &iwl6000_eeprom_params,                \
+       .led_mode = IWL_LED_BLINK,                              \
+       .internal_wimax_coex = true
+
+const struct iwl_cfg iwl6150_bgn_cfg = {
+       .name = "Intel(R) Centrino(R) Wireless-N + WiMAX 6150 BGN",
+       IWL_DEVICE_6150,
+       .ht_params = &iwl6000_ht_params,
+};
+
+const struct iwl_cfg iwl6150_bg_cfg = {
+       .name = "Intel(R) Centrino(R) Wireless-N + WiMAX 6150 BG",
+       IWL_DEVICE_6150,
+};
+
+const struct iwl_cfg iwl6000_3agn_cfg = {
+       .name = "Intel(R) Centrino(R) Ultimate-N 6300 AGN",
+       .fw_name_pre = IWL6000_FW_PRE,
+       .ucode_api_max = IWL6000_UCODE_API_MAX,
+       .ucode_api_ok = IWL6000_UCODE_API_OK,
+       .ucode_api_min = IWL6000_UCODE_API_MIN,
+       .device_family = IWL_DEVICE_FAMILY_6000,
+       .max_inst_size = IWL60_RTC_INST_SIZE,
+       .max_data_size = IWL60_RTC_DATA_SIZE,
+       .nvm_ver = EEPROM_6000_EEPROM_VERSION,
+       .nvm_calib_ver = EEPROM_6000_TX_POWER_VERSION,
+       .base_params = &iwl6000_base_params,
+       .eeprom_params = &iwl6000_eeprom_params,
+       .ht_params = &iwl6000_ht_params,
+       .led_mode = IWL_LED_BLINK,
+};
+
+MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_OK));
+MODULE_FIRMWARE(IWL6050_MODULE_FIRMWARE(IWL6050_UCODE_API_OK));
+MODULE_FIRMWARE(IWL6005_MODULE_FIRMWARE(IWL6000G2_UCODE_API_OK));
+MODULE_FIRMWARE(IWL6030_MODULE_FIRMWARE(IWL6000G2B_UCODE_API_OK));
diff --git a/drivers/net/wireless/iwlwifi/iwl-7000.c b/drivers/net/wireless/iwlwifi/iwl-7000.c
new file mode 100644 (file)
index 0000000..50263e8
--- /dev/null
@@ -0,0 +1,146 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called COPYING.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+
+#include <linux/module.h>
+#include <linux/stringify.h>
+#include "iwl-config.h"
+#include "iwl-agn-hw.h"
+
+/* Highest firmware API version supported */
+#define IWL7260_UCODE_API_MAX  6
+#define IWL3160_UCODE_API_MAX  6
+
+/* Oldest version we won't warn about */
+#define IWL7260_UCODE_API_OK   6
+#define IWL3160_UCODE_API_OK   6
+
+/* Lowest firmware API version supported */
+#define IWL7260_UCODE_API_MIN  6
+#define IWL3160_UCODE_API_MIN  6
+
+/* NVM versions */
+#define IWL7260_NVM_VERSION            0x0a1d
+#define IWL7260_TX_POWER_VERSION       0xffff /* meaningless */
+#define IWL3160_NVM_VERSION            0x709
+#define IWL3160_TX_POWER_VERSION       0xffff /* meaningless */
+
+#define IWL7260_FW_PRE "iwlwifi-7260-"
+#define IWL7260_MODULE_FIRMWARE(api) IWL7260_FW_PRE __stringify(api) ".ucode"
+
+#define IWL3160_FW_PRE "iwlwifi-3160-"
+#define IWL3160_MODULE_FIRMWARE(api) IWL3160_FW_PRE __stringify(api) ".ucode"
+
+static const struct iwl_base_params iwl7000_base_params = {
+       .eeprom_size = OTP_LOW_IMAGE_SIZE,
+       .num_of_queues = IWLAGN_NUM_QUEUES,
+       .pll_cfg_val = 0,
+       .shadow_ram_support = true,
+       .led_compensation = 57,
+       .adv_thermal_throttle = true,
+       .support_ct_kill_exit = true,
+       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+       .chain_noise_scale = 1000,
+       .wd_timeout = IWL_LONG_WD_TIMEOUT,
+       .max_event_log_size = 512,
+       .shadow_reg_enable = false, /* TODO: fix bugs using this feature */
+};
+
+static const struct iwl_ht_params iwl7000_ht_params = {
+       .use_rts_for_aggregation = true, /* use rts/cts protection */
+       .ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ),
+};
+
+#define IWL_DEVICE_7000                                                \
+       .ucode_api_max = IWL7260_UCODE_API_MAX,                 \
+       .ucode_api_ok = IWL7260_UCODE_API_OK,                   \
+       .ucode_api_min = IWL7260_UCODE_API_MIN,                 \
+       .device_family = IWL_DEVICE_FAMILY_7000,                \
+       .max_inst_size = IWL60_RTC_INST_SIZE,                   \
+       .max_data_size = IWL60_RTC_DATA_SIZE,                   \
+       .base_params = &iwl7000_base_params,                    \
+       /* TODO: .bt_params? */                                 \
+       .need_temp_offset_calib = true,                         \
+       .led_mode = IWL_LED_RF_STATE,                           \
+       .adv_pm = true                                          \
+
+
+const struct iwl_cfg iwl7260_2ac_cfg = {
+       .name = "Intel(R) Dual Band Wireless AC7260",
+       .fw_name_pre = IWL7260_FW_PRE,
+       IWL_DEVICE_7000,
+       .ht_params = &iwl7000_ht_params,
+       .nvm_ver = IWL7260_NVM_VERSION,
+       .nvm_calib_ver = IWL7260_TX_POWER_VERSION,
+};
+
+const struct iwl_cfg iwl3160_ac_cfg = {
+       .name = "Intel(R) Dual Band Wireless AC3160",
+       .fw_name_pre = IWL3160_FW_PRE,
+       IWL_DEVICE_7000,
+       .ht_params = &iwl7000_ht_params,
+       .nvm_ver = IWL3160_NVM_VERSION,
+       .nvm_calib_ver = IWL3160_TX_POWER_VERSION,
+};
+
+MODULE_FIRMWARE(IWL7260_MODULE_FIRMWARE(IWL7260_UCODE_API_OK));
+MODULE_FIRMWARE(IWL3160_MODULE_FIRMWARE(IWL3160_UCODE_API_OK));
index e9975c5..6d73f94 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
index 743b483..c38aa8f 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
@@ -275,4 +275,51 @@ struct iwl_cfg {
        const bool temp_offset_v2;
 };
 
+/*
+ * This list declares the config structures for all devices.
+ */
+extern const struct iwl_cfg iwl5300_agn_cfg;
+extern const struct iwl_cfg iwl5100_agn_cfg;
+extern const struct iwl_cfg iwl5350_agn_cfg;
+extern const struct iwl_cfg iwl5100_bgn_cfg;
+extern const struct iwl_cfg iwl5100_abg_cfg;
+extern const struct iwl_cfg iwl5150_agn_cfg;
+extern const struct iwl_cfg iwl5150_abg_cfg;
+extern const struct iwl_cfg iwl6005_2agn_cfg;
+extern const struct iwl_cfg iwl6005_2abg_cfg;
+extern const struct iwl_cfg iwl6005_2bg_cfg;
+extern const struct iwl_cfg iwl6005_2agn_sff_cfg;
+extern const struct iwl_cfg iwl6005_2agn_d_cfg;
+extern const struct iwl_cfg iwl6005_2agn_mow1_cfg;
+extern const struct iwl_cfg iwl6005_2agn_mow2_cfg;
+extern const struct iwl_cfg iwl1030_bgn_cfg;
+extern const struct iwl_cfg iwl1030_bg_cfg;
+extern const struct iwl_cfg iwl6030_2agn_cfg;
+extern const struct iwl_cfg iwl6030_2abg_cfg;
+extern const struct iwl_cfg iwl6030_2bgn_cfg;
+extern const struct iwl_cfg iwl6030_2bg_cfg;
+extern const struct iwl_cfg iwl6000i_2agn_cfg;
+extern const struct iwl_cfg iwl6000i_2abg_cfg;
+extern const struct iwl_cfg iwl6000i_2bg_cfg;
+extern const struct iwl_cfg iwl6000_3agn_cfg;
+extern const struct iwl_cfg iwl6050_2agn_cfg;
+extern const struct iwl_cfg iwl6050_2abg_cfg;
+extern const struct iwl_cfg iwl6150_bgn_cfg;
+extern const struct iwl_cfg iwl6150_bg_cfg;
+extern const struct iwl_cfg iwl1000_bgn_cfg;
+extern const struct iwl_cfg iwl1000_bg_cfg;
+extern const struct iwl_cfg iwl100_bgn_cfg;
+extern const struct iwl_cfg iwl100_bg_cfg;
+extern const struct iwl_cfg iwl130_bgn_cfg;
+extern const struct iwl_cfg iwl130_bg_cfg;
+extern const struct iwl_cfg iwl2000_2bgn_cfg;
+extern const struct iwl_cfg iwl2000_2bgn_d_cfg;
+extern const struct iwl_cfg iwl2030_2bgn_cfg;
+extern const struct iwl_cfg iwl6035_2agn_cfg;
+extern const struct iwl_cfg iwl105_bgn_cfg;
+extern const struct iwl_cfg iwl105_bgn_d_cfg;
+extern const struct iwl_cfg iwl135_bgn_cfg;
+extern const struct iwl_cfg iwl7260_2ac_cfg;
+extern const struct iwl_cfg iwl3160_ac_cfg;
+
 #endif /* __IWL_CONFIG_H__ */
index df3463a..20e845d 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
index 87535a6..8a44f59 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
@@ -66,6 +66,7 @@
 #include <linux/device.h>
 #include <linux/interrupt.h>
 #include <linux/export.h>
+#include "iwl-drv.h"
 #include "iwl-debug.h"
 #include "iwl-devtrace.h"
 
@@ -85,11 +86,11 @@ void __iwl_ ##fn(struct device *dev, const char *fmt, ...)  \
 }
 
 __iwl_fn(warn)
-EXPORT_SYMBOL_GPL(__iwl_warn);
+IWL_EXPORT_SYMBOL(__iwl_warn);
 __iwl_fn(info)
-EXPORT_SYMBOL_GPL(__iwl_info);
+IWL_EXPORT_SYMBOL(__iwl_info);
 __iwl_fn(crit)
-EXPORT_SYMBOL_GPL(__iwl_crit);
+IWL_EXPORT_SYMBOL(__iwl_crit);
 
 void __iwl_err(struct device *dev, bool rfkill_prefix, bool trace_only,
                const char *fmt, ...)
@@ -110,7 +111,7 @@ void __iwl_err(struct device *dev, bool rfkill_prefix, bool trace_only,
        trace_iwlwifi_err(&vaf);
        va_end(args);
 }
-EXPORT_SYMBOL_GPL(__iwl_err);
+IWL_EXPORT_SYMBOL(__iwl_err);
 
 #if defined(CONFIG_IWLWIFI_DEBUG) || defined(CONFIG_IWLWIFI_DEVICE_TRACING)
 void __iwl_dbg(struct device *dev,
@@ -133,5 +134,5 @@ void __iwl_dbg(struct device *dev,
        trace_iwlwifi_dbg(level, in_interrupt(), function, &vaf);
        va_end(args);
 }
-EXPORT_SYMBOL_GPL(__iwl_dbg);
+IWL_EXPORT_SYMBOL(__iwl_dbg);
 #endif
index 81aa91f..4491c1c 100644 (file)
@@ -298,7 +298,7 @@ TRACE_EVENT(iwlwifi_dbg,
                                       MAX_MSG_LEN, vaf->fmt,
                                       *vaf->va) >= MAX_MSG_LEN);
        ),
-       TP_printk("%s", (char *)__get_dynamic_array(msg))
+       TP_printk("%s", __get_str(msg))
 );
 
 #undef TRACE_SYSTEM
index fbfd2d1..3ce4e9d 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
@@ -1102,7 +1102,7 @@ void iwl_drv_stop(struct iwl_drv *drv)
 
 /* shared module parameters */
 struct iwl_mod_params iwlwifi_mod_params = {
-       .restart_fw = 1,
+       .restart_fw = true,
        .plcp_check = true,
        .bt_coex_active = true,
        .power_level = IWL_POWER_INDEX_1,
@@ -1111,7 +1111,7 @@ struct iwl_mod_params iwlwifi_mod_params = {
        .wd_disable = true,
        /* the rest are 0 by default */
 };
-EXPORT_SYMBOL_GPL(iwlwifi_mod_params);
+IWL_EXPORT_SYMBOL(iwlwifi_mod_params);
 
 int iwl_opmode_register(const char *name, const struct iwl_op_mode_ops *ops)
 {
@@ -1135,7 +1135,7 @@ int iwl_opmode_register(const char *name, const struct iwl_op_mode_ops *ops)
        mutex_unlock(&iwlwifi_opmode_table_mtx);
        return -EIO;
 }
-EXPORT_SYMBOL_GPL(iwl_opmode_register);
+IWL_EXPORT_SYMBOL(iwl_opmode_register);
 
 void iwl_opmode_deregister(const char *name)
 {
@@ -1157,7 +1157,7 @@ void iwl_opmode_deregister(const char *name)
        }
        mutex_unlock(&iwlwifi_opmode_table_mtx);
 }
-EXPORT_SYMBOL_GPL(iwl_opmode_deregister);
+IWL_EXPORT_SYMBOL(iwl_opmode_deregister);
 
 static int __init iwl_drv_init(void)
 {
@@ -1207,8 +1207,8 @@ MODULE_PARM_DESC(11n_disable,
 module_param_named(amsdu_size_8K, iwlwifi_mod_params.amsdu_size_8K,
                   int, S_IRUGO);
 MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size (default 0)");
-module_param_named(fw_restart, iwlwifi_mod_params.restart_fw, int, S_IRUGO);
-MODULE_PARM_DESC(fw_restart, "restart firmware in case of error");
+module_param_named(fw_restart, iwlwifi_mod_params.restart_fw, bool, S_IRUGO);
+MODULE_PARM_DESC(fw_restart, "restart firmware in case of error (default true)");
 
 module_param_named(antenna_coupling, iwlwifi_mod_params.ant_coupling,
                   int, S_IRUGO);
index 594a5c7..7d14509 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
@@ -63,6 +63,8 @@
 #ifndef __iwl_drv_h__
 #define __iwl_drv_h__
 
+#include <linux/module.h>
+
 /* for all modules */
 #define DRV_NAME        "iwlwifi"
 #define IWLWIFI_VERSION "in-tree:"
@@ -123,4 +125,17 @@ struct iwl_drv *iwl_drv_start(struct iwl_trans *trans,
  */
 void iwl_drv_stop(struct iwl_drv *drv);
 
+/*
+ * exported symbol management
+ *
+ * The driver can be split into multiple modules, in which case some symbols
+ * must be exported for the sub-modules. However, if it's not split and
+ * everything is built-in, then we can avoid that.
+ */
+#ifdef CONFIG_IWLWIFI_OPMODE_MODULAR
+#define IWL_EXPORT_SYMBOL(sym) EXPORT_SYMBOL_GPL(sym)
+#else
+#define IWL_EXPORT_SYMBOL(sym)
+#endif
+
 #endif /* __iwl_drv_h__ */
index 034f2ff..600c9fd 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
@@ -62,6 +62,7 @@
 #include <linux/types.h>
 #include <linux/slab.h>
 #include <linux/export.h>
+#include "iwl-drv.h"
 #include "iwl-modparams.h"
 #include "iwl-eeprom-parse.h"
 
@@ -749,7 +750,7 @@ void iwl_init_ht_hw_capab(const struct iwl_cfg *cfg,
        }
 
        ht_info->ht_supported = true;
-       ht_info->cap = 0;
+       ht_info->cap = IEEE80211_HT_CAP_DSSSCCK40;
 
        if (iwlwifi_mod_params.amsdu_size_8K)
                ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU;
@@ -909,7 +910,7 @@ iwl_parse_eeprom_data(struct device *dev, const struct iwl_cfg *cfg,
        kfree(data);
        return NULL;
 }
-EXPORT_SYMBOL_GPL(iwl_parse_eeprom_data);
+IWL_EXPORT_SYMBOL(iwl_parse_eeprom_data);
 
 /* helper functions */
 int iwl_nvm_check_version(struct iwl_nvm_data *data,
@@ -928,4 +929,4 @@ int iwl_nvm_check_version(struct iwl_nvm_data *data,
                data->calib_version,  trans->cfg->nvm_calib_ver);
        return -EINVAL;
 }
-EXPORT_SYMBOL_GPL(iwl_nvm_check_version);
+IWL_EXPORT_SYMBOL(iwl_nvm_check_version);
index 683fe6a..37f1153 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
index ef4806f..e5f2e36 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
@@ -63,6 +63,7 @@
 #include <linux/slab.h>
 #include <linux/export.h>
 
+#include "iwl-drv.h"
 #include "iwl-debug.h"
 #include "iwl-eeprom-read.h"
 #include "iwl-io.h"
@@ -460,4 +461,4 @@ int iwl_read_eeprom(struct iwl_trans *trans, u8 **eeprom, size_t *eeprom_size)
 
        return ret;
 }
-EXPORT_SYMBOL_GPL(iwl_read_eeprom);
+IWL_EXPORT_SYMBOL(iwl_read_eeprom);
index b2588c5..8e941f8 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
index f5592fb..484d318 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
index 90873ec..8b6c6fd 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
index b545178..4356185 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
  *     treats good CRC threshold as a boolean
  * @IWL_UCODE_TLV_FLAGS_MFP: This uCode image supports MFP (802.11w).
  * @IWL_UCODE_TLV_FLAGS_P2P: This uCode image supports P2P.
+ * @IWL_UCODE_TLV_FLAGS_DW_BC_TABLE: The SCD byte count table is in DWORDS
  */
 enum iwl_ucode_tlv_flag {
        IWL_UCODE_TLV_FLAGS_PAN         = BIT(0),
        IWL_UCODE_TLV_FLAGS_NEWSCAN     = BIT(1),
        IWL_UCODE_TLV_FLAGS_MFP         = BIT(2),
        IWL_UCODE_TLV_FLAGS_P2P         = BIT(3),
+       IWL_UCODE_TLV_FLAGS_DW_BC_TABLE = BIT(4),
 };
 
 /* The default calibrate table size if not specified by firmware file */
index 276410d..305c81f 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/device.h>
 #include <linux/export.h>
 
+#include "iwl-drv.h"
 #include "iwl-io.h"
 #include "iwl-csr.h"
 #include "iwl-debug.h"
@@ -49,7 +50,7 @@ int iwl_poll_bit(struct iwl_trans *trans, u32 addr,
 
        return -ETIMEDOUT;
 }
-EXPORT_SYMBOL_GPL(iwl_poll_bit);
+IWL_EXPORT_SYMBOL(iwl_poll_bit);
 
 u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg)
 {
@@ -62,7 +63,7 @@ u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg)
 
        return value;
 }
-EXPORT_SYMBOL_GPL(iwl_read_direct32);
+IWL_EXPORT_SYMBOL(iwl_read_direct32);
 
 void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value)
 {
@@ -73,7 +74,7 @@ void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value)
                iwl_trans_release_nic_access(trans, &flags);
        }
 }
-EXPORT_SYMBOL_GPL(iwl_write_direct32);
+IWL_EXPORT_SYMBOL(iwl_write_direct32);
 
 int iwl_poll_direct_bit(struct iwl_trans *trans, u32 addr, u32 mask,
                        int timeout)
@@ -89,7 +90,7 @@ int iwl_poll_direct_bit(struct iwl_trans *trans, u32 addr, u32 mask,
 
        return -ETIMEDOUT;
 }
-EXPORT_SYMBOL_GPL(iwl_poll_direct_bit);
+IWL_EXPORT_SYMBOL(iwl_poll_direct_bit);
 
 static inline u32 __iwl_read_prph(struct iwl_trans *trans, u32 ofs)
 {
@@ -115,7 +116,7 @@ u32 iwl_read_prph(struct iwl_trans *trans, u32 ofs)
        }
        return val;
 }
-EXPORT_SYMBOL_GPL(iwl_read_prph);
+IWL_EXPORT_SYMBOL(iwl_read_prph);
 
 void iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val)
 {
@@ -126,7 +127,7 @@ void iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val)
                iwl_trans_release_nic_access(trans, &flags);
        }
 }
-EXPORT_SYMBOL_GPL(iwl_write_prph);
+IWL_EXPORT_SYMBOL(iwl_write_prph);
 
 void iwl_set_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask)
 {
@@ -138,7 +139,7 @@ void iwl_set_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask)
                iwl_trans_release_nic_access(trans, &flags);
        }
 }
-EXPORT_SYMBOL_GPL(iwl_set_bits_prph);
+IWL_EXPORT_SYMBOL(iwl_set_bits_prph);
 
 void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 ofs,
                            u32 bits, u32 mask)
@@ -151,7 +152,7 @@ void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 ofs,
                iwl_trans_release_nic_access(trans, &flags);
        }
 }
-EXPORT_SYMBOL_GPL(iwl_set_bits_mask_prph);
+IWL_EXPORT_SYMBOL(iwl_set_bits_mask_prph);
 
 void iwl_clear_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask)
 {
@@ -164,4 +165,4 @@ void iwl_clear_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask)
                iwl_trans_release_nic_access(trans, &flags);
        }
 }
-EXPORT_SYMBOL_GPL(iwl_clear_bits_prph);
+IWL_EXPORT_SYMBOL(iwl_clear_bits_prph);
index 2c2a729..3cc39ff 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
@@ -109,7 +109,7 @@ struct iwl_mod_params {
        int sw_crypto;
        unsigned int disable_11n;
        int amsdu_size_8K;
-       int restart_fw;
+       bool restart_fw;
        bool plcp_check;
        int  wd_disable;
        bool bt_coex_active;
index c3affbc..940b8a9 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
@@ -63,6 +63,7 @@
 #include <linux/sched.h>
 #include <linux/export.h>
 
+#include "iwl-drv.h"
 #include "iwl-notif-wait.h"
 
 
@@ -72,7 +73,7 @@ void iwl_notification_wait_init(struct iwl_notif_wait_data *notif_wait)
        INIT_LIST_HEAD(&notif_wait->notif_waits);
        init_waitqueue_head(&notif_wait->notif_waitq);
 }
-EXPORT_SYMBOL_GPL(iwl_notification_wait_init);
+IWL_EXPORT_SYMBOL(iwl_notification_wait_init);
 
 void iwl_notification_wait_notify(struct iwl_notif_wait_data *notif_wait,
                                  struct iwl_rx_packet *pkt)
@@ -117,7 +118,7 @@ void iwl_notification_wait_notify(struct iwl_notif_wait_data *notif_wait,
        if (triggered)
                wake_up_all(&notif_wait->notif_waitq);
 }
-EXPORT_SYMBOL_GPL(iwl_notification_wait_notify);
+IWL_EXPORT_SYMBOL(iwl_notification_wait_notify);
 
 void iwl_abort_notification_waits(struct iwl_notif_wait_data *notif_wait)
 {
@@ -130,7 +131,7 @@ void iwl_abort_notification_waits(struct iwl_notif_wait_data *notif_wait)
 
        wake_up_all(&notif_wait->notif_waitq);
 }
-EXPORT_SYMBOL_GPL(iwl_abort_notification_waits);
+IWL_EXPORT_SYMBOL(iwl_abort_notification_waits);
 
 void
 iwl_init_notification_wait(struct iwl_notif_wait_data *notif_wait,
@@ -154,7 +155,7 @@ iwl_init_notification_wait(struct iwl_notif_wait_data *notif_wait,
        list_add(&wait_entry->list, &notif_wait->notif_waits);
        spin_unlock_bh(&notif_wait->notif_wait_lock);
 }
-EXPORT_SYMBOL_GPL(iwl_init_notification_wait);
+IWL_EXPORT_SYMBOL(iwl_init_notification_wait);
 
 int iwl_wait_notification(struct iwl_notif_wait_data *notif_wait,
                          struct iwl_notification_wait *wait_entry,
@@ -178,7 +179,7 @@ int iwl_wait_notification(struct iwl_notif_wait_data *notif_wait,
                return -ETIMEDOUT;
        return 0;
 }
-EXPORT_SYMBOL_GPL(iwl_wait_notification);
+IWL_EXPORT_SYMBOL(iwl_wait_notification);
 
 void iwl_remove_notification(struct iwl_notif_wait_data *notif_wait,
                             struct iwl_notification_wait *wait_entry)
@@ -187,4 +188,4 @@ void iwl_remove_notification(struct iwl_notif_wait_data *notif_wait,
        list_del(&wait_entry->list);
        spin_unlock_bh(&notif_wait->notif_wait_lock);
 }
-EXPORT_SYMBOL_GPL(iwl_remove_notification);
+IWL_EXPORT_SYMBOL(iwl_remove_notification);
index c2ce764..2e2f1c8 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
index a70213b..6199a0a 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
@@ -62,6 +62,7 @@
 #include <linux/types.h>
 #include <linux/slab.h>
 #include <linux/export.h>
+#include "iwl-drv.h"
 #include "iwl-modparams.h"
 #include "iwl-nvm-parse.h"
 
@@ -149,6 +150,8 @@ static struct ieee80211_rate iwl_cfg80211_rates[] = {
  * @NVM_CHANNEL_DFS: dynamic freq selection candidate
  * @NVM_CHANNEL_WIDE: 20 MHz channel okay (?)
  * @NVM_CHANNEL_40MHZ: 40 MHz channel okay (?)
+ * @NVM_CHANNEL_80MHZ: 80 MHz channel okay (?)
+ * @NVM_CHANNEL_160MHZ: 160 MHz channel okay (?)
  */
 enum iwl_nvm_channel_flags {
        NVM_CHANNEL_VALID = BIT(0),
@@ -158,6 +161,8 @@ enum iwl_nvm_channel_flags {
        NVM_CHANNEL_DFS = BIT(7),
        NVM_CHANNEL_WIDE = BIT(8),
        NVM_CHANNEL_40MHZ = BIT(9),
+       NVM_CHANNEL_80MHZ = BIT(10),
+       NVM_CHANNEL_160MHZ = BIT(11),
 };
 
 #define CHECK_AND_PRINT_I(x)   \
@@ -210,6 +215,10 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
                        else
                                channel->flags &= ~IEEE80211_CHAN_NO_HT40MINUS;
                }
+               if (!(ch_flags & NVM_CHANNEL_80MHZ))
+                       channel->flags |= IEEE80211_CHAN_NO_80MHZ;
+               if (!(ch_flags & NVM_CHANNEL_160MHZ))
+                       channel->flags |= IEEE80211_CHAN_NO_160MHZ;
 
                if (!(ch_flags & NVM_CHANNEL_IBSS))
                        channel->flags |= IEEE80211_CHAN_NO_IBSS;
@@ -245,6 +254,43 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
        return n_channels;
 }
 
+static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
+                                 struct iwl_nvm_data *data,
+                                 struct ieee80211_sta_vht_cap *vht_cap)
+{
+       /* For now, assume new devices with NVM are VHT capable */
+
+       vht_cap->vht_supported = true;
+
+       vht_cap->cap = IEEE80211_VHT_CAP_SHORT_GI_80 |
+                      IEEE80211_VHT_CAP_RXSTBC_1 |
+                      IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
+                      7 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT;
+
+       if (iwlwifi_mod_params.amsdu_size_8K)
+               vht_cap->cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991;
+
+       vht_cap->vht_mcs.rx_mcs_map =
+               cpu_to_le16(IEEE80211_VHT_MCS_SUPPORT_0_9 << 0 |
+                           IEEE80211_VHT_MCS_SUPPORT_0_9 << 2 |
+                           IEEE80211_VHT_MCS_NOT_SUPPORTED << 4 |
+                           IEEE80211_VHT_MCS_NOT_SUPPORTED << 6 |
+                           IEEE80211_VHT_MCS_NOT_SUPPORTED << 8 |
+                           IEEE80211_VHT_MCS_NOT_SUPPORTED << 10 |
+                           IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 |
+                           IEEE80211_VHT_MCS_NOT_SUPPORTED << 14);
+
+       if (data->valid_rx_ant == 1 || cfg->rx_with_siso_diversity) {
+               vht_cap->cap |= IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN |
+                               IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN;
+               /* this works because NOT_SUPPORTED == 3 */
+               vht_cap->vht_mcs.rx_mcs_map |=
+                       cpu_to_le16(IEEE80211_VHT_MCS_NOT_SUPPORTED << 2);
+       }
+
+       vht_cap->vht_mcs.tx_mcs_map = vht_cap->vht_mcs.rx_mcs_map;
+}
+
 static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
                            struct iwl_nvm_data *data, const __le16 *nvm_sw)
 {
@@ -268,6 +314,7 @@ static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
        n_used += iwl_init_sband_channels(data, sband, n_channels,
                                          IEEE80211_BAND_5GHZ);
        iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, IEEE80211_BAND_5GHZ);
+       iwl_init_vht_hw_capab(cfg, data, &sband->vht_cap);
 
        if (n_channels != n_used)
                IWL_ERR_DEV(dev, "NVM: used only %d of %d channels\n",
@@ -343,4 +390,4 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
 
        return data;
 }
-EXPORT_SYMBOL_GPL(iwl_parse_nvm_data);
+IWL_EXPORT_SYMBOL(iwl_parse_nvm_data);
index b2692bd..e57fb98 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
index 4a68001..98c7aa7 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
index 3392011..25745da 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
@@ -65,6 +65,7 @@
 #include <linux/string.h>
 #include <linux/export.h>
 
+#include "iwl-drv.h"
 #include "iwl-phy-db.h"
 #include "iwl-debug.h"
 #include "iwl-op-mode.h"
@@ -149,7 +150,7 @@ struct iwl_phy_db *iwl_phy_db_init(struct iwl_trans *trans)
        /* TODO: add default values of the phy db. */
        return phy_db;
 }
-EXPORT_SYMBOL(iwl_phy_db_init);
+IWL_EXPORT_SYMBOL(iwl_phy_db_init);
 
 /*
  * get phy db section: returns a pointer to a phy db section specified by
@@ -215,7 +216,7 @@ void iwl_phy_db_free(struct iwl_phy_db *phy_db)
 
        kfree(phy_db);
 }
-EXPORT_SYMBOL(iwl_phy_db_free);
+IWL_EXPORT_SYMBOL(iwl_phy_db_free);
 
 int iwl_phy_db_set_section(struct iwl_phy_db *phy_db, struct iwl_rx_packet *pkt,
                           gfp_t alloc_ctx)
@@ -260,7 +261,7 @@ int iwl_phy_db_set_section(struct iwl_phy_db *phy_db, struct iwl_rx_packet *pkt,
 
        return 0;
 }
-EXPORT_SYMBOL(iwl_phy_db_set_section);
+IWL_EXPORT_SYMBOL(iwl_phy_db_set_section);
 
 static int is_valid_channel(u16 ch_id)
 {
@@ -495,4 +496,4 @@ int iwl_send_phy_db_data(struct iwl_phy_db *phy_db)
                       "Finished sending phy db non channel data\n");
        return 0;
 }
-EXPORT_SYMBOL(iwl_send_phy_db_data);
+IWL_EXPORT_SYMBOL(iwl_send_phy_db_data);
index d0e43d9..ce983af 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
index f76e9ca..386f2a7 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
index ce0c67b..efff298 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
@@ -64,6 +64,7 @@
 #include <linux/export.h>
 #include <net/netlink.h>
 
+#include "iwl-drv.h"
 #include "iwl-io.h"
 #include "iwl-fh.h"
 #include "iwl-prph.h"
@@ -653,7 +654,7 @@ int iwl_test_parse(struct iwl_test *tst, struct nlattr **tb,
        }
        return 0;
 }
-EXPORT_SYMBOL_GPL(iwl_test_parse);
+IWL_EXPORT_SYMBOL(iwl_test_parse);
 
 /*
  * Handle test commands.
@@ -715,7 +716,7 @@ int iwl_test_handle_cmd(struct iwl_test *tst, struct nlattr **tb)
        }
        return result;
 }
-EXPORT_SYMBOL_GPL(iwl_test_handle_cmd);
+IWL_EXPORT_SYMBOL(iwl_test_handle_cmd);
 
 static int iwl_test_trace_dump(struct iwl_test *tst, struct sk_buff *skb,
                               struct netlink_callback *cb)
@@ -803,7 +804,7 @@ int iwl_test_dump(struct iwl_test *tst, u32 cmd, struct sk_buff *skb,
        }
        return result;
 }
-EXPORT_SYMBOL_GPL(iwl_test_dump);
+IWL_EXPORT_SYMBOL(iwl_test_dump);
 
 /*
  * Multicast a spontaneous messages from the device to the user space.
@@ -849,4 +850,4 @@ void iwl_test_rx(struct iwl_test *tst, struct iwl_rx_cmd_buffer *rxb)
        if (tst->notify)
                iwl_test_send_rx(tst, rxb);
 }
-EXPORT_SYMBOL_GPL(iwl_test_rx);
+IWL_EXPORT_SYMBOL(iwl_test_rx);
index 7fbf4d7..8fbd217 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
index a963f45..98f48a9 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
index 0cac2b7..7f9c254 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
  * completely agnostic to these differences.
  * The transport does provide helper functionnality (i.e. SYNC / ASYNC mode),
  */
-#define SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4)
-#define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ)
-#define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4)
 #define SEQ_TO_QUEUE(s)        (((s) >> 8) & 0x1f)
 #define QUEUE_TO_SEQ(q)        (((q) & 0x1f) << 8)
 #define SEQ_TO_INDEX(s)        ((s) & 0xff)
index 807b250..2acc44b 100644 (file)
@@ -2,7 +2,7 @@ obj-$(CONFIG_IWLMVM)   += iwlmvm.o
 iwlmvm-y += fw.o mac80211.o nvm.o ops.o phy-ctxt.o mac-ctxt.o
 iwlmvm-y += utils.o rx.o tx.o binding.o quota.o sta.o
 iwlmvm-y += scan.o time-event.o rs.o
-iwlmvm-y += power.o
+iwlmvm-y += power.o bt-coex.o
 iwlmvm-y += led.o
 iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o
 iwlmvm-$(CONFIG_PM_SLEEP) += d3.o
index 73d24aa..93fd145 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
diff --git a/drivers/net/wireless/iwlwifi/mvm/bt-coex.c b/drivers/net/wireless/iwlwifi/mvm/bt-coex.c
new file mode 100644 (file)
index 0000000..47954de
--- /dev/null
@@ -0,0 +1,347 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2013 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called COPYING.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2013 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+
+#include "fw-api-bt-coex.h"
+#include "iwl-modparams.h"
+#include "mvm.h"
+#include "iwl-debug.h"
+
+#define EVENT_PRIO_ANT(_evt, _prio, _shrd_ant)                 \
+       [(_evt)] = (((_prio) << BT_COEX_PRIO_TBL_PRIO_POS) |    \
+                  ((_shrd_ant) << BT_COEX_PRIO_TBL_SHRD_ANT_POS))
+
+static const u8 iwl_bt_prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX] = {
+       EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_INIT_CALIB1,
+                      BT_COEX_PRIO_TBL_PRIO_BYPASS, 0),
+       EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_INIT_CALIB2,
+                      BT_COEX_PRIO_TBL_PRIO_BYPASS, 1),
+       EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_LOW1,
+                      BT_COEX_PRIO_TBL_PRIO_LOW, 0),
+       EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_LOW2,
+                      BT_COEX_PRIO_TBL_PRIO_LOW, 1),
+       EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_HIGH1,
+                      BT_COEX_PRIO_TBL_PRIO_HIGH, 0),
+       EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_HIGH2,
+                      BT_COEX_PRIO_TBL_PRIO_HIGH, 1),
+       EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_DTIM,
+                      BT_COEX_PRIO_TBL_DISABLED, 0),
+       EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_SCAN52,
+                      BT_COEX_PRIO_TBL_PRIO_COEX_OFF, 0),
+       EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_SCAN24,
+                      BT_COEX_PRIO_TBL_PRIO_COEX_ON, 0),
+       EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_IDLE,
+                      BT_COEX_PRIO_TBL_PRIO_COEX_IDLE, 0),
+       0, 0, 0, 0, 0, 0,
+};
+
+#undef EVENT_PRIO_ANT
+
+int iwl_send_bt_prio_tbl(struct iwl_mvm *mvm)
+{
+       return iwl_mvm_send_cmd_pdu(mvm, BT_COEX_PRIO_TABLE, CMD_SYNC,
+                                   sizeof(struct iwl_bt_coex_prio_tbl_cmd),
+                                   &iwl_bt_prio_tbl);
+}
+
+static int iwl_send_bt_env(struct iwl_mvm *mvm, u8 action, u8 type)
+{
+       struct iwl_bt_coex_prot_env_cmd env_cmd;
+       int ret;
+
+       env_cmd.action = action;
+       env_cmd.type = type;
+       ret = iwl_mvm_send_cmd_pdu(mvm, BT_COEX_PROT_ENV, CMD_SYNC,
+                                  sizeof(env_cmd), &env_cmd);
+       if (ret)
+               IWL_ERR(mvm, "failed to send BT env command\n");
+       return ret;
+}
+
+enum iwl_bt_kill_msk {
+       BT_KILL_MSK_DEFAULT,
+       BT_KILL_MSK_SCO_HID_A2DP,
+       BT_KILL_MSK_REDUCED_TXPOW,
+       BT_KILL_MSK_MAX,
+};
+
+static const u32 iwl_bt_ack_kill_msk[BT_KILL_MSK_MAX] = {
+       0xffffffff,
+       0xfffffc00,
+       0,
+};
+
+static const u32 iwl_bt_cts_kill_msk[BT_KILL_MSK_MAX] = {
+       0xffffffff,
+       0xfffffc00,
+       0,
+};
+
+#define IWL_BT_DEFAULT_BOOST (0xf0f0f0f0)
+
+/* Tight Coex */
+static const __le32 iwl_tight_lookup[BT_COEX_LUT_SIZE] = {
+       cpu_to_le32(0xaaaaaaaa),
+       cpu_to_le32(0xaaaaaaaa),
+       cpu_to_le32(0xaeaaaaaa),
+       cpu_to_le32(0xaaaaaaaa),
+       cpu_to_le32(0xcc00ff28),
+       cpu_to_le32(0x0000aaaa),
+       cpu_to_le32(0xcc00aaaa),
+       cpu_to_le32(0x0000aaaa),
+       cpu_to_le32(0xc0004000),
+       cpu_to_le32(0x00000000),
+       cpu_to_le32(0xf0005000),
+       cpu_to_le32(0xf0005000),
+};
+
+/* Loose Coex */
+static const __le32 iwl_loose_lookup[BT_COEX_LUT_SIZE] = {
+       cpu_to_le32(0xaaaaaaaa),
+       cpu_to_le32(0xaaaaaaaa),
+       cpu_to_le32(0xaeaaaaaa),
+       cpu_to_le32(0xaaaaaaaa),
+       cpu_to_le32(0xcc00ff28),
+       cpu_to_le32(0x0000aaaa),
+       cpu_to_le32(0xcc00aaaa),
+       cpu_to_le32(0x0000aaaa),
+       cpu_to_le32(0x00000000),
+       cpu_to_le32(0x00000000),
+       cpu_to_le32(0xf0005000),
+       cpu_to_le32(0xf0005000),
+};
+
+/* Full concurrency */
+static const __le32 iwl_concurrent_lookup[BT_COEX_LUT_SIZE] = {
+       cpu_to_le32(0xaaaaaaaa),
+       cpu_to_le32(0xaaaaaaaa),
+       cpu_to_le32(0xaaaaaaaa),
+       cpu_to_le32(0xaaaaaaaa),
+       cpu_to_le32(0xaaaaaaaa),
+       cpu_to_le32(0xaaaaaaaa),
+       cpu_to_le32(0xaaaaaaaa),
+       cpu_to_le32(0xaaaaaaaa),
+       cpu_to_le32(0x00000000),
+       cpu_to_le32(0x00000000),
+       cpu_to_le32(0x00000000),
+       cpu_to_le32(0x00000000),
+};
+
+/* BT Antenna Coupling Threshold (dB) */
+#define IWL_BT_ANTENNA_COUPLING_THRESHOLD      (35)
+
+int iwl_send_bt_init_conf(struct iwl_mvm *mvm)
+{
+       struct iwl_bt_coex_cmd cmd = {
+               .max_kill = 5,
+               .bt3_time_t7_value = 1,
+               .bt3_prio_sample_time = 2,
+               .bt3_timer_t2_value = 0xc,
+       };
+       int ret;
+
+       cmd.flags = iwlwifi_mod_params.bt_coex_active ?
+                       BT_COEX_NW : BT_COEX_DISABLE;
+       cmd.flags |= iwlwifi_mod_params.bt_ch_announce ?
+                       BT_CH_PRIMARY_EN | BT_CH_SECONDARY_EN : 0;
+       cmd.flags |= BT_SYNC_2_BT_DISABLE;
+
+       cmd.valid_bit_msk = cpu_to_le16(BT_VALID_ENABLE |
+                                       BT_VALID_BT_PRIO_BOOST |
+                                       BT_VALID_MAX_KILL |
+                                       BT_VALID_3W_TMRS |
+                                       BT_VALID_KILL_ACK |
+                                       BT_VALID_KILL_CTS |
+                                       BT_VALID_REDUCED_TX_POWER |
+                                       BT_VALID_LUT);
+
+       if (iwlwifi_mod_params.ant_coupling > IWL_BT_ANTENNA_COUPLING_THRESHOLD)
+               memcpy(&cmd.decision_lut, iwl_loose_lookup,
+                      sizeof(iwl_tight_lookup));
+       else
+               memcpy(&cmd.decision_lut, iwl_tight_lookup,
+                      sizeof(iwl_tight_lookup));
+
+       cmd.bt_prio_boost = cpu_to_le32(IWL_BT_DEFAULT_BOOST);
+       cmd.kill_ack_msk =
+               cpu_to_le32(iwl_bt_ack_kill_msk[BT_KILL_MSK_DEFAULT]);
+       cmd.kill_cts_msk =
+               cpu_to_le32(iwl_bt_cts_kill_msk[BT_KILL_MSK_DEFAULT]);
+
+       /* go to CALIB state in internal BT-Coex state machine */
+       ret = iwl_send_bt_env(mvm, BT_COEX_ENV_OPEN,
+                             BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
+       if (ret)
+               return ret;
+
+       ret  = iwl_send_bt_env(mvm, BT_COEX_ENV_CLOSE,
+                              BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
+       if (ret)
+               return ret;
+
+       return iwl_mvm_send_cmd_pdu(mvm, BT_CONFIG, CMD_SYNC,
+                                   sizeof(cmd), &cmd);
+}
+
+struct iwl_bt_notif_iterator_data {
+       struct iwl_mvm *mvm;
+       struct iwl_bt_coex_profile_notif *notif;
+};
+
+static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
+                                     struct ieee80211_vif *vif)
+{
+       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+       struct iwl_bt_notif_iterator_data *data = _data;
+       struct ieee80211_chanctx_conf *chanctx_conf;
+       enum ieee80211_smps_mode smps_mode;
+       enum ieee80211_band band;
+
+       if (vif->type != NL80211_IFTYPE_STATION)
+               return;
+
+       rcu_read_lock();
+       chanctx_conf = rcu_dereference(vif->chanctx_conf);
+       if (chanctx_conf && chanctx_conf->def.chan)
+               band = chanctx_conf->def.chan->band;
+       else
+               band = -1;
+       rcu_read_unlock();
+
+       if (band != IEEE80211_BAND_2GHZ)
+               return;
+
+       smps_mode = IEEE80211_SMPS_AUTOMATIC;
+
+       if (data->notif->bt_status)
+               smps_mode = IEEE80211_SMPS_DYNAMIC;
+
+       if (data->notif->bt_traffic_load)
+               smps_mode = IEEE80211_SMPS_STATIC;
+
+       IWL_DEBUG_COEX(data->mvm,
+                      "mac %d: bt_status %d traffic_load %d smps_req %d\n",
+                      mvmvif->id,  data->notif->bt_status,
+                      data->notif->bt_traffic_load, smps_mode);
+
+       ieee80211_request_smps(vif, smps_mode);
+}
+
+int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm,
+                            struct iwl_rx_cmd_buffer *rxb,
+                            struct iwl_device_cmd *dev_cmd)
+{
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       struct iwl_bt_coex_profile_notif *notif = (void *)pkt->data;
+       struct iwl_bt_notif_iterator_data data = {
+               .mvm = mvm,
+               .notif = notif,
+       };
+       struct iwl_bt_coex_cmd cmd = {};
+       enum iwl_bt_kill_msk bt_kill_msk;
+
+       IWL_DEBUG_COEX(mvm, "BT Coex Notification received\n");
+       IWL_DEBUG_COEX(mvm, "\tBT %salive\n", notif->bt_status ? "" : "not ");
+       IWL_DEBUG_COEX(mvm, "\tBT open conn %d\n", notif->bt_open_conn);
+       IWL_DEBUG_COEX(mvm, "\tBT traffic load %d\n", notif->bt_traffic_load);
+       IWL_DEBUG_COEX(mvm, "\tBT agg traffic load %d\n",
+                      notif->bt_agg_traffic_load);
+       IWL_DEBUG_COEX(mvm, "\tBT ci compliance %d\n", notif->bt_ci_compliance);
+
+       /* remember this notification for future use: rssi fluctuations */
+       memcpy(&mvm->last_bt_notif, notif, sizeof(mvm->last_bt_notif));
+
+       ieee80211_iterate_active_interfaces_atomic(
+                                       mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
+                                       iwl_mvm_bt_notif_iterator, &data);
+
+       /* Low latency BT profile is active: give higher prio to BT */
+       if (BT_MBOX_MSG(notif, 3, SCO_STATE)  ||
+           BT_MBOX_MSG(notif, 3, A2DP_STATE) ||
+           BT_MBOX_MSG(notif, 3, SNIFF_STATE))
+               bt_kill_msk = BT_KILL_MSK_SCO_HID_A2DP;
+       else
+               bt_kill_msk = BT_KILL_MSK_DEFAULT;
+
+       /* Don't send HCMD if there is no update */
+       if (bt_kill_msk == mvm->bt_kill_msk)
+               return 0;
+
+       IWL_DEBUG_COEX(mvm,
+                      "Udpate kill_msk: %d\n\t SCO %sactive A2DP %sactive SNIFF %sactive\n",
+                      bt_kill_msk,
+                      BT_MBOX_MSG(notif, 3, SCO_STATE) ? "" : "in",
+                      BT_MBOX_MSG(notif, 3, A2DP_STATE) ? "" : "in",
+                      BT_MBOX_MSG(notif, 3, SNIFF_STATE) ? "" : "in");
+
+       mvm->bt_kill_msk = bt_kill_msk;
+       cmd.kill_ack_msk = cpu_to_le32(iwl_bt_ack_kill_msk[bt_kill_msk]);
+       cmd.kill_cts_msk = cpu_to_le32(iwl_bt_cts_kill_msk[bt_kill_msk]);
+
+       cmd.valid_bit_msk = cpu_to_le16(BT_VALID_KILL_ACK | BT_VALID_KILL_CTS);
+
+       if (iwl_mvm_send_cmd_pdu(mvm, BT_CONFIG, CMD_SYNC, sizeof(cmd), &cmd))
+               IWL_ERR(mvm, "Failed to sent BT Coex CMD\n");
+
+       /* This handler is ASYNC */
+       return 0;
+}
index 994c8c2..d4578ce 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
  *****************************************************************************/
 
 #include <linux/etherdevice.h>
+#include <linux/ip.h>
 #include <net/cfg80211.h>
 #include <net/ipv6.h>
+#include <net/tcp.h>
 #include "iwl-modparams.h"
 #include "fw-api.h"
 #include "mvm.h"
@@ -402,6 +404,233 @@ static int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm,
                                    sizeof(cmd), &cmd);
 }
 
+enum iwl_mvm_tcp_packet_type {
+       MVM_TCP_TX_SYN,
+       MVM_TCP_RX_SYNACK,
+       MVM_TCP_TX_DATA,
+       MVM_TCP_RX_ACK,
+       MVM_TCP_RX_WAKE,
+       MVM_TCP_TX_FIN,
+};
+
+static __le16 pseudo_hdr_check(int len, __be32 saddr, __be32 daddr)
+{
+       __sum16 check = tcp_v4_check(len, saddr, daddr, 0);
+       return cpu_to_le16(be16_to_cpu((__force __be16)check));
+}
+
+static void iwl_mvm_build_tcp_packet(struct iwl_mvm *mvm,
+                                    struct ieee80211_vif *vif,
+                                    struct cfg80211_wowlan_tcp *tcp,
+                                    void *_pkt, u8 *mask,
+                                    __le16 *pseudo_hdr_csum,
+                                    enum iwl_mvm_tcp_packet_type ptype)
+{
+       struct {
+               struct ethhdr eth;
+               struct iphdr ip;
+               struct tcphdr tcp;
+               u8 data[];
+       } __packed *pkt = _pkt;
+       u16 ip_tot_len = sizeof(struct iphdr) + sizeof(struct tcphdr);
+       int i;
+
+       pkt->eth.h_proto = cpu_to_be16(ETH_P_IP),
+       pkt->ip.version = 4;
+       pkt->ip.ihl = 5;
+       pkt->ip.protocol = IPPROTO_TCP;
+
+       switch (ptype) {
+       case MVM_TCP_TX_SYN:
+       case MVM_TCP_TX_DATA:
+       case MVM_TCP_TX_FIN:
+               memcpy(pkt->eth.h_dest, tcp->dst_mac, ETH_ALEN);
+               memcpy(pkt->eth.h_source, vif->addr, ETH_ALEN);
+               pkt->ip.ttl = 128;
+               pkt->ip.saddr = tcp->src;
+               pkt->ip.daddr = tcp->dst;
+               pkt->tcp.source = cpu_to_be16(tcp->src_port);
+               pkt->tcp.dest = cpu_to_be16(tcp->dst_port);
+               /* overwritten for TX SYN later */
+               pkt->tcp.doff = sizeof(struct tcphdr) / 4;
+               pkt->tcp.window = cpu_to_be16(65000);
+               break;
+       case MVM_TCP_RX_SYNACK:
+       case MVM_TCP_RX_ACK:
+       case MVM_TCP_RX_WAKE:
+               memcpy(pkt->eth.h_dest, vif->addr, ETH_ALEN);
+               memcpy(pkt->eth.h_source, tcp->dst_mac, ETH_ALEN);
+               pkt->ip.saddr = tcp->dst;
+               pkt->ip.daddr = tcp->src;
+               pkt->tcp.source = cpu_to_be16(tcp->dst_port);
+               pkt->tcp.dest = cpu_to_be16(tcp->src_port);
+               break;
+       default:
+               WARN_ON(1);
+               return;
+       }
+
+       switch (ptype) {
+       case MVM_TCP_TX_SYN:
+               /* firmware assumes 8 option bytes - 8 NOPs for now */
+               memset(pkt->data, 0x01, 8);
+               ip_tot_len += 8;
+               pkt->tcp.doff = (sizeof(struct tcphdr) + 8) / 4;
+               pkt->tcp.syn = 1;
+               break;
+       case MVM_TCP_TX_DATA:
+               ip_tot_len += tcp->payload_len;
+               memcpy(pkt->data, tcp->payload, tcp->payload_len);
+               pkt->tcp.psh = 1;
+               pkt->tcp.ack = 1;
+               break;
+       case MVM_TCP_TX_FIN:
+               pkt->tcp.fin = 1;
+               pkt->tcp.ack = 1;
+               break;
+       case MVM_TCP_RX_SYNACK:
+               pkt->tcp.syn = 1;
+               pkt->tcp.ack = 1;
+               break;
+       case MVM_TCP_RX_ACK:
+               pkt->tcp.ack = 1;
+               break;
+       case MVM_TCP_RX_WAKE:
+               ip_tot_len += tcp->wake_len;
+               pkt->tcp.psh = 1;
+               pkt->tcp.ack = 1;
+               memcpy(pkt->data, tcp->wake_data, tcp->wake_len);
+               break;
+       }
+
+       switch (ptype) {
+       case MVM_TCP_TX_SYN:
+       case MVM_TCP_TX_DATA:
+       case MVM_TCP_TX_FIN:
+               pkt->ip.tot_len = cpu_to_be16(ip_tot_len);
+               pkt->ip.check = ip_fast_csum(&pkt->ip, pkt->ip.ihl);
+               break;
+       case MVM_TCP_RX_WAKE:
+               for (i = 0; i < DIV_ROUND_UP(tcp->wake_len, 8); i++) {
+                       u8 tmp = tcp->wake_mask[i];
+                       mask[i + 6] |= tmp << 6;
+                       if (i + 1 < DIV_ROUND_UP(tcp->wake_len, 8))
+                               mask[i + 7] = tmp >> 2;
+               }
+               /* fall through for ethernet/IP/TCP headers mask */
+       case MVM_TCP_RX_SYNACK:
+       case MVM_TCP_RX_ACK:
+               mask[0] = 0xff; /* match ethernet */
+               /*
+                * match ethernet, ip.version, ip.ihl
+                * the ip.ihl half byte is really masked out by firmware
+                */
+               mask[1] = 0x7f;
+               mask[2] = 0x80; /* match ip.protocol */
+               mask[3] = 0xfc; /* match ip.saddr, ip.daddr */
+               mask[4] = 0x3f; /* match ip.daddr, tcp.source, tcp.dest */
+               mask[5] = 0x80; /* match tcp flags */
+               /* leave rest (0 or set for MVM_TCP_RX_WAKE) */
+               break;
+       };
+
+       *pseudo_hdr_csum = pseudo_hdr_check(ip_tot_len - sizeof(struct iphdr),
+                                           pkt->ip.saddr, pkt->ip.daddr);
+}
+
+static int iwl_mvm_send_remote_wake_cfg(struct iwl_mvm *mvm,
+                                       struct ieee80211_vif *vif,
+                                       struct cfg80211_wowlan_tcp *tcp)
+{
+       struct iwl_wowlan_remote_wake_config *cfg;
+       struct iwl_host_cmd cmd = {
+               .id = REMOTE_WAKE_CONFIG_CMD,
+               .len = { sizeof(*cfg), },
+               .dataflags = { IWL_HCMD_DFL_NOCOPY, },
+               .flags = CMD_SYNC,
+       };
+       int ret;
+
+       if (!tcp)
+               return 0;
+
+       cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
+       if (!cfg)
+               return -ENOMEM;
+       cmd.data[0] = cfg;
+
+       cfg->max_syn_retries = 10;
+       cfg->max_data_retries = 10;
+       cfg->tcp_syn_ack_timeout = 1; /* seconds */
+       cfg->tcp_ack_timeout = 1; /* seconds */
+
+       /* SYN (TX) */
+       iwl_mvm_build_tcp_packet(
+               mvm, vif, tcp, cfg->syn_tx.data, NULL,
+               &cfg->syn_tx.info.tcp_pseudo_header_checksum,
+               MVM_TCP_TX_SYN);
+       cfg->syn_tx.info.tcp_payload_length = 0;
+
+       /* SYN/ACK (RX) */
+       iwl_mvm_build_tcp_packet(
+               mvm, vif, tcp, cfg->synack_rx.data, cfg->synack_rx.rx_mask,
+               &cfg->synack_rx.info.tcp_pseudo_header_checksum,
+               MVM_TCP_RX_SYNACK);
+       cfg->synack_rx.info.tcp_payload_length = 0;
+
+       /* KEEPALIVE/ACK (TX) */
+       iwl_mvm_build_tcp_packet(
+               mvm, vif, tcp, cfg->keepalive_tx.data, NULL,
+               &cfg->keepalive_tx.info.tcp_pseudo_header_checksum,
+               MVM_TCP_TX_DATA);
+       cfg->keepalive_tx.info.tcp_payload_length =
+               cpu_to_le16(tcp->payload_len);
+       cfg->sequence_number_offset = tcp->payload_seq.offset;
+       /* length must be 0..4, the field is little endian */
+       cfg->sequence_number_length = tcp->payload_seq.len;
+       cfg->initial_sequence_number = cpu_to_le32(tcp->payload_seq.start);
+       cfg->keepalive_interval = cpu_to_le16(tcp->data_interval);
+       if (tcp->payload_tok.len) {
+               cfg->token_offset = tcp->payload_tok.offset;
+               cfg->token_length = tcp->payload_tok.len;
+               cfg->num_tokens =
+                       cpu_to_le16(tcp->tokens_size % tcp->payload_tok.len);
+               memcpy(cfg->tokens, tcp->payload_tok.token_stream,
+                      tcp->tokens_size);
+       } else {
+               /* set tokens to max value to almost never run out */
+               cfg->num_tokens = cpu_to_le16(65535);
+       }
+
+       /* ACK (RX) */
+       iwl_mvm_build_tcp_packet(
+               mvm, vif, tcp, cfg->keepalive_ack_rx.data,
+               cfg->keepalive_ack_rx.rx_mask,
+               &cfg->keepalive_ack_rx.info.tcp_pseudo_header_checksum,
+               MVM_TCP_RX_ACK);
+       cfg->keepalive_ack_rx.info.tcp_payload_length = 0;
+
+       /* WAKEUP (RX) */
+       iwl_mvm_build_tcp_packet(
+               mvm, vif, tcp, cfg->wake_rx.data, cfg->wake_rx.rx_mask,
+               &cfg->wake_rx.info.tcp_pseudo_header_checksum,
+               MVM_TCP_RX_WAKE);
+       cfg->wake_rx.info.tcp_payload_length =
+               cpu_to_le16(tcp->wake_len);
+
+       /* FIN */
+       iwl_mvm_build_tcp_packet(
+               mvm, vif, tcp, cfg->fin_tx.data, NULL,
+               &cfg->fin_tx.info.tcp_pseudo_header_checksum,
+               MVM_TCP_TX_FIN);
+       cfg->fin_tx.info.tcp_payload_length = 0;
+
+       ret = iwl_mvm_send_cmd(mvm, &cmd);
+       kfree(cfg);
+
+       return ret;
+}
+
 struct iwl_d3_iter_data {
        struct iwl_mvm *mvm;
        struct ieee80211_vif *vif;
@@ -640,6 +869,22 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
                d3_cfg_cmd.wakeup_flags |=
                        cpu_to_le32(IWL_WOWLAN_WAKEUP_RF_KILL_DEASSERT);
 
+       if (wowlan->tcp) {
+               /*
+                * The firmware currently doesn't really look at these, only
+                * the IWL_WOWLAN_WAKEUP_LINK_CHANGE bit. We have to set that
+                * reason bit since losing the connection to the AP implies
+                * losing the TCP connection.
+                * Set the flags anyway as long as they exist, in case this
+                * will be changed in the firmware.
+                */
+               wowlan_config_cmd.wakeup_filter |=
+                       cpu_to_le32(IWL_WOWLAN_WAKEUP_REMOTE_LINK_LOSS |
+                                   IWL_WOWLAN_WAKEUP_REMOTE_SIGNATURE_TABLE |
+                                   IWL_WOWLAN_WAKEUP_REMOTE_WAKEUP_PACKET |
+                                   IWL_WOWLAN_WAKEUP_LINK_CHANGE);
+       }
+
        iwl_mvm_cancel_scan(mvm);
 
        iwl_trans_stop_device(mvm->trans);
@@ -755,6 +1000,10 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
        if (ret)
                goto out;
 
+       ret = iwl_mvm_send_remote_wake_cfg(mvm, vif, wowlan->tcp);
+       if (ret)
+               goto out;
+
        /* must be last -- this switches firmware state */
        ret = iwl_mvm_send_cmd_pdu(mvm, D3_CONFIG_CMD, CMD_SYNC,
                                   sizeof(d3_cfg_cmd), &d3_cfg_cmd);
@@ -874,6 +1123,15 @@ static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
        if (reasons & IWL_WOWLAN_WAKEUP_BY_FOUR_WAY_HANDSHAKE)
                wakeup.four_way_handshake = true;
 
+       if (reasons & IWL_WOWLAN_WAKEUP_BY_REM_WAKE_LINK_LOSS)
+               wakeup.tcp_connlost = true;
+
+       if (reasons & IWL_WOWLAN_WAKEUP_BY_REM_WAKE_SIGNATURE_TABLE)
+               wakeup.tcp_nomoretokens = true;
+
+       if (reasons & IWL_WOWLAN_WAKEUP_BY_REM_WAKE_WAKEUP_PACKET)
+               wakeup.tcp_match = true;
+
        if (status->wake_packet_bufsize) {
                int pktsize = le32_to_cpu(status->wake_packet_bufsize);
                int pktlen = le32_to_cpu(status->wake_packet_length);
index c1bdb55..b080b4b 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
@@ -69,12 +69,6 @@ struct iwl_dbgfs_mvm_ctx {
        struct ieee80211_vif *vif;
 };
 
-static int iwl_dbgfs_open_file_generic(struct inode *inode, struct file *file)
-{
-       file->private_data = inode->i_private;
-       return 0;
-}
-
 static ssize_t iwl_dbgfs_tx_flush_write(struct file *file,
                                        const char __user *user_buf,
                                        size_t count, loff_t *ppos)
@@ -306,10 +300,130 @@ static ssize_t iwl_dbgfs_power_down_d3_allow_write(struct file *file,
        return count;
 }
 
+#define BT_MBOX_MSG(_notif, _num, _field)                                   \
+       ((le32_to_cpu((_notif)->mbox_msg[(_num)]) & BT_MBOX##_num##_##_field)\
+       >> BT_MBOX##_num##_##_field##_POS)
+
+
+#define BT_MBOX_PRINT(_num, _field, _end)                                  \
+                       pos += scnprintf(buf + pos, bufsz - pos,            \
+                                        "\t%s: %d%s",                      \
+                                        #_field,                           \
+                                        BT_MBOX_MSG(notif, _num, _field),  \
+                                        true ? "\n" : ", ");
+
+static ssize_t iwl_dbgfs_bt_notif_read(struct file *file, char __user *user_buf,
+                                      size_t count, loff_t *ppos)
+{
+       struct iwl_mvm *mvm = file->private_data;
+       struct iwl_bt_coex_profile_notif *notif = &mvm->last_bt_notif;
+       char *buf;
+       int ret, pos = 0, bufsz = sizeof(char) * 1024;
+
+       buf = kmalloc(bufsz, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       mutex_lock(&mvm->mutex);
+
+       pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw0:\n");
+
+       BT_MBOX_PRINT(0, LE_SLAVE_LAT, false);
+       BT_MBOX_PRINT(0, LE_PROF1, false);
+       BT_MBOX_PRINT(0, LE_PROF2, false);
+       BT_MBOX_PRINT(0, LE_PROF_OTHER, false);
+       BT_MBOX_PRINT(0, CHL_SEQ_N, false);
+       BT_MBOX_PRINT(0, INBAND_S, false);
+       BT_MBOX_PRINT(0, LE_MIN_RSSI, false);
+       BT_MBOX_PRINT(0, LE_SCAN, false);
+       BT_MBOX_PRINT(0, LE_ADV, false);
+       BT_MBOX_PRINT(0, LE_MAX_TX_POWER, false);
+       BT_MBOX_PRINT(0, OPEN_CON_1, true);
+
+       pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw1:\n");
+
+       BT_MBOX_PRINT(1, BR_MAX_TX_POWER, false);
+       BT_MBOX_PRINT(1, IP_SR, false);
+       BT_MBOX_PRINT(1, LE_MSTR, false);
+       BT_MBOX_PRINT(1, AGGR_TRFC_LD, false);
+       BT_MBOX_PRINT(1, MSG_TYPE, false);
+       BT_MBOX_PRINT(1, SSN, true);
+
+       pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw2:\n");
+
+       BT_MBOX_PRINT(2, SNIFF_ACT, false);
+       BT_MBOX_PRINT(2, PAG, false);
+       BT_MBOX_PRINT(2, INQUIRY, false);
+       BT_MBOX_PRINT(2, CONN, false);
+       BT_MBOX_PRINT(2, SNIFF_INTERVAL, false);
+       BT_MBOX_PRINT(2, DISC, false);
+       BT_MBOX_PRINT(2, SCO_TX_ACT, false);
+       BT_MBOX_PRINT(2, SCO_RX_ACT, false);
+       BT_MBOX_PRINT(2, ESCO_RE_TX, false);
+       BT_MBOX_PRINT(2, SCO_DURATION, true);
+
+       pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw3:\n");
+
+       BT_MBOX_PRINT(3, SCO_STATE, false);
+       BT_MBOX_PRINT(3, SNIFF_STATE, false);
+       BT_MBOX_PRINT(3, A2DP_STATE, false);
+       BT_MBOX_PRINT(3, ACL_STATE, false);
+       BT_MBOX_PRINT(3, MSTR_STATE, false);
+       BT_MBOX_PRINT(3, OBX_STATE, false);
+       BT_MBOX_PRINT(3, OPEN_CON_2, false);
+       BT_MBOX_PRINT(3, TRAFFIC_LOAD, false);
+       BT_MBOX_PRINT(3, CHL_SEQN_LSB, false);
+       BT_MBOX_PRINT(3, INBAND_P, false);
+       BT_MBOX_PRINT(3, MSG_TYPE_2, false);
+       BT_MBOX_PRINT(3, SSN_2, false);
+       BT_MBOX_PRINT(3, UPDATE_REQUEST, true);
+
+       pos += scnprintf(buf+pos, bufsz-pos, "bt_status = %d\n",
+                                        notif->bt_status);
+       pos += scnprintf(buf+pos, bufsz-pos, "bt_open_conn = %d\n",
+                                        notif->bt_open_conn);
+       pos += scnprintf(buf+pos, bufsz-pos, "bt_traffic_load = %d\n",
+                                        notif->bt_traffic_load);
+       pos += scnprintf(buf+pos, bufsz-pos, "bt_agg_traffic_load = %d\n",
+                                        notif->bt_agg_traffic_load);
+       pos += scnprintf(buf+pos, bufsz-pos, "bt_ci_compliance = %d\n",
+                                        notif->bt_ci_compliance);
+
+       mutex_unlock(&mvm->mutex);
+
+       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+       kfree(buf);
+
+       return ret;
+}
+#undef BT_MBOX_PRINT
+
+static ssize_t iwl_dbgfs_fw_restart_write(struct file *file,
+                                         const char __user *user_buf,
+                                         size_t count, loff_t *ppos)
+{
+       struct iwl_mvm *mvm = file->private_data;
+       bool restart_fw = iwlwifi_mod_params.restart_fw;
+       int ret;
+
+       iwlwifi_mod_params.restart_fw = true;
+
+       mutex_lock(&mvm->mutex);
+
+       /* take the return value to make compiler happy - it will fail anyway */
+       ret = iwl_mvm_send_cmd_pdu(mvm, REPLY_ERROR, CMD_SYNC, 0, NULL);
+
+       mutex_unlock(&mvm->mutex);
+
+       iwlwifi_mod_params.restart_fw = restart_fw;
+
+       return count;
+}
+
 #define MVM_DEBUGFS_READ_FILE_OPS(name)                                        \
 static const struct file_operations iwl_dbgfs_##name##_ops = { \
        .read = iwl_dbgfs_##name##_read,                                \
-       .open = iwl_dbgfs_open_file_generic,                            \
+       .open = simple_open,                                            \
        .llseek = generic_file_llseek,                                  \
 }
 
@@ -317,14 +431,14 @@ static const struct file_operations iwl_dbgfs_##name##_ops = {    \
 static const struct file_operations iwl_dbgfs_##name##_ops = { \
        .write = iwl_dbgfs_##name##_write,                              \
        .read = iwl_dbgfs_##name##_read,                                \
-       .open = iwl_dbgfs_open_file_generic,                            \
+       .open = simple_open,                                            \
        .llseek = generic_file_llseek,                                  \
 };
 
 #define MVM_DEBUGFS_WRITE_FILE_OPS(name)                               \
 static const struct file_operations iwl_dbgfs_##name##_ops = { \
        .write = iwl_dbgfs_##name##_write,                              \
-       .open = iwl_dbgfs_open_file_generic,                            \
+       .open = simple_open,                                            \
        .llseek = generic_file_llseek,                                  \
 };
 
@@ -345,8 +459,10 @@ MVM_DEBUGFS_WRITE_FILE_OPS(tx_flush);
 MVM_DEBUGFS_WRITE_FILE_OPS(sta_drain);
 MVM_DEBUGFS_READ_WRITE_FILE_OPS(sram);
 MVM_DEBUGFS_READ_FILE_OPS(stations);
+MVM_DEBUGFS_READ_FILE_OPS(bt_notif);
 MVM_DEBUGFS_WRITE_FILE_OPS(power_down_allow);
 MVM_DEBUGFS_WRITE_FILE_OPS(power_down_d3_allow);
+MVM_DEBUGFS_WRITE_FILE_OPS(fw_restart);
 
 int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
 {
@@ -358,8 +474,10 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
        MVM_DEBUGFS_ADD_FILE(sta_drain, mvm->debugfs_dir, S_IWUSR);
        MVM_DEBUGFS_ADD_FILE(sram, mvm->debugfs_dir, S_IWUSR | S_IRUSR);
        MVM_DEBUGFS_ADD_FILE(stations, dbgfs_dir, S_IRUSR);
+       MVM_DEBUGFS_ADD_FILE(bt_notif, dbgfs_dir, S_IRUSR);
        MVM_DEBUGFS_ADD_FILE(power_down_allow, mvm->debugfs_dir, S_IWUSR);
        MVM_DEBUGFS_ADD_FILE(power_down_d3_allow, mvm->debugfs_dir, S_IWUSR);
+       MVM_DEBUGFS_ADD_FILE(fw_restart, mvm->debugfs_dir, S_IWUSR);
 
        /*
         * Create a symlink with mac80211. It will be removed when mac80211
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h
new file mode 100644 (file)
index 0000000..05c61d6
--- /dev/null
@@ -0,0 +1,319 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2013 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called COPYING.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2013 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef __fw_api_bt_coex_h__
+#define __fw_api_bt_coex_h__
+
+#include <linux/types.h>
+#include <linux/bitops.h>
+
+#define BITS(nb) (BIT(nb) - 1)
+
+/**
+ * enum iwl_bt_coex_flags - flags for BT_COEX command
+ * @BT_CH_PRIMARY_EN:
+ * @BT_CH_SECONDARY_EN:
+ * @BT_NOTIF_COEX_OFF:
+ * @BT_COEX_MODE_POS:
+ * @BT_COEX_MODE_MSK:
+ * @BT_COEX_DISABLE:
+ * @BT_COEX_2W:
+ * @BT_COEX_3W:
+ * @BT_COEX_NW:
+ * @BT_USE_DEFAULTS:
+ * @BT_SYNC_2_BT_DISABLE:
+ * @BT_COEX_CORUNNING_TBL_EN:
+ */
+enum iwl_bt_coex_flags {
+       BT_CH_PRIMARY_EN                = BIT(0),
+       BT_CH_SECONDARY_EN              = BIT(1),
+       BT_NOTIF_COEX_OFF               = BIT(2),
+       BT_COEX_MODE_POS                = 3,
+       BT_COEX_MODE_MSK                = BITS(3) << BT_COEX_MODE_POS,
+       BT_COEX_DISABLE                 = 0x0 << BT_COEX_MODE_POS,
+       BT_COEX_2W                      = 0x1 << BT_COEX_MODE_POS,
+       BT_COEX_3W                      = 0x2 << BT_COEX_MODE_POS,
+       BT_COEX_NW                      = 0x3 << BT_COEX_MODE_POS,
+       BT_USE_DEFAULTS                 = BIT(6),
+       BT_SYNC_2_BT_DISABLE            = BIT(7),
+       /*
+        * For future use - when the flags will be enlarged
+        * BT_COEX_CORUNNING_TBL_EN     = BIT(8),
+        */
+};
+
+/*
+ * indicates what has changed in the BT_COEX command.
+ */
+enum iwl_bt_coex_valid_bit_msk {
+       BT_VALID_ENABLE                 = BIT(0),
+       BT_VALID_BT_PRIO_BOOST          = BIT(1),
+       BT_VALID_MAX_KILL               = BIT(2),
+       BT_VALID_3W_TMRS                = BIT(3),
+       BT_VALID_KILL_ACK               = BIT(4),
+       BT_VALID_KILL_CTS               = BIT(5),
+       BT_VALID_REDUCED_TX_POWER       = BIT(6),
+       BT_VALID_LUT                    = BIT(7),
+       BT_VALID_WIFI_RX_SW_PRIO_BOOST  = BIT(8),
+       BT_VALID_WIFI_TX_SW_PRIO_BOOST  = BIT(9),
+       BT_VALID_MULTI_PRIO_LUT         = BIT(10),
+       BT_VALID_TRM_KICK_FILTER        = BIT(11),
+       BT_VALID_CORUN_LUT_20           = BIT(12),
+       BT_VALID_CORUN_LUT_40           = BIT(13),
+       BT_VALID_ANT_ISOLATION          = BIT(14),
+       BT_VALID_ANT_ISOLATION_THRS     = BIT(15),
+       /*
+        * For future use - when the valid flags will be enlarged
+        * BT_VALID_TXTX_DELTA_FREQ_THRS        = BIT(16),
+        * BT_VALID_TXRX_MAX_FREQ_0     = BIT(17),
+        */
+};
+
+/**
+ * enum iwl_bt_reduced_tx_power - allows to reduce txpower for WiFi frames.
+ * @BT_REDUCED_TX_POWER_CTL: reduce Tx power for control frames
+ * @BT_REDUCED_TX_POWER_DATA: reduce Tx power for data frames
+ *
+ * This mechanism allows to have BT and WiFi run concurrently. Since WiFi
+ * reduces its Tx power, it can work along with BT, hence reducing the amount
+ * of WiFi frames being killed by BT.
+ */
+enum iwl_bt_reduced_tx_power {
+       BT_REDUCED_TX_POWER_CTL         = BIT(0),
+       BT_REDUCED_TX_POWER_DATA        = BIT(1),
+};
+
+#define BT_COEX_LUT_SIZE (12)
+
+/**
+ * struct iwl_bt_coex_cmd - bt coex configuration command
+ * @flags:&enum iwl_bt_coex_flags
+ * @lead_time:
+ * @max_kill:
+ * @bt3_time_t7_value:
+ * @kill_ack_msk:
+ * @kill_cts_msk:
+ * @bt3_prio_sample_time:
+ * @bt3_timer_t2_value:
+ * @bt4_reaction_time:
+ * @decision_lut[12]:
+ * @bt_reduced_tx_power: enum %iwl_bt_reduced_tx_power
+ * @valid_bit_msk: enum %iwl_bt_coex_valid_bit_msk
+ * @bt_prio_boost: values for PTA boost register
+ * @wifi_tx_prio_boost: SW boost of wifi tx priority
+ * @wifi_rx_prio_boost: SW boost of wifi rx priority
+ *
+ * The structure is used for the BT_COEX command.
+ */
+struct iwl_bt_coex_cmd {
+       u8 flags;
+       u8 lead_time;
+       u8 max_kill;
+       u8 bt3_time_t7_value;
+       __le32 kill_ack_msk;
+       __le32 kill_cts_msk;
+       u8 bt3_prio_sample_time;
+       u8 bt3_timer_t2_value;
+       __le16 bt4_reaction_time;
+       __le32 decision_lut[BT_COEX_LUT_SIZE];
+       u8 bt_reduced_tx_power;
+       u8 reserved;
+       __le16 valid_bit_msk;
+       __le32 bt_prio_boost;
+       u8 reserved2;
+       u8 wifi_tx_prio_boost;
+       __le16 wifi_rx_prio_boost;
+} __packed; /* BT_COEX_CMD_API_S_VER_3 */
+
+#define BT_MBOX(n_dw, _msg, _pos, _nbits)      \
+       BT_MBOX##n_dw##_##_msg##_POS = (_pos),  \
+       BT_MBOX##n_dw##_##_msg = BITS(_nbits) << BT_MBOX##n_dw##_##_msg##_POS
+
+enum iwl_bt_mxbox_dw0 {
+       BT_MBOX(0, LE_SLAVE_LAT, 0, 3),
+       BT_MBOX(0, LE_PROF1, 3, 1),
+       BT_MBOX(0, LE_PROF2, 4, 1),
+       BT_MBOX(0, LE_PROF_OTHER, 5, 1),
+       BT_MBOX(0, CHL_SEQ_N, 8, 4),
+       BT_MBOX(0, INBAND_S, 13, 1),
+       BT_MBOX(0, LE_MIN_RSSI, 16, 4),
+       BT_MBOX(0, LE_SCAN, 20, 1),
+       BT_MBOX(0, LE_ADV, 21, 1),
+       BT_MBOX(0, LE_MAX_TX_POWER, 24, 4),
+       BT_MBOX(0, OPEN_CON_1, 28, 2),
+};
+
+enum iwl_bt_mxbox_dw1 {
+       BT_MBOX(1, BR_MAX_TX_POWER, 0, 4),
+       BT_MBOX(1, IP_SR, 4, 1),
+       BT_MBOX(1, LE_MSTR, 5, 1),
+       BT_MBOX(1, AGGR_TRFC_LD, 8, 6),
+       BT_MBOX(1, MSG_TYPE, 16, 3),
+       BT_MBOX(1, SSN, 19, 2),
+};
+
+enum iwl_bt_mxbox_dw2 {
+       BT_MBOX(2, SNIFF_ACT, 0, 3),
+       BT_MBOX(2, PAG, 3, 1),
+       BT_MBOX(2, INQUIRY, 4, 1),
+       BT_MBOX(2, CONN, 5, 1),
+       BT_MBOX(2, SNIFF_INTERVAL, 8, 5),
+       BT_MBOX(2, DISC, 13, 1),
+       BT_MBOX(2, SCO_TX_ACT, 16, 2),
+       BT_MBOX(2, SCO_RX_ACT, 18, 2),
+       BT_MBOX(2, ESCO_RE_TX, 20, 2),
+       BT_MBOX(2, SCO_DURATION, 24, 6),
+};
+
+enum iwl_bt_mxbox_dw3 {
+       BT_MBOX(3, SCO_STATE, 0, 1),
+       BT_MBOX(3, SNIFF_STATE, 1, 1),
+       BT_MBOX(3, A2DP_STATE, 2, 1),
+       BT_MBOX(3, ACL_STATE, 3, 1),
+       BT_MBOX(3, MSTR_STATE, 4, 1),
+       BT_MBOX(3, OBX_STATE, 5, 1),
+       BT_MBOX(3, OPEN_CON_2, 8, 2),
+       BT_MBOX(3, TRAFFIC_LOAD, 10, 2),
+       BT_MBOX(3, CHL_SEQN_LSB, 12, 1),
+       BT_MBOX(3, INBAND_P, 13, 1),
+       BT_MBOX(3, MSG_TYPE_2, 16, 3),
+       BT_MBOX(3, SSN_2, 19, 2),
+       BT_MBOX(3, UPDATE_REQUEST, 21, 1),
+};
+
+#define BT_MBOX_MSG(_notif, _num, _field)                                   \
+       ((le32_to_cpu((_notif)->mbox_msg[(_num)]) & BT_MBOX##_num##_##_field)\
+       >> BT_MBOX##_num##_##_field##_POS)
+
+/**
+ * struct iwl_bt_coex_profile_notif - notification about BT coex
+ * @mbox_msg: message from BT to WiFi
+ * @:bt_status: 0 - off, 1 - on
+ * @:bt_open_conn: number of BT connections open
+ * @:bt_traffic_load: load of BT traffic
+ * @:bt_agg_traffic_load: aggregated load of BT traffic
+ * @:bt_ci_compliance: 0 - no CI compliance, 1 - CI compliant
+ */
+struct iwl_bt_coex_profile_notif {
+       __le32 mbox_msg[4];
+       u8 bt_status;
+       u8 bt_open_conn;
+       u8 bt_traffic_load;
+       u8 bt_agg_traffic_load;
+       u8 bt_ci_compliance;
+       u8 reserved[3];
+} __packed; /* BT_COEX_PROFILE_NTFY_API_S_VER_2 */
+
+enum iwl_bt_coex_prio_table_event {
+       BT_COEX_PRIO_TBL_EVT_INIT_CALIB1                = 0,
+       BT_COEX_PRIO_TBL_EVT_INIT_CALIB2                = 1,
+       BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_LOW1        = 2,
+       BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_LOW2        = 3,
+       BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_HIGH1       = 4,
+       BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_HIGH2       = 5,
+       BT_COEX_PRIO_TBL_EVT_DTIM                       = 6,
+       BT_COEX_PRIO_TBL_EVT_SCAN52                     = 7,
+       BT_COEX_PRIO_TBL_EVT_SCAN24                     = 8,
+       BT_COEX_PRIO_TBL_EVT_IDLE                       = 9,
+       BT_COEX_PRIO_TBL_EVT_MAX                        = 16,
+}; /* BT_COEX_PRIO_TABLE_EVENTS_API_E_VER_1 */
+
+enum iwl_bt_coex_prio_table_prio {
+       BT_COEX_PRIO_TBL_DISABLED       = 0,
+       BT_COEX_PRIO_TBL_PRIO_LOW       = 1,
+       BT_COEX_PRIO_TBL_PRIO_HIGH      = 2,
+       BT_COEX_PRIO_TBL_PRIO_BYPASS    = 3,
+       BT_COEX_PRIO_TBL_PRIO_COEX_OFF  = 4,
+       BT_COEX_PRIO_TBL_PRIO_COEX_ON   = 5,
+       BT_COEX_PRIO_TBL_PRIO_COEX_IDLE = 6,
+       BT_COEX_PRIO_TBL_MAX            = 8,
+}; /* BT_COEX_PRIO_TABLE_PRIORITIES_API_E_VER_1 */
+
+#define BT_COEX_PRIO_TBL_SHRD_ANT_POS     (0)
+#define BT_COEX_PRIO_TBL_PRIO_POS         (1)
+#define BT_COEX_PRIO_TBL_RESERVED_POS     (4)
+
+/**
+ * struct iwl_bt_coex_prio_tbl_cmd - priority table for BT coex
+ * @prio_tbl:
+ */
+struct iwl_bt_coex_prio_tbl_cmd {
+       u8 prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX];
+} __packed;
+
+enum iwl_bt_coex_env_action {
+       BT_COEX_ENV_CLOSE        = 0,
+       BT_COEX_ENV_OPEN         = 1,
+}; /* BT_COEX_PROT_ENV_ACTION_API_E_VER_1 */
+
+/**
+ * struct iwl_bt_coex_prot_env_cmd - BT Protection Envelope
+ * @action: enum %iwl_bt_coex_env_action
+ * @type: enum %iwl_bt_coex_prio_table_event
+ */
+struct iwl_bt_coex_prot_env_cmd {
+       u8 action; /* 0 = closed, 1 = open */
+       u8 type; /* 0 .. 15 */
+       u8 reserved[2];
+} __packed;
+
+#endif /* __fw_api_bt_coex_h__ */
index cf6f9a0..51e015d 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
@@ -258,7 +258,7 @@ enum iwl_wowlan_wakeup_reason {
        IWL_WOWLAN_WAKEUP_BY_FOUR_WAY_HANDSHAKE                 = BIT(8),
        IWL_WOWLAN_WAKEUP_BY_REM_WAKE_LINK_LOSS                 = BIT(9),
        IWL_WOWLAN_WAKEUP_BY_REM_WAKE_SIGNATURE_TABLE           = BIT(10),
-       IWL_WOWLAN_WAKEUP_BY_REM_WAKE_TCP_EXTERNAL              = BIT(11),
+       /* BIT(11) reserved */
        IWL_WOWLAN_WAKEUP_BY_REM_WAKE_WAKEUP_PACKET             = BIT(12),
 }; /* WOWLAN_WAKE_UP_REASON_API_E_VER_2 */
 
@@ -277,6 +277,55 @@ struct iwl_wowlan_status {
        u8 wake_packet[]; /* can be truncated from _length to _bufsize */
 } __packed; /* WOWLAN_STATUSES_API_S_VER_4 */
 
+#define IWL_WOWLAN_TCP_MAX_PACKET_LEN          64
+#define IWL_WOWLAN_REMOTE_WAKE_MAX_PACKET_LEN  128
+#define IWL_WOWLAN_REMOTE_WAKE_MAX_TOKENS      2048
+
+struct iwl_tcp_packet_info {
+       __le16 tcp_pseudo_header_checksum;
+       __le16 tcp_payload_length;
+} __packed; /* TCP_PACKET_INFO_API_S_VER_2 */
+
+struct iwl_tcp_packet {
+       struct iwl_tcp_packet_info info;
+       u8 rx_mask[IWL_WOWLAN_MAX_PATTERN_LEN / 8];
+       u8 data[IWL_WOWLAN_TCP_MAX_PACKET_LEN];
+} __packed; /* TCP_PROTOCOL_PACKET_API_S_VER_1 */
+
+struct iwl_remote_wake_packet {
+       struct iwl_tcp_packet_info info;
+       u8 rx_mask[IWL_WOWLAN_MAX_PATTERN_LEN / 8];
+       u8 data[IWL_WOWLAN_REMOTE_WAKE_MAX_PACKET_LEN];
+} __packed; /* TCP_PROTOCOL_PACKET_API_S_VER_1 */
+
+struct iwl_wowlan_remote_wake_config {
+       __le32 connection_max_time; /* unused */
+       /* TCP_PROTOCOL_CONFIG_API_S_VER_1 */
+       u8 max_syn_retries;
+       u8 max_data_retries;
+       u8 tcp_syn_ack_timeout;
+       u8 tcp_ack_timeout;
+
+       struct iwl_tcp_packet syn_tx;
+       struct iwl_tcp_packet synack_rx;
+       struct iwl_tcp_packet keepalive_ack_rx;
+       struct iwl_tcp_packet fin_tx;
+
+       struct iwl_remote_wake_packet keepalive_tx;
+       struct iwl_remote_wake_packet wake_rx;
+
+       /* REMOTE_WAKE_OFFSET_INFO_API_S_VER_1 */
+       u8 sequence_number_offset;
+       u8 sequence_number_length;
+       u8 token_offset;
+       u8 token_length;
+       /* REMOTE_WAKE_PROTOCOL_PARAMS_API_S_VER_1 */
+       __le32 initial_sequence_number;
+       __le16 keepalive_interval;
+       __le16 num_tokens;
+       u8 tokens[IWL_WOWLAN_REMOTE_WAKE_MAX_TOKENS];
+} __packed; /* REMOTE_WAKE_CONFIG_API_S_VER_2 */
+
 /* TODO: NetDetect API */
 
 #endif /* __fw_api_d3_h__ */
index ae39b7d..d68640e 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
index be36b76..1270518 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
index aa3474d..fdd33bc 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
index 670ac8f..b60d141 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
index 0acb53d..a30691a 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
index 2677914..6d53850 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
index 2adb61f..f8d7e88 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
@@ -70,6 +70,7 @@
 #include "fw-api-mac.h"
 #include "fw-api-power.h"
 #include "fw-api-d3.h"
+#include "fw-api-bt-coex.h"
 
 /* queue and FIFO numbers by usage */
 enum {
@@ -152,6 +153,7 @@ enum {
 
        BEACON_TEMPLATE_CMD = 0x91,
        TX_ANT_CONFIGURATION_CMD = 0x98,
+       BT_CONFIG = 0x9b,
        STATISTICS_NOTIFICATION = 0x9d,
 
        /* RF-KILL commands and notifications */
@@ -162,6 +164,11 @@ enum {
        REPLY_RX_MPDU_CMD = 0xc1,
        BA_NOTIF = 0xc5,
 
+       /* BT Coex */
+       BT_COEX_PRIO_TABLE = 0xcc,
+       BT_COEX_PROT_ENV = 0xcd,
+       BT_PROFILE_NOTIFICATION = 0xce,
+
        REPLY_DEBUG_CMD = 0xf0,
        DEBUG_LOG_MSG = 0xf7,
 
@@ -794,6 +801,7 @@ struct iwl_phy_context_cmd {
  * @byte_count: frame's byte-count
  * @frame_time: frame's time on the air, based on byte count and frame rate
  *     calculation
+ * @mac_active_msk: what MACs were active when the frame was received
  *
  * Before each Rx, the device sends this data. It contains PHY information
  * about the reception of the packet.
@@ -811,7 +819,7 @@ struct iwl_rx_phy_info {
        __le32 non_cfg_phy[IWL_RX_INFO_PHY_CNT];
        __le32 rate_n_flags;
        __le32 byte_count;
-       __le16 reserved2;
+       __le16 mac_active_msk;
        __le16 frame_time;
 } __packed;
 
index 500f818..1006b32 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
@@ -309,6 +309,10 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
                goto error;
        }
 
+       ret = iwl_send_bt_prio_tbl(mvm);
+       if (ret)
+               goto error;
+
        if (read_nvm) {
                /* Read nvm */
                ret = iwl_nvm_init(mvm);
@@ -414,6 +418,14 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
        if (ret)
                goto error;
 
+       ret = iwl_send_bt_prio_tbl(mvm);
+       if (ret)
+               goto error;
+
+       ret = iwl_send_bt_init_conf(mvm);
+       if (ret)
+               goto error;
+
        /* Send phy db control command and then phy db calibration*/
        ret = iwl_send_phy_db_data(mvm->phy_db);
        if (ret)
index 011906e..2269a9e 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
index 341dbc0..2779235 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
@@ -553,9 +553,9 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm,
        if (vif->bss_conf.qos)
                cmd->qos_flags |= cpu_to_le32(MAC_QOS_FLG_UPDATE_EDCA);
 
+       /* Don't use cts to self as the fw doesn't support it currently. */
        if (vif->bss_conf.use_cts_prot)
-               cmd->protection_flags |= cpu_to_le32(MAC_PROT_FLG_TGG_PROTECT |
-                                                    MAC_PROT_FLG_SELF_CTS_EN);
+               cmd->protection_flags |= cpu_to_le32(MAC_PROT_FLG_TGG_PROTECT);
 
        /*
         * I think that we should enable these 2 flags regardless the HT PROT
@@ -651,6 +651,13 @@ static int iwl_mvm_mac_ctxt_cmd_station(struct iwl_mvm *mvm,
        /* Fill the common data for all mac context types */
        iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
 
+       /* Allow beacons to pass through as long as we are not associated,or we
+        * do not have dtim period information */
+       if (!vif->bss_conf.assoc || !vif->bss_conf.dtim_period)
+               cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_BEACON);
+       else
+               cmd.filter_flags &= ~cpu_to_le32(MAC_FILTER_IN_BEACON);
+
        /* Fill the data specific for station mode */
        iwl_mvm_mac_ctxt_cmd_fill_sta(mvm, vif, &cmd.sta);
 
@@ -714,7 +721,9 @@ static int iwl_mvm_mac_ctxt_cmd_p2p_device(struct iwl_mvm *mvm,
        iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
 
        cmd.protection_flags |= cpu_to_le32(MAC_PROT_FLG_TGG_PROTECT);
-       cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_PROMISC);
+
+       /* Override the filter flags to accept only probe requests */
+       cmd.filter_flags = cpu_to_le32(MAC_FILTER_IN_PROBE_REQUEST);
 
        /*
         * This flag should be set to true when the P2P Device is
@@ -846,10 +855,10 @@ int iwl_mvm_mac_ctxt_beacon_changed(struct iwl_mvm *mvm,
  */
 static void iwl_mvm_mac_ctxt_cmd_fill_ap(struct iwl_mvm *mvm,
                                         struct ieee80211_vif *vif,
-                                        struct iwl_mac_data_ap *ctxt_ap)
+                                        struct iwl_mac_data_ap *ctxt_ap,
+                                        bool add)
 {
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
-       u32 curr_dev_time;
 
        ctxt_ap->bi = cpu_to_le32(vif->bss_conf.beacon_int);
        ctxt_ap->bi_reciprocal =
@@ -861,10 +870,19 @@ static void iwl_mvm_mac_ctxt_cmd_fill_ap(struct iwl_mvm *mvm,
                                               vif->bss_conf.dtim_period));
 
        ctxt_ap->mcast_qid = cpu_to_le32(vif->cab_queue);
-       curr_dev_time = iwl_read_prph(mvm->trans, DEVICE_SYSTEM_TIME_REG);
-       ctxt_ap->beacon_time = cpu_to_le32(curr_dev_time);
 
-       ctxt_ap->beacon_tsf = cpu_to_le64(curr_dev_time);
+       /*
+        * Only read the system time when the MAC is being added, when we
+        * just modify the MAC then we should keep the time -- the firmware
+        * can otherwise have a "jumping" TBTT.
+        */
+       if (add)
+               mvmvif->ap_beacon_time =
+                       iwl_read_prph(mvm->trans, DEVICE_SYSTEM_TIME_REG);
+
+       ctxt_ap->beacon_time = cpu_to_le32(mvmvif->ap_beacon_time);
+
+       ctxt_ap->beacon_tsf = 0; /* unused */
 
        /* TODO: Assume that the beacon id == mac context id */
        ctxt_ap->beacon_template = cpu_to_le32(mvmvif->id);
@@ -881,8 +899,12 @@ static int iwl_mvm_mac_ctxt_cmd_ap(struct iwl_mvm *mvm,
        /* Fill the common data for all mac context types */
        iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
 
+       /* Also enable probe requests to pass */
+       cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_PROBE_REQUEST);
+
        /* Fill the data specific for ap mode */
-       iwl_mvm_mac_ctxt_cmd_fill_ap(mvm, vif, &cmd.ap);
+       iwl_mvm_mac_ctxt_cmd_fill_ap(mvm, vif, &cmd.ap,
+                                    action == FW_CTXT_ACTION_ADD);
 
        return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd);
 }
@@ -899,7 +921,8 @@ static int iwl_mvm_mac_ctxt_cmd_go(struct iwl_mvm *mvm,
        iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
 
        /* Fill the data specific for GO mode */
-       iwl_mvm_mac_ctxt_cmd_fill_ap(mvm, vif, &cmd.go.ap);
+       iwl_mvm_mac_ctxt_cmd_fill_ap(mvm, vif, &cmd.go.ap,
+                                    action == FW_CTXT_ACTION_ADD);
 
        cmd.go.ctwin = cpu_to_le32(vif->bss_conf.p2p_ctwindow);
        cmd.go.opp_ps_enabled = cpu_to_le32(!!vif->bss_conf.p2p_oppps);
index 7e169b0..14dd5ee 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
@@ -65,7 +65,9 @@
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
+#include <linux/ip.h>
 #include <net/mac80211.h>
+#include <net/tcp.h>
 
 #include "iwl-op-mode.h"
 #include "iwl-io.h"
@@ -102,10 +104,33 @@ static const struct ieee80211_iface_combination iwl_mvm_iface_combinations[] = {
        },
 };
 
+#ifdef CONFIG_PM_SLEEP
+static const struct nl80211_wowlan_tcp_data_token_feature
+iwl_mvm_wowlan_tcp_token_feature = {
+       .min_len = 0,
+       .max_len = 255,
+       .bufsize = IWL_WOWLAN_REMOTE_WAKE_MAX_TOKENS,
+};
+
+static const struct wiphy_wowlan_tcp_support iwl_mvm_wowlan_tcp_support = {
+       .tok = &iwl_mvm_wowlan_tcp_token_feature,
+       .data_payload_max = IWL_WOWLAN_TCP_MAX_PACKET_LEN -
+                           sizeof(struct ethhdr) -
+                           sizeof(struct iphdr) -
+                           sizeof(struct tcphdr),
+       .data_interval_max = 65535, /* __le16 in API */
+       .wake_payload_max = IWL_WOWLAN_REMOTE_WAKE_MAX_PACKET_LEN -
+                           sizeof(struct ethhdr) -
+                           sizeof(struct iphdr) -
+                           sizeof(struct tcphdr),
+       .seq = true,
+};
+#endif
+
 int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
 {
        struct ieee80211_hw *hw = mvm->hw;
-       int num_mac, ret;
+       int num_mac, ret, i;
 
        /* Tell mac80211 our characteristics */
        hw->flags = IEEE80211_HW_SIGNAL_DBM |
@@ -156,11 +181,15 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
        memcpy(mvm->addresses[0].addr, mvm->nvm_data->hw_addr, ETH_ALEN);
        hw->wiphy->addresses = mvm->addresses;
        hw->wiphy->n_addresses = 1;
-       num_mac = mvm->nvm_data->n_hw_addrs;
-       if (num_mac > 1) {
-               memcpy(mvm->addresses[1].addr, mvm->addresses[0].addr,
+
+       /* Extract additional MAC addresses if available */
+       num_mac = (mvm->nvm_data->n_hw_addrs > 1) ?
+               min(IWL_MVM_MAX_ADDRESSES, mvm->nvm_data->n_hw_addrs) : 1;
+
+       for (i = 1; i < num_mac; i++) {
+               memcpy(mvm->addresses[i].addr, mvm->addresses[i-1].addr,
                       ETH_ALEN);
-               mvm->addresses[1].addr[5]++;
+               mvm->addresses[i].addr[5]++;
                hw->wiphy->n_addresses++;
        }
 
@@ -206,6 +235,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
                hw->wiphy->wowlan.n_patterns = IWL_WOWLAN_MAX_PATTERNS;
                hw->wiphy->wowlan.pattern_min_len = IWL_WOWLAN_MIN_PATTERN_LEN;
                hw->wiphy->wowlan.pattern_max_len = IWL_WOWLAN_MAX_PATTERN_LEN;
+               hw->wiphy->wowlan.tcp = &iwl_mvm_wowlan_tcp_support;
        }
 #endif
 
@@ -273,12 +303,18 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw,
                ret = iwl_mvm_sta_rx_agg(mvm, sta, tid, 0, false);
                break;
        case IEEE80211_AMPDU_TX_START:
+               if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_TXAGG) {
+                       ret = -EINVAL;
+                       break;
+               }
                ret = iwl_mvm_sta_tx_agg_start(mvm, vif, sta, tid, ssn);
                break;
        case IEEE80211_AMPDU_TX_STOP_CONT:
+               ret = iwl_mvm_sta_tx_agg_stop(mvm, vif, sta, tid);
+               break;
        case IEEE80211_AMPDU_TX_STOP_FLUSH:
        case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
-               ret = iwl_mvm_sta_tx_agg_stop(mvm, vif, sta, tid);
+               ret = iwl_mvm_sta_tx_agg_flush(mvm, vif, sta, tid);
                break;
        case IEEE80211_AMPDU_TX_OPERATIONAL:
                ret = iwl_mvm_sta_tx_agg_oper(mvm, vif, sta, tid, buf_size);
@@ -1090,7 +1126,8 @@ static void iwl_mvm_mac_update_tkip_key(struct ieee80211_hw *hw,
 static int iwl_mvm_roc(struct ieee80211_hw *hw,
                       struct ieee80211_vif *vif,
                       struct ieee80211_channel *channel,
-                      int duration)
+                      int duration,
+                      enum ieee80211_roc_type type)
 {
        struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
        struct cfg80211_chan_def chandef;
@@ -1101,8 +1138,8 @@ static int iwl_mvm_roc(struct ieee80211_hw *hw,
                return -EINVAL;
        }
 
-       IWL_DEBUG_MAC80211(mvm, "enter (%d, %d)\n", channel->hw_value,
-                          duration);
+       IWL_DEBUG_MAC80211(mvm, "enter (%d, %d, %d)\n", channel->hw_value,
+                          duration, type);
 
        mutex_lock(&mvm->mutex);
 
index bdae700..203eb85 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
@@ -79,7 +79,7 @@
 #include "fw-api.h"
 
 #define IWL_INVALID_MAC80211_QUEUE     0xff
-#define IWL_MVM_MAX_ADDRESSES          2
+#define IWL_MVM_MAX_ADDRESSES          5
 /* RSSI offset for WkP */
 #define IWL_RSSI_OFFSET 50
 
@@ -174,6 +174,8 @@ struct iwl_mvm_vif {
        bool uploaded;
        bool ap_active;
 
+       u32 ap_beacon_time;
+
        enum iwl_tsf_id tsf_id;
 
        /*
@@ -332,6 +334,10 @@ struct iwl_mvm {
 #ifdef CONFIG_PM_SLEEP
        int gtk_ivlen, gtk_icvlen, ptk_ivlen, ptk_icvlen;
 #endif
+
+       /* BT-Coex */
+       u8 bt_kill_msk;
+       struct iwl_bt_coex_profile_notif last_bt_notif;
 };
 
 /* Extract MVM priv from op_mode and _hw */
@@ -502,4 +508,11 @@ void iwl_mvm_ipv6_addr_change(struct ieee80211_hw *hw,
 void iwl_mvm_set_default_unicast_key(struct ieee80211_hw *hw,
                                     struct ieee80211_vif *vif, int idx);
 
+/* BT Coex */
+int iwl_send_bt_prio_tbl(struct iwl_mvm *mvm);
+int iwl_send_bt_init_conf(struct iwl_mvm *mvm);
+int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm,
+                            struct iwl_rx_cmd_buffer *rxb,
+                            struct iwl_device_cmd *cmd);
+
 #endif /* __IWL_MVM_H__ */
index 20016bc..93e3d0f 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
@@ -74,6 +74,9 @@ static const int nvm_to_read[] = {
        NVM_SECTION_TYPE_PRODUCTION,
 };
 
+/* Default NVM size to read */
+#define IWL_NVM_DEFAULT_CHUNK_SIZE (2*1024);
+
 /* used to simplify the shared operations on NCM_ACCESS_CMD versions */
 union iwl_nvm_access_cmd {
        struct iwl_nvm_access_cmd_ver1 ver1;
@@ -193,9 +196,9 @@ static int iwl_nvm_read_section(struct iwl_mvm *mvm, u16 section,
        int ret;
        bool old_eeprom = mvm->cfg->device_family != IWL_DEVICE_FAMILY_7000;
 
-       length = (iwlwifi_mod_params.amsdu_size_8K ? (8 * 1024) : (4 * 1024))
-               - sizeof(union iwl_nvm_access_cmd)
-               - sizeof(struct iwl_rx_packet);
+       /* Set nvm section read length */
+       length = IWL_NVM_DEFAULT_CHUNK_SIZE;
+
        /*
         * if length is greater than EEPROM size, truncate it because uCode
         * doesn't check it by itself, and exit the loop when reached.
index d0f9c1e..828bddd 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
@@ -230,6 +230,8 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {
        RX_HANDLER(SCAN_REQUEST_CMD, iwl_mvm_rx_scan_response, false),
        RX_HANDLER(SCAN_COMPLETE_NOTIFICATION, iwl_mvm_rx_scan_complete, false),
 
+       RX_HANDLER(BT_PROFILE_NOTIFICATION, iwl_mvm_rx_bt_coex_notif, true),
+
        RX_HANDLER(RADIO_VERSION_NOTIFICATION, iwl_mvm_rx_radio_ver, false),
        RX_HANDLER(CARD_STATE_NOTIFICATION, iwl_mvm_rx_card_state_notif, false),
 
@@ -293,6 +295,11 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = {
        CMD(NET_DETECT_PROFILES_CMD),
        CMD(NET_DETECT_HOTSPOTS_CMD),
        CMD(NET_DETECT_HOTSPOTS_QUERY_CMD),
+       CMD(CARD_STATE_NOTIFICATION),
+       CMD(BT_COEX_PRIO_TABLE),
+       CMD(BT_COEX_PROT_ENV),
+       CMD(BT_PROFILE_NOTIFICATION),
+       CMD(BT_CONFIG),
 };
 #undef CMD
 
@@ -363,8 +370,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
        trans_cfg.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds);
        trans_cfg.rx_buf_size_8k = iwlwifi_mod_params.amsdu_size_8K;
 
-       /* TODO: this should really be a TLV */
-       if (cfg->device_family == IWL_DEVICE_FAMILY_7000)
+       if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DW_BC_TABLE)
                trans_cfg.bc_table_dword = true;
 
        if (!iwlwifi_mod_params.wd_disable)
index b428448..0d537e0 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
index 5a92a49..efb9a6f 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
index 9256284..df85c49 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
index 56b636d..a01a661 100644 (file)
@@ -680,12 +680,14 @@ static int rs_toggle_antenna(u32 valid_ant, u32 *rate_n_flags,
  */
 static bool rs_use_green(struct ieee80211_sta *sta)
 {
-       struct iwl_mvm_sta *sta_priv = (void *)sta->drv_priv;
-
-       bool use_green = !(sta_priv->vif->bss_conf.ht_operation_mode &
-                               IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
-
-       return (sta->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD) && use_green;
+       /*
+        * There's a bug somewhere in this code that causes the
+        * scaling to get stuck because GF+SGI can't be combined
+        * in SISO rates. Until we find that bug, disable GF, it
+        * has only limited benefit and we still interoperate with
+        * GF APs since we can always receive GF transmissions.
+        */
+       return false;
 }
 
 /**
index b0b190d..4dfc21a 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
index 9b21b92..0d3c76b 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
index 274f44e..4d872d6 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
@@ -101,8 +101,55 @@ int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
        }
        add_sta_cmd.add_modify = update ? 1 : 0;
 
-       /* STA_FLG_FAT_EN_MSK ? */
-       /* STA_FLG_MIMO_EN_MSK ? */
+       add_sta_cmd.station_flags_msk |= cpu_to_le32(STA_FLG_FAT_EN_MSK |
+                                                    STA_FLG_MIMO_EN_MSK);
+
+       switch (sta->bandwidth) {
+       case IEEE80211_STA_RX_BW_160:
+               add_sta_cmd.station_flags |= cpu_to_le32(STA_FLG_FAT_EN_160MHZ);
+               /* fall through */
+       case IEEE80211_STA_RX_BW_80:
+               add_sta_cmd.station_flags |= cpu_to_le32(STA_FLG_FAT_EN_80MHZ);
+               /* fall through */
+       case IEEE80211_STA_RX_BW_40:
+               add_sta_cmd.station_flags |= cpu_to_le32(STA_FLG_FAT_EN_40MHZ);
+               /* fall through */
+       case IEEE80211_STA_RX_BW_20:
+               if (sta->ht_cap.ht_supported)
+                       add_sta_cmd.station_flags |=
+                               cpu_to_le32(STA_FLG_FAT_EN_20MHZ);
+               break;
+       }
+
+       switch (sta->rx_nss) {
+       case 1:
+               add_sta_cmd.station_flags |= cpu_to_le32(STA_FLG_MIMO_EN_SISO);
+               break;
+       case 2:
+               add_sta_cmd.station_flags |= cpu_to_le32(STA_FLG_MIMO_EN_MIMO2);
+               break;
+       case 3 ... 8:
+               add_sta_cmd.station_flags |= cpu_to_le32(STA_FLG_MIMO_EN_MIMO3);
+               break;
+       }
+
+       switch (sta->smps_mode) {
+       case IEEE80211_SMPS_AUTOMATIC:
+       case IEEE80211_SMPS_NUM_MODES:
+               WARN_ON(1);
+               break;
+       case IEEE80211_SMPS_STATIC:
+               /* override NSS */
+               add_sta_cmd.station_flags &= ~cpu_to_le32(STA_FLG_MIMO_EN_MSK);
+               add_sta_cmd.station_flags |= cpu_to_le32(STA_FLG_MIMO_EN_SISO);
+               break;
+       case IEEE80211_SMPS_DYNAMIC:
+               add_sta_cmd.station_flags |= cpu_to_le32(STA_FLG_RTS_MIMO_PROT);
+               break;
+       case IEEE80211_SMPS_OFF:
+               /* nothing */
+               break;
+       }
 
        if (sta->ht_cap.ht_supported) {
                add_sta_cmd.station_flags_msk |=
@@ -340,6 +387,9 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
 
        if (vif->type == NL80211_IFTYPE_STATION &&
            mvmvif->ap_sta_id == mvm_sta->sta_id) {
+               /* flush its queues here since we are freeing mvm_sta */
+               ret = iwl_mvm_flush_tx_path(mvm, mvm_sta->tfd_queue_msk, true);
+
                /*
                 * Put a non-NULL since the fw station isn't removed.
                 * It will be removed after the MAC will be set as
@@ -348,9 +398,6 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
                rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id],
                                   ERR_PTR(-EINVAL));
 
-               /* flush its queues here since we are freeing mvm_sta */
-               ret = iwl_mvm_flush_tx_path(mvm, mvm_sta->tfd_queue_msk, true);
-
                /* if we are associated - we can't remove the AP STA now */
                if (vif->bss_conf.assoc)
                        return ret;
@@ -686,7 +733,7 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
 
        spin_lock_bh(&mvmsta->lock);
        tid_data = &mvmsta->tid_data[tid];
-       tid_data->ssn = SEQ_TO_SN(tid_data->seq_number);
+       tid_data->ssn = IEEE80211_SEQ_TO_SN(tid_data->seq_number);
        tid_data->txq_id = txq_id;
        *ssn = tid_data->ssn;
 
@@ -789,7 +836,7 @@ int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
 
        switch (tid_data->state) {
        case IWL_AGG_ON:
-               tid_data->ssn = SEQ_TO_SN(tid_data->seq_number);
+               tid_data->ssn = IEEE80211_SEQ_TO_SN(tid_data->seq_number);
 
                IWL_DEBUG_TX_QUEUES(mvm,
                                    "ssn = %d, next_recl = %d\n",
@@ -834,6 +881,34 @@ int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
        return err;
 }
 
+int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+                           struct ieee80211_sta *sta, u16 tid)
+{
+       struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv;
+       struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid];
+       u16 txq_id;
+
+       /*
+        * First set the agg state to OFF to avoid calling
+        * ieee80211_stop_tx_ba_cb in iwl_mvm_check_ratid_empty.
+        */
+       spin_lock_bh(&mvmsta->lock);
+       txq_id = tid_data->txq_id;
+       IWL_DEBUG_TX_QUEUES(mvm, "Flush AGG: sta %d tid %d q %d state %d\n",
+                           mvmsta->sta_id, tid, txq_id, tid_data->state);
+       tid_data->state = IWL_AGG_OFF;
+       spin_unlock_bh(&mvmsta->lock);
+
+       if (iwl_mvm_flush_tx_path(mvm, BIT(txq_id), true))
+               IWL_ERR(mvm, "Couldn't flush the AGG queue\n");
+
+       iwl_trans_txq_disable(mvm->trans, tid_data->txq_id);
+       mvm->queue_to_mac80211[tid_data->txq_id] =
+                               IWL_INVALID_MAC80211_QUEUE;
+
+       return 0;
+}
+
 static int iwl_mvm_set_fw_key_idx(struct iwl_mvm *mvm)
 {
        int i;
index 896f88a..b0352df 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
@@ -348,6 +348,8 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
                        struct ieee80211_sta *sta, u16 tid, u8 buf_size);
 int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
                            struct ieee80211_sta *sta, u16 tid);
+int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+                           struct ieee80211_sta *sta, u16 tid);
 
 int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm);
 int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta,
index e437e02..c2c7f51 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
index 64fb57a..b36424e 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
index 6645efe..0556d5e 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
@@ -637,7 +637,7 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
                next_reclaimed = ssn;
        } else {
                /* The next packet to be reclaimed is the one after this one */
-               next_reclaimed = SEQ_TO_SN(seq_ctl + 0x10);
+               next_reclaimed = IEEE80211_SEQ_TO_SN(seq_ctl + 0x10);
        }
 
        IWL_DEBUG_TX_REPLY(mvm,
index 000e842..e308ad9 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
diff --git a/drivers/net/wireless/iwlwifi/pcie/1000.c b/drivers/net/wireless/iwlwifi/pcie/1000.c
deleted file mode 100644 (file)
index ff33897..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License 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.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- * The full GNU General Public License is included in this distribution in the
- * file called LICENSE.
- *
- * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- *****************************************************************************/
-
-#include <linux/module.h>
-#include <linux/stringify.h>
-#include "iwl-config.h"
-#include "iwl-csr.h"
-#include "iwl-agn-hw.h"
-#include "cfg.h"
-
-/* Highest firmware API version supported */
-#define IWL1000_UCODE_API_MAX 5
-#define IWL100_UCODE_API_MAX 5
-
-/* Oldest version we won't warn about */
-#define IWL1000_UCODE_API_OK 5
-#define IWL100_UCODE_API_OK 5
-
-/* Lowest firmware API version supported */
-#define IWL1000_UCODE_API_MIN 1
-#define IWL100_UCODE_API_MIN 5
-
-/* EEPROM version */
-#define EEPROM_1000_TX_POWER_VERSION   (4)
-#define EEPROM_1000_EEPROM_VERSION     (0x15C)
-
-#define IWL1000_FW_PRE "iwlwifi-1000-"
-#define IWL1000_MODULE_FIRMWARE(api) IWL1000_FW_PRE __stringify(api) ".ucode"
-
-#define IWL100_FW_PRE "iwlwifi-100-"
-#define IWL100_MODULE_FIRMWARE(api) IWL100_FW_PRE __stringify(api) ".ucode"
-
-
-static const struct iwl_base_params iwl1000_base_params = {
-       .num_of_queues = IWLAGN_NUM_QUEUES,
-       .eeprom_size = OTP_LOW_IMAGE_SIZE,
-       .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
-       .max_ll_items = OTP_MAX_LL_ITEMS_1000,
-       .shadow_ram_support = false,
-       .led_compensation = 51,
-       .support_ct_kill_exit = true,
-       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF,
-       .chain_noise_scale = 1000,
-       .wd_timeout = IWL_WATCHDOG_DISABLED,
-       .max_event_log_size = 128,
-};
-
-static const struct iwl_ht_params iwl1000_ht_params = {
-       .ht_greenfield_support = true,
-       .use_rts_for_aggregation = true, /* use rts/cts protection */
-       .ht40_bands = BIT(IEEE80211_BAND_2GHZ),
-};
-
-static const struct iwl_eeprom_params iwl1000_eeprom_params = {
-       .regulatory_bands = {
-               EEPROM_REG_BAND_1_CHANNELS,
-               EEPROM_REG_BAND_2_CHANNELS,
-               EEPROM_REG_BAND_3_CHANNELS,
-               EEPROM_REG_BAND_4_CHANNELS,
-               EEPROM_REG_BAND_5_CHANNELS,
-               EEPROM_REG_BAND_24_HT40_CHANNELS,
-               EEPROM_REGULATORY_BAND_NO_HT40,
-       }
-};
-
-#define IWL_DEVICE_1000                                                \
-       .fw_name_pre = IWL1000_FW_PRE,                          \
-       .ucode_api_max = IWL1000_UCODE_API_MAX,                 \
-       .ucode_api_ok = IWL1000_UCODE_API_OK,                   \
-       .ucode_api_min = IWL1000_UCODE_API_MIN,                 \
-       .device_family = IWL_DEVICE_FAMILY_1000,                \
-       .max_inst_size = IWLAGN_RTC_INST_SIZE,                  \
-       .max_data_size = IWLAGN_RTC_DATA_SIZE,                  \
-       .nvm_ver = EEPROM_1000_EEPROM_VERSION,          \
-       .nvm_calib_ver = EEPROM_1000_TX_POWER_VERSION,  \
-       .base_params = &iwl1000_base_params,                    \
-       .eeprom_params = &iwl1000_eeprom_params,                \
-       .led_mode = IWL_LED_BLINK
-
-const struct iwl_cfg iwl1000_bgn_cfg = {
-       .name = "Intel(R) Centrino(R) Wireless-N 1000 BGN",
-       IWL_DEVICE_1000,
-       .ht_params = &iwl1000_ht_params,
-};
-
-const struct iwl_cfg iwl1000_bg_cfg = {
-       .name = "Intel(R) Centrino(R) Wireless-N 1000 BG",
-       IWL_DEVICE_1000,
-};
-
-#define IWL_DEVICE_100                                         \
-       .fw_name_pre = IWL100_FW_PRE,                           \
-       .ucode_api_max = IWL100_UCODE_API_MAX,                  \
-       .ucode_api_ok = IWL100_UCODE_API_OK,                    \
-       .ucode_api_min = IWL100_UCODE_API_MIN,                  \
-       .device_family = IWL_DEVICE_FAMILY_100,                 \
-       .max_inst_size = IWLAGN_RTC_INST_SIZE,                  \
-       .max_data_size = IWLAGN_RTC_DATA_SIZE,                  \
-       .nvm_ver = EEPROM_1000_EEPROM_VERSION,          \
-       .nvm_calib_ver = EEPROM_1000_TX_POWER_VERSION,  \
-       .base_params = &iwl1000_base_params,                    \
-       .eeprom_params = &iwl1000_eeprom_params,                \
-       .led_mode = IWL_LED_RF_STATE,                           \
-       .rx_with_siso_diversity = true
-
-const struct iwl_cfg iwl100_bgn_cfg = {
-       .name = "Intel(R) Centrino(R) Wireless-N 100 BGN",
-       IWL_DEVICE_100,
-       .ht_params = &iwl1000_ht_params,
-};
-
-const struct iwl_cfg iwl100_bg_cfg = {
-       .name = "Intel(R) Centrino(R) Wireless-N 100 BG",
-       IWL_DEVICE_100,
-};
-
-MODULE_FIRMWARE(IWL1000_MODULE_FIRMWARE(IWL1000_UCODE_API_OK));
-MODULE_FIRMWARE(IWL100_MODULE_FIRMWARE(IWL100_UCODE_API_OK));
diff --git a/drivers/net/wireless/iwlwifi/pcie/2000.c b/drivers/net/wireless/iwlwifi/pcie/2000.c
deleted file mode 100644 (file)
index e7de331..0000000
+++ /dev/null
@@ -1,243 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License 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.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- * The full GNU General Public License is included in this distribution in the
- * file called LICENSE.
- *
- * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- *****************************************************************************/
-
-#include <linux/module.h>
-#include <linux/stringify.h>
-#include "iwl-config.h"
-#include "iwl-agn-hw.h"
-#include "cfg.h"
-#include "dvm/commands.h" /* needed for BT for now */
-
-/* Highest firmware API version supported */
-#define IWL2030_UCODE_API_MAX 6
-#define IWL2000_UCODE_API_MAX 6
-#define IWL105_UCODE_API_MAX 6
-#define IWL135_UCODE_API_MAX 6
-
-/* Oldest version we won't warn about */
-#define IWL2030_UCODE_API_OK 6
-#define IWL2000_UCODE_API_OK 6
-#define IWL105_UCODE_API_OK 6
-#define IWL135_UCODE_API_OK 6
-
-/* Lowest firmware API version supported */
-#define IWL2030_UCODE_API_MIN 5
-#define IWL2000_UCODE_API_MIN 5
-#define IWL105_UCODE_API_MIN 5
-#define IWL135_UCODE_API_MIN 5
-
-/* EEPROM version */
-#define EEPROM_2000_TX_POWER_VERSION   (6)
-#define EEPROM_2000_EEPROM_VERSION     (0x805)
-
-
-#define IWL2030_FW_PRE "iwlwifi-2030-"
-#define IWL2030_MODULE_FIRMWARE(api) IWL2030_FW_PRE __stringify(api) ".ucode"
-
-#define IWL2000_FW_PRE "iwlwifi-2000-"
-#define IWL2000_MODULE_FIRMWARE(api) IWL2000_FW_PRE __stringify(api) ".ucode"
-
-#define IWL105_FW_PRE "iwlwifi-105-"
-#define IWL105_MODULE_FIRMWARE(api) IWL105_FW_PRE __stringify(api) ".ucode"
-
-#define IWL135_FW_PRE "iwlwifi-135-"
-#define IWL135_MODULE_FIRMWARE(api) IWL135_FW_PRE __stringify(api) ".ucode"
-
-static const struct iwl_base_params iwl2000_base_params = {
-       .eeprom_size = OTP_LOW_IMAGE_SIZE,
-       .num_of_queues = IWLAGN_NUM_QUEUES,
-       .pll_cfg_val = 0,
-       .max_ll_items = OTP_MAX_LL_ITEMS_2x00,
-       .shadow_ram_support = true,
-       .led_compensation = 51,
-       .adv_thermal_throttle = true,
-       .support_ct_kill_exit = true,
-       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
-       .chain_noise_scale = 1000,
-       .wd_timeout = IWL_DEF_WD_TIMEOUT,
-       .max_event_log_size = 512,
-       .shadow_reg_enable = false, /* TODO: fix bugs using this feature */
-       .hd_v2 = true,
-};
-
-
-static const struct iwl_base_params iwl2030_base_params = {
-       .eeprom_size = OTP_LOW_IMAGE_SIZE,
-       .num_of_queues = IWLAGN_NUM_QUEUES,
-       .pll_cfg_val = 0,
-       .max_ll_items = OTP_MAX_LL_ITEMS_2x00,
-       .shadow_ram_support = true,
-       .led_compensation = 57,
-       .adv_thermal_throttle = true,
-       .support_ct_kill_exit = true,
-       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
-       .chain_noise_scale = 1000,
-       .wd_timeout = IWL_LONG_WD_TIMEOUT,
-       .max_event_log_size = 512,
-       .shadow_reg_enable = false, /* TODO: fix bugs using this feature */
-       .hd_v2 = true,
-};
-
-static const struct iwl_ht_params iwl2000_ht_params = {
-       .ht_greenfield_support = true,
-       .use_rts_for_aggregation = true, /* use rts/cts protection */
-       .ht40_bands = BIT(IEEE80211_BAND_2GHZ),
-};
-
-static const struct iwl_bt_params iwl2030_bt_params = {
-       /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
-       .advanced_bt_coexist = true,
-       .agg_time_limit = BT_AGG_THRESHOLD_DEF,
-       .bt_init_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_NONE,
-       .bt_prio_boost = IWLAGN_BT_PRIO_BOOST_DEFAULT32,
-       .bt_sco_disable = true,
-       .bt_session_2 = true,
-};
-
-static const struct iwl_eeprom_params iwl20x0_eeprom_params = {
-       .regulatory_bands = {
-               EEPROM_REG_BAND_1_CHANNELS,
-               EEPROM_REG_BAND_2_CHANNELS,
-               EEPROM_REG_BAND_3_CHANNELS,
-               EEPROM_REG_BAND_4_CHANNELS,
-               EEPROM_REG_BAND_5_CHANNELS,
-               EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
-               EEPROM_REGULATORY_BAND_NO_HT40,
-       },
-       .enhanced_txpower = true,
-};
-
-#define IWL_DEVICE_2000                                                \
-       .fw_name_pre = IWL2000_FW_PRE,                          \
-       .ucode_api_max = IWL2000_UCODE_API_MAX,                 \
-       .ucode_api_ok = IWL2000_UCODE_API_OK,                   \
-       .ucode_api_min = IWL2000_UCODE_API_MIN,                 \
-       .device_family = IWL_DEVICE_FAMILY_2000,                \
-       .max_inst_size = IWL60_RTC_INST_SIZE,                   \
-       .max_data_size = IWL60_RTC_DATA_SIZE,                   \
-       .nvm_ver = EEPROM_2000_EEPROM_VERSION,          \
-       .nvm_calib_ver = EEPROM_2000_TX_POWER_VERSION,  \
-       .base_params = &iwl2000_base_params,                    \
-       .eeprom_params = &iwl20x0_eeprom_params,                \
-       .need_temp_offset_calib = true,                         \
-       .temp_offset_v2 = true,                                 \
-       .led_mode = IWL_LED_RF_STATE
-
-const struct iwl_cfg iwl2000_2bgn_cfg = {
-       .name = "Intel(R) Centrino(R) Wireless-N 2200 BGN",
-       IWL_DEVICE_2000,
-       .ht_params = &iwl2000_ht_params,
-};
-
-const struct iwl_cfg iwl2000_2bgn_d_cfg = {
-       .name = "Intel(R) Centrino(R) Wireless-N 2200D BGN",
-       IWL_DEVICE_2000,
-       .ht_params = &iwl2000_ht_params,
-};
-
-#define IWL_DEVICE_2030                                                \
-       .fw_name_pre = IWL2030_FW_PRE,                          \
-       .ucode_api_max = IWL2030_UCODE_API_MAX,                 \
-       .ucode_api_ok = IWL2030_UCODE_API_OK,                   \
-       .ucode_api_min = IWL2030_UCODE_API_MIN,                 \
-       .device_family = IWL_DEVICE_FAMILY_2030,                \
-       .max_inst_size = IWL60_RTC_INST_SIZE,                   \
-       .max_data_size = IWL60_RTC_DATA_SIZE,                   \
-       .nvm_ver = EEPROM_2000_EEPROM_VERSION,          \
-       .nvm_calib_ver = EEPROM_2000_TX_POWER_VERSION,  \
-       .base_params = &iwl2030_base_params,                    \
-       .bt_params = &iwl2030_bt_params,                        \
-       .eeprom_params = &iwl20x0_eeprom_params,                \
-       .need_temp_offset_calib = true,                         \
-       .temp_offset_v2 = true,                                 \
-       .led_mode = IWL_LED_RF_STATE,                           \
-       .adv_pm = true
-
-const struct iwl_cfg iwl2030_2bgn_cfg = {
-       .name = "Intel(R) Centrino(R) Wireless-N 2230 BGN",
-       IWL_DEVICE_2030,
-       .ht_params = &iwl2000_ht_params,
-};
-
-#define IWL_DEVICE_105                                         \
-       .fw_name_pre = IWL105_FW_PRE,                           \
-       .ucode_api_max = IWL105_UCODE_API_MAX,                  \
-       .ucode_api_ok = IWL105_UCODE_API_OK,                    \
-       .ucode_api_min = IWL105_UCODE_API_MIN,                  \
-       .device_family = IWL_DEVICE_FAMILY_105,                 \
-       .max_inst_size = IWL60_RTC_INST_SIZE,                   \
-       .max_data_size = IWL60_RTC_DATA_SIZE,                   \
-       .nvm_ver = EEPROM_2000_EEPROM_VERSION,          \
-       .nvm_calib_ver = EEPROM_2000_TX_POWER_VERSION,  \
-       .base_params = &iwl2000_base_params,                    \
-       .eeprom_params = &iwl20x0_eeprom_params,                \
-       .need_temp_offset_calib = true,                         \
-       .temp_offset_v2 = true,                                 \
-       .led_mode = IWL_LED_RF_STATE,                           \
-       .adv_pm = true,                                         \
-       .rx_with_siso_diversity = true
-
-const struct iwl_cfg iwl105_bgn_cfg = {
-       .name = "Intel(R) Centrino(R) Wireless-N 105 BGN",
-       IWL_DEVICE_105,
-       .ht_params = &iwl2000_ht_params,
-};
-
-const struct iwl_cfg iwl105_bgn_d_cfg = {
-       .name = "Intel(R) Centrino(R) Wireless-N 105D BGN",
-       IWL_DEVICE_105,
-       .ht_params = &iwl2000_ht_params,
-};
-
-#define IWL_DEVICE_135                                         \
-       .fw_name_pre = IWL135_FW_PRE,                           \
-       .ucode_api_max = IWL135_UCODE_API_MAX,                  \
-       .ucode_api_ok = IWL135_UCODE_API_OK,                    \
-       .ucode_api_min = IWL135_UCODE_API_MIN,                  \
-       .device_family = IWL_DEVICE_FAMILY_135,                 \
-       .max_inst_size = IWL60_RTC_INST_SIZE,                   \
-       .max_data_size = IWL60_RTC_DATA_SIZE,                   \
-       .nvm_ver = EEPROM_2000_EEPROM_VERSION,          \
-       .nvm_calib_ver = EEPROM_2000_TX_POWER_VERSION,  \
-       .base_params = &iwl2030_base_params,                    \
-       .bt_params = &iwl2030_bt_params,                        \
-       .eeprom_params = &iwl20x0_eeprom_params,                \
-       .need_temp_offset_calib = true,                         \
-       .temp_offset_v2 = true,                                 \
-       .led_mode = IWL_LED_RF_STATE,                           \
-       .adv_pm = true,                                         \
-       .rx_with_siso_diversity = true
-
-const struct iwl_cfg iwl135_bgn_cfg = {
-       .name = "Intel(R) Centrino(R) Wireless-N 135 BGN",
-       IWL_DEVICE_135,
-       .ht_params = &iwl2000_ht_params,
-};
-
-MODULE_FIRMWARE(IWL2000_MODULE_FIRMWARE(IWL2000_UCODE_API_OK));
-MODULE_FIRMWARE(IWL2030_MODULE_FIRMWARE(IWL2030_UCODE_API_OK));
-MODULE_FIRMWARE(IWL105_MODULE_FIRMWARE(IWL105_UCODE_API_OK));
-MODULE_FIRMWARE(IWL135_MODULE_FIRMWARE(IWL135_UCODE_API_OK));
diff --git a/drivers/net/wireless/iwlwifi/pcie/5000.c b/drivers/net/wireless/iwlwifi/pcie/5000.c
deleted file mode 100644 (file)
index 5096f7c..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License 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.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- * The full GNU General Public License is included in this distribution in the
- * file called LICENSE.
- *
- * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- *****************************************************************************/
-
-#include <linux/module.h>
-#include <linux/stringify.h>
-#include "iwl-config.h"
-#include "iwl-agn-hw.h"
-#include "iwl-csr.h"
-#include "cfg.h"
-
-/* Highest firmware API version supported */
-#define IWL5000_UCODE_API_MAX 5
-#define IWL5150_UCODE_API_MAX 2
-
-/* Oldest version we won't warn about */
-#define IWL5000_UCODE_API_OK 5
-#define IWL5150_UCODE_API_OK 2
-
-/* Lowest firmware API version supported */
-#define IWL5000_UCODE_API_MIN 1
-#define IWL5150_UCODE_API_MIN 1
-
-/* EEPROM versions */
-#define EEPROM_5000_TX_POWER_VERSION   (4)
-#define EEPROM_5000_EEPROM_VERSION     (0x11A)
-#define EEPROM_5050_TX_POWER_VERSION   (4)
-#define EEPROM_5050_EEPROM_VERSION     (0x21E)
-
-#define IWL5000_FW_PRE "iwlwifi-5000-"
-#define IWL5000_MODULE_FIRMWARE(api) IWL5000_FW_PRE __stringify(api) ".ucode"
-
-#define IWL5150_FW_PRE "iwlwifi-5150-"
-#define IWL5150_MODULE_FIRMWARE(api) IWL5150_FW_PRE __stringify(api) ".ucode"
-
-static const struct iwl_base_params iwl5000_base_params = {
-       .eeprom_size = IWLAGN_EEPROM_IMG_SIZE,
-       .num_of_queues = IWLAGN_NUM_QUEUES,
-       .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
-       .led_compensation = 51,
-       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
-       .chain_noise_scale = 1000,
-       .wd_timeout = IWL_WATCHDOG_DISABLED,
-       .max_event_log_size = 512,
-       .no_idle_support = true,
-};
-
-static const struct iwl_ht_params iwl5000_ht_params = {
-       .ht_greenfield_support = true,
-       .ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ),
-};
-
-static const struct iwl_eeprom_params iwl5000_eeprom_params = {
-       .regulatory_bands = {
-               EEPROM_REG_BAND_1_CHANNELS,
-               EEPROM_REG_BAND_2_CHANNELS,
-               EEPROM_REG_BAND_3_CHANNELS,
-               EEPROM_REG_BAND_4_CHANNELS,
-               EEPROM_REG_BAND_5_CHANNELS,
-               EEPROM_REG_BAND_24_HT40_CHANNELS,
-               EEPROM_REG_BAND_52_HT40_CHANNELS
-       },
-};
-
-#define IWL_DEVICE_5000                                                \
-       .fw_name_pre = IWL5000_FW_PRE,                          \
-       .ucode_api_max = IWL5000_UCODE_API_MAX,                 \
-       .ucode_api_ok = IWL5000_UCODE_API_OK,                   \
-       .ucode_api_min = IWL5000_UCODE_API_MIN,                 \
-       .device_family = IWL_DEVICE_FAMILY_5000,                \
-       .max_inst_size = IWLAGN_RTC_INST_SIZE,                  \
-       .max_data_size = IWLAGN_RTC_DATA_SIZE,                  \
-       .nvm_ver = EEPROM_5000_EEPROM_VERSION,          \
-       .nvm_calib_ver = EEPROM_5000_TX_POWER_VERSION,  \
-       .base_params = &iwl5000_base_params,                    \
-       .eeprom_params = &iwl5000_eeprom_params,                \
-       .led_mode = IWL_LED_BLINK
-
-const struct iwl_cfg iwl5300_agn_cfg = {
-       .name = "Intel(R) Ultimate N WiFi Link 5300 AGN",
-       IWL_DEVICE_5000,
-       /* at least EEPROM 0x11A has wrong info */
-       .valid_tx_ant = ANT_ABC,        /* .cfg overwrite */
-       .valid_rx_ant = ANT_ABC,        /* .cfg overwrite */
-       .ht_params = &iwl5000_ht_params,
-};
-
-const struct iwl_cfg iwl5100_bgn_cfg = {
-       .name = "Intel(R) WiFi Link 5100 BGN",
-       IWL_DEVICE_5000,
-       .valid_tx_ant = ANT_B,          /* .cfg overwrite */
-       .valid_rx_ant = ANT_AB,         /* .cfg overwrite */
-       .ht_params = &iwl5000_ht_params,
-};
-
-const struct iwl_cfg iwl5100_abg_cfg = {
-       .name = "Intel(R) WiFi Link 5100 ABG",
-       IWL_DEVICE_5000,
-       .valid_tx_ant = ANT_B,          /* .cfg overwrite */
-       .valid_rx_ant = ANT_AB,         /* .cfg overwrite */
-};
-
-const struct iwl_cfg iwl5100_agn_cfg = {
-       .name = "Intel(R) WiFi Link 5100 AGN",
-       IWL_DEVICE_5000,
-       .valid_tx_ant = ANT_B,          /* .cfg overwrite */
-       .valid_rx_ant = ANT_AB,         /* .cfg overwrite */
-       .ht_params = &iwl5000_ht_params,
-};
-
-const struct iwl_cfg iwl5350_agn_cfg = {
-       .name = "Intel(R) WiMAX/WiFi Link 5350 AGN",
-       .fw_name_pre = IWL5000_FW_PRE,
-       .ucode_api_max = IWL5000_UCODE_API_MAX,
-       .ucode_api_ok = IWL5000_UCODE_API_OK,
-       .ucode_api_min = IWL5000_UCODE_API_MIN,
-       .device_family = IWL_DEVICE_FAMILY_5000,
-       .max_inst_size = IWLAGN_RTC_INST_SIZE,
-       .max_data_size = IWLAGN_RTC_DATA_SIZE,
-       .nvm_ver = EEPROM_5050_EEPROM_VERSION,
-       .nvm_calib_ver = EEPROM_5050_TX_POWER_VERSION,
-       .base_params = &iwl5000_base_params,
-       .eeprom_params = &iwl5000_eeprom_params,
-       .ht_params = &iwl5000_ht_params,
-       .led_mode = IWL_LED_BLINK,
-       .internal_wimax_coex = true,
-};
-
-#define IWL_DEVICE_5150                                                \
-       .fw_name_pre = IWL5150_FW_PRE,                          \
-       .ucode_api_max = IWL5150_UCODE_API_MAX,                 \
-       .ucode_api_ok = IWL5150_UCODE_API_OK,                   \
-       .ucode_api_min = IWL5150_UCODE_API_MIN,                 \
-       .device_family = IWL_DEVICE_FAMILY_5150,                \
-       .max_inst_size = IWLAGN_RTC_INST_SIZE,                  \
-       .max_data_size = IWLAGN_RTC_DATA_SIZE,                  \
-       .nvm_ver = EEPROM_5050_EEPROM_VERSION,          \
-       .nvm_calib_ver = EEPROM_5050_TX_POWER_VERSION,  \
-       .base_params = &iwl5000_base_params,                    \
-       .eeprom_params = &iwl5000_eeprom_params,                \
-       .no_xtal_calib = true,                                  \
-       .led_mode = IWL_LED_BLINK,                              \
-       .internal_wimax_coex = true
-
-const struct iwl_cfg iwl5150_agn_cfg = {
-       .name = "Intel(R) WiMAX/WiFi Link 5150 AGN",
-       IWL_DEVICE_5150,
-       .ht_params = &iwl5000_ht_params,
-
-};
-
-const struct iwl_cfg iwl5150_abg_cfg = {
-       .name = "Intel(R) WiMAX/WiFi Link 5150 ABG",
-       IWL_DEVICE_5150,
-};
-
-MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_OK));
-MODULE_FIRMWARE(IWL5150_MODULE_FIRMWARE(IWL5150_UCODE_API_OK));
diff --git a/drivers/net/wireless/iwlwifi/pcie/6000.c b/drivers/net/wireless/iwlwifi/pcie/6000.c
deleted file mode 100644 (file)
index 801ff49..0000000
+++ /dev/null
@@ -1,403 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License 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.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- * The full GNU General Public License is included in this distribution in the
- * file called LICENSE.
- *
- * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- *****************************************************************************/
-
-#include <linux/module.h>
-#include <linux/stringify.h>
-#include "iwl-config.h"
-#include "iwl-agn-hw.h"
-#include "cfg.h"
-#include "dvm/commands.h" /* needed for BT for now */
-
-/* Highest firmware API version supported */
-#define IWL6000_UCODE_API_MAX 6
-#define IWL6050_UCODE_API_MAX 5
-#define IWL6000G2_UCODE_API_MAX 6
-#define IWL6035_UCODE_API_MAX 6
-
-/* Oldest version we won't warn about */
-#define IWL6000_UCODE_API_OK 4
-#define IWL6000G2_UCODE_API_OK 5
-#define IWL6050_UCODE_API_OK 5
-#define IWL6000G2B_UCODE_API_OK 6
-#define IWL6035_UCODE_API_OK 6
-
-/* Lowest firmware API version supported */
-#define IWL6000_UCODE_API_MIN 4
-#define IWL6050_UCODE_API_MIN 4
-#define IWL6000G2_UCODE_API_MIN 5
-#define IWL6035_UCODE_API_MIN 6
-
-/* EEPROM versions */
-#define EEPROM_6000_TX_POWER_VERSION   (4)
-#define EEPROM_6000_EEPROM_VERSION     (0x423)
-#define EEPROM_6050_TX_POWER_VERSION   (4)
-#define EEPROM_6050_EEPROM_VERSION     (0x532)
-#define EEPROM_6150_TX_POWER_VERSION   (6)
-#define EEPROM_6150_EEPROM_VERSION     (0x553)
-#define EEPROM_6005_TX_POWER_VERSION   (6)
-#define EEPROM_6005_EEPROM_VERSION     (0x709)
-#define EEPROM_6030_TX_POWER_VERSION   (6)
-#define EEPROM_6030_EEPROM_VERSION     (0x709)
-#define EEPROM_6035_TX_POWER_VERSION   (6)
-#define EEPROM_6035_EEPROM_VERSION     (0x753)
-
-#define IWL6000_FW_PRE "iwlwifi-6000-"
-#define IWL6000_MODULE_FIRMWARE(api) IWL6000_FW_PRE __stringify(api) ".ucode"
-
-#define IWL6050_FW_PRE "iwlwifi-6050-"
-#define IWL6050_MODULE_FIRMWARE(api) IWL6050_FW_PRE __stringify(api) ".ucode"
-
-#define IWL6005_FW_PRE "iwlwifi-6000g2a-"
-#define IWL6005_MODULE_FIRMWARE(api) IWL6005_FW_PRE __stringify(api) ".ucode"
-
-#define IWL6030_FW_PRE "iwlwifi-6000g2b-"
-#define IWL6030_MODULE_FIRMWARE(api) IWL6030_FW_PRE __stringify(api) ".ucode"
-
-static const struct iwl_base_params iwl6000_base_params = {
-       .eeprom_size = OTP_LOW_IMAGE_SIZE,
-       .num_of_queues = IWLAGN_NUM_QUEUES,
-       .pll_cfg_val = 0,
-       .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
-       .shadow_ram_support = true,
-       .led_compensation = 51,
-       .adv_thermal_throttle = true,
-       .support_ct_kill_exit = true,
-       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
-       .chain_noise_scale = 1000,
-       .wd_timeout = IWL_DEF_WD_TIMEOUT,
-       .max_event_log_size = 512,
-       .shadow_reg_enable = false, /* TODO: fix bugs using this feature */
-};
-
-static const struct iwl_base_params iwl6050_base_params = {
-       .eeprom_size = OTP_LOW_IMAGE_SIZE,
-       .num_of_queues = IWLAGN_NUM_QUEUES,
-       .pll_cfg_val = 0,
-       .max_ll_items = OTP_MAX_LL_ITEMS_6x50,
-       .shadow_ram_support = true,
-       .led_compensation = 51,
-       .adv_thermal_throttle = true,
-       .support_ct_kill_exit = true,
-       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
-       .chain_noise_scale = 1500,
-       .wd_timeout = IWL_DEF_WD_TIMEOUT,
-       .max_event_log_size = 1024,
-       .shadow_reg_enable = false, /* TODO: fix bugs using this feature */
-};
-
-static const struct iwl_base_params iwl6000_g2_base_params = {
-       .eeprom_size = OTP_LOW_IMAGE_SIZE,
-       .num_of_queues = IWLAGN_NUM_QUEUES,
-       .pll_cfg_val = 0,
-       .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
-       .shadow_ram_support = true,
-       .led_compensation = 57,
-       .adv_thermal_throttle = true,
-       .support_ct_kill_exit = true,
-       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
-       .chain_noise_scale = 1000,
-       .wd_timeout = IWL_LONG_WD_TIMEOUT,
-       .max_event_log_size = 512,
-       .shadow_reg_enable = false, /* TODO: fix bugs using this feature */
-};
-
-static const struct iwl_ht_params iwl6000_ht_params = {
-       .ht_greenfield_support = true,
-       .use_rts_for_aggregation = true, /* use rts/cts protection */
-       .ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ),
-};
-
-static const struct iwl_bt_params iwl6000_bt_params = {
-       /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
-       .advanced_bt_coexist = true,
-       .agg_time_limit = BT_AGG_THRESHOLD_DEF,
-       .bt_init_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_NONE,
-       .bt_prio_boost = IWLAGN_BT_PRIO_BOOST_DEFAULT,
-       .bt_sco_disable = true,
-};
-
-static const struct iwl_eeprom_params iwl6000_eeprom_params = {
-       .regulatory_bands = {
-               EEPROM_REG_BAND_1_CHANNELS,
-               EEPROM_REG_BAND_2_CHANNELS,
-               EEPROM_REG_BAND_3_CHANNELS,
-               EEPROM_REG_BAND_4_CHANNELS,
-               EEPROM_REG_BAND_5_CHANNELS,
-               EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
-               EEPROM_REG_BAND_52_HT40_CHANNELS
-       },
-       .enhanced_txpower = true,
-};
-
-#define IWL_DEVICE_6005                                                \
-       .fw_name_pre = IWL6005_FW_PRE,                          \
-       .ucode_api_max = IWL6000G2_UCODE_API_MAX,               \
-       .ucode_api_ok = IWL6000G2_UCODE_API_OK,                 \
-       .ucode_api_min = IWL6000G2_UCODE_API_MIN,               \
-       .device_family = IWL_DEVICE_FAMILY_6005,                \
-       .max_inst_size = IWL60_RTC_INST_SIZE,                   \
-       .max_data_size = IWL60_RTC_DATA_SIZE,                   \
-       .nvm_ver = EEPROM_6005_EEPROM_VERSION,          \
-       .nvm_calib_ver = EEPROM_6005_TX_POWER_VERSION,  \
-       .base_params = &iwl6000_g2_base_params,                 \
-       .eeprom_params = &iwl6000_eeprom_params,                \
-       .need_temp_offset_calib = true,                         \
-       .led_mode = IWL_LED_RF_STATE
-
-const struct iwl_cfg iwl6005_2agn_cfg = {
-       .name = "Intel(R) Centrino(R) Advanced-N 6205 AGN",
-       IWL_DEVICE_6005,
-       .ht_params = &iwl6000_ht_params,
-};
-
-const struct iwl_cfg iwl6005_2abg_cfg = {
-       .name = "Intel(R) Centrino(R) Advanced-N 6205 ABG",
-       IWL_DEVICE_6005,
-};
-
-const struct iwl_cfg iwl6005_2bg_cfg = {
-       .name = "Intel(R) Centrino(R) Advanced-N 6205 BG",
-       IWL_DEVICE_6005,
-};
-
-const struct iwl_cfg iwl6005_2agn_sff_cfg = {
-       .name = "Intel(R) Centrino(R) Advanced-N 6205S AGN",
-       IWL_DEVICE_6005,
-       .ht_params = &iwl6000_ht_params,
-};
-
-const struct iwl_cfg iwl6005_2agn_d_cfg = {
-       .name = "Intel(R) Centrino(R) Advanced-N 6205D AGN",
-       IWL_DEVICE_6005,
-       .ht_params = &iwl6000_ht_params,
-};
-
-const struct iwl_cfg iwl6005_2agn_mow1_cfg = {
-       .name = "Intel(R) Centrino(R) Advanced-N 6206 AGN",
-       IWL_DEVICE_6005,
-       .ht_params = &iwl6000_ht_params,
-};
-
-const struct iwl_cfg iwl6005_2agn_mow2_cfg = {
-       .name = "Intel(R) Centrino(R) Advanced-N 6207 AGN",
-       IWL_DEVICE_6005,
-       .ht_params = &iwl6000_ht_params,
-};
-
-#define IWL_DEVICE_6030                                                \
-       .fw_name_pre = IWL6030_FW_PRE,                          \
-       .ucode_api_max = IWL6000G2_UCODE_API_MAX,               \
-       .ucode_api_ok = IWL6000G2B_UCODE_API_OK,                \
-       .ucode_api_min = IWL6000G2_UCODE_API_MIN,               \
-       .device_family = IWL_DEVICE_FAMILY_6030,                \
-       .max_inst_size = IWL60_RTC_INST_SIZE,                   \
-       .max_data_size = IWL60_RTC_DATA_SIZE,                   \
-       .nvm_ver = EEPROM_6030_EEPROM_VERSION,          \
-       .nvm_calib_ver = EEPROM_6030_TX_POWER_VERSION,  \
-       .base_params = &iwl6000_g2_base_params,                 \
-       .bt_params = &iwl6000_bt_params,                        \
-       .eeprom_params = &iwl6000_eeprom_params,                \
-       .need_temp_offset_calib = true,                         \
-       .led_mode = IWL_LED_RF_STATE,                           \
-       .adv_pm = true                                          \
-
-const struct iwl_cfg iwl6030_2agn_cfg = {
-       .name = "Intel(R) Centrino(R) Advanced-N 6230 AGN",
-       IWL_DEVICE_6030,
-       .ht_params = &iwl6000_ht_params,
-};
-
-const struct iwl_cfg iwl6030_2abg_cfg = {
-       .name = "Intel(R) Centrino(R) Advanced-N 6230 ABG",
-       IWL_DEVICE_6030,
-};
-
-const struct iwl_cfg iwl6030_2bgn_cfg = {
-       .name = "Intel(R) Centrino(R) Advanced-N 6230 BGN",
-       IWL_DEVICE_6030,
-       .ht_params = &iwl6000_ht_params,
-};
-
-const struct iwl_cfg iwl6030_2bg_cfg = {
-       .name = "Intel(R) Centrino(R) Advanced-N 6230 BG",
-       IWL_DEVICE_6030,
-};
-
-#define IWL_DEVICE_6035                                                \
-       .fw_name_pre = IWL6030_FW_PRE,                          \
-       .ucode_api_max = IWL6035_UCODE_API_MAX,                 \
-       .ucode_api_ok = IWL6035_UCODE_API_OK,                   \
-       .ucode_api_min = IWL6035_UCODE_API_MIN,                 \
-       .device_family = IWL_DEVICE_FAMILY_6030,                \
-       .max_inst_size = IWL60_RTC_INST_SIZE,                   \
-       .max_data_size = IWL60_RTC_DATA_SIZE,                   \
-       .nvm_ver = EEPROM_6030_EEPROM_VERSION,          \
-       .nvm_calib_ver = EEPROM_6030_TX_POWER_VERSION,  \
-       .base_params = &iwl6000_g2_base_params,                 \
-       .bt_params = &iwl6000_bt_params,                        \
-       .eeprom_params = &iwl6000_eeprom_params,                \
-       .need_temp_offset_calib = true,                         \
-       .led_mode = IWL_LED_RF_STATE,                           \
-       .adv_pm = true
-
-const struct iwl_cfg iwl6035_2agn_cfg = {
-       .name = "Intel(R) Centrino(R) Advanced-N 6235 AGN",
-       IWL_DEVICE_6035,
-       .ht_params = &iwl6000_ht_params,
-};
-
-const struct iwl_cfg iwl1030_bgn_cfg = {
-       .name = "Intel(R) Centrino(R) Wireless-N 1030 BGN",
-       IWL_DEVICE_6030,
-       .ht_params = &iwl6000_ht_params,
-};
-
-const struct iwl_cfg iwl1030_bg_cfg = {
-       .name = "Intel(R) Centrino(R) Wireless-N 1030 BG",
-       IWL_DEVICE_6030,
-};
-
-const struct iwl_cfg iwl130_bgn_cfg = {
-       .name = "Intel(R) Centrino(R) Wireless-N 130 BGN",
-       IWL_DEVICE_6030,
-       .ht_params = &iwl6000_ht_params,
-       .rx_with_siso_diversity = true,
-};
-
-const struct iwl_cfg iwl130_bg_cfg = {
-       .name = "Intel(R) Centrino(R) Wireless-N 130 BG",
-       IWL_DEVICE_6030,
-       .rx_with_siso_diversity = true,
-};
-
-/*
- * "i": Internal configuration, use internal Power Amplifier
- */
-#define IWL_DEVICE_6000i                                       \
-       .fw_name_pre = IWL6000_FW_PRE,                          \
-       .ucode_api_max = IWL6000_UCODE_API_MAX,                 \
-       .ucode_api_ok = IWL6000_UCODE_API_OK,                   \
-       .ucode_api_min = IWL6000_UCODE_API_MIN,                 \
-       .device_family = IWL_DEVICE_FAMILY_6000i,               \
-       .max_inst_size = IWL60_RTC_INST_SIZE,                   \
-       .max_data_size = IWL60_RTC_DATA_SIZE,                   \
-       .valid_tx_ant = ANT_BC,         /* .cfg overwrite */    \
-       .valid_rx_ant = ANT_BC,         /* .cfg overwrite */    \
-       .nvm_ver = EEPROM_6000_EEPROM_VERSION,          \
-       .nvm_calib_ver = EEPROM_6000_TX_POWER_VERSION,  \
-       .base_params = &iwl6000_base_params,                    \
-       .eeprom_params = &iwl6000_eeprom_params,                \
-       .led_mode = IWL_LED_BLINK
-
-const struct iwl_cfg iwl6000i_2agn_cfg = {
-       .name = "Intel(R) Centrino(R) Advanced-N 6200 AGN",
-       IWL_DEVICE_6000i,
-       .ht_params = &iwl6000_ht_params,
-};
-
-const struct iwl_cfg iwl6000i_2abg_cfg = {
-       .name = "Intel(R) Centrino(R) Advanced-N 6200 ABG",
-       IWL_DEVICE_6000i,
-};
-
-const struct iwl_cfg iwl6000i_2bg_cfg = {
-       .name = "Intel(R) Centrino(R) Advanced-N 6200 BG",
-       IWL_DEVICE_6000i,
-};
-
-#define IWL_DEVICE_6050                                                \
-       .fw_name_pre = IWL6050_FW_PRE,                          \
-       .ucode_api_max = IWL6050_UCODE_API_MAX,                 \
-       .ucode_api_min = IWL6050_UCODE_API_MIN,                 \
-       .device_family = IWL_DEVICE_FAMILY_6050,                \
-       .max_inst_size = IWL60_RTC_INST_SIZE,                   \
-       .max_data_size = IWL60_RTC_DATA_SIZE,                   \
-       .valid_tx_ant = ANT_AB,         /* .cfg overwrite */    \
-       .valid_rx_ant = ANT_AB,         /* .cfg overwrite */    \
-       .nvm_ver = EEPROM_6050_EEPROM_VERSION,          \
-       .nvm_calib_ver = EEPROM_6050_TX_POWER_VERSION,  \
-       .base_params = &iwl6050_base_params,                    \
-       .eeprom_params = &iwl6000_eeprom_params,                \
-       .led_mode = IWL_LED_BLINK,                              \
-       .internal_wimax_coex = true
-
-const struct iwl_cfg iwl6050_2agn_cfg = {
-       .name = "Intel(R) Centrino(R) Advanced-N + WiMAX 6250 AGN",
-       IWL_DEVICE_6050,
-       .ht_params = &iwl6000_ht_params,
-};
-
-const struct iwl_cfg iwl6050_2abg_cfg = {
-       .name = "Intel(R) Centrino(R) Advanced-N + WiMAX 6250 ABG",
-       IWL_DEVICE_6050,
-};
-
-#define IWL_DEVICE_6150                                                \
-       .fw_name_pre = IWL6050_FW_PRE,                          \
-       .ucode_api_max = IWL6050_UCODE_API_MAX,                 \
-       .ucode_api_min = IWL6050_UCODE_API_MIN,                 \
-       .device_family = IWL_DEVICE_FAMILY_6150,                \
-       .max_inst_size = IWL60_RTC_INST_SIZE,                   \
-       .max_data_size = IWL60_RTC_DATA_SIZE,                   \
-       .nvm_ver = EEPROM_6150_EEPROM_VERSION,          \
-       .nvm_calib_ver = EEPROM_6150_TX_POWER_VERSION,  \
-       .base_params = &iwl6050_base_params,                    \
-       .eeprom_params = &iwl6000_eeprom_params,                \
-       .led_mode = IWL_LED_BLINK,                              \
-       .internal_wimax_coex = true
-
-const struct iwl_cfg iwl6150_bgn_cfg = {
-       .name = "Intel(R) Centrino(R) Wireless-N + WiMAX 6150 BGN",
-       IWL_DEVICE_6150,
-       .ht_params = &iwl6000_ht_params,
-};
-
-const struct iwl_cfg iwl6150_bg_cfg = {
-       .name = "Intel(R) Centrino(R) Wireless-N + WiMAX 6150 BG",
-       IWL_DEVICE_6150,
-};
-
-const struct iwl_cfg iwl6000_3agn_cfg = {
-       .name = "Intel(R) Centrino(R) Ultimate-N 6300 AGN",
-       .fw_name_pre = IWL6000_FW_PRE,
-       .ucode_api_max = IWL6000_UCODE_API_MAX,
-       .ucode_api_ok = IWL6000_UCODE_API_OK,
-       .ucode_api_min = IWL6000_UCODE_API_MIN,
-       .device_family = IWL_DEVICE_FAMILY_6000,
-       .max_inst_size = IWL60_RTC_INST_SIZE,
-       .max_data_size = IWL60_RTC_DATA_SIZE,
-       .nvm_ver = EEPROM_6000_EEPROM_VERSION,
-       .nvm_calib_ver = EEPROM_6000_TX_POWER_VERSION,
-       .base_params = &iwl6000_base_params,
-       .eeprom_params = &iwl6000_eeprom_params,
-       .ht_params = &iwl6000_ht_params,
-       .led_mode = IWL_LED_BLINK,
-};
-
-MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_OK));
-MODULE_FIRMWARE(IWL6050_MODULE_FIRMWARE(IWL6050_UCODE_API_OK));
-MODULE_FIRMWARE(IWL6005_MODULE_FIRMWARE(IWL6000G2_UCODE_API_OK));
-MODULE_FIRMWARE(IWL6030_MODULE_FIRMWARE(IWL6000G2B_UCODE_API_OK));
diff --git a/drivers/net/wireless/iwlwifi/pcie/7000.c b/drivers/net/wireless/iwlwifi/pcie/7000.c
deleted file mode 100644 (file)
index 6e35b2b..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License 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.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- * The full GNU General Public License is included in this distribution in the
- * file called LICENSE.
- *
- * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- *****************************************************************************/
-
-#include <linux/module.h>
-#include <linux/stringify.h>
-#include "iwl-config.h"
-#include "iwl-agn-hw.h"
-#include "cfg.h"
-
-/* Highest firmware API version supported */
-#define IWL7260_UCODE_API_MAX  6
-#define IWL3160_UCODE_API_MAX  6
-
-/* Oldest version we won't warn about */
-#define IWL7260_UCODE_API_OK   6
-#define IWL3160_UCODE_API_OK   6
-
-/* Lowest firmware API version supported */
-#define IWL7260_UCODE_API_MIN  6
-#define IWL3160_UCODE_API_MIN  6
-
-/* NVM versions */
-#define IWL7260_NVM_VERSION            0x0a1d
-#define IWL7260_TX_POWER_VERSION       0xffff /* meaningless */
-#define IWL3160_NVM_VERSION            0x709
-#define IWL3160_TX_POWER_VERSION       0xffff /* meaningless */
-
-#define IWL7260_FW_PRE "iwlwifi-7260-"
-#define IWL7260_MODULE_FIRMWARE(api) IWL7260_FW_PRE __stringify(api) ".ucode"
-
-#define IWL3160_FW_PRE "iwlwifi-3160-"
-#define IWL3160_MODULE_FIRMWARE(api) IWL3160_FW_PRE __stringify(api) ".ucode"
-
-static const struct iwl_base_params iwl7000_base_params = {
-       .eeprom_size = OTP_LOW_IMAGE_SIZE,
-       .num_of_queues = IWLAGN_NUM_QUEUES,
-       .pll_cfg_val = 0,
-       .shadow_ram_support = true,
-       .led_compensation = 57,
-       .adv_thermal_throttle = true,
-       .support_ct_kill_exit = true,
-       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
-       .chain_noise_scale = 1000,
-       .wd_timeout = IWL_LONG_WD_TIMEOUT,
-       .max_event_log_size = 512,
-       .shadow_reg_enable = false, /* TODO: fix bugs using this feature */
-};
-
-static const struct iwl_ht_params iwl7000_ht_params = {
-       .ht_greenfield_support = true,
-       .use_rts_for_aggregation = true, /* use rts/cts protection */
-       .ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ),
-};
-
-#define IWL_DEVICE_7000                                                \
-       .ucode_api_max = IWL7260_UCODE_API_MAX,                 \
-       .ucode_api_ok = IWL7260_UCODE_API_OK,                   \
-       .ucode_api_min = IWL7260_UCODE_API_MIN,                 \
-       .device_family = IWL_DEVICE_FAMILY_7000,                \
-       .max_inst_size = IWL60_RTC_INST_SIZE,                   \
-       .max_data_size = IWL60_RTC_DATA_SIZE,                   \
-       .base_params = &iwl7000_base_params,                    \
-       /* TODO: .bt_params? */                                 \
-       .need_temp_offset_calib = true,                         \
-       .led_mode = IWL_LED_RF_STATE,                           \
-       .adv_pm = true                                          \
-
-
-const struct iwl_cfg iwl7260_2ac_cfg = {
-       .name = "Intel(R) Dual Band Wireless AC7260",
-       .fw_name_pre = IWL7260_FW_PRE,
-       IWL_DEVICE_7000,
-       .ht_params = &iwl7000_ht_params,
-       .nvm_ver = IWL7260_NVM_VERSION,
-       .nvm_calib_ver = IWL7260_TX_POWER_VERSION,
-};
-
-const struct iwl_cfg iwl3160_ac_cfg = {
-       .name = "Intel(R) Dual Band Wireless AC3160",
-       .fw_name_pre = IWL3160_FW_PRE,
-       IWL_DEVICE_7000,
-       .ht_params = &iwl7000_ht_params,
-       .nvm_ver = IWL3160_NVM_VERSION,
-       .nvm_calib_ver = IWL3160_TX_POWER_VERSION,
-};
-
-MODULE_FIRMWARE(IWL7260_MODULE_FIRMWARE(IWL7260_UCODE_API_OK));
-MODULE_FIRMWARE(IWL3160_MODULE_FIRMWARE(IWL3160_UCODE_API_OK));
diff --git a/drivers/net/wireless/iwlwifi/pcie/cfg.h b/drivers/net/wireless/iwlwifi/pcie/cfg.h
deleted file mode 100644 (file)
index c6f8e83..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-/******************************************************************************
- *
- * This file is provided under a dual BSD/GPLv2 license.  When using or
- * redistributing this file, you may do so under either license.
- *
- * GPL LICENSE SUMMARY
- *
- * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
- * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
- *
- * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- * BSD LICENSE
- *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *  * Neither the name Intel Corporation nor the names of its
- *    contributors may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *****************************************************************************/
-#ifndef __iwl_pci_h__
-#define __iwl_pci_h__
-
-
-/*
- * This file declares the config structures for all devices.
- */
-
-extern const struct iwl_cfg iwl5300_agn_cfg;
-extern const struct iwl_cfg iwl5100_agn_cfg;
-extern const struct iwl_cfg iwl5350_agn_cfg;
-extern const struct iwl_cfg iwl5100_bgn_cfg;
-extern const struct iwl_cfg iwl5100_abg_cfg;
-extern const struct iwl_cfg iwl5150_agn_cfg;
-extern const struct iwl_cfg iwl5150_abg_cfg;
-extern const struct iwl_cfg iwl6005_2agn_cfg;
-extern const struct iwl_cfg iwl6005_2abg_cfg;
-extern const struct iwl_cfg iwl6005_2bg_cfg;
-extern const struct iwl_cfg iwl6005_2agn_sff_cfg;
-extern const struct iwl_cfg iwl6005_2agn_d_cfg;
-extern const struct iwl_cfg iwl6005_2agn_mow1_cfg;
-extern const struct iwl_cfg iwl6005_2agn_mow2_cfg;
-extern const struct iwl_cfg iwl1030_bgn_cfg;
-extern const struct iwl_cfg iwl1030_bg_cfg;
-extern const struct iwl_cfg iwl6030_2agn_cfg;
-extern const struct iwl_cfg iwl6030_2abg_cfg;
-extern const struct iwl_cfg iwl6030_2bgn_cfg;
-extern const struct iwl_cfg iwl6030_2bg_cfg;
-extern const struct iwl_cfg iwl6000i_2agn_cfg;
-extern const struct iwl_cfg iwl6000i_2abg_cfg;
-extern const struct iwl_cfg iwl6000i_2bg_cfg;
-extern const struct iwl_cfg iwl6000_3agn_cfg;
-extern const struct iwl_cfg iwl6050_2agn_cfg;
-extern const struct iwl_cfg iwl6050_2abg_cfg;
-extern const struct iwl_cfg iwl6150_bgn_cfg;
-extern const struct iwl_cfg iwl6150_bg_cfg;
-extern const struct iwl_cfg iwl1000_bgn_cfg;
-extern const struct iwl_cfg iwl1000_bg_cfg;
-extern const struct iwl_cfg iwl100_bgn_cfg;
-extern const struct iwl_cfg iwl100_bg_cfg;
-extern const struct iwl_cfg iwl130_bgn_cfg;
-extern const struct iwl_cfg iwl130_bg_cfg;
-extern const struct iwl_cfg iwl2000_2bgn_cfg;
-extern const struct iwl_cfg iwl2000_2bgn_d_cfg;
-extern const struct iwl_cfg iwl2030_2bgn_cfg;
-extern const struct iwl_cfg iwl6035_2agn_cfg;
-extern const struct iwl_cfg iwl105_bgn_cfg;
-extern const struct iwl_cfg iwl105_bgn_d_cfg;
-extern const struct iwl_cfg iwl135_bgn_cfg;
-extern const struct iwl_cfg iwl7260_2ac_cfg;
-extern const struct iwl_cfg iwl3160_ac_cfg;
-
-#endif /* __iwl_pci_h__ */
index 7bc0fb9..46ca91f 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
@@ -69,8 +69,6 @@
 
 #include "iwl-trans.h"
 #include "iwl-drv.h"
-
-#include "cfg.h"
 #include "internal.h"
 
 #define IWL_PCI_DEVICE(dev, subdev, cfg) \
index 17bedc5..6649e37 100644 (file)
@@ -22,7 +22,7 @@
  * USA
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
  *
  * Contact Information:
  *  Intel Linux Wireless <ilw@linux.intel.com>
@@ -715,7 +715,8 @@ static u32 iwl_trans_pcie_read32(struct iwl_trans *trans, u32 ofs)
 
 static u32 iwl_trans_pcie_read_prph(struct iwl_trans *trans, u32 reg)
 {
-       iwl_trans_pcie_write32(trans, HBUS_TARG_PRPH_RADDR, reg | (3 << 24));
+       iwl_trans_pcie_write32(trans, HBUS_TARG_PRPH_RADDR,
+                              ((reg & 0x000FFFFF) | (3 << 24)));
        return iwl_trans_pcie_read32(trans, HBUS_TARG_PRPH_RDAT);
 }
 
@@ -723,7 +724,7 @@ static void iwl_trans_pcie_write_prph(struct iwl_trans *trans, u32 addr,
                                      u32 val)
 {
        iwl_trans_pcie_write32(trans, HBUS_TARG_PRPH_WADDR,
-                              ((addr & 0x0000FFFF) | (3 << 24)));
+                              ((addr & 0x000FFFFF) | (3 << 24)));
        iwl_trans_pcie_write32(trans, HBUS_TARG_PRPH_WDAT, val);
 }
 
@@ -1370,28 +1371,11 @@ static ssize_t iwl_dbgfs_fh_reg_read(struct file *file,
        return ret;
 }
 
-static ssize_t iwl_dbgfs_fw_restart_write(struct file *file,
-                                         const char __user *user_buf,
-                                         size_t count, loff_t *ppos)
-{
-       struct iwl_trans *trans = file->private_data;
-
-       if (!trans->op_mode)
-               return -EAGAIN;
-
-       local_bh_disable();
-       iwl_op_mode_nic_error(trans->op_mode);
-       local_bh_enable();
-
-       return count;
-}
-
 DEBUGFS_READ_WRITE_FILE_OPS(interrupt);
 DEBUGFS_READ_FILE_OPS(fh_reg);
 DEBUGFS_READ_FILE_OPS(rx_queue);
 DEBUGFS_READ_FILE_OPS(tx_queue);
 DEBUGFS_WRITE_FILE_OPS(csr);
-DEBUGFS_WRITE_FILE_OPS(fw_restart);
 
 /*
  * Create the debugfs files and directories
@@ -1405,7 +1389,6 @@ static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,
        DEBUGFS_ADD_FILE(interrupt, dir, S_IWUSR | S_IRUSR);
        DEBUGFS_ADD_FILE(csr, dir, S_IWUSR);
        DEBUGFS_ADD_FILE(fh_reg, dir, S_IRUSR);
-       DEBUGFS_ADD_FILE(fw_restart, dir, S_IWUSR);
        return 0;
 
 err:
index 8595c16..84f4634 100644 (file)
@@ -1609,7 +1609,7 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
         * 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));
+       wifi_seq = IEEE80211_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",
index cffdf4f..7490c4f 100644 (file)
@@ -1535,7 +1535,8 @@ static void hw_roc_done(struct work_struct *work)
 static int mac80211_hwsim_roc(struct ieee80211_hw *hw,
                              struct ieee80211_vif *vif,
                              struct ieee80211_channel *chan,
-                             int duration)
+                             int duration,
+                             enum ieee80211_roc_type type)
 {
        struct mac80211_hwsim_data *hwsim = hw->priv;
 
index 97b245c..ecf2846 100644 (file)
@@ -39,6 +39,7 @@ mwifiex-y += sta_tx.o
 mwifiex-y += sta_rx.o
 mwifiex-y += uap_txrx.o
 mwifiex-y += cfg80211.o
+mwifiex-y += ethtool.o
 mwifiex-$(CONFIG_DEBUG_FS) += debugfs.o
 obj-$(CONFIG_MWIFIEX) += mwifiex.o
 
index a44023a..c9bc5f5 100644 (file)
@@ -2235,6 +2235,7 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
        dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
        dev->watchdog_timeo = MWIFIEX_DEFAULT_WATCHDOG_TIMEOUT;
        dev->hard_header_len += MWIFIEX_MIN_DATA_HEADER_LEN;
+       dev->ethtool_ops = &mwifiex_ethtool_ops;
 
        mdev_priv = netdev_priv(dev);
        *((unsigned long *) mdev_priv) = (unsigned long) priv;
@@ -2293,6 +2294,152 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)
 }
 EXPORT_SYMBOL_GPL(mwifiex_del_virtual_intf);
 
+#ifdef CONFIG_PM
+static bool
+mwifiex_is_pattern_supported(struct cfg80211_wowlan_trig_pkt_pattern *pat,
+                            s8 *byte_seq)
+{
+       int j, k, valid_byte_cnt = 0;
+       bool dont_care_byte = false;
+
+       for (j = 0; j < DIV_ROUND_UP(pat->pattern_len, 8); j++) {
+               for (k = 0; k < 8; k++) {
+                       if (pat->mask[j] & 1 << k) {
+                               memcpy(byte_seq + valid_byte_cnt,
+                                      &pat->pattern[j * 8 + k], 1);
+                               valid_byte_cnt++;
+                               if (dont_care_byte)
+                                       return false;
+                       } else {
+                               if (valid_byte_cnt)
+                                       dont_care_byte = true;
+                       }
+
+                       if (valid_byte_cnt > MAX_BYTESEQ)
+                               return false;
+               }
+       }
+
+       byte_seq[MAX_BYTESEQ] = valid_byte_cnt;
+
+       return true;
+}
+
+static int mwifiex_cfg80211_suspend(struct wiphy *wiphy,
+                                   struct cfg80211_wowlan *wowlan)
+{
+       struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy);
+       struct mwifiex_ds_mef_cfg mef_cfg;
+       struct mwifiex_mef_entry *mef_entry;
+       int i, filt_num = 0, ret;
+       bool first_pat = true;
+       u8 byte_seq[MAX_BYTESEQ + 1];
+       const u8 ipv4_mc_mac[] = {0x33, 0x33};
+       const u8 ipv6_mc_mac[] = {0x01, 0x00, 0x5e};
+       struct mwifiex_private *priv =
+                       mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA);
+
+       if (!wowlan) {
+               dev_warn(adapter->dev, "None of the WOWLAN triggers enabled\n");
+               return 0;
+       }
+
+       if (!priv->media_connected) {
+               dev_warn(adapter->dev,
+                        "Can not configure WOWLAN in disconnected state\n");
+               return 0;
+       }
+
+       mef_entry = kzalloc(sizeof(*mef_entry), GFP_KERNEL);
+       if (!mef_entry)
+               return -ENOMEM;
+
+       memset(&mef_cfg, 0, sizeof(mef_cfg));
+       mef_cfg.num_entries = 1;
+       mef_cfg.mef_entry = mef_entry;
+       mef_entry->mode = MEF_MODE_HOST_SLEEP;
+       mef_entry->action = MEF_ACTION_ALLOW_AND_WAKEUP_HOST;
+
+       for (i = 0; i < wowlan->n_patterns; i++) {
+               memset(byte_seq, 0, sizeof(byte_seq));
+               if (!mwifiex_is_pattern_supported(&wowlan->patterns[i],
+                                                 byte_seq)) {
+                       wiphy_err(wiphy, "Pattern not supported\n");
+                       kfree(mef_entry);
+                       return -EOPNOTSUPP;
+               }
+
+               if (!wowlan->patterns[i].pkt_offset) {
+                       if (!(byte_seq[0] & 0x01) &&
+                           (byte_seq[MAX_BYTESEQ] == 1)) {
+                               mef_cfg.criteria |= MWIFIEX_CRITERIA_UNICAST;
+                               continue;
+                       } else if (is_broadcast_ether_addr(byte_seq)) {
+                               mef_cfg.criteria |= MWIFIEX_CRITERIA_BROADCAST;
+                               continue;
+                       } else if ((!memcmp(byte_seq, ipv4_mc_mac, 2) &&
+                                   (byte_seq[MAX_BYTESEQ] == 2)) ||
+                                  (!memcmp(byte_seq, ipv6_mc_mac, 3) &&
+                                   (byte_seq[MAX_BYTESEQ] == 3))) {
+                               mef_cfg.criteria |= MWIFIEX_CRITERIA_MULTICAST;
+                               continue;
+                       }
+               }
+
+               mef_entry->filter[filt_num].repeat = 1;
+               mef_entry->filter[filt_num].offset =
+                                               wowlan->patterns[i].pkt_offset;
+               memcpy(mef_entry->filter[filt_num].byte_seq, byte_seq,
+                      sizeof(byte_seq));
+               mef_entry->filter[filt_num].filt_type = TYPE_EQ;
+
+               if (first_pat)
+                       first_pat = false;
+               else
+                       mef_entry->filter[filt_num].filt_action = TYPE_AND;
+
+               filt_num++;
+       }
+
+       if (wowlan->magic_pkt) {
+               mef_cfg.criteria |= MWIFIEX_CRITERIA_UNICAST;
+               mef_entry->filter[filt_num].repeat = 16;
+               memcpy(mef_entry->filter[filt_num].byte_seq, priv->curr_addr,
+                      ETH_ALEN);
+               mef_entry->filter[filt_num].byte_seq[MAX_BYTESEQ] = ETH_ALEN;
+               mef_entry->filter[filt_num].offset = 14;
+               mef_entry->filter[filt_num].filt_type = TYPE_EQ;
+               if (filt_num)
+                       mef_entry->filter[filt_num].filt_action = TYPE_OR;
+       }
+
+       if (!mef_cfg.criteria)
+               mef_cfg.criteria = MWIFIEX_CRITERIA_BROADCAST |
+                                  MWIFIEX_CRITERIA_UNICAST |
+                                  MWIFIEX_CRITERIA_MULTICAST;
+
+       ret =  mwifiex_send_cmd_sync(priv, HostCmd_CMD_MEF_CFG,
+                                    HostCmd_ACT_GEN_SET, 0,
+                                    &mef_cfg);
+
+       kfree(mef_entry);
+       return ret;
+}
+
+static int mwifiex_cfg80211_resume(struct wiphy *wiphy)
+{
+       return 0;
+}
+
+static void mwifiex_cfg80211_set_wakeup(struct wiphy *wiphy,
+                                      bool enabled)
+{
+       struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy);
+
+       device_set_wakeup_enable(adapter->dev, enabled);
+}
+#endif
+
 /* station cfg80211 operations */
 static struct cfg80211_ops mwifiex_cfg80211_ops = {
        .add_virtual_intf = mwifiex_add_virtual_intf,
@@ -2321,6 +2468,11 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = {
        .change_beacon = mwifiex_cfg80211_change_beacon,
        .set_cqm_rssi_config = mwifiex_cfg80211_set_cqm_rssi_config,
        .set_antenna = mwifiex_cfg80211_set_antenna,
+#ifdef CONFIG_PM
+       .suspend = mwifiex_cfg80211_suspend,
+       .resume = mwifiex_cfg80211_resume,
+       .set_wakeup = mwifiex_cfg80211_set_wakeup,
+#endif
 };
 
 /*
@@ -2379,6 +2531,14 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
 
        wiphy_apply_custom_regulatory(wiphy, &mwifiex_world_regdom_custom);
 
+#ifdef CONFIG_PM
+       wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT;
+       wiphy->wowlan.n_patterns = MWIFIEX_MAX_FILTERS;
+       wiphy->wowlan.pattern_min_len = 1;
+       wiphy->wowlan.pattern_max_len = MWIFIEX_MAX_PATTERN_LEN;
+       wiphy->wowlan.max_pkt_offset = MWIFIEX_MAX_OFFSET_LEN;
+#endif
+
        wiphy->probe_resp_offload = NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
                                    NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
                                    NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
index 20a6c55..d19a88c 100644 (file)
@@ -1139,7 +1139,7 @@ int mwifiex_ret_802_11_hs_cfg(struct mwifiex_private *priv,
                        phs_cfg->params.hs_config.gpio,
                        phs_cfg->params.hs_config.gap);
        }
-       if (conditions != HOST_SLEEP_CFG_CANCEL) {
+       if (conditions != HS_CFG_CANCEL) {
                adapter->is_hs_configured = true;
                if (adapter->iface_type == MWIFIEX_USB ||
                    adapter->iface_type == MWIFIEX_PCIE)
diff --git a/drivers/net/wireless/mwifiex/ethtool.c b/drivers/net/wireless/mwifiex/ethtool.c
new file mode 100644 (file)
index 0000000..bfb3990
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Marvell Wireless LAN device driver: ethtool
+ *
+ * Copyright (C) 2013, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License").  You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include "main.h"
+
+static void mwifiex_ethtool_get_wol(struct net_device *dev,
+                                   struct ethtool_wolinfo *wol)
+{
+       struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+       u32 conditions = le32_to_cpu(priv->adapter->hs_cfg.conditions);
+
+       wol->supported = WAKE_UCAST|WAKE_MCAST|WAKE_BCAST|WAKE_PHY;
+
+       if (conditions == HS_CFG_COND_DEF)
+               return;
+
+       if (conditions & HS_CFG_COND_UNICAST_DATA)
+               wol->wolopts |= WAKE_UCAST;
+       if (conditions & HS_CFG_COND_MULTICAST_DATA)
+               wol->wolopts |= WAKE_MCAST;
+       if (conditions & HS_CFG_COND_BROADCAST_DATA)
+               wol->wolopts |= WAKE_BCAST;
+       if (conditions & HS_CFG_COND_MAC_EVENT)
+               wol->wolopts |= WAKE_PHY;
+}
+
+static int mwifiex_ethtool_set_wol(struct net_device *dev,
+                                  struct ethtool_wolinfo *wol)
+{
+       struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+       u32 conditions = 0;
+
+       if (wol->wolopts & ~(WAKE_UCAST|WAKE_MCAST|WAKE_BCAST|WAKE_PHY))
+               return -EOPNOTSUPP;
+
+       if (wol->wolopts & WAKE_UCAST)
+               conditions |= HS_CFG_COND_UNICAST_DATA;
+       if (wol->wolopts & WAKE_MCAST)
+               conditions |= HS_CFG_COND_MULTICAST_DATA;
+       if (wol->wolopts & WAKE_BCAST)
+               conditions |= HS_CFG_COND_BROADCAST_DATA;
+       if (wol->wolopts & WAKE_PHY)
+               conditions |= HS_CFG_COND_MAC_EVENT;
+       if (wol->wolopts == 0)
+               conditions |= HS_CFG_COND_DEF;
+       priv->adapter->hs_cfg.conditions = cpu_to_le32(conditions);
+
+       return 0;
+}
+
+const struct ethtool_ops mwifiex_ethtool_ops = {
+       .get_wol = mwifiex_ethtool_get_wol,
+       .set_wol = mwifiex_ethtool_set_wol,
+};
index 25acb06..6d6e5ae 100644 (file)
@@ -300,6 +300,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
 #define HostCmd_CMD_802_11_TX_RATE_QUERY              0x007f
 #define HostCmd_CMD_802_11_IBSS_COALESCING_STATUS     0x0083
 #define HostCmd_CMD_VERSION_EXT                       0x0097
+#define HostCmd_CMD_MEF_CFG                           0x009a
 #define HostCmd_CMD_RSSI_INFO                         0x00a4
 #define HostCmd_CMD_FUNC_INIT                         0x00a9
 #define HostCmd_CMD_FUNC_SHUTDOWN                     0x00aa
@@ -376,10 +377,14 @@ enum P2P_MODES {
 #define HostCmd_SCAN_RADIO_TYPE_BG          0
 #define HostCmd_SCAN_RADIO_TYPE_A           1
 
-#define HOST_SLEEP_CFG_CANCEL          0xffffffff
-#define HOST_SLEEP_CFG_COND_DEF                0x00000000
-#define HOST_SLEEP_CFG_GPIO_DEF                0xff
-#define HOST_SLEEP_CFG_GAP_DEF         0
+#define HS_CFG_CANCEL                  0xffffffff
+#define HS_CFG_COND_DEF                        0x00000000
+#define HS_CFG_GPIO_DEF                        0xff
+#define HS_CFG_GAP_DEF                 0
+#define HS_CFG_COND_BROADCAST_DATA     0x00000001
+#define HS_CFG_COND_UNICAST_DATA       0x00000002
+#define HS_CFG_COND_MAC_EVENT          0x00000004
+#define HS_CFG_COND_MULTICAST_DATA     0x00000008
 
 #define MWIFIEX_TIMEOUT_FOR_AP_RESP            0xfffc
 #define MWIFIEX_STATUS_CODE_AUTH_TIMEOUT       2
@@ -469,6 +474,23 @@ enum P2P_MODES {
 #define EVENT_GET_BSS_TYPE(event_cause)         \
        (((event_cause) >> 24) & 0x00ff)
 
+#define MWIFIEX_MAX_PATTERN_LEN                20
+#define MWIFIEX_MAX_OFFSET_LEN         50
+#define STACK_NBYTES                   100
+#define TYPE_DNUM                      1
+#define TYPE_BYTESEQ                   2
+#define MAX_OPERAND                    0x40
+#define TYPE_EQ                                (MAX_OPERAND+1)
+#define TYPE_EQ_DNUM                   (MAX_OPERAND+2)
+#define TYPE_EQ_BIT                    (MAX_OPERAND+3)
+#define TYPE_AND                       (MAX_OPERAND+4)
+#define TYPE_OR                                (MAX_OPERAND+5)
+#define MEF_MODE_HOST_SLEEP                    1
+#define MEF_ACTION_ALLOW_AND_WAKEUP_HOST       3
+#define MWIFIEX_CRITERIA_BROADCAST     BIT(0)
+#define MWIFIEX_CRITERIA_UNICAST       BIT(1)
+#define MWIFIEX_CRITERIA_MULTICAST     BIT(3)
+
 struct mwifiex_ie_types_header {
        __le16 type;
        __le16 len;
@@ -1499,6 +1521,19 @@ struct host_cmd_ds_802_11_ibss_status {
        __le16 use_g_rate_protect;
 } __packed;
 
+struct mwifiex_fw_mef_entry {
+       u8 mode;
+       u8 action;
+       __le16 exprsize;
+       u8 expr[0];
+} __packed;
+
+struct host_cmd_ds_mef_cfg {
+       __le32 criteria;
+       __le16 num_entries;
+       struct mwifiex_fw_mef_entry mef_entry[0];
+} __packed;
+
 #define CONNECTION_TYPE_INFRA   0
 #define CONNECTION_TYPE_ADHOC   1
 #define CONNECTION_TYPE_AP      2
@@ -1603,6 +1638,7 @@ struct host_cmd_ds_command {
                struct host_cmd_ds_remain_on_chan roc_cfg;
                struct host_cmd_ds_p2p_mode_cfg mode_cfg;
                struct host_cmd_ds_802_11_ibss_status ibss_coalescing;
+               struct host_cmd_ds_mef_cfg mef_cfg;
                struct host_cmd_ds_mac_reg_access mac_reg;
                struct host_cmd_ds_bbp_reg_access bbp_reg;
                struct host_cmd_ds_rf_reg_access rf_reg;
index e38aa9b..cab3434 100644 (file)
@@ -318,9 +318,9 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter)
        adapter->curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K;
 
        adapter->is_hs_configured = false;
-       adapter->hs_cfg.conditions = cpu_to_le32(HOST_SLEEP_CFG_COND_DEF);
-       adapter->hs_cfg.gpio = HOST_SLEEP_CFG_GPIO_DEF;
-       adapter->hs_cfg.gap = HOST_SLEEP_CFG_GAP_DEF;
+       adapter->hs_cfg.conditions = cpu_to_le32(HS_CFG_COND_DEF);
+       adapter->hs_cfg.gpio = HS_CFG_GPIO_DEF;
+       adapter->hs_cfg.gap = HS_CFG_GAP_DEF;
        adapter->hs_activated = false;
 
        memset(adapter->event_body, 0, sizeof(adapter->event_body));
index d85e6eb..91d522c 100644 (file)
@@ -354,6 +354,29 @@ struct mwifiex_ds_misc_subsc_evt {
        struct subsc_evt_cfg bcn_h_rssi_cfg;
 };
 
+#define MAX_BYTESEQ            6       /* non-adjustable */
+#define MWIFIEX_MAX_FILTERS    10
+
+struct mwifiex_mef_filter {
+       u16 repeat;
+       u16 offset;
+       s8 byte_seq[MAX_BYTESEQ + 1];
+       u8 filt_type;
+       u8 filt_action;
+};
+
+struct mwifiex_mef_entry {
+       u8 mode;
+       u8 action;
+       struct mwifiex_mef_filter filter[MWIFIEX_MAX_FILTERS];
+};
+
+struct mwifiex_ds_mef_cfg {
+       u32 criteria;
+       u16 num_entries;
+       struct mwifiex_mef_entry *mef_entry;
+};
+
 #define MWIFIEX_MAX_VSIE_LEN       (256)
 #define MWIFIEX_MAX_VSIE_NUM       (8)
 #define MWIFIEX_VSIE_MASK_CLEAR    0x00
index 9c802ed..121443a 100644 (file)
@@ -588,10 +588,19 @@ mwifiex_tx_timeout(struct net_device *dev)
 {
        struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
 
-       dev_err(priv->adapter->dev, "%lu : Tx timeout, bss_type-num = %d-%d\n",
-               jiffies, priv->bss_type, priv->bss_num);
-       mwifiex_set_trans_start(dev);
        priv->num_tx_timeout++;
+       priv->tx_timeout_cnt++;
+       dev_err(priv->adapter->dev,
+               "%lu : Tx timeout(#%d), bss_type-num = %d-%d\n",
+               jiffies, priv->tx_timeout_cnt, priv->bss_type, priv->bss_num);
+       mwifiex_set_trans_start(dev);
+
+       if (priv->tx_timeout_cnt > TX_TIMEOUT_THRESHOLD &&
+           priv->adapter->if_ops.card_reset) {
+               dev_err(priv->adapter->dev,
+                       "tx_timeout_cnt exceeds threshold. Triggering card reset!\n");
+               priv->adapter->if_ops.card_reset(priv->adapter);
+       }
 }
 
 /*
index 553adfb..9206575 100644 (file)
@@ -130,6 +130,9 @@ enum {
 #define MWIFIEX_USB_TYPE_DATA                  0xBEADC0DE
 #define MWIFIEX_USB_TYPE_EVENT                 0xBEEFFACE
 
+/* Threshold for tx_timeout_cnt before we trigger a card reset */
+#define TX_TIMEOUT_THRESHOLD   6
+
 struct mwifiex_dbg {
        u32 num_cmd_host_to_card_failure;
        u32 num_cmd_sleep_cfm_host_to_card_failure;
@@ -394,6 +397,8 @@ struct mwifiex_private {
        u8 curr_addr[ETH_ALEN];
        u8 media_connected;
        u32 num_tx_timeout;
+       /* track consecutive timeout */
+       u8 tx_timeout_cnt;
        struct net_device *netdev;
        struct net_device_stats stats;
        u16 curr_pkt_filter;
@@ -1098,11 +1103,15 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev);
 
 void mwifiex_set_sys_config_invalid_data(struct mwifiex_uap_bss_param *config);
 
+int mwifiex_add_wowlan_magic_pkt_filter(struct mwifiex_adapter *adapter);
+
 int mwifiex_set_mgmt_ies(struct mwifiex_private *priv,
                         struct cfg80211_beacon_data *data);
 int mwifiex_del_mgmt_ies(struct mwifiex_private *priv);
 u8 *mwifiex_11d_code_2_region(u8 code);
 
+extern const struct ethtool_ops mwifiex_ethtool_ops;
+
 #ifdef CONFIG_DEBUG_FS
 void mwifiex_debugfs_init(void);
 void mwifiex_debugfs_remove(void);
index 5c395e2..6283294 100644 (file)
@@ -36,8 +36,6 @@ static u8 user_rmmod;
 static struct mwifiex_if_ops pcie_ops;
 
 static struct semaphore add_remove_card_sem;
-static int mwifiex_pcie_enable_host_int(struct mwifiex_adapter *adapter);
-static int mwifiex_pcie_resume(struct pci_dev *pdev);
 
 static int
 mwifiex_map_pci_memory(struct mwifiex_adapter *adapter, struct sk_buff *skb,
@@ -78,6 +76,82 @@ static bool mwifiex_pcie_ok_to_access_hw(struct mwifiex_adapter *adapter)
        return false;
 }
 
+#ifdef CONFIG_PM
+/*
+ * Kernel needs to suspend all functions separately. Therefore all
+ * registered functions must have drivers with suspend and resume
+ * methods. Failing that the kernel simply removes the whole card.
+ *
+ * If already not suspended, this function allocates and sends a host
+ * sleep activate request to the firmware and turns off the traffic.
+ */
+static int mwifiex_pcie_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+       struct mwifiex_adapter *adapter;
+       struct pcie_service_card *card;
+       int hs_actived;
+
+       if (pdev) {
+               card = (struct pcie_service_card *) pci_get_drvdata(pdev);
+               if (!card || !card->adapter) {
+                       pr_err("Card or adapter structure is not valid\n");
+                       return 0;
+               }
+       } else {
+               pr_err("PCIE device is not specified\n");
+               return 0;
+       }
+
+       adapter = card->adapter;
+
+       hs_actived = mwifiex_enable_hs(adapter);
+
+       /* Indicate device suspended */
+       adapter->is_suspended = true;
+
+       return 0;
+}
+
+/*
+ * Kernel needs to suspend all functions separately. Therefore all
+ * registered functions must have drivers with suspend and resume
+ * methods. Failing that the kernel simply removes the whole card.
+ *
+ * If already not resumed, this function turns on the traffic and
+ * sends a host sleep cancel request to the firmware.
+ */
+static int mwifiex_pcie_resume(struct pci_dev *pdev)
+{
+       struct mwifiex_adapter *adapter;
+       struct pcie_service_card *card;
+
+       if (pdev) {
+               card = (struct pcie_service_card *) pci_get_drvdata(pdev);
+               if (!card || !card->adapter) {
+                       pr_err("Card or adapter structure is not valid\n");
+                       return 0;
+               }
+       } else {
+               pr_err("PCIE device is not specified\n");
+               return 0;
+       }
+
+       adapter = card->adapter;
+
+       if (!adapter->is_suspended) {
+               dev_warn(adapter->dev, "Device already resumed\n");
+               return 0;
+       }
+
+       adapter->is_suspended = false;
+
+       mwifiex_cancel_hs(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA),
+                         MWIFIEX_ASYNC_CMD);
+
+       return 0;
+}
+#endif
+
 /*
  * This function probes an mwifiex device and registers it. It allocates
  * the card structure, enables PCIE function number and initiates the
@@ -159,80 +233,6 @@ static void mwifiex_pcie_remove(struct pci_dev *pdev)
        kfree(card);
 }
 
-/*
- * Kernel needs to suspend all functions separately. Therefore all
- * registered functions must have drivers with suspend and resume
- * methods. Failing that the kernel simply removes the whole card.
- *
- * If already not suspended, this function allocates and sends a host
- * sleep activate request to the firmware and turns off the traffic.
- */
-static int mwifiex_pcie_suspend(struct pci_dev *pdev, pm_message_t state)
-{
-       struct mwifiex_adapter *adapter;
-       struct pcie_service_card *card;
-       int hs_actived;
-
-       if (pdev) {
-               card = (struct pcie_service_card *) pci_get_drvdata(pdev);
-               if (!card || !card->adapter) {
-                       pr_err("Card or adapter structure is not valid\n");
-                       return 0;
-               }
-       } else {
-               pr_err("PCIE device is not specified\n");
-               return 0;
-       }
-
-       adapter = card->adapter;
-
-       hs_actived = mwifiex_enable_hs(adapter);
-
-       /* Indicate device suspended */
-       adapter->is_suspended = true;
-
-       return 0;
-}
-
-/*
- * Kernel needs to suspend all functions separately. Therefore all
- * registered functions must have drivers with suspend and resume
- * methods. Failing that the kernel simply removes the whole card.
- *
- * If already not resumed, this function turns on the traffic and
- * sends a host sleep cancel request to the firmware.
- */
-static int mwifiex_pcie_resume(struct pci_dev *pdev)
-{
-       struct mwifiex_adapter *adapter;
-       struct pcie_service_card *card;
-
-       if (pdev) {
-               card = (struct pcie_service_card *) pci_get_drvdata(pdev);
-               if (!card || !card->adapter) {
-                       pr_err("Card or adapter structure is not valid\n");
-                       return 0;
-               }
-       } else {
-               pr_err("PCIE device is not specified\n");
-               return 0;
-       }
-
-       adapter = card->adapter;
-
-       if (!adapter->is_suspended) {
-               dev_warn(adapter->dev, "Device already resumed\n");
-               return 0;
-       }
-
-       adapter->is_suspended = false;
-
-       mwifiex_cancel_hs(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA),
-                         MWIFIEX_ASYNC_CMD);
-
-       return 0;
-}
-
 static DEFINE_PCI_DEVICE_TABLE(mwifiex_ids) = {
        {
                PCIE_VENDOR_ID_MARVELL, PCIE_DEVICE_ID_MARVELL_88W8766P,
@@ -1030,8 +1030,8 @@ mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb,
        u32 wrindx, num_tx_buffs, rx_val;
        int ret;
        dma_addr_t buf_pa;
-       struct mwifiex_pcie_buf_desc *desc;
-       struct mwifiex_pfu_buf_desc *desc2;
+       struct mwifiex_pcie_buf_desc *desc = NULL;
+       struct mwifiex_pfu_buf_desc *desc2 = NULL;
        __le16 *tmp;
 
        if (!(skb->data && skb->len)) {
index c55c5bb..a2ae690 100644 (file)
@@ -334,7 +334,7 @@ mwifiex_cmd_802_11_hs_cfg(struct mwifiex_private *priv,
        cmd->command = cpu_to_le16(HostCmd_CMD_802_11_HS_CFG_ENH);
 
        if (!hs_activate &&
-           (hscfg_param->conditions != cpu_to_le32(HOST_SLEEP_CFG_CANCEL)) &&
+           (hscfg_param->conditions != cpu_to_le32(HS_CFG_CANCEL)) &&
            ((adapter->arp_filter_size > 0) &&
             (adapter->arp_filter_size <= ARP_FILTER_MAX_BUF_SIZE))) {
                dev_dbg(adapter->dev,
@@ -1059,6 +1059,80 @@ mwifiex_cmd_802_11_subsc_evt(struct mwifiex_private *priv,
        return 0;
 }
 
+static int
+mwifiex_cmd_append_rpn_expression(struct mwifiex_private *priv,
+                                 struct mwifiex_mef_entry *mef_entry,
+                                 u8 **buffer)
+{
+       struct mwifiex_mef_filter *filter = mef_entry->filter;
+       int i, byte_len;
+       u8 *stack_ptr = *buffer;
+
+       for (i = 0; i < MWIFIEX_MAX_FILTERS; i++) {
+               filter = &mef_entry->filter[i];
+               if (!filter->filt_type)
+                       break;
+               *(__le32 *)stack_ptr = cpu_to_le32((u32)filter->repeat);
+               stack_ptr += 4;
+               *stack_ptr = TYPE_DNUM;
+               stack_ptr += 1;
+
+               byte_len = filter->byte_seq[MAX_BYTESEQ];
+               memcpy(stack_ptr, filter->byte_seq, byte_len);
+               stack_ptr += byte_len;
+               *stack_ptr = byte_len;
+               stack_ptr += 1;
+               *stack_ptr = TYPE_BYTESEQ;
+               stack_ptr += 1;
+
+               *(__le32 *)stack_ptr = cpu_to_le32((u32)filter->offset);
+               stack_ptr += 4;
+               *stack_ptr = TYPE_DNUM;
+               stack_ptr += 1;
+
+               *stack_ptr = filter->filt_type;
+               stack_ptr += 1;
+
+               if (filter->filt_action) {
+                       *stack_ptr = filter->filt_action;
+                       stack_ptr += 1;
+               }
+
+               if (stack_ptr - *buffer > STACK_NBYTES)
+                       return -1;
+       }
+
+       *buffer = stack_ptr;
+       return 0;
+}
+
+static int
+mwifiex_cmd_mef_cfg(struct mwifiex_private *priv,
+                   struct host_cmd_ds_command *cmd,
+                   struct mwifiex_ds_mef_cfg *mef)
+{
+       struct host_cmd_ds_mef_cfg *mef_cfg = &cmd->params.mef_cfg;
+       u8 *pos = (u8 *)mef_cfg;
+
+       cmd->command = cpu_to_le16(HostCmd_CMD_MEF_CFG);
+
+       mef_cfg->criteria = cpu_to_le32(mef->criteria);
+       mef_cfg->num_entries = cpu_to_le16(mef->num_entries);
+       pos += sizeof(*mef_cfg);
+       mef_cfg->mef_entry->mode = mef->mef_entry->mode;
+       mef_cfg->mef_entry->action = mef->mef_entry->action;
+       pos += sizeof(*(mef_cfg->mef_entry));
+
+       if (mwifiex_cmd_append_rpn_expression(priv, mef->mef_entry, &pos))
+               return -1;
+
+       mef_cfg->mef_entry->exprsize =
+                       cpu_to_le16(pos - mef_cfg->mef_entry->expr);
+       cmd->size = cpu_to_le16((u16) (pos - (u8 *)mef_cfg) + S_DS_GEN);
+
+       return 0;
+}
+
 /*
  * This function prepares the commands before sending them to the firmware.
  *
@@ -1273,6 +1347,9 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
        case HostCmd_CMD_802_11_SUBSCRIBE_EVENT:
                ret = mwifiex_cmd_802_11_subsc_evt(priv, cmd_ptr, data_buf);
                break;
+       case HostCmd_CMD_MEF_CFG:
+               ret = mwifiex_cmd_mef_cfg(priv, cmd_ptr, data_buf);
+               break;
        default:
                dev_err(priv->adapter->dev,
                        "PREP_CMD: unknown cmd- %#x\n", cmd_no);
index 4669f8d..80b9f22 100644 (file)
@@ -976,6 +976,8 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no,
        case HostCmd_CMD_UAP_BSS_STOP:
                priv->bss_started = 0;
                break;
+       case HostCmd_CMD_MEF_CFG:
+               break;
        default:
                dev_err(adapter->dev, "CMD_RESP: unknown cmd response %#x\n",
                        resp->command);
index 9f33c92..76d31de 100644 (file)
@@ -388,7 +388,7 @@ static int mwifiex_set_hs_params(struct mwifiex_private *priv, u16 action,
                        break;
                }
                if (hs_cfg->is_invoke_hostcmd) {
-                       if (hs_cfg->conditions == HOST_SLEEP_CFG_CANCEL) {
+                       if (hs_cfg->conditions == HS_CFG_CANCEL) {
                                if (!adapter->is_hs_configured)
                                        /* Already cancelled */
                                        break;
@@ -403,8 +403,8 @@ static int mwifiex_set_hs_params(struct mwifiex_private *priv, u16 action,
                                adapter->hs_cfg.gpio = (u8)hs_cfg->gpio;
                                if (hs_cfg->gap)
                                        adapter->hs_cfg.gap = (u8)hs_cfg->gap;
-                       } else if (adapter->hs_cfg.conditions
-                                  == cpu_to_le32(HOST_SLEEP_CFG_CANCEL)) {
+                       } else if (adapter->hs_cfg.conditions ==
+                                  cpu_to_le32(HS_CFG_CANCEL)) {
                                /* Return failure if no parameters for HS
                                   enable */
                                status = -1;
@@ -420,7 +420,7 @@ static int mwifiex_set_hs_params(struct mwifiex_private *priv, u16 action,
                                                HostCmd_CMD_802_11_HS_CFG_ENH,
                                                HostCmd_ACT_GEN_SET, 0,
                                                &adapter->hs_cfg);
-                       if (hs_cfg->conditions == HOST_SLEEP_CFG_CANCEL)
+                       if (hs_cfg->conditions == HS_CFG_CANCEL)
                                /* Restore previous condition */
                                adapter->hs_cfg.conditions =
                                                cpu_to_le32(prev_cond);
@@ -454,7 +454,7 @@ int mwifiex_cancel_hs(struct mwifiex_private *priv, int cmd_type)
 {
        struct mwifiex_ds_hs_cfg hscfg;
 
-       hscfg.conditions = HOST_SLEEP_CFG_CANCEL;
+       hscfg.conditions = HS_CFG_CANCEL;
        hscfg.is_invoke_hostcmd = true;
 
        return mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_SET,
index 296faec..8f923d0 100644 (file)
@@ -169,6 +169,8 @@ int mwifiex_write_data_complete(struct mwifiex_adapter *adapter,
        if (!status) {
                priv->stats.tx_packets++;
                priv->stats.tx_bytes += skb->len;
+               if (priv->tx_timeout_cnt)
+                       priv->tx_timeout_cnt = 0;
        } else {
                priv->stats.tx_errors++;
        }
index 2155397..54667e6 100644 (file)
@@ -195,7 +195,7 @@ int mwifiex_recv_packet(struct mwifiex_private *priv, struct sk_buff *skb)
        skb->protocol = eth_type_trans(skb, priv->netdev);
        skb->ip_summed = CHECKSUM_NONE;
 
-       /* This is required only in case of 11n and USB as we alloc
+       /* This is required only in case of 11n and USB/PCIE as we alloc
         * a buffer of 4K only if its 11N (to be able to receive 4K
         * AMSDU packets). In case of SD we allocate buffers based
         * on the size of packet and hence this is not needed.
@@ -212,7 +212,8 @@ int mwifiex_recv_packet(struct mwifiex_private *priv, struct sk_buff *skb)
         * fragments. Currently we fail the Filesndl-ht.scr script
         * for UDP, hence this fix
         */
-       if ((priv->adapter->iface_type == MWIFIEX_USB) &&
+       if ((priv->adapter->iface_type == MWIFIEX_USB ||
+            priv->adapter->iface_type == MWIFIEX_PCIE) &&
            (skb->truesize > MWIFIEX_RX_DATA_BUF_SIZE))
                skb->truesize += (skb->len - MWIFIEX_RX_DATA_BUF_SIZE);
 
index 091d9a6..0640e7d 100644 (file)
@@ -232,6 +232,7 @@ struct mwl8k_priv {
        u16 num_mcaddrs;
        u8 hw_rev;
        u32 fw_rev;
+       u32 caps;
 
        /*
         * Running count of TX packets in flight, to avoid
@@ -284,6 +285,7 @@ struct mwl8k_priv {
        unsigned fw_state;
        char *fw_pref;
        char *fw_alt;
+       bool is_8764;
        struct completion firmware_loading_complete;
 
        /* bitmap of running BSSes */
@@ -600,13 +602,18 @@ mwl8k_send_fw_load_cmd(struct mwl8k_priv *priv, void *data, int length)
        loops = 1000;
        do {
                u32 int_code;
-
-               int_code = ioread32(regs + MWL8K_HIU_INT_CODE);
-               if (int_code == MWL8K_INT_CODE_CMD_FINISHED) {
-                       iowrite32(0, regs + MWL8K_HIU_INT_CODE);
-                       break;
+               if (priv->is_8764) {
+                       int_code = ioread32(regs +
+                                           MWL8K_HIU_H2A_INTERRUPT_STATUS);
+                       if (int_code == 0)
+                               break;
+               } else {
+                       int_code = ioread32(regs + MWL8K_HIU_INT_CODE);
+                       if (int_code == MWL8K_INT_CODE_CMD_FINISHED) {
+                               iowrite32(0, regs + MWL8K_HIU_INT_CODE);
+                               break;
+                       }
                }
-
                cond_resched();
                udelay(1);
        } while (--loops);
@@ -724,7 +731,7 @@ static int mwl8k_load_firmware(struct ieee80211_hw *hw)
        int rc;
        int loops;
 
-       if (!memcmp(fw->data, "\x01\x00\x00\x00", 4)) {
+       if (!memcmp(fw->data, "\x01\x00\x00\x00", 4) && !priv->is_8764) {
                const struct firmware *helper = priv->fw_helper;
 
                if (helper == NULL) {
@@ -743,7 +750,10 @@ static int mwl8k_load_firmware(struct ieee80211_hw *hw)
 
                rc = mwl8k_feed_fw_image(priv, fw->data, fw->size);
        } else {
-               rc = mwl8k_load_fw_image(priv, fw->data, fw->size);
+               if (priv->is_8764)
+                       rc = mwl8k_feed_fw_image(priv, fw->data, fw->size);
+               else
+                       rc = mwl8k_load_fw_image(priv, fw->data, fw->size);
        }
 
        if (rc) {
@@ -908,9 +918,9 @@ static void mwl8k_encapsulate_tx_frame(struct mwl8k_priv *priv,
 }
 
 /*
- * Packet reception for 88w8366 AP firmware.
+ * Packet reception for 88w8366/88w8764 AP firmware.
  */
-struct mwl8k_rxd_8366_ap {
+struct mwl8k_rxd_ap {
        __le16 pkt_len;
        __u8 sq2;
        __u8 rate;
@@ -928,30 +938,30 @@ struct mwl8k_rxd_8366_ap {
        __u8 rx_ctrl;
 } __packed;
 
-#define MWL8K_8366_AP_RATE_INFO_MCS_FORMAT     0x80
-#define MWL8K_8366_AP_RATE_INFO_40MHZ          0x40
-#define MWL8K_8366_AP_RATE_INFO_RATEID(x)      ((x) & 0x3f)
+#define MWL8K_AP_RATE_INFO_MCS_FORMAT          0x80
+#define MWL8K_AP_RATE_INFO_40MHZ               0x40
+#define MWL8K_AP_RATE_INFO_RATEID(x)           ((x) & 0x3f)
 
-#define MWL8K_8366_AP_RX_CTRL_OWNED_BY_HOST    0x80
+#define MWL8K_AP_RX_CTRL_OWNED_BY_HOST         0x80
 
-/* 8366 AP rx_status bits */
-#define MWL8K_8366_AP_RXSTAT_DECRYPT_ERR_MASK          0x80
-#define MWL8K_8366_AP_RXSTAT_GENERAL_DECRYPT_ERR       0xFF
-#define MWL8K_8366_AP_RXSTAT_TKIP_DECRYPT_MIC_ERR      0x02
-#define MWL8K_8366_AP_RXSTAT_WEP_DECRYPT_ICV_ERR       0x04
-#define MWL8K_8366_AP_RXSTAT_TKIP_DECRYPT_ICV_ERR      0x08
+/* 8366/8764 AP rx_status bits */
+#define MWL8K_AP_RXSTAT_DECRYPT_ERR_MASK               0x80
+#define MWL8K_AP_RXSTAT_GENERAL_DECRYPT_ERR            0xFF
+#define MWL8K_AP_RXSTAT_TKIP_DECRYPT_MIC_ERR           0x02
+#define MWL8K_AP_RXSTAT_WEP_DECRYPT_ICV_ERR            0x04
+#define MWL8K_AP_RXSTAT_TKIP_DECRYPT_ICV_ERR           0x08
 
-static void mwl8k_rxd_8366_ap_init(void *_rxd, dma_addr_t next_dma_addr)
+static void mwl8k_rxd_ap_init(void *_rxd, dma_addr_t next_dma_addr)
 {
-       struct mwl8k_rxd_8366_ap *rxd = _rxd;
+       struct mwl8k_rxd_ap *rxd = _rxd;
 
        rxd->next_rxd_phys_addr = cpu_to_le32(next_dma_addr);
-       rxd->rx_ctrl = MWL8K_8366_AP_RX_CTRL_OWNED_BY_HOST;
+       rxd->rx_ctrl = MWL8K_AP_RX_CTRL_OWNED_BY_HOST;
 }
 
-static void mwl8k_rxd_8366_ap_refill(void *_rxd, dma_addr_t addr, int len)
+static void mwl8k_rxd_ap_refill(void *_rxd, dma_addr_t addr, int len)
 {
-       struct mwl8k_rxd_8366_ap *rxd = _rxd;
+       struct mwl8k_rxd_ap *rxd = _rxd;
 
        rxd->pkt_len = cpu_to_le16(len);
        rxd->pkt_phys_addr = cpu_to_le32(addr);
@@ -960,12 +970,12 @@ static void mwl8k_rxd_8366_ap_refill(void *_rxd, dma_addr_t addr, int len)
 }
 
 static int
-mwl8k_rxd_8366_ap_process(void *_rxd, struct ieee80211_rx_status *status,
-                         __le16 *qos, s8 *noise)
+mwl8k_rxd_ap_process(void *_rxd, struct ieee80211_rx_status *status,
+                    __le16 *qos, s8 *noise)
 {
-       struct mwl8k_rxd_8366_ap *rxd = _rxd;
+       struct mwl8k_rxd_ap *rxd = _rxd;
 
-       if (!(rxd->rx_ctrl & MWL8K_8366_AP_RX_CTRL_OWNED_BY_HOST))
+       if (!(rxd->rx_ctrl & MWL8K_AP_RX_CTRL_OWNED_BY_HOST))
                return -1;
        rmb();
 
@@ -974,11 +984,11 @@ mwl8k_rxd_8366_ap_process(void *_rxd, struct ieee80211_rx_status *status,
        status->signal = -rxd->rssi;
        *noise = -rxd->noise_floor;
 
-       if (rxd->rate & MWL8K_8366_AP_RATE_INFO_MCS_FORMAT) {
+       if (rxd->rate & MWL8K_AP_RATE_INFO_MCS_FORMAT) {
                status->flag |= RX_FLAG_HT;
-               if (rxd->rate & MWL8K_8366_AP_RATE_INFO_40MHZ)
+               if (rxd->rate & MWL8K_AP_RATE_INFO_40MHZ)
                        status->flag |= RX_FLAG_40MHZ;
-               status->rate_idx = MWL8K_8366_AP_RATE_INFO_RATEID(rxd->rate);
+               status->rate_idx = MWL8K_AP_RATE_INFO_RATEID(rxd->rate);
        } else {
                int i;
 
@@ -1002,19 +1012,19 @@ mwl8k_rxd_8366_ap_process(void *_rxd, struct ieee80211_rx_status *status,
 
        *qos = rxd->qos_control;
 
-       if ((rxd->rx_status != MWL8K_8366_AP_RXSTAT_GENERAL_DECRYPT_ERR) &&
-           (rxd->rx_status & MWL8K_8366_AP_RXSTAT_DECRYPT_ERR_MASK) &&
-           (rxd->rx_status & MWL8K_8366_AP_RXSTAT_TKIP_DECRYPT_MIC_ERR))
+       if ((rxd->rx_status != MWL8K_AP_RXSTAT_GENERAL_DECRYPT_ERR) &&
+           (rxd->rx_status & MWL8K_AP_RXSTAT_DECRYPT_ERR_MASK) &&
+           (rxd->rx_status & MWL8K_AP_RXSTAT_TKIP_DECRYPT_MIC_ERR))
                status->flag |= RX_FLAG_MMIC_ERROR;
 
        return le16_to_cpu(rxd->pkt_len);
 }
 
-static struct rxd_ops rxd_8366_ap_ops = {
-       .rxd_size       = sizeof(struct mwl8k_rxd_8366_ap),
-       .rxd_init       = mwl8k_rxd_8366_ap_init,
-       .rxd_refill     = mwl8k_rxd_8366_ap_refill,
-       .rxd_process    = mwl8k_rxd_8366_ap_process,
+static struct rxd_ops rxd_ap_ops = {
+       .rxd_size       = sizeof(struct mwl8k_rxd_ap),
+       .rxd_init       = mwl8k_rxd_ap_init,
+       .rxd_refill     = mwl8k_rxd_ap_refill,
+       .rxd_process    = mwl8k_rxd_ap_process,
 };
 
 /*
@@ -2401,6 +2411,9 @@ mwl8k_set_caps(struct ieee80211_hw *hw, u32 caps)
 {
        struct mwl8k_priv *priv = hw->priv;
 
+       if (priv->caps)
+               return;
+
        if ((caps & MWL8K_CAP_2GHZ4) || !(caps & MWL8K_CAP_BAND_MASK)) {
                mwl8k_setup_2ghz_band(hw);
                if (caps & MWL8K_CAP_MIMO)
@@ -2412,6 +2425,8 @@ mwl8k_set_caps(struct ieee80211_hw *hw, u32 caps)
                if (caps & MWL8K_CAP_MIMO)
                        mwl8k_set_ht_caps(hw, &priv->band_50, caps);
        }
+
+       priv->caps = caps;
 }
 
 static int mwl8k_cmd_get_hw_spec_sta(struct ieee80211_hw *hw)
@@ -5429,12 +5444,17 @@ enum {
        MWL8363 = 0,
        MWL8687,
        MWL8366,
+       MWL8764,
 };
 
 #define MWL8K_8366_AP_FW_API 3
 #define _MWL8K_8366_AP_FW(api) "mwl8k/fmimage_8366_ap-" #api ".fw"
 #define MWL8K_8366_AP_FW(api) _MWL8K_8366_AP_FW(api)
 
+#define MWL8K_8764_AP_FW_API 1
+#define _MWL8K_8764_AP_FW(api) "mwl8k/fmimage_8764_ap-" #api ".fw"
+#define MWL8K_8764_AP_FW(api) _MWL8K_8764_AP_FW(api)
+
 static struct mwl8k_device_info mwl8k_info_tbl[] = {
        [MWL8363] = {
                .part_name      = "88w8363",
@@ -5452,7 +5472,13 @@ static struct mwl8k_device_info mwl8k_info_tbl[] = {
                .fw_image_sta   = "mwl8k/fmimage_8366.fw",
                .fw_image_ap    = MWL8K_8366_AP_FW(MWL8K_8366_AP_FW_API),
                .fw_api_ap      = MWL8K_8366_AP_FW_API,
-               .ap_rxd_ops     = &rxd_8366_ap_ops,
+               .ap_rxd_ops     = &rxd_ap_ops,
+       },
+       [MWL8764] = {
+               .part_name      = "88w8764",
+               .fw_image_ap    = MWL8K_8764_AP_FW(MWL8K_8764_AP_FW_API),
+               .fw_api_ap      = MWL8K_8764_AP_FW_API,
+               .ap_rxd_ops     = &rxd_ap_ops,
        },
 };
 
@@ -5474,6 +5500,7 @@ static DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = {
        { PCI_VDEVICE(MARVELL, 0x2a41), .driver_data = MWL8366, },
        { PCI_VDEVICE(MARVELL, 0x2a42), .driver_data = MWL8366, },
        { PCI_VDEVICE(MARVELL, 0x2a43), .driver_data = MWL8366, },
+       { PCI_VDEVICE(MARVELL, 0x2b36), .driver_data = MWL8764, },
        { },
 };
 MODULE_DEVICE_TABLE(pci, mwl8k_pci_id_table);
@@ -5995,6 +6022,8 @@ static int mwl8k_probe(struct pci_dev *pdev,
        priv->pdev = pdev;
        priv->device_info = &mwl8k_info_tbl[id->driver_data];
 
+       if (id->driver_data == MWL8764)
+               priv->is_8764 = true;
 
        priv->sram = pci_iomap(pdev, 0, 0x10000);
        if (priv->sram == NULL) {
index 7744f42..1f9cb55 100644 (file)
@@ -1584,7 +1584,7 @@ static int ezusb_probe(struct usb_interface *interface,
        struct ezusb_priv *upriv = NULL;
        struct usb_interface_descriptor *iface_desc;
        struct usb_endpoint_descriptor *ep;
-       const struct firmware *fw_entry;
+       const struct firmware *fw_entry = NULL;
        int retval = 0;
        int i;
 
index 3109c0d..4775b5d 100644 (file)
@@ -144,7 +144,7 @@ static int psm;
 static char *essid;
 
 /* Default to encapsulation unless translation requested */
-static int translate = 1;
+static bool translate = 1;
 
 static int country = USA;
 
@@ -178,7 +178,7 @@ module_param(hop_dwell, int, 0);
 module_param(beacon_period, int, 0);
 module_param(psm, int, 0);
 module_param(essid, charp, 0);
-module_param(translate, int, 0);
+module_param(translate, bool, 0);
 module_param(country, int, 0);
 module_param(sniffer, int, 0);
 module_param(bc, int, 0);
@@ -1353,7 +1353,7 @@ static int ray_get_range(struct net_device *dev, struct iw_request_info *info,
 static int ray_set_framing(struct net_device *dev, struct iw_request_info *info,
                           union iwreq_data *wrqu, char *extra)
 {
-       translate = *(extra);   /* Set framing mode */
+       translate = !!*(extra); /* Set framing mode */
 
        return 0;
 }
index 525fd75..8169a85 100644 (file)
@@ -2,7 +2,7 @@
  * Driver for RNDIS based wireless USB devices.
  *
  * Copyright (C) 2007 by Bjorge Dijkstra <bjd@jooz.net>
- * Copyright (C) 2008-2009 by Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
+ * Copyright (C) 2008-2009 by Jussi Kivilinna <jussi.kivilinna@iki.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -2839,8 +2839,7 @@ static void rndis_wlan_do_link_up_work(struct usbnet *usbdev)
        } else if (priv->infra_mode == NDIS_80211_INFRA_ADHOC)
                cfg80211_ibss_joined(usbdev->net, bssid, GFP_KERNEL);
 
-       if (info != NULL)
-               kfree(info);
+       kfree(info);
 
        priv->connected = true;
        memcpy(priv->bssid, bssid, ETH_ALEN);
index a0c8cae..b1c673e 100644 (file)
@@ -52,8 +52,8 @@ int rt2x00pci_regbusy_read(struct rt2x00_dev *rt2x00dev,
                udelay(REGISTER_BUSY_DELAY);
        }
 
-       ERROR(rt2x00dev, "Indirect register access failed: "
-             "offset=0x%.08x, value=0x%.08x\n", offset, *reg);
+       printk_once(KERN_ERR "%s() Indirect register access failed: "
+             "offset=0x%.08x, value=0x%.08x\n", __func__, offset, *reg);
        *reg = ~0;
 
        return 0;
index 156b527..b5c80b5 100644 (file)
@@ -224,10 +224,9 @@ static void _usb_writeN_sync(struct rtl_priv *rtlpriv, u32 addr, void *data,
        u8 *buffer;
 
        wvalue = (u16)(addr & 0x0000ffff);
-       buffer = kmalloc(len, GFP_ATOMIC);
+       buffer = kmemdup(data, len, GFP_ATOMIC);
        if (!buffer)
                return;
-       memcpy(buffer, data, len);
        usb_control_msg(udev, pipe, request, reqtype, wvalue,
                        index, buffer, len, 50);
 
index f13258a..c3eff32 100644 (file)
@@ -2127,9 +2127,6 @@ value to host byte ordering.*/
 #define WLAN_FC_GET_TYPE(fc)   (le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE)
 #define WLAN_FC_GET_STYPE(fc)  (le16_to_cpu(fc) & IEEE80211_FCTL_STYPE)
 #define WLAN_FC_MORE_DATA(fc)  (le16_to_cpu(fc) & IEEE80211_FCTL_MOREDATA)
-#define SEQ_TO_SN(seq)         (((seq) & IEEE80211_SCTL_SEQ) >> 4)
-#define SN_TO_SEQ(ssn)         (((ssn) << 4) & IEEE80211_SCTL_SEQ)
-#define MAX_SN                 ((IEEE80211_SCTL_SEQ) >> 4)
 
 #define        RT_RF_OFF_LEVL_ASPM             BIT(0)  /*PCI ASPM */
 #define        RT_RF_OFF_LEVL_CLK_REQ          BIT(1)  /*PCI clock request */
index 2c2ff3e..d7e3063 100644 (file)
@@ -4956,7 +4956,8 @@ 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,
-                                      int duration)
+                                      int duration,
+                                      enum ieee80211_roc_type type)
 {
        struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
        struct wl1271 *wl = hw->priv;
index eef38cf..13bde92 100644 (file)
@@ -48,7 +48,7 @@ struct mei_nfc_hdr {
 #define MEI_NFC_MAX_READ (MEI_NFC_HEADER_SIZE + MEI_NFC_MAX_HCI_PAYLOAD)
 
 struct microread_mei_phy {
-       struct mei_device *mei_device;
+       struct mei_device *device;
        struct nfc_hci_dev *hdev;
 
        int powered;
index 71098a7..7cb7d2c 100644 (file)
@@ -354,7 +354,7 @@ void ssb_chipcommon_init(struct ssb_chipcommon *cc)
 
        if (cc->dev->id.revision >= 11)
                cc->status = chipco_read32(cc, SSB_CHIPCO_CHIPSTAT);
-       ssb_dprintk(KERN_INFO PFX "chipcommon status is 0x%x\n", cc->status);
+       ssb_dbg("chipcommon status is 0x%x\n", cc->status);
 
        if (cc->dev->id.revision >= 20) {
                chipco_write32(cc, SSB_CHIPCO_GPIOPULLUP, 0);
index 4c0f6d8..791da2c 100644 (file)
@@ -110,8 +110,8 @@ static void ssb_pmu0_pllinit_r0(struct ssb_chipcommon *cc,
                return;
        }
 
-       ssb_printk(KERN_INFO PFX "Programming PLL to %u.%03u MHz\n",
-                  (crystalfreq / 1000), (crystalfreq % 1000));
+       ssb_info("Programming PLL to %u.%03u MHz\n",
+                crystalfreq / 1000, crystalfreq % 1000);
 
        /* First turn the PLL off. */
        switch (bus->chip_id) {
@@ -138,7 +138,7 @@ static void ssb_pmu0_pllinit_r0(struct ssb_chipcommon *cc,
        }
        tmp = chipco_read32(cc, SSB_CHIPCO_CLKCTLST);
        if (tmp & SSB_CHIPCO_CLKCTLST_HAVEHT)
-               ssb_printk(KERN_EMERG PFX "Failed to turn the PLL off!\n");
+               ssb_emerg("Failed to turn the PLL off!\n");
 
        /* Set PDIV in PLL control 0. */
        pllctl = ssb_chipco_pll_read(cc, SSB_PMU0_PLLCTL0);
@@ -249,8 +249,8 @@ static void ssb_pmu1_pllinit_r0(struct ssb_chipcommon *cc,
                return;
        }
 
-       ssb_printk(KERN_INFO PFX "Programming PLL to %u.%03u MHz\n",
-                  (crystalfreq / 1000), (crystalfreq % 1000));
+       ssb_info("Programming PLL to %u.%03u MHz\n",
+                crystalfreq / 1000, crystalfreq % 1000);
 
        /* First turn the PLL off. */
        switch (bus->chip_id) {
@@ -275,7 +275,7 @@ static void ssb_pmu1_pllinit_r0(struct ssb_chipcommon *cc,
        }
        tmp = chipco_read32(cc, SSB_CHIPCO_CLKCTLST);
        if (tmp & SSB_CHIPCO_CLKCTLST_HAVEHT)
-               ssb_printk(KERN_EMERG PFX "Failed to turn the PLL off!\n");
+               ssb_emerg("Failed to turn the PLL off!\n");
 
        /* Set p1div and p2div. */
        pllctl = ssb_chipco_pll_read(cc, SSB_PMU1_PLLCTL0);
@@ -349,9 +349,8 @@ static void ssb_pmu_pll_init(struct ssb_chipcommon *cc)
        case 43222:
                break;
        default:
-               ssb_printk(KERN_ERR PFX
-                          "ERROR: PLL init unknown for device %04X\n",
-                          bus->chip_id);
+               ssb_err("ERROR: PLL init unknown for device %04X\n",
+                       bus->chip_id);
        }
 }
 
@@ -472,9 +471,8 @@ static void ssb_pmu_resources_init(struct ssb_chipcommon *cc)
                max_msk = 0xFFFFF;
                break;
        default:
-               ssb_printk(KERN_ERR PFX
-                          "ERROR: PMU resource config unknown for device %04X\n",
-                          bus->chip_id);
+               ssb_err("ERROR: PMU resource config unknown for device %04X\n",
+                       bus->chip_id);
        }
 
        if (updown_tab) {
@@ -526,8 +524,8 @@ void ssb_pmu_init(struct ssb_chipcommon *cc)
        pmucap = chipco_read32(cc, SSB_CHIPCO_PMU_CAP);
        cc->pmu.rev = (pmucap & SSB_CHIPCO_PMU_CAP_REVISION);
 
-       ssb_dprintk(KERN_DEBUG PFX "Found rev %u PMU (capabilities 0x%08X)\n",
-                   cc->pmu.rev, pmucap);
+       ssb_dbg("Found rev %u PMU (capabilities 0x%08X)\n",
+               cc->pmu.rev, pmucap);
 
        if (cc->pmu.rev == 1)
                chipco_mask32(cc, SSB_CHIPCO_PMU_CTL,
@@ -638,9 +636,8 @@ u32 ssb_pmu_get_alp_clock(struct ssb_chipcommon *cc)
        case 0x5354:
                ssb_pmu_get_alp_clock_clk0(cc);
        default:
-               ssb_printk(KERN_ERR PFX
-                          "ERROR: PMU alp clock unknown for device %04X\n",
-                          bus->chip_id);
+               ssb_err("ERROR: PMU alp clock unknown for device %04X\n",
+                       bus->chip_id);
                return 0;
        }
 }
@@ -654,9 +651,8 @@ u32 ssb_pmu_get_cpu_clock(struct ssb_chipcommon *cc)
                /* 5354 chip uses a non programmable PLL of frequency 240MHz */
                return 240000000;
        default:
-               ssb_printk(KERN_ERR PFX
-                          "ERROR: PMU cpu clock unknown for device %04X\n",
-                          bus->chip_id);
+               ssb_err("ERROR: PMU cpu clock unknown for device %04X\n",
+                       bus->chip_id);
                return 0;
        }
 }
@@ -669,9 +665,8 @@ u32 ssb_pmu_get_controlclock(struct ssb_chipcommon *cc)
        case 0x5354:
                return 120000000;
        default:
-               ssb_printk(KERN_ERR PFX
-                          "ERROR: PMU controlclock unknown for device %04X\n",
-                          bus->chip_id);
+               ssb_err("ERROR: PMU controlclock unknown for device %04X\n",
+                       bus->chip_id);
                return 0;
        }
 }
index 33b37da..fa385a3 100644 (file)
@@ -167,21 +167,22 @@ static void set_irq(struct ssb_device *dev, unsigned int irq)
                irqflag |= (ipsflag & ~ipsflag_irq_mask[irq]);
                ssb_write32(mdev, SSB_IPSFLAG, irqflag);
        }
-       ssb_dprintk(KERN_INFO PFX
-                   "set_irq: core 0x%04x, irq %d => %d\n",
-                   dev->id.coreid, oldirq+2, irq+2);
+       ssb_dbg("set_irq: core 0x%04x, irq %d => %d\n",
+               dev->id.coreid, oldirq+2, irq+2);
 }
 
 static void print_irq(struct ssb_device *dev, unsigned int irq)
 {
-       int i;
        static const char *irq_name[] = {"2(S)", "3", "4", "5", "6", "D", "I"};
-       ssb_dprintk(KERN_INFO PFX
-               "core 0x%04x, irq :", dev->id.coreid);
-       for (i = 0; i <= 6; i++) {
-               ssb_dprintk(" %s%s", irq_name[i], i==irq?"*":" ");
-       }
-       ssb_dprintk("\n");
+       ssb_dbg("core 0x%04x, irq : %s%s %s%s %s%s %s%s %s%s %s%s %s%s\n",
+               dev->id.coreid,
+               irq_name[0], irq == 0 ? "*" : " ",
+               irq_name[1], irq == 1 ? "*" : " ",
+               irq_name[2], irq == 2 ? "*" : " ",
+               irq_name[3], irq == 3 ? "*" : " ",
+               irq_name[4], irq == 4 ? "*" : " ",
+               irq_name[5], irq == 5 ? "*" : " ",
+               irq_name[6], irq == 6 ? "*" : " ");
 }
 
 static void dump_irq(struct ssb_bus *bus)
@@ -286,7 +287,7 @@ void ssb_mipscore_init(struct ssb_mipscore *mcore)
        if (!mcore->dev)
                return; /* We don't have a MIPS core */
 
-       ssb_dprintk(KERN_INFO PFX "Initializing MIPS core...\n");
+       ssb_dbg("Initializing MIPS core...\n");
 
        bus = mcore->dev->bus;
        hz = ssb_clockspeed(bus);
@@ -334,7 +335,7 @@ void ssb_mipscore_init(struct ssb_mipscore *mcore)
                        break;
                }
        }
-       ssb_dprintk(KERN_INFO PFX "after irq reconfiguration\n");
+       ssb_dbg("after irq reconfiguration\n");
        dump_irq(bus);
 
        ssb_mips_serial_init(mcore);
index 59801d2..d75b72b 100644 (file)
@@ -263,8 +263,7 @@ int ssb_pcicore_plat_dev_init(struct pci_dev *d)
                return -ENODEV;
        }
 
-       ssb_printk(KERN_INFO "PCI: Fixing up device %s\n",
-                  pci_name(d));
+       ssb_info("PCI: Fixing up device %s\n", pci_name(d));
 
        /* Fix up interrupt lines */
        d->irq = ssb_mips_irq(extpci_core->dev) + 2;
@@ -285,12 +284,12 @@ static void ssb_pcicore_fixup_pcibridge(struct pci_dev *dev)
        if (dev->bus->number != 0 || PCI_SLOT(dev->devfn) != 0)
                return;
 
-       ssb_printk(KERN_INFO "PCI: Fixing up bridge %s\n", pci_name(dev));
+       ssb_info("PCI: Fixing up bridge %s\n", pci_name(dev));
 
        /* Enable PCI bridge bus mastering and memory space */
        pci_set_master(dev);
        if (pcibios_enable_device(dev, ~0) < 0) {
-               ssb_printk(KERN_ERR "PCI: SSB bridge enable failed\n");
+               ssb_err("PCI: SSB bridge enable failed\n");
                return;
        }
 
@@ -299,8 +298,8 @@ static void ssb_pcicore_fixup_pcibridge(struct pci_dev *dev)
 
        /* Make sure our latency is high enough to handle the devices behind us */
        lat = 168;
-       ssb_printk(KERN_INFO "PCI: Fixing latency timer of device %s to %u\n",
-                  pci_name(dev), lat);
+       ssb_info("PCI: Fixing latency timer of device %s to %u\n",
+                pci_name(dev), lat);
        pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
 }
 DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, ssb_pcicore_fixup_pcibridge);
@@ -323,7 +322,7 @@ static void ssb_pcicore_init_hostmode(struct ssb_pcicore *pc)
                return;
        extpci_core = pc;
 
-       ssb_dprintk(KERN_INFO PFX "PCIcore in host mode found\n");
+       ssb_dbg("PCIcore in host mode found\n");
        /* Reset devices on the external PCI bus */
        val = SSB_PCICORE_CTL_RST_OE;
        val |= SSB_PCICORE_CTL_CLK_OE;
@@ -338,7 +337,7 @@ static void ssb_pcicore_init_hostmode(struct ssb_pcicore *pc)
        udelay(1); /* Assertion time demanded by the PCI standard */
 
        if (pc->dev->bus->has_cardbus_slot) {
-               ssb_dprintk(KERN_INFO PFX "CardBus slot detected\n");
+               ssb_dbg("CardBus slot detected\n");
                pc->cardbusmode = 1;
                /* GPIO 1 resets the bridge */
                ssb_gpio_out(pc->dev->bus, 1, 1);
index bb18d76..55e1011 100644 (file)
@@ -57,9 +57,8 @@ int ssb_watchdog_register(struct ssb_bus *bus)
                                             bus->busnumber, &wdt,
                                             sizeof(wdt));
        if (IS_ERR(pdev)) {
-               ssb_dprintk(KERN_INFO PFX
-                           "can not register watchdog device, err: %li\n",
-                           PTR_ERR(pdev));
+               ssb_dbg("can not register watchdog device, err: %li\n",
+                       PTR_ERR(pdev));
                return PTR_ERR(pdev);
        }
 
index 3b645b8..812775a 100644 (file)
@@ -275,8 +275,8 @@ int ssb_devices_thaw(struct ssb_freeze_context *ctx)
 
                err = sdrv->probe(sdev, &sdev->id);
                if (err) {
-                       ssb_printk(KERN_ERR PFX "Failed to thaw device %s\n",
-                                  dev_name(sdev->dev));
+                       ssb_err("Failed to thaw device %s\n",
+                               dev_name(sdev->dev));
                        result = err;
                }
                ssb_device_put(sdev);
@@ -447,10 +447,9 @@ void ssb_bus_unregister(struct ssb_bus *bus)
 
        err = ssb_gpio_unregister(bus);
        if (err == -EBUSY)
-               ssb_dprintk(KERN_ERR PFX "Some GPIOs are still in use.\n");
+               ssb_dbg("Some GPIOs are still in use\n");
        else if (err)
-               ssb_dprintk(KERN_ERR PFX
-                           "Can not unregister GPIO driver: %i\n", err);
+               ssb_dbg("Can not unregister GPIO driver: %i\n", err);
 
        ssb_buses_lock();
        ssb_devices_unregister(bus);
@@ -497,8 +496,7 @@ static int ssb_devices_register(struct ssb_bus *bus)
 
                devwrap = kzalloc(sizeof(*devwrap), GFP_KERNEL);
                if (!devwrap) {
-                       ssb_printk(KERN_ERR PFX
-                                  "Could not allocate device\n");
+                       ssb_err("Could not allocate device\n");
                        err = -ENOMEM;
                        goto error;
                }
@@ -537,9 +535,7 @@ static int ssb_devices_register(struct ssb_bus *bus)
                sdev->dev = dev;
                err = device_register(dev);
                if (err) {
-                       ssb_printk(KERN_ERR PFX
-                                  "Could not register %s\n",
-                                  dev_name(dev));
+                       ssb_err("Could not register %s\n", dev_name(dev));
                        /* Set dev to NULL to not unregister
                         * dev on error unwinding. */
                        sdev->dev = NULL;
@@ -825,10 +821,9 @@ static int ssb_bus_register(struct ssb_bus *bus,
        ssb_mipscore_init(&bus->mipscore);
        err = ssb_gpio_init(bus);
        if (err == -ENOTSUPP)
-               ssb_dprintk(KERN_DEBUG PFX "GPIO driver not activated\n");
+               ssb_dbg("GPIO driver not activated\n");
        else if (err)
-               ssb_dprintk(KERN_ERR PFX
-                          "Error registering GPIO driver: %i\n", err);
+               ssb_dbg("Error registering GPIO driver: %i\n", err);
        err = ssb_fetch_invariants(bus, get_invariants);
        if (err) {
                ssb_bus_may_powerdown(bus);
@@ -878,11 +873,11 @@ int ssb_bus_pcibus_register(struct ssb_bus *bus, struct pci_dev *host_pci)
 
        err = ssb_bus_register(bus, ssb_pci_get_invariants, 0);
        if (!err) {
-               ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found on "
-                          "PCI device %s\n", dev_name(&host_pci->dev));
+               ssb_info("Sonics Silicon Backplane found on PCI device %s\n",
+                        dev_name(&host_pci->dev));
        } else {
-               ssb_printk(KERN_ERR PFX "Failed to register PCI version"
-                          " of SSB with error %d\n", err);
+               ssb_err("Failed to register PCI version of SSB with error %d\n",
+                       err);
        }
 
        return err;
@@ -903,8 +898,8 @@ int ssb_bus_pcmciabus_register(struct ssb_bus *bus,
 
        err = ssb_bus_register(bus, ssb_pcmcia_get_invariants, baseaddr);
        if (!err) {
-               ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found on "
-                          "PCMCIA device %s\n", pcmcia_dev->devname);
+               ssb_info("Sonics Silicon Backplane found on PCMCIA device %s\n",
+                        pcmcia_dev->devname);
        }
 
        return err;
@@ -925,8 +920,8 @@ int ssb_bus_sdiobus_register(struct ssb_bus *bus, struct sdio_func *func,
 
        err = ssb_bus_register(bus, ssb_sdio_get_invariants, ~0);
        if (!err) {
-               ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found on "
-                          "SDIO device %s\n", sdio_func_id(func));
+               ssb_info("Sonics Silicon Backplane found on SDIO device %s\n",
+                        sdio_func_id(func));
        }
 
        return err;
@@ -944,8 +939,8 @@ int ssb_bus_ssbbus_register(struct ssb_bus *bus, unsigned long baseaddr,
 
        err = ssb_bus_register(bus, get_invariants, baseaddr);
        if (!err) {
-               ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found at "
-                          "address 0x%08lX\n", baseaddr);
+               ssb_info("Sonics Silicon Backplane found at address 0x%08lX\n",
+                        baseaddr);
        }
 
        return err;
@@ -1339,7 +1334,7 @@ out:
 #endif
        return err;
 error:
-       ssb_printk(KERN_ERR PFX "Bus powerdown failed\n");
+       ssb_err("Bus powerdown failed\n");
        goto out;
 }
 EXPORT_SYMBOL(ssb_bus_may_powerdown);
@@ -1362,7 +1357,7 @@ int ssb_bus_powerup(struct ssb_bus *bus, bool dynamic_pctl)
 
        return 0;
 error:
-       ssb_printk(KERN_ERR PFX "Bus powerup failed\n");
+       ssb_err("Bus powerup failed\n");
        return err;
 }
 EXPORT_SYMBOL(ssb_bus_powerup);
@@ -1470,15 +1465,13 @@ static int __init ssb_modinit(void)
 
        err = b43_pci_ssb_bridge_init();
        if (err) {
-               ssb_printk(KERN_ERR "Broadcom 43xx PCI-SSB-bridge "
-                          "initialization failed\n");
+               ssb_err("Broadcom 43xx PCI-SSB-bridge initialization failed\n");
                /* don't fail SSB init because of this */
                err = 0;
        }
        err = ssb_gige_init();
        if (err) {
-               ssb_printk(KERN_ERR "SSB Broadcom Gigabit Ethernet "
-                          "driver initialization failed\n");
+               ssb_err("SSB Broadcom Gigabit Ethernet driver initialization failed\n");
                /* don't fail SSB init because of this */
                err = 0;
        }
index e9d9496..63ff69f 100644 (file)
@@ -56,7 +56,7 @@ int ssb_pci_switch_coreidx(struct ssb_bus *bus, u8 coreidx)
        }
        return 0;
 error:
-       ssb_printk(KERN_ERR PFX "Failed to switch to core %u\n", coreidx);
+       ssb_err("Failed to switch to core %u\n", coreidx);
        return -ENODEV;
 }
 
@@ -67,10 +67,9 @@ int ssb_pci_switch_core(struct ssb_bus *bus,
        unsigned long flags;
 
 #if SSB_VERBOSE_PCICORESWITCH_DEBUG
-       ssb_printk(KERN_INFO PFX
-                  "Switching to %s core, index %d\n",
-                  ssb_core_name(dev->id.coreid),
-                  dev->core_index);
+       ssb_info("Switching to %s core, index %d\n",
+                ssb_core_name(dev->id.coreid),
+                dev->core_index);
 #endif
 
        spin_lock_irqsave(&bus->bar_lock, flags);
@@ -231,6 +230,15 @@ static inline u8 ssb_crc8(u8 crc, u8 data)
        return t[crc ^ data];
 }
 
+static void sprom_get_mac(char *mac, const u16 *in)
+{
+       int i;
+       for (i = 0; i < 3; i++) {
+               *mac++ = in[i] >> 8;
+               *mac++ = in[i];
+       }
+}
+
 static u8 ssb_sprom_crc(const u16 *sprom, u16 size)
 {
        int word;
@@ -278,7 +286,7 @@ static int sprom_do_write(struct ssb_bus *bus, const u16 *sprom)
        u32 spromctl;
        u16 size = bus->sprom_size;
 
-       ssb_printk(KERN_NOTICE PFX "Writing SPROM. Do NOT turn off the power! Please stand by...\n");
+       ssb_notice("Writing SPROM. Do NOT turn off the power! Please stand by...\n");
        err = pci_read_config_dword(pdev, SSB_SPROMCTL, &spromctl);
        if (err)
                goto err_ctlreg;
@@ -286,17 +294,17 @@ static int sprom_do_write(struct ssb_bus *bus, const u16 *sprom)
        err = pci_write_config_dword(pdev, SSB_SPROMCTL, spromctl);
        if (err)
                goto err_ctlreg;
-       ssb_printk(KERN_NOTICE PFX "[ 0%%");
+       ssb_notice("[ 0%%");
        msleep(500);
        for (i = 0; i < size; i++) {
                if (i == size / 4)
-                       ssb_printk("25%%");
+                       ssb_cont("25%%");
                else if (i == size / 2)
-                       ssb_printk("50%%");
+                       ssb_cont("50%%");
                else if (i == (size * 3) / 4)
-                       ssb_printk("75%%");
+                       ssb_cont("75%%");
                else if (i % 2)
-                       ssb_printk(".");
+                       ssb_cont(".");
                writew(sprom[i], bus->mmio + bus->sprom_offset + (i * 2));
                mmiowb();
                msleep(20);
@@ -309,12 +317,12 @@ static int sprom_do_write(struct ssb_bus *bus, const u16 *sprom)
        if (err)
                goto err_ctlreg;
        msleep(500);
-       ssb_printk("100%% ]\n");
-       ssb_printk(KERN_NOTICE PFX "SPROM written.\n");
+       ssb_cont("100%% ]\n");
+       ssb_notice("SPROM written\n");
 
        return 0;
 err_ctlreg:
-       ssb_printk(KERN_ERR PFX "Could not access SPROM control register.\n");
+       ssb_err("Could not access SPROM control register.\n");
        return err;
 }
 
@@ -341,8 +349,6 @@ static s8 r123_extract_antgain(u8 sprom_revision, const u16 *in,
 
 static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in)
 {
-       int i;
-       u16 v;
        u16 loc[3];
 
        if (out->revision == 3)                 /* rev 3 moved MAC */
@@ -352,19 +358,10 @@ static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in)
                loc[1] = SSB_SPROM1_ET0MAC;
                loc[2] = SSB_SPROM1_ET1MAC;
        }
-       for (i = 0; i < 3; i++) {
-               v = in[SPOFF(loc[0]) + i];
-               *(((__be16 *)out->il0mac) + i) = cpu_to_be16(v);
-       }
+       sprom_get_mac(out->il0mac, &in[SPOFF(loc[0])]);
        if (out->revision < 3) {        /* only rev 1-2 have et0, et1 */
-               for (i = 0; i < 3; i++) {
-                       v = in[SPOFF(loc[1]) + i];
-                       *(((__be16 *)out->et0mac) + i) = cpu_to_be16(v);
-               }
-               for (i = 0; i < 3; i++) {
-                       v = in[SPOFF(loc[2]) + i];
-                       *(((__be16 *)out->et1mac) + i) = cpu_to_be16(v);
-               }
+               sprom_get_mac(out->et0mac, &in[SPOFF(loc[1])]);
+               sprom_get_mac(out->et1mac, &in[SPOFF(loc[2])]);
        }
        SPEX(et0phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0A, 0);
        SPEX(et1phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1A,
@@ -454,19 +451,15 @@ static void sprom_extract_r458(struct ssb_sprom *out, const u16 *in)
 
 static void sprom_extract_r45(struct ssb_sprom *out, const u16 *in)
 {
-       int i;
-       u16 v;
        u16 il0mac_offset;
 
        if (out->revision == 4)
                il0mac_offset = SSB_SPROM4_IL0MAC;
        else
                il0mac_offset = SSB_SPROM5_IL0MAC;
-       /* extract the MAC address */
-       for (i = 0; i < 3; i++) {
-               v = in[SPOFF(il0mac_offset) + i];
-               *(((__be16 *)out->il0mac) + i) = cpu_to_be16(v);
-       }
+
+       sprom_get_mac(out->il0mac, &in[SPOFF(il0mac_offset)]);
+
        SPEX(et0phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET0A, 0);
        SPEX(et1phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET1A,
             SSB_SPROM4_ETHPHY_ET1A_SHIFT);
@@ -530,7 +523,7 @@ static void sprom_extract_r45(struct ssb_sprom *out, const u16 *in)
 static void sprom_extract_r8(struct ssb_sprom *out, const u16 *in)
 {
        int i;
-       u16 v, o;
+       u16 o;
        u16 pwr_info_offset[] = {
                SSB_SROM8_PWR_INFO_CORE0, SSB_SROM8_PWR_INFO_CORE1,
                SSB_SROM8_PWR_INFO_CORE2, SSB_SROM8_PWR_INFO_CORE3
@@ -539,10 +532,8 @@ static void sprom_extract_r8(struct ssb_sprom *out, const u16 *in)
                        ARRAY_SIZE(out->core_pwr_info));
 
        /* extract the MAC address */
-       for (i = 0; i < 3; i++) {
-               v = in[SPOFF(SSB_SPROM8_IL0MAC) + i];
-               *(((__be16 *)out->il0mac) + i) = cpu_to_be16(v);
-       }
+       sprom_get_mac(out->il0mac, &in[SPOFF(SSB_SPROM8_IL0MAC)]);
+
        SPEX(board_rev, SSB_SPROM8_BOARDREV, 0xFFFF, 0);
        SPEX(alpha2[0], SSB_SPROM8_CCODE, 0xff00, 8);
        SPEX(alpha2[1], SSB_SPROM8_CCODE, 0x00ff, 0);
@@ -743,7 +734,7 @@ static int sprom_extract(struct ssb_bus *bus, struct ssb_sprom *out,
        memset(out, 0, sizeof(*out));
 
        out->revision = in[size - 1] & 0x00FF;
-       ssb_dprintk(KERN_DEBUG PFX "SPROM revision %d detected.\n", out->revision);
+       ssb_dbg("SPROM revision %d detected\n", out->revision);
        memset(out->et0mac, 0xFF, 6);           /* preset et0 and et1 mac */
        memset(out->et1mac, 0xFF, 6);
 
@@ -752,7 +743,7 @@ static int sprom_extract(struct ssb_bus *bus, struct ssb_sprom *out,
                 * number stored in the SPROM.
                 * Always extract r1. */
                out->revision = 1;
-               ssb_dprintk(KERN_DEBUG PFX "SPROM treated as revision %d\n", out->revision);
+               ssb_dbg("SPROM treated as revision %d\n", out->revision);
        }
 
        switch (out->revision) {
@@ -769,9 +760,8 @@ static int sprom_extract(struct ssb_bus *bus, struct ssb_sprom *out,
                sprom_extract_r8(out, in);
                break;
        default:
-               ssb_printk(KERN_WARNING PFX "Unsupported SPROM"
-                          " revision %d detected. Will extract"
-                          " v1\n", out->revision);
+               ssb_warn("Unsupported SPROM revision %d detected. Will extract v1\n",
+                        out->revision);
                out->revision = 1;
                sprom_extract_r123(out, in);
        }
@@ -791,7 +781,7 @@ static int ssb_pci_sprom_get(struct ssb_bus *bus,
        u16 *buf;
 
        if (!ssb_is_sprom_available(bus)) {
-               ssb_printk(KERN_ERR PFX "No SPROM available!\n");
+               ssb_err("No SPROM available!\n");
                return -ENODEV;
        }
        if (bus->chipco.dev) {  /* can be unavailable! */
@@ -810,7 +800,7 @@ static int ssb_pci_sprom_get(struct ssb_bus *bus,
        } else {
                bus->sprom_offset = SSB_SPROM_BASE1;
        }
-       ssb_dprintk(KERN_INFO PFX "SPROM offset is 0x%x\n", bus->sprom_offset);
+       ssb_dbg("SPROM offset is 0x%x\n", bus->sprom_offset);
 
        buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL);
        if (!buf)
@@ -835,18 +825,15 @@ static int ssb_pci_sprom_get(struct ssb_bus *bus,
                         * available for this device in some other storage */
                        err = ssb_fill_sprom_with_fallback(bus, sprom);
                        if (err) {
-                               ssb_printk(KERN_WARNING PFX "WARNING: Using"
-                                          " fallback SPROM failed (err %d)\n",
-                                          err);
+                               ssb_warn("WARNING: Using fallback SPROM failed (err %d)\n",
+                                        err);
                        } else {
-                               ssb_dprintk(KERN_DEBUG PFX "Using SPROM"
-                                           " revision %d provided by"
-                                           " platform.\n", sprom->revision);
+                               ssb_dbg("Using SPROM revision %d provided by platform\n",
+                                       sprom->revision);
                                err = 0;
                                goto out_free;
                        }
-                       ssb_printk(KERN_WARNING PFX "WARNING: Invalid"
-                                  " SPROM CRC (corrupt SPROM)\n");
+                       ssb_warn("WARNING: Invalid SPROM CRC (corrupt SPROM)\n");
                }
        }
        err = sprom_extract(bus, sprom, buf, bus->sprom_size);
index fbafed5..b413e01 100644 (file)
@@ -143,7 +143,7 @@ int ssb_pcmcia_switch_coreidx(struct ssb_bus *bus,
 
        return 0;
 error:
-       ssb_printk(KERN_ERR PFX "Failed to switch to core %u\n", coreidx);
+       ssb_err("Failed to switch to core %u\n", coreidx);
        return err;
 }
 
@@ -153,10 +153,9 @@ int ssb_pcmcia_switch_core(struct ssb_bus *bus,
        int err;
 
 #if SSB_VERBOSE_PCMCIACORESWITCH_DEBUG
-       ssb_printk(KERN_INFO PFX
-                  "Switching to %s core, index %d\n",
-                  ssb_core_name(dev->id.coreid),
-                  dev->core_index);
+       ssb_info("Switching to %s core, index %d\n",
+                ssb_core_name(dev->id.coreid),
+                dev->core_index);
 #endif
 
        err = ssb_pcmcia_switch_coreidx(bus, dev->core_index);
@@ -192,7 +191,7 @@ int ssb_pcmcia_switch_segment(struct ssb_bus *bus, u8 seg)
 
        return 0;
 error:
-       ssb_printk(KERN_ERR PFX "Failed to switch pcmcia segment\n");
+       ssb_err("Failed to switch pcmcia segment\n");
        return err;
 }
 
@@ -549,44 +548,39 @@ static int ssb_pcmcia_sprom_write_all(struct ssb_bus *bus, const u16 *sprom)
        bool failed = 0;
        size_t size = SSB_PCMCIA_SPROM_SIZE;
 
-       ssb_printk(KERN_NOTICE PFX
-                  "Writing SPROM. Do NOT turn off the power! "
-                  "Please stand by...\n");
+       ssb_notice("Writing SPROM. Do NOT turn off the power! Please stand by...\n");
        err = ssb_pcmcia_sprom_command(bus, SSB_PCMCIA_SPROMCTL_WRITEEN);
        if (err) {
-               ssb_printk(KERN_NOTICE PFX
-                          "Could not enable SPROM write access.\n");
+               ssb_notice("Could not enable SPROM write access\n");
                return -EBUSY;
        }
-       ssb_printk(KERN_NOTICE PFX "[ 0%%");
+       ssb_notice("[ 0%%");
        msleep(500);
        for (i = 0; i < size; i++) {
                if (i == size / 4)
-                       ssb_printk("25%%");
+                       ssb_cont("25%%");
                else if (i == size / 2)
-                       ssb_printk("50%%");
+                       ssb_cont("50%%");
                else if (i == (size * 3) / 4)
-                       ssb_printk("75%%");
+                       ssb_cont("75%%");
                else if (i % 2)
-                       ssb_printk(".");
+                       ssb_cont(".");
                err = ssb_pcmcia_sprom_write(bus, i, sprom[i]);
                if (err) {
-                       ssb_printk(KERN_NOTICE PFX
-                                  "Failed to write to SPROM.\n");
+                       ssb_notice("Failed to write to SPROM\n");
                        failed = 1;
                        break;
                }
        }
        err = ssb_pcmcia_sprom_command(bus, SSB_PCMCIA_SPROMCTL_WRITEDIS);
        if (err) {
-               ssb_printk(KERN_NOTICE PFX
-                          "Could not disable SPROM write access.\n");
+               ssb_notice("Could not disable SPROM write access\n");
                failed = 1;
        }
        msleep(500);
        if (!failed) {
-               ssb_printk("100%% ]\n");
-               ssb_printk(KERN_NOTICE PFX "SPROM written.\n");
+               ssb_cont("100%% ]\n");
+               ssb_notice("SPROM written\n");
        }
 
        return failed ? -EBUSY : 0;
@@ -700,7 +694,7 @@ static int ssb_pcmcia_do_get_invariants(struct pcmcia_device *p_dev,
        return -ENOSPC; /* continue with next entry */
 
 error:
-       ssb_printk(KERN_ERR PFX
+       ssb_err(
                   "PCMCIA: Failed to fetch device invariants: %s\n",
                   error_description);
        return -ENODEV;
@@ -722,7 +716,7 @@ int ssb_pcmcia_get_invariants(struct ssb_bus *bus,
        res = pcmcia_loop_tuple(bus->host_pcmcia, CISTPL_FUNCE,
                                ssb_pcmcia_get_mac, sprom);
        if (res != 0) {
-               ssb_printk(KERN_ERR PFX
+               ssb_err(
                        "PCMCIA: Failed to fetch MAC address\n");
                return -ENODEV;
        }
@@ -733,7 +727,7 @@ int ssb_pcmcia_get_invariants(struct ssb_bus *bus,
        if ((res == 0) || (res == -ENOSPC))
                return 0;
 
-       ssb_printk(KERN_ERR PFX
+       ssb_err(
                        "PCMCIA: Failed to fetch device invariants\n");
        return -ENODEV;
 }
@@ -843,6 +837,6 @@ int ssb_pcmcia_init(struct ssb_bus *bus)
 
        return 0;
 error:
-       ssb_printk(KERN_ERR PFX "Failed to initialize PCMCIA host device\n");
+       ssb_err("Failed to initialize PCMCIA host device\n");
        return err;
 }
index ab4627c..b9429df 100644 (file)
@@ -125,8 +125,7 @@ static u16 pcidev_to_chipid(struct pci_dev *pci_dev)
                chipid_fallback = 0x4401;
                break;
        default:
-               ssb_printk(KERN_ERR PFX
-                          "PCI-ID not in fallback list\n");
+               ssb_err("PCI-ID not in fallback list\n");
        }
 
        return chipid_fallback;
@@ -152,8 +151,7 @@ static u8 chipid_to_nrcores(u16 chipid)
        case 0x4704:
                return 9;
        default:
-               ssb_printk(KERN_ERR PFX
-                          "CHIPID not in nrcores fallback list\n");
+               ssb_err("CHIPID not in nrcores fallback list\n");
        }
 
        return 1;
@@ -320,15 +318,13 @@ int ssb_bus_scan(struct ssb_bus *bus,
                        bus->chip_package = 0;
                }
        }
-       ssb_printk(KERN_INFO PFX "Found chip with id 0x%04X, rev 0x%02X and "
-                  "package 0x%02X\n", bus->chip_id, bus->chip_rev,
-                  bus->chip_package);
+       ssb_info("Found chip with id 0x%04X, rev 0x%02X and package 0x%02X\n",
+                bus->chip_id, bus->chip_rev, bus->chip_package);
        if (!bus->nr_devices)
                bus->nr_devices = chipid_to_nrcores(bus->chip_id);
        if (bus->nr_devices > ARRAY_SIZE(bus->devices)) {
-               ssb_printk(KERN_ERR PFX
-                          "More than %d ssb cores found (%d)\n",
-                          SSB_MAX_NR_CORES, bus->nr_devices);
+               ssb_err("More than %d ssb cores found (%d)\n",
+                       SSB_MAX_NR_CORES, bus->nr_devices);
                goto err_unmap;
        }
        if (bus->bustype == SSB_BUSTYPE_SSB) {
@@ -370,8 +366,7 @@ int ssb_bus_scan(struct ssb_bus *bus,
                        nr_80211_cores++;
                        if (nr_80211_cores > 1) {
                                if (!we_support_multiple_80211_cores(bus)) {
-                                       ssb_dprintk(KERN_INFO PFX "Ignoring additional "
-                                                   "802.11 core\n");
+                                       ssb_dbg("Ignoring additional 802.11 core\n");
                                        continue;
                                }
                        }
@@ -379,8 +374,7 @@ int ssb_bus_scan(struct ssb_bus *bus,
                case SSB_DEV_EXTIF:
 #ifdef CONFIG_SSB_DRIVER_EXTIF
                        if (bus->extif.dev) {
-                               ssb_printk(KERN_WARNING PFX
-                                          "WARNING: Multiple EXTIFs found\n");
+                               ssb_warn("WARNING: Multiple EXTIFs found\n");
                                break;
                        }
                        bus->extif.dev = dev;
@@ -388,8 +382,7 @@ int ssb_bus_scan(struct ssb_bus *bus,
                        break;
                case SSB_DEV_CHIPCOMMON:
                        if (bus->chipco.dev) {
-                               ssb_printk(KERN_WARNING PFX
-                                          "WARNING: Multiple ChipCommon found\n");
+                               ssb_warn("WARNING: Multiple ChipCommon found\n");
                                break;
                        }
                        bus->chipco.dev = dev;
@@ -398,8 +391,7 @@ int ssb_bus_scan(struct ssb_bus *bus,
                case SSB_DEV_MIPS_3302:
 #ifdef CONFIG_SSB_DRIVER_MIPS
                        if (bus->mipscore.dev) {
-                               ssb_printk(KERN_WARNING PFX
-                                          "WARNING: Multiple MIPS cores found\n");
+                               ssb_warn("WARNING: Multiple MIPS cores found\n");
                                break;
                        }
                        bus->mipscore.dev = dev;
@@ -420,8 +412,7 @@ int ssb_bus_scan(struct ssb_bus *bus,
                                }
                        }
                        if (bus->pcicore.dev) {
-                               ssb_printk(KERN_WARNING PFX
-                                          "WARNING: Multiple PCI(E) cores found\n");
+                               ssb_warn("WARNING: Multiple PCI(E) cores found\n");
                                break;
                        }
                        bus->pcicore.dev = dev;
index 80d366f..a3b2364 100644 (file)
@@ -127,13 +127,13 @@ ssize_t ssb_attr_sprom_store(struct ssb_bus *bus,
                goto out_kfree;
        err = ssb_devices_freeze(bus, &freeze);
        if (err) {
-               ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze all devices\n");
+               ssb_err("SPROM write: Could not freeze all devices\n");
                goto out_unlock;
        }
        res = sprom_write(bus, sprom);
        err = ssb_devices_thaw(&freeze);
        if (err)
-               ssb_printk(KERN_ERR PFX "SPROM write: Could not thaw all devices\n");
+               ssb_err("SPROM write: Could not thaw all devices\n");
 out_unlock:
        mutex_unlock(&bus->sprom_mutex);
 out_kfree:
index 466171b..4671f17 100644 (file)
@@ -9,16 +9,27 @@
 #define PFX    "ssb: "
 
 #ifdef CONFIG_SSB_SILENT
-# define ssb_printk(fmt, x...) do { /* nothing */ } while (0)
+# define ssb_printk(fmt, ...)                                  \
+       do { if (0) printk(fmt, ##__VA_ARGS__); } while (0)
 #else
-# define ssb_printk            printk
+# define ssb_printk(fmt, ...)                                  \
+       printk(fmt, ##__VA_ARGS__)
 #endif /* CONFIG_SSB_SILENT */
 
+#define ssb_emerg(fmt, ...)    ssb_printk(KERN_EMERG PFX fmt, ##__VA_ARGS__)
+#define ssb_err(fmt, ...)      ssb_printk(KERN_ERR PFX fmt, ##__VA_ARGS__)
+#define ssb_warn(fmt, ...)     ssb_printk(KERN_WARNING PFX fmt, ##__VA_ARGS__)
+#define ssb_notice(fmt, ...)   ssb_printk(KERN_NOTICE PFX fmt, ##__VA_ARGS__)
+#define ssb_info(fmt, ...)     ssb_printk(KERN_INFO PFX fmt, ##__VA_ARGS__)
+#define ssb_cont(fmt, ...)     ssb_printk(KERN_CONT fmt, ##__VA_ARGS__)
+
 /* dprintk: Debugging printk; vanishes for non-debug compilation */
 #ifdef CONFIG_SSB_DEBUG
-# define ssb_dprintk(fmt, x...)        ssb_printk(fmt , ##x)
+# define ssb_dbg(fmt, ...)                                     \
+       ssb_printk(KERN_DEBUG PFX fmt, ##__VA_ARGS__)
 #else
-# define ssb_dprintk(fmt, x...)        do { /* nothing */ } while (0)
+# define ssb_dbg(fmt, ...)                                     \
+       do { if (0) printk(KERN_DEBUG PFX fmt, ##__VA_ARGS__); } while (0)
 #endif
 
 #ifdef CONFIG_SSB_DEBUG
index 7e24fe0..4cf0c9e 100644 (file)
 #define IEEE80211_CTL_EXT_SSW_FBACK    0x9000
 #define IEEE80211_CTL_EXT_SSW_ACK      0xa000
 
+
+#define IEEE80211_SN_MASK              ((IEEE80211_SCTL_SEQ) >> 4)
+#define IEEE80211_MAX_SN               IEEE80211_SN_MASK
+#define IEEE80211_SN_MODULO            (IEEE80211_MAX_SN + 1)
+
+static inline int ieee80211_sn_less(u16 sn1, u16 sn2)
+{
+       return ((sn1 - sn2) & IEEE80211_SN_MASK) > (IEEE80211_SN_MODULO >> 1);
+}
+
+static inline u16 ieee80211_sn_add(u16 sn1, u16 sn2)
+{
+       return (sn1 + sn2) & IEEE80211_SN_MASK;
+}
+
+static inline u16 ieee80211_sn_inc(u16 sn)
+{
+       return ieee80211_sn_add(sn, 1);
+}
+
+static inline u16 ieee80211_sn_sub(u16 sn1, u16 sn2)
+{
+       return (sn1 - sn2) & IEEE80211_SN_MASK;
+}
+
+#define IEEE80211_SEQ_TO_SN(seq)       (((seq) & IEEE80211_SCTL_SEQ) >> 4)
+#define IEEE80211_SN_TO_SEQ(ssn)       (((ssn) << 4) & IEEE80211_SCTL_SEQ)
+
 /* miscellaneous IEEE 802.11 constants */
 #define IEEE80211_MAX_FRAG_THRESHOLD   2352
 #define IEEE80211_MAX_RTS_THRESHOLD    2353
@@ -185,7 +213,7 @@ struct ieee80211_hdr {
        u8 addr3[6];
        __le16 seq_ctrl;
        u8 addr4[6];
-} __packed;
+} __packed __aligned(2);
 
 struct ieee80211_hdr_3addr {
        __le16 frame_control;
@@ -194,7 +222,7 @@ struct ieee80211_hdr_3addr {
        u8 addr2[6];
        u8 addr3[6];
        __le16 seq_ctrl;
-} __packed;
+} __packed __aligned(2);
 
 struct ieee80211_qos_hdr {
        __le16 frame_control;
@@ -204,7 +232,7 @@ struct ieee80211_qos_hdr {
        u8 addr3[6];
        __le16 seq_ctrl;
        __le16 qos_ctrl;
-} __packed;
+} __packed __aligned(2);
 
 /**
  * ieee80211_has_tods - check if IEEE80211_FCTL_TODS is set
@@ -581,7 +609,7 @@ struct ieee80211s_hdr {
        __le32 seqnum;
        u8 eaddr1[6];
        u8 eaddr2[6];
-} __packed;
+} __packed __aligned(2);
 
 /* Mesh flags */
 #define MESH_FLAGS_AE_A4       0x1
@@ -875,7 +903,7 @@ struct ieee80211_mgmt {
                        } u;
                } __packed action;
        } u;
-} __packed;
+} __packed __aligned(2);
 
 /* Supported Rates value encodings in 802.11n-2009 7.3.2.2 */
 #define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127
@@ -906,20 +934,20 @@ struct ieee80211_rts {
        __le16 duration;
        u8 ra[6];
        u8 ta[6];
-} __packed;
+} __packed __aligned(2);
 
 struct ieee80211_cts {
        __le16 frame_control;
        __le16 duration;
        u8 ra[6];
-} __packed;
+} __packed __aligned(2);
 
 struct ieee80211_pspoll {
        __le16 frame_control;
        __le16 aid;
        u8 bssid[6];
        u8 ta[6];
-} __packed;
+} __packed __aligned(2);
 
 /* TDLS */
 
@@ -1290,11 +1318,6 @@ struct ieee80211_vht_operation {
 } __packed;
 
 
-#define IEEE80211_VHT_MCS_ZERO_TO_SEVEN_SUPPORT 0
-#define IEEE80211_VHT_MCS_ZERO_TO_EIGHT_SUPPORT 1
-#define IEEE80211_VHT_MCS_ZERO_TO_NINE_SUPPORT  2
-#define IEEE80211_VHT_MCS_NOT_SUPPORTED 3
-
 /* 802.11ac VHT Capabilities */
 #define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895                 0x00000000
 #define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991                 0x00000001
@@ -1310,10 +1333,11 @@ struct ieee80211_vht_operation {
 #define IEEE80211_VHT_CAP_RXSTBC_2                             0x00000200
 #define IEEE80211_VHT_CAP_RXSTBC_3                             0x00000300
 #define IEEE80211_VHT_CAP_RXSTBC_4                             0x00000400
+#define IEEE80211_VHT_CAP_RXSTBC_MASK                          0x00000700
 #define IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE                        0x00000800
 #define IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE                        0x00001000
 #define IEEE80211_VHT_CAP_BEAMFORMER_ANTENNAS_MAX              0x00006000
-#define IEEE80211_VHT_CAP_SOUNDING_DIMENTION_MAX               0x00030000
+#define IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MAX              0x00030000
 #define IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE                        0x00080000
 #define IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE                        0x00100000
 #define IEEE80211_VHT_CAP_VHT_TXOP_PS                          0x00200000
index 2b9f74b..428c37a 100644 (file)
@@ -298,6 +298,7 @@ struct ucred {
 #define SOL_IUCV       277
 #define SOL_CAIF       278
 #define SOL_ALG                279
+#define SOL_NFC                280
 
 /* IPX options */
 #define IPX_TYPE       1
index 22958d6..8b13222 100644 (file)
@@ -26,9 +26,9 @@ struct ssb_sprom_core_pwr_info {
 
 struct ssb_sprom {
        u8 revision;
-       u8 il0mac[6];           /* MAC address for 802.11b/g */
-       u8 et0mac[6];           /* MAC address for Ethernet */
-       u8 et1mac[6];           /* MAC address for 802.11a */
+       u8 il0mac[6] __aligned(sizeof(u16));    /* MAC address for 802.11b/g */
+       u8 et0mac[6] __aligned(sizeof(u16));    /* MAC address for Ethernet */
+       u8 et1mac[6] __aligned(sizeof(u16));    /* MAC address for 802.11a */
        u8 et0phyaddr;          /* MII address for enet0 */
        u8 et1phyaddr;          /* MII address for enet1 */
        u8 et0mdcport;          /* MDIO for enet0 */
index d581c6d..bdba9b6 100644 (file)
@@ -610,23 +610,11 @@ struct cfg80211_ap_settings {
        bool radar_required;
 };
 
-/**
- * enum plink_action - actions to perform in mesh peers
- *
- * @PLINK_ACTION_INVALID: action 0 is reserved
- * @PLINK_ACTION_OPEN: start mesh peer link establishment
- * @PLINK_ACTION_BLOCK: block traffic from this mesh peer
- */
-enum plink_actions {
-       PLINK_ACTION_INVALID,
-       PLINK_ACTION_OPEN,
-       PLINK_ACTION_BLOCK,
-};
-
 /**
  * enum station_parameters_apply_mask - station parameter values to apply
  * @STATION_PARAM_APPLY_UAPSD: apply new uAPSD parameters (uapsd_queues, max_sp)
  * @STATION_PARAM_APPLY_CAPABILITY: apply new capability
+ * @STATION_PARAM_APPLY_PLINK_STATE: apply new plink state
  *
  * Not all station parameters have in-band "no change" signalling,
  * for those that don't these flags will are used.
@@ -634,6 +622,7 @@ enum plink_actions {
 enum station_parameters_apply_mask {
        STATION_PARAM_APPLY_UAPSD = BIT(0),
        STATION_PARAM_APPLY_CAPABILITY = BIT(1),
+       STATION_PARAM_APPLY_PLINK_STATE = BIT(2),
 };
 
 /**
@@ -669,7 +658,7 @@ enum station_parameters_apply_mask {
  * @ext_capab_len: number of extended capabilities
  */
 struct station_parameters {
-       u8 *supported_rates;
+       const u8 *supported_rates;
        struct net_device *vlan;
        u32 sta_flags_mask, sta_flags_set;
        u32 sta_modify_mask;
@@ -678,16 +667,59 @@ struct station_parameters {
        u8 supported_rates_len;
        u8 plink_action;
        u8 plink_state;
-       struct ieee80211_ht_cap *ht_capa;
-       struct ieee80211_vht_cap *vht_capa;
+       const struct ieee80211_ht_cap *ht_capa;
+       const struct ieee80211_vht_cap *vht_capa;
        u8 uapsd_queues;
        u8 max_sp;
        enum nl80211_mesh_power_mode local_pm;
        u16 capability;
-       u8 *ext_capab;
+       const u8 *ext_capab;
        u8 ext_capab_len;
 };
 
+/**
+ * enum cfg80211_station_type - the type of station being modified
+ * @CFG80211_STA_AP_CLIENT: client of an AP interface
+ * @CFG80211_STA_AP_MLME_CLIENT: client of an AP interface that has
+ *     the AP MLME in the device
+ * @CFG80211_STA_AP_STA: AP station on managed interface
+ * @CFG80211_STA_IBSS: IBSS station
+ * @CFG80211_STA_TDLS_PEER_SETUP: TDLS peer on managed interface (dummy entry
+ *     while TDLS setup is in progress, it moves out of this state when
+ *     being marked authorized; use this only if TDLS with external setup is
+ *     supported/used)
+ * @CFG80211_STA_TDLS_PEER_ACTIVE: TDLS peer on managed interface (active
+ *     entry that is operating, has been marked authorized by userspace)
+ * @CFG80211_STA_MESH_PEER_KERNEL: peer on mesh interface (kernel managed)
+ * @CFG80211_STA_MESH_PEER_USER: peer on mesh interface (user managed)
+ */
+enum cfg80211_station_type {
+       CFG80211_STA_AP_CLIENT,
+       CFG80211_STA_AP_MLME_CLIENT,
+       CFG80211_STA_AP_STA,
+       CFG80211_STA_IBSS,
+       CFG80211_STA_TDLS_PEER_SETUP,
+       CFG80211_STA_TDLS_PEER_ACTIVE,
+       CFG80211_STA_MESH_PEER_KERNEL,
+       CFG80211_STA_MESH_PEER_USER,
+};
+
+/**
+ * cfg80211_check_station_change - validate parameter changes
+ * @wiphy: the wiphy this operates on
+ * @params: the new parameters for a station
+ * @statype: the type of station being modified
+ *
+ * Utility function for the @change_station driver method. Call this function
+ * with the appropriate station type looking up the station (and checking that
+ * it exists). It will verify whether the station change is acceptable, and if
+ * not will return an error code. Note that it may modify the parameters for
+ * backward compatibility reasons, so don't use them before calling this.
+ */
+int cfg80211_check_station_change(struct wiphy *wiphy,
+                                 struct station_parameters *params,
+                                 enum cfg80211_station_type statype);
+
 /**
  * enum station_info_flags - station information flags
  *
@@ -1119,6 +1151,7 @@ struct mesh_config {
  * @ie_len: length of vendor information elements
  * @is_authenticated: this mesh requires authentication
  * @is_secure: this mesh uses security
+ * @user_mpm: userspace handles all MPM functions
  * @dtim_period: DTIM period to use
  * @beacon_interval: beacon interval to use
  * @mcast_rate: multicat rate for Mesh Node [6Mbps is the default for 802.11a]
@@ -1136,6 +1169,7 @@ struct mesh_setup {
        u8 ie_len;
        bool is_authenticated;
        bool is_secure;
+       bool user_mpm;
        u8 dtim_period;
        u16 beacon_interval;
        int mcast_rate[IEEE80211_NUM_BANDS];
@@ -1398,9 +1432,11 @@ struct cfg80211_auth_request {
  * enum cfg80211_assoc_req_flags - Over-ride default behaviour in association.
  *
  * @ASSOC_REQ_DISABLE_HT:  Disable HT (802.11n)
+ * @ASSOC_REQ_DISABLE_VHT:  Disable VHT
  */
 enum cfg80211_assoc_req_flags {
        ASSOC_REQ_DISABLE_HT            = BIT(0),
+       ASSOC_REQ_DISABLE_VHT           = BIT(1),
 };
 
 /**
@@ -1422,6 +1458,8 @@ enum cfg80211_assoc_req_flags {
  * @ht_capa:  HT Capabilities over-rides.  Values set in ht_capa_mask
  *   will be used in ht_capa.  Un-supported values will be ignored.
  * @ht_capa_mask:  The bits of ht_capa which are to be used.
+ * @vht_capa: VHT capability override
+ * @vht_capa_mask: VHT capability mask indicating which fields to use
  */
 struct cfg80211_assoc_request {
        struct cfg80211_bss *bss;
@@ -1432,6 +1470,7 @@ struct cfg80211_assoc_request {
        u32 flags;
        struct ieee80211_ht_cap ht_capa;
        struct ieee80211_ht_cap ht_capa_mask;
+       struct ieee80211_vht_cap vht_capa, vht_capa_mask;
 };
 
 /**
@@ -1542,6 +1581,8 @@ struct cfg80211_ibss_params {
  * @ht_capa:  HT Capabilities over-rides.  Values set in ht_capa_mask
  *   will be used in ht_capa.  Un-supported values will be ignored.
  * @ht_capa_mask:  The bits of ht_capa which are to be used.
+ * @vht_capa:  VHT Capability overrides
+ * @vht_capa_mask: The bits of vht_capa which are to be used.
  */
 struct cfg80211_connect_params {
        struct ieee80211_channel *channel;
@@ -1560,6 +1601,8 @@ struct cfg80211_connect_params {
        int bg_scan_period;
        struct ieee80211_ht_cap ht_capa;
        struct ieee80211_ht_cap ht_capa_mask;
+       struct ieee80211_vht_cap vht_capa;
+       struct ieee80211_vht_cap vht_capa_mask;
 };
 
 /**
@@ -1721,6 +1764,21 @@ struct cfg80211_gtk_rekey_data {
        u8 replay_ctr[NL80211_REPLAY_CTR_LEN];
 };
 
+/**
+ * struct cfg80211_update_ft_ies_params - FT IE Information
+ *
+ * This structure provides information needed to update the fast transition IE
+ *
+ * @md: The Mobility Domain ID, 2 Octet value
+ * @ie: Fast Transition IEs
+ * @ie_len: Length of ft_ie in octets
+ */
+struct cfg80211_update_ft_ies_params {
+       u16 md;
+       const u8 *ie;
+       size_t ie_len;
+};
+
 /**
  * struct cfg80211_ops - backend description for wireless configuration
  *
@@ -1781,9 +1839,8 @@ struct cfg80211_gtk_rekey_data {
  * @change_station: Modify a given station. Note that flags changes are not much
  *     validated in cfg80211, in particular the auth/assoc/authorized flags
  *     might come to the driver in invalid combinations -- make sure to check
- *     them, also against the existing state! Also, supported_rates changes are
- *     not checked in station mode -- drivers need to reject (or ignore) them
- *     for anything but TDLS peers.
+ *     them, also against the existing state! Drivers must call
+ *     cfg80211_check_station_change() to validate the information.
  * @get_station: get station information for the station identified by @mac
  * @dump_station: dump station callback -- resume dump at index @idx
  *
@@ -2168,6 +2225,8 @@ struct cfg80211_ops {
        int     (*start_radar_detection)(struct wiphy *wiphy,
                                         struct net_device *dev,
                                         struct cfg80211_chan_def *chandef);
+       int     (*update_ft_ies)(struct wiphy *wiphy, struct net_device *dev,
+                                struct cfg80211_update_ft_ies_params *ftie);
 };
 
 /*
@@ -2485,6 +2544,8 @@ struct wiphy_wowlan_support {
  * @ap_sme_capa: AP SME capabilities, flags from &enum nl80211_ap_sme_features.
  * @ht_capa_mod_mask:  Specify what ht_cap values can be over-ridden.
  *     If null, then none can be over-ridden.
+ * @vht_capa_mod_mask:  Specify what VHT capabilities can be over-ridden.
+ *     If null, then none can be over-ridden.
  *
  * @max_acl_mac_addrs: Maximum number of MAC addresses that the device
  *     supports for ACL.
@@ -2593,6 +2654,7 @@ struct wiphy {
        struct dentry *debugfsdir;
 
        const struct ieee80211_ht_cap *ht_capa_mod_mask;
+       const struct ieee80211_vht_cap *vht_capa_mod_mask;
 
 #ifdef CONFIG_NET_NS
        /* the network namespace this phy lives in currently */
@@ -4001,6 +4063,30 @@ u32 cfg80211_calculate_bitrate(struct rate_info *rate);
  */
 void cfg80211_unregister_wdev(struct wireless_dev *wdev);
 
+/**
+ * struct cfg80211_ft_event - FT Information Elements
+ * @ies: FT IEs
+ * @ies_len: length of the FT IE in bytes
+ * @target_ap: target AP's MAC address
+ * @ric_ies: RIC IE
+ * @ric_ies_len: length of the RIC IE in bytes
+ */
+struct cfg80211_ft_event_params {
+       const u8 *ies;
+       size_t ies_len;
+       const u8 *target_ap;
+       const u8 *ric_ies;
+       size_t ric_ies_len;
+};
+
+/**
+ * cfg80211_ft_event - notify userspace about FT IE and RIC IE
+ * @netdev: network device
+ * @ft_event: IE information
+ */
+void cfg80211_ft_event(struct net_device *netdev,
+                      struct cfg80211_ft_event_params *ft_event);
+
 /**
  * cfg80211_get_p2p_attr - find and copy a P2P attribute from IE buffer
  * @ies: the input IE buffer
index f7eba13..cdd7cea 100644 (file)
@@ -1101,8 +1101,6 @@ static inline bool ieee80211_vif_is_mesh(struct ieee80211_vif *vif)
  * These flags are used for communication about keys between the driver
  * and mac80211, with the @flags parameter of &struct ieee80211_key_conf.
  *
- * @IEEE80211_KEY_FLAG_WMM_STA: Set by mac80211, this flag indicates
- *     that the STA this key will be used with could be using QoS.
  * @IEEE80211_KEY_FLAG_GENERATE_IV: This flag should be set by the
  *     driver to indicate that it requires IV generation for this
  *     particular key.
@@ -1127,7 +1125,6 @@ static inline bool ieee80211_vif_is_mesh(struct ieee80211_vif *vif)
  *     %IEEE80211_KEY_FLAG_SW_MGMT_TX flag to encrypt such frames in SW.
  */
 enum ieee80211_key_flags {
-       IEEE80211_KEY_FLAG_WMM_STA      = 1<<0,
        IEEE80211_KEY_FLAG_GENERATE_IV  = 1<<1,
        IEEE80211_KEY_FLAG_GENERATE_MMIC= 1<<2,
        IEEE80211_KEY_FLAG_PAIRWISE     = 1<<3,
@@ -1231,9 +1228,8 @@ enum ieee80211_sta_rx_bandwidth {
  * @addr: MAC address
  * @aid: AID we assigned to the station if we're an AP
  * @supp_rates: Bitmap of supported rates (per band)
- * @ht_cap: HT capabilities of this STA; restricted to our own TX capabilities
- * @vht_cap: VHT capabilities of this STA; Not restricting any capabilities
- *     of remote STA. Taking as is.
+ * @ht_cap: HT capabilities of this STA; restricted to our own capabilities
+ * @vht_cap: VHT capabilities of this STA; restricted to our own capabilities
  * @wme: indicates whether the STA supports WME. Only valid during AP-mode.
  * @drv_priv: data area for driver use, will always be aligned to
  *     sizeof(void *), size is determined in hw information.
@@ -2134,6 +2130,24 @@ enum ieee80211_rate_control_changed {
        IEEE80211_RC_NSS_CHANGED        = BIT(3),
 };
 
+/**
+ * enum ieee80211_roc_type - remain on channel type
+ *
+ * With the support for multi channel contexts and multi channel operations,
+ * remain on channel operations might be limited/deferred/aborted by other
+ * flows/operations which have higher priority (and vise versa).
+ * Specifying the ROC type can be used by devices to prioritize the ROC
+ * operations compared to other operations/flows.
+ *
+ * @IEEE80211_ROC_TYPE_NORMAL: There are no special requirements for this ROC.
+ * @IEEE80211_ROC_TYPE_MGMT_TX: The remain on channel request is required
+ *     for sending managment frames offchannel.
+ */
+enum ieee80211_roc_type {
+       IEEE80211_ROC_TYPE_NORMAL = 0,
+       IEEE80211_ROC_TYPE_MGMT_TX,
+};
+
 /**
  * struct ieee80211_ops - callbacks from mac80211 to the driver
  *
@@ -2687,7 +2701,8 @@ struct ieee80211_ops {
        int (*remain_on_channel)(struct ieee80211_hw *hw,
                                 struct ieee80211_vif *vif,
                                 struct ieee80211_channel *chan,
-                                int duration);
+                                int duration,
+                                enum ieee80211_roc_type type);
        int (*cancel_remain_on_channel)(struct ieee80211_hw *hw);
        int (*set_ringparam)(struct ieee80211_hw *hw, u32 tx, u32 rx);
        void (*get_ringparam)(struct ieee80211_hw *hw,
index 7969f46..7440bc8 100644 (file)
@@ -90,6 +90,8 @@ enum nfc_commands {
        NFC_CMD_LLC_SET_PARAMS,
        NFC_CMD_ENABLE_SE,
        NFC_CMD_DISABLE_SE,
+       NFC_CMD_LLC_SDREQ,
+       NFC_EVENT_LLC_SDRES,
 /* private: internal use only */
        __NFC_CMD_AFTER_LAST
 };
@@ -140,11 +142,21 @@ enum nfc_attrs {
        NFC_ATTR_LLC_PARAM_RW,
        NFC_ATTR_LLC_PARAM_MIUX,
        NFC_ATTR_SE,
+       NFC_ATTR_LLC_SDP,
 /* private: internal use only */
        __NFC_ATTR_AFTER_LAST
 };
 #define NFC_ATTR_MAX (__NFC_ATTR_AFTER_LAST - 1)
 
+enum nfc_sdp_attr {
+       NFC_SDP_ATTR_UNSPEC,
+       NFC_SDP_ATTR_URI,
+       NFC_SDP_ATTR_SAP,
+/* private: internal use only */
+       __NFC_SDP_ATTR_AFTER_LAST
+};
+#define NFC_SDP_ATTR_MAX (__NFC_SDP_ATTR_AFTER_LAST - 1)
+
 #define NFC_DEVICE_NAME_MAXSIZE 8
 #define NFC_NFCID1_MAXSIZE 10
 #define NFC_SENSB_RES_MAXSIZE 12
@@ -220,4 +232,8 @@ struct sockaddr_nfc_llcp {
 #define NFC_LLCP_DIRECTION_RX          0x00
 #define NFC_LLCP_DIRECTION_TX          0x01
 
+/* socket option names */
+#define NFC_LLCP_RW   0
+#define NFC_LLCP_MIUX 1
+
 #endif /*__LINUX_NFC_H */
index c46bb01..79da871 100644 (file)
  * The station is still assumed to belong to the AP interface it was added
  * to.
  *
- * TODO: need more info?
+ * Station handling varies per interface type and depending on the driver's
+ * capabilities.
+ *
+ * For drivers supporting TDLS with external setup (WIPHY_FLAG_SUPPORTS_TDLS
+ * and WIPHY_FLAG_TDLS_EXTERNAL_SETUP), the station lifetime is as follows:
+ *  - a setup station entry is added, not yet authorized, without any rate
+ *    or capability information, this just exists to avoid race conditions
+ *  - when the TDLS setup is done, a single NL80211_CMD_SET_STATION is valid
+ *    to add rate and capability information to the station and at the same
+ *    time mark it authorized.
+ *  - %NL80211_TDLS_ENABLE_LINK is then used
+ *  - after this, the only valid operation is to remove it by tearing down
+ *    the TDLS link (%NL80211_TDLS_DISABLE_LINK)
+ *
+ * TODO: need more info for other interface types
  */
 
 /**
  * @NL80211_CMD_NEW_PEER_CANDIDATE: Notification on the reception of a
  *      beacon or probe response from a compatible mesh peer.  This is only
  *      sent while no station information (sta_info) exists for the new peer
- *      candidate and when @NL80211_MESH_SETUP_USERSPACE_AUTH is set.  On
- *      reception of this notification, userspace may decide to create a new
- *      station (@NL80211_CMD_NEW_STATION).  To stop this notification from
+ *      candidate and when @NL80211_MESH_SETUP_USERSPACE_AUTH,
+ *      @NL80211_MESH_SETUP_USERSPACE_AMPE, or
+ *      @NL80211_MESH_SETUP_USERSPACE_MPM is set.  On reception of this
+ *      notification, userspace may decide to create a new station
+ *      (@NL80211_CMD_NEW_STATION).  To stop this notification from
  *      reoccurring, the userspace authentication daemon may want to create the
  *      new station with the AUTHENTICATED flag unset and maybe change it later
  *      depending on the authentication result.
  *     %NL80211_ATTR_RADAR_EVENT is used to inform about the type of the
  *     event.
  *
+ * @NL80211_CMD_GET_PROTOCOL_FEATURES: Get global nl80211 protocol features,
+ *     i.e. features for the nl80211 protocol rather than device features.
+ *     Returns the features in the %NL80211_ATTR_PROTOCOL_FEATURES bitmap.
+ *
+ * @NL80211_CMD_UPDATE_FT_IES: Pass down the most up-to-date Fast Transition
+ *     Information Element to the WLAN driver
+ *
+ * @NL80211_CMD_FT_EVENT: Send a Fast transition event from the WLAN driver
+ *     to the supplicant. This will carry the target AP's MAC address along
+ *     with the relevant Information Elements. This event is used to report
+ *     received FT IEs (MDIE, FTIE, RSN IE, TIE, RICIE).
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -765,6 +793,11 @@ enum nl80211_commands {
 
        NL80211_CMD_RADAR_DETECT,
 
+       NL80211_CMD_GET_PROTOCOL_FEATURES,
+
+       NL80211_CMD_UPDATE_FT_IES,
+       NL80211_CMD_FT_EVENT,
+
        /* add new commands above here */
 
        /* used to define NL80211_CMD_MAX below */
@@ -884,7 +917,8 @@ enum nl80211_commands {
  *     consisting of a nested array.
  *
  * @NL80211_ATTR_MESH_ID: mesh id (1-32 bytes).
- * @NL80211_ATTR_STA_PLINK_ACTION: action to perform on the mesh peer link.
+ * @NL80211_ATTR_STA_PLINK_ACTION: action to perform on the mesh peer link
+ *     (see &enum nl80211_plink_action).
  * @NL80211_ATTR_MPATH_NEXT_HOP: MAC address of the next hop for a mesh path.
  * @NL80211_ATTR_MPATH_INFO: information about a mesh_path, part of mesh path
  *     info given for %NL80211_CMD_GET_MPATH, nested attribute described at
@@ -1167,10 +1201,10 @@ enum nl80211_commands {
  * @NL80211_ATTR_SUPPORT_MESH_AUTH: Currently, this means the underlying driver
  *     allows auth frames in a mesh to be passed to userspace for processing via
  *     the @NL80211_MESH_SETUP_USERSPACE_AUTH flag.
- * @NL80211_ATTR_STA_PLINK_STATE: The state of a mesh peer link as
- *     defined in &enum nl80211_plink_state. Used when userspace is
- *     driving the peer link management state machine.
- *     @NL80211_MESH_SETUP_USERSPACE_AMPE must be enabled.
+ * @NL80211_ATTR_STA_PLINK_STATE: The state of a mesh peer link as defined in
+ *     &enum nl80211_plink_state. Used when userspace is driving the peer link
+ *     management state machine.  @NL80211_MESH_SETUP_USERSPACE_AMPE or
+ *     @NL80211_MESH_SETUP_USERSPACE_MPM must be enabled.
  *
  * @NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED: indicates, as part of the wiphy
  *     capabilities, the supported WoWLAN triggers
@@ -1368,6 +1402,18 @@ enum nl80211_commands {
  *     advertised to the driver, e.g., to enable TDLS off channel operations
  *     and PU-APSD.
  *
+ * @NL80211_ATTR_PROTOCOL_FEATURES: global nl80211 feature flags, see
+ *     &enum nl80211_protocol_features, the attribute is a u32.
+ *
+ * @NL80211_ATTR_SPLIT_WIPHY_DUMP: flag attribute, userspace supports
+ *     receiving the data for a single wiphy split across multiple
+ *     messages, given with wiphy dump message
+ *
+ * @NL80211_ATTR_MDID: Mobility Domain Identifier
+ *
+ * @NL80211_ATTR_IE_RIC: Resource Information Container Information
+ *     Element
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -1654,6 +1700,15 @@ enum nl80211_attrs {
        NL80211_ATTR_STA_CAPABILITY,
        NL80211_ATTR_STA_EXT_CAPABILITY,
 
+       NL80211_ATTR_PROTOCOL_FEATURES,
+       NL80211_ATTR_SPLIT_WIPHY_DUMP,
+
+       NL80211_ATTR_DISABLE_VHT,
+       NL80211_ATTR_VHT_CAPABILITY_MASK,
+
+       NL80211_ATTR_MDID,
+       NL80211_ATTR_IE_RIC,
+
        /* add attributes here, update the policy in nl80211.c */
 
        __NL80211_ATTR_AFTER_LAST,
@@ -2412,8 +2467,10 @@ enum nl80211_mesh_power_mode {
  * @NL80211_MESHCONF_TTL: specifies the value of TTL field set at a source mesh
  *     point.
  *
- * @NL80211_MESHCONF_AUTO_OPEN_PLINKS: whether we should automatically
- *     open peer links when we detect compatible mesh peers.
+ * @NL80211_MESHCONF_AUTO_OPEN_PLINKS: whether we should automatically open
+ *     peer links when we detect compatible mesh peers. Disabled if
+ *     @NL80211_MESH_SETUP_USERSPACE_MPM or @NL80211_MESH_SETUP_USERSPACE_AMPE are
+ *     set.
  *
  * @NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES: the number of action frames
  *     containing a PREQ that an MP can send to a particular destination (path
@@ -2559,6 +2616,9 @@ enum nl80211_meshconf_params {
  *     vendor specific synchronization method or disable it to use the default
  *     neighbor offset synchronization
  *
+ * @NL80211_MESH_SETUP_USERSPACE_MPM: Enable this option if userspace will
+ *     implement an MPM which handles peer allocation and state.
+ *
  * @NL80211_MESH_SETUP_ATTR_MAX: highest possible mesh setup attribute number
  *
  * @__NL80211_MESH_SETUP_ATTR_AFTER_LAST: Internal use
@@ -2571,6 +2631,7 @@ enum nl80211_mesh_setup_params {
        NL80211_MESH_SETUP_USERSPACE_AUTH,
        NL80211_MESH_SETUP_USERSPACE_AMPE,
        NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC,
+       NL80211_MESH_SETUP_USERSPACE_MPM,
 
        /* keep last */
        __NL80211_MESH_SETUP_ATTR_AFTER_LAST,
@@ -3307,6 +3368,23 @@ enum nl80211_plink_state {
        MAX_NL80211_PLINK_STATES = NUM_NL80211_PLINK_STATES - 1
 };
 
+/**
+ * enum nl80211_plink_action - actions to perform in mesh peers
+ *
+ * @NL80211_PLINK_ACTION_NO_ACTION: perform no action
+ * @NL80211_PLINK_ACTION_OPEN: start mesh peer link establishment
+ * @NL80211_PLINK_ACTION_BLOCK: block traffic from this mesh peer
+ * @NUM_NL80211_PLINK_ACTIONS: number of possible actions
+ */
+enum plink_actions {
+       NL80211_PLINK_ACTION_NO_ACTION,
+       NL80211_PLINK_ACTION_OPEN,
+       NL80211_PLINK_ACTION_BLOCK,
+
+       NUM_NL80211_PLINK_ACTIONS,
+};
+
+
 #define NL80211_KCK_LEN                        16
 #define NL80211_KEK_LEN                        16
 #define NL80211_REPLAY_CTR_LEN         8
@@ -3456,6 +3534,10 @@ enum nl80211_ap_sme_features {
  *     stations the authenticated/associated bits have to be set in the mask.
  * @NL80211_FEATURE_ADVERTISE_CHAN_LIMITS: cfg80211 advertises channel limits
  *     (HT40, VHT 80/160 MHz) if this flag is set
+ * @NL80211_FEATURE_USERSPACE_MPM: This driver supports a userspace Mesh
+ *     Peering Management entity which may be implemented by registering for
+ *     beacons or NL80211_CMD_NEW_PEER_CANDIDATE events. The mesh beacon is
+ *     still generated by the driver.
  */
 enum nl80211_feature_flags {
        NL80211_FEATURE_SK_TX_STATUS                    = 1 << 0,
@@ -3474,6 +3556,7 @@ enum nl80211_feature_flags {
        /* bit 13 is reserved */
        NL80211_FEATURE_ADVERTISE_CHAN_LIMITS           = 1 << 14,
        NL80211_FEATURE_FULL_AP_CLIENT_STATE            = 1 << 15,
+       NL80211_FEATURE_USERSPACE_MPM                   = 1 << 16,
 };
 
 /**
@@ -3587,4 +3670,16 @@ enum nl80211_dfs_state {
        NL80211_DFS_AVAILABLE,
 };
 
+/**
+ * enum enum nl80211_protocol_features - nl80211 protocol features
+ * @NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP: nl80211 supports splitting
+ *     wiphy dumps (if requested by the application with the attribute
+ *     %NL80211_ATTR_SPLIT_WIPHY_DUMP. Also supported is filtering the
+ *     wiphy dump by %NL80211_ATTR_WIPHY, %NL80211_ATTR_IFINDEX or
+ *     %NL80211_ATTR_WDEV.
+ */
+enum nl80211_protocol_features {
+       NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP =     1 << 0,
+};
+
 #endif /* __LINUX_NL80211_H */
index fb30681..1d1ddab 100644 (file)
@@ -254,7 +254,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
                goto out_unlock;
        }
 
-       __ieee80211_key_free(key);
+       __ieee80211_key_free(key, true);
 
        ret = 0;
  out_unlock:
@@ -1035,9 +1035,12 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
                sta_info_flush_defer(vlan);
        sta_info_flush_defer(sdata);
        rcu_barrier();
-       list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
+       list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) {
                sta_info_flush_cleanup(vlan);
+               ieee80211_free_keys(vlan);
+       }
        sta_info_flush_cleanup(sdata);
+       ieee80211_free_keys(sdata);
 
        sdata->vif.bss_conf.enable_beacon = false;
        clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state);
@@ -1177,6 +1180,18 @@ static int sta_apply_parameters(struct ieee80211_local *local,
                        mask |= BIT(NL80211_STA_FLAG_ASSOCIATED);
                if (set & BIT(NL80211_STA_FLAG_AUTHENTICATED))
                        set |= BIT(NL80211_STA_FLAG_ASSOCIATED);
+       } else if (test_sta_flag(sta, WLAN_STA_TDLS_PEER)) {
+               /*
+                * TDLS -- everything follows authorized, but
+                * only becoming authorized is possible, not
+                * going back
+                */
+               if (set & BIT(NL80211_STA_FLAG_AUTHORIZED)) {
+                       set |= BIT(NL80211_STA_FLAG_AUTHENTICATED) |
+                              BIT(NL80211_STA_FLAG_ASSOCIATED);
+                       mask |= BIT(NL80211_STA_FLAG_AUTHENTICATED) |
+                               BIT(NL80211_STA_FLAG_ASSOCIATED);
+               }
        }
 
        ret = sta_apply_auth_flags(local, sta, mask, set);
@@ -1261,7 +1276,8 @@ static int sta_apply_parameters(struct ieee80211_local *local,
        if (ieee80211_vif_is_mesh(&sdata->vif)) {
 #ifdef CONFIG_MAC80211_MESH
                u32 changed = 0;
-               if (sdata->u.mesh.security & IEEE80211_MESH_SEC_SECURED) {
+
+               if (params->sta_modify_mask & STATION_PARAM_APPLY_PLINK_STATE) {
                        switch (params->plink_state) {
                        case NL80211_PLINK_ESTAB:
                                if (sta->plink_state != NL80211_PLINK_ESTAB)
@@ -1292,15 +1308,18 @@ static int sta_apply_parameters(struct ieee80211_local *local,
                                /*  nothing  */
                                break;
                        }
-               } else {
-                       switch (params->plink_action) {
-                       case PLINK_ACTION_OPEN:
-                               changed |= mesh_plink_open(sta);
-                               break;
-                       case PLINK_ACTION_BLOCK:
-                               changed |= mesh_plink_block(sta);
-                               break;
-                       }
+               }
+
+               switch (params->plink_action) {
+               case NL80211_PLINK_ACTION_NO_ACTION:
+                       /* nothing */
+                       break;
+               case NL80211_PLINK_ACTION_OPEN:
+                       changed |= mesh_plink_open(sta);
+                       break;
+               case NL80211_PLINK_ACTION_BLOCK:
+                       changed |= mesh_plink_block(sta);
+                       break;
                }
 
                if (params->local_pm)
@@ -1346,8 +1365,10 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
         * defaults -- if userspace wants something else we'll
         * change it accordingly in sta_apply_parameters()
         */
-       sta_info_pre_move_state(sta, IEEE80211_STA_AUTH);
-       sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC);
+       if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))) {
+               sta_info_pre_move_state(sta, IEEE80211_STA_AUTH);
+               sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC);
+       }
 
        err = sta_apply_parameters(local, sta, params);
        if (err) {
@@ -1356,8 +1377,8 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
        }
 
        /*
-        * for TDLS, rate control should be initialized only when supported
-        * rates are known.
+        * for TDLS, rate control should be initialized only when
+        * rates are known and station is marked authorized
         */
        if (!test_sta_flag(sta, WLAN_STA_TDLS_PEER))
                rate_control_rate_init(sta);
@@ -1394,50 +1415,67 @@ static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev,
 }
 
 static int ieee80211_change_station(struct wiphy *wiphy,
-                                   struct net_device *dev,
-                                   u8 *mac,
+                                   struct net_device *dev, u8 *mac,
                                    struct station_parameters *params)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_local *local = wiphy_priv(wiphy);
        struct sta_info *sta;
        struct ieee80211_sub_if_data *vlansdata;
+       enum cfg80211_station_type statype;
        int err;
 
        mutex_lock(&local->sta_mtx);
 
        sta = sta_info_get_bss(sdata, mac);
        if (!sta) {
-               mutex_unlock(&local->sta_mtx);
-               return -ENOENT;
+               err = -ENOENT;
+               goto out_err;
        }
 
-       /* in station mode, some updates are only valid with TDLS */
-       if (sdata->vif.type == NL80211_IFTYPE_STATION &&
-           (params->supported_rates || params->ht_capa || params->vht_capa ||
-            params->sta_modify_mask ||
-            (params->sta_flags_mask & BIT(NL80211_STA_FLAG_WME))) &&
-           !test_sta_flag(sta, WLAN_STA_TDLS_PEER)) {
-               mutex_unlock(&local->sta_mtx);
-               return -EINVAL;
+       switch (sdata->vif.type) {
+       case NL80211_IFTYPE_MESH_POINT:
+               if (sdata->u.mesh.user_mpm)
+                       statype = CFG80211_STA_MESH_PEER_USER;
+               else
+                       statype = CFG80211_STA_MESH_PEER_KERNEL;
+               break;
+       case NL80211_IFTYPE_ADHOC:
+               statype = CFG80211_STA_IBSS;
+               break;
+       case NL80211_IFTYPE_STATION:
+               if (!test_sta_flag(sta, WLAN_STA_TDLS_PEER)) {
+                       statype = CFG80211_STA_AP_STA;
+                       break;
+               }
+               if (test_sta_flag(sta, WLAN_STA_AUTHORIZED))
+                       statype = CFG80211_STA_TDLS_PEER_ACTIVE;
+               else
+                       statype = CFG80211_STA_TDLS_PEER_SETUP;
+               break;
+       case NL80211_IFTYPE_AP:
+       case NL80211_IFTYPE_AP_VLAN:
+               statype = CFG80211_STA_AP_CLIENT;
+               break;
+       default:
+               err = -EOPNOTSUPP;
+               goto out_err;
        }
 
+       err = cfg80211_check_station_change(wiphy, params, statype);
+       if (err)
+               goto out_err;
+
        if (params->vlan && params->vlan != sta->sdata->dev) {
                bool prev_4addr = false;
                bool new_4addr = false;
 
                vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
 
-               if (vlansdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
-                   vlansdata->vif.type != NL80211_IFTYPE_AP) {
-                       mutex_unlock(&local->sta_mtx);
-                       return -EINVAL;
-               }
-
                if (params->vlan->ieee80211_ptr->use_4addr) {
                        if (vlansdata->u.vlan.sta) {
-                               mutex_unlock(&local->sta_mtx);
-                               return -EBUSY;
+                               err = -EBUSY;
+                               goto out_err;
                        }
 
                        rcu_assign_pointer(vlansdata->u.vlan.sta, sta);
@@ -1464,12 +1502,12 @@ static int ieee80211_change_station(struct wiphy *wiphy,
        }
 
        err = sta_apply_parameters(local, sta, params);
-       if (err) {
-               mutex_unlock(&local->sta_mtx);
-               return err;
-       }
+       if (err)
+               goto out_err;
 
-       if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) && params->supported_rates)
+       /* When peer becomes authorized, init rate control as well */
+       if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) &&
+           test_sta_flag(sta, WLAN_STA_AUTHORIZED))
                rate_control_rate_init(sta);
 
        mutex_unlock(&local->sta_mtx);
@@ -1479,7 +1517,11 @@ static int ieee80211_change_station(struct wiphy *wiphy,
                ieee80211_recalc_ps(local, -1);
                ieee80211_recalc_ps_vif(sdata);
        }
+
        return 0;
+out_err:
+       mutex_unlock(&local->sta_mtx);
+       return err;
 }
 
 #ifdef CONFIG_MAC80211_MESH
@@ -1687,6 +1729,7 @@ static int copy_mesh_setup(struct ieee80211_if_mesh *ifmsh,
        ifmsh->mesh_sp_id = setup->sync_method;
        ifmsh->mesh_pp_id = setup->path_sel_proto;
        ifmsh->mesh_pm_id = setup->path_metric;
+       ifmsh->user_mpm = setup->user_mpm;
        ifmsh->security = IEEE80211_MESH_SEC_NONE;
        if (setup->is_authenticated)
                ifmsh->security |= IEEE80211_MESH_SEC_AUTHED;
@@ -1730,8 +1773,11 @@ static int ieee80211_update_mesh_config(struct wiphy *wiphy,
                conf->dot11MeshTTL = nconf->dot11MeshTTL;
        if (_chg_mesh_attr(NL80211_MESHCONF_ELEMENT_TTL, mask))
                conf->element_ttl = nconf->element_ttl;
-       if (_chg_mesh_attr(NL80211_MESHCONF_AUTO_OPEN_PLINKS, mask))
+       if (_chg_mesh_attr(NL80211_MESHCONF_AUTO_OPEN_PLINKS, mask)) {
+               if (ifmsh->user_mpm)
+                       return -EBUSY;
                conf->auto_open_plinks = nconf->auto_open_plinks;
+       }
        if (_chg_mesh_attr(NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR, mask))
                conf->dot11MeshNbrOffsetMaxNeighbor =
                        nconf->dot11MeshNbrOffsetMaxNeighbor;
@@ -2371,7 +2417,8 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
                                    struct ieee80211_sub_if_data *sdata,
                                    struct ieee80211_channel *channel,
                                    unsigned int duration, u64 *cookie,
-                                   struct sk_buff *txskb)
+                                   struct sk_buff *txskb,
+                                   enum ieee80211_roc_type type)
 {
        struct ieee80211_roc_work *roc, *tmp;
        bool queued = false;
@@ -2390,6 +2437,7 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
        roc->duration = duration;
        roc->req_duration = duration;
        roc->frame = txskb;
+       roc->type = type;
        roc->mgmt_tx_cookie = (unsigned long)txskb;
        roc->sdata = sdata;
        INIT_DELAYED_WORK(&roc->work, ieee80211_sw_roc_work);
@@ -2420,7 +2468,7 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
        if (!duration)
                duration = 10;
 
-       ret = drv_remain_on_channel(local, sdata, channel, duration);
+       ret = drv_remain_on_channel(local, sdata, channel, duration, type);
        if (ret) {
                kfree(roc);
                return ret;
@@ -2439,10 +2487,13 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
                 *
                 * If it hasn't started yet, just increase the duration
                 * and add the new one to the list of dependents.
+                * If the type of the new ROC has higher priority, modify the
+                * type of the previous one to match that of the new one.
                 */
                if (!tmp->started) {
                        list_add_tail(&roc->list, &tmp->dependents);
                        tmp->duration = max(tmp->duration, roc->duration);
+                       tmp->type = max(tmp->type, roc->type);
                        queued = true;
                        break;
                }
@@ -2454,16 +2505,18 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
                        /*
                         * In the offloaded ROC case, if it hasn't begun, add
                         * this new one to the dependent list to be handled
-                        * when the the master one begins. If it has begun,
+                        * when the master one begins. If it has begun,
                         * check that there's still a minimum time left and
                         * if so, start this one, transmitting the frame, but
-                        * add it to the list directly after this one with a
+                        * add it to the list directly after this one with
                         * a reduced time so we'll ask the driver to execute
                         * it right after finishing the previous one, in the
                         * hope that it'll also be executed right afterwards,
                         * effectively extending the old one.
                         * If there's no minimum time left, just add it to the
                         * normal list.
+                        * TODO: the ROC type is ignored here, assuming that it
+                        * is better to immediately use the current ROC.
                         */
                        if (!tmp->hw_begun) {
                                list_add_tail(&roc->list, &tmp->dependents);
@@ -2557,7 +2610,8 @@ static int ieee80211_remain_on_channel(struct wiphy *wiphy,
 
        mutex_lock(&local->mtx);
        ret = ieee80211_start_roc_work(local, sdata, chan,
-                                      duration, cookie, NULL);
+                                      duration, cookie, NULL,
+                                      IEEE80211_ROC_TYPE_NORMAL);
        mutex_unlock(&local->mtx);
 
        return ret;
@@ -2790,7 +2844,8 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
 
        /* This will handle all kinds of coalescing and immediate TX */
        ret = ieee80211_start_roc_work(local, sdata, chan,
-                                      wait, cookie, skb);
+                                      wait, cookie, skb,
+                                      IEEE80211_ROC_TYPE_MGMT_TX);
        if (ret)
                kfree_skb(skb);
  out_unlock:
index c7591f7..4f841fe 100644 (file)
@@ -325,6 +325,36 @@ static ssize_t sta_ht_capa_read(struct file *file, char __user *userbuf,
 }
 STA_OPS(ht_capa);
 
+static ssize_t sta_vht_capa_read(struct file *file, char __user *userbuf,
+                                size_t count, loff_t *ppos)
+{
+       char buf[128], *p = buf;
+       struct sta_info *sta = file->private_data;
+       struct ieee80211_sta_vht_cap *vhtc = &sta->sta.vht_cap;
+
+       p += scnprintf(p, sizeof(buf) + buf - p, "VHT %ssupported\n",
+                       vhtc->vht_supported ? "" : "not ");
+       if (vhtc->vht_supported) {
+               p += scnprintf(p, sizeof(buf)+buf-p, "cap: %#.8x\n", vhtc->cap);
+
+               p += scnprintf(p, sizeof(buf)+buf-p, "RX MCS: %.4x\n",
+                              le16_to_cpu(vhtc->vht_mcs.rx_mcs_map));
+               if (vhtc->vht_mcs.rx_highest)
+                       p += scnprintf(p, sizeof(buf)+buf-p,
+                                      "MCS RX highest: %d Mbps\n",
+                                      le16_to_cpu(vhtc->vht_mcs.rx_highest));
+               p += scnprintf(p, sizeof(buf)+buf-p, "TX MCS: %.4x\n",
+                              le16_to_cpu(vhtc->vht_mcs.tx_mcs_map));
+               if (vhtc->vht_mcs.tx_highest)
+                       p += scnprintf(p, sizeof(buf)+buf-p,
+                                      "MCS TX highest: %d Mbps\n",
+                                      le16_to_cpu(vhtc->vht_mcs.tx_highest));
+       }
+
+       return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
+}
+STA_OPS(vht_capa);
+
 static ssize_t sta_current_tx_rate_read(struct file *file, char __user *userbuf,
                                        size_t count, loff_t *ppos)
 {
@@ -405,6 +435,7 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta)
        DEBUGFS_ADD(dev);
        DEBUGFS_ADD(last_signal);
        DEBUGFS_ADD(ht_capa);
+       DEBUGFS_ADD(vht_capa);
        DEBUGFS_ADD(last_ack_signal);
        DEBUGFS_ADD(current_tx_rate);
        DEBUGFS_ADD(last_rx_rate);
index ee56d07..832acea 100644 (file)
@@ -787,15 +787,16 @@ 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,
-                                       unsigned int duration)
+                                       unsigned int duration,
+                                       enum ieee80211_roc_type type)
 {
        int ret;
 
        might_sleep();
 
-       trace_drv_remain_on_channel(local, sdata, chan, duration);
+       trace_drv_remain_on_channel(local, sdata, chan, duration, type);
        ret = local->ops->remain_on_channel(&local->hw, &sdata->vif,
-                                           chan, duration);
+                                           chan, duration, type);
        trace_drv_return_int(local, ret);
 
        return ret;
index 0db25d4..af8cee0 100644 (file)
@@ -40,13 +40,6 @@ void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,
        if (!ht_cap->ht_supported)
                return;
 
-       if (sdata->vif.type != NL80211_IFTYPE_STATION) {
-               /* AP interfaces call this code when adding new stations,
-                * so just silently ignore non station interfaces.
-                */
-               return;
-       }
-
        /* NOTE:  If you add more over-rides here, update register_hw
         * ht_capa_mod_msk logic in main.c as well.
         * And, if this method can ever change ht_cap.ht_supported, fix
@@ -97,7 +90,7 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
                                       const struct ieee80211_ht_cap *ht_cap_ie,
                                       struct sta_info *sta)
 {
-       struct ieee80211_sta_ht_cap ht_cap;
+       struct ieee80211_sta_ht_cap ht_cap, own_cap;
        u8 ampdu_info, tx_mcs_set_cap;
        int i, max_tx_streams;
        bool changed;
@@ -111,6 +104,18 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
 
        ht_cap.ht_supported = true;
 
+       own_cap = sband->ht_cap;
+
+       /*
+        * If user has specified capability over-rides, take care
+        * of that if the station we're setting up is the AP that
+        * we advertised a restricted capability set to. Override
+        * our own capabilities and then use those below.
+        */
+       if (sdata->vif.type == NL80211_IFTYPE_STATION &&
+           !test_sta_flag(sta, WLAN_STA_TDLS_PEER))
+               ieee80211_apply_htcap_overrides(sdata, &own_cap);
+
        /*
         * The bits listed in this expression should be
         * the same for the peer and us, if the station
@@ -118,21 +123,20 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
         * we mask them out.
         */
        ht_cap.cap = le16_to_cpu(ht_cap_ie->cap_info) &
-               (sband->ht_cap.cap |
-                ~(IEEE80211_HT_CAP_LDPC_CODING |
-                  IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
-                  IEEE80211_HT_CAP_GRN_FLD |
-                  IEEE80211_HT_CAP_SGI_20 |
-                  IEEE80211_HT_CAP_SGI_40 |
-                  IEEE80211_HT_CAP_DSSSCCK40));
+               (own_cap.cap | ~(IEEE80211_HT_CAP_LDPC_CODING |
+                                IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
+                                IEEE80211_HT_CAP_GRN_FLD |
+                                IEEE80211_HT_CAP_SGI_20 |
+                                IEEE80211_HT_CAP_SGI_40 |
+                                IEEE80211_HT_CAP_DSSSCCK40));
 
        /*
         * The STBC bits are asymmetric -- if we don't have
         * TX then mask out the peer's RX and vice versa.
         */
-       if (!(sband->ht_cap.cap & IEEE80211_HT_CAP_TX_STBC))
+       if (!(own_cap.cap & IEEE80211_HT_CAP_TX_STBC))
                ht_cap.cap &= ~IEEE80211_HT_CAP_RX_STBC;
-       if (!(sband->ht_cap.cap & IEEE80211_HT_CAP_RX_STBC))
+       if (!(own_cap.cap & IEEE80211_HT_CAP_RX_STBC))
                ht_cap.cap &= ~IEEE80211_HT_CAP_TX_STBC;
 
        ampdu_info = ht_cap_ie->ampdu_params_info;
@@ -142,7 +146,7 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
                (ampdu_info & IEEE80211_HT_AMPDU_PARM_DENSITY) >> 2;
 
        /* own MCS TX capabilities */
-       tx_mcs_set_cap = sband->ht_cap.mcs.tx_params;
+       tx_mcs_set_cap = own_cap.mcs.tx_params;
 
        /* Copy peer MCS TX capabilities, the driver might need them. */
        ht_cap.mcs.tx_params = ht_cap_ie->mcs.tx_params;
@@ -168,26 +172,20 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
         */
        for (i = 0; i < max_tx_streams; i++)
                ht_cap.mcs.rx_mask[i] =
-                       sband->ht_cap.mcs.rx_mask[i] & ht_cap_ie->mcs.rx_mask[i];
+                       own_cap.mcs.rx_mask[i] & ht_cap_ie->mcs.rx_mask[i];
 
        if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_UNEQUAL_MODULATION)
                for (i = IEEE80211_HT_MCS_UNEQUAL_MODULATION_START_BYTE;
                     i < IEEE80211_HT_MCS_MASK_LEN; i++)
                        ht_cap.mcs.rx_mask[i] =
-                               sband->ht_cap.mcs.rx_mask[i] &
+                               own_cap.mcs.rx_mask[i] &
                                        ht_cap_ie->mcs.rx_mask[i];
 
        /* handle MCS rate 32 too */
-       if (sband->ht_cap.mcs.rx_mask[32/8] & ht_cap_ie->mcs.rx_mask[32/8] & 1)
+       if (own_cap.mcs.rx_mask[32/8] & ht_cap_ie->mcs.rx_mask[32/8] & 1)
                ht_cap.mcs.rx_mask[32/8] |= 1;
 
  apply:
-       /*
-        * If user has specified capability over-rides, take care
-        * of that here.
-        */
-       ieee80211_apply_htcap_overrides(sdata, &ht_cap);
-
        changed = memcmp(&sta->sta.ht_cap, &ht_cap, sizeof(ht_cap));
 
        memcpy(&sta->sta.ht_cap, &ht_cap, sizeof(ht_cap));
index 40b71df..539d4a1 100644 (file)
@@ -985,36 +985,9 @@ static void ieee80211_ibss_timer(unsigned long data)
 {
        struct ieee80211_sub_if_data *sdata =
                (struct ieee80211_sub_if_data *) data;
-       struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
-       struct ieee80211_local *local = sdata->local;
-
-       if (local->quiescing) {
-               ifibss->timer_running = true;
-               return;
-       }
-
-       ieee80211_queue_work(&local->hw, &sdata->work);
-}
-
-#ifdef CONFIG_PM
-void ieee80211_ibss_quiesce(struct ieee80211_sub_if_data *sdata)
-{
-       struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
 
-       if (del_timer_sync(&ifibss->timer))
-               ifibss->timer_running = true;
-}
-
-void ieee80211_ibss_restart(struct ieee80211_sub_if_data *sdata)
-{
-       struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
-
-       if (ifibss->timer_running) {
-               add_timer(&ifibss->timer);
-               ifibss->timer_running = false;
-       }
+       ieee80211_queue_work(&sdata->local->hw, &sdata->work);
 }
-#endif
 
 void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata)
 {
index 388580a..f4433f0 100644 (file)
@@ -315,6 +315,7 @@ struct ieee80211_roc_work {
        u32 duration, req_duration;
        struct sk_buff *frame;
        u64 cookie, mgmt_tx_cookie;
+       enum ieee80211_roc_type type;
 };
 
 /* flags used in struct ieee80211_if_managed.flags */
@@ -400,7 +401,6 @@ struct ieee80211_if_managed {
 
        u16 aid;
 
-       unsigned long timers_running; /* used for quiesce/restart */
        bool powersave; /* powersave requested for this iface */
        bool broken_ap; /* AP is broken -- turn off powersave */
        u8 dtim_period;
@@ -479,6 +479,8 @@ struct ieee80211_if_managed {
 
        struct ieee80211_ht_cap ht_capa; /* configured ht-cap over-rides */
        struct ieee80211_ht_cap ht_capa_mask; /* Valid parts of ht_capa */
+       struct ieee80211_vht_cap vht_capa; /* configured VHT overrides */
+       struct ieee80211_vht_cap vht_capa_mask; /* Valid parts of vht_capa */
 };
 
 struct ieee80211_if_ibss {
@@ -490,8 +492,6 @@ struct ieee80211_if_ibss {
 
        u32 basic_rates;
 
-       bool timer_running;
-
        bool fixed_bssid;
        bool fixed_channel;
        bool privacy;
@@ -543,8 +543,6 @@ struct ieee80211_if_mesh {
        struct timer_list mesh_path_timer;
        struct timer_list mesh_path_root_timer;
 
-       unsigned long timers_running;
-
        unsigned long wrkq_flags;
 
        u8 mesh_id[IEEE80211_MAX_MESH_ID_LEN];
@@ -590,6 +588,7 @@ struct ieee80211_if_mesh {
                IEEE80211_MESH_SEC_AUTHED = 0x1,
                IEEE80211_MESH_SEC_SECURED = 0x2,
        } security;
+       bool user_mpm;
        /* Extensible Synchronization Framework */
        const struct ieee80211_mesh_sync_ops *sync_ops;
        s64 sync_offset_clockdrift_max;
@@ -682,6 +681,8 @@ struct ieee80211_sub_if_data {
 
        /* count for keys needing tailroom space allocation */
        int crypto_tx_tailroom_needed_cnt;
+       int crypto_tx_tailroom_pending_dec;
+       struct delayed_work dec_tailroom_needed_wk;
 
        struct net_device *dev;
        struct ieee80211_local *local;
@@ -765,10 +766,6 @@ struct ieee80211_sub_if_data {
        } debugfs;
 #endif
 
-#ifdef CONFIG_PM
-       struct ieee80211_bss_conf suspend_bss_conf;
-#endif
-
        /* must be last, dynamically sized area in this! */
        struct ieee80211_vif vif;
 };
@@ -1136,11 +1133,6 @@ struct ieee80211_local {
 
        struct ieee80211_sub_if_data __rcu *p2p_sdata;
 
-       /* dummy netdev for use w/ NAPI */
-       struct net_device napi_dev;
-
-       struct napi_struct napi;
-
        /* virtual monitor interface */
        struct ieee80211_sub_if_data __rcu *monitor_sdata;
        struct cfg80211_chan_def monitor_chandef;
@@ -1283,8 +1275,6 @@ void
 ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
                                 const struct ieee80211_channel_sw_ie *sw_elem,
                                 struct ieee80211_bss *bss, u64 timestamp);
-void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata);
-void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata);
 void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata);
 void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
                                  struct sk_buff *skb);
@@ -1302,8 +1292,6 @@ void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata,
 int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
                        struct cfg80211_ibss_params *params);
 int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata);
-void ieee80211_ibss_quiesce(struct ieee80211_sub_if_data *sdata);
-void ieee80211_ibss_restart(struct ieee80211_sub_if_data *sdata);
 void ieee80211_ibss_work(struct ieee80211_sub_if_data *sdata);
 void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
                                   struct sk_buff *skb);
@@ -1441,6 +1429,8 @@ void ieee80211_sta_set_rx_nss(struct sta_info *sta);
 void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
                                 struct sta_info *sta, u8 opmode,
                                 enum ieee80211_band band, bool nss_only);
+void ieee80211_apply_vhtcap_overrides(struct ieee80211_sub_if_data *sdata,
+                                     struct ieee80211_sta_vht_cap *vht_cap);
 
 /* Spectrum management */
 void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
index baaa860..d85282f 100644 (file)
@@ -485,8 +485,6 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
                res = drv_start(local);
                if (res)
                        goto err_del_bss;
-               if (local->ops->napi_poll)
-                       napi_enable(&local->napi);
                /* we're brought up, everything changes */
                hw_reconf_flags = ~0;
                ieee80211_led_radio(local, true);
@@ -838,14 +836,16 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
                rcu_barrier();
                sta_info_flush_cleanup(sdata);
 
-               skb_queue_purge(&sdata->skb_queue);
-
                /*
                 * Free all remaining keys, there shouldn't be any,
-                * except maybe group keys in AP more or WDS?
+                * except maybe in WDS mode?
                 */
                ieee80211_free_keys(sdata);
 
+               /* fall through */
+       case NL80211_IFTYPE_AP:
+               skb_queue_purge(&sdata->skb_queue);
+
                drv_remove_interface_debugfs(local, sdata);
 
                if (going_down)
@@ -857,8 +857,6 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
        ieee80211_recalc_ps(local, -1);
 
        if (local->open_count == 0) {
-               if (local->ops->napi_poll)
-                       napi_disable(&local->napi);
                ieee80211_clear_tx_pending(local);
                ieee80211_stop_device(local);
 
@@ -1547,6 +1545,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
        INIT_WORK(&sdata->cleanup_stations_wk, ieee80211_cleanup_sdata_stas_wk);
        INIT_DELAYED_WORK(&sdata->dfs_cac_timer_work,
                          ieee80211_dfs_cac_timer_work);
+       INIT_DELAYED_WORK(&sdata->dec_tailroom_needed_wk,
+                         ieee80211_delayed_tailroom_dec);
 
        for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
                struct ieee80211_supported_band *sband;
index ef252eb..99e9f6a 100644 (file)
@@ -397,7 +397,8 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
        return key;
 }
 
-static void __ieee80211_key_destroy(struct ieee80211_key *key)
+static void __ieee80211_key_destroy(struct ieee80211_key *key,
+                                   bool delay_tailroom)
 {
        if (!key)
                return;
@@ -416,8 +417,18 @@ static void __ieee80211_key_destroy(struct ieee80211_key *key)
        if (key->conf.cipher == WLAN_CIPHER_SUITE_AES_CMAC)
                ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm);
        if (key->local) {
+               struct ieee80211_sub_if_data *sdata = key->sdata;
+
                ieee80211_debugfs_key_remove(key);
-               key->sdata->crypto_tx_tailroom_needed_cnt--;
+
+               if (delay_tailroom) {
+                       /* see ieee80211_delayed_tailroom_dec */
+                       sdata->crypto_tx_tailroom_pending_dec++;
+                       schedule_delayed_work(&sdata->dec_tailroom_needed_wk,
+                                             HZ/2);
+               } else {
+                       sdata->crypto_tx_tailroom_needed_cnt--;
+               }
        }
 
        kfree(key);
@@ -440,32 +451,6 @@ int ieee80211_key_link(struct ieee80211_key *key,
        key->sdata = sdata;
        key->sta = sta;
 
-       if (sta) {
-               /*
-                * some hardware cannot handle TKIP with QoS, so
-                * we indicate whether QoS could be in use.
-                */
-               if (test_sta_flag(sta, WLAN_STA_WME))
-                       key->conf.flags |= IEEE80211_KEY_FLAG_WMM_STA;
-       } else {
-               if (sdata->vif.type == NL80211_IFTYPE_STATION) {
-                       struct sta_info *ap;
-
-                       /*
-                        * We're getting a sta pointer in, so must be under
-                        * appropriate locking for sta_info_get().
-                        */
-
-                       /* same here, the AP could be using QoS */
-                       ap = sta_info_get(key->sdata, key->sdata->u.mgd.bssid);
-                       if (ap) {
-                               if (test_sta_flag(ap, WLAN_STA_WME))
-                                       key->conf.flags |=
-                                               IEEE80211_KEY_FLAG_WMM_STA;
-                       }
-               }
-       }
-
        mutex_lock(&sdata->local->key_mtx);
 
        if (sta && pairwise)
@@ -478,7 +463,7 @@ int ieee80211_key_link(struct ieee80211_key *key,
        increment_tailroom_need_count(sdata);
 
        __ieee80211_key_replace(sdata, sta, pairwise, old_key, key);
-       __ieee80211_key_destroy(old_key);
+       __ieee80211_key_destroy(old_key, true);
 
        ieee80211_debugfs_key_add(key);
 
@@ -489,7 +474,7 @@ int ieee80211_key_link(struct ieee80211_key *key,
        return ret;
 }
 
-void __ieee80211_key_free(struct ieee80211_key *key)
+void __ieee80211_key_free(struct ieee80211_key *key, bool delay_tailroom)
 {
        if (!key)
                return;
@@ -501,14 +486,14 @@ void __ieee80211_key_free(struct ieee80211_key *key)
                __ieee80211_key_replace(key->sdata, key->sta,
                                key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE,
                                key, NULL);
-       __ieee80211_key_destroy(key);
+       __ieee80211_key_destroy(key, delay_tailroom);
 }
 
 void ieee80211_key_free(struct ieee80211_local *local,
                        struct ieee80211_key *key)
 {
        mutex_lock(&local->key_mtx);
-       __ieee80211_key_free(key);
+       __ieee80211_key_free(key, true);
        mutex_unlock(&local->key_mtx);
 }
 
@@ -566,36 +551,60 @@ void ieee80211_iter_keys(struct ieee80211_hw *hw,
 }
 EXPORT_SYMBOL(ieee80211_iter_keys);
 
-void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata)
-{
-       struct ieee80211_key *key;
-
-       ASSERT_RTNL();
-
-       mutex_lock(&sdata->local->key_mtx);
-
-       list_for_each_entry(key, &sdata->key_list, list)
-               ieee80211_key_disable_hw_accel(key);
-
-       mutex_unlock(&sdata->local->key_mtx);
-}
-
 void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_key *key, *tmp;
 
+       cancel_delayed_work_sync(&sdata->dec_tailroom_needed_wk);
+
        mutex_lock(&sdata->local->key_mtx);
 
+       sdata->crypto_tx_tailroom_needed_cnt -=
+               sdata->crypto_tx_tailroom_pending_dec;
+       sdata->crypto_tx_tailroom_pending_dec = 0;
+
        ieee80211_debugfs_key_remove_mgmt_default(sdata);
 
        list_for_each_entry_safe(key, tmp, &sdata->key_list, list)
-               __ieee80211_key_free(key);
+               __ieee80211_key_free(key, false);
 
        ieee80211_debugfs_key_update_default(sdata);
 
+       WARN_ON_ONCE(sdata->crypto_tx_tailroom_needed_cnt ||
+                    sdata->crypto_tx_tailroom_pending_dec);
+
        mutex_unlock(&sdata->local->key_mtx);
 }
 
+void ieee80211_delayed_tailroom_dec(struct work_struct *wk)
+{
+       struct ieee80211_sub_if_data *sdata;
+
+       sdata = container_of(wk, struct ieee80211_sub_if_data,
+                            dec_tailroom_needed_wk.work);
+
+       /*
+        * The reason for the delayed tailroom needed decrementing is to
+        * make roaming faster: during roaming, all keys are first deleted
+        * and then new keys are installed. The first new key causes the
+        * crypto_tx_tailroom_needed_cnt to go from 0 to 1, which invokes
+        * the cost of synchronize_net() (which can be slow). Avoid this
+        * by deferring the crypto_tx_tailroom_needed_cnt decrementing on
+        * key removal for a while, so if we roam the value is larger than
+        * zero and no 0->1 transition happens.
+        *
+        * The cost is that if the AP switching was from an AP with keys
+        * to one without, we still allocate tailroom while it would no
+        * longer be needed. However, in the typical (fast) roaming case
+        * within an ESS this usually won't happen.
+        */
+
+       mutex_lock(&sdata->local->key_mtx);
+       sdata->crypto_tx_tailroom_needed_cnt -=
+               sdata->crypto_tx_tailroom_pending_dec;
+       sdata->crypto_tx_tailroom_pending_dec = 0;
+       mutex_unlock(&sdata->local->key_mtx);
+}
 
 void ieee80211_gtk_rekey_notify(struct ieee80211_vif *vif, const u8 *bssid,
                                const u8 *replay_ctr, gfp_t gfp)
index 382dc44..2a682d8 100644 (file)
@@ -134,7 +134,7 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
 int __must_check ieee80211_key_link(struct ieee80211_key *key,
                                    struct ieee80211_sub_if_data *sdata,
                                    struct sta_info *sta);
-void __ieee80211_key_free(struct ieee80211_key *key);
+void __ieee80211_key_free(struct ieee80211_key *key, bool delay_tailroom);
 void ieee80211_key_free(struct ieee80211_local *local,
                        struct ieee80211_key *key);
 void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx,
@@ -143,9 +143,10 @@ void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata,
                                    int idx);
 void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata);
 void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata);
-void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata);
 
 #define key_mtx_dereference(local, ref) \
        rcu_dereference_protected(ref, lockdep_is_held(&((local)->key_mtx)))
 
+void ieee80211_delayed_tailroom_dec(struct work_struct *wk);
+
 #endif /* IEEE80211_KEY_H */
index 1a8591b..5a53aa5 100644 (file)
@@ -399,30 +399,6 @@ static int ieee80211_ifa6_changed(struct notifier_block *nb,
 }
 #endif
 
-static int ieee80211_napi_poll(struct napi_struct *napi, int budget)
-{
-       struct ieee80211_local *local =
-               container_of(napi, struct ieee80211_local, napi);
-
-       return local->ops->napi_poll(&local->hw, budget);
-}
-
-void ieee80211_napi_schedule(struct ieee80211_hw *hw)
-{
-       struct ieee80211_local *local = hw_to_local(hw);
-
-       napi_schedule(&local->napi);
-}
-EXPORT_SYMBOL(ieee80211_napi_schedule);
-
-void ieee80211_napi_complete(struct ieee80211_hw *hw)
-{
-       struct ieee80211_local *local = hw_to_local(hw);
-
-       napi_complete(&local->napi);
-}
-EXPORT_SYMBOL(ieee80211_napi_complete);
-
 /* There isn't a lot of sense in it, but you can transmit anything you like */
 static const struct ieee80211_txrx_stypes
 ieee80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = {
@@ -501,6 +477,27 @@ static const struct ieee80211_ht_cap mac80211_ht_capa_mod_mask = {
        },
 };
 
+static const struct ieee80211_vht_cap mac80211_vht_capa_mod_mask = {
+       .vht_cap_info =
+               cpu_to_le32(IEEE80211_VHT_CAP_RXLDPC |
+                           IEEE80211_VHT_CAP_SHORT_GI_80 |
+                           IEEE80211_VHT_CAP_SHORT_GI_160 |
+                           IEEE80211_VHT_CAP_RXSTBC_1 |
+                           IEEE80211_VHT_CAP_RXSTBC_2 |
+                           IEEE80211_VHT_CAP_RXSTBC_3 |
+                           IEEE80211_VHT_CAP_RXSTBC_4 |
+                           IEEE80211_VHT_CAP_TXSTBC |
+                           IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE |
+                           IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
+                           IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN |
+                           IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN |
+                           IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK),
+       .supp_mcs = {
+               .rx_mcs_map = cpu_to_le16(~0),
+               .tx_mcs_map = cpu_to_le16(~0),
+       },
+};
+
 static const u8 extended_capabilities[] = {
        0, 0, 0, 0, 0, 0, 0,
        WLAN_EXT_CAPA8_OPMODE_NOTIF,
@@ -572,7 +569,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_VIF_TXPOWER;
+                          NL80211_FEATURE_VIF_TXPOWER |
+                          NL80211_FEATURE_USERSPACE_MPM;
 
        if (!ops->hw_scan)
                wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN |
@@ -609,6 +607,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
                                         IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH;
        local->user_power_level = IEEE80211_UNSET_POWER_LEVEL;
        wiphy->ht_capa_mod_mask = &mac80211_ht_capa_mod_mask;
+       wiphy->vht_capa_mod_mask = &mac80211_vht_capa_mod_mask;
 
        INIT_LIST_HEAD(&local->interfaces);
 
@@ -664,9 +663,6 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
        skb_queue_head_init(&local->skb_queue);
        skb_queue_head_init(&local->skb_queue_unreliable);
 
-       /* init dummy netdev for use w/ NAPI */
-       init_dummy_netdev(&local->napi_dev);
-
        ieee80211_led_names(local);
 
        ieee80211_roc_setup(local);
@@ -1021,9 +1017,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
                goto fail_ifa6;
 #endif
 
-       netif_napi_add(&local->napi_dev, &local->napi, ieee80211_napi_poll,
-                       local->hw.napi_weight);
-
        return 0;
 
 #if IS_ENABLED(CONFIG_IPV6)
index 29ce2aa..5ac017f 100644 (file)
 #include "ieee80211_i.h"
 #include "mesh.h"
 
-#define TMR_RUNNING_HK 0
-#define TMR_RUNNING_MP 1
-#define TMR_RUNNING_MPR        2
-
 static int mesh_allocated;
 static struct kmem_cache *rm_cache;
 
@@ -50,11 +46,6 @@ static void ieee80211_mesh_housekeeping_timer(unsigned long data)
 
        set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags);
 
-       if (local->quiescing) {
-               set_bit(TMR_RUNNING_HK, &ifmsh->timers_running);
-               return;
-       }
-
        ieee80211_queue_work(&local->hw, &sdata->work);
 }
 
@@ -165,7 +156,7 @@ void mesh_sta_cleanup(struct sta_info *sta)
         * an update.
         */
        changed = mesh_accept_plinks_update(sdata);
-       if (sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) {
+       if (!sdata->u.mesh.user_mpm) {
                changed |= mesh_plink_deactivate(sta);
                del_timer_sync(&sta->plink_timer);
        }
@@ -479,15 +470,8 @@ static void ieee80211_mesh_path_timer(unsigned long data)
 {
        struct ieee80211_sub_if_data *sdata =
                (struct ieee80211_sub_if_data *) data;
-       struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
-       struct ieee80211_local *local = sdata->local;
-
-       if (local->quiescing) {
-               set_bit(TMR_RUNNING_MP, &ifmsh->timers_running);
-               return;
-       }
 
-       ieee80211_queue_work(&local->hw, &sdata->work);
+       ieee80211_queue_work(&sdata->local->hw, &sdata->work);
 }
 
 static void ieee80211_mesh_path_root_timer(unsigned long data)
@@ -495,16 +479,10 @@ static void ieee80211_mesh_path_root_timer(unsigned long data)
        struct ieee80211_sub_if_data *sdata =
                (struct ieee80211_sub_if_data *) data;
        struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
-       struct ieee80211_local *local = sdata->local;
 
        set_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags);
 
-       if (local->quiescing) {
-               set_bit(TMR_RUNNING_MPR, &ifmsh->timers_running);
-               return;
-       }
-
-       ieee80211_queue_work(&local->hw, &sdata->work);
+       ieee80211_queue_work(&sdata->local->hw, &sdata->work);
 }
 
 void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh)
@@ -622,35 +600,6 @@ static void ieee80211_mesh_rootpath(struct ieee80211_sub_if_data *sdata)
                  round_jiffies(TU_TO_EXP_TIME(interval)));
 }
 
-#ifdef CONFIG_PM
-void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata)
-{
-       struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
-
-       /* use atomic bitops in case all timers fire at the same time */
-
-       if (del_timer_sync(&ifmsh->housekeeping_timer))
-               set_bit(TMR_RUNNING_HK, &ifmsh->timers_running);
-       if (del_timer_sync(&ifmsh->mesh_path_timer))
-               set_bit(TMR_RUNNING_MP, &ifmsh->timers_running);
-       if (del_timer_sync(&ifmsh->mesh_path_root_timer))
-               set_bit(TMR_RUNNING_MPR, &ifmsh->timers_running);
-}
-
-void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata)
-{
-       struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
-
-       if (test_and_clear_bit(TMR_RUNNING_HK, &ifmsh->timers_running))
-               add_timer(&ifmsh->housekeeping_timer);
-       if (test_and_clear_bit(TMR_RUNNING_MP, &ifmsh->timers_running))
-               add_timer(&ifmsh->mesh_path_timer);
-       if (test_and_clear_bit(TMR_RUNNING_MPR, &ifmsh->timers_running))
-               add_timer(&ifmsh->mesh_path_root_timer);
-       ieee80211_mesh_root_setup(ifmsh);
-}
-#endif
-
 static int
 ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
 {
@@ -871,8 +820,6 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
        local->fif_other_bss--;
        atomic_dec(&local->iff_allmultis);
        ieee80211_configure_filter(local);
-
-       sdata->u.mesh.timers_running = 0;
 }
 
 static void
index 336c88a..6ffabbe 100644 (file)
@@ -313,8 +313,6 @@ void mesh_path_timer(unsigned long data);
 void mesh_path_flush_by_nexthop(struct sta_info *sta);
 void mesh_path_discard_frame(struct ieee80211_sub_if_data *sdata,
                             struct sk_buff *skb);
-void mesh_path_quiesce(struct ieee80211_sub_if_data *sdata);
-void mesh_path_restart(struct ieee80211_sub_if_data *sdata);
 void mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata);
 
 bool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt);
@@ -359,22 +357,12 @@ static inline bool mesh_path_sel_is_hwmp(struct ieee80211_sub_if_data *sdata)
 
 void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local);
 
-void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata);
-void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata);
-void mesh_plink_quiesce(struct sta_info *sta);
-void mesh_plink_restart(struct sta_info *sta);
 void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata);
 void mesh_sync_adjust_tbtt(struct ieee80211_sub_if_data *sdata);
 void ieee80211s_stop(void);
 #else
 static inline void
 ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) {}
-static inline void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata)
-{}
-static inline void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata)
-{}
-static inline void mesh_plink_quiesce(struct sta_info *sta) {}
-static inline void mesh_plink_restart(struct sta_info *sta) {}
 static inline bool mesh_path_sel_is_hwmp(struct ieee80211_sub_if_data *sdata)
 { return false; }
 static inline void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata)
index 07d396d..937e06f 100644 (file)
@@ -420,7 +420,6 @@ __mesh_sta_info_alloc(struct ieee80211_sub_if_data *sdata, u8 *hw_addr)
                return NULL;
 
        sta->plink_state = NL80211_PLINK_LISTEN;
-       init_timer(&sta->plink_timer);
 
        sta_info_pre_move_state(sta, IEEE80211_STA_AUTH);
        sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC);
@@ -437,8 +436,9 @@ mesh_sta_info_alloc(struct ieee80211_sub_if_data *sdata, u8 *addr,
 {
        struct sta_info *sta = NULL;
 
-       /* Userspace handles peer allocation when security is enabled */
-       if (sdata->u.mesh.security & IEEE80211_MESH_SEC_AUTHED)
+       /* Userspace handles station allocation */
+       if (sdata->u.mesh.user_mpm ||
+           sdata->u.mesh.security & IEEE80211_MESH_SEC_AUTHED)
                cfg80211_notify_new_peer_candidate(sdata->dev, addr,
                                                   elems->ie_start,
                                                   elems->total_len,
@@ -534,10 +534,8 @@ static void mesh_plink_timer(unsigned long data)
         */
        sta = (struct sta_info *) data;
 
-       if (sta->sdata->local->quiescing) {
-               sta->plink_timer_was_running = true;
+       if (sta->sdata->local->quiescing)
                return;
-       }
 
        spin_lock_bh(&sta->lock);
        if (sta->ignore_plink_timer) {
@@ -598,29 +596,6 @@ static void mesh_plink_timer(unsigned long data)
        }
 }
 
-#ifdef CONFIG_PM
-void mesh_plink_quiesce(struct sta_info *sta)
-{
-       if (!ieee80211_vif_is_mesh(&sta->sdata->vif))
-               return;
-
-       /* no kernel mesh sta timers have been initialized */
-       if (sta->sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE)
-               return;
-
-       if (del_timer_sync(&sta->plink_timer))
-               sta->plink_timer_was_running = true;
-}
-
-void mesh_plink_restart(struct sta_info *sta)
-{
-       if (sta->plink_timer_was_running) {
-               add_timer(&sta->plink_timer);
-               sta->plink_timer_was_running = false;
-       }
-}
-#endif
-
 static inline void mesh_plink_timer_set(struct sta_info *sta, int timeout)
 {
        sta->plink_timer.expires = jiffies + (HZ * timeout / 1000);
@@ -695,6 +670,10 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
        if (len < IEEE80211_MIN_ACTION_SIZE + 3)
                return;
 
+       if (sdata->u.mesh.user_mpm)
+               /* userspace must register for these */
+               return;
+
        if (is_multicast_ether_addr(mgmt->da)) {
                mpl_dbg(sdata,
                        "Mesh plink: ignore frame from multicast address\n");
index 1415774..fdc06e3 100644 (file)
@@ -87,9 +87,6 @@ MODULE_PARM_DESC(probe_wait_ms,
  */
 #define IEEE80211_SIGNAL_AVE_MIN_COUNT 4
 
-#define TMR_RUNNING_TIMER      0
-#define TMR_RUNNING_CHANSW     1
-
 /*
  * All cfg80211 functions have to be called outside a locked
  * section so that they can acquire a lock themselves... This
@@ -609,6 +606,7 @@ static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata,
        BUILD_BUG_ON(sizeof(vht_cap) != sizeof(sband->vht_cap));
 
        memcpy(&vht_cap, &sband->vht_cap, sizeof(vht_cap));
+       ieee80211_apply_vhtcap_overrides(sdata, &vht_cap);
 
        /* determine capability flags */
        cap = vht_cap.cap;
@@ -1038,14 +1036,8 @@ static void ieee80211_chswitch_timer(unsigned long data)
 {
        struct ieee80211_sub_if_data *sdata =
                (struct ieee80211_sub_if_data *) data;
-       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 
-       if (sdata->local->quiescing) {
-               set_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running);
-               return;
-       }
-
-       ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work);
+       ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.chswitch_work);
 }
 
 void
@@ -1802,9 +1794,11 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
        sdata->vif.bss_conf.p2p_ctwindow = 0;
        sdata->vif.bss_conf.p2p_oppps = false;
 
-       /* on the next assoc, re-program HT parameters */
+       /* on the next assoc, re-program HT/VHT parameters */
        memset(&ifmgd->ht_capa, 0, sizeof(ifmgd->ht_capa));
        memset(&ifmgd->ht_capa_mask, 0, sizeof(ifmgd->ht_capa_mask));
+       memset(&ifmgd->vht_capa, 0, sizeof(ifmgd->vht_capa));
+       memset(&ifmgd->vht_capa_mask, 0, sizeof(ifmgd->vht_capa_mask));
 
        sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL;
 
@@ -1830,8 +1824,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
        del_timer_sync(&sdata->u.mgd.timer);
        del_timer_sync(&sdata->u.mgd.chswitch_timer);
 
-       sdata->u.mgd.timers_running = 0;
-
        sdata->vif.bss_conf.dtim_period = 0;
 
        ifmgd->flags = 0;
@@ -3140,15 +3132,8 @@ static void ieee80211_sta_timer(unsigned long data)
 {
        struct ieee80211_sub_if_data *sdata =
                (struct ieee80211_sub_if_data *) data;
-       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
-       struct ieee80211_local *local = sdata->local;
-
-       if (local->quiescing) {
-               set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running);
-               return;
-       }
 
-       ieee80211_queue_work(&local->hw, &sdata->work);
+       ieee80211_queue_work(&sdata->local->hw, &sdata->work);
 }
 
 static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata,
@@ -3500,72 +3485,6 @@ static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata)
        }
 }
 
-#ifdef CONFIG_PM
-void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata)
-{
-       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
-
-       /*
-        * Stop timers before deleting work items, as timers
-        * could race and re-add the work-items. They will be
-        * re-established on connection.
-        */
-       del_timer_sync(&ifmgd->conn_mon_timer);
-       del_timer_sync(&ifmgd->bcn_mon_timer);
-
-       /*
-        * we need to use atomic bitops for the running bits
-        * only because both timers might fire at the same
-        * time -- the code here is properly synchronised.
-        */
-
-       cancel_work_sync(&ifmgd->request_smps_work);
-
-       cancel_work_sync(&ifmgd->monitor_work);
-       cancel_work_sync(&ifmgd->beacon_connection_loss_work);
-       cancel_work_sync(&ifmgd->csa_connection_drop_work);
-       if (del_timer_sync(&ifmgd->timer))
-               set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running);
-
-       if (del_timer_sync(&ifmgd->chswitch_timer))
-               set_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running);
-       cancel_work_sync(&ifmgd->chswitch_work);
-}
-
-void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata)
-{
-       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
-
-       mutex_lock(&ifmgd->mtx);
-       if (!ifmgd->associated) {
-               mutex_unlock(&ifmgd->mtx);
-               return;
-       }
-
-       if (sdata->flags & IEEE80211_SDATA_DISCONNECT_RESUME) {
-               sdata->flags &= ~IEEE80211_SDATA_DISCONNECT_RESUME;
-               mlme_dbg(sdata, "driver requested disconnect after resume\n");
-               ieee80211_sta_connection_lost(sdata,
-                                             ifmgd->associated->bssid,
-                                             WLAN_REASON_UNSPECIFIED,
-                                             true);
-               mutex_unlock(&ifmgd->mtx);
-               return;
-       }
-       mutex_unlock(&ifmgd->mtx);
-
-       if (test_and_clear_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running))
-               add_timer(&ifmgd->timer);
-       if (test_and_clear_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running))
-               add_timer(&ifmgd->chswitch_timer);
-       ieee80211_sta_reset_beacon_monitor(sdata);
-
-       mutex_lock(&sdata->local->mtx);
-       ieee80211_restart_sta_timer(sdata);
-       mutex_unlock(&sdata->local->mtx);
-}
-#endif
-
 /* interface setup */
 void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
 {
@@ -4071,6 +3990,9 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
                ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
        }
 
+       if (req->flags & ASSOC_REQ_DISABLE_VHT)
+               ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
+
        /* Also disable HT if we don't support it or the AP doesn't use WMM */
        sband = local->hw.wiphy->bands[req->bss->channel->band];
        if (!sband->ht_cap.ht_supported ||
@@ -4094,6 +4016,10 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
        memcpy(&ifmgd->ht_capa_mask, &req->ht_capa_mask,
               sizeof(ifmgd->ht_capa_mask));
 
+       memcpy(&ifmgd->vht_capa, &req->vht_capa, sizeof(ifmgd->vht_capa));
+       memcpy(&ifmgd->vht_capa_mask, &req->vht_capa_mask,
+              sizeof(ifmgd->vht_capa_mask));
+
        if (req->ie && req->ie_len) {
                memcpy(assoc_data->ie, req->ie, req->ie_len);
                assoc_data->ie_len = req->ie_len;
index cc79b4a..db547fc 100644 (file)
@@ -277,7 +277,7 @@ void ieee80211_start_next_roc(struct ieee80211_local *local)
                        duration = 10;
 
                ret = drv_remain_on_channel(local, roc->sdata, roc->chan,
-                                           duration);
+                                           duration, roc->type);
 
                roc->started = true;
 
index d0275f3..b471a67 100644 (file)
@@ -6,32 +6,11 @@
 #include "driver-ops.h"
 #include "led.h"
 
-/* return value indicates whether the driver should be further notified */
-static void ieee80211_quiesce(struct ieee80211_sub_if_data *sdata)
-{
-       switch (sdata->vif.type) {
-       case NL80211_IFTYPE_STATION:
-               ieee80211_sta_quiesce(sdata);
-               break;
-       case NL80211_IFTYPE_ADHOC:
-               ieee80211_ibss_quiesce(sdata);
-               break;
-       case NL80211_IFTYPE_MESH_POINT:
-               ieee80211_mesh_quiesce(sdata);
-               break;
-       default:
-               break;
-       }
-
-       cancel_work_sync(&sdata->work);
-}
-
 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;
@@ -93,19 +72,12 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
                        return err;
                } else if (err > 0) {
                        WARN_ON(err != 1);
-                       local->wowlan = false;
+                       return err;
                } else {
-                       list_for_each_entry(sdata, &local->interfaces, list)
-                               if (ieee80211_sdata_running(sdata))
-                                       ieee80211_quiesce(sdata);
                        goto suspend;
                }
        }
 
-       /* disable keys */
-       list_for_each_entry(sdata, &local->interfaces, list)
-               ieee80211_disable_keys(sdata);
-
        /* tear down aggregation sessions and remove STAs */
        mutex_lock(&local->sta_mtx);
        list_for_each_entry(sta, &local->sta_list, list) {
@@ -117,100 +89,25 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
                                WARN_ON(drv_sta_state(local, sta->sdata, sta,
                                                      state, state - 1));
                }
-
-               mesh_plink_quiesce(sta);
        }
        mutex_unlock(&local->sta_mtx);
 
        /* remove all interfaces */
        list_for_each_entry(sdata, &local->interfaces, list) {
-               static u8 zero_addr[ETH_ALEN] = {};
-               u32 changed = 0;
-
                if (!ieee80211_sdata_running(sdata))
                        continue;
-
-               switch (sdata->vif.type) {
-               case NL80211_IFTYPE_AP_VLAN:
-               case NL80211_IFTYPE_MONITOR:
-                       /* skip these */
-                       continue;
-               case NL80211_IFTYPE_STATION:
-                       if (sdata->vif.bss_conf.assoc)
-                               changed = BSS_CHANGED_ASSOC |
-                                         BSS_CHANGED_BSSID |
-                                         BSS_CHANGED_IDLE;
-                       break;
-               case NL80211_IFTYPE_AP:
-               case NL80211_IFTYPE_ADHOC:
-               case NL80211_IFTYPE_MESH_POINT:
-                       if (sdata->vif.bss_conf.enable_beacon)
-                               changed = BSS_CHANGED_BEACON_ENABLED;
-                       break;
-               default:
-                       break;
-               }
-
-               ieee80211_quiesce(sdata);
-
-               sdata->suspend_bss_conf = sdata->vif.bss_conf;
-               memset(&sdata->vif.bss_conf, 0, sizeof(sdata->vif.bss_conf));
-               sdata->vif.bss_conf.idle = true;
-               if (sdata->suspend_bss_conf.bssid)
-                       sdata->vif.bss_conf.bssid = zero_addr;
-
-               /* disable beaconing or remove association */
-               ieee80211_bss_info_change_notify(sdata, changed);
-
-               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 (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);
-               }
-
+       if (sdata)
                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);
+       /*
+        * We disconnected on all interfaces before suspend, all channel
+        * contexts should be released.
+        */
+       WARN_ON(!list_empty(&local->chanctx_list));
 
        /* stop hardware - this must stop RX */
        if (local->open_count)
index eea45a2..1c36c9b 100644 (file)
@@ -55,7 +55,6 @@
 #include "rate.h"
 #include "rc80211_minstrel.h"
 
-#define SAMPLE_COLUMNS 10
 #define SAMPLE_TBL(_mi, _idx, _col) \
                _mi->sample_table[(_idx * SAMPLE_COLUMNS) + _col]
 
@@ -70,16 +69,31 @@ rix_to_ndx(struct minstrel_sta_info *mi, int rix)
        return i;
 }
 
+/* find & sort topmost throughput rates */
+static inline void
+minstrel_sort_best_tp_rates(struct minstrel_sta_info *mi, int i, u8 *tp_list)
+{
+       int j = MAX_THR_RATES;
+
+       while (j > 0 && mi->r[i].cur_tp > mi->r[tp_list[j - 1]].cur_tp)
+               j--;
+       if (j < MAX_THR_RATES - 1)
+               memmove(&tp_list[j + 1], &tp_list[j], MAX_THR_RATES - (j + 1));
+       if (j < MAX_THR_RATES)
+               tp_list[j] = i;
+}
+
 static void
 minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi)
 {
-       u32 max_tp = 0, index_max_tp = 0, index_max_tp2 = 0;
-       u32 max_prob = 0, index_max_prob = 0;
+       u8 tmp_tp_rate[MAX_THR_RATES];
+       u8 tmp_prob_rate = 0;
        u32 usecs;
-       u32 p;
        int i;
 
-       mi->stats_update = jiffies;
+       for (i=0; i < MAX_THR_RATES; i++)
+           tmp_tp_rate[i] = 0;
+
        for (i = 0; i < mi->n_rates; i++) {
                struct minstrel_rate *mr = &mi->r[i];
 
@@ -87,27 +101,32 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi)
                if (!usecs)
                        usecs = 1000000;
 
-               /* To avoid rounding issues, probabilities scale from 0 (0%)
-                * to 18000 (100%) */
-               if (mr->attempts) {
-                       p = (mr->success * 18000) / mr->attempts;
+               if (unlikely(mr->attempts > 0)) {
+                       mr->sample_skipped = 0;
+                       mr->cur_prob = MINSTREL_FRAC(mr->success, mr->attempts);
                        mr->succ_hist += mr->success;
                        mr->att_hist += mr->attempts;
-                       mr->cur_prob = p;
-                       p = ((p * (100 - mp->ewma_level)) + (mr->probability *
-                               mp->ewma_level)) / 100;
-                       mr->probability = p;
-                       mr->cur_tp = p * (1000000 / usecs);
-               }
+                       mr->probability = minstrel_ewma(mr->probability,
+                                                       mr->cur_prob,
+                                                       EWMA_LEVEL);
+               } else
+                       mr->sample_skipped++;
 
                mr->last_success = mr->success;
                mr->last_attempts = mr->attempts;
                mr->success = 0;
                mr->attempts = 0;
 
+               /* Update throughput per rate, reset thr. below 10% success */
+               if (mr->probability < MINSTREL_FRAC(10, 100))
+                       mr->cur_tp = 0;
+               else
+                       mr->cur_tp = mr->probability * (1000000 / usecs);
+
                /* Sample less often below the 10% chance of success.
                 * Sample less often above the 95% chance of success. */
-               if ((mr->probability > 17100) || (mr->probability < 1800)) {
+               if (mr->probability > MINSTREL_FRAC(95, 100) ||
+                   mr->probability < MINSTREL_FRAC(10, 100)) {
                        mr->adjusted_retry_count = mr->retry_count >> 1;
                        if (mr->adjusted_retry_count > 2)
                                mr->adjusted_retry_count = 2;
@@ -118,35 +137,30 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi)
                }
                if (!mr->adjusted_retry_count)
                        mr->adjusted_retry_count = 2;
-       }
 
-       for (i = 0; i < mi->n_rates; i++) {
-               struct minstrel_rate *mr = &mi->r[i];
-               if (max_tp < mr->cur_tp) {
-                       index_max_tp = i;
-                       max_tp = mr->cur_tp;
-               }
-               if (max_prob < mr->probability) {
-                       index_max_prob = i;
-                       max_prob = mr->probability;
+               minstrel_sort_best_tp_rates(mi, i, tmp_tp_rate);
+
+               /* To determine the most robust rate (max_prob_rate) used at
+                * 3rd mmr stage we distinct between two cases:
+                * (1) if any success probabilitiy >= 95%, out of those rates
+                * choose the maximum throughput rate as max_prob_rate
+                * (2) if all success probabilities < 95%, the rate with
+                * highest success probability is choosen as max_prob_rate */
+               if (mr->probability >= MINSTREL_FRAC(95,100)) {
+                       if (mr->cur_tp >= mi->r[tmp_prob_rate].cur_tp)
+                               tmp_prob_rate = i;
+               } else {
+                       if (mr->probability >= mi->r[tmp_prob_rate].probability)
+                               tmp_prob_rate = i;
                }
        }
 
-       max_tp = 0;
-       for (i = 0; i < mi->n_rates; i++) {
-               struct minstrel_rate *mr = &mi->r[i];
-
-               if (i == index_max_tp)
-                       continue;
+       /* Assign the new rate set */
+       memcpy(mi->max_tp_rate, tmp_tp_rate, sizeof(mi->max_tp_rate));
+       mi->max_prob_rate = tmp_prob_rate;
 
-               if (max_tp < mr->cur_tp) {
-                       index_max_tp2 = i;
-                       max_tp = mr->cur_tp;
-               }
-       }
-       mi->max_tp_rate = index_max_tp;
-       mi->max_tp_rate2 = index_max_tp2;
-       mi->max_prob_rate = index_max_prob;
+       /* Reset update timer */
+       mi->stats_update = jiffies;
 }
 
 static void
@@ -207,10 +221,10 @@ static int
 minstrel_get_next_sample(struct minstrel_sta_info *mi)
 {
        unsigned int sample_ndx;
-       sample_ndx = SAMPLE_TBL(mi, mi->sample_idx, mi->sample_column);
-       mi->sample_idx++;
-       if ((int) mi->sample_idx > (mi->n_rates - 2)) {
-               mi->sample_idx = 0;
+       sample_ndx = SAMPLE_TBL(mi, mi->sample_row, mi->sample_column);
+       mi->sample_row++;
+       if ((int) mi->sample_row >= mi->n_rates) {
+               mi->sample_row = 0;
                mi->sample_column++;
                if (mi->sample_column >= SAMPLE_COLUMNS)
                        mi->sample_column = 0;
@@ -228,31 +242,37 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta,
        struct minstrel_priv *mp = priv;
        struct ieee80211_tx_rate *ar = info->control.rates;
        unsigned int ndx, sample_ndx = 0;
-       bool mrr;
-       bool sample_slower = false;
-       bool sample = false;
+       bool mrr_capable;
+       bool indirect_rate_sampling = false;
+       bool rate_sampling = false;
        int i, delta;
        int mrr_ndx[3];
-       int sample_rate;
+       int sampling_ratio;
 
+       /* management/no-ack frames do not use rate control */
        if (rate_control_send_low(sta, priv_sta, txrc))
                return;
 
-       mrr = mp->has_mrr && !txrc->rts && !txrc->bss_conf->use_cts_prot;
-
-       ndx = mi->max_tp_rate;
-
-       if (mrr)
-               sample_rate = mp->lookaround_rate_mrr;
+       /* check multi-rate-retry capabilities & adjust lookaround_rate */
+       mrr_capable = mp->has_mrr &&
+                     !txrc->rts &&
+                     !txrc->bss_conf->use_cts_prot;
+       if (mrr_capable)
+               sampling_ratio = mp->lookaround_rate_mrr;
        else
-               sample_rate = mp->lookaround_rate;
+               sampling_ratio = mp->lookaround_rate;
+
+       /* init rateindex [ndx] with max throughput rate */
+       ndx = mi->max_tp_rate[0];
 
+       /* increase sum packet counter */
        mi->packet_count++;
-       delta = (mi->packet_count * sample_rate / 100) -
+
+       delta = (mi->packet_count * sampling_ratio / 100) -
                        (mi->sample_count + mi->sample_deferred / 2);
 
        /* delta > 0: sampling required */
-       if ((delta > 0) && (mrr || !mi->prev_sample)) {
+       if ((delta > 0) && (mrr_capable || !mi->prev_sample)) {
                struct minstrel_rate *msr;
                if (mi->packet_count >= 10000) {
                        mi->sample_deferred = 0;
@@ -271,21 +291,28 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta,
                        mi->sample_count += (delta - mi->n_rates * 2);
                }
 
+               /* get next random rate sample */
                sample_ndx = minstrel_get_next_sample(mi);
                msr = &mi->r[sample_ndx];
-               sample = true;
-               sample_slower = mrr && (msr->perfect_tx_time >
-                       mi->r[ndx].perfect_tx_time);
-
-               if (!sample_slower) {
+               rate_sampling = true;
+
+               /* Decide if direct ( 1st mrr stage) or indirect (2nd mrr stage)
+                * rate sampling method should be used.
+                * Respect such rates that are not sampled for 20 interations.
+                */
+               if (mrr_capable &&
+                   msr->perfect_tx_time > mi->r[ndx].perfect_tx_time &&
+                   msr->sample_skipped < 20)
+                               indirect_rate_sampling = true;
+
+               if (!indirect_rate_sampling) {
                        if (msr->sample_limit != 0) {
                                ndx = sample_ndx;
                                mi->sample_count++;
                                if (msr->sample_limit > 0)
                                        msr->sample_limit--;
-                       } else {
-                               sample = false;
-                       }
+                       } else
+                               rate_sampling = false;
                } else {
                        /* Only use IEEE80211_TX_CTL_RATE_CTRL_PROBE to mark
                         * packets that have the sampling rate deferred to the
@@ -297,34 +324,39 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta,
                        mi->sample_deferred++;
                }
        }
-       mi->prev_sample = sample;
+       mi->prev_sample = rate_sampling;
 
        /* If we're not using MRR and the sampling rate already
         * has a probability of >95%, we shouldn't be attempting
         * to use it, as this only wastes precious airtime */
-       if (!mrr && sample && (mi->r[ndx].probability > 17100))
-               ndx = mi->max_tp_rate;
+       if (!mrr_capable && rate_sampling &&
+          (mi->r[ndx].probability > MINSTREL_FRAC(95, 100)))
+               ndx = mi->max_tp_rate[0];
 
+       /* mrr setup for 1st stage */
        ar[0].idx = mi->r[ndx].rix;
        ar[0].count = minstrel_get_retry_count(&mi->r[ndx], info);
 
-       if (!mrr) {
-               if (!sample)
+       /* non mrr setup for 2nd stage */
+       if (!mrr_capable) {
+               if (!rate_sampling)
                        ar[0].count = mp->max_retry;
                ar[1].idx = mi->lowest_rix;
                ar[1].count = mp->max_retry;
                return;
        }
 
-       /* MRR setup */
-       if (sample) {
-               if (sample_slower)
+       /* mrr setup for 2nd stage */
+       if (rate_sampling) {
+               if (indirect_rate_sampling)
                        mrr_ndx[0] = sample_ndx;
                else
-                       mrr_ndx[0] = mi->max_tp_rate;
+                       mrr_ndx[0] = mi->max_tp_rate[0];
        } else {
-               mrr_ndx[0] = mi->max_tp_rate2;
+               mrr_ndx[0] = mi->max_tp_rate[1];
        }
+
+       /* mrr setup for 3rd & 4th stage */
        mrr_ndx[1] = mi->max_prob_rate;
        mrr_ndx[2] = 0;
        for (i = 1; i < 4; i++) {
@@ -351,26 +383,21 @@ static void
 init_sample_table(struct minstrel_sta_info *mi)
 {
        unsigned int i, col, new_idx;
-       unsigned int n_srates = mi->n_rates - 1;
        u8 rnd[8];
 
        mi->sample_column = 0;
-       mi->sample_idx = 0;
-       memset(mi->sample_table, 0, SAMPLE_COLUMNS * mi->n_rates);
+       mi->sample_row = 0;
+       memset(mi->sample_table, 0xff, SAMPLE_COLUMNS * mi->n_rates);
 
        for (col = 0; col < SAMPLE_COLUMNS; col++) {
-               for (i = 0; i < n_srates; i++) {
+               for (i = 0; i < mi->n_rates; i++) {
                        get_random_bytes(rnd, sizeof(rnd));
-                       new_idx = (i + rnd[i & 7]) % n_srates;
+                       new_idx = (i + rnd[i & 7]) % mi->n_rates;
 
-                       while (SAMPLE_TBL(mi, new_idx, col) != 0)
-                               new_idx = (new_idx + 1) % n_srates;
+                       while (SAMPLE_TBL(mi, new_idx, col) != 0xff)
+                               new_idx = (new_idx + 1) % mi->n_rates;
 
-                       /* Don't sample the slowest rate (i.e. slowest base
-                        * rate). We must presume that the slowest rate works
-                        * fine, or else other management frames will also be
-                        * failing and the link will break */
-                       SAMPLE_TBL(mi, new_idx, col) = i + 1;
+                       SAMPLE_TBL(mi, new_idx, col) = i;
                }
        }
 }
@@ -542,9 +569,6 @@ minstrel_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
        mp->lookaround_rate = 5;
        mp->lookaround_rate_mrr = 10;
 
-       /* moving average weight for EWMA */
-       mp->ewma_level = 75;
-
        /* maximum time that the hw is allowed to stay in one MRR segment */
        mp->segment_size = 6000;
 
index 5ecf757..85ebf42 100644 (file)
@@ -9,6 +9,28 @@
 #ifndef __RC_MINSTREL_H
 #define __RC_MINSTREL_H
 
+#define EWMA_LEVEL     75      /* ewma weighting factor [%] */
+#define SAMPLE_COLUMNS 10      /* number of columns in sample table */
+
+
+/* scaled fraction values */
+#define MINSTREL_SCALE  16
+#define MINSTREL_FRAC(val, div) (((val) << MINSTREL_SCALE) / div)
+#define MINSTREL_TRUNC(val) ((val) >> MINSTREL_SCALE)
+
+/* number of highest throughput rates to consider*/
+#define MAX_THR_RATES 4
+
+/*
+ * Perform EWMA (Exponentially Weighted Moving Average) calculation
+  */
+static inline int
+minstrel_ewma(int old, int new, int weight)
+{
+       return (new * (100 - weight) + old * weight) / 100;
+}
+
+
 struct minstrel_rate {
        int bitrate;
        int rix;
@@ -26,6 +48,7 @@ struct minstrel_rate {
        u32 attempts;
        u32 last_attempts;
        u32 last_success;
+       u8 sample_skipped;
 
        /* parts per thousand */
        u32 cur_prob;
@@ -45,14 +68,13 @@ struct minstrel_sta_info {
 
        unsigned int lowest_rix;
 
-       unsigned int max_tp_rate;
-       unsigned int max_tp_rate2;
-       unsigned int max_prob_rate;
+       u8 max_tp_rate[MAX_THR_RATES];
+       u8 max_prob_rate;
        unsigned int packet_count;
        unsigned int sample_count;
        int sample_deferred;
 
-       unsigned int sample_idx;
+       unsigned int sample_row;
        unsigned int sample_column;
 
        int n_rates;
@@ -73,7 +95,6 @@ struct minstrel_priv {
        unsigned int cw_min;
        unsigned int cw_max;
        unsigned int max_retry;
-       unsigned int ewma_level;
        unsigned int segment_size;
        unsigned int update_interval;
        unsigned int lookaround_rate;
index d5a5622..d104834 100644 (file)
@@ -73,15 +73,17 @@ minstrel_stats_open(struct inode *inode, struct file *file)
        for (i = 0; i < mi->n_rates; i++) {
                struct minstrel_rate *mr = &mi->r[i];
 
-               *(p++) = (i == mi->max_tp_rate) ? 'T' : ' ';
-               *(p++) = (i == mi->max_tp_rate2) ? 't' : ' ';
+               *(p++) = (i == mi->max_tp_rate[0]) ? 'A' : ' ';
+               *(p++) = (i == mi->max_tp_rate[1]) ? 'B' : ' ';
+               *(p++) = (i == mi->max_tp_rate[2]) ? 'C' : ' ';
+               *(p++) = (i == mi->max_tp_rate[3]) ? 'D' : ' ';
                *(p++) = (i == mi->max_prob_rate) ? 'P' : ' ';
                p += sprintf(p, "%3u%s", mr->bitrate / 2,
                                (mr->bitrate & 1 ? ".5" : "  "));
 
-               tp = mr->cur_tp / ((18000 << 10) / 96);
-               prob = mr->cur_prob / 18;
-               eprob = mr->probability / 18;
+               tp = MINSTREL_TRUNC(mr->cur_tp / 10);
+               prob = MINSTREL_TRUNC(mr->cur_prob * 1000);
+               eprob = MINSTREL_TRUNC(mr->probability * 1000);
 
                p += sprintf(p, "  %6u.%1u   %6u.%1u   %6u.%1u        "
                                "%3u(%3u)   %8llu    %8llu\n",
index 3af141c..749552b 100644 (file)
@@ -17,8 +17,6 @@
 #include "rc80211_minstrel_ht.h"
 
 #define AVG_PKT_SIZE   1200
-#define SAMPLE_COLUMNS 10
-#define EWMA_LEVEL             75
 
 /* Number of bits for an average sized packet */
 #define MCS_NBITS (AVG_PKT_SIZE << 3)
 /* Number of symbols for a packet with (bps) bits per symbol */
 #define MCS_NSYMS(bps) ((MCS_NBITS + (bps) - 1) / (bps))
 
-/* Transmission time for a packet containing (syms) symbols */
+/* Transmission time (nanoseconds) for a packet containing (syms) symbols */
 #define MCS_SYMBOL_TIME(sgi, syms)                                     \
        (sgi ?                                                          \
-         ((syms) * 18 + 4) / 5 :       /* syms * 3.6 us */             \
-         (syms) << 2                   /* syms * 4 us */               \
+         ((syms) * 18000 + 4000) / 5 : /* syms * 3.6 us */             \
+         ((syms) * 1000) << 2          /* syms * 4 us */               \
        )
 
 /* Transmit duration for the raw data part of an average sized packet */
@@ -64,9 +62,9 @@
 }
 
 #define CCK_DURATION(_bitrate, _short, _len)           \
-       (10 /* SIFS */ +                                \
+       (1000 * (10 /* SIFS */ +                        \
         (_short ? 72 + 24 : 144 + 48 ) +               \
-        (8 * (_len + 4) * 10) / (_bitrate))
+        (8 * (_len + 4) * 10) / (_bitrate)))
 
 #define CCK_ACK_DURATION(_bitrate, _short)                     \
        (CCK_DURATION((_bitrate > 10 ? 20 : 10), false, 60) +   \
@@ -128,15 +126,6 @@ const struct mcs_group minstrel_mcs_groups[] = {
 
 static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES];
 
-/*
- * Perform EWMA (Exponentially Weighted Moving Average) calculation
- */
-static int
-minstrel_ewma(int old, int new, int weight)
-{
-       return (new * (100 - weight) + old * weight) / 100;
-}
-
 /*
  * Look up an MCS group index based on mac80211 rate information
  */
@@ -211,7 +200,8 @@ static void
 minstrel_ht_calc_tp(struct minstrel_ht_sta *mi, int group, int rate)
 {
        struct minstrel_rate_stats *mr;
-       unsigned int usecs = 0;
+       unsigned int nsecs = 0;
+       unsigned int tp;
 
        mr = &mi->groups[group].rates[rate];
 
@@ -221,10 +211,12 @@ minstrel_ht_calc_tp(struct minstrel_ht_sta *mi, int group, int rate)
        }
 
        if (group != MINSTREL_CCK_GROUP)
-               usecs = mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len);
+               nsecs = 1000 * mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len);
 
-       usecs += minstrel_mcs_groups[group].duration[rate];
-       mr->cur_tp = MINSTREL_TRUNC((1000000 / usecs) * mr->probability);
+       nsecs += minstrel_mcs_groups[group].duration[rate];
+       tp = 1000000 * ((mr->probability * 1000) / nsecs);
+
+       mr->cur_tp = MINSTREL_TRUNC(tp);
 }
 
 /*
@@ -308,8 +300,8 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
                }
        }
 
-       /* try to sample up to half of the available rates during each interval */
-       mi->sample_count *= 4;
+       /* try to sample all available rates during each interval */
+       mi->sample_count *= 8;
 
        cur_prob = 0;
        cur_prob_tp = 0;
@@ -320,20 +312,13 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
                if (!mg->supported)
                        continue;
 
-               mr = minstrel_get_ratestats(mi, mg->max_prob_rate);
-               if (cur_prob_tp < mr->cur_tp &&
-                   minstrel_mcs_groups[group].streams == 1) {
-                       mi->max_prob_rate = mg->max_prob_rate;
-                       cur_prob = mr->cur_prob;
-                       cur_prob_tp = mr->cur_tp;
-               }
-
                mr = minstrel_get_ratestats(mi, mg->max_tp_rate);
                if (cur_tp < mr->cur_tp) {
                        mi->max_tp_rate2 = mi->max_tp_rate;
                        cur_tp2 = cur_tp;
                        mi->max_tp_rate = mg->max_tp_rate;
                        cur_tp = mr->cur_tp;
+                       mi->max_prob_streams = minstrel_mcs_groups[group].streams - 1;
                }
 
                mr = minstrel_get_ratestats(mi, mg->max_tp_rate2);
@@ -343,6 +328,23 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
                }
        }
 
+       if (mi->max_prob_streams < 1)
+               mi->max_prob_streams = 1;
+
+       for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) {
+               mg = &mi->groups[group];
+               if (!mg->supported)
+                       continue;
+               mr = minstrel_get_ratestats(mi, mg->max_prob_rate);
+               if (cur_prob_tp < mr->cur_tp &&
+                   minstrel_mcs_groups[group].streams <= mi->max_prob_streams) {
+                       mi->max_prob_rate = mg->max_prob_rate;
+                       cur_prob = mr->cur_prob;
+                       cur_prob_tp = mr->cur_tp;
+               }
+       }
+
+
        mi->stats_update = jiffies;
 }
 
@@ -467,7 +469,7 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband,
 
        if (!mi->sample_wait && !mi->sample_tries && mi->sample_count > 0) {
                mi->sample_wait = 16 + 2 * MINSTREL_TRUNC(mi->avg_ampdu_len);
-               mi->sample_tries = 2;
+               mi->sample_tries = 1;
                mi->sample_count--;
        }
 
@@ -536,7 +538,7 @@ minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
        mr->retry_updated = true;
 
        group = &minstrel_mcs_groups[index / MCS_GROUP_RATES];
-       tx_time_data = group->duration[index % MCS_GROUP_RATES] * ampdu_len;
+       tx_time_data = group->duration[index % MCS_GROUP_RATES] * ampdu_len / 1000;
 
        /* Contention time for first 2 tries */
        ctime = (t_slot * cw) >> 1;
@@ -616,6 +618,7 @@ minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
 {
        struct minstrel_rate_stats *mr;
        struct minstrel_mcs_group_data *mg;
+       unsigned int sample_dur, sample_group;
        int sample_idx = 0;
 
        if (mi->sample_wait > 0) {
@@ -626,11 +629,11 @@ minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
        if (!mi->sample_tries)
                return -1;
 
-       mi->sample_tries--;
        mg = &mi->groups[mi->sample_group];
        sample_idx = sample_table[mg->column][mg->index];
        mr = &mg->rates[sample_idx];
-       sample_idx += mi->sample_group * MCS_GROUP_RATES;
+       sample_group = mi->sample_group;
+       sample_idx += sample_group * MCS_GROUP_RATES;
        minstrel_next_sample_idx(mi);
 
        /*
@@ -651,14 +654,18 @@ minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
         * Make sure that lower rates get sampled only occasionally,
         * if the link is working perfectly.
         */
-       if (minstrel_get_duration(sample_idx) >
-           minstrel_get_duration(mi->max_tp_rate)) {
+       sample_dur = minstrel_get_duration(sample_idx);
+       if (sample_dur >= minstrel_get_duration(mi->max_tp_rate2) &&
+           (mi->max_prob_streams <
+            minstrel_mcs_groups[sample_group].streams ||
+            sample_dur >= minstrel_get_duration(mi->max_prob_rate))) {
                if (mr->sample_skipped < 20)
                        return -1;
 
                if (mi->sample_slow++ > 2)
                        return -1;
        }
+       mi->sample_tries--;
 
        return sample_idx;
 }
index 302dbd5..9b16e9d 100644 (file)
 #define MINSTREL_MAX_STREAMS   3
 #define MINSTREL_STREAM_GROUPS 4
 
-/* scaled fraction values */
-#define MINSTREL_SCALE 16
-#define MINSTREL_FRAC(val, div) (((val) << MINSTREL_SCALE) / div)
-#define MINSTREL_TRUNC(val) ((val) >> MINSTREL_SCALE)
-
 #define MCS_GROUP_RATES        8
 
 struct mcs_group {
@@ -85,6 +80,7 @@ struct minstrel_ht_sta {
 
        /* best probability rate */
        unsigned int max_prob_rate;
+       unsigned int max_prob_streams;
 
        /* time of last status update */
        unsigned long stats_update;
index bb73ed2..5b4492a 100644 (file)
@@ -648,24 +648,6 @@ static ieee80211_rx_result ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
        return RX_CONTINUE;
 }
 
-#define SEQ_MODULO 0x1000
-#define SEQ_MASK   0xfff
-
-static inline int seq_less(u16 sq1, u16 sq2)
-{
-       return ((sq1 - sq2) & SEQ_MASK) > (SEQ_MODULO >> 1);
-}
-
-static inline u16 seq_inc(u16 sq)
-{
-       return (sq + 1) & SEQ_MASK;
-}
-
-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,
@@ -687,7 +669,7 @@ static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata,
        __skb_queue_tail(frames, skb);
 
 no_frame:
-       tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num);
+       tid_agg_rx->head_seq_num = ieee80211_sn_inc(tid_agg_rx->head_seq_num);
 }
 
 static void ieee80211_release_reorder_frames(struct ieee80211_sub_if_data *sdata,
@@ -699,8 +681,9 @@ static void ieee80211_release_reorder_frames(struct ieee80211_sub_if_data *sdata
 
        lockdep_assert_held(&tid_agg_rx->reorder_lock);
 
-       while (seq_less(tid_agg_rx->head_seq_num, head_seq_num)) {
-               index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
+       while (ieee80211_sn_less(tid_agg_rx->head_seq_num, head_seq_num)) {
+               index = ieee80211_sn_sub(tid_agg_rx->head_seq_num,
+                                        tid_agg_rx->ssn) %
                                                        tid_agg_rx->buf_size;
                ieee80211_release_reorder_frame(sdata, tid_agg_rx, index,
                                                frames);
@@ -727,8 +710,8 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata,
        lockdep_assert_held(&tid_agg_rx->reorder_lock);
 
        /* release the buffer until next missing frame */
-       index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
-                                               tid_agg_rx->buf_size;
+       index = ieee80211_sn_sub(tid_agg_rx->head_seq_num,
+                                tid_agg_rx->ssn) % tid_agg_rx->buf_size;
        if (!tid_agg_rx->reorder_buf[index] &&
            tid_agg_rx->stored_mpdu_num) {
                /*
@@ -756,19 +739,22 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata,
                         * Increment the head seq# also for the skipped slots.
                         */
                        tid_agg_rx->head_seq_num =
-                               (tid_agg_rx->head_seq_num + skipped) & SEQ_MASK;
+                               (tid_agg_rx->head_seq_num +
+                                skipped) & IEEE80211_SN_MASK;
                        skipped = 0;
                }
        } else while (tid_agg_rx->reorder_buf[index]) {
                ieee80211_release_reorder_frame(sdata, tid_agg_rx, index,
                                                frames);
-               index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
+               index = ieee80211_sn_sub(tid_agg_rx->head_seq_num,
+                                        tid_agg_rx->ssn) %
                                                        tid_agg_rx->buf_size;
        }
 
        if (tid_agg_rx->stored_mpdu_num) {
-               j = index = seq_sub(tid_agg_rx->head_seq_num,
-                                   tid_agg_rx->ssn) % tid_agg_rx->buf_size;
+               j = index = ieee80211_sn_sub(tid_agg_rx->head_seq_num,
+                                            tid_agg_rx->ssn) %
+                                                       tid_agg_rx->buf_size;
 
                for (; j != (index - 1) % tid_agg_rx->buf_size;
                     j = (j + 1) % tid_agg_rx->buf_size) {
@@ -809,7 +795,7 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata
        head_seq_num = tid_agg_rx->head_seq_num;
 
        /* frame with out of date sequence number */
-       if (seq_less(mpdu_seq_num, head_seq_num)) {
+       if (ieee80211_sn_less(mpdu_seq_num, head_seq_num)) {
                dev_kfree_skb(skb);
                goto out;
        }
@@ -818,8 +804,9 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata
         * If frame the sequence number exceeds our buffering window
         * size release some previous frames to make room for this one.
         */
-       if (!seq_less(mpdu_seq_num, head_seq_num + buf_size)) {
-               head_seq_num = seq_inc(seq_sub(mpdu_seq_num, buf_size));
+       if (!ieee80211_sn_less(mpdu_seq_num, head_seq_num + buf_size)) {
+               head_seq_num = ieee80211_sn_inc(
+                               ieee80211_sn_sub(mpdu_seq_num, buf_size));
                /* release stored frames up to new head to stack */
                ieee80211_release_reorder_frames(sdata, tid_agg_rx,
                                                 head_seq_num, frames);
@@ -827,7 +814,8 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata
 
        /* Now the new frame is always in the range of the reordering buffer */
 
-       index = seq_sub(mpdu_seq_num, tid_agg_rx->ssn) % tid_agg_rx->buf_size;
+       index = ieee80211_sn_sub(mpdu_seq_num,
+                                tid_agg_rx->ssn) % tid_agg_rx->buf_size;
 
        /* check if we already stored this frame */
        if (tid_agg_rx->reorder_buf[index]) {
@@ -843,7 +831,8 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata
         */
        if (mpdu_seq_num == tid_agg_rx->head_seq_num &&
            tid_agg_rx->stored_mpdu_num == 0) {
-               tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num);
+               tid_agg_rx->head_seq_num =
+                       ieee80211_sn_inc(tid_agg_rx->head_seq_num);
                ret = false;
                goto out;
        }
@@ -1894,8 +1883,10 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
                 * 'align' will only take the values 0 or 2 here
                 * since all frames are required to be aligned
                 * to 2-byte boundaries when being passed to
-                * mac80211. That also explains the __skb_push()
-                * below.
+                * mac80211; the code here works just as well if
+                * that isn't true, but mac80211 assumes it can
+                * access fields as 2-byte aligned (e.g. for
+                * compare_ether_addr)
                 */
                align = ((unsigned long)(skb->data + sizeof(struct ethhdr))) & 3;
                if (align) {
@@ -2552,7 +2543,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
                case WLAN_SP_MESH_PEERING_CONFIRM:
                        if (!ieee80211_vif_is_mesh(&sdata->vif))
                                goto invalid;
-                       if (sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE)
+                       if (sdata->u.mesh.user_mpm)
                                /* userspace handles this frame */
                                break;
                        goto queue;
index a79ce82..3644ad7 100644 (file)
@@ -342,6 +342,11 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
        INIT_WORK(&sta->drv_unblock_wk, sta_unblock);
        INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work);
        mutex_init(&sta->ampdu_mlme.mtx);
+#ifdef CONFIG_MAC80211_MESH
+       if (ieee80211_vif_is_mesh(&sdata->vif) &&
+           !sdata->u.mesh.user_mpm)
+               init_timer(&sta->plink_timer);
+#endif
 
        memcpy(sta->sta.addr, addr, ETH_ALEN);
        sta->local = local;
@@ -794,9 +799,11 @@ int __must_check __sta_info_destroy(struct sta_info *sta)
 
        mutex_lock(&local->key_mtx);
        for (i = 0; i < NUM_DEFAULT_KEYS; i++)
-               __ieee80211_key_free(key_mtx_dereference(local, sta->gtk[i]));
+               __ieee80211_key_free(key_mtx_dereference(local, sta->gtk[i]),
+                                    true);
        if (sta->ptk)
-               __ieee80211_key_free(key_mtx_dereference(local, sta->ptk));
+               __ieee80211_key_free(key_mtx_dereference(local, sta->ptk),
+                                    true);
        mutex_unlock(&local->key_mtx);
 
        sta->dead = true;
index 4947341..e5868c3 100644 (file)
@@ -281,7 +281,6 @@ struct sta_ampdu_mlme {
  * @plink_state: peer link state
  * @plink_timeout: timeout of peer link
  * @plink_timer: peer link watch timer
- * @plink_timer_was_running: used by suspend/resume to restore timers
  * @t_offset: timing offset relative to this host
  * @t_offset_setpoint: reference timing offset of this sta to be used when
  *     calculating clockdrift
@@ -379,7 +378,6 @@ struct sta_info {
        __le16 reason;
        u8 plink_retries;
        bool ignore_plink_timer;
-       bool plink_timer_was_running;
        enum nl80211_plink_state plink_state;
        u32 plink_timeout;
        struct timer_list plink_timer;
index 3d7cd2a..e7db2b8 100644 (file)
@@ -1042,15 +1042,17 @@ TRACE_EVENT(drv_remain_on_channel,
        TP_PROTO(struct ieee80211_local *local,
                 struct ieee80211_sub_if_data *sdata,
                 struct ieee80211_channel *chan,
-                unsigned int duration),
+                unsigned int duration,
+                enum ieee80211_roc_type type),
 
-       TP_ARGS(local, sdata, chan, duration),
+       TP_ARGS(local, sdata, chan, duration, type),
 
        TP_STRUCT__entry(
                LOCAL_ENTRY
                VIF_ENTRY
                __field(int, center_freq)
                __field(unsigned int, duration)
+               __field(u32, type)
        ),
 
        TP_fast_assign(
@@ -1058,12 +1060,13 @@ TRACE_EVENT(drv_remain_on_channel,
                VIF_ASSIGN;
                __entry->center_freq = chan->center_freq;
                __entry->duration = duration;
+               __entry->type = type;
        ),
 
        TP_printk(
-               LOCAL_PR_FMT  VIF_PR_FMT " freq:%dMHz duration:%dms",
+               LOCAL_PR_FMT  VIF_PR_FMT " freq:%dMHz duration:%dms type=%d",
                LOCAL_PR_ARG, VIF_PR_ARG,
-               __entry->center_freq, __entry->duration
+               __entry->center_freq, __entry->duration, __entry->type
        )
 );
 
index 0f38f43..b7a856e 100644 (file)
@@ -1357,6 +1357,25 @@ void ieee80211_stop_device(struct ieee80211_local *local)
        drv_stop(local);
 }
 
+static void ieee80211_assign_chanctx(struct ieee80211_local *local,
+                                    struct ieee80211_sub_if_data *sdata)
+{
+       struct ieee80211_chanctx_conf *conf;
+       struct ieee80211_chanctx *ctx;
+
+       if (!local->use_chanctx)
+               return;
+
+       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_assign_vif_chanctx(local, sdata, ctx);
+       }
+       mutex_unlock(&local->chanctx_mtx);
+}
+
 int ieee80211_reconfig(struct ieee80211_local *local)
 {
        struct ieee80211_hw *hw = &local->hw;
@@ -1445,36 +1464,14 @@ int ieee80211_reconfig(struct ieee80211_local *local)
        }
 
        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);
+               ieee80211_assign_chanctx(local, sdata);
        }
 
        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);
-       }
+       if (sdata && ieee80211_sdata_running(sdata))
+               ieee80211_assign_chanctx(local, sdata);
 
        /* add STAs back */
        mutex_lock(&local->sta_mtx);
@@ -1534,11 +1531,6 @@ int ieee80211_reconfig(struct ieee80211_local *local)
                          BSS_CHANGED_IDLE |
                          BSS_CHANGED_TXPOWER;
 
-#ifdef CONFIG_PM
-               if (local->resuming && !reconfig_due_to_wowlan)
-                       sdata->vif.bss_conf = sdata->suspend_bss_conf;
-#endif
-
                switch (sdata->vif.type) {
                case NL80211_IFTYPE_STATION:
                        changed |= BSS_CHANGED_ASSOC |
@@ -1678,28 +1670,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
        mb();
        local->resuming = false;
 
-       list_for_each_entry(sdata, &local->interfaces, list) {
-               switch(sdata->vif.type) {
-               case NL80211_IFTYPE_STATION:
-                       ieee80211_sta_restart(sdata);
-                       break;
-               case NL80211_IFTYPE_ADHOC:
-                       ieee80211_ibss_restart(sdata);
-                       break;
-               case NL80211_IFTYPE_MESH_POINT:
-                       ieee80211_mesh_restart(sdata);
-                       break;
-               default:
-                       break;
-               }
-       }
-
        mod_timer(&local->sta_cleanup, jiffies + 1);
-
-       mutex_lock(&local->sta_mtx);
-       list_for_each_entry(sta, &local->sta_list, list)
-               mesh_plink_restart(sta);
-       mutex_unlock(&local->sta_mtx);
 #else
        WARN_ON(1);
 #endif
index a2c2258..171344d 100644 (file)
 #include "rate.h"
 
 
+static void __check_vhtcap_disable(struct ieee80211_sub_if_data *sdata,
+                                  struct ieee80211_sta_vht_cap *vht_cap,
+                                  u32 flag)
+{
+       __le32 le_flag = cpu_to_le32(flag);
+
+       if (sdata->u.mgd.vht_capa_mask.vht_cap_info & le_flag &&
+           !(sdata->u.mgd.vht_capa.vht_cap_info & le_flag))
+               vht_cap->cap &= ~flag;
+}
+
+void ieee80211_apply_vhtcap_overrides(struct ieee80211_sub_if_data *sdata,
+                                     struct ieee80211_sta_vht_cap *vht_cap)
+{
+       int i;
+       u16 rxmcs_mask, rxmcs_cap, rxmcs_n, txmcs_mask, txmcs_cap, txmcs_n;
+
+       if (!vht_cap->vht_supported)
+               return;
+
+       if (sdata->vif.type != NL80211_IFTYPE_STATION)
+               return;
+
+       __check_vhtcap_disable(sdata, vht_cap,
+                              IEEE80211_VHT_CAP_RXLDPC);
+       __check_vhtcap_disable(sdata, vht_cap,
+                              IEEE80211_VHT_CAP_SHORT_GI_80);
+       __check_vhtcap_disable(sdata, vht_cap,
+                              IEEE80211_VHT_CAP_SHORT_GI_160);
+       __check_vhtcap_disable(sdata, vht_cap,
+                              IEEE80211_VHT_CAP_TXSTBC);
+       __check_vhtcap_disable(sdata, vht_cap,
+                              IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE);
+       __check_vhtcap_disable(sdata, vht_cap,
+                              IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE);
+       __check_vhtcap_disable(sdata, vht_cap,
+                              IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN);
+       __check_vhtcap_disable(sdata, vht_cap,
+                              IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN);
+
+       /* Allow user to decrease AMPDU length exponent */
+       if (sdata->u.mgd.vht_capa_mask.vht_cap_info &
+           cpu_to_le32(IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK)) {
+               u32 cap, n;
+
+               n = le32_to_cpu(sdata->u.mgd.vht_capa.vht_cap_info) &
+                       IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK;
+               n >>= IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT;
+               cap = vht_cap->cap & IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK;
+               cap >>= IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT;
+
+               if (n < cap) {
+                       vht_cap->cap &=
+                               ~IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK;
+                       vht_cap->cap |=
+                               n << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT;
+               }
+       }
+
+       /* Allow the user to decrease MCSes */
+       rxmcs_mask =
+               le16_to_cpu(sdata->u.mgd.vht_capa_mask.supp_mcs.rx_mcs_map);
+       rxmcs_n = le16_to_cpu(sdata->u.mgd.vht_capa.supp_mcs.rx_mcs_map);
+       rxmcs_n &= rxmcs_mask;
+       rxmcs_cap = le16_to_cpu(vht_cap->vht_mcs.rx_mcs_map);
+
+       txmcs_mask =
+               le16_to_cpu(sdata->u.mgd.vht_capa_mask.supp_mcs.tx_mcs_map);
+       txmcs_n = le16_to_cpu(sdata->u.mgd.vht_capa.supp_mcs.tx_mcs_map);
+       txmcs_n &= txmcs_mask;
+       txmcs_cap = le16_to_cpu(vht_cap->vht_mcs.tx_mcs_map);
+       for (i = 0; i < 8; i++) {
+               u8 m, n, c;
+
+               m = (rxmcs_mask >> 2*i) & IEEE80211_VHT_MCS_NOT_SUPPORTED;
+               n = (rxmcs_n >> 2*i) & IEEE80211_VHT_MCS_NOT_SUPPORTED;
+               c = (rxmcs_cap >> 2*i) & IEEE80211_VHT_MCS_NOT_SUPPORTED;
+
+               if (m && ((c != IEEE80211_VHT_MCS_NOT_SUPPORTED && n < c) ||
+                         n == IEEE80211_VHT_MCS_NOT_SUPPORTED)) {
+                       rxmcs_cap &= ~(3 << 2*i);
+                       rxmcs_cap |= (rxmcs_n & (3 << 2*i));
+               }
+
+               m = (txmcs_mask >> 2*i) & IEEE80211_VHT_MCS_NOT_SUPPORTED;
+               n = (txmcs_n >> 2*i) & IEEE80211_VHT_MCS_NOT_SUPPORTED;
+               c = (txmcs_cap >> 2*i) & IEEE80211_VHT_MCS_NOT_SUPPORTED;
+
+               if (m && ((c != IEEE80211_VHT_MCS_NOT_SUPPORTED && n < c) ||
+                         n == IEEE80211_VHT_MCS_NOT_SUPPORTED)) {
+                       txmcs_cap &= ~(3 << 2*i);
+                       txmcs_cap |= (txmcs_n & (3 << 2*i));
+               }
+       }
+       vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(rxmcs_cap);
+       vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(txmcs_cap);
+}
+
 void
 ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
                                    struct ieee80211_supported_band *sband,
@@ -20,6 +118,8 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
                                    struct sta_info *sta)
 {
        struct ieee80211_sta_vht_cap *vht_cap = &sta->sta.vht_cap;
+       struct ieee80211_sta_vht_cap own_cap;
+       u32 cap_info, i;
 
        memset(vht_cap, 0, sizeof(*vht_cap));
 
@@ -35,12 +135,122 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
 
        vht_cap->vht_supported = true;
 
-       vht_cap->cap = le32_to_cpu(vht_cap_ie->vht_cap_info);
+       own_cap = sband->vht_cap;
+       /*
+        * If user has specified capability overrides, take care
+        * of that if the station we're setting up is the AP that
+        * we advertised a restricted capability set to. Override
+        * our own capabilities and then use those below.
+        */
+       if (sdata->vif.type == NL80211_IFTYPE_STATION &&
+           !test_sta_flag(sta, WLAN_STA_TDLS_PEER))
+               ieee80211_apply_vhtcap_overrides(sdata, &own_cap);
+
+       /* take some capabilities as-is */
+       cap_info = le32_to_cpu(vht_cap_ie->vht_cap_info);
+       vht_cap->cap = cap_info;
+       vht_cap->cap &= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895 |
+                       IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991 |
+                       IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 |
+                       IEEE80211_VHT_CAP_RXLDPC |
+                       IEEE80211_VHT_CAP_VHT_TXOP_PS |
+                       IEEE80211_VHT_CAP_HTC_VHT |
+                       IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK |
+                       IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB |
+                       IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB |
+                       IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN |
+                       IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN;
+
+       /* and some based on our own capabilities */
+       switch (own_cap.cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) {
+       case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ:
+               vht_cap->cap |= cap_info &
+                               IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
+               break;
+       case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ:
+               vht_cap->cap |= cap_info &
+                               IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
+               break;
+       default:
+               /* nothing */
+               break;
+       }
+
+       /* symmetric capabilities */
+       vht_cap->cap |= cap_info & own_cap.cap &
+                       (IEEE80211_VHT_CAP_SHORT_GI_80 |
+                        IEEE80211_VHT_CAP_SHORT_GI_160);
+
+       /* remaining ones */
+       if (own_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE) {
+               vht_cap->cap |= cap_info &
+                               (IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE |
+                                IEEE80211_VHT_CAP_BEAMFORMER_ANTENNAS_MAX |
+                                IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MAX);
+       }
+
+       if (own_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE)
+               vht_cap->cap |= cap_info &
+                               IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE;
+
+       if (own_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE)
+               vht_cap->cap |= cap_info &
+                               IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE;
+
+       if (own_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE)
+               vht_cap->cap |= cap_info &
+                               IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE;
+
+       if (own_cap.cap & IEEE80211_VHT_CAP_TXSTBC)
+               vht_cap->cap |= cap_info & IEEE80211_VHT_CAP_RXSTBC_MASK;
+
+       if (own_cap.cap & IEEE80211_VHT_CAP_RXSTBC_MASK)
+               vht_cap->cap |= cap_info & IEEE80211_VHT_CAP_TXSTBC;
 
        /* Copy peer MCS info, the driver might need them. */
        memcpy(&vht_cap->vht_mcs, &vht_cap_ie->supp_mcs,
               sizeof(struct ieee80211_vht_mcs_info));
 
+       /* but also restrict MCSes */
+       for (i = 0; i < 8; i++) {
+               u16 own_rx, own_tx, peer_rx, peer_tx;
+
+               own_rx = le16_to_cpu(own_cap.vht_mcs.rx_mcs_map);
+               own_rx = (own_rx >> i * 2) & IEEE80211_VHT_MCS_NOT_SUPPORTED;
+
+               own_tx = le16_to_cpu(own_cap.vht_mcs.tx_mcs_map);
+               own_tx = (own_tx >> i * 2) & IEEE80211_VHT_MCS_NOT_SUPPORTED;
+
+               peer_rx = le16_to_cpu(vht_cap->vht_mcs.rx_mcs_map);
+               peer_rx = (peer_rx >> i * 2) & IEEE80211_VHT_MCS_NOT_SUPPORTED;
+
+               peer_tx = le16_to_cpu(vht_cap->vht_mcs.tx_mcs_map);
+               peer_tx = (peer_tx >> i * 2) & IEEE80211_VHT_MCS_NOT_SUPPORTED;
+
+               if (peer_tx != IEEE80211_VHT_MCS_NOT_SUPPORTED) {
+                       if (own_rx == IEEE80211_VHT_MCS_NOT_SUPPORTED)
+                               peer_tx = IEEE80211_VHT_MCS_NOT_SUPPORTED;
+                       else if (own_rx < peer_tx)
+                               peer_tx = own_rx;
+               }
+
+               if (peer_rx != IEEE80211_VHT_MCS_NOT_SUPPORTED) {
+                       if (own_tx == IEEE80211_VHT_MCS_NOT_SUPPORTED)
+                               peer_rx = IEEE80211_VHT_MCS_NOT_SUPPORTED;
+                       else if (own_tx < peer_rx)
+                               peer_rx = own_tx;
+               }
+
+               vht_cap->vht_mcs.rx_mcs_map &=
+                       ~cpu_to_le16(IEEE80211_VHT_MCS_NOT_SUPPORTED << i * 2);
+               vht_cap->vht_mcs.rx_mcs_map |= cpu_to_le16(peer_rx << i * 2);
+
+               vht_cap->vht_mcs.tx_mcs_map &=
+                       ~cpu_to_le16(IEEE80211_VHT_MCS_NOT_SUPPORTED << i * 2);
+               vht_cap->vht_mcs.tx_mcs_map |= cpu_to_le16(peer_tx << i * 2);
+       }
+
+       /* finally set up the bandwidth */
        switch (vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) {
        case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ:
        case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ:
index c6bc3bd..b75a9b3 100644 (file)
@@ -117,6 +117,88 @@ u8 *nfc_llcp_build_tlv(u8 type, u8 *value, u8 value_length, u8 *tlv_length)
        return tlv;
 }
 
+struct nfc_llcp_sdp_tlv *nfc_llcp_build_sdres_tlv(u8 tid, u8 sap)
+{
+       struct nfc_llcp_sdp_tlv *sdres;
+       u8 value[2];
+
+       sdres = kzalloc(sizeof(struct nfc_llcp_sdp_tlv), GFP_KERNEL);
+       if (sdres == NULL)
+               return NULL;
+
+       value[0] = tid;
+       value[1] = sap;
+
+       sdres->tlv = nfc_llcp_build_tlv(LLCP_TLV_SDRES, value, 2,
+                                       &sdres->tlv_len);
+       if (sdres->tlv == NULL) {
+               kfree(sdres);
+               return NULL;
+       }
+
+       sdres->tid = tid;
+       sdres->sap = sap;
+
+       INIT_HLIST_NODE(&sdres->node);
+
+       return sdres;
+}
+
+struct nfc_llcp_sdp_tlv *nfc_llcp_build_sdreq_tlv(u8 tid, char *uri,
+                                                 size_t uri_len)
+{
+       struct nfc_llcp_sdp_tlv *sdreq;
+
+       pr_debug("uri: %s, len: %zu\n", uri, uri_len);
+
+       sdreq = kzalloc(sizeof(struct nfc_llcp_sdp_tlv), GFP_KERNEL);
+       if (sdreq == NULL)
+               return NULL;
+
+       sdreq->tlv_len = uri_len + 3;
+
+       if (uri[uri_len - 1] == 0)
+               sdreq->tlv_len--;
+
+       sdreq->tlv = kzalloc(sdreq->tlv_len + 1, GFP_KERNEL);
+       if (sdreq->tlv == NULL) {
+               kfree(sdreq);
+               return NULL;
+       }
+
+       sdreq->tlv[0] = LLCP_TLV_SDREQ;
+       sdreq->tlv[1] = sdreq->tlv_len - 2;
+       sdreq->tlv[2] = tid;
+
+       sdreq->tid = tid;
+       sdreq->uri = sdreq->tlv + 3;
+       memcpy(sdreq->uri, uri, uri_len);
+
+       sdreq->time = jiffies;
+
+       INIT_HLIST_NODE(&sdreq->node);
+
+       return sdreq;
+}
+
+void nfc_llcp_free_sdp_tlv(struct nfc_llcp_sdp_tlv *sdp)
+{
+       kfree(sdp->tlv);
+       kfree(sdp);
+}
+
+void nfc_llcp_free_sdp_tlv_list(struct hlist_head *head)
+{
+       struct nfc_llcp_sdp_tlv *sdp;
+       struct hlist_node *n;
+
+       hlist_for_each_entry_safe(sdp, n, head, node) {
+               hlist_del(&sdp->node);
+
+               nfc_llcp_free_sdp_tlv(sdp);
+       }
+}
+
 int nfc_llcp_parse_gb_tlv(struct nfc_llcp_local *local,
                          u8 *tlv_array, u16 tlv_array_len)
 {
@@ -184,10 +266,10 @@ int nfc_llcp_parse_connection_tlv(struct nfc_llcp_sock *sock,
 
                switch (type) {
                case LLCP_TLV_MIUX:
-                       sock->miu = llcp_tlv_miux(tlv) + 128;
+                       sock->remote_miu = llcp_tlv_miux(tlv) + 128;
                        break;
                case LLCP_TLV_RW:
-                       sock->rw = llcp_tlv_rw(tlv);
+                       sock->remote_rw = llcp_tlv_rw(tlv);
                        break;
                case LLCP_TLV_SN:
                        break;
@@ -200,7 +282,8 @@ int nfc_llcp_parse_connection_tlv(struct nfc_llcp_sock *sock,
                tlv += length + 2;
        }
 
-       pr_debug("sock %p rw %d miu %d\n", sock, sock->rw, sock->miu);
+       pr_debug("sock %p rw %d miu %d\n", sock,
+                sock->remote_rw, sock->remote_miu);
 
        return 0;
 }
@@ -318,9 +401,9 @@ int nfc_llcp_send_connect(struct nfc_llcp_sock *sock)
        struct sk_buff *skb;
        u8 *service_name_tlv = NULL, service_name_tlv_length;
        u8 *miux_tlv = NULL, miux_tlv_length;
-       u8 *rw_tlv = NULL, rw_tlv_length;
+       u8 *rw_tlv = NULL, rw_tlv_length, rw;
        int err;
-       u16 size = 0;
+       u16 size = 0, miux;
 
        pr_debug("Sending CONNECT\n");
 
@@ -336,11 +419,15 @@ int nfc_llcp_send_connect(struct nfc_llcp_sock *sock)
                size += service_name_tlv_length;
        }
 
-       miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&local->miux, 0,
+       /* If the socket parameters are not set, use the local ones */
+       miux = sock->miux > LLCP_MAX_MIUX ? local->miux : sock->miux;
+       rw = sock->rw > LLCP_MAX_RW ? local->rw : sock->rw;
+
+       miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&miux, 0,
                                      &miux_tlv_length);
        size += miux_tlv_length;
 
-       rw_tlv = nfc_llcp_build_tlv(LLCP_TLV_RW, &local->rw, 0, &rw_tlv_length);
+       rw_tlv = nfc_llcp_build_tlv(LLCP_TLV_RW, &rw, 0, &rw_tlv_length);
        size += rw_tlv_length;
 
        pr_debug("SKB size %d SN length %zu\n", size, sock->service_name_len);
@@ -377,9 +464,9 @@ int nfc_llcp_send_cc(struct nfc_llcp_sock *sock)
        struct nfc_llcp_local *local;
        struct sk_buff *skb;
        u8 *miux_tlv = NULL, miux_tlv_length;
-       u8 *rw_tlv = NULL, rw_tlv_length;
+       u8 *rw_tlv = NULL, rw_tlv_length, rw;
        int err;
-       u16 size = 0;
+       u16 size = 0, miux;
 
        pr_debug("Sending CC\n");
 
@@ -387,11 +474,15 @@ int nfc_llcp_send_cc(struct nfc_llcp_sock *sock)
        if (local == NULL)
                return -ENODEV;
 
-       miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&local->miux, 0,
+       /* If the socket parameters are not set, use the local ones */
+       miux = sock->miux > LLCP_MAX_MIUX ? local->miux : sock->miux;
+       rw = sock->rw > LLCP_MAX_RW ? local->rw : sock->rw;
+
+       miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&miux, 0,
                                      &miux_tlv_length);
        size += miux_tlv_length;
 
-       rw_tlv = nfc_llcp_build_tlv(LLCP_TLV_RW, &local->rw, 0, &rw_tlv_length);
+       rw_tlv = nfc_llcp_build_tlv(LLCP_TLV_RW, &rw, 0, &rw_tlv_length);
        size += rw_tlv_length;
 
        skb = llcp_allocate_pdu(sock, LLCP_PDU_CC, size);
@@ -416,48 +507,90 @@ error_tlv:
        return err;
 }
 
-int nfc_llcp_send_snl(struct nfc_llcp_local *local, u8 tid, u8 sap)
+static struct sk_buff *nfc_llcp_allocate_snl(struct nfc_llcp_local *local,
+                                            size_t tlv_length)
 {
        struct sk_buff *skb;
        struct nfc_dev *dev;
-       u8 *sdres_tlv = NULL, sdres_tlv_length, sdres[2];
        u16 size = 0;
 
-       pr_debug("Sending SNL tid 0x%x sap 0x%x\n", tid, sap);
-
        if (local == NULL)
-               return -ENODEV;
+               return ERR_PTR(-ENODEV);
 
        dev = local->dev;
        if (dev == NULL)
-               return -ENODEV;
-
-       sdres[0] = tid;
-       sdres[1] = sap;
-       sdres_tlv = nfc_llcp_build_tlv(LLCP_TLV_SDRES, sdres, 0,
-                                      &sdres_tlv_length);
-       if (sdres_tlv == NULL)
-               return -ENOMEM;
+               return ERR_PTR(-ENODEV);
 
        size += LLCP_HEADER_SIZE;
        size += dev->tx_headroom + dev->tx_tailroom + NFC_HEADER_SIZE;
-       size += sdres_tlv_length;
+       size += tlv_length;
 
        skb = alloc_skb(size, GFP_KERNEL);
-       if (skb == NULL) {
-               kfree(sdres_tlv);
-               return -ENOMEM;
-       }
+       if (skb == NULL)
+               return ERR_PTR(-ENOMEM);
 
        skb_reserve(skb, dev->tx_headroom + NFC_HEADER_SIZE);
 
        skb = llcp_add_header(skb, LLCP_SAP_SDP, LLCP_SAP_SDP, LLCP_PDU_SNL);
 
-       memcpy(skb_put(skb, sdres_tlv_length), sdres_tlv, sdres_tlv_length);
+       return skb;
+}
+
+int nfc_llcp_send_snl_sdres(struct nfc_llcp_local *local,
+                           struct hlist_head *tlv_list, size_t tlvs_len)
+{
+       struct nfc_llcp_sdp_tlv *sdp;
+       struct hlist_node *n;
+       struct sk_buff *skb;
+
+       skb = nfc_llcp_allocate_snl(local, tlvs_len);
+       if (IS_ERR(skb))
+               return PTR_ERR(skb);
+
+       hlist_for_each_entry_safe(sdp, n, tlv_list, node) {
+               memcpy(skb_put(skb, sdp->tlv_len), sdp->tlv, sdp->tlv_len);
+
+               hlist_del(&sdp->node);
+
+               nfc_llcp_free_sdp_tlv(sdp);
+       }
 
        skb_queue_tail(&local->tx_queue, skb);
 
-       kfree(sdres_tlv);
+       return 0;
+}
+
+int nfc_llcp_send_snl_sdreq(struct nfc_llcp_local *local,
+                           struct hlist_head *tlv_list, size_t tlvs_len)
+{
+       struct nfc_llcp_sdp_tlv *sdreq;
+       struct hlist_node *n;
+       struct sk_buff *skb;
+
+       skb = nfc_llcp_allocate_snl(local, tlvs_len);
+       if (IS_ERR(skb))
+               return PTR_ERR(skb);
+
+       mutex_lock(&local->sdreq_lock);
+
+       if (hlist_empty(&local->pending_sdreqs))
+               mod_timer(&local->sdreq_timer,
+                         jiffies + msecs_to_jiffies(3 * local->remote_lto));
+
+       hlist_for_each_entry_safe(sdreq, n, tlv_list, node) {
+               pr_debug("tid %d for %s\n", sdreq->tid, sdreq->uri);
+
+               memcpy(skb_put(skb, sdreq->tlv_len), sdreq->tlv,
+                      sdreq->tlv_len);
+
+               hlist_del(&sdreq->node);
+
+               hlist_add_head(&sdreq->node, &local->pending_sdreqs);
+       }
+
+       mutex_unlock(&local->sdreq_lock);
+
+       skb_queue_tail(&local->tx_queue, skb);
 
        return 0;
 }
@@ -532,8 +665,8 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock,
 
        /* 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)) {
+           skb_queue_len(&sock->tx_pending_queue) >= sock->remote_rw &&
+           skb_queue_len(&sock->tx_queue) >= 2 * sock->remote_rw)) {
                pr_err("Pending queue is full %d frames\n",
                       skb_queue_len(&sock->tx_pending_queue));
                return -ENOBUFS;
@@ -541,7 +674,7 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock,
 
        /* Remote is not ready and we've been queueing enough frames */
        if ((!sock->remote_ready &&
-            skb_queue_len(&sock->tx_queue) >= 2 * sock->rw)) {
+            skb_queue_len(&sock->tx_queue) >= 2 * sock->remote_rw)) {
                pr_err("Tx queue is full %d frames\n",
                       skb_queue_len(&sock->tx_queue));
                return -ENOBUFS;
@@ -561,7 +694,7 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock,
 
        while (remaining_len > 0) {
 
-               frag_len = min_t(size_t, sock->miu, remaining_len);
+               frag_len = min_t(size_t, sock->remote_miu, remaining_len);
 
                pr_debug("Fragment %zd bytes remaining %zd",
                         frag_len, remaining_len);
@@ -621,7 +754,7 @@ int nfc_llcp_send_ui_frame(struct nfc_llcp_sock *sock, u8 ssap, u8 dsap,
 
        while (remaining_len > 0) {
 
-               frag_len = min_t(size_t, sock->miu, remaining_len);
+               frag_len = min_t(size_t, sock->remote_miu, remaining_len);
 
                pr_debug("Fragment %zd bytes remaining %zd",
                         frag_len, remaining_len);
index b530afa..bb67b98 100644 (file)
@@ -188,6 +188,9 @@ static void local_cleanup(struct nfc_llcp_local *local, bool listen)
        cancel_work_sync(&local->rx_work);
        cancel_work_sync(&local->timeout_work);
        kfree_skb(local->rx_pending);
+       del_timer_sync(&local->sdreq_timer);
+       cancel_work_sync(&local->sdreq_timeout_work);
+       nfc_llcp_free_sdp_tlv_list(&local->pending_sdreqs);
 }
 
 static void local_release(struct kref *ref)
@@ -265,6 +268,47 @@ static void nfc_llcp_symm_timer(unsigned long data)
        schedule_work(&local->timeout_work);
 }
 
+static void nfc_llcp_sdreq_timeout_work(struct work_struct *work)
+{
+       unsigned long time;
+       HLIST_HEAD(nl_sdres_list);
+       struct hlist_node *n;
+       struct nfc_llcp_sdp_tlv *sdp;
+       struct nfc_llcp_local *local = container_of(work, struct nfc_llcp_local,
+                                                   sdreq_timeout_work);
+
+       mutex_lock(&local->sdreq_lock);
+
+       time = jiffies - msecs_to_jiffies(3 * local->remote_lto);
+
+       hlist_for_each_entry_safe(sdp, n, &local->pending_sdreqs, node) {
+               if (time_after(sdp->time, time))
+                       continue;
+
+               sdp->sap = LLCP_SDP_UNBOUND;
+
+               hlist_del(&sdp->node);
+
+               hlist_add_head(&sdp->node, &nl_sdres_list);
+       }
+
+       if (!hlist_empty(&local->pending_sdreqs))
+               mod_timer(&local->sdreq_timer,
+                         jiffies + msecs_to_jiffies(3 * local->remote_lto));
+
+       mutex_unlock(&local->sdreq_lock);
+
+       if (!hlist_empty(&nl_sdres_list))
+               nfc_genl_llc_send_sdres(local->dev, &nl_sdres_list);
+}
+
+static void nfc_llcp_sdreq_timer(unsigned long data)
+{
+       struct nfc_llcp_local *local = (struct nfc_llcp_local *) data;
+
+       schedule_work(&local->sdreq_timeout_work);
+}
+
 struct nfc_llcp_local *nfc_llcp_find_local(struct nfc_dev *dev)
 {
        struct nfc_llcp_local *local, *n;
@@ -808,8 +852,6 @@ static void nfc_llcp_recv_ui(struct nfc_llcp_local *local,
        ui_cb->dsap = dsap;
        ui_cb->ssap = ssap;
 
-       printk("%s %d %d\n", __func__, dsap, ssap);
-
        pr_debug("%d %d\n", dsap, ssap);
 
        /* We're looking for a bound socket, not a client one */
@@ -907,7 +949,9 @@ static void nfc_llcp_recv_connect(struct nfc_llcp_local *local,
        new_sock = nfc_llcp_sock(new_sk);
        new_sock->dev = local->dev;
        new_sock->local = nfc_llcp_local_get(local);
-       new_sock->miu = local->remote_miu;
+       new_sock->rw = sock->rw;
+       new_sock->miux = sock->miux;
+       new_sock->remote_miu = local->remote_miu;
        new_sock->nfc_protocol = sock->nfc_protocol;
        new_sock->dsap = ssap;
        new_sock->target_idx = local->target_idx;
@@ -961,11 +1005,11 @@ int nfc_llcp_queue_i_frames(struct nfc_llcp_sock *sock)
 
        pr_debug("Remote ready %d tx queue len %d remote rw %d",
                 sock->remote_ready, skb_queue_len(&sock->tx_pending_queue),
-                sock->rw);
+                sock->remote_rw);
 
        /* Try to queue some I frames for transmission */
        while (sock->remote_ready &&
-              skb_queue_len(&sock->tx_pending_queue) < sock->rw) {
+              skb_queue_len(&sock->tx_pending_queue) < sock->remote_rw) {
                struct sk_buff *pdu;
 
                pdu = skb_dequeue(&sock->tx_queue);
@@ -1186,6 +1230,10 @@ static void nfc_llcp_recv_snl(struct nfc_llcp_local *local,
        u16 tlv_len, offset;
        char *service_name;
        size_t service_name_len;
+       struct nfc_llcp_sdp_tlv *sdp;
+       HLIST_HEAD(llc_sdres_list);
+       size_t sdres_tlvs_len;
+       HLIST_HEAD(nl_sdres_list);
 
        dsap = nfc_llcp_dsap(skb);
        ssap = nfc_llcp_ssap(skb);
@@ -1200,6 +1248,7 @@ static void nfc_llcp_recv_snl(struct nfc_llcp_local *local,
        tlv = &skb->data[LLCP_HEADER_SIZE];
        tlv_len = skb->len - LLCP_HEADER_SIZE;
        offset = 0;
+       sdres_tlvs_len = 0;
 
        while (offset < tlv_len) {
                type = tlv[0];
@@ -1217,14 +1266,14 @@ static void nfc_llcp_recv_snl(struct nfc_llcp_local *local,
                            !strncmp(service_name, "urn:nfc:sn:sdp",
                                     service_name_len)) {
                                sap = 1;
-                               goto send_snl;
+                               goto add_snl;
                        }
 
                        llcp_sock = nfc_llcp_sock_from_sn(local, service_name,
                                                          service_name_len);
                        if (!llcp_sock) {
                                sap = 0;
-                               goto send_snl;
+                               goto add_snl;
                        }
 
                        /*
@@ -1241,7 +1290,7 @@ static void nfc_llcp_recv_snl(struct nfc_llcp_local *local,
 
                                if (sap == LLCP_SAP_MAX) {
                                        sap = 0;
-                                       goto send_snl;
+                                       goto add_snl;
                                }
 
                                client_count =
@@ -1258,8 +1307,37 @@ static void nfc_llcp_recv_snl(struct nfc_llcp_local *local,
 
                        pr_debug("%p %d\n", llcp_sock, sap);
 
-send_snl:
-                       nfc_llcp_send_snl(local, tid, sap);
+add_snl:
+                       sdp = nfc_llcp_build_sdres_tlv(tid, sap);
+                       if (sdp == NULL)
+                               goto exit;
+
+                       sdres_tlvs_len += sdp->tlv_len;
+                       hlist_add_head(&sdp->node, &llc_sdres_list);
+                       break;
+
+               case LLCP_TLV_SDRES:
+                       mutex_lock(&local->sdreq_lock);
+
+                       pr_debug("LLCP_TLV_SDRES: searching tid %d\n", tlv[2]);
+
+                       hlist_for_each_entry(sdp, &local->pending_sdreqs, node) {
+                               if (sdp->tid != tlv[2])
+                                       continue;
+
+                               sdp->sap = tlv[3];
+
+                               pr_debug("Found: uri=%s, sap=%d\n",
+                                        sdp->uri, sdp->sap);
+
+                               hlist_del(&sdp->node);
+
+                               hlist_add_head(&sdp->node, &nl_sdres_list);
+
+                               break;
+                       }
+
+                       mutex_unlock(&local->sdreq_lock);
                        break;
 
                default:
@@ -1270,6 +1348,13 @@ send_snl:
                offset += length + 2;
                tlv += length + 2;
        }
+
+exit:
+       if (!hlist_empty(&nl_sdres_list))
+               nfc_genl_llc_send_sdres(local->dev, &nl_sdres_list);
+
+       if (!hlist_empty(&llc_sdres_list))
+               nfc_llcp_send_snl_sdres(local, &llc_sdres_list, sdres_tlvs_len);
 }
 
 static void nfc_llcp_rx_work(struct work_struct *work)
@@ -1455,6 +1540,13 @@ int nfc_llcp_register_device(struct nfc_dev *ndev)
        local->remote_miu = LLCP_DEFAULT_MIU;
        local->remote_lto = LLCP_DEFAULT_LTO;
 
+       mutex_init(&local->sdreq_lock);
+       INIT_HLIST_HEAD(&local->pending_sdreqs);
+       init_timer(&local->sdreq_timer);
+       local->sdreq_timer.data = (unsigned long) local;
+       local->sdreq_timer.function = nfc_llcp_sdreq_timer;
+       INIT_WORK(&local->sdreq_timeout_work, nfc_llcp_sdreq_timeout_work);
+
        list_add(&local->list, &llcp_devices);
 
        return 0;
index 0eae5c5..7e87a66 100644 (file)
@@ -46,6 +46,19 @@ struct llcp_sock_list {
        rwlock_t          lock;
 };
 
+struct nfc_llcp_sdp_tlv {
+       u8 *tlv;
+       u8 tlv_len;
+
+       char *uri;
+       u8 tid;
+       u8 sap;
+
+       unsigned long time;
+
+       struct hlist_node node;
+};
+
 struct nfc_llcp_local {
        struct list_head list;
        struct nfc_dev *dev;
@@ -86,6 +99,12 @@ struct nfc_llcp_local {
        u8  remote_opt;
        u16 remote_wks;
 
+       struct mutex sdreq_lock;
+       struct hlist_head pending_sdreqs;
+       struct timer_list sdreq_timer;
+       struct work_struct sdreq_timeout_work;
+       u8 sdreq_next_tid;
+
        /* sockets array */
        struct llcp_sock_list sockets;
        struct llcp_sock_list connecting_sockets;
@@ -105,7 +124,12 @@ struct nfc_llcp_sock {
        char *service_name;
        size_t service_name_len;
        u8 rw;
-       u16 miu;
+       u16 miux;
+
+
+       /* Remote link parameters */
+       u8 remote_rw;
+       u16 remote_miu;
 
        /* Link variables */
        u8 send_n;
@@ -213,12 +237,20 @@ int nfc_llcp_parse_connection_tlv(struct nfc_llcp_sock *sock,
 /* Commands API */
 void nfc_llcp_recv(void *data, struct sk_buff *skb, int err);
 u8 *nfc_llcp_build_tlv(u8 type, u8 *value, u8 value_length, u8 *tlv_length);
+struct nfc_llcp_sdp_tlv *nfc_llcp_build_sdres_tlv(u8 tid, u8 sap);
+struct nfc_llcp_sdp_tlv *nfc_llcp_build_sdreq_tlv(u8 tid, char *uri,
+                                                 size_t uri_len);
+void nfc_llcp_free_sdp_tlv(struct nfc_llcp_sdp_tlv *sdp);
+void nfc_llcp_free_sdp_tlv_list(struct hlist_head *sdp_head);
 void nfc_llcp_recv(void *data, struct sk_buff *skb, int err);
 int nfc_llcp_disconnect(struct nfc_llcp_sock *sock);
 int nfc_llcp_send_symm(struct nfc_dev *dev);
 int nfc_llcp_send_connect(struct nfc_llcp_sock *sock);
 int nfc_llcp_send_cc(struct nfc_llcp_sock *sock);
-int nfc_llcp_send_snl(struct nfc_llcp_local *local, u8 tid, u8 sap);
+int nfc_llcp_send_snl_sdres(struct nfc_llcp_local *local,
+                           struct hlist_head *tlv_list, size_t tlvs_len);
+int nfc_llcp_send_snl_sdreq(struct nfc_llcp_local *local,
+                           struct hlist_head *tlv_list, size_t tlvs_len);
 int nfc_llcp_send_dm(struct nfc_llcp_local *local, u8 ssap, u8 dsap, u8 reason);
 int nfc_llcp_send_disconnect(struct nfc_llcp_sock *sock);
 int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock,
index 5c7cdf3..f1b377e 100644 (file)
@@ -223,6 +223,124 @@ error:
        return ret;
 }
 
+static int nfc_llcp_setsockopt(struct socket *sock, int level, int optname,
+                              char __user *optval, unsigned int optlen)
+{
+       struct sock *sk = sock->sk;
+       struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk);
+       u32 opt;
+       int err = 0;
+
+       pr_debug("%p optname %d\n", sk, optname);
+
+       if (level != SOL_NFC)
+               return -ENOPROTOOPT;
+
+       lock_sock(sk);
+
+       switch (optname) {
+       case NFC_LLCP_RW:
+               if (sk->sk_state == LLCP_CONNECTED ||
+                   sk->sk_state == LLCP_BOUND ||
+                   sk->sk_state == LLCP_LISTEN) {
+                       err = -EINVAL;
+                       break;
+               }
+
+               if (get_user(opt, (u32 __user *) optval)) {
+                       err = -EFAULT;
+                       break;
+               }
+
+               if (opt > LLCP_MAX_RW) {
+                       err = -EINVAL;
+                       break;
+               }
+
+               llcp_sock->rw = (u8) opt;
+
+               break;
+
+       case NFC_LLCP_MIUX:
+               if (sk->sk_state == LLCP_CONNECTED ||
+                   sk->sk_state == LLCP_BOUND ||
+                   sk->sk_state == LLCP_LISTEN) {
+                       err = -EINVAL;
+                       break;
+               }
+
+               if (get_user(opt, (u32 __user *) optval)) {
+                       err = -EFAULT;
+                       break;
+               }
+
+               if (opt > LLCP_MAX_MIUX) {
+                       err = -EINVAL;
+                       break;
+               }
+
+               llcp_sock->miux = (u16) opt;
+
+               break;
+
+       default:
+               err = -ENOPROTOOPT;
+               break;
+       }
+
+       release_sock(sk);
+
+       pr_debug("%p rw %d miux %d\n", llcp_sock,
+                llcp_sock->rw, llcp_sock->miux);
+
+       return err;
+}
+
+static int nfc_llcp_getsockopt(struct socket *sock, int level, int optname,
+                              char __user *optval, int __user *optlen)
+{
+       struct sock *sk = sock->sk;
+       struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk);
+       int len, err = 0;
+
+       pr_debug("%p optname %d\n", sk, optname);
+
+       if (level != SOL_NFC)
+               return -ENOPROTOOPT;
+
+       if (get_user(len, optlen))
+               return -EFAULT;
+
+       len = min_t(u32, len, sizeof(u32));
+
+       lock_sock(sk);
+
+       switch (optname) {
+       case NFC_LLCP_RW:
+               if (put_user(llcp_sock->rw, (u32 __user *) optval))
+                       err = -EFAULT;
+
+               break;
+
+       case NFC_LLCP_MIUX:
+               if (put_user(llcp_sock->miux, (u32 __user *) optval))
+                       err = -EFAULT;
+
+               break;
+
+       default:
+               err = -ENOPROTOOPT;
+               break;
+       }
+
+       release_sock(sk);
+
+       if (put_user(len, optlen))
+               return -EFAULT;
+
+       return err;
+}
+
 void nfc_llcp_accept_unlink(struct sock *sk)
 {
        struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk);
@@ -543,7 +661,7 @@ static int llcp_sock_connect(struct socket *sock, struct sockaddr *_addr,
 
        llcp_sock->dev = dev;
        llcp_sock->local = nfc_llcp_local_get(local);
-       llcp_sock->miu = llcp_sock->local->remote_miu;
+       llcp_sock->remote_miu = llcp_sock->local->remote_miu;
        llcp_sock->ssap = nfc_llcp_get_local_ssap(local);
        if (llcp_sock->ssap == LLCP_SAP_MAX) {
                ret = -ENOMEM;
@@ -737,8 +855,8 @@ static const struct proto_ops llcp_sock_ops = {
        .ioctl          = sock_no_ioctl,
        .listen         = llcp_sock_listen,
        .shutdown       = sock_no_shutdown,
-       .setsockopt     = sock_no_setsockopt,
-       .getsockopt     = sock_no_getsockopt,
+       .setsockopt     = nfc_llcp_setsockopt,
+       .getsockopt     = nfc_llcp_getsockopt,
        .sendmsg        = llcp_sock_sendmsg,
        .recvmsg        = llcp_sock_recvmsg,
        .mmap           = sock_no_mmap,
@@ -802,8 +920,10 @@ struct sock *nfc_llcp_sock_alloc(struct socket *sock, int type, gfp_t gfp)
 
        llcp_sock->ssap = 0;
        llcp_sock->dsap = LLCP_SAP_SDP;
-       llcp_sock->rw = LLCP_DEFAULT_RW;
-       llcp_sock->miu = LLCP_DEFAULT_MIU;
+       llcp_sock->rw = LLCP_MAX_RW + 1;
+       llcp_sock->miux = LLCP_MAX_MIUX + 1;
+       llcp_sock->remote_rw = LLCP_DEFAULT_RW;
+       llcp_sock->remote_miu = LLCP_DEFAULT_MIU;
        llcp_sock->send_n = llcp_sock->send_ack_n = 0;
        llcp_sock->recv_n = llcp_sock->recv_ack_n = 0;
        llcp_sock->remote_ready = 1;
index 504b883..73fd510 100644 (file)
@@ -53,6 +53,15 @@ static const struct nla_policy nfc_genl_policy[NFC_ATTR_MAX + 1] = {
        [NFC_ATTR_DEVICE_POWERED] = { .type = NLA_U8 },
        [NFC_ATTR_IM_PROTOCOLS] = { .type = NLA_U32 },
        [NFC_ATTR_TM_PROTOCOLS] = { .type = NLA_U32 },
+       [NFC_ATTR_LLC_PARAM_LTO] = { .type = NLA_U8 },
+       [NFC_ATTR_LLC_PARAM_RW] = { .type = NLA_U8 },
+       [NFC_ATTR_LLC_PARAM_MIUX] = { .type = NLA_U16 },
+       [NFC_ATTR_LLC_SDP] = { .type = NLA_NESTED },
+};
+
+static const struct nla_policy nfc_sdp_genl_policy[NFC_SDP_ATTR_MAX + 1] = {
+       [NFC_SDP_ATTR_URI] = { .type = NLA_STRING },
+       [NFC_SDP_ATTR_SAP] = { .type = NLA_U8 },
 };
 
 static int nfc_genl_send_target(struct sk_buff *msg, struct nfc_target *target,
@@ -348,6 +357,74 @@ free_msg:
        return -EMSGSIZE;
 }
 
+int nfc_genl_llc_send_sdres(struct nfc_dev *dev, struct hlist_head *sdres_list)
+{
+       struct sk_buff *msg;
+       struct nlattr *sdp_attr, *uri_attr;
+       struct nfc_llcp_sdp_tlv *sdres;
+       struct hlist_node *n;
+       void *hdr;
+       int rc = -EMSGSIZE;
+       int i;
+
+       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+       if (!msg)
+               return -ENOMEM;
+
+       hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
+                         NFC_EVENT_LLC_SDRES);
+       if (!hdr)
+               goto free_msg;
+
+       if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx))
+               goto nla_put_failure;
+
+       sdp_attr = nla_nest_start(msg, NFC_ATTR_LLC_SDP);
+       if (sdp_attr == NULL) {
+               rc = -ENOMEM;
+               goto nla_put_failure;
+       }
+
+       i = 1;
+       hlist_for_each_entry_safe(sdres, n, sdres_list, node) {
+               pr_debug("uri: %s, sap: %d\n", sdres->uri, sdres->sap);
+
+               uri_attr = nla_nest_start(msg, i++);
+               if (uri_attr == NULL) {
+                       rc = -ENOMEM;
+                       goto nla_put_failure;
+               }
+
+               if (nla_put_u8(msg, NFC_SDP_ATTR_SAP, sdres->sap))
+                       goto nla_put_failure;
+
+               if (nla_put_string(msg, NFC_SDP_ATTR_URI, sdres->uri))
+                       goto nla_put_failure;
+
+               nla_nest_end(msg, uri_attr);
+
+               hlist_del(&sdres->node);
+
+               nfc_llcp_free_sdp_tlv(sdres);
+       }
+
+       nla_nest_end(msg, sdp_attr);
+
+       genlmsg_end(msg, hdr);
+
+       return genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_ATOMIC);
+
+nla_put_failure:
+       genlmsg_cancel(msg, hdr);
+
+free_msg:
+       nlmsg_free(msg);
+
+       nfc_llcp_free_sdp_tlv_list(sdres_list);
+
+       return rc;
+}
+
 static int nfc_genl_send_device(struct sk_buff *msg, struct nfc_dev *dev,
                                u32 portid, u32 seq,
                                struct netlink_callback *cb,
@@ -859,6 +936,96 @@ exit:
        return rc;
 }
 
+static int nfc_genl_llc_sdreq(struct sk_buff *skb, struct genl_info *info)
+{
+       struct nfc_dev *dev;
+       struct nfc_llcp_local *local;
+       struct nlattr *attr, *sdp_attrs[NFC_SDP_ATTR_MAX+1];
+       u32 idx;
+       u8 tid;
+       char *uri;
+       int rc = 0, rem;
+       size_t uri_len, tlvs_len;
+       struct hlist_head sdreq_list;
+       struct nfc_llcp_sdp_tlv *sdreq;
+
+       if (!info->attrs[NFC_ATTR_DEVICE_INDEX] ||
+           !info->attrs[NFC_ATTR_LLC_SDP])
+               return -EINVAL;
+
+       idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
+
+       dev = nfc_get_device(idx);
+       if (!dev) {
+               rc = -ENODEV;
+               goto exit;
+       }
+
+       device_lock(&dev->dev);
+
+       if (dev->dep_link_up == false) {
+               rc = -ENOLINK;
+               goto exit;
+       }
+
+       local = nfc_llcp_find_local(dev);
+       if (!local) {
+               nfc_put_device(dev);
+               rc = -ENODEV;
+               goto exit;
+       }
+
+       INIT_HLIST_HEAD(&sdreq_list);
+
+       tlvs_len = 0;
+
+       nla_for_each_nested(attr, info->attrs[NFC_ATTR_LLC_SDP], rem) {
+               rc = nla_parse_nested(sdp_attrs, NFC_SDP_ATTR_MAX, attr,
+                                     nfc_sdp_genl_policy);
+
+               if (rc != 0) {
+                       rc = -EINVAL;
+                       goto exit;
+               }
+
+               if (!sdp_attrs[NFC_SDP_ATTR_URI])
+                       continue;
+
+               uri_len = nla_len(sdp_attrs[NFC_SDP_ATTR_URI]);
+               if (uri_len == 0)
+                       continue;
+
+               uri = nla_data(sdp_attrs[NFC_SDP_ATTR_URI]);
+               if (uri == NULL || *uri == 0)
+                       continue;
+
+               tid = local->sdreq_next_tid++;
+
+               sdreq = nfc_llcp_build_sdreq_tlv(tid, uri, uri_len);
+               if (sdreq == NULL) {
+                       rc = -ENOMEM;
+                       goto exit;
+               }
+
+               tlvs_len += sdreq->tlv_len;
+
+               hlist_add_head(&sdreq->node, &sdreq_list);
+       }
+
+       if (hlist_empty(&sdreq_list)) {
+               rc = -EINVAL;
+               goto exit;
+       }
+
+       rc = nfc_llcp_send_snl_sdreq(local, &sdreq_list, tlvs_len);
+exit:
+       device_unlock(&dev->dev);
+
+       nfc_put_device(dev);
+
+       return rc;
+}
+
 static struct genl_ops nfc_genl_ops[] = {
        {
                .cmd = NFC_CMD_GET_DEVICE,
@@ -913,6 +1080,11 @@ static struct genl_ops nfc_genl_ops[] = {
                .doit = nfc_genl_llc_set_params,
                .policy = nfc_genl_policy,
        },
+       {
+               .cmd = NFC_CMD_LLC_SDREQ,
+               .doit = nfc_genl_llc_sdreq,
+               .policy = nfc_genl_policy,
+       },
 };
 
 
index 87d914d..94bfe19 100644 (file)
@@ -46,6 +46,8 @@ struct nfc_rawsock {
 #define to_rawsock_sk(_tx_work) \
        ((struct sock *) container_of(_tx_work, struct nfc_rawsock, tx_work))
 
+struct nfc_llcp_sdp_tlv;
+
 #ifdef CONFIG_NFC_LLCP
 
 void nfc_llcp_mac_is_down(struct nfc_dev *dev);
@@ -59,6 +61,8 @@ int nfc_llcp_data_received(struct nfc_dev *dev, struct sk_buff *skb);
 struct nfc_llcp_local *nfc_llcp_find_local(struct nfc_dev *dev);
 int __init nfc_llcp_init(void);
 void nfc_llcp_exit(void);
+void nfc_llcp_free_sdp_tlv(struct nfc_llcp_sdp_tlv *sdp);
+void nfc_llcp_free_sdp_tlv_list(struct hlist_head *head);
 
 #else
 
@@ -112,6 +116,14 @@ static inline void nfc_llcp_exit(void)
 {
 }
 
+static inline void nfc_llcp_free_sdp_tlv(struct nfc_llcp_sdp_tlv *sdp)
+{
+}
+
+static inline void nfc_llcp_free_sdp_tlv_list(struct hlist_head *sdp_head)
+{
+}
+
 #endif
 
 int __init rawsock_init(void);
@@ -144,6 +156,8 @@ int nfc_genl_dep_link_down_event(struct nfc_dev *dev);
 int nfc_genl_tm_activated(struct nfc_dev *dev, u32 protocol);
 int nfc_genl_tm_deactivated(struct nfc_dev *dev);
 
+int nfc_genl_llc_send_sdres(struct nfc_dev *dev, struct hlist_head *sdres_list);
+
 struct nfc_dev *nfc_get_device(unsigned int idx);
 
 static inline void nfc_put_device(struct nfc_dev *dev)
index 4b5ab21..d11ac79 100644 (file)
@@ -51,7 +51,7 @@ static int rfkill_regulator_set_block(void *data, bool blocked)
        return 0;
 }
 
-struct rfkill_ops rfkill_regulator_ops = {
+static struct rfkill_ops rfkill_regulator_ops = {
        .set_block = rfkill_regulator_set_block,
 };
 
index a4a14e8..324e8d8 100644 (file)
@@ -46,65 +46,3 @@ int cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
 
        return err;
 }
-
-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);
-
-       trace_cfg80211_ch_switch_notify(dev, chandef);
-
-       wdev_lock(wdev);
-
-       if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
-                   wdev->iftype != NL80211_IFTYPE_P2P_GO))
-               goto out;
-
-       wdev->channel = chandef->chan;
-       nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL);
-out:
-       wdev_unlock(wdev);
-       return;
-}
-EXPORT_SYMBOL(cfg80211_ch_switch_notify);
-
-bool cfg80211_rx_spurious_frame(struct net_device *dev,
-                               const u8 *addr, gfp_t gfp)
-{
-       struct wireless_dev *wdev = dev->ieee80211_ptr;
-       bool ret;
-
-       trace_cfg80211_rx_spurious_frame(dev, addr);
-
-       if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
-                   wdev->iftype != NL80211_IFTYPE_P2P_GO)) {
-               trace_cfg80211_return_bool(false);
-               return false;
-       }
-       ret = nl80211_unexpected_frame(dev, addr, gfp);
-       trace_cfg80211_return_bool(ret);
-       return ret;
-}
-EXPORT_SYMBOL(cfg80211_rx_spurious_frame);
-
-bool cfg80211_rx_unexpected_4addr_frame(struct net_device *dev,
-                                       const u8 *addr, gfp_t gfp)
-{
-       struct wireless_dev *wdev = dev->ieee80211_ptr;
-       bool ret;
-
-       trace_cfg80211_rx_unexpected_4addr_frame(dev, addr);
-
-       if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
-                   wdev->iftype != NL80211_IFTYPE_P2P_GO &&
-                   wdev->iftype != NL80211_IFTYPE_AP_VLAN)) {
-               trace_cfg80211_return_bool(false);
-               return false;
-       }
-       ret = nl80211_unexpected_4addr_frame(dev, addr, gfp);
-       trace_cfg80211_return_bool(ret);
-       return ret;
-}
-EXPORT_SYMBOL(cfg80211_rx_unexpected_4addr_frame);
index ea4155f..f382cae 100644 (file)
@@ -814,6 +814,46 @@ void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev,
                rdev->num_running_monitor_ifaces += num;
 }
 
+void cfg80211_leave(struct cfg80211_registered_device *rdev,
+                  struct wireless_dev *wdev)
+{
+       struct net_device *dev = wdev->netdev;
+
+       switch (wdev->iftype) {
+       case NL80211_IFTYPE_ADHOC:
+               cfg80211_leave_ibss(rdev, dev, true);
+               break;
+       case NL80211_IFTYPE_P2P_CLIENT:
+       case NL80211_IFTYPE_STATION:
+               mutex_lock(&rdev->sched_scan_mtx);
+               __cfg80211_stop_sched_scan(rdev, false);
+               mutex_unlock(&rdev->sched_scan_mtx);
+
+               wdev_lock(wdev);
+#ifdef CONFIG_CFG80211_WEXT
+               kfree(wdev->wext.ie);
+               wdev->wext.ie = NULL;
+               wdev->wext.ie_len = 0;
+               wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
+#endif
+               __cfg80211_disconnect(rdev, dev,
+                                     WLAN_REASON_DEAUTH_LEAVING, true);
+               cfg80211_mlme_down(rdev, dev);
+               wdev_unlock(wdev);
+               break;
+       case NL80211_IFTYPE_MESH_POINT:
+               cfg80211_leave_mesh(rdev, dev);
+               break;
+       case NL80211_IFTYPE_AP:
+               cfg80211_stop_ap(rdev, dev);
+               break;
+       default:
+               break;
+       }
+
+       wdev->beacon_interval = 0;
+}
+
 static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
                                         unsigned long state,
                                         void *ndev)
@@ -882,38 +922,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
                        dev->priv_flags |= IFF_DONT_BRIDGE;
                break;
        case NETDEV_GOING_DOWN:
-               switch (wdev->iftype) {
-               case NL80211_IFTYPE_ADHOC:
-                       cfg80211_leave_ibss(rdev, dev, true);
-                       break;
-               case NL80211_IFTYPE_P2P_CLIENT:
-               case NL80211_IFTYPE_STATION:
-                       mutex_lock(&rdev->sched_scan_mtx);
-                       __cfg80211_stop_sched_scan(rdev, false);
-                       mutex_unlock(&rdev->sched_scan_mtx);
-
-                       wdev_lock(wdev);
-#ifdef CONFIG_CFG80211_WEXT
-                       kfree(wdev->wext.ie);
-                       wdev->wext.ie = NULL;
-                       wdev->wext.ie_len = 0;
-                       wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
-#endif
-                       __cfg80211_disconnect(rdev, dev,
-                                             WLAN_REASON_DEAUTH_LEAVING, true);
-                       cfg80211_mlme_down(rdev, dev);
-                       wdev_unlock(wdev);
-                       break;
-               case NL80211_IFTYPE_MESH_POINT:
-                       cfg80211_leave_mesh(rdev, dev);
-                       break;
-               case NL80211_IFTYPE_AP:
-                       cfg80211_stop_ap(rdev, dev);
-                       break;
-               default:
-                       break;
-               }
-               wdev->beacon_interval = 0;
+               cfg80211_leave(rdev, wdev);
                break;
        case NETDEV_DOWN:
                cfg80211_update_iface_num(rdev, wdev->iftype, -1);
index 3aec0e4..d5d06fd 100644 (file)
@@ -330,20 +330,15 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
 int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
                          struct net_device *dev,
                          struct ieee80211_channel *chan,
-                         const u8 *bssid, const u8 *prev_bssid,
+                         const u8 *bssid,
                          const u8 *ssid, int ssid_len,
-                         const u8 *ie, int ie_len, bool use_mfp,
-                         struct cfg80211_crypto_settings *crypt,
-                         u32 assoc_flags, struct ieee80211_ht_cap *ht_capa,
-                         struct ieee80211_ht_cap *ht_capa_mask);
+                         struct cfg80211_assoc_request *req);
 int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
-                       struct net_device *dev, struct ieee80211_channel *chan,
-                       const u8 *bssid, const u8 *prev_bssid,
+                       struct net_device *dev,
+                       struct ieee80211_channel *chan,
+                       const u8 *bssid,
                        const u8 *ssid, int ssid_len,
-                       const u8 *ie, int ie_len, bool use_mfp,
-                       struct cfg80211_crypto_settings *crypt,
-                       u32 assoc_flags, struct ieee80211_ht_cap *ht_capa,
-                       struct ieee80211_ht_cap *ht_capa_mask);
+                       struct cfg80211_assoc_request *req);
 int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
                           struct net_device *dev, const u8 *bssid,
                           const u8 *ie, int ie_len, u16 reason,
@@ -375,6 +370,8 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
                          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);
+void cfg80211_oper_and_vht_capa(struct ieee80211_vht_cap *vht_capa,
+                               const struct ieee80211_vht_cap *vht_capa_mask);
 
 /* SME */
 int __cfg80211_connect(struct cfg80211_registered_device *rdev,
@@ -503,6 +500,9 @@ 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);
 
+void cfg80211_leave(struct cfg80211_registered_device *rdev,
+                   struct wireless_dev *wdev);
+
 #define CFG80211_MAX_NUM_DIFFERENT_CHANNELS 10
 
 #ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS
index 55957a2..0bb93f3 100644 (file)
@@ -85,6 +85,7 @@ const struct mesh_setup default_mesh_setup = {
        .ie = NULL,
        .ie_len = 0,
        .is_secure = false,
+       .user_mpm = false,
        .beacon_interval = MESH_DEFAULT_BEACON_INTERVAL,
        .dtim_period = MESH_DEFAULT_DTIM_PERIOD,
 };
@@ -233,20 +234,6 @@ int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev,
        return 0;
 }
 
-void cfg80211_notify_new_peer_candidate(struct net_device *dev,
-               const u8 *macaddr, const u8* ie, u8 ie_len, gfp_t gfp)
-{
-       struct wireless_dev *wdev = dev->ieee80211_ptr;
-
-       trace_cfg80211_notify_new_peer_candidate(dev, macaddr);
-       if (WARN_ON(wdev->iftype != NL80211_IFTYPE_MESH_POINT))
-               return;
-
-       nl80211_send_new_peer_candidate(wiphy_to_dev(wdev->wiphy), dev,
-                       macaddr, ie, ie_len, gfp);
-}
-EXPORT_SYMBOL(cfg80211_notify_new_peer_candidate);
-
 static int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev,
                                 struct net_device *dev)
 {
index caddca3..390198b 100644 (file)
@@ -187,30 +187,6 @@ void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len)
 }
 EXPORT_SYMBOL(cfg80211_send_disassoc);
 
-void cfg80211_send_unprot_deauth(struct net_device *dev, const u8 *buf,
-                                size_t len)
-{
-       struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct wiphy *wiphy = wdev->wiphy;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
-
-       trace_cfg80211_send_unprot_deauth(dev);
-       nl80211_send_unprot_deauth(rdev, dev, buf, len, GFP_ATOMIC);
-}
-EXPORT_SYMBOL(cfg80211_send_unprot_deauth);
-
-void cfg80211_send_unprot_disassoc(struct net_device *dev, const u8 *buf,
-                                  size_t len)
-{
-       struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct wiphy *wiphy = wdev->wiphy;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
-
-       trace_cfg80211_send_unprot_disassoc(dev);
-       nl80211_send_unprot_disassoc(rdev, dev, buf, len, GFP_ATOMIC);
-}
-EXPORT_SYMBOL(cfg80211_send_unprot_disassoc);
-
 void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
@@ -367,27 +343,38 @@ void cfg80211_oper_and_ht_capa(struct ieee80211_ht_cap *ht_capa,
                p1[i] &= p2[i];
 }
 
+/*  Do a logical ht_capa &= ht_capa_mask.  */
+void cfg80211_oper_and_vht_capa(struct ieee80211_vht_cap *vht_capa,
+                               const struct ieee80211_vht_cap *vht_capa_mask)
+{
+       int i;
+       u8 *p1, *p2;
+       if (!vht_capa_mask) {
+               memset(vht_capa, 0, sizeof(*vht_capa));
+               return;
+       }
+
+       p1 = (u8*)(vht_capa);
+       p2 = (u8*)(vht_capa_mask);
+       for (i = 0; i < sizeof(*vht_capa); i++)
+               p1[i] &= p2[i];
+}
+
 int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
                          struct net_device *dev,
                          struct ieee80211_channel *chan,
-                         const u8 *bssid, const u8 *prev_bssid,
+                         const u8 *bssid,
                          const u8 *ssid, int ssid_len,
-                         const u8 *ie, int ie_len, bool use_mfp,
-                         struct cfg80211_crypto_settings *crypt,
-                         u32 assoc_flags, struct ieee80211_ht_cap *ht_capa,
-                         struct ieee80211_ht_cap *ht_capa_mask)
+                         struct cfg80211_assoc_request *req)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct cfg80211_assoc_request req;
        int err;
        bool was_connected = false;
 
        ASSERT_WDEV_LOCK(wdev);
 
-       memset(&req, 0, sizeof(req));
-
-       if (wdev->current_bss && prev_bssid &&
-           ether_addr_equal(wdev->current_bss->pub.bssid, prev_bssid)) {
+       if (wdev->current_bss && req->prev_bssid &&
+           ether_addr_equal(wdev->current_bss->pub.bssid, req->prev_bssid)) {
                /*
                 * Trying to reassociate: Allow this to proceed and let the old
                 * association to be dropped when the new one is completed.
@@ -399,40 +386,30 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
        } else if (wdev->current_bss)
                return -EALREADY;
 
-       req.ie = ie;
-       req.ie_len = ie_len;
-       memcpy(&req.crypto, crypt, sizeof(req.crypto));
-       req.use_mfp = use_mfp;
-       req.prev_bssid = prev_bssid;
-       req.flags = assoc_flags;
-       if (ht_capa)
-               memcpy(&req.ht_capa, ht_capa, sizeof(req.ht_capa));
-       if (ht_capa_mask)
-               memcpy(&req.ht_capa_mask, ht_capa_mask,
-                      sizeof(req.ht_capa_mask));
-       cfg80211_oper_and_ht_capa(&req.ht_capa_mask,
+       cfg80211_oper_and_ht_capa(&req->ht_capa_mask,
                                  rdev->wiphy.ht_capa_mod_mask);
+       cfg80211_oper_and_vht_capa(&req->vht_capa_mask,
+                                  rdev->wiphy.vht_capa_mod_mask);
 
-       req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
-                                  WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
-       if (!req.bss) {
+       req->bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
+                                   WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
+       if (!req->bss) {
                if (was_connected)
                        wdev->sme_state = CFG80211_SME_CONNECTED;
                return -ENOENT;
        }
 
-       err = cfg80211_can_use_chan(rdev, wdev, req.bss->channel,
-                                   CHAN_MODE_SHARED);
+       err = cfg80211_can_use_chan(rdev, wdev, chan, CHAN_MODE_SHARED);
        if (err)
                goto out;
 
-       err = rdev_assoc(rdev, dev, &req);
+       err = rdev_assoc(rdev, dev, req);
 
 out:
        if (err) {
                if (was_connected)
                        wdev->sme_state = CFG80211_SME_CONNECTED;
-               cfg80211_put_bss(&rdev->wiphy, req.bss);
+               cfg80211_put_bss(&rdev->wiphy, req->bss);
        }
 
        return err;
@@ -441,21 +418,17 @@ out:
 int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
                        struct net_device *dev,
                        struct ieee80211_channel *chan,
-                       const u8 *bssid, const u8 *prev_bssid,
+                       const u8 *bssid,
                        const u8 *ssid, int ssid_len,
-                       const u8 *ie, int ie_len, bool use_mfp,
-                       struct cfg80211_crypto_settings *crypt,
-                       u32 assoc_flags, struct ieee80211_ht_cap *ht_capa,
-                       struct ieee80211_ht_cap *ht_capa_mask)
+                       struct cfg80211_assoc_request *req)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        int err;
 
        mutex_lock(&rdev->devlist_mtx);
        wdev_lock(wdev);
-       err = __cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid,
-                                   ssid, ssid_len, ie, ie_len, use_mfp, crypt,
-                                   assoc_flags, ht_capa, ht_capa_mask);
+       err = __cfg80211_mlme_assoc(rdev, dev, chan, bssid,
+                                   ssid, ssid_len, req);
        wdev_unlock(wdev);
        mutex_unlock(&rdev->devlist_mtx);
 
@@ -577,62 +550,6 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
        }
 }
 
-void cfg80211_ready_on_channel(struct wireless_dev *wdev, u64 cookie,
-                              struct ieee80211_channel *chan,
-                              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, 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,
-                                       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);
-       nl80211_send_remain_on_channel_cancel(rdev, wdev, cookie, chan, gfp);
-}
-EXPORT_SYMBOL(cfg80211_remain_on_channel_expired);
-
-void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr,
-                     struct station_info *sinfo, gfp_t gfp)
-{
-       struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
-
-       trace_cfg80211_new_sta(dev, mac_addr, sinfo);
-       nl80211_send_sta_event(rdev, dev, mac_addr, sinfo, gfp);
-}
-EXPORT_SYMBOL(cfg80211_new_sta);
-
-void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp)
-{
-       struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
-
-       trace_cfg80211_del_sta(dev, mac_addr);
-       nl80211_send_sta_del_event(rdev, dev, mac_addr, gfp);
-}
-EXPORT_SYMBOL(cfg80211_del_sta);
-
-void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr,
-                         enum nl80211_connect_failed_reason reason,
-                         gfp_t gfp)
-{
-       struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
-
-       nl80211_send_conn_failed_event(rdev, dev, mac_addr, reason, gfp);
-}
-EXPORT_SYMBOL(cfg80211_conn_failed);
-
 struct cfg80211_mgmt_registration {
        struct list_head list;
 
@@ -909,85 +826,6 @@ bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_mbm,
 }
 EXPORT_SYMBOL(cfg80211_rx_mgmt);
 
-void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie,
-                            const u8 *buf, size_t len, bool ack, gfp_t gfp)
-{
-       struct wiphy *wiphy = wdev->wiphy;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
-
-       trace_cfg80211_mgmt_tx_status(wdev, cookie, ack);
-
-       /* Indicate TX status of the Action frame to user space */
-       nl80211_send_mgmt_tx_status(rdev, wdev, cookie, buf, len, ack, gfp);
-}
-EXPORT_SYMBOL(cfg80211_mgmt_tx_status);
-
-void cfg80211_cqm_rssi_notify(struct net_device *dev,
-                             enum nl80211_cqm_rssi_threshold_event rssi_event,
-                             gfp_t gfp)
-{
-       struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct wiphy *wiphy = wdev->wiphy;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
-
-       trace_cfg80211_cqm_rssi_notify(dev, rssi_event);
-
-       /* Indicate roaming trigger event to user space */
-       nl80211_send_cqm_rssi_notify(rdev, dev, rssi_event, gfp);
-}
-EXPORT_SYMBOL(cfg80211_cqm_rssi_notify);
-
-void cfg80211_cqm_pktloss_notify(struct net_device *dev,
-                                const u8 *peer, u32 num_packets, gfp_t gfp)
-{
-       struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct wiphy *wiphy = wdev->wiphy;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
-
-       trace_cfg80211_cqm_pktloss_notify(dev, peer, num_packets);
-
-       /* Indicate roaming trigger event to user space */
-       nl80211_send_cqm_pktloss_notify(rdev, dev, peer, num_packets, gfp);
-}
-EXPORT_SYMBOL(cfg80211_cqm_pktloss_notify);
-
-void cfg80211_cqm_txe_notify(struct net_device *dev,
-                            const u8 *peer, u32 num_packets,
-                            u32 rate, u32 intvl, gfp_t gfp)
-{
-       struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct wiphy *wiphy = wdev->wiphy;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
-
-       nl80211_send_cqm_txe_notify(rdev, dev, peer, num_packets,
-                                   rate, intvl, gfp);
-}
-EXPORT_SYMBOL(cfg80211_cqm_txe_notify);
-
-void cfg80211_gtk_rekey_notify(struct net_device *dev, const u8 *bssid,
-                              const u8 *replay_ctr, gfp_t gfp)
-{
-       struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct wiphy *wiphy = wdev->wiphy;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
-
-       trace_cfg80211_gtk_rekey_notify(dev, bssid);
-       nl80211_gtk_rekey_notify(rdev, dev, bssid, replay_ctr, gfp);
-}
-EXPORT_SYMBOL(cfg80211_gtk_rekey_notify);
-
-void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index,
-                                    const u8 *bssid, bool preauth, gfp_t gfp)
-{
-       struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct wiphy *wiphy = wdev->wiphy;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
-
-       trace_cfg80211_pmksa_candidate_notify(dev, index, bssid, preauth);
-       nl80211_pmksa_candidate_notify(rdev, dev, index, bssid, preauth, gfp);
-}
-EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify);
-
 void cfg80211_dfs_channels_update_work(struct work_struct *work)
 {
        struct delayed_work *delayed_work;
index d44ab21..f924d45 100644 (file)
@@ -370,6 +370,14 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
        [NL80211_ATTR_MAC_ADDRS] = { .type = NLA_NESTED },
        [NL80211_ATTR_STA_CAPABILITY] = { .type = NLA_U16 },
        [NL80211_ATTR_STA_EXT_CAPABILITY] = { .type = NLA_BINARY, },
+       [NL80211_ATTR_SPLIT_WIPHY_DUMP] = { .type = NLA_FLAG, },
+       [NL80211_ATTR_DISABLE_VHT] = { .type = NLA_FLAG },
+       [NL80211_ATTR_VHT_CAPABILITY_MASK] = {
+               .len = NL80211_VHT_CAPABILITY_LEN,
+       },
+       [NL80211_ATTR_MDID] = { .type = NLA_U16 },
+       [NL80211_ATTR_IE_RIC] = { .type = NLA_BINARY,
+                                 .len = IEEE80211_MAX_DATA_LEN },
 };
 
 /* policy for the key attributes */
@@ -539,7 +547,8 @@ static inline void *nl80211hdr_put(struct sk_buff *skb, u32 portid, u32 seq,
 }
 
 static int nl80211_msg_put_channel(struct sk_buff *msg,
-                                  struct ieee80211_channel *chan)
+                                  struct ieee80211_channel *chan,
+                                  bool large)
 {
        if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_FREQ,
                        chan->center_freq))
@@ -554,9 +563,37 @@ static int nl80211_msg_put_channel(struct sk_buff *msg,
        if ((chan->flags & IEEE80211_CHAN_NO_IBSS) &&
            nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_IBSS))
                goto nla_put_failure;
-       if ((chan->flags & IEEE80211_CHAN_RADAR) &&
-           nla_put_flag(msg, NL80211_FREQUENCY_ATTR_RADAR))
-               goto nla_put_failure;
+       if (chan->flags & IEEE80211_CHAN_RADAR) {
+               if (nla_put_flag(msg, NL80211_FREQUENCY_ATTR_RADAR))
+                       goto nla_put_failure;
+               if (large) {
+                       u32 time;
+
+                       time = elapsed_jiffies_msecs(chan->dfs_state_entered);
+
+                       if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_DFS_STATE,
+                                       chan->dfs_state))
+                               goto nla_put_failure;
+                       if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_DFS_TIME,
+                                       time))
+                               goto nla_put_failure;
+               }
+       }
+
+       if (large) {
+               if ((chan->flags & IEEE80211_CHAN_NO_HT40MINUS) &&
+                   nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_HT40_MINUS))
+                       goto nla_put_failure;
+               if ((chan->flags & IEEE80211_CHAN_NO_HT40PLUS) &&
+                   nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_HT40_PLUS))
+                       goto nla_put_failure;
+               if ((chan->flags & IEEE80211_CHAN_NO_80MHZ) &&
+                   nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_80MHZ))
+                       goto nla_put_failure;
+               if ((chan->flags & IEEE80211_CHAN_NO_160MHZ) &&
+                   nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_160MHZ))
+                       goto nla_put_failure;
+       }
 
        if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER,
                        DBM_TO_MBM(chan->max_power)))
@@ -832,7 +869,8 @@ nla_put_failure:
 }
 
 static int nl80211_put_iface_combinations(struct wiphy *wiphy,
-                                         struct sk_buff *msg)
+                                         struct sk_buff *msg,
+                                         bool large)
 {
        struct nlattr *nl_combis;
        int i, j;
@@ -881,6 +919,10 @@ static int nl80211_put_iface_combinations(struct wiphy *wiphy,
                    nla_put_u32(msg, NL80211_IFACE_COMB_MAXNUM,
                                c->max_interfaces))
                        goto nla_put_failure;
+               if (large &&
+                   nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS,
+                               c->radar_detect_widths))
+                       goto nla_put_failure;
 
                nla_nest_end(msg, nl_combi);
        }
@@ -892,412 +934,611 @@ nla_put_failure:
        return -ENOBUFS;
 }
 
-static int nl80211_send_wiphy(struct sk_buff *msg, u32 portid, u32 seq, int flags,
-                             struct cfg80211_registered_device *dev)
+#ifdef CONFIG_PM
+static int nl80211_send_wowlan_tcp_caps(struct cfg80211_registered_device *rdev,
+                                       struct sk_buff *msg)
 {
-       void *hdr;
-       struct nlattr *nl_bands, *nl_band;
-       struct nlattr *nl_freqs, *nl_freq;
-       struct nlattr *nl_rates, *nl_rate;
-       struct nlattr *nl_cmds;
-       enum ieee80211_band band;
-       struct ieee80211_channel *chan;
-       struct ieee80211_rate *rate;
-       int i;
-       const struct ieee80211_txrx_stypes *mgmt_stypes =
-                               dev->wiphy.mgmt_stypes;
+       const struct wiphy_wowlan_tcp_support *tcp = rdev->wiphy.wowlan.tcp;
+       struct nlattr *nl_tcp;
 
-       hdr = nl80211hdr_put(msg, portid, seq, flags, NL80211_CMD_NEW_WIPHY);
-       if (!hdr)
-               return -1;
+       if (!tcp)
+               return 0;
 
-       if (nla_put_u32(msg, NL80211_ATTR_WIPHY, dev->wiphy_idx) ||
-           nla_put_string(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy)) ||
-           nla_put_u32(msg, NL80211_ATTR_GENERATION,
-                       cfg80211_rdev_list_generation) ||
-           nla_put_u8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT,
-                      dev->wiphy.retry_short) ||
-           nla_put_u8(msg, NL80211_ATTR_WIPHY_RETRY_LONG,
-                      dev->wiphy.retry_long) ||
-           nla_put_u32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD,
-                       dev->wiphy.frag_threshold) ||
-           nla_put_u32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD,
-                       dev->wiphy.rts_threshold) ||
-           nla_put_u8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS,
-                      dev->wiphy.coverage_class) ||
-           nla_put_u8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS,
-                      dev->wiphy.max_scan_ssids) ||
-           nla_put_u8(msg, NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS,
-                      dev->wiphy.max_sched_scan_ssids) ||
-           nla_put_u16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN,
-                       dev->wiphy.max_scan_ie_len) ||
-           nla_put_u16(msg, NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN,
-                       dev->wiphy.max_sched_scan_ie_len) ||
-           nla_put_u8(msg, NL80211_ATTR_MAX_MATCH_SETS,
-                      dev->wiphy.max_match_sets))
-               goto nla_put_failure;
+       nl_tcp = nla_nest_start(msg, NL80211_WOWLAN_TRIG_TCP_CONNECTION);
+       if (!nl_tcp)
+               return -ENOBUFS;
 
-       if ((dev->wiphy.flags & WIPHY_FLAG_IBSS_RSN) &&
-           nla_put_flag(msg, NL80211_ATTR_SUPPORT_IBSS_RSN))
-               goto nla_put_failure;
-       if ((dev->wiphy.flags & WIPHY_FLAG_MESH_AUTH) &&
-           nla_put_flag(msg, NL80211_ATTR_SUPPORT_MESH_AUTH))
-               goto nla_put_failure;
-       if ((dev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) &&
-           nla_put_flag(msg, NL80211_ATTR_SUPPORT_AP_UAPSD))
-               goto nla_put_failure;
-       if ((dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_FW_ROAM) &&
-           nla_put_flag(msg, NL80211_ATTR_ROAM_SUPPORT))
-               goto nla_put_failure;
-       if ((dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) &&
-           nla_put_flag(msg, NL80211_ATTR_TDLS_SUPPORT))
-               goto nla_put_failure;
-       if ((dev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP) &&
-           nla_put_flag(msg, NL80211_ATTR_TDLS_EXTERNAL_SETUP))
-               goto nla_put_failure;
+       if (nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD,
+                       tcp->data_payload_max))
+               return -ENOBUFS;
 
-       if (nla_put(msg, NL80211_ATTR_CIPHER_SUITES,
-                   sizeof(u32) * dev->wiphy.n_cipher_suites,
-                   dev->wiphy.cipher_suites))
-               goto nla_put_failure;
+       if (nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD,
+                       tcp->data_payload_max))
+               return -ENOBUFS;
 
-       if (nla_put_u8(msg, NL80211_ATTR_MAX_NUM_PMKIDS,
-                      dev->wiphy.max_num_pmkids))
-               goto nla_put_failure;
+       if (tcp->seq && nla_put_flag(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ))
+               return -ENOBUFS;
 
-       if ((dev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL) &&
-           nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE))
-               goto nla_put_failure;
+       if (tcp->tok && nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN,
+                               sizeof(*tcp->tok), tcp->tok))
+               return -ENOBUFS;
 
-       if (nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX,
-                       dev->wiphy.available_antennas_tx) ||
-           nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX,
-                       dev->wiphy.available_antennas_rx))
-               goto nla_put_failure;
+       if (nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_INTERVAL,
+                       tcp->data_interval_max))
+               return -ENOBUFS;
 
-       if ((dev->wiphy.flags & WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD) &&
-           nla_put_u32(msg, NL80211_ATTR_PROBE_RESP_OFFLOAD,
-                       dev->wiphy.probe_resp_offload))
-               goto nla_put_failure;
+       if (nla_put_u32(msg, NL80211_WOWLAN_TCP_WAKE_PAYLOAD,
+                       tcp->wake_payload_max))
+               return -ENOBUFS;
 
-       if ((dev->wiphy.available_antennas_tx ||
-            dev->wiphy.available_antennas_rx) && dev->ops->get_antenna) {
-               u32 tx_ant = 0, rx_ant = 0;
-               int res;
-               res = rdev_get_antenna(dev, &tx_ant, &rx_ant);
-               if (!res) {
-                       if (nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_TX,
-                                       tx_ant) ||
-                           nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_RX,
-                                       rx_ant))
-                               goto nla_put_failure;
-               }
+       nla_nest_end(msg, nl_tcp);
+       return 0;
+}
+
+static int nl80211_send_wowlan(struct sk_buff *msg,
+                              struct cfg80211_registered_device *dev,
+                              bool large)
+{
+       struct nlattr *nl_wowlan;
+
+       if (!dev->wiphy.wowlan.flags && !dev->wiphy.wowlan.n_patterns)
+               return 0;
+
+       nl_wowlan = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED);
+       if (!nl_wowlan)
+               return -ENOBUFS;
+
+       if (((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_ANY) &&
+            nla_put_flag(msg, NL80211_WOWLAN_TRIG_ANY)) ||
+           ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_DISCONNECT) &&
+            nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT)) ||
+           ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_MAGIC_PKT) &&
+            nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT)) ||
+           ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY) &&
+            nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED)) ||
+           ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) &&
+            nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE)) ||
+           ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ) &&
+            nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST)) ||
+           ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_4WAY_HANDSHAKE) &&
+            nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE)) ||
+           ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_RFKILL_RELEASE) &&
+            nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE)))
+               return -ENOBUFS;
+
+       if (dev->wiphy.wowlan.n_patterns) {
+               struct nl80211_wowlan_pattern_support pat = {
+                       .max_patterns = dev->wiphy.wowlan.n_patterns,
+                       .min_pattern_len = dev->wiphy.wowlan.pattern_min_len,
+                       .max_pattern_len = dev->wiphy.wowlan.pattern_max_len,
+                       .max_pkt_offset = dev->wiphy.wowlan.max_pkt_offset,
+               };
+
+               if (nla_put(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN,
+                           sizeof(pat), &pat))
+                       return -ENOBUFS;
        }
 
-       if (nl80211_put_iftypes(msg, NL80211_ATTR_SUPPORTED_IFTYPES,
-                               dev->wiphy.interface_modes))
-               goto nla_put_failure;
+       if (large && nl80211_send_wowlan_tcp_caps(dev, msg))
+               return -ENOBUFS;
 
-       nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS);
-       if (!nl_bands)
-               goto nla_put_failure;
+       nla_nest_end(msg, nl_wowlan);
 
-       for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
-               if (!dev->wiphy.bands[band])
-                       continue;
+       return 0;
+}
+#endif
 
-               nl_band = nla_nest_start(msg, band);
-               if (!nl_band)
-                       goto nla_put_failure;
+static int nl80211_send_band_rateinfo(struct sk_buff *msg,
+                                     struct ieee80211_supported_band *sband)
+{
+       struct nlattr *nl_rates, *nl_rate;
+       struct ieee80211_rate *rate;
+       int i;
 
-               /* add HT info */
-               if (dev->wiphy.bands[band]->ht_cap.ht_supported &&
-                   (nla_put(msg, NL80211_BAND_ATTR_HT_MCS_SET,
-                            sizeof(dev->wiphy.bands[band]->ht_cap.mcs),
-                            &dev->wiphy.bands[band]->ht_cap.mcs) ||
-                    nla_put_u16(msg, NL80211_BAND_ATTR_HT_CAPA,
-                                dev->wiphy.bands[band]->ht_cap.cap) ||
-                    nla_put_u8(msg, NL80211_BAND_ATTR_HT_AMPDU_FACTOR,
-                               dev->wiphy.bands[band]->ht_cap.ampdu_factor) ||
-                    nla_put_u8(msg, NL80211_BAND_ATTR_HT_AMPDU_DENSITY,
-                               dev->wiphy.bands[band]->ht_cap.ampdu_density)))
-                       goto nla_put_failure;
+       /* add HT info */
+       if (sband->ht_cap.ht_supported &&
+           (nla_put(msg, NL80211_BAND_ATTR_HT_MCS_SET,
+                    sizeof(sband->ht_cap.mcs),
+                    &sband->ht_cap.mcs) ||
+            nla_put_u16(msg, NL80211_BAND_ATTR_HT_CAPA,
+                        sband->ht_cap.cap) ||
+            nla_put_u8(msg, NL80211_BAND_ATTR_HT_AMPDU_FACTOR,
+                       sband->ht_cap.ampdu_factor) ||
+            nla_put_u8(msg, NL80211_BAND_ATTR_HT_AMPDU_DENSITY,
+                       sband->ht_cap.ampdu_density)))
+               return -ENOBUFS;
 
-               /* add VHT info */
-               if (dev->wiphy.bands[band]->vht_cap.vht_supported &&
-                   (nla_put(msg, NL80211_BAND_ATTR_VHT_MCS_SET,
-                            sizeof(dev->wiphy.bands[band]->vht_cap.vht_mcs),
-                            &dev->wiphy.bands[band]->vht_cap.vht_mcs) ||
-                    nla_put_u32(msg, NL80211_BAND_ATTR_VHT_CAPA,
-                                dev->wiphy.bands[band]->vht_cap.cap)))
-                       goto nla_put_failure;
+       /* add VHT info */
+       if (sband->vht_cap.vht_supported &&
+           (nla_put(msg, NL80211_BAND_ATTR_VHT_MCS_SET,
+                    sizeof(sband->vht_cap.vht_mcs),
+                    &sband->vht_cap.vht_mcs) ||
+            nla_put_u32(msg, NL80211_BAND_ATTR_VHT_CAPA,
+                        sband->vht_cap.cap)))
+               return -ENOBUFS;
 
-               /* add frequencies */
-               nl_freqs = nla_nest_start(msg, NL80211_BAND_ATTR_FREQS);
-               if (!nl_freqs)
-                       goto nla_put_failure;
+       /* add bitrates */
+       nl_rates = nla_nest_start(msg, NL80211_BAND_ATTR_RATES);
+       if (!nl_rates)
+               return -ENOBUFS;
 
-               for (i = 0; i < dev->wiphy.bands[band]->n_channels; i++) {
-                       nl_freq = nla_nest_start(msg, i);
-                       if (!nl_freq)
-                               goto nla_put_failure;
+       for (i = 0; i < sband->n_bitrates; i++) {
+               nl_rate = nla_nest_start(msg, i);
+               if (!nl_rate)
+                       return -ENOBUFS;
 
-                       chan = &dev->wiphy.bands[band]->channels[i];
+               rate = &sband->bitrates[i];
+               if (nla_put_u32(msg, NL80211_BITRATE_ATTR_RATE,
+                               rate->bitrate))
+                       return -ENOBUFS;
+               if ((rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) &&
+                   nla_put_flag(msg,
+                                NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE))
+                       return -ENOBUFS;
 
-                       if (nl80211_msg_put_channel(msg, chan))
-                               goto nla_put_failure;
+               nla_nest_end(msg, nl_rate);
+       }
 
-                       nla_nest_end(msg, nl_freq);
-               }
+       nla_nest_end(msg, nl_rates);
 
-               nla_nest_end(msg, nl_freqs);
+       return 0;
+}
 
-               /* add bitrates */
-               nl_rates = nla_nest_start(msg, NL80211_BAND_ATTR_RATES);
-               if (!nl_rates)
-                       goto nla_put_failure;
+static int
+nl80211_send_mgmt_stypes(struct sk_buff *msg,
+                        const struct ieee80211_txrx_stypes *mgmt_stypes)
+{
+       u16 stypes;
+       struct nlattr *nl_ftypes, *nl_ifs;
+       enum nl80211_iftype ift;
+       int i;
 
-               for (i = 0; i < dev->wiphy.bands[band]->n_bitrates; i++) {
-                       nl_rate = nla_nest_start(msg, i);
-                       if (!nl_rate)
-                               goto nla_put_failure;
+       if (!mgmt_stypes)
+               return 0;
 
-                       rate = &dev->wiphy.bands[band]->bitrates[i];
-                       if (nla_put_u32(msg, NL80211_BITRATE_ATTR_RATE,
-                                       rate->bitrate))
-                               goto nla_put_failure;
-                       if ((rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) &&
-                           nla_put_flag(msg,
-                                        NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE))
-                               goto nla_put_failure;
+       nl_ifs = nla_nest_start(msg, NL80211_ATTR_TX_FRAME_TYPES);
+       if (!nl_ifs)
+               return -ENOBUFS;
+
+       for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) {
+               nl_ftypes = nla_nest_start(msg, ift);
+               if (!nl_ftypes)
+                       return -ENOBUFS;
+               i = 0;
+               stypes = mgmt_stypes[ift].tx;
+               while (stypes) {
+                       if ((stypes & 1) &&
+                           nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE,
+                                       (i << 4) | IEEE80211_FTYPE_MGMT))
+                               return -ENOBUFS;
+                       stypes >>= 1;
+                       i++;
+               }
+               nla_nest_end(msg, nl_ftypes);
+       }
+
+       nla_nest_end(msg, nl_ifs);
+
+       nl_ifs = nla_nest_start(msg, NL80211_ATTR_RX_FRAME_TYPES);
+       if (!nl_ifs)
+               return -ENOBUFS;
 
-                       nla_nest_end(msg, nl_rate);
+       for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) {
+               nl_ftypes = nla_nest_start(msg, ift);
+               if (!nl_ftypes)
+                       return -ENOBUFS;
+               i = 0;
+               stypes = mgmt_stypes[ift].rx;
+               while (stypes) {
+                       if ((stypes & 1) &&
+                           nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE,
+                                       (i << 4) | IEEE80211_FTYPE_MGMT))
+                               return -ENOBUFS;
+                       stypes >>= 1;
+                       i++;
                }
+               nla_nest_end(msg, nl_ftypes);
+       }
+       nla_nest_end(msg, nl_ifs);
+
+       return 0;
+}
 
-               nla_nest_end(msg, nl_rates);
+static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
+                             struct sk_buff *msg, u32 portid, u32 seq,
+                             int flags, bool split, long *split_start,
+                             long *band_start, long *chan_start)
+{
+       void *hdr;
+       struct nlattr *nl_bands, *nl_band;
+       struct nlattr *nl_freqs, *nl_freq;
+       struct nlattr *nl_cmds;
+       enum ieee80211_band band;
+       struct ieee80211_channel *chan;
+       int i;
+       const struct ieee80211_txrx_stypes *mgmt_stypes =
+                               dev->wiphy.mgmt_stypes;
+       long start = 0, start_chan = 0, start_band = 0;
+       u32 features;
 
-               nla_nest_end(msg, nl_band);
+       hdr = nl80211hdr_put(msg, portid, seq, flags, NL80211_CMD_NEW_WIPHY);
+       if (!hdr)
+               return -ENOBUFS;
+
+       /* allow always using the variables */
+       if (!split) {
+               split_start = &start;
+               band_start = &start_band;
+               chan_start = &start_chan;
        }
-       nla_nest_end(msg, nl_bands);
 
-       nl_cmds = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_COMMANDS);
-       if (!nl_cmds)
-               goto nla_put_failure;
+       if (nla_put_u32(msg, NL80211_ATTR_WIPHY, dev->wiphy_idx) ||
+           nla_put_string(msg, NL80211_ATTR_WIPHY_NAME,
+                          wiphy_name(&dev->wiphy)) ||
+           nla_put_u32(msg, NL80211_ATTR_GENERATION,
+                       cfg80211_rdev_list_generation))
+               goto nla_put_failure;
+
+       switch (*split_start) {
+       case 0:
+               if (nla_put_u8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT,
+                              dev->wiphy.retry_short) ||
+                   nla_put_u8(msg, NL80211_ATTR_WIPHY_RETRY_LONG,
+                              dev->wiphy.retry_long) ||
+                   nla_put_u32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD,
+                               dev->wiphy.frag_threshold) ||
+                   nla_put_u32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD,
+                               dev->wiphy.rts_threshold) ||
+                   nla_put_u8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS,
+                              dev->wiphy.coverage_class) ||
+                   nla_put_u8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS,
+                              dev->wiphy.max_scan_ssids) ||
+                   nla_put_u8(msg, NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS,
+                              dev->wiphy.max_sched_scan_ssids) ||
+                   nla_put_u16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN,
+                               dev->wiphy.max_scan_ie_len) ||
+                   nla_put_u16(msg, NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN,
+                               dev->wiphy.max_sched_scan_ie_len) ||
+                   nla_put_u8(msg, NL80211_ATTR_MAX_MATCH_SETS,
+                              dev->wiphy.max_match_sets))
+                       goto nla_put_failure;
 
-       i = 0;
-#define CMD(op, n)                                             \
-        do {                                                   \
-               if (dev->ops->op) {                             \
-                       i++;                                    \
-                       if (nla_put_u32(msg, i, NL80211_CMD_ ## n)) \
-                               goto nla_put_failure;           \
-               }                                               \
-       } while (0)
-
-       CMD(add_virtual_intf, NEW_INTERFACE);
-       CMD(change_virtual_intf, SET_INTERFACE);
-       CMD(add_key, NEW_KEY);
-       CMD(start_ap, START_AP);
-       CMD(add_station, NEW_STATION);
-       CMD(add_mpath, NEW_MPATH);
-       CMD(update_mesh_config, SET_MESH_CONFIG);
-       CMD(change_bss, SET_BSS);
-       CMD(auth, AUTHENTICATE);
-       CMD(assoc, ASSOCIATE);
-       CMD(deauth, DEAUTHENTICATE);
-       CMD(disassoc, DISASSOCIATE);
-       CMD(join_ibss, JOIN_IBSS);
-       CMD(join_mesh, JOIN_MESH);
-       CMD(set_pmksa, SET_PMKSA);
-       CMD(del_pmksa, DEL_PMKSA);
-       CMD(flush_pmksa, FLUSH_PMKSA);
-       if (dev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL)
-               CMD(remain_on_channel, REMAIN_ON_CHANNEL);
-       CMD(set_bitrate_mask, SET_TX_BITRATE_MASK);
-       CMD(mgmt_tx, FRAME);
-       CMD(mgmt_tx_cancel_wait, FRAME_WAIT_CANCEL);
-       if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) {
-               i++;
-               if (nla_put_u32(msg, i, NL80211_CMD_SET_WIPHY_NETNS))
+               if ((dev->wiphy.flags & WIPHY_FLAG_IBSS_RSN) &&
+                   nla_put_flag(msg, NL80211_ATTR_SUPPORT_IBSS_RSN))
                        goto nla_put_failure;
-       }
-       if (dev->ops->set_monitor_channel || dev->ops->start_ap ||
-           dev->ops->join_mesh) {
-               i++;
-               if (nla_put_u32(msg, i, NL80211_CMD_SET_CHANNEL))
+               if ((dev->wiphy.flags & WIPHY_FLAG_MESH_AUTH) &&
+                   nla_put_flag(msg, NL80211_ATTR_SUPPORT_MESH_AUTH))
                        goto nla_put_failure;
-       }
-       CMD(set_wds_peer, SET_WDS_PEER);
-       if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) {
-               CMD(tdls_mgmt, TDLS_MGMT);
-               CMD(tdls_oper, TDLS_OPER);
-       }
-       if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN)
-               CMD(sched_scan_start, START_SCHED_SCAN);
-       CMD(probe_client, PROBE_CLIENT);
-       CMD(set_noack_map, SET_NOACK_MAP);
-       if (dev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS) {
-               i++;
-               if (nla_put_u32(msg, i, NL80211_CMD_REGISTER_BEACONS))
+               if ((dev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) &&
+                   nla_put_flag(msg, NL80211_ATTR_SUPPORT_AP_UAPSD))
+                       goto nla_put_failure;
+               if ((dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_FW_ROAM) &&
+                   nla_put_flag(msg, NL80211_ATTR_ROAM_SUPPORT))
+                       goto nla_put_failure;
+               if ((dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) &&
+                   nla_put_flag(msg, NL80211_ATTR_TDLS_SUPPORT))
+                       goto nla_put_failure;
+               if ((dev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP) &&
+                   nla_put_flag(msg, NL80211_ATTR_TDLS_EXTERNAL_SETUP))
                        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);
-#endif
+               (*split_start)++;
+               if (split)
+                       break;
+       case 1:
+               if (nla_put(msg, NL80211_ATTR_CIPHER_SUITES,
+                           sizeof(u32) * dev->wiphy.n_cipher_suites,
+                           dev->wiphy.cipher_suites))
+                       goto nla_put_failure;
 
-#undef CMD
+               if (nla_put_u8(msg, NL80211_ATTR_MAX_NUM_PMKIDS,
+                              dev->wiphy.max_num_pmkids))
+                       goto nla_put_failure;
 
-       if (dev->ops->connect || dev->ops->auth) {
-               i++;
-               if (nla_put_u32(msg, i, NL80211_CMD_CONNECT))
+               if ((dev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL) &&
+                   nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE))
                        goto nla_put_failure;
-       }
 
-       if (dev->ops->disconnect || dev->ops->deauth) {
-               i++;
-               if (nla_put_u32(msg, i, NL80211_CMD_DISCONNECT))
+               if (nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX,
+                               dev->wiphy.available_antennas_tx) ||
+                   nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX,
+                               dev->wiphy.available_antennas_rx))
+                       goto nla_put_failure;
+
+               if ((dev->wiphy.flags & WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD) &&
+                   nla_put_u32(msg, NL80211_ATTR_PROBE_RESP_OFFLOAD,
+                               dev->wiphy.probe_resp_offload))
                        goto nla_put_failure;
-       }
 
-       nla_nest_end(msg, nl_cmds);
+               if ((dev->wiphy.available_antennas_tx ||
+                    dev->wiphy.available_antennas_rx) &&
+                   dev->ops->get_antenna) {
+                       u32 tx_ant = 0, rx_ant = 0;
+                       int res;
+                       res = rdev_get_antenna(dev, &tx_ant, &rx_ant);
+                       if (!res) {
+                               if (nla_put_u32(msg,
+                                               NL80211_ATTR_WIPHY_ANTENNA_TX,
+                                               tx_ant) ||
+                                   nla_put_u32(msg,
+                                               NL80211_ATTR_WIPHY_ANTENNA_RX,
+                                               rx_ant))
+                                       goto nla_put_failure;
+                       }
+               }
 
-       if (dev->ops->remain_on_channel &&
-           (dev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL) &&
-           nla_put_u32(msg, NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION,
-                       dev->wiphy.max_remain_on_channel_duration))
-               goto nla_put_failure;
+               (*split_start)++;
+               if (split)
+                       break;
+       case 2:
+               if (nl80211_put_iftypes(msg, NL80211_ATTR_SUPPORTED_IFTYPES,
+                                       dev->wiphy.interface_modes))
+                               goto nla_put_failure;
+               (*split_start)++;
+               if (split)
+                       break;
+       case 3:
+               nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS);
+               if (!nl_bands)
+                       goto nla_put_failure;
 
-       if ((dev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX) &&
-           nla_put_flag(msg, NL80211_ATTR_OFFCHANNEL_TX_OK))
-               goto nla_put_failure;
+               for (band = *band_start; band < IEEE80211_NUM_BANDS; band++) {
+                       struct ieee80211_supported_band *sband;
 
-       if (mgmt_stypes) {
-               u16 stypes;
-               struct nlattr *nl_ftypes, *nl_ifs;
-               enum nl80211_iftype ift;
+                       sband = dev->wiphy.bands[band];
 
-               nl_ifs = nla_nest_start(msg, NL80211_ATTR_TX_FRAME_TYPES);
-               if (!nl_ifs)
-                       goto nla_put_failure;
+                       if (!sband)
+                               continue;
 
-               for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) {
-                       nl_ftypes = nla_nest_start(msg, ift);
-                       if (!nl_ftypes)
+                       nl_band = nla_nest_start(msg, band);
+                       if (!nl_band)
                                goto nla_put_failure;
-                       i = 0;
-                       stypes = mgmt_stypes[ift].tx;
-                       while (stypes) {
-                               if ((stypes & 1) &&
-                                   nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE,
-                                               (i << 4) | IEEE80211_FTYPE_MGMT))
+
+                       switch (*chan_start) {
+                       case 0:
+                               if (nl80211_send_band_rateinfo(msg, sband))
                                        goto nla_put_failure;
-                               stypes >>= 1;
-                               i++;
+                               (*chan_start)++;
+                               if (split)
+                                       break;
+                       default:
+                               /* add frequencies */
+                               nl_freqs = nla_nest_start(
+                                       msg, NL80211_BAND_ATTR_FREQS);
+                               if (!nl_freqs)
+                                       goto nla_put_failure;
+
+                               for (i = *chan_start - 1;
+                                    i < sband->n_channels;
+                                    i++) {
+                                       nl_freq = nla_nest_start(msg, i);
+                                       if (!nl_freq)
+                                               goto nla_put_failure;
+
+                                       chan = &sband->channels[i];
+
+                                       if (nl80211_msg_put_channel(msg, chan,
+                                                                   split))
+                                               goto nla_put_failure;
+
+                                       nla_nest_end(msg, nl_freq);
+                                       if (split)
+                                               break;
+                               }
+                               if (i < sband->n_channels)
+                                       *chan_start = i + 2;
+                               else
+                                       *chan_start = 0;
+                               nla_nest_end(msg, nl_freqs);
+                       }
+
+                       nla_nest_end(msg, nl_band);
+
+                       if (split) {
+                               /* start again here */
+                               if (*chan_start)
+                                       band--;
+                               break;
                        }
-                       nla_nest_end(msg, nl_ftypes);
                }
+               nla_nest_end(msg, nl_bands);
 
-               nla_nest_end(msg, nl_ifs);
+               if (band < IEEE80211_NUM_BANDS)
+                       *band_start = band + 1;
+               else
+                       *band_start = 0;
 
-               nl_ifs = nla_nest_start(msg, NL80211_ATTR_RX_FRAME_TYPES);
-               if (!nl_ifs)
+               /* if bands & channels are done, continue outside */
+               if (*band_start == 0 && *chan_start == 0)
+                       (*split_start)++;
+               if (split)
+                       break;
+       case 4:
+               nl_cmds = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_COMMANDS);
+               if (!nl_cmds)
                        goto nla_put_failure;
 
-               for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) {
-                       nl_ftypes = nla_nest_start(msg, ift);
-                       if (!nl_ftypes)
+               i = 0;
+#define CMD(op, n)                                                     \
+                do {                                                   \
+                       if (dev->ops->op) {                             \
+                               i++;                                    \
+                               if (nla_put_u32(msg, i, NL80211_CMD_ ## n)) \
+                                       goto nla_put_failure;           \
+                       }                                               \
+               } while (0)
+
+               CMD(add_virtual_intf, NEW_INTERFACE);
+               CMD(change_virtual_intf, SET_INTERFACE);
+               CMD(add_key, NEW_KEY);
+               CMD(start_ap, START_AP);
+               CMD(add_station, NEW_STATION);
+               CMD(add_mpath, NEW_MPATH);
+               CMD(update_mesh_config, SET_MESH_CONFIG);
+               CMD(change_bss, SET_BSS);
+               CMD(auth, AUTHENTICATE);
+               CMD(assoc, ASSOCIATE);
+               CMD(deauth, DEAUTHENTICATE);
+               CMD(disassoc, DISASSOCIATE);
+               CMD(join_ibss, JOIN_IBSS);
+               CMD(join_mesh, JOIN_MESH);
+               CMD(set_pmksa, SET_PMKSA);
+               CMD(del_pmksa, DEL_PMKSA);
+               CMD(flush_pmksa, FLUSH_PMKSA);
+               if (dev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL)
+                       CMD(remain_on_channel, REMAIN_ON_CHANNEL);
+               CMD(set_bitrate_mask, SET_TX_BITRATE_MASK);
+               CMD(mgmt_tx, FRAME);
+               CMD(mgmt_tx_cancel_wait, FRAME_WAIT_CANCEL);
+               if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) {
+                       i++;
+                       if (nla_put_u32(msg, i, NL80211_CMD_SET_WIPHY_NETNS))
                                goto nla_put_failure;
-                       i = 0;
-                       stypes = mgmt_stypes[ift].rx;
-                       while (stypes) {
-                               if ((stypes & 1) &&
-                                   nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE,
-                                               (i << 4) | IEEE80211_FTYPE_MGMT))
-                                       goto nla_put_failure;
-                               stypes >>= 1;
-                               i++;
-                       }
-                       nla_nest_end(msg, nl_ftypes);
                }
-               nla_nest_end(msg, nl_ifs);
-       }
+               if (dev->ops->set_monitor_channel || dev->ops->start_ap ||
+                   dev->ops->join_mesh) {
+                       i++;
+                       if (nla_put_u32(msg, i, NL80211_CMD_SET_CHANNEL))
+                               goto nla_put_failure;
+               }
+               CMD(set_wds_peer, SET_WDS_PEER);
+               if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) {
+                       CMD(tdls_mgmt, TDLS_MGMT);
+                       CMD(tdls_oper, TDLS_OPER);
+               }
+               if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN)
+                       CMD(sched_scan_start, START_SCHED_SCAN);
+               CMD(probe_client, PROBE_CLIENT);
+               CMD(set_noack_map, SET_NOACK_MAP);
+               if (dev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS) {
+                       i++;
+                       if (nla_put_u32(msg, i, NL80211_CMD_REGISTER_BEACONS))
+                               goto nla_put_failure;
+               }
+               CMD(start_p2p_device, START_P2P_DEVICE);
+               CMD(set_mcast_rate, SET_MCAST_RATE);
 
-#ifdef CONFIG_PM
-       if (dev->wiphy.wowlan.flags || dev->wiphy.wowlan.n_patterns) {
-               struct nlattr *nl_wowlan;
+#ifdef CONFIG_NL80211_TESTMODE
+               CMD(testmode_cmd, TESTMODE);
+#endif
 
-               nl_wowlan = nla_nest_start(msg,
-                               NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED);
-               if (!nl_wowlan)
-                       goto nla_put_failure;
+#undef CMD
 
-               if (((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_ANY) &&
-                    nla_put_flag(msg, NL80211_WOWLAN_TRIG_ANY)) ||
-                   ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_DISCONNECT) &&
-                    nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT)) ||
-                   ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_MAGIC_PKT) &&
-                    nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT)) ||
-                   ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY) &&
-                    nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED)) ||
-                   ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) &&
-                    nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE)) ||
-                   ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ) &&
-                    nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST)) ||
-                   ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_4WAY_HANDSHAKE) &&
-                    nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE)) ||
-                   ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_RFKILL_RELEASE) &&
-                    nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE)))
-                   goto nla_put_failure;
-               if (dev->wiphy.wowlan.n_patterns) {
-                       struct nl80211_wowlan_pattern_support pat = {
-                               .max_patterns = dev->wiphy.wowlan.n_patterns,
-                               .min_pattern_len =
-                                       dev->wiphy.wowlan.pattern_min_len,
-                               .max_pattern_len =
-                                       dev->wiphy.wowlan.pattern_max_len,
-                               .max_pkt_offset =
-                                       dev->wiphy.wowlan.max_pkt_offset,
-                       };
-                       if (nla_put(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN,
-                                   sizeof(pat), &pat))
+               if (dev->ops->connect || dev->ops->auth) {
+                       i++;
+                       if (nla_put_u32(msg, i, NL80211_CMD_CONNECT))
                                goto nla_put_failure;
                }
 
-               nla_nest_end(msg, nl_wowlan);
-       }
+               if (dev->ops->disconnect || dev->ops->deauth) {
+                       i++;
+                       if (nla_put_u32(msg, i, NL80211_CMD_DISCONNECT))
+                               goto nla_put_failure;
+               }
+
+               nla_nest_end(msg, nl_cmds);
+               (*split_start)++;
+               if (split)
+                       break;
+       case 5:
+               if (dev->ops->remain_on_channel &&
+                   (dev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL) &&
+                   nla_put_u32(msg,
+                               NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION,
+                               dev->wiphy.max_remain_on_channel_duration))
+                       goto nla_put_failure;
+
+               if ((dev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX) &&
+                   nla_put_flag(msg, NL80211_ATTR_OFFCHANNEL_TX_OK))
+                       goto nla_put_failure;
+
+               if (nl80211_send_mgmt_stypes(msg, mgmt_stypes))
+                       goto nla_put_failure;
+               (*split_start)++;
+               if (split)
+                       break;
+       case 6:
+#ifdef CONFIG_PM
+               if (nl80211_send_wowlan(msg, dev, split))
+                       goto nla_put_failure;
+               (*split_start)++;
+               if (split)
+                       break;
+#else
+               (*split_start)++;
 #endif
+       case 7:
+               if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES,
+                                       dev->wiphy.software_iftypes))
+                       goto nla_put_failure;
 
-       if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES,
-                               dev->wiphy.software_iftypes))
-               goto nla_put_failure;
+               if (nl80211_put_iface_combinations(&dev->wiphy, msg, split))
+                       goto nla_put_failure;
 
-       if (nl80211_put_iface_combinations(&dev->wiphy, msg))
-               goto nla_put_failure;
+               (*split_start)++;
+               if (split)
+                       break;
+       case 8:
+               if ((dev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME) &&
+                   nla_put_u32(msg, NL80211_ATTR_DEVICE_AP_SME,
+                               dev->wiphy.ap_sme_capa))
+                       goto nla_put_failure;
 
-       if ((dev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME) &&
-           nla_put_u32(msg, NL80211_ATTR_DEVICE_AP_SME,
-                       dev->wiphy.ap_sme_capa))
-               goto nla_put_failure;
+               features = dev->wiphy.features;
+               /*
+                * We can only add the per-channel limit information if the
+                * dump is split, otherwise it makes it too big. Therefore
+                * only advertise it in that case.
+                */
+               if (split)
+                       features |= NL80211_FEATURE_ADVERTISE_CHAN_LIMITS;
+               if (nla_put_u32(msg, NL80211_ATTR_FEATURE_FLAGS, features))
+                       goto nla_put_failure;
 
-       if (nla_put_u32(msg, NL80211_ATTR_FEATURE_FLAGS,
-                       dev->wiphy.features))
-               goto nla_put_failure;
+               if (dev->wiphy.ht_capa_mod_mask &&
+                   nla_put(msg, NL80211_ATTR_HT_CAPABILITY_MASK,
+                           sizeof(*dev->wiphy.ht_capa_mod_mask),
+                           dev->wiphy.ht_capa_mod_mask))
+                       goto nla_put_failure;
 
-       if (dev->wiphy.ht_capa_mod_mask &&
-           nla_put(msg, NL80211_ATTR_HT_CAPABILITY_MASK,
-                   sizeof(*dev->wiphy.ht_capa_mod_mask),
-                   dev->wiphy.ht_capa_mod_mask))
-               goto nla_put_failure;
+               if (dev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME &&
+                   dev->wiphy.max_acl_mac_addrs &&
+                   nla_put_u32(msg, NL80211_ATTR_MAC_ACL_MAX,
+                               dev->wiphy.max_acl_mac_addrs))
+                       goto nla_put_failure;
 
-       if (dev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME &&
-           dev->wiphy.max_acl_mac_addrs &&
-           nla_put_u32(msg, NL80211_ATTR_MAC_ACL_MAX,
-                       dev->wiphy.max_acl_mac_addrs))
-               goto nla_put_failure;
+               /*
+                * Any information below this point is only available to
+                * applications that can deal with it being split. This
+                * helps ensure that newly added capabilities don't break
+                * older tools by overrunning their buffers.
+                *
+                * We still increment split_start so that in the split
+                * case we'll continue with more data in the next round,
+                * but break unconditionally so unsplit data stops here.
+                */
+               (*split_start)++;
+               break;
+       case 9:
+               if (dev->wiphy.extended_capabilities &&
+                   (nla_put(msg, NL80211_ATTR_EXT_CAPA,
+                            dev->wiphy.extended_capabilities_len,
+                            dev->wiphy.extended_capabilities) ||
+                    nla_put(msg, NL80211_ATTR_EXT_CAPA_MASK,
+                            dev->wiphy.extended_capabilities_len,
+                            dev->wiphy.extended_capabilities_mask)))
+                       goto nla_put_failure;
+
+               if (dev->wiphy.vht_capa_mod_mask &&
+                   nla_put(msg, NL80211_ATTR_VHT_CAPABILITY_MASK,
+                           sizeof(*dev->wiphy.vht_capa_mod_mask),
+                           dev->wiphy.vht_capa_mod_mask))
+                       goto nla_put_failure;
 
+               /* done */
+               *split_start = 0;
+               break;
+       }
        return genlmsg_end(msg, hdr);
 
  nla_put_failure:
@@ -1310,39 +1551,80 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
        int idx = 0, ret;
        int start = cb->args[0];
        struct cfg80211_registered_device *dev;
+       s64 filter_wiphy = -1;
+       bool split = false;
+       struct nlattr **tb = nl80211_fam.attrbuf;
+       int res;
 
        mutex_lock(&cfg80211_mutex);
+       res = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
+                         tb, nl80211_fam.maxattr, nl80211_policy);
+       if (res == 0) {
+               split = tb[NL80211_ATTR_SPLIT_WIPHY_DUMP];
+               if (tb[NL80211_ATTR_WIPHY])
+                       filter_wiphy = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
+               if (tb[NL80211_ATTR_WDEV])
+                       filter_wiphy = nla_get_u64(tb[NL80211_ATTR_WDEV]) >> 32;
+               if (tb[NL80211_ATTR_IFINDEX]) {
+                       struct net_device *netdev;
+                       int ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
+
+                       netdev = dev_get_by_index(sock_net(skb->sk), ifidx);
+                       if (!netdev) {
+                               mutex_unlock(&cfg80211_mutex);
+                               return -ENODEV;
+                       }
+                       if (netdev->ieee80211_ptr) {
+                               dev = wiphy_to_dev(
+                                       netdev->ieee80211_ptr->wiphy);
+                               filter_wiphy = dev->wiphy_idx;
+                       }
+                       dev_put(netdev);
+               }
+       }
+
        list_for_each_entry(dev, &cfg80211_rdev_list, list) {
                if (!net_eq(wiphy_net(&dev->wiphy), sock_net(skb->sk)))
                        continue;
                if (++idx <= start)
                        continue;
-               ret = nl80211_send_wiphy(skb, NETLINK_CB(cb->skb).portid,
-                                        cb->nlh->nlmsg_seq, NLM_F_MULTI,
-                                        dev);
-               if (ret < 0) {
-                       /*
-                        * If sending the wiphy data didn't fit (ENOBUFS or
-                        * EMSGSIZE returned), this SKB is still empty (so
-                        * it's not too big because another wiphy dataset is
-                        * already in the skb) and we've not tried to adjust
-                        * the dump allocation yet ... then adjust the alloc
-                        * size to be bigger, and return 1 but with the empty
-                        * skb. This results in an empty message being RX'ed
-                        * in userspace, but that is ignored.
-                        *
-                        * We can then retry with the larger buffer.
-                        */
-                       if ((ret == -ENOBUFS || ret == -EMSGSIZE) &&
-                           !skb->len &&
-                           cb->min_dump_alloc < 4096) {
-                               cb->min_dump_alloc = 4096;
-                               mutex_unlock(&cfg80211_mutex);
-                               return 1;
+               if (filter_wiphy != -1 && dev->wiphy_idx != filter_wiphy)
+                       continue;
+               /* attempt to fit multiple wiphy data chunks into the skb */
+               do {
+                       ret = nl80211_send_wiphy(dev, skb,
+                                                NETLINK_CB(cb->skb).portid,
+                                                cb->nlh->nlmsg_seq,
+                                                NLM_F_MULTI,
+                                                split, &cb->args[1],
+                                                &cb->args[2],
+                                                &cb->args[3]);
+                       if (ret < 0) {
+                               /*
+                                * If sending the wiphy data didn't fit (ENOBUFS
+                                * or EMSGSIZE returned), this SKB is still
+                                * empty (so it's not too big because another
+                                * wiphy dataset is already in the skb) and
+                                * we've not tried to adjust the dump allocation
+                                * yet ... then adjust the alloc size to be
+                                * bigger, and return 1 but with the empty skb.
+                                * This results in an empty message being RX'ed
+                                * in userspace, but that is ignored.
+                                *
+                                * We can then retry with the larger buffer.
+                                */
+                               if ((ret == -ENOBUFS || ret == -EMSGSIZE) &&
+                                   !skb->len &&
+                                   cb->min_dump_alloc < 4096) {
+                                       cb->min_dump_alloc = 4096;
+                                       mutex_unlock(&cfg80211_mutex);
+                                       return 1;
+                               }
+                               idx--;
+                               break;
                        }
-                       idx--;
-                       break;
-               }
+               } while (cb->args[1] > 0);
+               break;
        }
        mutex_unlock(&cfg80211_mutex);
 
@@ -1360,7 +1642,8 @@ static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info)
        if (!msg)
                return -ENOMEM;
 
-       if (nl80211_send_wiphy(msg, info->snd_portid, info->snd_seq, 0, dev) < 0) {
+       if (nl80211_send_wiphy(dev, msg, info->snd_portid, info->snd_seq, 0,
+                              false, NULL, NULL, NULL) < 0) {
                nlmsg_free(msg);
                return -ENOBUFS;
        }
@@ -2967,6 +3250,7 @@ static int parse_station_flags(struct genl_info *info,
                sta_flags = nla_data(nla);
                params->sta_flags_mask = sta_flags->mask;
                params->sta_flags_set = sta_flags->set;
+               params->sta_flags_set &= params->sta_flags_mask;
                if ((params->sta_flags_mask |
                     params->sta_flags_set) & BIT(__NL80211_STA_FLAG_INVALID))
                        return -EINVAL;
@@ -3320,6 +3604,136 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
        return genlmsg_reply(msg, info);
 }
 
+int cfg80211_check_station_change(struct wiphy *wiphy,
+                                 struct station_parameters *params,
+                                 enum cfg80211_station_type statype)
+{
+       if (params->listen_interval != -1)
+               return -EINVAL;
+       if (params->aid)
+               return -EINVAL;
+
+       /* When you run into this, adjust the code below for the new flag */
+       BUILD_BUG_ON(NL80211_STA_FLAG_MAX != 7);
+
+       switch (statype) {
+       case CFG80211_STA_MESH_PEER_KERNEL:
+       case CFG80211_STA_MESH_PEER_USER:
+               /*
+                * No ignoring the TDLS flag here -- the userspace mesh
+                * code doesn't have the bug of including TDLS in the
+                * mask everywhere.
+                */
+               if (params->sta_flags_mask &
+                               ~(BIT(NL80211_STA_FLAG_AUTHENTICATED) |
+                                 BIT(NL80211_STA_FLAG_MFP) |
+                                 BIT(NL80211_STA_FLAG_AUTHORIZED)))
+                       return -EINVAL;
+               break;
+       case CFG80211_STA_TDLS_PEER_SETUP:
+       case CFG80211_STA_TDLS_PEER_ACTIVE:
+               if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)))
+                       return -EINVAL;
+               /* ignore since it can't change */
+               params->sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
+               break;
+       default:
+               /* disallow mesh-specific things */
+               if (params->plink_action != NL80211_PLINK_ACTION_NO_ACTION)
+                       return -EINVAL;
+               if (params->local_pm)
+                       return -EINVAL;
+               if (params->sta_modify_mask & STATION_PARAM_APPLY_PLINK_STATE)
+                       return -EINVAL;
+       }
+
+       if (statype != CFG80211_STA_TDLS_PEER_SETUP &&
+           statype != CFG80211_STA_TDLS_PEER_ACTIVE) {
+               /* TDLS can't be set, ... */
+               if (params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))
+                       return -EINVAL;
+               /*
+                * ... but don't bother the driver with it. This works around
+                * a hostapd/wpa_supplicant issue -- it always includes the
+                * TLDS_PEER flag in the mask even for AP mode.
+                */
+               params->sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
+       }
+
+       if (statype != CFG80211_STA_TDLS_PEER_SETUP) {
+               /* reject other things that can't change */
+               if (params->sta_modify_mask & STATION_PARAM_APPLY_UAPSD)
+                       return -EINVAL;
+               if (params->sta_modify_mask & STATION_PARAM_APPLY_CAPABILITY)
+                       return -EINVAL;
+               if (params->supported_rates)
+                       return -EINVAL;
+               if (params->ext_capab || params->ht_capa || params->vht_capa)
+                       return -EINVAL;
+       }
+
+       if (statype != CFG80211_STA_AP_CLIENT) {
+               if (params->vlan)
+                       return -EINVAL;
+       }
+
+       switch (statype) {
+       case CFG80211_STA_AP_MLME_CLIENT:
+               /* Use this only for authorizing/unauthorizing a station */
+               if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
+                       return -EOPNOTSUPP;
+               break;
+       case CFG80211_STA_AP_CLIENT:
+               /* accept only the listed bits */
+               if (params->sta_flags_mask &
+                               ~(BIT(NL80211_STA_FLAG_AUTHORIZED) |
+                                 BIT(NL80211_STA_FLAG_AUTHENTICATED) |
+                                 BIT(NL80211_STA_FLAG_ASSOCIATED) |
+                                 BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) |
+                                 BIT(NL80211_STA_FLAG_WME) |
+                                 BIT(NL80211_STA_FLAG_MFP)))
+                       return -EINVAL;
+
+               /* but authenticated/associated only if driver handles it */
+               if (!(wiphy->features & NL80211_FEATURE_FULL_AP_CLIENT_STATE) &&
+                   params->sta_flags_mask &
+                               (BIT(NL80211_STA_FLAG_AUTHENTICATED) |
+                                BIT(NL80211_STA_FLAG_ASSOCIATED)))
+                       return -EINVAL;
+               break;
+       case CFG80211_STA_IBSS:
+       case CFG80211_STA_AP_STA:
+               /* reject any changes other than AUTHORIZED */
+               if (params->sta_flags_mask & ~BIT(NL80211_STA_FLAG_AUTHORIZED))
+                       return -EINVAL;
+               break;
+       case CFG80211_STA_TDLS_PEER_SETUP:
+               /* reject any changes other than AUTHORIZED or WME */
+               if (params->sta_flags_mask & ~(BIT(NL80211_STA_FLAG_AUTHORIZED) |
+                                              BIT(NL80211_STA_FLAG_WME)))
+                       return -EINVAL;
+               /* force (at least) rates when authorizing */
+               if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED) &&
+                   !params->supported_rates)
+                       return -EINVAL;
+               break;
+       case CFG80211_STA_TDLS_PEER_ACTIVE:
+               /* reject any changes */
+               return -EINVAL;
+       case CFG80211_STA_MESH_PEER_KERNEL:
+               if (params->sta_modify_mask & STATION_PARAM_APPLY_PLINK_STATE)
+                       return -EINVAL;
+               break;
+       case CFG80211_STA_MESH_PEER_USER:
+               if (params->plink_action != NL80211_PLINK_ACTION_NO_ACTION)
+                       return -EINVAL;
+               break;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(cfg80211_check_station_change);
+
 /*
  * Get vlan interface making sure it is running and on the right wiphy.
  */
@@ -3342,6 +3756,13 @@ static struct net_device *get_vlan(struct genl_info *info,
                goto error;
        }
 
+       if (v->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
+           v->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
+           v->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) {
+               ret = -EINVAL;
+               goto error;
+       }
+
        if (!netif_running(v)) {
                ret = -ENETDOWN;
                goto error;
@@ -3359,21 +3780,13 @@ nl80211_sta_wme_policy[NL80211_STA_WME_MAX + 1] __read_mostly = {
        [NL80211_STA_WME_MAX_SP] = { .type = NLA_U8 },
 };
 
-static int nl80211_set_station_tdls(struct genl_info *info,
-                                   struct station_parameters *params)
+static int nl80211_parse_sta_wme(struct genl_info *info,
+                                struct station_parameters *params)
 {
        struct nlattr *tb[NL80211_STA_WME_MAX + 1];
        struct nlattr *nla;
        int err;
 
-       /* Dummy STA entry gets updated once the peer capabilities are known */
-       if (info->attrs[NL80211_ATTR_HT_CAPABILITY])
-               params->ht_capa =
-                       nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);
-       if (info->attrs[NL80211_ATTR_VHT_CAPABILITY])
-               params->vht_capa =
-                       nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]);
-
        /* parse WME attributes if present */
        if (!info->attrs[NL80211_ATTR_STA_WME])
                return 0;
@@ -3401,18 +3814,34 @@ static int nl80211_set_station_tdls(struct genl_info *info,
        return 0;
 }
 
+static int nl80211_set_station_tdls(struct genl_info *info,
+                                   struct station_parameters *params)
+{
+       /* Dummy STA entry gets updated once the peer capabilities are known */
+       if (info->attrs[NL80211_ATTR_HT_CAPABILITY])
+               params->ht_capa =
+                       nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);
+       if (info->attrs[NL80211_ATTR_VHT_CAPABILITY])
+               params->vht_capa =
+                       nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]);
+
+       return nl80211_parse_sta_wme(info, params);
+}
+
 static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
 {
        struct cfg80211_registered_device *rdev = info->user_ptr[0];
-       int err;
        struct net_device *dev = info->user_ptr[1];
        struct station_parameters params;
-       u8 *mac_addr = NULL;
+       u8 *mac_addr;
+       int err;
 
        memset(&params, 0, sizeof(params));
 
        params.listen_interval = -1;
-       params.plink_state = -1;
+
+       if (!rdev->ops->change_station)
+               return -EOPNOTSUPP;
 
        if (info->attrs[NL80211_ATTR_STA_AID])
                return -EINVAL;
@@ -3445,152 +3874,62 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
        if (info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL])
                return -EINVAL;
 
-       if (!rdev->ops->change_station)
-               return -EOPNOTSUPP;
-
        if (parse_station_flags(info, dev->ieee80211_ptr->iftype, &params))
                return -EINVAL;
 
-       if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION])
+       if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) {
                params.plink_action =
-                   nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]);
-
-       if (info->attrs[NL80211_ATTR_STA_PLINK_STATE])
-               params.plink_state =
-                   nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_STATE]);
-
-       if (info->attrs[NL80211_ATTR_LOCAL_MESH_POWER_MODE]) {
-               enum nl80211_mesh_power_mode pm = nla_get_u32(
-                       info->attrs[NL80211_ATTR_LOCAL_MESH_POWER_MODE]);
-
-               if (pm <= NL80211_MESH_POWER_UNKNOWN ||
-                   pm > NL80211_MESH_POWER_MAX)
-                       return -EINVAL;
-
-               params.local_pm = pm;
-       }
-
-       switch (dev->ieee80211_ptr->iftype) {
-       case NL80211_IFTYPE_AP:
-       case NL80211_IFTYPE_AP_VLAN:
-       case NL80211_IFTYPE_P2P_GO:
-               /* disallow mesh-specific things */
-               if (params.plink_action)
-                       return -EINVAL;
-               if (params.local_pm)
-                       return -EINVAL;
-
-               /* TDLS can't be set, ... */
-               if (params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))
-                       return -EINVAL;
-               /*
-                * ... but don't bother the driver with it. This works around
-                * a hostapd/wpa_supplicant issue -- it always includes the
-                * TLDS_PEER flag in the mask even for AP mode.
-                */
-               params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
-
-               /* accept only the listed bits */
-               if (params.sta_flags_mask &
-                               ~(BIT(NL80211_STA_FLAG_AUTHORIZED) |
-                                 BIT(NL80211_STA_FLAG_AUTHENTICATED) |
-                                 BIT(NL80211_STA_FLAG_ASSOCIATED) |
-                                 BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) |
-                                 BIT(NL80211_STA_FLAG_WME) |
-                                 BIT(NL80211_STA_FLAG_MFP)))
-                       return -EINVAL;
-
-               /* but authenticated/associated only if driver handles it */
-               if (!(rdev->wiphy.features &
-                               NL80211_FEATURE_FULL_AP_CLIENT_STATE) &&
-                   params.sta_flags_mask &
-                               (BIT(NL80211_STA_FLAG_AUTHENTICATED) |
-                                BIT(NL80211_STA_FLAG_ASSOCIATED)))
-                       return -EINVAL;
-
-               /* reject other things that can't change */
-               if (params.supported_rates)
-                       return -EINVAL;
-               if (info->attrs[NL80211_ATTR_STA_CAPABILITY])
+                       nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]);
+               if (params.plink_action >= NUM_NL80211_PLINK_ACTIONS)
                        return -EINVAL;
-               if (info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY])
+       }
+
+       if (info->attrs[NL80211_ATTR_STA_PLINK_STATE]) {
+               params.plink_state =
+                       nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_STATE]);
+               if (params.plink_state >= NUM_NL80211_PLINK_STATES)
                        return -EINVAL;
-               if (info->attrs[NL80211_ATTR_HT_CAPABILITY] ||
-                   info->attrs[NL80211_ATTR_VHT_CAPABILITY])
+               params.sta_modify_mask |= STATION_PARAM_APPLY_PLINK_STATE;
+       }
+
+       if (info->attrs[NL80211_ATTR_LOCAL_MESH_POWER_MODE]) {
+               enum nl80211_mesh_power_mode pm = nla_get_u32(
+                       info->attrs[NL80211_ATTR_LOCAL_MESH_POWER_MODE]);
+
+               if (pm <= NL80211_MESH_POWER_UNKNOWN ||
+                   pm > NL80211_MESH_POWER_MAX)
                        return -EINVAL;
 
-               /* must be last in here for error handling */
-               params.vlan = get_vlan(info, rdev);
-               if (IS_ERR(params.vlan))
-                       return PTR_ERR(params.vlan);
-               break;
+               params.local_pm = pm;
+       }
+
+       /* Include parameters for TDLS peer (will check later) */
+       err = nl80211_set_station_tdls(info, &params);
+       if (err)
+               return err;
+
+       params.vlan = get_vlan(info, rdev);
+       if (IS_ERR(params.vlan))
+               return PTR_ERR(params.vlan);
+
+       switch (dev->ieee80211_ptr->iftype) {
+       case NL80211_IFTYPE_AP:
+       case NL80211_IFTYPE_AP_VLAN:
+       case NL80211_IFTYPE_P2P_GO:
        case NL80211_IFTYPE_P2P_CLIENT:
        case NL80211_IFTYPE_STATION:
-               /*
-                * Don't allow userspace to change the TDLS_PEER flag,
-                * but silently ignore attempts to change it since we
-                * don't have state here to verify that it doesn't try
-                * to change the flag.
-                */
-               params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
-               /* Include parameters for TDLS peer (driver will check) */
-               err = nl80211_set_station_tdls(info, &params);
-               if (err)
-                       return err;
-               /* disallow things sta doesn't support */
-               if (params.plink_action)
-                       return -EINVAL;
-               if (params.local_pm)
-                       return -EINVAL;
-               /* reject any changes other than AUTHORIZED or WME (for TDLS) */
-               if (params.sta_flags_mask & ~(BIT(NL80211_STA_FLAG_AUTHORIZED) |
-                                             BIT(NL80211_STA_FLAG_WME)))
-                       return -EINVAL;
-               break;
        case NL80211_IFTYPE_ADHOC:
-               /* disallow things sta doesn't support */
-               if (params.plink_action)
-                       return -EINVAL;
-               if (params.local_pm)
-                       return -EINVAL;
-               if (info->attrs[NL80211_ATTR_HT_CAPABILITY] ||
-                   info->attrs[NL80211_ATTR_VHT_CAPABILITY])
-                       return -EINVAL;
-               /* reject any changes other than AUTHORIZED */
-               if (params.sta_flags_mask & ~BIT(NL80211_STA_FLAG_AUTHORIZED))
-                       return -EINVAL;
-               break;
        case NL80211_IFTYPE_MESH_POINT:
-               /* disallow things mesh doesn't support */
-               if (params.vlan)
-                       return -EINVAL;
-               if (params.supported_rates)
-                       return -EINVAL;
-               if (info->attrs[NL80211_ATTR_STA_CAPABILITY])
-                       return -EINVAL;
-               if (info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY])
-                       return -EINVAL;
-               if (info->attrs[NL80211_ATTR_HT_CAPABILITY] ||
-                   info->attrs[NL80211_ATTR_VHT_CAPABILITY])
-                       return -EINVAL;
-               /*
-                * No special handling for TDLS here -- the userspace
-                * mesh code doesn't have this bug.
-                */
-               if (params.sta_flags_mask &
-                               ~(BIT(NL80211_STA_FLAG_AUTHENTICATED) |
-                                 BIT(NL80211_STA_FLAG_MFP) |
-                                 BIT(NL80211_STA_FLAG_AUTHORIZED)))
-                       return -EINVAL;
                break;
        default:
-               return -EOPNOTSUPP;
+               err = -EOPNOTSUPP;
+               goto out_put_vlan;
        }
 
-       /* be aware of params.vlan when changing code here */
-
+       /* driver will call cfg80211_check_station_change() */
        err = rdev_change_station(rdev, dev, mac_addr, &params);
 
+ out_put_vlan:
        if (params.vlan)
                dev_put(params.vlan);
 
@@ -3607,6 +3946,9 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
 
        memset(&params, 0, sizeof(params));
 
+       if (!rdev->ops->add_station)
+               return -EOPNOTSUPP;
+
        if (!info->attrs[NL80211_ATTR_MAC])
                return -EINVAL;
 
@@ -3652,50 +3994,32 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
                params.vht_capa =
                        nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]);
 
-       if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION])
+       if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) {
                params.plink_action =
-                   nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]);
+                       nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]);
+               if (params.plink_action >= NUM_NL80211_PLINK_ACTIONS)
+                       return -EINVAL;
+       }
 
-       if (!rdev->ops->add_station)
-               return -EOPNOTSUPP;
+       err = nl80211_parse_sta_wme(info, &params);
+       if (err)
+               return err;
 
        if (parse_station_flags(info, dev->ieee80211_ptr->iftype, &params))
                return -EINVAL;
 
+       /* When you run into this, adjust the code below for the new flag */
+       BUILD_BUG_ON(NL80211_STA_FLAG_MAX != 7);
+
        switch (dev->ieee80211_ptr->iftype) {
        case NL80211_IFTYPE_AP:
        case NL80211_IFTYPE_AP_VLAN:
        case NL80211_IFTYPE_P2P_GO:
-               /* parse WME attributes if sta is WME capable */
-               if ((rdev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) &&
-                   (params.sta_flags_set & BIT(NL80211_STA_FLAG_WME)) &&
-                   info->attrs[NL80211_ATTR_STA_WME]) {
-                       struct nlattr *tb[NL80211_STA_WME_MAX + 1];
-                       struct nlattr *nla;
-
-                       nla = info->attrs[NL80211_ATTR_STA_WME];
-                       err = nla_parse_nested(tb, NL80211_STA_WME_MAX, nla,
-                                              nl80211_sta_wme_policy);
-                       if (err)
-                               return err;
-
-                       if (tb[NL80211_STA_WME_UAPSD_QUEUES])
-                               params.uapsd_queues =
-                                    nla_get_u8(tb[NL80211_STA_WME_UAPSD_QUEUES]);
-                       if (params.uapsd_queues &
-                                       ~IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK)
-                               return -EINVAL;
-
-                       if (tb[NL80211_STA_WME_MAX_SP])
-                               params.max_sp =
-                                    nla_get_u8(tb[NL80211_STA_WME_MAX_SP]);
+               /* ignore WME attributes if iface/sta is not capable */
+               if (!(rdev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) ||
+                   !(params.sta_flags_set & BIT(NL80211_STA_FLAG_WME)))
+                       params.sta_modify_mask &= ~STATION_PARAM_APPLY_UAPSD;
 
-                       if (params.max_sp &
-                                       ~IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK)
-                               return -EINVAL;
-
-                       params.sta_modify_mask |= STATION_PARAM_APPLY_UAPSD;
-               }
                /* TDLS peers cannot be added */
                if (params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))
                        return -EINVAL;
@@ -3716,6 +4040,9 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
                        return PTR_ERR(params.vlan);
                break;
        case NL80211_IFTYPE_MESH_POINT:
+               /* ignore uAPSD data */
+               params.sta_modify_mask &= ~STATION_PARAM_APPLY_UAPSD;
+
                /* associated is disallowed */
                if (params.sta_flags_mask & BIT(NL80211_STA_FLAG_ASSOCIATED))
                        return -EINVAL;
@@ -3724,8 +4051,14 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
                        return -EINVAL;
                break;
        case NL80211_IFTYPE_STATION:
-               /* associated is disallowed */
-               if (params.sta_flags_mask & BIT(NL80211_STA_FLAG_ASSOCIATED))
+       case NL80211_IFTYPE_P2P_CLIENT:
+               /* ignore uAPSD data */
+               params.sta_modify_mask &= ~STATION_PARAM_APPLY_UAPSD;
+
+               /* these are disallowed */
+               if (params.sta_flags_mask &
+                               (BIT(NL80211_STA_FLAG_ASSOCIATED) |
+                                BIT(NL80211_STA_FLAG_AUTHENTICATED)))
                        return -EINVAL;
                /* Only TDLS peers can be added */
                if (!(params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)))
@@ -3736,6 +4069,11 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
                /* ... with external setup is supported */
                if (!(rdev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP))
                        return -EOPNOTSUPP;
+               /*
+                * Older wpa_supplicant versions always mark the TDLS peer
+                * as authorized, but it shouldn't yet be.
+                */
+               params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_AUTHORIZED);
                break;
        default:
                return -EOPNOTSUPP;
@@ -4280,6 +4618,7 @@ static const struct nla_policy
        [NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL] = { .type = NLA_U8 },
        [NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC] = { .type = NLA_U8 },
        [NL80211_MESH_SETUP_USERSPACE_AUTH] = { .type = NLA_FLAG },
+       [NL80211_MESH_SETUP_USERSPACE_MPM] = { .type = NLA_FLAG },
        [NL80211_MESH_SETUP_IE] = { .type = NLA_BINARY,
                                    .len = IEEE80211_MAX_DATA_LEN },
        [NL80211_MESH_SETUP_USERSPACE_AMPE] = { .type = NLA_FLAG },
@@ -4418,6 +4757,7 @@ do {                                                                          \
 static int nl80211_parse_mesh_setup(struct genl_info *info,
                                     struct mesh_setup *setup)
 {
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
        struct nlattr *tb[NL80211_MESH_SETUP_ATTR_MAX + 1];
 
        if (!info->attrs[NL80211_ATTR_MESH_SETUP])
@@ -4454,8 +4794,14 @@ static int nl80211_parse_mesh_setup(struct genl_info *info,
                setup->ie = nla_data(ieattr);
                setup->ie_len = nla_len(ieattr);
        }
+       if (tb[NL80211_MESH_SETUP_USERSPACE_MPM] &&
+           !(rdev->wiphy.features & NL80211_FEATURE_USERSPACE_MPM))
+               return -EINVAL;
+       setup->user_mpm = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_MPM]);
        setup->is_authenticated = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_AUTH]);
        setup->is_secure = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_AMPE]);
+       if (setup->is_secure)
+               setup->user_mpm = true;
 
        return 0;
 }
@@ -5650,14 +5996,10 @@ static int nl80211_associate(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];
-       struct cfg80211_crypto_settings crypto;
        struct ieee80211_channel *chan;
-       const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL;
-       int err, ssid_len, ie_len = 0;
-       bool use_mfp = false;
-       u32 flags = 0;
-       struct ieee80211_ht_cap *ht_capa = NULL;
-       struct ieee80211_ht_cap *ht_capa_mask = NULL;
+       struct cfg80211_assoc_request req = {};
+       const u8 *bssid, *ssid;
+       int err, ssid_len = 0;
 
        if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
                return -EINVAL;
@@ -5685,41 +6027,58 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
        ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
 
        if (info->attrs[NL80211_ATTR_IE]) {
-               ie = nla_data(info->attrs[NL80211_ATTR_IE]);
-               ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
+               req.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
+               req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
        }
 
        if (info->attrs[NL80211_ATTR_USE_MFP]) {
                enum nl80211_mfp mfp =
                        nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]);
                if (mfp == NL80211_MFP_REQUIRED)
-                       use_mfp = true;
+                       req.use_mfp = true;
                else if (mfp != NL80211_MFP_NO)
                        return -EINVAL;
        }
 
        if (info->attrs[NL80211_ATTR_PREV_BSSID])
-               prev_bssid = nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]);
+               req.prev_bssid = nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]);
 
        if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_HT]))
-               flags |= ASSOC_REQ_DISABLE_HT;
+               req.flags |= ASSOC_REQ_DISABLE_HT;
 
        if (info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
-               ht_capa_mask =
-                       nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]);
+               memcpy(&req.ht_capa_mask,
+                      nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]),
+                      sizeof(req.ht_capa_mask));
 
        if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) {
-               if (!ht_capa_mask)
+               if (!info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
                        return -EINVAL;
-               ht_capa = nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);
+               memcpy(&req.ht_capa,
+                      nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]),
+                      sizeof(req.ht_capa));
+       }
+
+       if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_VHT]))
+               req.flags |= ASSOC_REQ_DISABLE_VHT;
+
+       if (info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK])
+               memcpy(&req.vht_capa_mask,
+                      nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]),
+                      sizeof(req.vht_capa_mask));
+
+       if (info->attrs[NL80211_ATTR_VHT_CAPABILITY]) {
+               if (!info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK])
+                       return -EINVAL;
+               memcpy(&req.vht_capa,
+                      nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]),
+                      sizeof(req.vht_capa));
        }
 
-       err = nl80211_crypto_settings(rdev, info, &crypto, 1);
+       err = nl80211_crypto_settings(rdev, info, &req.crypto, 1);
        if (!err)
-               err = cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid,
-                                         ssid, ssid_len, ie, ie_len, use_mfp,
-                                         &crypto, flags, ht_capa,
-                                         ht_capa_mask);
+               err = cfg80211_mlme_assoc(rdev, dev, chan, bssid,
+                                         ssid, ssid_len, &req);
 
        return err;
 }
@@ -6299,6 +6658,24 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
                       sizeof(connect.ht_capa));
        }
 
+       if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_VHT]))
+               connect.flags |= ASSOC_REQ_DISABLE_VHT;
+
+       if (info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK])
+               memcpy(&connect.vht_capa_mask,
+                      nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]),
+                      sizeof(connect.vht_capa_mask));
+
+       if (info->attrs[NL80211_ATTR_VHT_CAPABILITY]) {
+               if (!info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]) {
+                       kfree(connkeys);
+                       return -EINVAL;
+               }
+               memcpy(&connect.vht_capa,
+                      nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]),
+                      sizeof(connect.vht_capa));
+       }
+
        err = cfg80211_connect(rdev, dev, &connect, connkeys);
        if (err)
                kfree(connkeys);
@@ -7072,6 +7449,9 @@ static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)
                        return err;
        }
 
+       if (setup.user_mpm)
+               cfg.auto_open_plinks = false;
+
        if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
                err = nl80211_parse_chandef(rdev, info, &setup.chandef);
                if (err)
@@ -7271,7 +7651,8 @@ static int nl80211_parse_wowlan_tcp(struct cfg80211_registered_device *rdev,
                return -EINVAL;
 
        if (nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]) >
-                       rdev->wiphy.wowlan.tcp->data_interval_max)
+                       rdev->wiphy.wowlan.tcp->data_interval_max ||
+           nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]) == 0)
                return -EINVAL;
 
        wake_size = nla_len(tb[NL80211_WOWLAN_TCP_WAKE_PAYLOAD]);
@@ -7767,6 +8148,54 @@ static int nl80211_stop_p2p_device(struct sk_buff *skb, struct genl_info *info)
        return 0;
 }
 
+static int nl80211_get_protocol_features(struct sk_buff *skb,
+                                        struct genl_info *info)
+{
+       void *hdr;
+       struct sk_buff *msg;
+
+       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+       if (!msg)
+               return -ENOMEM;
+
+       hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
+                            NL80211_CMD_GET_PROTOCOL_FEATURES);
+       if (!hdr)
+               goto nla_put_failure;
+
+       if (nla_put_u32(msg, NL80211_ATTR_PROTOCOL_FEATURES,
+                       NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP))
+               goto nla_put_failure;
+
+       genlmsg_end(msg, hdr);
+       return genlmsg_reply(msg, info);
+
+ nla_put_failure:
+       kfree_skb(msg);
+       return -ENOBUFS;
+}
+
+static int nl80211_update_ft_ies(struct sk_buff *skb, struct genl_info *info)
+{
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct cfg80211_update_ft_ies_params ft_params;
+       struct net_device *dev = info->user_ptr[1];
+
+       if (!rdev->ops->update_ft_ies)
+               return -EOPNOTSUPP;
+
+       if (!info->attrs[NL80211_ATTR_MDID] ||
+           !is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
+               return -EINVAL;
+
+       memset(&ft_params, 0, sizeof(ft_params));
+       ft_params.md = nla_get_u16(info->attrs[NL80211_ATTR_MDID]);
+       ft_params.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
+       ft_params.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
+
+       return rdev_update_ft_ies(rdev, dev, &ft_params);
+}
+
 #define NL80211_FLAG_NEED_WIPHY                0x01
 #define NL80211_FLAG_NEED_NETDEV       0x02
 #define NL80211_FLAG_NEED_RTNL         0x04
@@ -8443,6 +8872,19 @@ static struct genl_ops nl80211_ops[] = {
                .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
                                  NL80211_FLAG_NEED_RTNL,
        },
+       {
+               .cmd = NL80211_CMD_GET_PROTOCOL_FEATURES,
+               .doit = nl80211_get_protocol_features,
+               .policy = nl80211_policy,
+       },
+       {
+               .cmd = NL80211_CMD_UPDATE_FT_IES,
+               .doit = nl80211_update_ft_ies,
+               .policy = nl80211_policy,
+               .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+                                 NL80211_FLAG_NEED_RTNL,
+       },
 };
 
 static struct genl_multicast_group nl80211_mlme_mcgrp = {
@@ -8470,7 +8912,8 @@ void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev)
        if (!msg)
                return;
 
-       if (nl80211_send_wiphy(msg, 0, 0, 0, rdev) < 0) {
+       if (nl80211_send_wiphy(rdev, msg, 0, 0, 0,
+                              false, NULL, NULL, NULL) < 0) {
                nlmsg_free(msg);
                return;
        }
@@ -8794,21 +9237,31 @@ void nl80211_send_disassoc(struct cfg80211_registered_device *rdev,
                                NL80211_CMD_DISASSOCIATE, gfp);
 }
 
-void nl80211_send_unprot_deauth(struct cfg80211_registered_device *rdev,
-                               struct net_device *netdev, const u8 *buf,
-                               size_t len, gfp_t gfp)
+void cfg80211_send_unprot_deauth(struct net_device *dev, const u8 *buf,
+                                size_t len)
 {
-       nl80211_send_mlme_event(rdev, netdev, buf, len,
-                               NL80211_CMD_UNPROT_DEAUTHENTICATE, gfp);
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct wiphy *wiphy = wdev->wiphy;
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+
+       trace_cfg80211_send_unprot_deauth(dev);
+       nl80211_send_mlme_event(rdev, dev, buf, len,
+                               NL80211_CMD_UNPROT_DEAUTHENTICATE, GFP_ATOMIC);
 }
+EXPORT_SYMBOL(cfg80211_send_unprot_deauth);
 
-void nl80211_send_unprot_disassoc(struct cfg80211_registered_device *rdev,
-                                 struct net_device *netdev, const u8 *buf,
-                                 size_t len, gfp_t gfp)
+void cfg80211_send_unprot_disassoc(struct net_device *dev, const u8 *buf,
+                                  size_t len)
 {
-       nl80211_send_mlme_event(rdev, netdev, buf, len,
-                               NL80211_CMD_UNPROT_DISASSOCIATE, gfp);
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct wiphy *wiphy = wdev->wiphy;
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+
+       trace_cfg80211_send_unprot_disassoc(dev);
+       nl80211_send_mlme_event(rdev, dev, buf, len,
+                               NL80211_CMD_UNPROT_DISASSOCIATE, GFP_ATOMIC);
 }
+EXPORT_SYMBOL(cfg80211_send_unprot_disassoc);
 
 static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev,
                                      struct net_device *netdev, int cmd,
@@ -9011,14 +9464,19 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev,
        nlmsg_free(msg);
 }
 
-void nl80211_send_new_peer_candidate(struct cfg80211_registered_device *rdev,
-               struct net_device *netdev,
-               const u8 *macaddr, const u8* ie, u8 ie_len,
-               gfp_t gfp)
+void cfg80211_notify_new_peer_candidate(struct net_device *dev, const u8 *addr,
+                                       const u8* ie, u8 ie_len, 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;
 
+       if (WARN_ON(wdev->iftype != NL80211_IFTYPE_MESH_POINT))
+               return;
+
+       trace_cfg80211_notify_new_peer_candidate(dev, addr);
+
        msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
        if (!msg)
                return;
@@ -9030,8 +9488,8 @@ void nl80211_send_new_peer_candidate(struct cfg80211_registered_device *rdev,
        }
 
        if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
-           nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
-           nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, macaddr) ||
+           nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
+           nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
            (ie_len && ie &&
             nla_put(msg, NL80211_ATTR_IE, ie_len , ie)))
                goto nla_put_failure;
@@ -9046,6 +9504,7 @@ void nl80211_send_new_peer_candidate(struct cfg80211_registered_device *rdev,
        genlmsg_cancel(msg, hdr);
        nlmsg_free(msg);
 }
+EXPORT_SYMBOL(cfg80211_notify_new_peer_candidate);
 
 void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev,
                                 struct net_device *netdev, const u8 *addr,
@@ -9114,7 +9573,7 @@ void nl80211_send_beacon_hint_event(struct wiphy *wiphy,
        nl_freq = nla_nest_start(msg, NL80211_ATTR_FREQ_BEFORE);
        if (!nl_freq)
                goto nla_put_failure;
-       if (nl80211_msg_put_channel(msg, channel_before))
+       if (nl80211_msg_put_channel(msg, channel_before, false))
                goto nla_put_failure;
        nla_nest_end(msg, nl_freq);
 
@@ -9122,7 +9581,7 @@ void nl80211_send_beacon_hint_event(struct wiphy *wiphy,
        nl_freq = nla_nest_start(msg, NL80211_ATTR_FREQ_AFTER);
        if (!nl_freq)
                goto nla_put_failure;
-       if (nl80211_msg_put_channel(msg, channel_after))
+       if (nl80211_msg_put_channel(msg, channel_after, false))
                goto nla_put_failure;
        nla_nest_end(msg, nl_freq);
 
@@ -9184,31 +9643,42 @@ static void nl80211_send_remain_on_chan_event(
        nlmsg_free(msg);
 }
 
-void nl80211_send_remain_on_channel(struct cfg80211_registered_device *rdev,
-                                   struct wireless_dev *wdev, u64 cookie,
-                                   struct ieee80211_channel *chan,
-                                   unsigned int duration, gfp_t gfp)
+void cfg80211_ready_on_channel(struct wireless_dev *wdev, u64 cookie,
+                              struct ieee80211_channel *chan,
+                              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, duration);
        nl80211_send_remain_on_chan_event(NL80211_CMD_REMAIN_ON_CHANNEL,
                                          rdev, wdev, cookie, chan,
                                          duration, gfp);
 }
+EXPORT_SYMBOL(cfg80211_ready_on_channel);
 
-void nl80211_send_remain_on_channel_cancel(
-       struct cfg80211_registered_device *rdev,
-       struct wireless_dev *wdev,
-       u64 cookie, struct ieee80211_channel *chan, gfp_t gfp)
+void cfg80211_remain_on_channel_expired(struct wireless_dev *wdev, u64 cookie,
+                                       struct ieee80211_channel *chan,
+                                       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);
        nl80211_send_remain_on_chan_event(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL,
                                          rdev, wdev, cookie, chan, 0, gfp);
 }
+EXPORT_SYMBOL(cfg80211_remain_on_channel_expired);
 
-void nl80211_send_sta_event(struct cfg80211_registered_device *rdev,
-                           struct net_device *dev, const u8 *mac_addr,
-                           struct station_info *sinfo, gfp_t gfp)
+void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr,
+                     struct station_info *sinfo, gfp_t gfp)
 {
+       struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
        struct sk_buff *msg;
 
+       trace_cfg80211_new_sta(dev, mac_addr, sinfo);
+
        msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
        if (!msg)
                return;
@@ -9222,14 +9692,17 @@ void nl80211_send_sta_event(struct cfg80211_registered_device *rdev,
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, gfp);
 }
+EXPORT_SYMBOL(cfg80211_new_sta);
 
-void nl80211_send_sta_del_event(struct cfg80211_registered_device *rdev,
-                               struct net_device *dev, const u8 *mac_addr,
-                               gfp_t gfp)
+void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp)
 {
+       struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
        struct sk_buff *msg;
        void *hdr;
 
+       trace_cfg80211_del_sta(dev, mac_addr);
+
        msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
        if (!msg)
                return;
@@ -9254,12 +9727,14 @@ void nl80211_send_sta_del_event(struct cfg80211_registered_device *rdev,
        genlmsg_cancel(msg, hdr);
        nlmsg_free(msg);
 }
+EXPORT_SYMBOL(cfg80211_del_sta);
 
-void nl80211_send_conn_failed_event(struct cfg80211_registered_device *rdev,
-                                   struct net_device *dev, const u8 *mac_addr,
-                                   enum nl80211_connect_failed_reason reason,
-                                   gfp_t gfp)
+void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr,
+                         enum nl80211_connect_failed_reason reason,
+                         gfp_t gfp)
 {
+       struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
        struct sk_buff *msg;
        void *hdr;
 
@@ -9288,6 +9763,7 @@ void nl80211_send_conn_failed_event(struct cfg80211_registered_device *rdev,
        genlmsg_cancel(msg, hdr);
        nlmsg_free(msg);
 }
+EXPORT_SYMBOL(cfg80211_conn_failed);
 
 static bool __nl80211_unexpected_frame(struct net_device *dev, u8 cmd,
                                       const u8 *addr, gfp_t gfp)
@@ -9332,19 +9808,47 @@ static bool __nl80211_unexpected_frame(struct net_device *dev, u8 cmd,
        return true;
 }
 
-bool nl80211_unexpected_frame(struct net_device *dev, const u8 *addr, gfp_t gfp)
+bool cfg80211_rx_spurious_frame(struct net_device *dev,
+                               const u8 *addr, gfp_t gfp)
 {
-       return __nl80211_unexpected_frame(dev, NL80211_CMD_UNEXPECTED_FRAME,
-                                         addr, gfp);
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       bool ret;
+
+       trace_cfg80211_rx_spurious_frame(dev, addr);
+
+       if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
+                   wdev->iftype != NL80211_IFTYPE_P2P_GO)) {
+               trace_cfg80211_return_bool(false);
+               return false;
+       }
+       ret = __nl80211_unexpected_frame(dev, NL80211_CMD_UNEXPECTED_FRAME,
+                                        addr, gfp);
+       trace_cfg80211_return_bool(ret);
+       return ret;
 }
+EXPORT_SYMBOL(cfg80211_rx_spurious_frame);
 
-bool nl80211_unexpected_4addr_frame(struct net_device *dev,
-                                   const u8 *addr, gfp_t gfp)
+bool cfg80211_rx_unexpected_4addr_frame(struct net_device *dev,
+                                       const u8 *addr, gfp_t gfp)
 {
-       return __nl80211_unexpected_frame(dev,
-                                         NL80211_CMD_UNEXPECTED_4ADDR_FRAME,
-                                         addr, gfp);
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       bool ret;
+
+       trace_cfg80211_rx_unexpected_4addr_frame(dev, addr);
+
+       if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
+                   wdev->iftype != NL80211_IFTYPE_P2P_GO &&
+                   wdev->iftype != NL80211_IFTYPE_AP_VLAN)) {
+               trace_cfg80211_return_bool(false);
+               return false;
+       }
+       ret = __nl80211_unexpected_frame(dev,
+                                        NL80211_CMD_UNEXPECTED_4ADDR_FRAME,
+                                        addr, gfp);
+       trace_cfg80211_return_bool(ret);
+       return ret;
 }
+EXPORT_SYMBOL(cfg80211_rx_unexpected_4addr_frame);
 
 int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
                      struct wireless_dev *wdev, u32 nlportid,
@@ -9384,15 +9888,17 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
        return -ENOBUFS;
 }
 
-void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev,
-                                struct wireless_dev *wdev, u64 cookie,
-                                const u8 *buf, size_t len, bool ack,
-                                gfp_t gfp)
+void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie,
+                            const u8 *buf, size_t len, bool ack, gfp_t gfp)
 {
+       struct wiphy *wiphy = wdev->wiphy;
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
        struct net_device *netdev = wdev->netdev;
        struct sk_buff *msg;
        void *hdr;
 
+       trace_cfg80211_mgmt_tx_status(wdev, cookie, ack);
+
        msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
        if (!msg)
                return;
@@ -9420,17 +9926,21 @@ void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev,
        genlmsg_cancel(msg, hdr);
        nlmsg_free(msg);
 }
+EXPORT_SYMBOL(cfg80211_mgmt_tx_status);
 
-void
-nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev,
-                            struct net_device *netdev,
-                            enum nl80211_cqm_rssi_threshold_event rssi_event,
-                            gfp_t gfp)
+void cfg80211_cqm_rssi_notify(struct net_device *dev,
+                             enum nl80211_cqm_rssi_threshold_event rssi_event,
+                             gfp_t gfp)
 {
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct wiphy *wiphy = wdev->wiphy;
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
        struct sk_buff *msg;
        struct nlattr *pinfoattr;
        void *hdr;
 
+       trace_cfg80211_cqm_rssi_notify(dev, rssi_event);
+
        msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
        if (!msg)
                return;
@@ -9442,7 +9952,7 @@ nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev,
        }
 
        if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
-           nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex))
+           nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex))
                goto nla_put_failure;
 
        pinfoattr = nla_nest_start(msg, NL80211_ATTR_CQM);
@@ -9465,10 +9975,11 @@ nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev,
        genlmsg_cancel(msg, hdr);
        nlmsg_free(msg);
 }
+EXPORT_SYMBOL(cfg80211_cqm_rssi_notify);
 
-void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev,
-                             struct net_device *netdev, const u8 *bssid,
-                             const u8 *replay_ctr, gfp_t gfp)
+static void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev,
+                                    struct net_device *netdev, const u8 *bssid,
+                                    const u8 *replay_ctr, gfp_t gfp)
 {
        struct sk_buff *msg;
        struct nlattr *rekey_attr;
@@ -9510,9 +10021,22 @@ void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev,
        nlmsg_free(msg);
 }
 
-void nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev,
-                                   struct net_device *netdev, int index,
-                                   const u8 *bssid, bool preauth, gfp_t gfp)
+void cfg80211_gtk_rekey_notify(struct net_device *dev, const u8 *bssid,
+                              const u8 *replay_ctr, gfp_t gfp)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct wiphy *wiphy = wdev->wiphy;
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+
+       trace_cfg80211_gtk_rekey_notify(dev, bssid);
+       nl80211_gtk_rekey_notify(rdev, dev, bssid, replay_ctr, gfp);
+}
+EXPORT_SYMBOL(cfg80211_gtk_rekey_notify);
+
+static void
+nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev,
+                              struct net_device *netdev, int index,
+                              const u8 *bssid, bool preauth, gfp_t gfp)
 {
        struct sk_buff *msg;
        struct nlattr *attr;
@@ -9555,9 +10079,22 @@ void nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev,
        nlmsg_free(msg);
 }
 
-void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev,
-                             struct net_device *netdev,
-                             struct cfg80211_chan_def *chandef, gfp_t gfp)
+void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index,
+                                    const u8 *bssid, bool preauth, gfp_t gfp)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct wiphy *wiphy = wdev->wiphy;
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+
+       trace_cfg80211_pmksa_candidate_notify(dev, index, bssid, preauth);
+       nl80211_pmksa_candidate_notify(rdev, dev, index, bssid, preauth, gfp);
+}
+EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify);
+
+static void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev,
+                                    struct net_device *netdev,
+                                    struct cfg80211_chan_def *chandef,
+                                    gfp_t gfp)
 {
        struct sk_buff *msg;
        void *hdr;
@@ -9589,11 +10126,36 @@ void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev,
        nlmsg_free(msg);
 }
 
-void
-nl80211_send_cqm_txe_notify(struct cfg80211_registered_device *rdev,
-                           struct net_device *netdev, const u8 *peer,
-                           u32 num_packets, u32 rate, u32 intvl, gfp_t gfp)
+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);
+
+       trace_cfg80211_ch_switch_notify(dev, chandef);
+
+       wdev_lock(wdev);
+
+       if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
+                   wdev->iftype != NL80211_IFTYPE_P2P_GO))
+               goto out;
+
+       wdev->channel = chandef->chan;
+       nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL);
+out:
+       wdev_unlock(wdev);
+       return;
+}
+EXPORT_SYMBOL(cfg80211_ch_switch_notify);
+
+void cfg80211_cqm_txe_notify(struct net_device *dev,
+                            const u8 *peer, u32 num_packets,
+                            u32 rate, u32 intvl, gfp_t gfp)
 {
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct wiphy *wiphy = wdev->wiphy;
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
        struct sk_buff *msg;
        struct nlattr *pinfoattr;
        void *hdr;
@@ -9609,7 +10171,7 @@ nl80211_send_cqm_txe_notify(struct cfg80211_registered_device *rdev,
        }
 
        if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
-           nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
+           nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
            nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer))
                goto nla_put_failure;
 
@@ -9638,6 +10200,7 @@ nl80211_send_cqm_txe_notify(struct cfg80211_registered_device *rdev,
        genlmsg_cancel(msg, hdr);
        nlmsg_free(msg);
 }
+EXPORT_SYMBOL(cfg80211_cqm_txe_notify);
 
 void
 nl80211_radar_notify(struct cfg80211_registered_device *rdev,
@@ -9690,15 +10253,18 @@ nl80211_radar_notify(struct cfg80211_registered_device *rdev,
        nlmsg_free(msg);
 }
 
-void
-nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev,
-                               struct net_device *netdev, const u8 *peer,
-                               u32 num_packets, gfp_t gfp)
+void cfg80211_cqm_pktloss_notify(struct net_device *dev,
+                                const u8 *peer, u32 num_packets, gfp_t gfp)
 {
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct wiphy *wiphy = wdev->wiphy;
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
        struct sk_buff *msg;
        struct nlattr *pinfoattr;
        void *hdr;
 
+       trace_cfg80211_cqm_pktloss_notify(dev, peer, num_packets);
+
        msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
        if (!msg)
                return;
@@ -9710,7 +10276,7 @@ nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev,
        }
 
        if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
-           nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
+           nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
            nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer))
                goto nla_put_failure;
 
@@ -9733,6 +10299,7 @@ nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev,
        genlmsg_cancel(msg, hdr);
        nlmsg_free(msg);
 }
+EXPORT_SYMBOL(cfg80211_cqm_pktloss_notify);
 
 void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
                           u64 cookie, bool acked, gfp_t gfp)
@@ -10019,6 +10586,50 @@ static struct notifier_block nl80211_netlink_notifier = {
        .notifier_call = nl80211_netlink_notify,
 };
 
+void cfg80211_ft_event(struct net_device *netdev,
+                      struct cfg80211_ft_event_params *ft_event)
+{
+       struct wiphy *wiphy = netdev->ieee80211_ptr->wiphy;
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+       struct sk_buff *msg;
+       void *hdr;
+       int err;
+
+       trace_cfg80211_ft_event(wiphy, netdev, ft_event);
+
+       if (!ft_event->target_ap)
+               return;
+
+       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+       if (!msg)
+               return;
+
+       hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FT_EVENT);
+       if (!hdr) {
+               nlmsg_free(msg);
+               return;
+       }
+
+       nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
+       nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
+       nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, ft_event->target_ap);
+       if (ft_event->ies)
+               nla_put(msg, NL80211_ATTR_IE, ft_event->ies_len, ft_event->ies);
+       if (ft_event->ric_ies)
+               nla_put(msg, NL80211_ATTR_IE_RIC, ft_event->ric_ies_len,
+                       ft_event->ric_ies);
+
+       err = genlmsg_end(msg, hdr);
+       if (err < 0) {
+               nlmsg_free(msg);
+               return;
+       }
+
+       genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+                               nl80211_mlme_mcgrp.id, GFP_KERNEL);
+}
+EXPORT_SYMBOL(cfg80211_ft_event);
+
 /* initialisation/exit functions */
 
 int nl80211_init(void)
index b061da4..a4073e8 100644 (file)
@@ -29,12 +29,6 @@ void nl80211_send_deauth(struct cfg80211_registered_device *rdev,
 void nl80211_send_disassoc(struct cfg80211_registered_device *rdev,
                           struct net_device *netdev,
                           const u8 *buf, size_t len, gfp_t gfp);
-void nl80211_send_unprot_deauth(struct cfg80211_registered_device *rdev,
-                               struct net_device *netdev,
-                               const u8 *buf, size_t len, gfp_t gfp);
-void nl80211_send_unprot_disassoc(struct cfg80211_registered_device *rdev,
-                                 struct net_device *netdev,
-                                 const u8 *buf, size_t len, gfp_t gfp);
 void nl80211_send_auth_timeout(struct cfg80211_registered_device *rdev,
                               struct net_device *netdev,
                               const u8 *addr, gfp_t gfp);
@@ -54,10 +48,6 @@ void nl80211_send_disconnected(struct cfg80211_registered_device *rdev,
                               struct net_device *netdev, u16 reason,
                               const u8 *ie, size_t ie_len, bool from_ap);
 
-void nl80211_send_new_peer_candidate(struct cfg80211_registered_device *rdev,
-                                    struct net_device *netdev,
-                                    const u8 *macaddr, const u8* ie, u8 ie_len,
-                                    gfp_t gfp);
 void
 nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev,
                            struct net_device *netdev, const u8 *addr,
@@ -73,41 +63,10 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev,
                             struct net_device *netdev, const u8 *bssid,
                             gfp_t gfp);
 
-void nl80211_send_remain_on_channel(struct cfg80211_registered_device *rdev,
-                                   struct wireless_dev *wdev, u64 cookie,
-                                   struct ieee80211_channel *chan,
-                                   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, gfp_t gfp);
-
-void nl80211_send_sta_event(struct cfg80211_registered_device *rdev,
-                           struct net_device *dev, const u8 *mac_addr,
-                           struct station_info *sinfo, gfp_t gfp);
-void nl80211_send_sta_del_event(struct cfg80211_registered_device *rdev,
-                               struct net_device *dev, const u8 *mac_addr,
-                               gfp_t gfp);
-
-void nl80211_send_conn_failed_event(struct cfg80211_registered_device *rdev,
-                                   struct net_device *dev, const u8 *mac_addr,
-                                   enum nl80211_connect_failed_reason reason,
-                                   gfp_t gfp);
-
 int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
                      struct wireless_dev *wdev, u32 nlpid,
                      int freq, int sig_dbm,
                      const u8 *buf, size_t len, gfp_t gfp);
-void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev,
-                                struct wireless_dev *wdev, u64 cookie,
-                                const u8 *buf, size_t len, bool ack,
-                                gfp_t gfp);
-
-void
-nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev,
-                            struct net_device *netdev,
-                            enum nl80211_cqm_rssi_threshold_event rssi_event,
-                            gfp_t gfp);
 
 void
 nl80211_radar_notify(struct cfg80211_registered_device *rdev,
@@ -115,31 +74,4 @@ nl80211_radar_notify(struct cfg80211_registered_device *rdev,
                     enum nl80211_radar_event event,
                     struct net_device *netdev, gfp_t gfp);
 
-void
-nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev,
-                               struct net_device *netdev, const u8 *peer,
-                               u32 num_packets, gfp_t gfp);
-
-void
-nl80211_send_cqm_txe_notify(struct cfg80211_registered_device *rdev,
-                           struct net_device *netdev, const u8 *peer,
-                           u32 num_packets, u32 rate, u32 intvl, gfp_t gfp);
-
-void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev,
-                             struct net_device *netdev, const u8 *bssid,
-                             const u8 *replay_ctr, gfp_t gfp);
-
-void nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev,
-                                   struct net_device *netdev, int index,
-                                   const u8 *bssid, bool preauth, gfp_t gfp);
-
-void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev,
-                             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);
-bool nl80211_unexpected_4addr_frame(struct net_device *dev,
-                                   const u8 *addr, gfp_t gfp);
-
 #endif /* __NET_WIRELESS_NL80211_H */
index 422d382..d77e1c1 100644 (file)
@@ -6,11 +6,12 @@
 #include "core.h"
 #include "trace.h"
 
-static inline int rdev_suspend(struct cfg80211_registered_device *rdev)
+static inline int rdev_suspend(struct cfg80211_registered_device *rdev,
+                              struct cfg80211_wowlan *wowlan)
 {
        int ret;
-       trace_rdev_suspend(&rdev->wiphy, rdev->wowlan);
-       ret = rdev->ops->suspend(&rdev->wiphy, rdev->wowlan);
+       trace_rdev_suspend(&rdev->wiphy, wowlan);
+       ret = rdev->ops->suspend(&rdev->wiphy, wowlan);
        trace_rdev_return_int(&rdev->wiphy, ret);
        return ret;
 }
@@ -887,4 +888,17 @@ static inline int rdev_set_mac_acl(struct cfg80211_registered_device *rdev,
        trace_rdev_return_int(&rdev->wiphy, ret);
        return ret;
 }
+
+static inline int rdev_update_ft_ies(struct cfg80211_registered_device *rdev,
+                                    struct net_device *dev,
+                                    struct cfg80211_update_ft_ies_params *ftie)
+{
+       int ret;
+
+       trace_rdev_update_ft_ies(&rdev->wiphy, dev, ftie);
+       ret = rdev->ops->update_ft_ies(&rdev->wiphy, dev, ftie);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
 #endif /* __CFG80211_RDEV_OPS */
index 98532c0..e6df52d 100644 (file)
@@ -184,14 +184,14 @@ static const struct ieee80211_regdomain world_regdom = {
                        NL80211_RRF_NO_IBSS |
                        NL80211_RRF_NO_OFDM),
                /* IEEE 802.11a, channel 36..48 */
-               REG_RULE(5180-10, 5240+10, 40, 6, 20,
+               REG_RULE(5180-10, 5240+10, 80, 6, 20,
                         NL80211_RRF_PASSIVE_SCAN |
                         NL80211_RRF_NO_IBSS),
 
-               /* NB: 5260 MHz - 5700 MHz requies DFS */
+               /* NB: 5260 MHz - 5700 MHz requires DFS */
 
                /* IEEE 802.11a, channel 149..165 */
-               REG_RULE(5745-10, 5825+10, 40, 6, 20,
+               REG_RULE(5745-10, 5825+10, 80, 6, 20,
                        NL80211_RRF_PASSIVE_SCAN |
                        NL80211_RRF_NO_IBSS),
 
index f432bd3..bad4c4b 100644 (file)
@@ -159,7 +159,7 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev)
 {
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
        struct cfg80211_connect_params *params;
-       const u8 *prev_bssid = NULL;
+       struct cfg80211_assoc_request req = {};
        int err;
 
        ASSERT_WDEV_LOCK(wdev);
@@ -186,16 +186,20 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev)
                BUG_ON(!rdev->ops->assoc);
                wdev->conn->state = CFG80211_CONN_ASSOCIATING;
                if (wdev->conn->prev_bssid_valid)
-                       prev_bssid = wdev->conn->prev_bssid;
-               err = __cfg80211_mlme_assoc(rdev, wdev->netdev,
-                                           params->channel, params->bssid,
-                                           prev_bssid,
-                                           params->ssid, params->ssid_len,
-                                           params->ie, params->ie_len,
-                                           params->mfp != NL80211_MFP_NO,
-                                           &params->crypto,
-                                           params->flags, &params->ht_capa,
-                                           &params->ht_capa_mask);
+                       req.prev_bssid = wdev->conn->prev_bssid;
+               req.ie = params->ie;
+               req.ie_len = params->ie_len;
+               req.use_mfp = params->mfp != NL80211_MFP_NO;
+               req.crypto = params->crypto;
+               req.flags = params->flags;
+               req.ht_capa = params->ht_capa;
+               req.ht_capa_mask = params->ht_capa_mask;
+               req.vht_capa = params->vht_capa;
+               req.vht_capa_mask = params->vht_capa_mask;
+
+               err = __cfg80211_mlme_assoc(rdev, wdev->netdev, params->channel,
+                                           params->bssid, params->ssid,
+                                           params->ssid_len, &req);
                if (err)
                        __cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid,
                                               NULL, 0,
index 238ee49..8f28b9f 100644 (file)
@@ -83,6 +83,14 @@ static int wiphy_uevent(struct device *dev, struct kobj_uevent_env *env)
        return 0;
 }
 
+static void cfg80211_leave_all(struct cfg80211_registered_device *rdev)
+{
+       struct wireless_dev *wdev;
+
+       list_for_each_entry(wdev, &rdev->wdev_list, list)
+               cfg80211_leave(rdev, wdev);
+}
+
 static int wiphy_suspend(struct device *dev, pm_message_t state)
 {
        struct cfg80211_registered_device *rdev = dev_to_rdev(dev);
@@ -90,12 +98,19 @@ static int wiphy_suspend(struct device *dev, pm_message_t state)
 
        rdev->suspend_at = get_seconds();
 
-       if (rdev->ops->suspend) {
-               rtnl_lock();
-               if (rdev->wiphy.registered)
-                       ret = rdev_suspend(rdev);
-               rtnl_unlock();
+       rtnl_lock();
+       if (rdev->wiphy.registered) {
+               if (!rdev->wowlan)
+                       cfg80211_leave_all(rdev);
+               if (rdev->ops->suspend)
+                       ret = rdev_suspend(rdev, rdev->wowlan);
+               if (ret == 1) {
+                       /* Driver refuse to configure wowlan */
+                       cfg80211_leave_all(rdev);
+                       ret = rdev_suspend(rdev, NULL);
+               }
        }
+       rtnl_unlock();
 
        return ret;
 }
index b7a5313..ccadef2 100644 (file)
@@ -1785,6 +1785,26 @@ TRACE_EVENT(rdev_set_mac_acl,
                  WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->acl_policy)
 );
 
+TRACE_EVENT(rdev_update_ft_ies,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+                struct cfg80211_update_ft_ies_params *ftie),
+       TP_ARGS(wiphy, netdev, ftie),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               NETDEV_ENTRY
+               __field(u16, md)
+               __dynamic_array(u8, ie, ftie->ie_len)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               NETDEV_ASSIGN;
+               __entry->md = ftie->md;
+               memcpy(__get_dynamic_array(ie), ftie->ie, ftie->ie_len);
+       ),
+       TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", md: 0x%x",
+                 WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->md)
+);
+
 /*************************************************************
  *          cfg80211 exported functions traces              *
  *************************************************************/
@@ -2413,6 +2433,32 @@ TRACE_EVENT(cfg80211_report_wowlan_wakeup,
        TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT, WIPHY_PR_ARG, WDEV_PR_ARG)
 );
 
+TRACE_EVENT(cfg80211_ft_event,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+                struct cfg80211_ft_event_params *ft_event),
+       TP_ARGS(wiphy, netdev, ft_event),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               NETDEV_ENTRY
+               __dynamic_array(u8, ies, ft_event->ies_len)
+               MAC_ENTRY(target_ap)
+               __dynamic_array(u8, ric_ies, ft_event->ric_ies_len)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               NETDEV_ASSIGN;
+               if (ft_event->ies)
+                       memcpy(__get_dynamic_array(ies), ft_event->ies,
+                              ft_event->ies_len);
+               MAC_ASSIGN(target_ap, ft_event->target_ap);
+               if (ft_event->ric_ies)
+                       memcpy(__get_dynamic_array(ric_ies), ft_event->ric_ies,
+                              ft_event->ric_ies_len);
+       ),
+       TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", target_ap: " MAC_PR_FMT,
+                 WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(target_ap))
+);
+
 #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */
 
 #undef TRACE_INCLUDE_PATH