]> Pileus Git - ~andy/linux/commitdiff
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
authorJohn W. Linville <linville@tuxdriver.com>
Wed, 1 Jan 2014 20:39:56 +0000 (15:39 -0500)
committerJohn W. Linville <linville@tuxdriver.com>
Wed, 1 Jan 2014 20:39:56 +0000 (15:39 -0500)
123 files changed:
MAINTAINERS
drivers/bcma/main.c
drivers/net/wireless/ath/ath6kl/wmi.c
drivers/net/wireless/ath/ath9k/Makefile
drivers/net/wireless/ath/ath9k/antenna.c
drivers/net/wireless/ath/ath9k/ar9002_hw.c
drivers/net/wireless/ath/ath9k/ar9002_mac.c
drivers/net/wireless/ath/ath9k/ar9002_phy.c
drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
drivers/net/wireless/ath/ath9k/ar9003_eeprom.h
drivers/net/wireless/ath/ath9k/ar9003_mac.c
drivers/net/wireless/ath/ath9k/ar9003_phy.h
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/beacon.c
drivers/net/wireless/ath/ath9k/btcoex.c
drivers/net/wireless/ath/ath9k/common.c
drivers/net/wireless/ath/ath9k/debug.c
drivers/net/wireless/ath/ath9k/debug.h
drivers/net/wireless/ath/ath9k/dfs.c
drivers/net/wireless/ath/ath9k/eeprom_4k.c
drivers/net/wireless/ath/ath9k/eeprom_9287.c
drivers/net/wireless/ath/ath9k/eeprom_def.c
drivers/net/wireless/ath/ath9k/gpio.c
drivers/net/wireless/ath/ath9k/htc.h
drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
drivers/net/wireless/ath/ath9k/htc_drv_gpio.c
drivers/net/wireless/ath/ath9k/htc_drv_init.c
drivers/net/wireless/ath/ath9k/hw-ops.h
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/ath/ath9k/hw.h
drivers/net/wireless/ath/ath9k/init.c
drivers/net/wireless/ath/ath9k/mac.c
drivers/net/wireless/ath/ath9k/mac.h
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/mci.c
drivers/net/wireless/ath/ath9k/recv.c
drivers/net/wireless/ath/ath9k/spectral.c [new file with mode: 0644]
drivers/net/wireless/ath/ath9k/spectral.h [new file with mode: 0644]
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/ath/wcn36xx/smd.c
drivers/net/wireless/brcm80211/brcmfmac/Makefile
drivers/net/wireless/brcm80211/brcmfmac/bcdc.c
drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c [deleted file]
drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h
drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
drivers/net/wireless/brcm80211/brcmfmac/fwil.c
drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
drivers/net/wireless/brcm80211/brcmfmac/proto.c
drivers/net/wireless/brcm80211/brcmfmac/proto.h
drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c
drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.h
drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h
drivers/net/wireless/brcm80211/brcmfmac/usb.c
drivers/net/wireless/iwlwifi/dvm/mac80211.c
drivers/net/wireless/iwlwifi/dvm/main.c
drivers/net/wireless/iwlwifi/iwl-7000.c
drivers/net/wireless/iwlwifi/iwl-config.h
drivers/net/wireless/iwlwifi/iwl-drv.c
drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c
drivers/net/wireless/iwlwifi/iwl-fw-file.h
drivers/net/wireless/iwlwifi/iwl-fw.h
drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
drivers/net/wireless/iwlwifi/iwl-op-mode.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/debugfs-vif.c
drivers/net/wireless/iwlwifi/mvm/fw-api-power.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/mac80211.c
drivers/net/wireless/iwlwifi/mvm/mvm.h
drivers/net/wireless/iwlwifi/mvm/ops.c
drivers/net/wireless/iwlwifi/mvm/power.c
drivers/net/wireless/iwlwifi/mvm/rs.c
drivers/net/wireless/iwlwifi/mvm/rs.h
drivers/net/wireless/iwlwifi/mvm/rx.c
drivers/net/wireless/iwlwifi/mvm/sf.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/mvm/sta.c
drivers/net/wireless/iwlwifi/mvm/tt.c
drivers/net/wireless/iwlwifi/mvm/tx.c
drivers/net/wireless/iwlwifi/mvm/utils.c
drivers/net/wireless/iwlwifi/pcie/internal.h
drivers/net/wireless/iwlwifi/pcie/rx.c
drivers/net/wireless/iwlwifi/pcie/trans.c
drivers/net/wireless/iwlwifi/pcie/tx.c
drivers/net/wireless/mwifiex/cfg80211.c
drivers/net/wireless/mwifiex/fw.h
drivers/net/wireless/mwifiex/main.h
drivers/net/wireless/mwifiex/sta_cmd.c
drivers/net/wireless/mwifiex/sta_ioctl.c
include/net/cfg80211.h
include/net/mac80211.h
include/uapi/linux/nl80211.h
net/mac80211/cfg.c
net/mac80211/driver-ops.h
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_sync.c
net/mac80211/mlme.c
net/mac80211/pm.c
net/mac80211/rx.c
net/mac80211/scan.c
net/mac80211/sta_info.c
net/mac80211/sta_info.h
net/mac80211/trace.h
net/mac80211/tx.c
net/mac80211/util.c
net/wireless/core.c
net/wireless/core.h
net/wireless/mesh.c
net/wireless/nl80211.c
net/wireless/reg.c
net/wireless/reg.h
net/wireless/scan.c

index 9bae7901162d29ea007ec467091d3a47802152af..0d58ff5d2a6229d677fb447038b75ab9233d7ec5 100644 (file)
@@ -1430,7 +1430,7 @@ F:        Documentation/aoe/
 F:     drivers/block/aoe/
 
 ATHEROS ATH GENERIC UTILITIES
-M:     "Luis R. Rodriguez" <mcgrof@qca.qualcomm.com>
+M:     "Luis R. Rodriguez" <mcgrof@do-not-panic.com>
 L:     linux-wireless@vger.kernel.org
 S:     Supported
 F:     drivers/net/wireless/ath/*
@@ -1438,7 +1438,7 @@ F:        drivers/net/wireless/ath/*
 ATHEROS ATH5K WIRELESS DRIVER
 M:     Jiri Slaby <jirislaby@gmail.com>
 M:     Nick Kossifidis <mickflemm@gmail.com>
-M:     "Luis R. Rodriguez" <mcgrof@qca.qualcomm.com>
+M:     "Luis R. Rodriguez" <mcgrof@do-not-panic.com>
 L:     linux-wireless@vger.kernel.org
 L:     ath5k-devel@lists.ath5k.org
 W:     http://wireless.kernel.org/en/users/Drivers/ath5k
index e15430a82e90e766163c7f5f40e26559b3fabbe1..5a9f6bdc88f1870f5e3c89a5c4e75f1981bb91f3 100644 (file)
@@ -176,6 +176,7 @@ static int bcma_register_cores(struct bcma_bus *bus)
                        bcma_err(bus,
                                 "Could not register dev for core 0x%03X\n",
                                 core->id.id);
+                       put_device(&core->dev);
                        continue;
                }
                core->dev_registered = true;
index 546d5da0b8947a2f8522c5f7b8893ee0a6f537d5..4f16d79c9eb187566ff878e9ac42c163cd58312a 100644 (file)
@@ -2754,9 +2754,9 @@ static int ath6kl_set_bitrate_mask64(struct wmi *wmi, u8 if_idx,
                                mask->control[band].legacy << 4;
 
                /* copy mcs rate mask */
-               mcsrate = mask->control[band].mcs[1];
+               mcsrate = mask->control[band].ht_mcs[1];
                mcsrate <<= 8;
-               mcsrate |= mask->control[band].mcs[0];
+               mcsrate |= mask->control[band].ht_mcs[0];
                ratemask[band] |= mcsrate << 12;
                ratemask[band] |= mcsrate << 28;
        }
@@ -2806,7 +2806,7 @@ static int ath6kl_set_bitrate_mask32(struct wmi *wmi, u8 if_idx,
                                mask->control[band].legacy << 4;
 
                /* copy mcs rate mask */
-               mcsrate = mask->control[band].mcs[0];
+               mcsrate = mask->control[band].ht_mcs[0];
                ratemask[band] |= mcsrate << 12;
                ratemask[band] |= mcsrate << 20;
        }
index 337c459eda284770c61dbb654b1762aac3965e9b..e9904e5ccd81007f543b4e12a185be1a43542085 100644 (file)
@@ -11,12 +11,14 @@ ath9k-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += mci.o
 ath9k-$(CONFIG_ATH9K_LEGACY_RATE_CONTROL) += rc.o
 ath9k-$(CONFIG_ATH9K_PCI) += pci.o
 ath9k-$(CONFIG_ATH9K_AHB) += ahb.o
-ath9k-$(CONFIG_ATH9K_DEBUGFS) += debug.o
 ath9k-$(CONFIG_ATH9K_DFS_DEBUGFS) += dfs_debug.o
 ath9k-$(CONFIG_ATH9K_DFS_CERTIFIED) += dfs.o
 ath9k-$(CONFIG_ATH9K_TX99) += tx99.o
 ath9k-$(CONFIG_ATH9K_WOW) += wow.o
 
+ath9k-$(CONFIG_ATH9K_DEBUGFS) += debug.o \
+                                spectral.o
+
 obj-$(CONFIG_ATH9K) += ath9k.o
 
 ath9k_hw-y:=   \
index bd048cc69a334d6234b6967ecff5e1aec8b75fbe..a3668433dc02b6c35df882367e6f441a811ce6f8 100644 (file)
@@ -724,14 +724,14 @@ void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs)
        struct ath_ant_comb *antcomb = &sc->ant_comb;
        int alt_ratio = 0, alt_rssi_avg = 0, main_rssi_avg = 0, curr_alt_set;
        int curr_main_set;
-       int main_rssi = rs->rs_rssi_ctl0;
-       int alt_rssi = rs->rs_rssi_ctl1;
+       int main_rssi = rs->rs_rssi_ctl[0];
+       int alt_rssi = rs->rs_rssi_ctl[1];
        int rx_ant_conf,  main_ant_conf;
        bool short_scan = false, ret;
 
-       rx_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_CURRENT_SHIFT) &
+       rx_ant_conf = (rs->rs_rssi_ctl[2] >> ATH_ANT_RX_CURRENT_SHIFT) &
                       ATH_ANT_RX_MASK;
-       main_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_MAIN_SHIFT) &
+       main_ant_conf = (rs->rs_rssi_ctl[2] >> ATH_ANT_RX_MAIN_SHIFT) &
                         ATH_ANT_RX_MASK;
 
        if (alt_rssi >= antcomb->low_rssi_thresh) {
index 5c95fd9e9c9e9c861edb283a2a8cfbf4a9b5e3b9..149aba3c7298c3af99f8f4d54b37eaf10da606ef 100644 (file)
@@ -32,12 +32,8 @@ static int ar9002_hw_init_mode_regs(struct ath_hw *ah)
                return 0;
        }
 
-       if (ah->config.pcie_clock_req)
-               INIT_INI_ARRAY(&ah->iniPcieSerdes,
-                          ar9280PciePhy_clkreq_off_L1_9280);
-       else
-               INIT_INI_ARRAY(&ah->iniPcieSerdes,
-                          ar9280PciePhy_clkreq_always_on_L1_9280);
+       INIT_INI_ARRAY(&ah->iniPcieSerdes,
+                      ar9280PciePhy_clkreq_always_on_L1_9280);
 
        if (AR_SREV_9287_11_OR_LATER(ah)) {
                INIT_INI_ARRAY(&ah->iniModes, ar9287Modes_9287_1_1);
index 8d78253c26cee6f459121e7e8ef5c3e0e44b8b2a..857ede3a999ca1a902f0a004979503cd3b40c101 100644 (file)
@@ -29,7 +29,8 @@ static void ar9002_hw_set_desc_link(void *ds, u32 ds_link)
        ((struct ath_desc*) ds)->ds_link = ds_link;
 }
 
-static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
+static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked,
+                             u32 *sync_cause_p)
 {
        u32 isr = 0;
        u32 mask2 = 0;
@@ -136,7 +137,8 @@ static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
        }
 
        if (sync_cause) {
-               ath9k_debug_sync_cause(common, sync_cause);
+               if (sync_cause_p)
+                       *sync_cause_p = sync_cause;
                fatal_int =
                        (sync_cause &
                         (AR_INTR_SYNC_HOST1_FATAL | AR_INTR_SYNC_HOST1_PERR))
index f087117b2e6b6b2592ae8eb7a2270314cffb7325..9a2afa2c690b761bef1e9203c60b2a3bb0e9e86f 100644 (file)
@@ -201,7 +201,6 @@ static void ar9002_hw_spur_mitigate(struct ath_hw *ah,
        ath9k_hw_get_channel_centers(ah, chan, &centers);
        freq = centers.synth_center;
 
-       ah->config.spurmode = SPUR_ENABLE_EEPROM;
        for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
                cur_bb_spur = ah->eep_ops->get_spur_channel(ah, i, is2GHz);
 
index ec317d6937d646e8cb9269675649d284789f5399..c8d22eccfef8778b88e1a2a05c9ba0dbe0e206b8 100644 (file)
@@ -131,6 +131,7 @@ static const struct ar9300_eeprom ar9300_default = {
                .thresh62 = 28,
                .papdRateMaskHt20 = LE32(0x0cf0e0e0),
                .papdRateMaskHt40 = LE32(0x6cf0e0e0),
+               .switchcomspdt = 0,
                .xlna_bias_strength = 0,
                .futureModal = {
                        0, 0, 0, 0, 0, 0, 0,
@@ -138,7 +139,7 @@ static const struct ar9300_eeprom ar9300_default = {
         },
        .base_ext1 = {
                .ant_div_control = 0,
-               .future = {0, 0, 0},
+               .future = {0, 0},
                .tempslopextension = {0, 0, 0, 0, 0, 0, 0, 0}
        },
        .calFreqPier2G = {
@@ -333,6 +334,7 @@ static const struct ar9300_eeprom ar9300_default = {
                .thresh62 = 28,
                .papdRateMaskHt20 = LE32(0x0c80c080),
                .papdRateMaskHt40 = LE32(0x0080c080),
+               .switchcomspdt = 0,
                .xlna_bias_strength = 0,
                .futureModal = {
                        0, 0, 0, 0, 0, 0, 0,
@@ -707,6 +709,7 @@ static const struct ar9300_eeprom ar9300_x113 = {
                .thresh62 = 28,
                .papdRateMaskHt20 = LE32(0x0c80c080),
                .papdRateMaskHt40 = LE32(0x0080c080),
+               .switchcomspdt = 0,
                .xlna_bias_strength = 0,
                .futureModal = {
                        0, 0, 0, 0, 0, 0, 0,
@@ -714,7 +717,7 @@ static const struct ar9300_eeprom ar9300_x113 = {
         },
         .base_ext1 = {
                .ant_div_control = 0,
-               .future = {0, 0, 0},
+               .future = {0, 0},
                .tempslopextension = {0, 0, 0, 0, 0, 0, 0, 0}
         },
        .calFreqPier2G = {
@@ -909,6 +912,7 @@ static const struct ar9300_eeprom ar9300_x113 = {
                .thresh62 = 28,
                .papdRateMaskHt20 = LE32(0x0cf0e0e0),
                .papdRateMaskHt40 = LE32(0x6cf0e0e0),
+               .switchcomspdt = 0,
                .xlna_bias_strength = 0,
                .futureModal = {
                        0, 0, 0, 0, 0, 0, 0,
@@ -1284,6 +1288,7 @@ static const struct ar9300_eeprom ar9300_h112 = {
                .thresh62 = 28,
                .papdRateMaskHt20 = LE32(0x0c80c080),
                .papdRateMaskHt40 = LE32(0x0080c080),
+               .switchcomspdt = 0,
                .xlna_bias_strength = 0,
                .futureModal = {
                        0, 0, 0, 0, 0, 0, 0,
@@ -1291,7 +1296,7 @@ static const struct ar9300_eeprom ar9300_h112 = {
        },
        .base_ext1 = {
                .ant_div_control = 0,
-               .future = {0, 0, 0},
+               .future = {0, 0},
                .tempslopextension = {0, 0, 0, 0, 0, 0, 0, 0}
        },
        .calFreqPier2G = {
@@ -1486,6 +1491,7 @@ static const struct ar9300_eeprom ar9300_h112 = {
                .thresh62 = 28,
                .papdRateMaskHt20 = LE32(0x0cf0e0e0),
                .papdRateMaskHt40 = LE32(0x6cf0e0e0),
+               .switchcomspdt = 0,
                .xlna_bias_strength = 0,
                .futureModal = {
                        0, 0, 0, 0, 0, 0, 0,
@@ -1861,6 +1867,7 @@ static const struct ar9300_eeprom ar9300_x112 = {
                .thresh62 = 28,
                .papdRateMaskHt20 = LE32(0x0c80c080),
                .papdRateMaskHt40 = LE32(0x0080c080),
+               .switchcomspdt = 0,
                .xlna_bias_strength = 0,
                .futureModal = {
                        0, 0, 0, 0, 0, 0, 0,
@@ -1868,7 +1875,7 @@ static const struct ar9300_eeprom ar9300_x112 = {
        },
        .base_ext1 = {
                .ant_div_control = 0,
-               .future = {0, 0, 0},
+               .future = {0, 0},
                .tempslopextension = {0, 0, 0, 0, 0, 0, 0, 0}
        },
        .calFreqPier2G = {
@@ -2063,6 +2070,7 @@ static const struct ar9300_eeprom ar9300_x112 = {
                .thresh62 = 28,
                .papdRateMaskHt20 = LE32(0x0cf0e0e0),
                .papdRateMaskHt40 = LE32(0x6cf0e0e0),
+               .switchcomspdt = 0,
                .xlna_bias_strength = 0,
                .futureModal = {
                        0, 0, 0, 0, 0, 0, 0,
@@ -2437,6 +2445,7 @@ static const struct ar9300_eeprom ar9300_h116 = {
                .thresh62 = 28,
                .papdRateMaskHt20 = LE32(0x0c80C080),
                .papdRateMaskHt40 = LE32(0x0080C080),
+               .switchcomspdt = 0,
                .xlna_bias_strength = 0,
                .futureModal = {
                        0, 0, 0, 0, 0, 0, 0,
@@ -2444,7 +2453,7 @@ static const struct ar9300_eeprom ar9300_h116 = {
         },
         .base_ext1 = {
                .ant_div_control = 0,
-               .future = {0, 0, 0},
+               .future = {0, 0},
                .tempslopextension = {0, 0, 0, 0, 0, 0, 0, 0}
         },
        .calFreqPier2G = {
@@ -2639,6 +2648,7 @@ static const struct ar9300_eeprom ar9300_h116 = {
                .thresh62 = 28,
                .papdRateMaskHt20 = LE32(0x0cf0e0e0),
                .papdRateMaskHt40 = LE32(0x6cf0e0e0),
+               .switchcomspdt = 0,
                .xlna_bias_strength = 0,
                .futureModal = {
                        0, 0, 0, 0, 0, 0, 0,
@@ -4111,6 +4121,37 @@ static void ar9003_hw_thermo_cal_apply(struct ath_hw *ah)
        }
 }
 
+static void ar9003_hw_apply_minccapwr_thresh(struct ath_hw *ah,
+                                            bool is2ghz)
+{
+       struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+       const u_int32_t cca_ctrl[AR9300_MAX_CHAINS] = {
+               AR_PHY_CCA_CTRL_0,
+               AR_PHY_CCA_CTRL_1,
+               AR_PHY_CCA_CTRL_2,
+       };
+       int chain;
+       u32 val;
+
+       if (is2ghz) {
+               if (!(eep->base_ext1.misc_enable & BIT(2)))
+                       return;
+       } else {
+               if (!(eep->base_ext1.misc_enable & BIT(3)))
+                       return;
+       }
+
+       for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
+               if (!(ah->caps.tx_chainmask & BIT(chain)))
+                       continue;
+
+               val = ar9003_modal_header(ah, is2ghz)->noiseFloorThreshCh[chain];
+               REG_RMW_FIELD(ah, cca_ctrl[chain],
+                             AR_PHY_EXT_CCA0_THRESH62_1, val);
+       }
+
+}
+
 static void ath9k_hw_ar9300_set_board_values(struct ath_hw *ah,
                                             struct ath9k_channel *chan)
 {
@@ -4125,6 +4166,7 @@ static void ath9k_hw_ar9300_set_board_values(struct ath_hw *ah,
        if (!AR_SREV_9330(ah) && !AR_SREV_9340(ah))
                ar9003_hw_internal_regulator_apply(ah);
        ar9003_hw_apply_tuning_caps(ah);
+       ar9003_hw_apply_minccapwr_thresh(ah, chan);
        ar9003_hw_txend_to_xpa_off_apply(ah, is2ghz);
        ar9003_hw_thermometer_apply(ah);
        ar9003_hw_thermo_cal_apply(ah);
index 0e5daa58a4fc14371d360bdc5aa22937902bc824..694ca2e680e5d5a7d45eba015216c395026ef94a 100644 (file)
@@ -270,10 +270,20 @@ struct cal_ctl_data_5g {
        u8 ctlEdges[AR9300_NUM_BAND_EDGES_5G];
 } __packed;
 
+#define MAX_BASE_EXTENSION_FUTURE 2
+
 struct ar9300_BaseExtension_1 {
        u8 ant_div_control;
-       u8 future[3];
-       u8 tempslopextension[8];
+       u8 future[MAX_BASE_EXTENSION_FUTURE];
+       /*
+        * misc_enable:
+        *
+        * BIT 0   - TX Gain Cap enable.
+        * BIT 1   - Uncompressed Checksum enable.
+        * BIT 2/3 - MinCCApwr enable 2g/5g.
+        */
+       u8 misc_enable;
+       int8_t tempslopextension[8];
        int8_t quick_drop_low;
        int8_t quick_drop_high;
 } __packed;
index f6c5c1b50471ee2f876d24238b6912182c449f13..729ffbf07343bb72c9313f037cc5965e58d8366f 100644 (file)
@@ -175,7 +175,8 @@ static void ar9003_hw_set_desc_link(void *ds, u32 ds_link)
        ads->ctl10 |= ar9003_calc_ptr_chksum(ads);
 }
 
-static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
+static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked,
+                             u32 *sync_cause_p)
 {
        u32 isr = 0;
        u32 mask2 = 0;
@@ -310,7 +311,8 @@ static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
                ar9003_mci_get_isr(ah, masked);
 
        if (sync_cause) {
-               ath9k_debug_sync_cause(common, sync_cause);
+               if (sync_cause_p)
+                       *sync_cause_p = sync_cause;
                fatal_int =
                        (sync_cause &
                         (AR_INTR_SYNC_HOST1_FATAL | AR_INTR_SYNC_HOST1_PERR))
@@ -476,12 +478,12 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs,
 
        /* XXX: Keycache */
        rxs->rs_rssi = MS(rxsp->status5, AR_RxRSSICombined);
-       rxs->rs_rssi_ctl0 = MS(rxsp->status1, AR_RxRSSIAnt00);
-       rxs->rs_rssi_ctl1 = MS(rxsp->status1, AR_RxRSSIAnt01);
-       rxs->rs_rssi_ctl2 = MS(rxsp->status1, AR_RxRSSIAnt02);
-       rxs->rs_rssi_ext0 = MS(rxsp->status5, AR_RxRSSIAnt10);
-       rxs->rs_rssi_ext1 = MS(rxsp->status5, AR_RxRSSIAnt11);
-       rxs->rs_rssi_ext2 = MS(rxsp->status5, AR_RxRSSIAnt12);
+       rxs->rs_rssi_ctl[0] = MS(rxsp->status1, AR_RxRSSIAnt00);
+       rxs->rs_rssi_ctl[1] = MS(rxsp->status1, AR_RxRSSIAnt01);
+       rxs->rs_rssi_ctl[2] = MS(rxsp->status1, AR_RxRSSIAnt02);
+       rxs->rs_rssi_ext[0] = MS(rxsp->status5, AR_RxRSSIAnt10);
+       rxs->rs_rssi_ext[1] = MS(rxsp->status5, AR_RxRSSIAnt11);
+       rxs->rs_rssi_ext[2] = MS(rxsp->status5, AR_RxRSSIAnt12);
 
        if (rxsp->status11 & AR_RxKeyIdxValid)
                rxs->rs_keyix = MS(rxsp->status11, AR_KeyIdx);
index bbbfc4dc59eb1e14f69fbd1e4c78eee38c3ad215..1b441715ba390216a26963ec7e272bbc5d05f60d 100644 (file)
 #define AR_PHY_AGC              (AR_AGC_BASE + 0x14)
 #define AR_PHY_EXT_ATTEN_CTL_0  (AR_AGC_BASE + 0x18)
 #define AR_PHY_CCA_0            (AR_AGC_BASE + 0x1c)
-#define AR_PHY_EXT_CCA0         (AR_AGC_BASE + 0x20)
+#define AR_PHY_CCA_CTRL_0       (AR_AGC_BASE + 0x20)
 #define AR_PHY_RESTART          (AR_AGC_BASE + 0x24)
 
 /*
 #define AR9280_PHY_CCA_THRESH62_S   12
 #define AR_PHY_EXT_CCA0_THRESH62    0x000000FF
 #define AR_PHY_EXT_CCA0_THRESH62_S  0
+#define AR_PHY_EXT_CCA0_THRESH62_1    0x000001FF
+#define AR_PHY_EXT_CCA0_THRESH62_1_S  0
 #define AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK          0x0000003F
 #define AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK_S        0
 #define AR_PHY_CCK_DETECT_ANT_SWITCH_TIME           0x00001FC0
index 5e5d5cb2458c0a9c492b8ea74aaf83bcc91a4568..f2202e78fa7b3de875f1c06fca9438dc01a59f5e 100644 (file)
 #include "common.h"
 #include "mci.h"
 #include "dfs.h"
-
-/*
- * Header for the ath9k.ko driver core *only* -- hw code nor any other driver
- * should rely on this file or its contents.
- */
+#include "spectral.h"
 
 struct ath_node;
+struct ath_rate_table;
 
-/* Macro to expand scalars to 64-bit objects */
-
-#define        ito64(x) (sizeof(x) == 1) ?                     \
-       (((unsigned long long int)(x)) & (0xff)) :      \
-       (sizeof(x) == 2) ?                              \
-       (((unsigned long long int)(x)) & 0xffff) :      \
-       ((sizeof(x) == 4) ?                             \
-        (((unsigned long long int)(x)) & 0xffffffff) : \
-        (unsigned long long int)(x))
-
-/* increment with wrap-around */
-#define INCR(_l, _sz)   do {                   \
-               (_l)++;                         \
-               (_l) &= ((_sz) - 1);            \
-       } while (0)
-
-/* decrement with wrap-around */
-#define DECR(_l,  _sz)  do {                   \
-               (_l)--;                         \
-               (_l) &= ((_sz) - 1);            \
-       } while (0)
-
-#define TSF_TO_TU(_h,_l) \
-       ((((u32)(_h)) << 22) | (((u32)(_l)) >> 10))
-
-#define        ATH_TXQ_SETUP(sc, i)        ((sc)->tx.txqsetup & (1<<i))
+extern struct ieee80211_ops ath9k_ops;
+extern int ath9k_modparam_nohwcrypt;
+extern int led_blink;
+extern bool is_ath9k_unloaded;
 
 struct ath_config {
        u16 txpowlimit;
@@ -70,6 +45,17 @@ struct ath_config {
 /* Descriptor Management */
 /*************************/
 
+#define ATH_TXSTATUS_RING_SIZE 512
+
+/* Macro to expand scalars to 64-bit objects */
+#define        ito64(x) (sizeof(x) == 1) ?                     \
+       (((unsigned long long int)(x)) & (0xff)) :      \
+       (sizeof(x) == 2) ?                              \
+       (((unsigned long long int)(x)) & 0xffff) :      \
+       ((sizeof(x) == 4) ?                             \
+        (((unsigned long long int)(x)) & 0xffffffff) : \
+        (unsigned long long int)(x))
+
 #define ATH_TXBUF_RESET(_bf) do {                              \
                (_bf)->bf_lastbf = NULL;                        \
                (_bf)->bf_next = NULL;                          \
@@ -77,23 +63,6 @@ struct ath_config {
                       sizeof(struct ath_buf_state));           \
        } while (0)
 
-/**
- * enum buffer_type - Buffer type flags
- *
- * @BUF_AMPDU: This buffer is an ampdu, as part of an aggregate (during TX)
- * @BUF_AGGR: Indicates whether the buffer can be aggregated
- *     (used in aggregation scheduling)
- */
-enum buffer_type {
-       BUF_AMPDU               = BIT(0),
-       BUF_AGGR                = BIT(1),
-};
-
-#define bf_isampdu(bf)         (bf->bf_state.bf_type & BUF_AMPDU)
-#define bf_isaggr(bf)          (bf->bf_state.bf_type & BUF_AGGR)
-
-#define ATH_TXSTATUS_RING_SIZE 512
-
 #define        DS2PHYS(_dd, _ds)                                               \
        ((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc))
 #define ATH_DESC_4KB_BOUND_CHECK(_daddr) ((((_daddr) & 0xFFF) > 0xF7F) ? 1 : 0)
@@ -113,11 +82,20 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
 /* RX / TX */
 /***********/
 
+#define        ATH_TXQ_SETUP(sc, i) ((sc)->tx.txqsetup & (1<<i))
+
+/* increment with wrap-around */
+#define INCR(_l, _sz)   do {                   \
+               (_l)++;                         \
+               (_l) &= ((_sz) - 1);            \
+       } while (0)
+
 #define ATH_RXBUF               512
 #define ATH_TXBUF               512
 #define ATH_TXBUF_RESERVE       5
 #define ATH_MAX_QDEPTH          (ATH_TXBUF / 4 - ATH_TXBUF_RESERVE)
 #define ATH_TXMAXTRY            13
+#define ATH_MAX_SW_RETRIES      30
 
 #define TID_TO_WME_AC(_tid)                            \
        ((((_tid) == 0) || ((_tid) == 3)) ? IEEE80211_AC_BE :   \
@@ -133,6 +111,9 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
 #define ATH_AGGR_MIN_QDEPTH        2
 /* minimum h/w qdepth for non-aggregated traffic */
 #define ATH_NON_AGGR_MIN_QDEPTH    8
+#define ATH_TX_COMPLETE_POLL_INT   1000
+#define ATH_TXFIFO_DEPTH           8
+#define ATH_TX_ERROR               0x01
 
 #define IEEE80211_SEQ_SEQ_SHIFT    4
 #define IEEE80211_SEQ_MAX          4096
@@ -167,9 +148,6 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
 
 #define IS_CCK_RATE(rate) ((rate >= 0x18) && (rate <= 0x1e))
 
-#define ATH_TX_COMPLETE_POLL_INT       1000
-
-#define ATH_TXFIFO_DEPTH 8
 struct ath_txq {
        int mac80211_qnum; /* mac80211 queue number, -1 means not mac80211 Q */
        u32 axq_qnum; /* ath9k hardware queue number */
@@ -214,6 +192,21 @@ struct ath_rxbuf {
        dma_addr_t bf_buf_addr;
 };
 
+/**
+ * enum buffer_type - Buffer type flags
+ *
+ * @BUF_AMPDU: This buffer is an ampdu, as part of an aggregate (during TX)
+ * @BUF_AGGR: Indicates whether the buffer can be aggregated
+ *     (used in aggregation scheduling)
+ */
+enum buffer_type {
+       BUF_AMPDU               = BIT(0),
+       BUF_AGGR                = BIT(1),
+};
+
+#define bf_isampdu(bf)         (bf->bf_state.bf_type & BUF_AMPDU)
+#define bf_isaggr(bf)          (bf->bf_state.bf_type & BUF_AGGR)
+
 struct ath_buf_state {
        u8 bf_type;
        u8 bfs_paprd;
@@ -278,7 +271,6 @@ struct ath_tx_control {
        struct ieee80211_sta *sta;
 };
 
-#define ATH_TX_ERROR        0x01
 
 /**
  * @txq_map:  Index is mac80211 queue number.  This is
@@ -372,6 +364,22 @@ struct ath_vif {
        struct ath_buf *av_bcbuf;
 };
 
+struct ath9k_vif_iter_data {
+       u8 hw_macaddr[ETH_ALEN]; /* address of the first vif */
+       u8 mask[ETH_ALEN]; /* bssid mask */
+       bool has_hw_macaddr;
+
+       int naps;      /* number of AP vifs */
+       int nmeshes;   /* number of mesh vifs */
+       int nstations; /* number of station vifs */
+       int nwds;      /* number of WDS vifs */
+       int nadhocs;   /* number of adhoc vifs */
+};
+
+void ath9k_calculate_iter_data(struct ieee80211_hw *hw,
+                              struct ieee80211_vif *vif,
+                              struct ath9k_vif_iter_data *iter_data);
+
 /*******************/
 /* Beacon Handling */
 /*******************/
@@ -387,6 +395,9 @@ struct ath_vif {
 #define ATH_DEFAULT_BMISS_LIMIT        10
 #define IEEE80211_MS_TO_TU(x)           (((x) * 1000) / 1024)
 
+#define TSF_TO_TU(_h,_l) \
+       ((((u32)(_h)) << 22) | (((u32)(_l)) >> 10))
+
 struct ath_beacon_config {
        int beacon_interval;
        u16 listen_interval;
@@ -420,12 +431,10 @@ struct ath_beacon {
 };
 
 void ath9k_beacon_tasklet(unsigned long data);
-bool ath9k_allow_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif);
 void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif,
                         u32 changed);
 void ath9k_beacon_assign_slot(struct ath_softc *sc, struct ieee80211_vif *vif);
 void ath9k_beacon_remove_slot(struct ath_softc *sc, struct ieee80211_vif *vif);
-void ath9k_set_tsfadjust(struct ath_softc *sc, struct ieee80211_vif *vif);
 void ath9k_set_beacon(struct ath_softc *sc);
 bool ath9k_csa_is_finished(struct ath_softc *sc);
 
@@ -440,10 +449,9 @@ bool ath9k_csa_is_finished(struct ath_softc *sc);
 #define ATH_LONG_CALINTERVAL_INT  1000    /* 1000 ms */
 #define ATH_LONG_CALINTERVAL      30000   /* 30 seconds */
 #define ATH_RESTART_CALINTERVAL   1200000 /* 20 minutes */
-#define ATH_ANI_MAX_SKIP_COUNT  10
-
-#define ATH_PAPRD_TIMEOUT      100 /* msecs */
-#define ATH_PLL_WORK_INTERVAL   100
+#define ATH_ANI_MAX_SKIP_COUNT    10
+#define ATH_PAPRD_TIMEOUT         100 /* msecs */
+#define ATH_PLL_WORK_INTERVAL     100
 
 void ath_tx_complete_poll_work(struct work_struct *work);
 void ath_reset_work(struct work_struct *work);
@@ -477,20 +485,19 @@ enum bt_op_flags {
 };
 
 struct ath_btcoex {
-       bool hw_timer_enabled;
        spinlock_t btcoex_lock;
        struct timer_list period_timer; /* Timer for BT period */
+       struct timer_list no_stomp_timer;
        u32 bt_priority_cnt;
        unsigned long bt_priority_time;
        unsigned long op_flags;
        int bt_stomp_type; /* Types of BT stomping */
-       u32 btcoex_no_stomp; /* in usec */
+       u32 btcoex_no_stomp; /* in msec */
        u32 btcoex_period; /* in msec */
-       u32 btscan_no_stomp; /* in usec */
+       u32 btscan_no_stomp; /* in msec */
        u32 duty_cycle;
        u32 bt_wait_time;
        int rssi_count;
-       struct ath_gen_timer *no_stomp_timer; /* Timer for no BT stomping */
        struct ath_mci_profile mci;
        u8 stomp_audio;
 };
@@ -538,12 +545,6 @@ static inline int ath9k_dump_btcoex(struct ath_softc *sc, u8 *buf, u32 size)
 }
 #endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */
 
-struct ath9k_wow_pattern {
-       u8 pattern_bytes[MAX_PATTERN_SIZE];
-       u8 mask_bytes[MAX_PATTERN_SIZE];
-       u32 pattern_len;
-};
-
 /********************/
 /*   LED Control    */
 /********************/
@@ -575,6 +576,12 @@ static inline void ath_fill_led_pin(struct ath_softc *sc)
 /* Wake on Wireless LAN */
 /************************/
 
+struct ath9k_wow_pattern {
+       u8 pattern_bytes[MAX_PATTERN_SIZE];
+       u8 mask_bytes[MAX_PATTERN_SIZE];
+       u32 pattern_len;
+};
+
 #ifdef CONFIG_ATH9K_WOW
 void ath9k_init_wow(struct ieee80211_hw *hw);
 int ath9k_suspend(struct ieee80211_hw *hw,
@@ -678,13 +685,8 @@ void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs);
  * Used when PCI device not fully initialized by bootrom/BIOS
 */
 #define DEFAULT_CACHELINE       32
-#define ATH_REGCLASSIDS_MAX     10
 #define ATH_CABQ_READY_TIME     80      /* % of beacon interval */
-#define ATH_MAX_SW_RETRIES      30
-#define ATH_CHAN_MAX            255
-
 #define ATH_TXPOWER_MAX         100     /* .5 dBm units */
-#define ATH_RATE_DUMMY_MARKER   0
 
 enum sc_op_flags {
        SC_OP_INVALID,
@@ -703,37 +705,6 @@ enum sc_op_flags {
 #define PS_BEACON_SYNC            BIT(4)
 #define PS_WAIT_FOR_ANI           BIT(5)
 
-struct ath_rate_table;
-
-struct ath9k_vif_iter_data {
-       u8 hw_macaddr[ETH_ALEN]; /* address of the first vif */
-       u8 mask[ETH_ALEN]; /* bssid mask */
-       bool has_hw_macaddr;
-
-       int naps;      /* number of AP vifs */
-       int nmeshes;   /* number of mesh vifs */
-       int nstations; /* number of station vifs */
-       int nwds;      /* number of WDS vifs */
-       int nadhocs;   /* number of adhoc vifs */
-};
-
-/* enum spectral_mode:
- *
- * @SPECTRAL_DISABLED: spectral mode is disabled
- * @SPECTRAL_BACKGROUND: hardware sends samples when it is not busy with
- *     something else.
- * @SPECTRAL_MANUAL: spectral scan is enabled, triggering for samples
- *     is performed manually.
- * @SPECTRAL_CHANSCAN: Like manual, but also triggered when changing channels
- *     during a channel scan.
- */
-enum spectral_mode {
-       SPECTRAL_DISABLED = 0,
-       SPECTRAL_BACKGROUND,
-       SPECTRAL_MANUAL,
-       SPECTRAL_CHANSCAN,
-};
-
 struct ath_softc {
        struct ieee80211_hw *hw;
        struct device *dev;
@@ -823,162 +794,6 @@ struct ath_softc {
 #endif
 };
 
-#define SPECTRAL_SCAN_BITMASK          0x10
-/* Radar info packet format, used for DFS and spectral formats. */
-struct ath_radar_info {
-       u8 pulse_length_pri;
-       u8 pulse_length_ext;
-       u8 pulse_bw_info;
-} __packed;
-
-/* The HT20 spectral data has 4 bytes of additional information at it's end.
- *
- * [7:0]: all bins {max_magnitude[1:0], bitmap_weight[5:0]}
- * [7:0]: all bins  max_magnitude[9:2]
- * [7:0]: all bins {max_index[5:0], max_magnitude[11:10]}
- * [3:0]: max_exp (shift amount to size max bin to 8-bit unsigned)
- */
-struct ath_ht20_mag_info {
-       u8 all_bins[3];
-       u8 max_exp;
-} __packed;
-
-#define SPECTRAL_HT20_NUM_BINS         56
-
-/* WARNING: don't actually use this struct! MAC may vary the amount of
- * data by -1/+2. This struct is for reference only.
- */
-struct ath_ht20_fft_packet {
-       u8 data[SPECTRAL_HT20_NUM_BINS];
-       struct ath_ht20_mag_info mag_info;
-       struct ath_radar_info radar_info;
-} __packed;
-
-#define SPECTRAL_HT20_TOTAL_DATA_LEN   (sizeof(struct ath_ht20_fft_packet))
-
-/* Dynamic 20/40 mode:
- *
- * [7:0]: lower bins {max_magnitude[1:0], bitmap_weight[5:0]}
- * [7:0]: lower bins  max_magnitude[9:2]
- * [7:0]: lower bins {max_index[5:0], max_magnitude[11:10]}
- * [7:0]: upper bins {max_magnitude[1:0], bitmap_weight[5:0]}
- * [7:0]: upper bins  max_magnitude[9:2]
- * [7:0]: upper bins {max_index[5:0], max_magnitude[11:10]}
- * [3:0]: max_exp (shift amount to size max bin to 8-bit unsigned)
- */
-struct ath_ht20_40_mag_info {
-       u8 lower_bins[3];
-       u8 upper_bins[3];
-       u8 max_exp;
-} __packed;
-
-#define SPECTRAL_HT20_40_NUM_BINS              128
-
-/* WARNING: don't actually use this struct! MAC may vary the amount of
- * data. This struct is for reference only.
- */
-struct ath_ht20_40_fft_packet {
-       u8 data[SPECTRAL_HT20_40_NUM_BINS];
-       struct ath_ht20_40_mag_info mag_info;
-       struct ath_radar_info radar_info;
-} __packed;
-
-
-#define SPECTRAL_HT20_40_TOTAL_DATA_LEN        (sizeof(struct ath_ht20_40_fft_packet))
-
-/* grabs the max magnitude from the all/upper/lower bins */
-static inline u16 spectral_max_magnitude(u8 *bins)
-{
-       return (bins[0] & 0xc0) >> 6 |
-              (bins[1] & 0xff) << 2 |
-              (bins[2] & 0x03) << 10;
-}
-
-/* return the max magnitude from the all/upper/lower bins */
-static inline u8 spectral_max_index(u8 *bins)
-{
-       s8 m = (bins[2] & 0xfc) >> 2;
-
-       /* TODO: this still doesn't always report the right values ... */
-       if (m > 32)
-               m |= 0xe0;
-       else
-               m &= ~0xe0;
-
-       return m + 29;
-}
-
-/* return the bitmap weight from the all/upper/lower bins */
-static inline u8 spectral_bitmap_weight(u8 *bins)
-{
-       return bins[0] & 0x3f;
-}
-
-/* FFT sample format given to userspace via debugfs.
- *
- * Please keep the type/length at the front position and change
- * other fields after adding another sample type
- *
- * TODO: this might need rework when switching to nl80211-based
- * interface.
- */
-enum ath_fft_sample_type {
-       ATH_FFT_SAMPLE_HT20 = 1,
-       ATH_FFT_SAMPLE_HT20_40,
-};
-
-struct fft_sample_tlv {
-       u8 type;        /* see ath_fft_sample */
-       __be16 length;
-       /* type dependent data follows */
-} __packed;
-
-struct fft_sample_ht20 {
-       struct fft_sample_tlv tlv;
-
-       u8 max_exp;
-
-       __be16 freq;
-       s8 rssi;
-       s8 noise;
-
-       __be16 max_magnitude;
-       u8 max_index;
-       u8 bitmap_weight;
-
-       __be64 tsf;
-
-       u8 data[SPECTRAL_HT20_NUM_BINS];
-} __packed;
-
-struct fft_sample_ht20_40 {
-       struct fft_sample_tlv tlv;
-
-       u8 channel_type;
-       __be16 freq;
-
-       s8 lower_rssi;
-       s8 upper_rssi;
-
-       __be64 tsf;
-
-       s8 lower_noise;
-       s8 upper_noise;
-
-       __be16 lower_max_magnitude;
-       __be16 upper_max_magnitude;
-
-       u8 lower_max_index;
-       u8 upper_max_index;
-
-       u8 lower_bitmap_weight;
-       u8 upper_bitmap_weight;
-
-       u8 max_exp;
-
-       u8 data[SPECTRAL_HT20_40_NUM_BINS];
-} __packed;
-
 /********/
 /* TX99 */
 /********/
@@ -999,19 +814,13 @@ static inline int ath9k_tx99_send(struct ath_softc *sc,
 }
 #endif /* CONFIG_ATH9K_TX99 */
 
-void ath9k_tasklet(unsigned long data);
-int ath_cabq_update(struct ath_softc *);
-
 static inline void ath_read_cachesize(struct ath_common *common, int *csz)
 {
        common->bus_ops->read_cachesize(common, csz);
 }
 
-extern struct ieee80211_ops ath9k_ops;
-extern int ath9k_modparam_nohwcrypt;
-extern int led_blink;
-extern bool is_ath9k_unloaded;
-
+void ath9k_tasklet(unsigned long data);
+int ath_cabq_update(struct ath_softc *);
 u8 ath9k_parse_mpdudensity(u8 mpdudensity);
 irqreturn_t ath_isr(int irq, void *dev);
 int ath_reset(struct ath_softc *sc);
@@ -1020,13 +829,12 @@ void ath_restart_work(struct ath_softc *sc);
 int ath9k_init_device(u16 devid, struct ath_softc *sc,
                    const struct ath_bus_ops *bus_ops);
 void ath9k_deinit_device(struct ath_softc *sc);
-void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw);
 void ath9k_reload_chainmask_settings(struct ath_softc *sc);
-
-void ath9k_spectral_scan_trigger(struct ieee80211_hw *hw);
-int ath9k_spectral_scan_config(struct ieee80211_hw *hw,
-                              enum spectral_mode spectral_mode);
-
+u8 ath_txchainmask_reduction(struct ath_softc *sc, u8 chainmask, u32 rate);
+void ath_start_rfkill_poll(struct ath_softc *sc);
+void ath9k_rfkill_poll_state(struct ieee80211_hw *hw);
+void ath9k_ps_wakeup(struct ath_softc *sc);
+void ath9k_ps_restore(struct ath_softc *sc);
 
 #ifdef CONFIG_ATH9K_PCI
 int ath_pci_init(void);
@@ -1044,15 +852,4 @@ static inline int ath_ahb_init(void) { return 0; };
 static inline void ath_ahb_exit(void) {};
 #endif
 
-void ath9k_ps_wakeup(struct ath_softc *sc);
-void ath9k_ps_restore(struct ath_softc *sc);
-
-u8 ath_txchainmask_reduction(struct ath_softc *sc, u8 chainmask, u32 rate);
-
-void ath_start_rfkill_poll(struct ath_softc *sc);
-void ath9k_rfkill_poll_state(struct ieee80211_hw *hw);
-void ath9k_calculate_iter_data(struct ieee80211_hw *hw,
-                              struct ieee80211_vif *vif,
-                              struct ath9k_vif_iter_data *iter_data);
-
 #endif /* ATH9K_H */
index 17be35392bb4f5134996a6e14b6bdc2547d40de9..112aff720e1377791ab939616b6c0b2ed9598e3e 100644 (file)
@@ -274,18 +274,19 @@ static int ath9k_beacon_choose_slot(struct ath_softc *sc)
        return slot;
 }
 
-void ath9k_set_tsfadjust(struct ath_softc *sc, struct ieee80211_vif *vif)
+static void ath9k_set_tsfadjust(struct ath_softc *sc, struct ieee80211_vif *vif)
 {
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
        struct ath_vif *avp = (void *)vif->drv_priv;
-       u64 tsfadjust;
+       u32 tsfadjust;
 
        if (avp->av_bslot == 0)
                return;
 
-       tsfadjust = cur_conf->beacon_interval * avp->av_bslot / ATH_BCBUF;
-       avp->tsf_adjust = cpu_to_le64(TU_TO_USEC(tsfadjust));
+       tsfadjust = cur_conf->beacon_interval * avp->av_bslot;
+       tsfadjust = TU_TO_USEC(tsfadjust) / ATH_BCBUF;
+       avp->tsf_adjust = cpu_to_le64(tsfadjust);
 
        ath_dbg(common, CONFIG, "tsfadjust is: %llu for bslot: %d\n",
                (unsigned long long)tsfadjust, avp->av_bslot);
@@ -431,6 +432,33 @@ static void ath9k_beacon_init(struct ath_softc *sc, u32 nexttbtt,
        ath9k_hw_enable_interrupts(ah);
 }
 
+/* Calculate the modulo of a 64 bit TSF snapshot with a TU divisor */
+static u32 ath9k_mod_tsf64_tu(u64 tsf, u32 div_tu)
+{
+       u32 tsf_mod, tsf_hi, tsf_lo, mod_hi, mod_lo;
+
+       tsf_mod = tsf & (BIT(10) - 1);
+       tsf_hi = tsf >> 32;
+       tsf_lo = ((u32) tsf) >> 10;
+
+       mod_hi = tsf_hi % div_tu;
+       mod_lo = ((mod_hi << 22) + tsf_lo) % div_tu;
+
+       return (mod_lo << 10) | tsf_mod;
+}
+
+static u32 ath9k_get_next_tbtt(struct ath_softc *sc, u64 tsf,
+                              unsigned int interval)
+{
+       struct ath_hw *ah = sc->sc_ah;
+       unsigned int offset;
+
+       tsf += TU_TO_USEC(FUDGE + ah->config.sw_beacon_response_time);
+       offset = ath9k_mod_tsf64_tu(tsf, interval);
+
+       return (u32) tsf + TU_TO_USEC(interval) - offset;
+}
+
 /*
  * For multi-bss ap support beacons are either staggered evenly over N slots or
  * burst together.  For the former arrange for the SWBA to be delivered for each
@@ -446,7 +474,8 @@ static void ath9k_beacon_config_ap(struct ath_softc *sc,
        /* NB: the beacon interval is kept internally in TU's */
        intval = TU_TO_USEC(conf->beacon_interval);
        intval /= ATH_BCBUF;
-       nexttbtt = intval;
+       nexttbtt = ath9k_get_next_tbtt(sc, ath9k_hw_gettsf64(ah),
+                                      conf->beacon_interval);
 
        if (conf->enable_beacon)
                ah->imask |= ATH9K_INT_SWBA;
@@ -458,7 +487,7 @@ static void ath9k_beacon_config_ap(struct ath_softc *sc,
                (conf->enable_beacon) ? "Enable" : "Disable",
                nexttbtt, intval, conf->beacon_interval);
 
-       ath9k_beacon_init(sc, nexttbtt, intval, true);
+       ath9k_beacon_init(sc, nexttbtt, intval, false);
 }
 
 /*
@@ -475,11 +504,9 @@ static void ath9k_beacon_config_sta(struct ath_softc *sc,
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
        struct ath9k_beacon_state bs;
-       int dtimperiod, dtimcount, sleepduration;
-       int cfpperiod, cfpcount;
-       u32 nexttbtt = 0, intval, tsftu;
+       int dtim_intval, sleepduration;
+       u32 nexttbtt = 0, intval;
        u64 tsf;
-       int num_beacons, offset, dtim_dec_count, cfp_dec_count;
 
        /* No need to configure beacon if we are not associated */
        if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) {
@@ -492,53 +519,25 @@ static void ath9k_beacon_config_sta(struct ath_softc *sc,
        intval = conf->beacon_interval;
 
        /*
-        * Setup dtim and cfp parameters according to
+        * Setup dtim parameters according to
         * last beacon we received (which may be none).
         */
-       dtimperiod = conf->dtim_period;
-       dtimcount = conf->dtim_count;
-       if (dtimcount >= dtimperiod)    /* NB: sanity check */
-               dtimcount = 0;
-       cfpperiod = 1;                  /* NB: no PCF support yet */
-       cfpcount = 0;
-
+       dtim_intval = intval * conf->dtim_period;
        sleepduration = conf->listen_interval * intval;
 
        /*
         * Pull nexttbtt forward to reflect the current
-        * TSF and calculate dtim+cfp state for the result.
+        * TSF and calculate dtim state for the result.
         */
        tsf = ath9k_hw_gettsf64(ah);
-       tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE;
-
-       num_beacons = tsftu / intval + 1;
-       offset = tsftu % intval;
-       nexttbtt = tsftu - offset;
-       if (offset)
-               nexttbtt += intval;
-
-       /* DTIM Beacon every dtimperiod Beacon */
-       dtim_dec_count = num_beacons % dtimperiod;
-       /* CFP every cfpperiod DTIM Beacon */
-       cfp_dec_count = (num_beacons / dtimperiod) % cfpperiod;
-       if (dtim_dec_count)
-               cfp_dec_count++;
-
-       dtimcount -= dtim_dec_count;
-       if (dtimcount < 0)
-               dtimcount += dtimperiod;
-
-       cfpcount -= cfp_dec_count;
-       if (cfpcount < 0)
-               cfpcount += cfpperiod;
-
-       bs.bs_intval = intval;
+       nexttbtt = ath9k_get_next_tbtt(sc, tsf, intval);
+
+       bs.bs_intval = TU_TO_USEC(intval);
+       bs.bs_dtimperiod = conf->dtim_period * bs.bs_intval;
        bs.bs_nexttbtt = nexttbtt;
-       bs.bs_dtimperiod = dtimperiod*intval;
-       bs.bs_nextdtim = bs.bs_nexttbtt + dtimcount*intval;
-       bs.bs_cfpperiod = cfpperiod*bs.bs_dtimperiod;
-       bs.bs_cfpnext = bs.bs_nextdtim + cfpcount*bs.bs_dtimperiod;
-       bs.bs_cfpmaxduration = 0;
+       bs.bs_nextdtim = nexttbtt;
+       if (conf->dtim_period > 1)
+               bs.bs_nextdtim = ath9k_get_next_tbtt(sc, tsf, dtim_intval);
 
        /*
         * Calculate the number of consecutive beacons to miss* before taking
@@ -566,18 +565,16 @@ static void ath9k_beacon_config_sta(struct ath_softc *sc,
         * XXX fixed at 100ms
         */
 
-       bs.bs_sleepduration = roundup(IEEE80211_MS_TO_TU(100), sleepduration);
+       bs.bs_sleepduration = TU_TO_USEC(roundup(IEEE80211_MS_TO_TU(100),
+                                                sleepduration));
        if (bs.bs_sleepduration > bs.bs_dtimperiod)
                bs.bs_sleepduration = bs.bs_dtimperiod;
 
        /* TSF out of range threshold fixed at 1 second */
        bs.bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD;
 
-       ath_dbg(common, BEACON, "tsf: %llu tsftu: %u\n", tsf, tsftu);
-       ath_dbg(common, BEACON,
-               "bmiss: %u sleep: %u cfp-period: %u maxdur: %u next: %u\n",
-               bs.bs_bmissthreshold, bs.bs_sleepduration,
-               bs.bs_cfpperiod, bs.bs_cfpmaxduration, bs.bs_cfpnext);
+       ath_dbg(common, BEACON, "bmiss: %u sleep: %u\n",
+               bs.bs_bmissthreshold, bs.bs_sleepduration);
 
        /* Set the computed STA beacon timers */
 
@@ -600,25 +597,11 @@ static void ath9k_beacon_config_adhoc(struct ath_softc *sc,
 
        intval = TU_TO_USEC(conf->beacon_interval);
 
-       if (conf->ibss_creator) {
+       if (conf->ibss_creator)
                nexttbtt = intval;
-       } else {
-               u32 tbtt, offset, tsftu;
-               u64 tsf;
-
-               /*
-                * Pull nexttbtt forward to reflect the current
-                * sync'd TSF.
-                */
-               tsf = ath9k_hw_gettsf64(ah);
-               tsftu = TSF_TO_TU(tsf >> 32, tsf) + FUDGE;
-               offset = tsftu % conf->beacon_interval;
-               tbtt = tsftu - offset;
-               if (offset)
-                       tbtt += conf->beacon_interval;
-
-               nexttbtt = TU_TO_USEC(tbtt);
-       }
+       else
+               nexttbtt = ath9k_get_next_tbtt(sc, ath9k_hw_gettsf64(ah),
+                                              conf->beacon_interval);
 
        if (conf->enable_beacon)
                ah->imask |= ATH9K_INT_SWBA;
@@ -640,7 +623,8 @@ static void ath9k_beacon_config_adhoc(struct ath_softc *sc,
                set_bit(SC_OP_BEACONS, &sc->sc_flags);
 }
 
-bool ath9k_allow_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
+static bool ath9k_allow_beacon_config(struct ath_softc *sc,
+                                     struct ieee80211_vif *vif)
 {
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ath_vif *avp = (void *)vif->drv_priv;
@@ -711,12 +695,17 @@ void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif,
        unsigned long flags;
        bool skip_beacon = false;
 
+       if (vif->type == NL80211_IFTYPE_AP)
+               ath9k_set_tsfadjust(sc, vif);
+
+       if (!ath9k_allow_beacon_config(sc, vif))
+               return;
+
        if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) {
                ath9k_cache_beacon_config(sc, bss_conf);
                ath9k_set_beacon(sc);
                set_bit(SC_OP_BEACONS, &sc->sc_flags);
                return;
-
        }
 
        /*
index 9963b0bf9f72694630cab058621547f53eeeb237..3dfc2c7f1f07862ce81238aa297b4a45cb944fd8 100644 (file)
@@ -66,7 +66,6 @@ void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum)
                .bt_first_slot_time = 5,
                .bt_hold_rx_clear = true,
        };
-       u32 i, idx;
        bool rxclear_polarity = ath_bt_config.bt_rxclear_polarity;
 
        if (AR_SREV_9300_20_OR_LATER(ah))
@@ -88,11 +87,6 @@ void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum)
                SM(ath_bt_config.bt_hold_rx_clear, AR_BT_HOLD_RX_CLEAR) |
                SM(ATH_BTCOEX_BMISS_THRESH, AR_BT_BCN_MISS_THRESH) |
                AR_BT_DISABLE_BT_ANT;
-
-       for (i = 0; i < 32; i++) {
-               idx = (debruijn32 << i) >> 27;
-               ah->hw_gen_timers.gen_timer_index[idx] = i;
-       }
 }
 EXPORT_SYMBOL(ath9k_hw_init_btcoex_hw);
 
index a7e5a05b2eff88e8d367cea6403058cc2813ebbc..768c733cad31d4ef7ae1c45bd17c2e207f2ca82f 100644 (file)
@@ -98,10 +98,8 @@ struct ath9k_channel *ath9k_cmn_get_channel(struct ieee80211_hw *hw,
 {
        struct ieee80211_channel *curchan = chandef->chan;
        struct ath9k_channel *channel;
-       u8 chan_idx;
 
-       chan_idx = curchan->hw_value;
-       channel = &ah->channels[chan_idx];
+       channel = &ah->channels[curchan->hw_value];
        ath9k_cmn_update_ichannel(channel, chandef);
 
        return channel;
index 2f7dccfdb72784bf5c098a72ed703cf3abc0f2a2..b041052a10eeaba1bd5e919422a205877a65a131 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/export.h>
-#include <linux/relay.h>
 #include <asm/unaligned.h>
 
 #include "ath9k.h"
 #define REG_READ_D(_ah, _reg) \
        ath9k_hw_common(_ah)->ops->read((_ah), (_reg))
 
+void ath9k_debug_sync_cause(struct ath_softc *sc, u32 sync_cause)
+{
+       if (sync_cause)
+               sc->debug.stats.istats.sync_cause_all++;
+       if (sync_cause & AR_INTR_SYNC_RTC_IRQ)
+               sc->debug.stats.istats.sync_rtc_irq++;
+       if (sync_cause & AR_INTR_SYNC_MAC_IRQ)
+               sc->debug.stats.istats.sync_mac_irq++;
+       if (sync_cause & AR_INTR_SYNC_EEPROM_ILLEGAL_ACCESS)
+               sc->debug.stats.istats.eeprom_illegal_access++;
+       if (sync_cause & AR_INTR_SYNC_APB_TIMEOUT)
+               sc->debug.stats.istats.apb_timeout++;
+       if (sync_cause & AR_INTR_SYNC_PCI_MODE_CONFLICT)
+               sc->debug.stats.istats.pci_mode_conflict++;
+       if (sync_cause & AR_INTR_SYNC_HOST1_FATAL)
+               sc->debug.stats.istats.host1_fatal++;
+       if (sync_cause & AR_INTR_SYNC_HOST1_PERR)
+               sc->debug.stats.istats.host1_perr++;
+       if (sync_cause & AR_INTR_SYNC_TRCV_FIFO_PERR)
+               sc->debug.stats.istats.trcv_fifo_perr++;
+       if (sync_cause & AR_INTR_SYNC_RADM_CPL_EP)
+               sc->debug.stats.istats.radm_cpl_ep++;
+       if (sync_cause & AR_INTR_SYNC_RADM_CPL_DLLP_ABORT)
+               sc->debug.stats.istats.radm_cpl_dllp_abort++;
+       if (sync_cause & AR_INTR_SYNC_RADM_CPL_TLP_ABORT)
+               sc->debug.stats.istats.radm_cpl_tlp_abort++;
+       if (sync_cause & AR_INTR_SYNC_RADM_CPL_ECRC_ERR)
+               sc->debug.stats.istats.radm_cpl_ecrc_err++;
+       if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT)
+               sc->debug.stats.istats.radm_cpl_timeout++;
+       if (sync_cause & AR_INTR_SYNC_LOCAL_TIMEOUT)
+               sc->debug.stats.istats.local_timeout++;
+       if (sync_cause & AR_INTR_SYNC_PM_ACCESS)
+               sc->debug.stats.istats.pm_access++;
+       if (sync_cause & AR_INTR_SYNC_MAC_AWAKE)
+               sc->debug.stats.istats.mac_awake++;
+       if (sync_cause & AR_INTR_SYNC_MAC_ASLEEP)
+               sc->debug.stats.istats.mac_asleep++;
+       if (sync_cause & AR_INTR_SYNC_MAC_SLEEP_ACCESS)
+               sc->debug.stats.istats.mac_sleep_access++;
+}
 
 static ssize_t ath9k_debugfs_read_buf(struct file *file, char __user *user_buf,
                                      size_t count, loff_t *ppos)
@@ -1016,293 +1056,6 @@ static const struct file_operations fops_recv = {
        .llseek = default_llseek,
 };
 
-static ssize_t read_file_spec_scan_ctl(struct file *file, char __user *user_buf,
-                                      size_t count, loff_t *ppos)
-{
-       struct ath_softc *sc = file->private_data;
-       char *mode = "";
-       unsigned int len;
-
-       switch (sc->spectral_mode) {
-       case SPECTRAL_DISABLED:
-               mode = "disable";
-               break;
-       case SPECTRAL_BACKGROUND:
-               mode = "background";
-               break;
-       case SPECTRAL_CHANSCAN:
-               mode = "chanscan";
-               break;
-       case SPECTRAL_MANUAL:
-               mode = "manual";
-               break;
-       }
-       len = strlen(mode);
-       return simple_read_from_buffer(user_buf, count, ppos, mode, len);
-}
-
-static ssize_t write_file_spec_scan_ctl(struct file *file,
-                                       const char __user *user_buf,
-                                       size_t count, loff_t *ppos)
-{
-       struct ath_softc *sc = file->private_data;
-       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-       char buf[32];
-       ssize_t len;
-
-       if (config_enabled(CONFIG_ATH9K_TX99))
-               return -EOPNOTSUPP;
-
-       len = min(count, sizeof(buf) - 1);
-       if (copy_from_user(buf, user_buf, len))
-               return -EFAULT;
-
-       buf[len] = '\0';
-
-       if (strncmp("trigger", buf, 7) == 0) {
-               ath9k_spectral_scan_trigger(sc->hw);
-       } else if (strncmp("background", buf, 9) == 0) {
-               ath9k_spectral_scan_config(sc->hw, SPECTRAL_BACKGROUND);
-               ath_dbg(common, CONFIG, "spectral scan: background mode enabled\n");
-       } else if (strncmp("chanscan", buf, 8) == 0) {
-               ath9k_spectral_scan_config(sc->hw, SPECTRAL_CHANSCAN);
-               ath_dbg(common, CONFIG, "spectral scan: channel scan mode enabled\n");
-       } else if (strncmp("manual", buf, 6) == 0) {
-               ath9k_spectral_scan_config(sc->hw, SPECTRAL_MANUAL);
-               ath_dbg(common, CONFIG, "spectral scan: manual mode enabled\n");
-       } else if (strncmp("disable", buf, 7) == 0) {
-               ath9k_spectral_scan_config(sc->hw, SPECTRAL_DISABLED);
-               ath_dbg(common, CONFIG, "spectral scan: disabled\n");
-       } else {
-               return -EINVAL;
-       }
-
-       return count;
-}
-
-static const struct file_operations fops_spec_scan_ctl = {
-       .read = read_file_spec_scan_ctl,
-       .write = write_file_spec_scan_ctl,
-       .open = simple_open,
-       .owner = THIS_MODULE,
-       .llseek = default_llseek,
-};
-
-static ssize_t read_file_spectral_short_repeat(struct file *file,
-                                              char __user *user_buf,
-                                              size_t count, loff_t *ppos)
-{
-       struct ath_softc *sc = file->private_data;
-       char buf[32];
-       unsigned int len;
-
-       len = sprintf(buf, "%d\n", sc->spec_config.short_repeat);
-       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
-}
-
-static ssize_t write_file_spectral_short_repeat(struct file *file,
-                                               const char __user *user_buf,
-                                               size_t count, loff_t *ppos)
-{
-       struct ath_softc *sc = file->private_data;
-       unsigned long val;
-       char buf[32];
-       ssize_t len;
-
-       len = min(count, sizeof(buf) - 1);
-       if (copy_from_user(buf, user_buf, len))
-               return -EFAULT;
-
-       buf[len] = '\0';
-       if (kstrtoul(buf, 0, &val))
-               return -EINVAL;
-
-       if (val < 0 || val > 1)
-               return -EINVAL;
-
-       sc->spec_config.short_repeat = val;
-       return count;
-}
-
-static const struct file_operations fops_spectral_short_repeat = {
-       .read = read_file_spectral_short_repeat,
-       .write = write_file_spectral_short_repeat,
-       .open = simple_open,
-       .owner = THIS_MODULE,
-       .llseek = default_llseek,
-};
-
-static ssize_t read_file_spectral_count(struct file *file,
-                                       char __user *user_buf,
-                                       size_t count, loff_t *ppos)
-{
-       struct ath_softc *sc = file->private_data;
-       char buf[32];
-       unsigned int len;
-
-       len = sprintf(buf, "%d\n", sc->spec_config.count);
-       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
-}
-
-static ssize_t write_file_spectral_count(struct file *file,
-                                        const char __user *user_buf,
-                                        size_t count, loff_t *ppos)
-{
-       struct ath_softc *sc = file->private_data;
-       unsigned long val;
-       char buf[32];
-       ssize_t len;
-
-       len = min(count, sizeof(buf) - 1);
-       if (copy_from_user(buf, user_buf, len))
-               return -EFAULT;
-
-       buf[len] = '\0';
-       if (kstrtoul(buf, 0, &val))
-               return -EINVAL;
-
-       if (val < 0 || val > 255)
-               return -EINVAL;
-
-       sc->spec_config.count = val;
-       return count;
-}
-
-static const struct file_operations fops_spectral_count = {
-       .read = read_file_spectral_count,
-       .write = write_file_spectral_count,
-       .open = simple_open,
-       .owner = THIS_MODULE,
-       .llseek = default_llseek,
-};
-
-static ssize_t read_file_spectral_period(struct file *file,
-                                        char __user *user_buf,
-                                        size_t count, loff_t *ppos)
-{
-       struct ath_softc *sc = file->private_data;
-       char buf[32];
-       unsigned int len;
-
-       len = sprintf(buf, "%d\n", sc->spec_config.period);
-       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
-}
-
-static ssize_t write_file_spectral_period(struct file *file,
-                                         const char __user *user_buf,
-                                         size_t count, loff_t *ppos)
-{
-       struct ath_softc *sc = file->private_data;
-       unsigned long val;
-       char buf[32];
-       ssize_t len;
-
-       len = min(count, sizeof(buf) - 1);
-       if (copy_from_user(buf, user_buf, len))
-               return -EFAULT;
-
-       buf[len] = '\0';
-       if (kstrtoul(buf, 0, &val))
-               return -EINVAL;
-
-       if (val < 0 || val > 255)
-               return -EINVAL;
-
-       sc->spec_config.period = val;
-       return count;
-}
-
-static const struct file_operations fops_spectral_period = {
-       .read = read_file_spectral_period,
-       .write = write_file_spectral_period,
-       .open = simple_open,
-       .owner = THIS_MODULE,
-       .llseek = default_llseek,
-};
-
-static ssize_t read_file_spectral_fft_period(struct file *file,
-                                            char __user *user_buf,
-                                            size_t count, loff_t *ppos)
-{
-       struct ath_softc *sc = file->private_data;
-       char buf[32];
-       unsigned int len;
-
-       len = sprintf(buf, "%d\n", sc->spec_config.fft_period);
-       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
-}
-
-static ssize_t write_file_spectral_fft_period(struct file *file,
-                                             const char __user *user_buf,
-                                             size_t count, loff_t *ppos)
-{
-       struct ath_softc *sc = file->private_data;
-       unsigned long val;
-       char buf[32];
-       ssize_t len;
-
-       len = min(count, sizeof(buf) - 1);
-       if (copy_from_user(buf, user_buf, len))
-               return -EFAULT;
-
-       buf[len] = '\0';
-       if (kstrtoul(buf, 0, &val))
-               return -EINVAL;
-
-       if (val < 0 || val > 15)
-               return -EINVAL;
-
-       sc->spec_config.fft_period = val;
-       return count;
-}
-
-static const struct file_operations fops_spectral_fft_period = {
-       .read = read_file_spectral_fft_period,
-       .write = write_file_spectral_fft_period,
-       .open = simple_open,
-       .owner = THIS_MODULE,
-       .llseek = default_llseek,
-};
-
-static struct dentry *create_buf_file_handler(const char *filename,
-                                             struct dentry *parent,
-                                             umode_t mode,
-                                             struct rchan_buf *buf,
-                                             int *is_global)
-{
-       struct dentry *buf_file;
-
-       buf_file = debugfs_create_file(filename, mode, parent, buf,
-                                      &relay_file_operations);
-       *is_global = 1;
-       return buf_file;
-}
-
-static int remove_buf_file_handler(struct dentry *dentry)
-{
-       debugfs_remove(dentry);
-
-       return 0;
-}
-
-void ath_debug_send_fft_sample(struct ath_softc *sc,
-                              struct fft_sample_tlv *fft_sample_tlv)
-{
-       int length;
-       if (!sc->rfs_chan_spec_scan)
-               return;
-
-       length = __be16_to_cpu(fft_sample_tlv->length) +
-                sizeof(*fft_sample_tlv);
-       relay_write(sc->rfs_chan_spec_scan, fft_sample_tlv, length);
-}
-
-static struct rchan_callbacks rfs_spec_scan_cb = {
-       .create_buf_file = create_buf_file_handler,
-       .remove_buf_file = remove_buf_file_handler,
-};
-
-
 static ssize_t read_file_regidx(struct file *file, char __user *user_buf,
                                 size_t count, loff_t *ppos)
 {
@@ -1772,10 +1525,7 @@ void ath9k_get_et_stats(struct ieee80211_hw *hw,
 
 void ath9k_deinit_debug(struct ath_softc *sc)
 {
-       if (config_enabled(CONFIG_ATH9K_DEBUGFS) && sc->rfs_chan_spec_scan) {
-               relay_close(sc->rfs_chan_spec_scan);
-               sc->rfs_chan_spec_scan = NULL;
-       }
+       ath9k_spectral_deinit_debug(sc);
 }
 
 int ath9k_init_debug(struct ath_hw *ah)
@@ -1795,6 +1545,7 @@ int ath9k_init_debug(struct ath_hw *ah)
 
        ath9k_dfs_init_debug(sc);
        ath9k_tx99_init_debug(sc);
+       ath9k_spectral_init_debug(sc);
 
        debugfs_create_file("dma", S_IRUSR, sc->debug.debugfs_phy, sc,
                            &fops_dma);
@@ -1841,23 +1592,6 @@ int ath9k_init_debug(struct ath_hw *ah)
                            &fops_base_eeprom);
        debugfs_create_file("modal_eeprom", S_IRUSR, sc->debug.debugfs_phy, sc,
                            &fops_modal_eeprom);
-       sc->rfs_chan_spec_scan = relay_open("spectral_scan",
-                                           sc->debug.debugfs_phy,
-                                           1024, 256, &rfs_spec_scan_cb,
-                                           NULL);
-       debugfs_create_file("spectral_scan_ctl", S_IRUSR | S_IWUSR,
-                           sc->debug.debugfs_phy, sc,
-                           &fops_spec_scan_ctl);
-       debugfs_create_file("spectral_short_repeat", S_IRUSR | S_IWUSR,
-                           sc->debug.debugfs_phy, sc,
-                           &fops_spectral_short_repeat);
-       debugfs_create_file("spectral_count", S_IRUSR | S_IWUSR,
-                           sc->debug.debugfs_phy, sc, &fops_spectral_count);
-       debugfs_create_file("spectral_period", S_IRUSR | S_IWUSR,
-                           sc->debug.debugfs_phy, sc, &fops_spectral_period);
-       debugfs_create_file("spectral_fft_period", S_IRUSR | S_IWUSR,
-                           sc->debug.debugfs_phy, sc,
-                           &fops_spectral_fft_period);
        debugfs_create_u32("gpio_mask", S_IRUSR | S_IWUSR,
                           sc->debug.debugfs_phy, &sc->sc_ah->gpio_mask);
        debugfs_create_u32("gpio_val", S_IRUSR | S_IWUSR,
index d6e3fa4299a4fa5e4f85e49502a900920d48f718..ec02d38ea8eae813b4078106a2426c2cd1862319 100644 (file)
@@ -292,11 +292,11 @@ void ath9k_sta_add_debugfs(struct ieee80211_hw *hw,
                           struct ieee80211_vif *vif,
                           struct ieee80211_sta *sta,
                           struct dentry *dir);
-void ath_debug_send_fft_sample(struct ath_softc *sc,
-                              struct fft_sample_tlv *fft_sample);
 void ath9k_debug_stat_ant(struct ath_softc *sc,
                          struct ath_hw_antcomb_conf *div_ant_conf,
                          int main_rssi_avg, int alt_rssi_avg);
+void ath9k_debug_sync_cause(struct ath_softc *sc, u32 sync_cause);
+
 #else
 
 #define RX_STAT_INC(c) /* NOP */
@@ -331,6 +331,11 @@ static inline void ath9k_debug_stat_ant(struct ath_softc *sc,
 
 }
 
+static inline void
+ath9k_debug_sync_cause(struct ath_softc *sc, u32 sync_cause)
+{
+}
+
 #endif /* CONFIG_ATH9K_DEBUGFS */
 
 #endif /* DEBUG_H */
index 7187d3671512eae62e3e1da59bb1aea9866a7be8..857bb28b389411ea2e1586abd3f5c749c0127327 100644 (file)
@@ -158,8 +158,8 @@ void ath9k_dfs_process_phyerr(struct ath_softc *sc, void *data,
                return;
        }
 
-       ard.rssi = rs->rs_rssi_ctl0;
-       ard.ext_rssi = rs->rs_rssi_ext0;
+       ard.rssi = rs->rs_rssi_ctl[0];
+       ard.ext_rssi = rs->rs_rssi_ext[0];
 
        /*
         * hardware stores this as 8 bit signed value.
index b4091716e9b3322881a6ed65fc3996a57e59a8b8..07b806c56c56b4b0a5167cd704493a85285a8b58 100644 (file)
@@ -1085,31 +1085,7 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah,
 
 static u16 ath9k_hw_4k_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz)
 {
-#define EEP_MAP4K_SPURCHAN \
-       (ah->eeprom.map4k.modalHeader.spurChans[i].spurChan)
-       struct ath_common *common = ath9k_hw_common(ah);
-
-       u16 spur_val = AR_NO_SPUR;
-
-       ath_dbg(common, ANI, "Getting spur idx:%d is2Ghz:%d val:%x\n",
-               i, is2GHz, ah->config.spurchans[i][is2GHz]);
-
-       switch (ah->config.spurmode) {
-       case SPUR_DISABLE:
-               break;
-       case SPUR_ENABLE_IOCTL:
-               spur_val = ah->config.spurchans[i][is2GHz];
-               ath_dbg(common, ANI, "Getting spur val from new loc. %d\n",
-                       spur_val);
-               break;
-       case SPUR_ENABLE_EEPROM:
-               spur_val = EEP_MAP4K_SPURCHAN;
-               break;
-       }
-
-       return spur_val;
-
-#undef EEP_MAP4K_SPURCHAN
+       return ah->eeprom.map4k.modalHeader.spurChans[i].spurChan;
 }
 
 const struct eeprom_ops eep_4k_ops = {
index e1d0c217c104f9ba6c2b0a1e55a941e2ccc63d20..5ba1385c9838016a942df4e189bf7d8a484fad6e 100644 (file)
@@ -1004,31 +1004,7 @@ static void ath9k_hw_ar9287_set_board_values(struct ath_hw *ah,
 static u16 ath9k_hw_ar9287_get_spur_channel(struct ath_hw *ah,
                                            u16 i, bool is2GHz)
 {
-#define EEP_MAP9287_SPURCHAN \
-       (ah->eeprom.map9287.modalHeader.spurChans[i].spurChan)
-
-       struct ath_common *common = ath9k_hw_common(ah);
-       u16 spur_val = AR_NO_SPUR;
-
-       ath_dbg(common, ANI, "Getting spur idx:%d is2Ghz:%d val:%x\n",
-               i, is2GHz, ah->config.spurchans[i][is2GHz]);
-
-       switch (ah->config.spurmode) {
-       case SPUR_DISABLE:
-               break;
-       case SPUR_ENABLE_IOCTL:
-               spur_val = ah->config.spurchans[i][is2GHz];
-               ath_dbg(common, ANI, "Getting spur val from new loc. %d\n",
-                       spur_val);
-               break;
-       case SPUR_ENABLE_EEPROM:
-               spur_val = EEP_MAP9287_SPURCHAN;
-               break;
-       }
-
-       return spur_val;
-
-#undef EEP_MAP9287_SPURCHAN
+       return ah->eeprom.map9287.modalHeader.spurChans[i].spurChan;
 }
 
 const struct eeprom_ops eep_ar9287_ops = {
index 39107e31e79aaa98fa93453f74db8b4e416ae457..3218ca9947463a844ed38f22956faedaca688cbb 100644 (file)
@@ -1348,31 +1348,7 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah,
 
 static u16 ath9k_hw_def_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz)
 {
-#define EEP_DEF_SPURCHAN \
-       (ah->eeprom.def.modalHeader[is2GHz].spurChans[i].spurChan)
-       struct ath_common *common = ath9k_hw_common(ah);
-
-       u16 spur_val = AR_NO_SPUR;
-
-       ath_dbg(common, ANI, "Getting spur idx:%d is2Ghz:%d val:%x\n",
-               i, is2GHz, ah->config.spurchans[i][is2GHz]);
-
-       switch (ah->config.spurmode) {
-       case SPUR_DISABLE:
-               break;
-       case SPUR_ENABLE_IOCTL:
-               spur_val = ah->config.spurchans[i][is2GHz];
-               ath_dbg(common, ANI, "Getting spur val from new loc. %d\n",
-                       spur_val);
-               break;
-       case SPUR_ENABLE_EEPROM:
-               spur_val = EEP_DEF_SPURCHAN;
-               break;
-       }
-
-       return spur_val;
-
-#undef EEP_DEF_SPURCHAN
+       return ah->eeprom.def.modalHeader[is2GHz].spurChans[i].spurChan;
 }
 
 const struct eeprom_ops eep_def_ops = {
index c34f21241da947e5297bc7ad18e6de9cc3430825..b1956bf6e01e12480fad2b0d8e580abca118399c 100644 (file)
@@ -157,36 +157,6 @@ static void ath_detect_bt_priority(struct ath_softc *sc)
        }
 }
 
-static void ath9k_gen_timer_start(struct ath_hw *ah,
-                                 struct ath_gen_timer *timer,
-                                 u32 trig_timeout,
-                                 u32 timer_period)
-{
-       ath9k_hw_gen_timer_start(ah, timer, trig_timeout, timer_period);
-
-       if ((ah->imask & ATH9K_INT_GENTIMER) == 0) {
-               ath9k_hw_disable_interrupts(ah);
-               ah->imask |= ATH9K_INT_GENTIMER;
-               ath9k_hw_set_interrupts(ah);
-               ath9k_hw_enable_interrupts(ah);
-       }
-}
-
-static void ath9k_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer)
-{
-       struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers;
-
-       ath9k_hw_gen_timer_stop(ah, timer);
-
-       /* if no timer is enabled, turn off interrupt mask */
-       if (timer_table->timer_mask.val == 0) {
-               ath9k_hw_disable_interrupts(ah);
-               ah->imask &= ~ATH9K_INT_GENTIMER;
-               ath9k_hw_set_interrupts(ah);
-               ath9k_hw_enable_interrupts(ah);
-       }
-}
-
 static void ath_mci_ftp_adjust(struct ath_softc *sc)
 {
        struct ath_btcoex *btcoex = &sc->btcoex;
@@ -257,19 +227,9 @@ static void ath_btcoex_period_timer(unsigned long data)
 
        spin_unlock_bh(&btcoex->btcoex_lock);
 
-       /*
-        * btcoex_period is in msec while (btocex/btscan_)no_stomp are in usec,
-        * ensure that we properly convert btcoex_period to usec
-        * for any comparision with (btcoex/btscan_)no_stomp.
-        */
-       if (btcoex->btcoex_period * 1000 != btcoex->btcoex_no_stomp) {
-               if (btcoex->hw_timer_enabled)
-                       ath9k_gen_timer_stop(ah, btcoex->no_stomp_timer);
-
-               ath9k_gen_timer_start(ah, btcoex->no_stomp_timer, timer_period,
-                                     timer_period * 10);
-               btcoex->hw_timer_enabled = true;
-       }
+       if (btcoex->btcoex_period != btcoex->btcoex_no_stomp)
+               mod_timer(&btcoex->no_stomp_timer,
+                        jiffies + msecs_to_jiffies(timer_period));
 
        ath9k_ps_restore(sc);
 
@@ -282,7 +242,7 @@ skip_hw_wakeup:
  * Generic tsf based hw timer which configures weight
  * registers to time slice between wlan and bt traffic
  */
-static void ath_btcoex_no_stomp_timer(void *arg)
+static void ath_btcoex_no_stomp_timer(unsigned long arg)
 {
        struct ath_softc *sc = (struct ath_softc *)arg;
        struct ath_hw *ah = sc->sc_ah;
@@ -311,24 +271,18 @@ static int ath_init_btcoex_timer(struct ath_softc *sc)
        struct ath_btcoex *btcoex = &sc->btcoex;
 
        btcoex->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD;
-       btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) * 1000 *
+       btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) *
                btcoex->btcoex_period / 100;
-       btcoex->btscan_no_stomp = (100 - ATH_BTCOEX_BTSCAN_DUTY_CYCLE) * 1000 *
+       btcoex->btscan_no_stomp = (100 - ATH_BTCOEX_BTSCAN_DUTY_CYCLE) *
                                   btcoex->btcoex_period / 100;
 
        setup_timer(&btcoex->period_timer, ath_btcoex_period_timer,
                        (unsigned long) sc);
+       setup_timer(&btcoex->no_stomp_timer, ath_btcoex_no_stomp_timer,
+                       (unsigned long) sc);
 
        spin_lock_init(&btcoex->btcoex_lock);
 
-       btcoex->no_stomp_timer = ath_gen_timer_alloc(sc->sc_ah,
-                       ath_btcoex_no_stomp_timer,
-                       ath_btcoex_no_stomp_timer,
-                       (void *) sc, AR_FIRST_NDP_TIMER);
-
-       if (!btcoex->no_stomp_timer)
-               return -ENOMEM;
-
        return 0;
 }
 
@@ -343,10 +297,7 @@ void ath9k_btcoex_timer_resume(struct ath_softc *sc)
        ath_dbg(ath9k_hw_common(ah), BTCOEX, "Starting btcoex timers\n");
 
        /* make sure duty cycle timer is also stopped when resuming */
-       if (btcoex->hw_timer_enabled) {
-               ath9k_gen_timer_stop(sc->sc_ah, btcoex->no_stomp_timer);
-               btcoex->hw_timer_enabled = false;
-       }
+       del_timer_sync(&btcoex->no_stomp_timer);
 
        btcoex->bt_priority_cnt = 0;
        btcoex->bt_priority_time = jiffies;
@@ -363,24 +314,16 @@ void ath9k_btcoex_timer_resume(struct ath_softc *sc)
 void ath9k_btcoex_timer_pause(struct ath_softc *sc)
 {
        struct ath_btcoex *btcoex = &sc->btcoex;
-       struct ath_hw *ah = sc->sc_ah;
 
        del_timer_sync(&btcoex->period_timer);
-
-       if (btcoex->hw_timer_enabled) {
-               ath9k_gen_timer_stop(ah, btcoex->no_stomp_timer);
-               btcoex->hw_timer_enabled = false;
-       }
+       del_timer_sync(&btcoex->no_stomp_timer);
 }
 
 void ath9k_btcoex_stop_gen_timer(struct ath_softc *sc)
 {
        struct ath_btcoex *btcoex = &sc->btcoex;
 
-       if (btcoex->hw_timer_enabled) {
-               ath9k_gen_timer_stop(sc->sc_ah, btcoex->no_stomp_timer);
-               btcoex->hw_timer_enabled = false;
-       }
+       del_timer_sync(&btcoex->no_stomp_timer);
 }
 
 u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc, u32 max_4ms_framelen)
@@ -400,12 +343,6 @@ u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc, u32 max_4ms_framelen)
 
 void ath9k_btcoex_handle_interrupt(struct ath_softc *sc, u32 status)
 {
-       struct ath_hw *ah = sc->sc_ah;
-
-       if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_3WIRE)
-               if (status & ATH9K_INT_GENTIMER)
-                       ath_gen_timer_isr(sc->sc_ah);
-
        if (status & ATH9K_INT_MCI)
                ath_mci_intr(sc);
 }
@@ -447,10 +384,6 @@ void ath9k_deinit_btcoex(struct ath_softc *sc)
 {
        struct ath_hw *ah = sc->sc_ah;
 
-        if ((sc->btcoex.no_stomp_timer) &&
-           ath9k_hw_get_btcoex_scheme(sc->sc_ah) == ATH_BTCOEX_CFG_3WIRE)
-               ath_gen_timer_free(sc->sc_ah, sc->btcoex.no_stomp_timer);
-
        if (ath9k_hw_mci_is_enabled(ah))
                ath_mci_cleanup(sc);
 }
index 055d7c25e090bd33ce70de75c8352dc22dbb4003..58da3468d1f0ac1b3de6522b7118640f2c80da76 100644 (file)
@@ -600,10 +600,15 @@ void ath9k_htc_rfkill_poll_state(struct ieee80211_hw *hw);
 struct base_eep_header *ath9k_htc_get_eeprom_base(struct ath9k_htc_priv *priv);
 
 #ifdef CONFIG_MAC80211_LEDS
+void ath9k_configure_leds(struct ath9k_htc_priv *priv);
 void ath9k_init_leds(struct ath9k_htc_priv *priv);
 void ath9k_deinit_leds(struct ath9k_htc_priv *priv);
 void ath9k_led_work(struct work_struct *work);
 #else
+static inline void ath9k_configure_leds(struct ath9k_htc_priv *priv)
+{
+}
+
 static inline void ath9k_init_leds(struct ath9k_htc_priv *priv)
 {
 }
index e0c03bd641821a165d8fd922bedd14c5f685d321..8b575773459677055fe6b427e8443f65796c4ae2 100644 (file)
@@ -70,11 +70,11 @@ static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv,
        struct ath9k_beacon_state bs;
        enum ath9k_int imask = 0;
        int dtimperiod, dtimcount, sleepduration;
-       int cfpperiod, cfpcount, bmiss_timeout;
+       int bmiss_timeout;
        u32 nexttbtt = 0, intval, tsftu;
        __be32 htc_imask = 0;
        u64 tsf;
-       int num_beacons, offset, dtim_dec_count, cfp_dec_count;
+       int num_beacons, offset, dtim_dec_count;
        int ret __attribute__ ((unused));
        u8 cmd_rsp;
 
@@ -84,7 +84,7 @@ static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv,
        bmiss_timeout = (ATH_DEFAULT_BMISS_LIMIT * bss_conf->beacon_interval);
 
        /*
-        * Setup dtim and cfp parameters according to
+        * Setup dtim parameters according to
         * last beacon we received (which may be none).
         */
        dtimperiod = bss_conf->dtim_period;
@@ -93,8 +93,6 @@ static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv,
        dtimcount = 1;
        if (dtimcount >= dtimperiod)    /* NB: sanity check */
                dtimcount = 0;
-       cfpperiod = 1;                  /* NB: no PCF support yet */
-       cfpcount = 0;
 
        sleepduration = intval;
        if (sleepduration <= 0)
@@ -102,7 +100,7 @@ static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv,
 
        /*
         * Pull nexttbtt forward to reflect the current
-        * TSF and calculate dtim+cfp state for the result.
+        * TSF and calculate dtim state for the result.
         */
        tsf = ath9k_hw_gettsf64(priv->ah);
        tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE;
@@ -115,26 +113,14 @@ static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv,
 
        /* DTIM Beacon every dtimperiod Beacon */
        dtim_dec_count = num_beacons % dtimperiod;
-       /* CFP every cfpperiod DTIM Beacon */
-       cfp_dec_count = (num_beacons / dtimperiod) % cfpperiod;
-       if (dtim_dec_count)
-               cfp_dec_count++;
-
        dtimcount -= dtim_dec_count;
        if (dtimcount < 0)
                dtimcount += dtimperiod;
 
-       cfpcount -= cfp_dec_count;
-       if (cfpcount < 0)
-               cfpcount += cfpperiod;
-
-       bs.bs_intval = intval;
-       bs.bs_nexttbtt = nexttbtt;
-       bs.bs_dtimperiod = dtimperiod*intval;
-       bs.bs_nextdtim = bs.bs_nexttbtt + dtimcount*intval;
-       bs.bs_cfpperiod = cfpperiod*bs.bs_dtimperiod;
-       bs.bs_cfpnext = bs.bs_nextdtim + cfpcount*bs.bs_dtimperiod;
-       bs.bs_cfpmaxduration = 0;
+       bs.bs_intval = TU_TO_USEC(intval);
+       bs.bs_nexttbtt = TU_TO_USEC(nexttbtt);
+       bs.bs_dtimperiod = dtimperiod * bs.bs_intval;
+       bs.bs_nextdtim = bs.bs_nexttbtt + dtimcount * bs.bs_intval;
 
        /*
         * Calculate the number of consecutive beacons to miss* before taking
@@ -161,7 +147,8 @@ static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv,
         * XXX fixed at 100ms
         */
 
-       bs.bs_sleepduration = roundup(IEEE80211_MS_TO_TU(100), sleepduration);
+       bs.bs_sleepduration = TU_TO_USEC(roundup(IEEE80211_MS_TO_TU(100),
+                                                sleepduration));
        if (bs.bs_sleepduration > bs.bs_dtimperiod)
                bs.bs_sleepduration = bs.bs_dtimperiod;
 
@@ -170,10 +157,8 @@ static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv,
 
        ath_dbg(common, CONFIG, "intval: %u tsf: %llu tsftu: %u\n",
                intval, tsf, tsftu);
-       ath_dbg(common, CONFIG,
-               "bmiss: %u sleep: %u cfp-period: %u maxdur: %u next: %u\n",
-               bs.bs_bmissthreshold, bs.bs_sleepduration,
-               bs.bs_cfpperiod, bs.bs_cfpmaxduration, bs.bs_cfpnext);
+       ath_dbg(common, CONFIG, "bmiss: %u sleep: %u\n",
+               bs.bs_bmissthreshold, bs.bs_sleepduration);
 
        /* Set the computed STA beacon timers */
 
index 105582d6b714956e124b291b56480d0c3c0adb6e..50f74a2a4cf8f99b8a619d7502cc6a225fa9005c 100644 (file)
@@ -255,6 +255,17 @@ void ath9k_deinit_leds(struct ath9k_htc_priv *priv)
        cancel_work_sync(&priv->led_work);
 }
 
+
+void ath9k_configure_leds(struct ath9k_htc_priv *priv)
+{
+       /* Configure gpio 1 for output */
+       ath9k_hw_cfg_output(priv->ah, priv->ah->led_pin,
+                           AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
+       /* LED off, active low */
+       ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 1);
+
+}
+
 void ath9k_init_leds(struct ath9k_htc_priv *priv)
 {
        int ret;
@@ -268,11 +279,7 @@ void ath9k_init_leds(struct ath9k_htc_priv *priv)
        else
                priv->ah->led_pin = ATH_LED_PIN_DEF;
 
-       /* Configure gpio 1 for output */
-       ath9k_hw_cfg_output(priv->ah, priv->ah->led_pin,
-                           AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
-       /* LED off, active low */
-       ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 1);
+       ath9k_configure_leds(priv);
 
        snprintf(priv->led_name, sizeof(priv->led_name),
                "ath9k_htc-%s", wiphy_name(priv->hw->wiphy));
index c3676bf1d6c45ab92d8a161d18ad5f3f0c586d18..b576c44bb31499a8e33c2f17cf9049f7ef205bdf 100644 (file)
@@ -1000,6 +1000,8 @@ int ath9k_htc_resume(struct htc_target *htc_handle)
 
        ret = ath9k_init_htc_services(priv, priv->ah->hw_version.devid,
                                      priv->ah->hw_version.usbdev);
+       ath9k_configure_leds(priv);
+
        return ret;
 }
 #endif
index 4f9378ddf07f21455a33a908180b9a28729bf6cd..cc58a8ee1223af3cab28878da2b40373794f4449 100644 (file)
@@ -49,9 +49,10 @@ static inline bool ath9k_hw_calibrate(struct ath_hw *ah,
        return ath9k_hw_ops(ah)->calibrate(ah, chan, rxchainmask, longcal);
 }
 
-static inline bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked)
+static inline bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked,
+                                  u32 *sync_cause_p)
 {
-       return ath9k_hw_ops(ah)->get_isr(ah, masked);
+       return ath9k_hw_ops(ah)->get_isr(ah, masked, sync_cause_p);
 }
 
 static inline void ath9k_hw_set_txdesc(struct ath_hw *ah, void *ds,
index 4ee24b1eec38fa12ba86c838573a31b8d808f28f..a4b1ae0262167144d7ecea0d7d6db95da356a4b1 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/time.h>
+#include <linux/bitops.h>
 #include <asm/unaligned.h>
 
 #include "hw.h"
@@ -84,48 +85,6 @@ static void ath9k_hw_ani_cache_ini_regs(struct ath_hw *ah)
 
 #ifdef CONFIG_ATH9K_DEBUGFS
 
-void ath9k_debug_sync_cause(struct ath_common *common, u32 sync_cause)
-{
-       struct ath_softc *sc = common->priv;
-       if (sync_cause)
-               sc->debug.stats.istats.sync_cause_all++;
-       if (sync_cause & AR_INTR_SYNC_RTC_IRQ)
-               sc->debug.stats.istats.sync_rtc_irq++;
-       if (sync_cause & AR_INTR_SYNC_MAC_IRQ)
-               sc->debug.stats.istats.sync_mac_irq++;
-       if (sync_cause & AR_INTR_SYNC_EEPROM_ILLEGAL_ACCESS)
-               sc->debug.stats.istats.eeprom_illegal_access++;
-       if (sync_cause & AR_INTR_SYNC_APB_TIMEOUT)
-               sc->debug.stats.istats.apb_timeout++;
-       if (sync_cause & AR_INTR_SYNC_PCI_MODE_CONFLICT)
-               sc->debug.stats.istats.pci_mode_conflict++;
-       if (sync_cause & AR_INTR_SYNC_HOST1_FATAL)
-               sc->debug.stats.istats.host1_fatal++;
-       if (sync_cause & AR_INTR_SYNC_HOST1_PERR)
-               sc->debug.stats.istats.host1_perr++;
-       if (sync_cause & AR_INTR_SYNC_TRCV_FIFO_PERR)
-               sc->debug.stats.istats.trcv_fifo_perr++;
-       if (sync_cause & AR_INTR_SYNC_RADM_CPL_EP)
-               sc->debug.stats.istats.radm_cpl_ep++;
-       if (sync_cause & AR_INTR_SYNC_RADM_CPL_DLLP_ABORT)
-               sc->debug.stats.istats.radm_cpl_dllp_abort++;
-       if (sync_cause & AR_INTR_SYNC_RADM_CPL_TLP_ABORT)
-               sc->debug.stats.istats.radm_cpl_tlp_abort++;
-       if (sync_cause & AR_INTR_SYNC_RADM_CPL_ECRC_ERR)
-               sc->debug.stats.istats.radm_cpl_ecrc_err++;
-       if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT)
-               sc->debug.stats.istats.radm_cpl_timeout++;
-       if (sync_cause & AR_INTR_SYNC_LOCAL_TIMEOUT)
-               sc->debug.stats.istats.local_timeout++;
-       if (sync_cause & AR_INTR_SYNC_PM_ACCESS)
-               sc->debug.stats.istats.pm_access++;
-       if (sync_cause & AR_INTR_SYNC_MAC_AWAKE)
-               sc->debug.stats.istats.mac_awake++;
-       if (sync_cause & AR_INTR_SYNC_MAC_ASLEEP)
-               sc->debug.stats.istats.mac_asleep++;
-       if (sync_cause & AR_INTR_SYNC_MAC_SLEEP_ACCESS)
-               sc->debug.stats.istats.mac_sleep_access++;
-}
 #endif
 
 
@@ -438,21 +397,12 @@ static bool ath9k_hw_chip_test(struct ath_hw *ah)
 
 static void ath9k_hw_init_config(struct ath_hw *ah)
 {
-       int i;
-
        ah->config.dma_beacon_response_time = 1;
        ah->config.sw_beacon_response_time = 6;
-       ah->config.additional_swba_backoff = 0;
        ah->config.ack_6mb = 0x0;
        ah->config.cwm_ignore_extcca = 0;
-       ah->config.pcie_clock_req = 0;
        ah->config.analog_shiftreg = 1;
 
-       for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
-               ah->config.spurchans[i][0] = AR_NO_SPUR;
-               ah->config.spurchans[i][1] = AR_NO_SPUR;
-       }
-
        ah->config.rx_intr_mitigation = true;
 
        /*
@@ -485,7 +435,6 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah)
        ah->hw_version.magic = AR5416_MAGIC;
        ah->hw_version.subvendorid = 0;
 
-       ah->atim_window = 0;
        ah->sta_id1_defaults =
                AR_STA_ID1_CRPT_MIC_ENABLE |
                AR_STA_ID1_MCAST_KSRCH;
@@ -1281,6 +1230,42 @@ void ath9k_hw_get_delta_slope_vals(struct ath_hw *ah, u32 coef_scaled,
        *coef_exponent = coef_exp - 16;
 }
 
+/* AR9330 WAR:
+ * call external reset function to reset WMAC if:
+ * - doing a cold reset
+ * - we have pending frames in the TX queues.
+ */
+static bool ath9k_hw_ar9330_reset_war(struct ath_hw *ah, int type)
+{
+       int i, npend = 0;
+
+       for (i = 0; i < AR_NUM_QCU; i++) {
+               npend = ath9k_hw_numtxpending(ah, i);
+               if (npend)
+                       break;
+       }
+
+       if (ah->external_reset &&
+           (npend || type == ATH9K_RESET_COLD)) {
+               int reset_err = 0;
+
+               ath_dbg(ath9k_hw_common(ah), RESET,
+                       "reset MAC via external reset\n");
+
+               reset_err = ah->external_reset();
+               if (reset_err) {
+                       ath_err(ath9k_hw_common(ah),
+                               "External reset failed, err=%d\n",
+                               reset_err);
+                       return false;
+               }
+
+               REG_WRITE(ah, AR_RTC_RESET, 1);
+       }
+
+       return true;
+}
+
 static bool ath9k_hw_set_reset(struct ath_hw *ah, int type)
 {
        u32 rst_flags;
@@ -1331,38 +1316,8 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type)
        }
 
        if (AR_SREV_9330(ah)) {
-               int npend = 0;
-               int i;
-
-               /* AR9330 WAR:
-                * call external reset function to reset WMAC if:
-                * - doing a cold reset
-                * - we have pending frames in the TX queues
-                */
-
-               for (i = 0; i < AR_NUM_QCU; i++) {
-                       npend = ath9k_hw_numtxpending(ah, i);
-                       if (npend)
-                               break;
-               }
-
-               if (ah->external_reset &&
-                   (npend || type == ATH9K_RESET_COLD)) {
-                       int reset_err = 0;
-
-                       ath_dbg(ath9k_hw_common(ah), RESET,
-                               "reset MAC via external reset\n");
-
-                       reset_err = ah->external_reset();
-                       if (reset_err) {
-                               ath_err(ath9k_hw_common(ah),
-                                       "External reset failed, err=%d\n",
-                                       reset_err);
-                               return false;
-                       }
-
-                       REG_WRITE(ah, AR_RTC_RESET, 1);
-               }
+               if (!ath9k_hw_ar9330_reset_war(ah, type))
+                       return false;
        }
 
        if (ath9k_hw_mci_is_enabled(ah))
@@ -1372,7 +1327,12 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type)
 
        REGWRITE_BUFFER_FLUSH(ah);
 
-       udelay(50);
+       if (AR_SREV_9300_20_OR_LATER(ah))
+               udelay(50);
+       else if (AR_SREV_9100(ah))
+               udelay(10000);
+       else
+               udelay(100);
 
        REG_WRITE(ah, AR_RTC_RC, 0);
        if (!ath9k_hw_wait(ah, AR_RTC_RC, AR_RTC_RC_M, 0, AH_WAIT_TIMEOUT)) {
@@ -1408,8 +1368,7 @@ static bool ath9k_hw_set_reset_power_on(struct ath_hw *ah)
 
        REGWRITE_BUFFER_FLUSH(ah);
 
-       if (!AR_SREV_9300_20_OR_LATER(ah))
-               udelay(2);
+       udelay(2);
 
        if (!AR_SREV_9100(ah) && !AR_SREV_9300_20_OR_LATER(ah))
                REG_WRITE(ah, AR_RC, 0);
@@ -1485,7 +1444,6 @@ static bool ath9k_hw_chip_reset(struct ath_hw *ah,
        if (AR_SREV_9330(ah))
                ar9003_hw_internal_regulator_apply(ah);
        ath9k_hw_init_pll(ah, chan);
-       ath9k_hw_set_rfmode(ah, chan);
 
        return true;
 }
@@ -1954,6 +1912,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        if (r)
                return r;
 
+       ath9k_hw_set_rfmode(ah, chan);
+
        if (ath9k_hw_mci_is_enabled(ah))
                ar9003_mci_reset(ah, false, IS_CHAN_2GHZ(chan), save_fullsleep);
 
@@ -2264,9 +2224,6 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period)
        case NL80211_IFTYPE_ADHOC:
                REG_SET_BIT(ah, AR_TXCFG,
                            AR_TXCFG_ADHOC_BEACON_ATIM_TX_POLICY);
-               REG_WRITE(ah, AR_NEXT_NDP_TIMER, next_beacon +
-                         TU_TO_USEC(ah->atim_window ? ah->atim_window : 1));
-               flags |= AR_NDP_TIMER_EN;
        case NL80211_IFTYPE_MESH_POINT:
        case NL80211_IFTYPE_AP:
                REG_WRITE(ah, AR_NEXT_TBTT_TIMER, next_beacon);
@@ -2287,7 +2244,6 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period)
        REG_WRITE(ah, AR_BEACON_PERIOD, beacon_period);
        REG_WRITE(ah, AR_DMA_BEACON_PERIOD, beacon_period);
        REG_WRITE(ah, AR_SWBA_PERIOD, beacon_period);
-       REG_WRITE(ah, AR_NDP_PERIOD, beacon_period);
 
        REGWRITE_BUFFER_FLUSH(ah);
 
@@ -2304,12 +2260,9 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
 
        ENABLE_REGWRITE_BUFFER(ah);
 
-       REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(bs->bs_nexttbtt));
-
-       REG_WRITE(ah, AR_BEACON_PERIOD,
-                 TU_TO_USEC(bs->bs_intval));
-       REG_WRITE(ah, AR_DMA_BEACON_PERIOD,
-                 TU_TO_USEC(bs->bs_intval));
+       REG_WRITE(ah, AR_NEXT_TBTT_TIMER, bs->bs_nexttbtt);
+       REG_WRITE(ah, AR_BEACON_PERIOD, bs->bs_intval);
+       REG_WRITE(ah, AR_DMA_BEACON_PERIOD, bs->bs_intval);
 
        REGWRITE_BUFFER_FLUSH(ah);
 
@@ -2337,9 +2290,8 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
 
        ENABLE_REGWRITE_BUFFER(ah);
 
-       REG_WRITE(ah, AR_NEXT_DTIM,
-                 TU_TO_USEC(bs->bs_nextdtim - SLEEP_SLOP));
-       REG_WRITE(ah, AR_NEXT_TIM, TU_TO_USEC(nextTbtt - SLEEP_SLOP));
+       REG_WRITE(ah, AR_NEXT_DTIM, bs->bs_nextdtim - SLEEP_SLOP);
+       REG_WRITE(ah, AR_NEXT_TIM, nextTbtt - SLEEP_SLOP);
 
        REG_WRITE(ah, AR_SLEEP1,
                  SM((CAB_TIMEOUT_VAL << 3), AR_SLEEP1_CAB_TIMEOUT)
@@ -2353,8 +2305,8 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
        REG_WRITE(ah, AR_SLEEP2,
                  SM(beacontimeout, AR_SLEEP2_BEACON_TIMEOUT));
 
-       REG_WRITE(ah, AR_TIM_PERIOD, TU_TO_USEC(beaconintval));
-       REG_WRITE(ah, AR_DTIM_PERIOD, TU_TO_USEC(dtimperiod));
+       REG_WRITE(ah, AR_TIM_PERIOD, beaconintval);
+       REG_WRITE(ah, AR_DTIM_PERIOD, dtimperiod);
 
        REGWRITE_BUFFER_FLUSH(ah);
 
@@ -2990,20 +2942,6 @@ static const struct ath_gen_timer_configuration gen_tmr_configuration[] =
 
 /* HW generic timer primitives */
 
-/* compute and clear index of rightmost 1 */
-static u32 rightmost_index(struct ath_gen_timer_table *timer_table, u32 *mask)
-{
-       u32 b;
-
-       b = *mask;
-       b &= (0-b);
-       *mask &= ~b;
-       b *= debruijn32;
-       b >>= 27;
-
-       return timer_table->gen_timer_index[b];
-}
-
 u32 ath9k_hw_gettsf32(struct ath_hw *ah)
 {
        return REG_READ(ah, AR_TSF_L32);
@@ -3019,6 +2957,10 @@ struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah,
        struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers;
        struct ath_gen_timer *timer;
 
+       if ((timer_index < AR_FIRST_NDP_TIMER) ||
+               (timer_index >= ATH_MAX_GEN_TIMER))
+               return NULL;
+
        timer = kzalloc(sizeof(struct ath_gen_timer), GFP_KERNEL);
        if (timer == NULL)
                return NULL;
@@ -3036,23 +2978,13 @@ EXPORT_SYMBOL(ath_gen_timer_alloc);
 
 void ath9k_hw_gen_timer_start(struct ath_hw *ah,
                              struct ath_gen_timer *timer,
-                             u32 trig_timeout,
+                             u32 timer_next,
                              u32 timer_period)
 {
        struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers;
-       u32 tsf, timer_next;
-
-       BUG_ON(!timer_period);
-
-       set_bit(timer->index, &timer_table->timer_mask.timer_bits);
-
-       tsf = ath9k_hw_gettsf32(ah);
+       u32 mask = 0;
 
-       timer_next = tsf + trig_timeout;
-
-       ath_dbg(ath9k_hw_common(ah), BTCOEX,
-               "current tsf %x period %x timer_next %x\n",
-               tsf, timer_period, timer_next);
+       timer_table->timer_mask |= BIT(timer->index);
 
        /*
         * Program generic timer registers
@@ -3078,10 +3010,19 @@ void ath9k_hw_gen_timer_start(struct ath_hw *ah,
                                       (1 << timer->index));
        }
 
-       /* Enable both trigger and thresh interrupt masks */
-       REG_SET_BIT(ah, AR_IMR_S5,
-               (SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_THRESH) |
-               SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_TRIG)));
+       if (timer->trigger)
+               mask |= SM(AR_GENTMR_BIT(timer->index),
+                          AR_IMR_S5_GENTIMER_TRIG);
+       if (timer->overflow)
+               mask |= SM(AR_GENTMR_BIT(timer->index),
+                          AR_IMR_S5_GENTIMER_THRESH);
+
+       REG_SET_BIT(ah, AR_IMR_S5, mask);
+
+       if ((ah->imask & ATH9K_INT_GENTIMER) == 0) {
+               ah->imask |= ATH9K_INT_GENTIMER;
+               ath9k_hw_set_interrupts(ah);
+       }
 }
 EXPORT_SYMBOL(ath9k_hw_gen_timer_start);
 
@@ -3089,11 +3030,6 @@ void ath9k_hw_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer)
 {
        struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers;
 
-       if ((timer->index < AR_FIRST_NDP_TIMER) ||
-               (timer->index >= ATH_MAX_GEN_TIMER)) {
-               return;
-       }
-
        /* Clear generic timer enable bits. */
        REG_CLR_BIT(ah, gen_tmr_configuration[timer->index].mode_addr,
                        gen_tmr_configuration[timer->index].mode_mask);
@@ -3113,7 +3049,12 @@ void ath9k_hw_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer)
                (SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_THRESH) |
                SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_TRIG)));
 
-       clear_bit(timer->index, &timer_table->timer_mask.timer_bits);
+       timer_table->timer_mask &= ~BIT(timer->index);
+
+       if (timer_table->timer_mask == 0) {
+               ah->imask &= ~ATH9K_INT_GENTIMER;
+               ath9k_hw_set_interrupts(ah);
+       }
 }
 EXPORT_SYMBOL(ath9k_hw_gen_timer_stop);
 
@@ -3134,32 +3075,32 @@ void ath_gen_timer_isr(struct ath_hw *ah)
 {
        struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers;
        struct ath_gen_timer *timer;
-       struct ath_common *common = ath9k_hw_common(ah);
-       u32 trigger_mask, thresh_mask, index;
+       unsigned long trigger_mask, thresh_mask;
+       unsigned int index;
 
        /* get hardware generic timer interrupt status */
        trigger_mask = ah->intr_gen_timer_trigger;
        thresh_mask = ah->intr_gen_timer_thresh;
-       trigger_mask &= timer_table->timer_mask.val;
-       thresh_mask &= timer_table->timer_mask.val;
+       trigger_mask &= timer_table->timer_mask;
+       thresh_mask &= timer_table->timer_mask;
 
        trigger_mask &= ~thresh_mask;
 
-       while (thresh_mask) {
-               index = rightmost_index(timer_table, &thresh_mask);
+       for_each_set_bit(index, &thresh_mask, ARRAY_SIZE(timer_table->timers)) {
                timer = timer_table->timers[index];
-               BUG_ON(!timer);
-               ath_dbg(common, BTCOEX, "TSF overflow for Gen timer %d\n",
-                       index);
+               if (!timer)
+                   continue;
+               if (!timer->overflow)
+                   continue;
                timer->overflow(timer->arg);
        }
 
-       while (trigger_mask) {
-               index = rightmost_index(timer_table, &trigger_mask);
+       for_each_set_bit(index, &trigger_mask, ARRAY_SIZE(timer_table->timers)) {
                timer = timer_table->timers[index];
-               BUG_ON(!timer);
-               ath_dbg(common, BTCOEX,
-                       "Gen timer[%d] trigger\n", index);
+               if (!timer)
+                   continue;
+               if (!timer->trigger)
+                   continue;
                timer->trigger(timer->arg);
        }
 }
index b1ff54631dcaa35c181f3b9f8cd03dbffc5d1259..6132ffeb304871108941af0ceef7a6632ecd1366 100644 (file)
 #define CAB_TIMEOUT_VAL             10
 #define BEACON_TIMEOUT_VAL          10
 #define MIN_BEACON_TIMEOUT_VAL      1
-#define SLEEP_SLOP                  3
+#define SLEEP_SLOP                  TU_TO_USEC(3)
 
 #define INIT_CONFIG_STATUS          0x00000000
 #define INIT_RSSI_THR               0x00000700
@@ -280,10 +280,8 @@ struct ath9k_hw_capabilities {
 struct ath9k_ops_config {
        int dma_beacon_response_time;
        int sw_beacon_response_time;
-       int additional_swba_backoff;
        int ack_6mb;
        u32 cwm_ignore_extcca;
-       u8 pcie_clock_req;
        u32 pcie_waen;
        u8 analog_shiftreg;
        u32 ofdm_trig_low;
@@ -294,18 +292,11 @@ struct ath9k_ops_config {
        int serialize_regmode;
        bool rx_intr_mitigation;
        bool tx_intr_mitigation;
-#define SPUR_DISABLE           0
-#define SPUR_ENABLE_IOCTL      1
-#define SPUR_ENABLE_EEPROM     2
-#define AR_SPUR_5413_1         1640
-#define AR_SPUR_5413_2         1200
 #define AR_NO_SPUR             0x8000
 #define AR_BASE_FREQ_2GHZ      2300
 #define AR_BASE_FREQ_5GHZ      4900
 #define AR_SPUR_FEEQ_BOUND_HT40 19
 #define AR_SPUR_FEEQ_BOUND_HT20 10
-       int spurmode;
-       u16 spurchans[AR_EEPROM_MODAL_SPURS][2];
        u8 max_txtrig_level;
        u16 ani_poll_interval; /* ANI poll interval in ms */
 
@@ -460,10 +451,6 @@ struct ath9k_beacon_state {
        u32 bs_intval;
 #define ATH9K_TSFOOR_THRESHOLD    0x00004240 /* 16k us */
        u32 bs_dtimperiod;
-       u16 bs_cfpperiod;
-       u16 bs_cfpmaxduration;
-       u32 bs_cfpnext;
-       u16 bs_timoffset;
        u16 bs_bmissthreshold;
        u32 bs_sleepduration;
        u32 bs_tsfoor_threshold;
@@ -499,12 +486,6 @@ struct ath9k_hw_version {
 
 #define AR_GENTMR_BIT(_index)  (1 << (_index))
 
-/*
- * Using de Bruijin sequence to look up 1's index in a 32 bit number
- * debruijn32 = 0000 0111 0111 1100 1011 0101 0011 0001
- */
-#define debruijn32 0x077CB531U
-
 struct ath_gen_timer_configuration {
        u32 next_addr;
        u32 period_addr;
@@ -520,12 +501,8 @@ struct ath_gen_timer {
 };
 
 struct ath_gen_timer_table {
-       u32 gen_timer_index[32];
        struct ath_gen_timer *timers[ATH_MAX_GEN_TIMER];
-       union {
-               unsigned long timer_bits;
-               u16 val;
-       } timer_mask;
+       u16 timer_mask;
 };
 
 struct ath_hw_antcomb_conf {
@@ -690,7 +667,8 @@ struct ath_hw_ops {
                          struct ath9k_channel *chan,
                          u8 rxchainmask,
                          bool longcal);
-       bool (*get_isr)(struct ath_hw *ah, enum ath9k_int *masked);
+       bool (*get_isr)(struct ath_hw *ah, enum ath9k_int *masked,
+                       u32 *sync_cause_p);
        void (*set_txdesc)(struct ath_hw *ah, void *ds,
                           struct ath_tx_info *i);
        int (*proc_txdesc)(struct ath_hw *ah, void *ds,
@@ -786,7 +764,6 @@ struct ath_hw {
        u32 txurn_interrupt_mask;
        atomic_t intr_ref_cnt;
        bool chip_fullsleep;
-       u32 atim_window;
        u32 modes_index;
 
        /* Calibration */
@@ -1018,13 +995,6 @@ bool ath9k_hw_check_alive(struct ath_hw *ah);
 
 bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode);
 
-#ifdef CONFIG_ATH9K_DEBUGFS
-void ath9k_debug_sync_cause(struct ath_common *common, u32 sync_cause);
-#else
-static inline void ath9k_debug_sync_cause(struct ath_common *common,
-                                         u32 sync_cause) {}
-#endif
-
 /* Generic hw timer primitives */
 struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah,
                                          void (*trigger)(void *),
index 609b7e13f3f0afaf3c3f86cdb0589c302a5e98d0..e63465b7eab9ccc7b0214382881b37d159f31546 100644 (file)
@@ -470,7 +470,6 @@ static int ath9k_init_queues(struct ath_softc *sc)
 
        sc->beacon.beaconq = ath9k_hw_beaconq_setup(sc->sc_ah);
        sc->beacon.cabq = ath_txq_setup(sc, ATH9K_TX_QUEUE_CAB, 0);
-
        ath_cabq_update(sc);
 
        sc->tx.uapsdq = ath_txq_setup(sc, ATH9K_TX_QUEUE_UAPSD, 0);
@@ -705,7 +704,6 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
        ah->reg_ops.read = ath9k_ioread32;
        ah->reg_ops.write = ath9k_iowrite32;
        ah->reg_ops.rmw = ath9k_reg_rmw;
-       atomic_set(&ah->intr_ref_cnt, -1);
        sc->sc_ah = ah;
        pCap = &ah->caps;
 
@@ -899,7 +897,7 @@ static const struct ieee80211_iface_combination if_comb[] = {
        }
 };
 
-void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
+static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
 {
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
index 6a18f9d3e9cc952ef116f9fda1bf56f37526d8bc..89d7e206992b2ec28fb100b109d7b9e63d4a441d 100644 (file)
@@ -481,8 +481,7 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
                            | AR_Q_MISC_CBR_INCR_DIS0);
                value = (qi->tqi_readyTime -
                         (ah->config.sw_beacon_response_time -
-                         ah->config.dma_beacon_response_time) -
-                        ah->config.additional_swba_backoff) * 1024;
+                         ah->config.dma_beacon_response_time)) * 1024;
                REG_WRITE(ah, AR_QRDYTIMECFG(q),
                          value | AR_Q_RDYTIMECFG_EN);
                REG_SET_BIT(ah, AR_DMISC(q),
@@ -550,25 +549,25 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
 
        if (ads.ds_rxstatus8 & AR_PostDelimCRCErr) {
                rs->rs_rssi = ATH9K_RSSI_BAD;
-               rs->rs_rssi_ctl0 = ATH9K_RSSI_BAD;
-               rs->rs_rssi_ctl1 = ATH9K_RSSI_BAD;
-               rs->rs_rssi_ctl2 = ATH9K_RSSI_BAD;
-               rs->rs_rssi_ext0 = ATH9K_RSSI_BAD;
-               rs->rs_rssi_ext1 = ATH9K_RSSI_BAD;
-               rs->rs_rssi_ext2 = ATH9K_RSSI_BAD;
+               rs->rs_rssi_ctl[0] = ATH9K_RSSI_BAD;
+               rs->rs_rssi_ctl[1] = ATH9K_RSSI_BAD;
+               rs->rs_rssi_ctl[2] = ATH9K_RSSI_BAD;
+               rs->rs_rssi_ext[0] = ATH9K_RSSI_BAD;
+               rs->rs_rssi_ext[1] = ATH9K_RSSI_BAD;
+               rs->rs_rssi_ext[2] = ATH9K_RSSI_BAD;
        } else {
                rs->rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined);
-               rs->rs_rssi_ctl0 = MS(ads.ds_rxstatus0,
+               rs->rs_rssi_ctl[0] = MS(ads.ds_rxstatus0,
                                                AR_RxRSSIAnt00);
-               rs->rs_rssi_ctl1 = MS(ads.ds_rxstatus0,
+               rs->rs_rssi_ctl[1] = MS(ads.ds_rxstatus0,
                                                AR_RxRSSIAnt01);
-               rs->rs_rssi_ctl2 = MS(ads.ds_rxstatus0,
+               rs->rs_rssi_ctl[2] = MS(ads.ds_rxstatus0,
                                                AR_RxRSSIAnt02);
-               rs->rs_rssi_ext0 = MS(ads.ds_rxstatus4,
+               rs->rs_rssi_ext[0] = MS(ads.ds_rxstatus4,
                                                AR_RxRSSIAnt10);
-               rs->rs_rssi_ext1 = MS(ads.ds_rxstatus4,
+               rs->rs_rssi_ext[1] = MS(ads.ds_rxstatus4,
                                                AR_RxRSSIAnt11);
-               rs->rs_rssi_ext2 = MS(ads.ds_rxstatus4,
+               rs->rs_rssi_ext[2] = MS(ads.ds_rxstatus4,
                                                AR_RxRSSIAnt12);
        }
        if (ads.ds_rxstatus8 & AR_RxKeyIdxValid)
index e3eed81f24391c61b1389a749d471cf4ad662056..10271373a0cd1081fa89b53ee35992982fd7679b 100644 (file)
@@ -133,12 +133,8 @@ struct ath_rx_status {
        u8 rs_rate;
        u8 rs_antenna;
        u8 rs_more;
-       int8_t rs_rssi_ctl0;
-       int8_t rs_rssi_ctl1;
-       int8_t rs_rssi_ctl2;
-       int8_t rs_rssi_ext0;
-       int8_t rs_rssi_ext1;
-       int8_t rs_rssi_ext2;
+       int8_t rs_rssi_ctl[3];
+       int8_t rs_rssi_ext[3];
        u8 rs_isaggr;
        u8 rs_firstaggr;
        u8 rs_moreaggr;
index b1dcf89138d30d4ce8899e9a117ee96ac29212e5..173a889f9dbb35de8a49d87aea7f1c43400613bf 100644 (file)
@@ -508,6 +508,9 @@ void ath9k_tasklet(unsigned long data)
                wake_up(&sc->tx_wait);
        }
 
+       if (status & ATH9K_INT_GENTIMER)
+               ath_gen_timer_isr(sc->sc_ah);
+
        ath9k_btcoex_handle_interrupt(sc, status);
 
        /* re-enable hardware interrupt */
@@ -538,6 +541,7 @@ irqreturn_t ath_isr(int irq, void *dev)
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
        enum ath9k_int status;
+       u32 sync_cause;
        bool sched = false;
 
        /*
@@ -564,7 +568,8 @@ irqreturn_t ath_isr(int irq, void *dev)
         * bits we haven't explicitly enabled so we mask the
         * value to insure we only process bits we requested.
         */
-       ath9k_hw_getisr(ah, &status);   /* NB: clears ISR too */
+       ath9k_hw_getisr(ah, &status, &sync_cause); /* NB: clears ISR too */
+       ath9k_debug_sync_cause(sc, sync_cause);
        status &= ah->imask;    /* discard unasked-for bits */
 
        /*
@@ -757,6 +762,8 @@ static int ath9k_start(struct ieee80211_hw *hw)
         */
        ath9k_cmn_init_crypto(sc->sc_ah);
 
+       ath9k_hw_reset_tsf(ah);
+
        spin_unlock_bh(&sc->sc_pcu_lock);
 
        mutex_unlock(&sc->mutex);
@@ -1657,13 +1664,8 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
        }
 
        if ((changed & BSS_CHANGED_BEACON_ENABLED) ||
-           (changed & BSS_CHANGED_BEACON_INT)) {
-               if (ah->opmode == NL80211_IFTYPE_AP &&
-                   bss_conf->enable_beacon)
-                       ath9k_set_tsfadjust(sc, vif);
-               if (ath9k_allow_beacon_config(sc, vif))
-                       ath9k_beacon_config(sc, vif, changed);
-       }
+           (changed & BSS_CHANGED_BEACON_INT))
+               ath9k_beacon_config(sc, vif, changed);
 
        if (changed & BSS_CHANGED_ERP_SLOT) {
                if (bss_conf->use_short_slot)
index 0ac1b5f04256517050be277696e9a9eae4f2391c..71799fcade543fca00ba709970c26f6ff33a948e 100644 (file)
@@ -200,7 +200,7 @@ skip_tuning:
        if (btcoex->duty_cycle > ATH_MCI_MAX_DUTY_CYCLE)
                btcoex->duty_cycle = ATH_MCI_MAX_DUTY_CYCLE;
 
-       btcoex->btcoex_no_stomp =  btcoex->btcoex_period * 1000 *
+       btcoex->btcoex_no_stomp =  btcoex->btcoex_period *
                (100 - btcoex->duty_cycle) / 100;
 
        ath9k_hw_btcoex_enable(sc->sc_ah);
index 95ddca5495d492cb5a1bf4bb99d8ee3283a9e1ec..3692b2a501a2e50d522d130e8a85883fe7d36d02 100644 (file)
@@ -15,7 +15,6 @@
  */
 
 #include <linux/dma-mapping.h>
-#include <linux/relay.h>
 #include "ath9k.h"
 #include "ar9003_mac.h"
 
@@ -906,6 +905,7 @@ static void ath9k_process_rssi(struct ath_common *common,
        struct ath_hw *ah = common->ah;
        int last_rssi;
        int rssi = rx_stats->rs_rssi;
+       int i, j;
 
        /*
         * RSSI is not available for subframes in an A-MPDU.
@@ -924,6 +924,20 @@ static void ath9k_process_rssi(struct ath_common *common,
                return;
        }
 
+       for (i = 0, j = 0; i < ARRAY_SIZE(rx_stats->rs_rssi_ctl); i++) {
+               s8 rssi;
+
+               if (!(ah->rxchainmask & BIT(i)))
+                       continue;
+
+               rssi = rx_stats->rs_rssi_ctl[i];
+               if (rssi != ATH9K_RSSI_BAD) {
+                   rxs->chains |= BIT(j);
+                   rxs->chain_signal[j] = ah->noise + rssi;
+               }
+               j++;
+       }
+
        /*
         * Update Beacon RSSI, this is used by ANI.
         */
@@ -960,186 +974,6 @@ static void ath9k_process_tsf(struct ath_rx_status *rs,
                rxs->mactime += 0x100000000ULL;
 }
 
-#ifdef CONFIG_ATH9K_DEBUGFS
-static s8 fix_rssi_inv_only(u8 rssi_val)
-{
-       if (rssi_val == 128)
-               rssi_val = 0;
-       return (s8) rssi_val;
-}
-#endif
-
-/* returns 1 if this was a spectral frame, even if not handled. */
-static int ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr,
-                          struct ath_rx_status *rs, u64 tsf)
-{
-#ifdef CONFIG_ATH9K_DEBUGFS
-       struct ath_hw *ah = sc->sc_ah;
-       u8 num_bins, *bins, *vdata = (u8 *)hdr;
-       struct fft_sample_ht20 fft_sample_20;
-       struct fft_sample_ht20_40 fft_sample_40;
-       struct fft_sample_tlv *tlv;
-       struct ath_radar_info *radar_info;
-       int len = rs->rs_datalen;
-       int dc_pos;
-       u16 fft_len, length, freq = ah->curchan->chan->center_freq;
-       enum nl80211_channel_type chan_type;
-
-       /* AR9280 and before report via ATH9K_PHYERR_RADAR, AR93xx and newer
-        * via ATH9K_PHYERR_SPECTRAL. Haven't seen ATH9K_PHYERR_FALSE_RADAR_EXT
-        * yet, but this is supposed to be possible as well.
-        */
-       if (rs->rs_phyerr != ATH9K_PHYERR_RADAR &&
-           rs->rs_phyerr != ATH9K_PHYERR_FALSE_RADAR_EXT &&
-           rs->rs_phyerr != ATH9K_PHYERR_SPECTRAL)
-               return 0;
-
-       /* check if spectral scan bit is set. This does not have to be checked
-        * if received through a SPECTRAL phy error, but shouldn't hurt.
-        */
-       radar_info = ((struct ath_radar_info *)&vdata[len]) - 1;
-       if (!(radar_info->pulse_bw_info & SPECTRAL_SCAN_BITMASK))
-               return 0;
-
-       chan_type = cfg80211_get_chandef_type(&sc->hw->conf.chandef);
-       if ((chan_type == NL80211_CHAN_HT40MINUS) ||
-           (chan_type == NL80211_CHAN_HT40PLUS)) {
-               fft_len = SPECTRAL_HT20_40_TOTAL_DATA_LEN;
-               num_bins = SPECTRAL_HT20_40_NUM_BINS;
-               bins = (u8 *)fft_sample_40.data;
-       } else {
-               fft_len = SPECTRAL_HT20_TOTAL_DATA_LEN;
-               num_bins = SPECTRAL_HT20_NUM_BINS;
-               bins = (u8 *)fft_sample_20.data;
-       }
-
-       /* Variation in the data length is possible and will be fixed later */
-       if ((len > fft_len + 2) || (len < fft_len - 1))
-               return 1;
-
-       switch (len - fft_len) {
-       case 0:
-               /* length correct, nothing to do. */
-               memcpy(bins, vdata, num_bins);
-               break;
-       case -1:
-               /* first byte missing, duplicate it. */
-               memcpy(&bins[1], vdata, num_bins - 1);
-               bins[0] = vdata[0];
-               break;
-       case 2:
-               /* MAC added 2 extra bytes at bin 30 and 32, remove them. */
-               memcpy(bins, vdata, 30);
-               bins[30] = vdata[31];
-               memcpy(&bins[31], &vdata[33], num_bins - 31);
-               break;
-       case 1:
-               /* MAC added 2 extra bytes AND first byte is missing. */
-               bins[0] = vdata[0];
-               memcpy(&bins[1], vdata, 30);
-               bins[31] = vdata[31];
-               memcpy(&bins[32], &vdata[33], num_bins - 32);
-               break;
-       default:
-               return 1;
-       }
-
-       /* DC value (value in the middle) is the blind spot of the spectral
-        * sample and invalid, interpolate it.
-        */
-       dc_pos = num_bins / 2;
-       bins[dc_pos] = (bins[dc_pos + 1] + bins[dc_pos - 1]) / 2;
-
-       if ((chan_type == NL80211_CHAN_HT40MINUS) ||
-           (chan_type == NL80211_CHAN_HT40PLUS)) {
-               s8 lower_rssi, upper_rssi;
-               s16 ext_nf;
-               u8 lower_max_index, upper_max_index;
-               u8 lower_bitmap_w, upper_bitmap_w;
-               u16 lower_mag, upper_mag;
-               struct ath9k_hw_cal_data *caldata = ah->caldata;
-               struct ath_ht20_40_mag_info *mag_info;
-
-               if (caldata)
-                       ext_nf = ath9k_hw_getchan_noise(ah, ah->curchan,
-                                       caldata->nfCalHist[3].privNF);
-               else
-                       ext_nf = ATH_DEFAULT_NOISE_FLOOR;
-
-               length = sizeof(fft_sample_40) - sizeof(struct fft_sample_tlv);
-               fft_sample_40.tlv.type = ATH_FFT_SAMPLE_HT20_40;
-               fft_sample_40.tlv.length = __cpu_to_be16(length);
-               fft_sample_40.freq = __cpu_to_be16(freq);
-               fft_sample_40.channel_type = chan_type;
-
-               if (chan_type == NL80211_CHAN_HT40PLUS) {
-                       lower_rssi = fix_rssi_inv_only(rs->rs_rssi_ctl0);
-                       upper_rssi = fix_rssi_inv_only(rs->rs_rssi_ext0);
-
-                       fft_sample_40.lower_noise = ah->noise;
-                       fft_sample_40.upper_noise = ext_nf;
-               } else {
-                       lower_rssi = fix_rssi_inv_only(rs->rs_rssi_ext0);
-                       upper_rssi = fix_rssi_inv_only(rs->rs_rssi_ctl0);
-
-                       fft_sample_40.lower_noise = ext_nf;
-                       fft_sample_40.upper_noise = ah->noise;
-               }
-               fft_sample_40.lower_rssi = lower_rssi;
-               fft_sample_40.upper_rssi = upper_rssi;
-
-               mag_info = ((struct ath_ht20_40_mag_info *)radar_info) - 1;
-               lower_mag = spectral_max_magnitude(mag_info->lower_bins);
-               upper_mag = spectral_max_magnitude(mag_info->upper_bins);
-               fft_sample_40.lower_max_magnitude = __cpu_to_be16(lower_mag);
-               fft_sample_40.upper_max_magnitude = __cpu_to_be16(upper_mag);
-               lower_max_index = spectral_max_index(mag_info->lower_bins);
-               upper_max_index = spectral_max_index(mag_info->upper_bins);
-               fft_sample_40.lower_max_index = lower_max_index;
-               fft_sample_40.upper_max_index = upper_max_index;
-               lower_bitmap_w = spectral_bitmap_weight(mag_info->lower_bins);
-               upper_bitmap_w = spectral_bitmap_weight(mag_info->upper_bins);
-               fft_sample_40.lower_bitmap_weight = lower_bitmap_w;
-               fft_sample_40.upper_bitmap_weight = upper_bitmap_w;
-               fft_sample_40.max_exp = mag_info->max_exp & 0xf;
-
-               fft_sample_40.tsf = __cpu_to_be64(tsf);
-
-               tlv = (struct fft_sample_tlv *)&fft_sample_40;
-       } else {
-               u8 max_index, bitmap_w;
-               u16 magnitude;
-               struct ath_ht20_mag_info *mag_info;
-
-               length = sizeof(fft_sample_20) - sizeof(struct fft_sample_tlv);
-               fft_sample_20.tlv.type = ATH_FFT_SAMPLE_HT20;
-               fft_sample_20.tlv.length = __cpu_to_be16(length);
-               fft_sample_20.freq = __cpu_to_be16(freq);
-
-               fft_sample_20.rssi = fix_rssi_inv_only(rs->rs_rssi_ctl0);
-               fft_sample_20.noise = ah->noise;
-
-               mag_info = ((struct ath_ht20_mag_info *)radar_info) - 1;
-               magnitude = spectral_max_magnitude(mag_info->all_bins);
-               fft_sample_20.max_magnitude = __cpu_to_be16(magnitude);
-               max_index = spectral_max_index(mag_info->all_bins);
-               fft_sample_20.max_index = max_index;
-               bitmap_w = spectral_bitmap_weight(mag_info->all_bins);
-               fft_sample_20.bitmap_weight = bitmap_w;
-               fft_sample_20.max_exp = mag_info->max_exp & 0xf;
-
-               fft_sample_20.tsf = __cpu_to_be64(tsf);
-
-               tlv = (struct fft_sample_tlv *)&fft_sample_20;
-       }
-
-       ath_debug_send_fft_sample(sc, tlv);
-       return 1;
-#else
-       return 0;
-#endif
-}
-
 static bool ath9k_is_mybeacon(struct ath_softc *sc, struct ieee80211_hdr *hdr)
 {
        struct ath_hw *ah = sc->sc_ah;
diff --git a/drivers/net/wireless/ath/ath9k/spectral.c b/drivers/net/wireless/ath/ath9k/spectral.c
new file mode 100644 (file)
index 0000000..11adb5e
--- /dev/null
@@ -0,0 +1,543 @@
+/*
+ * Copyright (c) 2013 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/relay.h>
+#include "ath9k.h"
+
+static s8 fix_rssi_inv_only(u8 rssi_val)
+{
+       if (rssi_val == 128)
+               rssi_val = 0;
+       return (s8) rssi_val;
+}
+
+static void ath_debug_send_fft_sample(struct ath_softc *sc,
+                                     struct fft_sample_tlv *fft_sample_tlv)
+{
+       int length;
+       if (!sc->rfs_chan_spec_scan)
+               return;
+
+       length = __be16_to_cpu(fft_sample_tlv->length) +
+                sizeof(*fft_sample_tlv);
+       relay_write(sc->rfs_chan_spec_scan, fft_sample_tlv, length);
+}
+
+/* returns 1 if this was a spectral frame, even if not handled. */
+int ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr,
+                   struct ath_rx_status *rs, u64 tsf)
+{
+       struct ath_hw *ah = sc->sc_ah;
+       u8 num_bins, *bins, *vdata = (u8 *)hdr;
+       struct fft_sample_ht20 fft_sample_20;
+       struct fft_sample_ht20_40 fft_sample_40;
+       struct fft_sample_tlv *tlv;
+       struct ath_radar_info *radar_info;
+       int len = rs->rs_datalen;
+       int dc_pos;
+       u16 fft_len, length, freq = ah->curchan->chan->center_freq;
+       enum nl80211_channel_type chan_type;
+
+       /* AR9280 and before report via ATH9K_PHYERR_RADAR, AR93xx and newer
+        * via ATH9K_PHYERR_SPECTRAL. Haven't seen ATH9K_PHYERR_FALSE_RADAR_EXT
+        * yet, but this is supposed to be possible as well.
+        */
+       if (rs->rs_phyerr != ATH9K_PHYERR_RADAR &&
+           rs->rs_phyerr != ATH9K_PHYERR_FALSE_RADAR_EXT &&
+           rs->rs_phyerr != ATH9K_PHYERR_SPECTRAL)
+               return 0;
+
+       /* check if spectral scan bit is set. This does not have to be checked
+        * if received through a SPECTRAL phy error, but shouldn't hurt.
+        */
+       radar_info = ((struct ath_radar_info *)&vdata[len]) - 1;
+       if (!(radar_info->pulse_bw_info & SPECTRAL_SCAN_BITMASK))
+               return 0;
+
+       chan_type = cfg80211_get_chandef_type(&sc->hw->conf.chandef);
+       if ((chan_type == NL80211_CHAN_HT40MINUS) ||
+           (chan_type == NL80211_CHAN_HT40PLUS)) {
+               fft_len = SPECTRAL_HT20_40_TOTAL_DATA_LEN;
+               num_bins = SPECTRAL_HT20_40_NUM_BINS;
+               bins = (u8 *)fft_sample_40.data;
+       } else {
+               fft_len = SPECTRAL_HT20_TOTAL_DATA_LEN;
+               num_bins = SPECTRAL_HT20_NUM_BINS;
+               bins = (u8 *)fft_sample_20.data;
+       }
+
+       /* Variation in the data length is possible and will be fixed later */
+       if ((len > fft_len + 2) || (len < fft_len - 1))
+               return 1;
+
+       switch (len - fft_len) {
+       case 0:
+               /* length correct, nothing to do. */
+               memcpy(bins, vdata, num_bins);
+               break;
+       case -1:
+               /* first byte missing, duplicate it. */
+               memcpy(&bins[1], vdata, num_bins - 1);
+               bins[0] = vdata[0];
+               break;
+       case 2:
+               /* MAC added 2 extra bytes at bin 30 and 32, remove them. */
+               memcpy(bins, vdata, 30);
+               bins[30] = vdata[31];
+               memcpy(&bins[31], &vdata[33], num_bins - 31);
+               break;
+       case 1:
+               /* MAC added 2 extra bytes AND first byte is missing. */
+               bins[0] = vdata[0];
+               memcpy(&bins[1], vdata, 30);
+               bins[31] = vdata[31];
+               memcpy(&bins[32], &vdata[33], num_bins - 32);
+               break;
+       default:
+               return 1;
+       }
+
+       /* DC value (value in the middle) is the blind spot of the spectral
+        * sample and invalid, interpolate it.
+        */
+       dc_pos = num_bins / 2;
+       bins[dc_pos] = (bins[dc_pos + 1] + bins[dc_pos - 1]) / 2;
+
+       if ((chan_type == NL80211_CHAN_HT40MINUS) ||
+           (chan_type == NL80211_CHAN_HT40PLUS)) {
+               s8 lower_rssi, upper_rssi;
+               s16 ext_nf;
+               u8 lower_max_index, upper_max_index;
+               u8 lower_bitmap_w, upper_bitmap_w;
+               u16 lower_mag, upper_mag;
+               struct ath9k_hw_cal_data *caldata = ah->caldata;
+               struct ath_ht20_40_mag_info *mag_info;
+
+               if (caldata)
+                       ext_nf = ath9k_hw_getchan_noise(ah, ah->curchan,
+                                       caldata->nfCalHist[3].privNF);
+               else
+                       ext_nf = ATH_DEFAULT_NOISE_FLOOR;
+
+               length = sizeof(fft_sample_40) - sizeof(struct fft_sample_tlv);
+               fft_sample_40.tlv.type = ATH_FFT_SAMPLE_HT20_40;
+               fft_sample_40.tlv.length = __cpu_to_be16(length);
+               fft_sample_40.freq = __cpu_to_be16(freq);
+               fft_sample_40.channel_type = chan_type;
+
+               if (chan_type == NL80211_CHAN_HT40PLUS) {
+                       lower_rssi = fix_rssi_inv_only(rs->rs_rssi_ctl[0]);
+                       upper_rssi = fix_rssi_inv_only(rs->rs_rssi_ext[0]);
+
+                       fft_sample_40.lower_noise = ah->noise;
+                       fft_sample_40.upper_noise = ext_nf;
+               } else {
+                       lower_rssi = fix_rssi_inv_only(rs->rs_rssi_ext[0]);
+                       upper_rssi = fix_rssi_inv_only(rs->rs_rssi_ctl[0]);
+
+                       fft_sample_40.lower_noise = ext_nf;
+                       fft_sample_40.upper_noise = ah->noise;
+               }
+               fft_sample_40.lower_rssi = lower_rssi;
+               fft_sample_40.upper_rssi = upper_rssi;
+
+               mag_info = ((struct ath_ht20_40_mag_info *)radar_info) - 1;
+               lower_mag = spectral_max_magnitude(mag_info->lower_bins);
+               upper_mag = spectral_max_magnitude(mag_info->upper_bins);
+               fft_sample_40.lower_max_magnitude = __cpu_to_be16(lower_mag);
+               fft_sample_40.upper_max_magnitude = __cpu_to_be16(upper_mag);
+               lower_max_index = spectral_max_index(mag_info->lower_bins);
+               upper_max_index = spectral_max_index(mag_info->upper_bins);
+               fft_sample_40.lower_max_index = lower_max_index;
+               fft_sample_40.upper_max_index = upper_max_index;
+               lower_bitmap_w = spectral_bitmap_weight(mag_info->lower_bins);
+               upper_bitmap_w = spectral_bitmap_weight(mag_info->upper_bins);
+               fft_sample_40.lower_bitmap_weight = lower_bitmap_w;
+               fft_sample_40.upper_bitmap_weight = upper_bitmap_w;
+               fft_sample_40.max_exp = mag_info->max_exp & 0xf;
+
+               fft_sample_40.tsf = __cpu_to_be64(tsf);
+
+               tlv = (struct fft_sample_tlv *)&fft_sample_40;
+       } else {
+               u8 max_index, bitmap_w;
+               u16 magnitude;
+               struct ath_ht20_mag_info *mag_info;
+
+               length = sizeof(fft_sample_20) - sizeof(struct fft_sample_tlv);
+               fft_sample_20.tlv.type = ATH_FFT_SAMPLE_HT20;
+               fft_sample_20.tlv.length = __cpu_to_be16(length);
+               fft_sample_20.freq = __cpu_to_be16(freq);
+
+               fft_sample_20.rssi = fix_rssi_inv_only(rs->rs_rssi_ctl[0]);
+               fft_sample_20.noise = ah->noise;
+
+               mag_info = ((struct ath_ht20_mag_info *)radar_info) - 1;
+               magnitude = spectral_max_magnitude(mag_info->all_bins);
+               fft_sample_20.max_magnitude = __cpu_to_be16(magnitude);
+               max_index = spectral_max_index(mag_info->all_bins);
+               fft_sample_20.max_index = max_index;
+               bitmap_w = spectral_bitmap_weight(mag_info->all_bins);
+               fft_sample_20.bitmap_weight = bitmap_w;
+               fft_sample_20.max_exp = mag_info->max_exp & 0xf;
+
+               fft_sample_20.tsf = __cpu_to_be64(tsf);
+
+               tlv = (struct fft_sample_tlv *)&fft_sample_20;
+       }
+
+       ath_debug_send_fft_sample(sc, tlv);
+
+       return 1;
+}
+
+/*********************/
+/* spectral_scan_ctl */
+/*********************/
+
+static ssize_t read_file_spec_scan_ctl(struct file *file, char __user *user_buf,
+                                      size_t count, loff_t *ppos)
+{
+       struct ath_softc *sc = file->private_data;
+       char *mode = "";
+       unsigned int len;
+
+       switch (sc->spectral_mode) {
+       case SPECTRAL_DISABLED:
+               mode = "disable";
+               break;
+       case SPECTRAL_BACKGROUND:
+               mode = "background";
+               break;
+       case SPECTRAL_CHANSCAN:
+               mode = "chanscan";
+               break;
+       case SPECTRAL_MANUAL:
+               mode = "manual";
+               break;
+       }
+       len = strlen(mode);
+       return simple_read_from_buffer(user_buf, count, ppos, mode, len);
+}
+
+static ssize_t write_file_spec_scan_ctl(struct file *file,
+                                       const char __user *user_buf,
+                                       size_t count, loff_t *ppos)
+{
+       struct ath_softc *sc = file->private_data;
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       char buf[32];
+       ssize_t len;
+
+       if (config_enabled(CONFIG_ATH9K_TX99))
+               return -EOPNOTSUPP;
+
+       len = min(count, sizeof(buf) - 1);
+       if (copy_from_user(buf, user_buf, len))
+               return -EFAULT;
+
+       buf[len] = '\0';
+
+       if (strncmp("trigger", buf, 7) == 0) {
+               ath9k_spectral_scan_trigger(sc->hw);
+       } else if (strncmp("background", buf, 9) == 0) {
+               ath9k_spectral_scan_config(sc->hw, SPECTRAL_BACKGROUND);
+               ath_dbg(common, CONFIG, "spectral scan: background mode enabled\n");
+       } else if (strncmp("chanscan", buf, 8) == 0) {
+               ath9k_spectral_scan_config(sc->hw, SPECTRAL_CHANSCAN);
+               ath_dbg(common, CONFIG, "spectral scan: channel scan mode enabled\n");
+       } else if (strncmp("manual", buf, 6) == 0) {
+               ath9k_spectral_scan_config(sc->hw, SPECTRAL_MANUAL);
+               ath_dbg(common, CONFIG, "spectral scan: manual mode enabled\n");
+       } else if (strncmp("disable", buf, 7) == 0) {
+               ath9k_spectral_scan_config(sc->hw, SPECTRAL_DISABLED);
+               ath_dbg(common, CONFIG, "spectral scan: disabled\n");
+       } else {
+               return -EINVAL;
+       }
+
+       return count;
+}
+
+static const struct file_operations fops_spec_scan_ctl = {
+       .read = read_file_spec_scan_ctl,
+       .write = write_file_spec_scan_ctl,
+       .open = simple_open,
+       .owner = THIS_MODULE,
+       .llseek = default_llseek,
+};
+
+/*************************/
+/* spectral_short_repeat */
+/*************************/
+
+static ssize_t read_file_spectral_short_repeat(struct file *file,
+                                              char __user *user_buf,
+                                              size_t count, loff_t *ppos)
+{
+       struct ath_softc *sc = file->private_data;
+       char buf[32];
+       unsigned int len;
+
+       len = sprintf(buf, "%d\n", sc->spec_config.short_repeat);
+       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_spectral_short_repeat(struct file *file,
+                                               const char __user *user_buf,
+                                               size_t count, loff_t *ppos)
+{
+       struct ath_softc *sc = file->private_data;
+       unsigned long val;
+       char buf[32];
+       ssize_t len;
+
+       len = min(count, sizeof(buf) - 1);
+       if (copy_from_user(buf, user_buf, len))
+               return -EFAULT;
+
+       buf[len] = '\0';
+       if (kstrtoul(buf, 0, &val))
+               return -EINVAL;
+
+       if (val < 0 || val > 1)
+               return -EINVAL;
+
+       sc->spec_config.short_repeat = val;
+       return count;
+}
+
+static const struct file_operations fops_spectral_short_repeat = {
+       .read = read_file_spectral_short_repeat,
+       .write = write_file_spectral_short_repeat,
+       .open = simple_open,
+       .owner = THIS_MODULE,
+       .llseek = default_llseek,
+};
+
+/******************/
+/* spectral_count */
+/******************/
+
+static ssize_t read_file_spectral_count(struct file *file,
+                                       char __user *user_buf,
+                                       size_t count, loff_t *ppos)
+{
+       struct ath_softc *sc = file->private_data;
+       char buf[32];
+       unsigned int len;
+
+       len = sprintf(buf, "%d\n", sc->spec_config.count);
+       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_spectral_count(struct file *file,
+                                        const char __user *user_buf,
+                                        size_t count, loff_t *ppos)
+{
+       struct ath_softc *sc = file->private_data;
+       unsigned long val;
+       char buf[32];
+       ssize_t len;
+
+       len = min(count, sizeof(buf) - 1);
+       if (copy_from_user(buf, user_buf, len))
+               return -EFAULT;
+
+       buf[len] = '\0';
+       if (kstrtoul(buf, 0, &val))
+               return -EINVAL;
+
+       if (val < 0 || val > 255)
+               return -EINVAL;
+
+       sc->spec_config.count = val;
+       return count;
+}
+
+static const struct file_operations fops_spectral_count = {
+       .read = read_file_spectral_count,
+       .write = write_file_spectral_count,
+       .open = simple_open,
+       .owner = THIS_MODULE,
+       .llseek = default_llseek,
+};
+
+/*******************/
+/* spectral_period */
+/*******************/
+
+static ssize_t read_file_spectral_period(struct file *file,
+                                        char __user *user_buf,
+                                        size_t count, loff_t *ppos)
+{
+       struct ath_softc *sc = file->private_data;
+       char buf[32];
+       unsigned int len;
+
+       len = sprintf(buf, "%d\n", sc->spec_config.period);
+       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_spectral_period(struct file *file,
+                                         const char __user *user_buf,
+                                         size_t count, loff_t *ppos)
+{
+       struct ath_softc *sc = file->private_data;
+       unsigned long val;
+       char buf[32];
+       ssize_t len;
+
+       len = min(count, sizeof(buf) - 1);
+       if (copy_from_user(buf, user_buf, len))
+               return -EFAULT;
+
+       buf[len] = '\0';
+       if (kstrtoul(buf, 0, &val))
+               return -EINVAL;
+
+       if (val < 0 || val > 255)
+               return -EINVAL;
+
+       sc->spec_config.period = val;
+       return count;
+}
+
+static const struct file_operations fops_spectral_period = {
+       .read = read_file_spectral_period,
+       .write = write_file_spectral_period,
+       .open = simple_open,
+       .owner = THIS_MODULE,
+       .llseek = default_llseek,
+};
+
+/***********************/
+/* spectral_fft_period */
+/***********************/
+
+static ssize_t read_file_spectral_fft_period(struct file *file,
+                                            char __user *user_buf,
+                                            size_t count, loff_t *ppos)
+{
+       struct ath_softc *sc = file->private_data;
+       char buf[32];
+       unsigned int len;
+
+       len = sprintf(buf, "%d\n", sc->spec_config.fft_period);
+       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_spectral_fft_period(struct file *file,
+                                             const char __user *user_buf,
+                                             size_t count, loff_t *ppos)
+{
+       struct ath_softc *sc = file->private_data;
+       unsigned long val;
+       char buf[32];
+       ssize_t len;
+
+       len = min(count, sizeof(buf) - 1);
+       if (copy_from_user(buf, user_buf, len))
+               return -EFAULT;
+
+       buf[len] = '\0';
+       if (kstrtoul(buf, 0, &val))
+               return -EINVAL;
+
+       if (val < 0 || val > 15)
+               return -EINVAL;
+
+       sc->spec_config.fft_period = val;
+       return count;
+}
+
+static const struct file_operations fops_spectral_fft_period = {
+       .read = read_file_spectral_fft_period,
+       .write = write_file_spectral_fft_period,
+       .open = simple_open,
+       .owner = THIS_MODULE,
+       .llseek = default_llseek,
+};
+
+/*******************/
+/* Relay interface */
+/*******************/
+
+static struct dentry *create_buf_file_handler(const char *filename,
+                                             struct dentry *parent,
+                                             umode_t mode,
+                                             struct rchan_buf *buf,
+                                             int *is_global)
+{
+       struct dentry *buf_file;
+
+       buf_file = debugfs_create_file(filename, mode, parent, buf,
+                                      &relay_file_operations);
+       *is_global = 1;
+       return buf_file;
+}
+
+static int remove_buf_file_handler(struct dentry *dentry)
+{
+       debugfs_remove(dentry);
+
+       return 0;
+}
+
+struct rchan_callbacks rfs_spec_scan_cb = {
+       .create_buf_file = create_buf_file_handler,
+       .remove_buf_file = remove_buf_file_handler,
+};
+
+/*********************/
+/* Debug Init/Deinit */
+/*********************/
+
+void ath9k_spectral_deinit_debug(struct ath_softc *sc)
+{
+       if (config_enabled(CONFIG_ATH9K_DEBUGFS) && sc->rfs_chan_spec_scan) {
+               relay_close(sc->rfs_chan_spec_scan);
+               sc->rfs_chan_spec_scan = NULL;
+       }
+}
+
+void ath9k_spectral_init_debug(struct ath_softc *sc)
+{
+       sc->rfs_chan_spec_scan = relay_open("spectral_scan",
+                                           sc->debug.debugfs_phy,
+                                           1024, 256, &rfs_spec_scan_cb,
+                                           NULL);
+       debugfs_create_file("spectral_scan_ctl",
+                           S_IRUSR | S_IWUSR,
+                           sc->debug.debugfs_phy, sc,
+                           &fops_spec_scan_ctl);
+       debugfs_create_file("spectral_short_repeat",
+                           S_IRUSR | S_IWUSR,
+                           sc->debug.debugfs_phy, sc,
+                           &fops_spectral_short_repeat);
+       debugfs_create_file("spectral_count",
+                           S_IRUSR | S_IWUSR,
+                           sc->debug.debugfs_phy, sc,
+                           &fops_spectral_count);
+       debugfs_create_file("spectral_period",
+                           S_IRUSR | S_IWUSR,
+                           sc->debug.debugfs_phy, sc,
+                           &fops_spectral_period);
+       debugfs_create_file("spectral_fft_period",
+                           S_IRUSR | S_IWUSR,
+                           sc->debug.debugfs_phy, sc,
+                           &fops_spectral_fft_period);
+}
diff --git a/drivers/net/wireless/ath/ath9k/spectral.h b/drivers/net/wireless/ath/ath9k/spectral.h
new file mode 100644 (file)
index 0000000..ead6341
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 2013 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef SPECTRAL_H
+#define SPECTRAL_H
+
+/* enum spectral_mode:
+ *
+ * @SPECTRAL_DISABLED: spectral mode is disabled
+ * @SPECTRAL_BACKGROUND: hardware sends samples when it is not busy with
+ *     something else.
+ * @SPECTRAL_MANUAL: spectral scan is enabled, triggering for samples
+ *     is performed manually.
+ * @SPECTRAL_CHANSCAN: Like manual, but also triggered when changing channels
+ *     during a channel scan.
+ */
+enum spectral_mode {
+       SPECTRAL_DISABLED = 0,
+       SPECTRAL_BACKGROUND,
+       SPECTRAL_MANUAL,
+       SPECTRAL_CHANSCAN,
+};
+
+#define SPECTRAL_SCAN_BITMASK          0x10
+/* Radar info packet format, used for DFS and spectral formats. */
+struct ath_radar_info {
+       u8 pulse_length_pri;
+       u8 pulse_length_ext;
+       u8 pulse_bw_info;
+} __packed;
+
+/* The HT20 spectral data has 4 bytes of additional information at it's end.
+ *
+ * [7:0]: all bins {max_magnitude[1:0], bitmap_weight[5:0]}
+ * [7:0]: all bins  max_magnitude[9:2]
+ * [7:0]: all bins {max_index[5:0], max_magnitude[11:10]}
+ * [3:0]: max_exp (shift amount to size max bin to 8-bit unsigned)
+ */
+struct ath_ht20_mag_info {
+       u8 all_bins[3];
+       u8 max_exp;
+} __packed;
+
+#define SPECTRAL_HT20_NUM_BINS         56
+
+/* WARNING: don't actually use this struct! MAC may vary the amount of
+ * data by -1/+2. This struct is for reference only.
+ */
+struct ath_ht20_fft_packet {
+       u8 data[SPECTRAL_HT20_NUM_BINS];
+       struct ath_ht20_mag_info mag_info;
+       struct ath_radar_info radar_info;
+} __packed;
+
+#define SPECTRAL_HT20_TOTAL_DATA_LEN   (sizeof(struct ath_ht20_fft_packet))
+
+/* Dynamic 20/40 mode:
+ *
+ * [7:0]: lower bins {max_magnitude[1:0], bitmap_weight[5:0]}
+ * [7:0]: lower bins  max_magnitude[9:2]
+ * [7:0]: lower bins {max_index[5:0], max_magnitude[11:10]}
+ * [7:0]: upper bins {max_magnitude[1:0], bitmap_weight[5:0]}
+ * [7:0]: upper bins  max_magnitude[9:2]
+ * [7:0]: upper bins {max_index[5:0], max_magnitude[11:10]}
+ * [3:0]: max_exp (shift amount to size max bin to 8-bit unsigned)
+ */
+struct ath_ht20_40_mag_info {
+       u8 lower_bins[3];
+       u8 upper_bins[3];
+       u8 max_exp;
+} __packed;
+
+#define SPECTRAL_HT20_40_NUM_BINS              128
+
+/* WARNING: don't actually use this struct! MAC may vary the amount of
+ * data. This struct is for reference only.
+ */
+struct ath_ht20_40_fft_packet {
+       u8 data[SPECTRAL_HT20_40_NUM_BINS];
+       struct ath_ht20_40_mag_info mag_info;
+       struct ath_radar_info radar_info;
+} __packed;
+
+
+#define SPECTRAL_HT20_40_TOTAL_DATA_LEN        (sizeof(struct ath_ht20_40_fft_packet))
+
+/* grabs the max magnitude from the all/upper/lower bins */
+static inline u16 spectral_max_magnitude(u8 *bins)
+{
+       return (bins[0] & 0xc0) >> 6 |
+              (bins[1] & 0xff) << 2 |
+              (bins[2] & 0x03) << 10;
+}
+
+/* return the max magnitude from the all/upper/lower bins */
+static inline u8 spectral_max_index(u8 *bins)
+{
+       s8 m = (bins[2] & 0xfc) >> 2;
+
+       /* TODO: this still doesn't always report the right values ... */
+       if (m > 32)
+               m |= 0xe0;
+       else
+               m &= ~0xe0;
+
+       return m + 29;
+}
+
+/* return the bitmap weight from the all/upper/lower bins */
+static inline u8 spectral_bitmap_weight(u8 *bins)
+{
+       return bins[0] & 0x3f;
+}
+
+/* FFT sample format given to userspace via debugfs.
+ *
+ * Please keep the type/length at the front position and change
+ * other fields after adding another sample type
+ *
+ * TODO: this might need rework when switching to nl80211-based
+ * interface.
+ */
+enum ath_fft_sample_type {
+       ATH_FFT_SAMPLE_HT20 = 1,
+       ATH_FFT_SAMPLE_HT20_40,
+};
+
+struct fft_sample_tlv {
+       u8 type;        /* see ath_fft_sample */
+       __be16 length;
+       /* type dependent data follows */
+} __packed;
+
+struct fft_sample_ht20 {
+       struct fft_sample_tlv tlv;
+
+       u8 max_exp;
+
+       __be16 freq;
+       s8 rssi;
+       s8 noise;
+
+       __be16 max_magnitude;
+       u8 max_index;
+       u8 bitmap_weight;
+
+       __be64 tsf;
+
+       u8 data[SPECTRAL_HT20_NUM_BINS];
+} __packed;
+
+struct fft_sample_ht20_40 {
+       struct fft_sample_tlv tlv;
+
+       u8 channel_type;
+       __be16 freq;
+
+       s8 lower_rssi;
+       s8 upper_rssi;
+
+       __be64 tsf;
+
+       s8 lower_noise;
+       s8 upper_noise;
+
+       __be16 lower_max_magnitude;
+       __be16 upper_max_magnitude;
+
+       u8 lower_max_index;
+       u8 upper_max_index;
+
+       u8 lower_bitmap_weight;
+       u8 upper_bitmap_weight;
+
+       u8 max_exp;
+
+       u8 data[SPECTRAL_HT20_40_NUM_BINS];
+} __packed;
+
+void ath9k_spectral_init_debug(struct ath_softc *sc);
+void ath9k_spectral_deinit_debug(struct ath_softc *sc);
+
+void ath9k_spectral_scan_trigger(struct ieee80211_hw *hw);
+int ath9k_spectral_scan_config(struct ieee80211_hw *hw,
+                              enum spectral_mode spectral_mode);
+
+#ifdef CONFIG_ATH9K_DEBUGFS
+int ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr,
+                   struct ath_rx_status *rs, u64 tsf);
+#else
+static inline int ath_process_fft(struct ath_softc *sc,
+                                 struct ieee80211_hdr *hdr,
+                                 struct ath_rx_status *rs, u64 tsf)
+{
+       return 0;
+}
+#endif /* CONFIG_ATH9K_DEBUGFS */
+
+#endif /* SPECTRAL_H */
index a907bc94800d323090a7e4d401d6ba4dab9a8835..9d735c55a0f39cf4056685259f6c8bb6f187019b 100644 (file)
@@ -174,14 +174,7 @@ static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq,
 static struct ath_atx_tid *
 ath_get_skb_tid(struct ath_softc *sc, struct ath_node *an, struct sk_buff *skb)
 {
-       struct ieee80211_hdr *hdr;
-       u8 tidno = 0;
-
-       hdr = (struct ieee80211_hdr *) skb->data;
-       if (ieee80211_is_data_qos(hdr->frame_control))
-               tidno = ieee80211_get_qos_ctl(hdr)[0];
-
-       tidno &= IEEE80211_QOS_CTL_TID_MASK;
+       u8 tidno = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
        return ATH_AN_2_TID(an, tidno);
 }
 
index 8f37562e0b113d6e5d4b13e50ea87cba679c6628..750626b0e22d528d6d76fbe4ad402a2c175316be 100644 (file)
@@ -2060,22 +2060,28 @@ static void wcn36xx_smd_rsp_process(struct wcn36xx *wcn, void *buf, size_t len)
        case WCN36XX_HAL_OTA_TX_COMPL_IND:
        case WCN36XX_HAL_MISSED_BEACON_IND:
        case WCN36XX_HAL_DELETE_STA_CONTEXT_IND:
-               mutex_lock(&wcn->hal_ind_mutex);
                msg_ind = kmalloc(sizeof(*msg_ind), GFP_KERNEL);
-               if (msg_ind) {
-                       msg_ind->msg_len = len;
-                       msg_ind->msg = kmalloc(len, GFP_KERNEL);
-                       memcpy(msg_ind->msg, buf, len);
-                       list_add_tail(&msg_ind->list, &wcn->hal_ind_queue);
-                       queue_work(wcn->hal_ind_wq, &wcn->hal_ind_work);
-                       wcn36xx_dbg(WCN36XX_DBG_HAL, "indication arrived\n");
+               if (!msg_ind)
+                       goto nomem;
+               msg_ind->msg_len = len;
+               msg_ind->msg = kmalloc(len, GFP_KERNEL);
+               if (!msg_ind->msg) {
+                       kfree(msg_ind);
+nomem:
+                       /*
+                        * FIXME: Do something smarter then just
+                        * printing an error.
+                        */
+                       wcn36xx_err("Run out of memory while handling SMD_EVENT (%d)\n",
+                                   msg_header->msg_type);
+                       break;
                }
+               memcpy(msg_ind->msg, buf, len);
+               mutex_lock(&wcn->hal_ind_mutex);
+               list_add_tail(&msg_ind->list, &wcn->hal_ind_queue);
+               queue_work(wcn->hal_ind_wq, &wcn->hal_ind_work);
                mutex_unlock(&wcn->hal_ind_mutex);
-               if (msg_ind)
-                       break;
-               /* FIXME: Do something smarter then just printing an error. */
-               wcn36xx_err("Run out of memory while handling SMD_EVENT (%d)\n",
-                           msg_header->msg_type);
+               wcn36xx_dbg(WCN36XX_DBG_HAL, "indication arrived\n");
                break;
        default:
                wcn36xx_err("SMD_EVENT (%d) not supported\n",
index 2082402d4b6364e03424f4ef00161b0fae9c298b..5681b9862023ee360bebc502be6facd22535884e 100644 (file)
@@ -36,7 +36,6 @@ brcmfmac-objs += \
 brcmfmac-$(CONFIG_BRCMFMAC_SDIO) += \
                dhd_sdio.o \
                bcmsdh.o \
-               bcmsdh_sdmmc.o \
                sdio_chip.o
 brcmfmac-$(CONFIG_BRCMFMAC_USB) += \
                usb.o
index 06848e426f9adf408f4795e09f28a7d2a31946ea..12c27d13df7f459426e4abf736540c1b502a68e1 100644 (file)
@@ -101,35 +101,41 @@ struct brcmf_proto_bcdc_header {
                                         * plus any space that might be needed
                                         * for bus alignment padding.
                                         */
-#define ROUND_UP_MARGIN        2048    /* Biggest bus block size possible for
-                                * round off at the end of buffer
-                                * Currently is SDIO
-                                */
-
 struct brcmf_bcdc {
        u16 reqid;
        u8 bus_header[BUS_HEADER_LEN];
        struct brcmf_proto_bcdc_dcmd msg;
-       unsigned char buf[BRCMF_DCMD_MAXLEN + ROUND_UP_MARGIN];
+       unsigned char buf[BRCMF_DCMD_MAXLEN];
 };
 
-static int brcmf_proto_bcdc_msg(struct brcmf_pub *drvr)
+
+static int
+brcmf_proto_bcdc_msg(struct brcmf_pub *drvr, int ifidx, uint cmd, void *buf,
+                    uint len, bool set)
 {
        struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd;
-       int len = le32_to_cpu(bcdc->msg.len) +
-                       sizeof(struct brcmf_proto_bcdc_dcmd);
+       struct brcmf_proto_bcdc_dcmd *msg = &bcdc->msg;
+       u32 flags;
 
        brcmf_dbg(BCDC, "Enter\n");
 
-       /* NOTE : bcdc->msg.len holds the desired length of the buffer to be
-        *        returned. Only up to BCDC_MAX_MSG_SIZE of this buffer area
-        *        is actually sent to the dongle
-        */
-       if (len > BCDC_MAX_MSG_SIZE)
-               len = BCDC_MAX_MSG_SIZE;
+       memset(msg, 0, sizeof(struct brcmf_proto_bcdc_dcmd));
+
+       msg->cmd = cpu_to_le32(cmd);
+       msg->len = cpu_to_le32(len);
+       flags = (++bcdc->reqid << BCDC_DCMD_ID_SHIFT);
+       if (set)
+               flags |= BCDC_DCMD_SET;
+       flags = (flags & ~BCDC_DCMD_IF_MASK) |
+               (ifidx << BCDC_DCMD_IF_SHIFT);
+       msg->flags = cpu_to_le32(flags);
+
+       if (buf)
+               memcpy(bcdc->buf, buf, len);
 
        /* Send request */
-       return brcmf_bus_txctl(drvr->bus_if, (unsigned char *)&bcdc->msg, len);
+       return brcmf_bus_txctl(drvr->bus_if, (unsigned char *)&bcdc->msg,
+                              len + sizeof(struct brcmf_proto_bcdc_dcmd));
 }
 
 static int brcmf_proto_bcdc_cmplt(struct brcmf_pub *drvr, u32 id, u32 len)
@@ -161,19 +167,7 @@ brcmf_proto_bcdc_query_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,
 
        brcmf_dbg(BCDC, "Enter, cmd %d len %d\n", cmd, len);
 
-       memset(msg, 0, sizeof(struct brcmf_proto_bcdc_dcmd));
-
-       msg->cmd = cpu_to_le32(cmd);
-       msg->len = cpu_to_le32(len);
-       flags = (++bcdc->reqid << BCDC_DCMD_ID_SHIFT);
-       flags = (flags & ~BCDC_DCMD_IF_MASK) |
-               (ifidx << BCDC_DCMD_IF_SHIFT);
-       msg->flags = cpu_to_le32(flags);
-
-       if (buf)
-               memcpy(bcdc->buf, buf, len);
-
-       ret = brcmf_proto_bcdc_msg(drvr);
+       ret = brcmf_proto_bcdc_msg(drvr, ifidx, cmd, buf, len, false);
        if (ret < 0) {
                brcmf_err("brcmf_proto_bcdc_msg failed w/status %d\n",
                          ret);
@@ -227,19 +221,7 @@ brcmf_proto_bcdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,
 
        brcmf_dbg(BCDC, "Enter, cmd %d len %d\n", cmd, len);
 
-       memset(msg, 0, sizeof(struct brcmf_proto_bcdc_dcmd));
-
-       msg->cmd = cpu_to_le32(cmd);
-       msg->len = cpu_to_le32(len);
-       flags = (++bcdc->reqid << BCDC_DCMD_ID_SHIFT) | BCDC_DCMD_SET;
-       flags = (flags & ~BCDC_DCMD_IF_MASK) |
-               (ifidx << BCDC_DCMD_IF_SHIFT);
-       msg->flags = cpu_to_le32(flags);
-
-       if (buf)
-               memcpy(bcdc->buf, buf, len);
-
-       ret = brcmf_proto_bcdc_msg(drvr);
+       ret = brcmf_proto_bcdc_msg(drvr, ifidx, cmd, buf, len, true);
        if (ret < 0)
                goto done;
 
@@ -347,6 +329,15 @@ brcmf_proto_bcdc_hdrpull(struct brcmf_pub *drvr, bool do_fws, u8 *ifidx,
        return 0;
 }
 
+static int
+brcmf_proto_bcdc_txdata(struct brcmf_pub *drvr, int ifidx, u8 offset,
+                       struct sk_buff *pktbuf)
+{
+       brcmf_proto_bcdc_hdrpush(drvr, ifidx, offset, pktbuf);
+       return brcmf_bus_txdata(drvr->bus_if, pktbuf);
+}
+
+
 int brcmf_proto_bcdc_attach(struct brcmf_pub *drvr)
 {
        struct brcmf_bcdc *bcdc;
@@ -361,15 +352,15 @@ int brcmf_proto_bcdc_attach(struct brcmf_pub *drvr)
                goto fail;
        }
 
-       drvr->proto->hdrpush = brcmf_proto_bcdc_hdrpush;
        drvr->proto->hdrpull = brcmf_proto_bcdc_hdrpull;
        drvr->proto->query_dcmd = brcmf_proto_bcdc_query_dcmd;
        drvr->proto->set_dcmd = brcmf_proto_bcdc_set_dcmd;
+       drvr->proto->txdata = brcmf_proto_bcdc_txdata;
        drvr->proto->pd = bcdc;
 
        drvr->hdrlen += BCDC_HEADER_LEN + BRCMF_PROT_FW_SIGNAL_MAX_TXBYTES;
        drvr->bus_if->maxctl = BRCMF_DCMD_MAXLEN +
-                       sizeof(struct brcmf_proto_bcdc_dcmd) + ROUND_UP_MARGIN;
+                       sizeof(struct brcmf_proto_bcdc_dcmd);
        return 0;
 
 fail:
index 91651ec7f13fedddaa7c18cce14c7654eb77404e..2b5cde67e728daa9110345549b893e4934386333 100644 (file)
 #include <linux/completion.h>
 #include <linux/scatterlist.h>
 #include <linux/mmc/sdio.h>
+#include <linux/mmc/core.h>
 #include <linux/mmc/sdio_func.h>
+#include <linux/mmc/sdio_ids.h>
 #include <linux/mmc/card.h>
+#include <linux/mmc/host.h>
+#include <linux/platform_device.h>
 #include <linux/platform_data/brcmfmac-sdio.h>
+#include <linux/suspend.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <net/cfg80211.h>
 
 #include <defs.h>
 #include <brcm_hw_ids.h>
 #include "dhd_bus.h"
 #include "dhd_dbg.h"
 #include "sdio_host.h"
+#include "sdio_chip.h"
 
 #define SDIOH_API_ACCESS_RETRY_LIMIT   2
 
+#define SDIO_VENDOR_ID_BROADCOM                0x02d0
 
-static irqreturn_t brcmf_sdio_oob_irqhandler(int irq, void *dev_id)
+#define DMA_ALIGN_MASK 0x03
+
+#define SDIO_FUNC1_BLOCKSIZE           64
+#define SDIO_FUNC2_BLOCKSIZE           512
+/* Maximum milliseconds to wait for F2 to come up */
+#define SDIO_WAIT_F2RDY        3000
+
+
+static irqreturn_t brcmf_sdiod_oob_irqhandler(int irq, void *dev_id)
 {
        struct brcmf_bus *bus_if = dev_get_drvdata(dev_id);
        struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
@@ -54,27 +72,46 @@ static irqreturn_t brcmf_sdio_oob_irqhandler(int irq, void *dev_id)
                sdiodev->irq_en = false;
        }
 
-       brcmf_sdbrcm_isr(sdiodev->bus);
+       brcmf_sdio_isr(sdiodev->bus);
 
        return IRQ_HANDLED;
 }
 
-static void brcmf_sdio_ib_irqhandler(struct sdio_func *func)
+static void brcmf_sdiod_ib_irqhandler(struct sdio_func *func)
 {
        struct brcmf_bus *bus_if = dev_get_drvdata(&func->dev);
        struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
 
        brcmf_dbg(INTR, "IB intr triggered\n");
 
-       brcmf_sdbrcm_isr(sdiodev->bus);
+       brcmf_sdio_isr(sdiodev->bus);
 }
 
 /* dummy handler for SDIO function 2 interrupt */
-static void brcmf_sdio_dummy_irqhandler(struct sdio_func *func)
+static void brcmf_sdiod_dummy_irqhandler(struct sdio_func *func)
+{
+}
+
+static bool brcmf_sdiod_pm_resume_error(struct brcmf_sdio_dev *sdiodev)
 {
+       bool is_err = false;
+#ifdef CONFIG_PM_SLEEP
+       is_err = atomic_read(&sdiodev->suspend);
+#endif
+       return is_err;
 }
 
-int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev)
+static void brcmf_sdiod_pm_resume_wait(struct brcmf_sdio_dev *sdiodev,
+                                      wait_queue_head_t *wq)
+{
+#ifdef CONFIG_PM_SLEEP
+       int retry = 0;
+       while (atomic_read(&sdiodev->suspend) && retry++ != 30)
+               wait_event_timeout(*wq, false, HZ/100);
+#endif
+}
+
+int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev)
 {
        int ret = 0;
        u8 data;
@@ -84,7 +121,7 @@ int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev)
                brcmf_dbg(SDIO, "Enter, register OOB IRQ %d\n",
                          sdiodev->pdata->oob_irq_nr);
                ret = request_irq(sdiodev->pdata->oob_irq_nr,
-                                 brcmf_sdio_oob_irqhandler,
+                                 brcmf_sdiod_oob_irqhandler,
                                  sdiodev->pdata->oob_irq_flags,
                                  "brcmf_oob_intr",
                                  &sdiodev->func[1]->dev);
@@ -108,36 +145,36 @@ int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev)
                sdio_claim_host(sdiodev->func[1]);
 
                /* must configure SDIO_CCCR_IENx to enable irq */
-               data = brcmf_sdio_regrb(sdiodev, SDIO_CCCR_IENx, &ret);
+               data = brcmf_sdiod_regrb(sdiodev, SDIO_CCCR_IENx, &ret);
                data |= 1 << SDIO_FUNC_1 | 1 << SDIO_FUNC_2 | 1;
-               brcmf_sdio_regwb(sdiodev, SDIO_CCCR_IENx, data, &ret);
+               brcmf_sdiod_regwb(sdiodev, SDIO_CCCR_IENx, data, &ret);
 
                /* redirect, configure and enable io for interrupt signal */
                data = SDIO_SEPINT_MASK | SDIO_SEPINT_OE;
                if (sdiodev->pdata->oob_irq_flags & IRQF_TRIGGER_HIGH)
                        data |= SDIO_SEPINT_ACT_HI;
-               brcmf_sdio_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, data, &ret);
+               brcmf_sdiod_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, data, &ret);
 
                sdio_release_host(sdiodev->func[1]);
        } else {
                brcmf_dbg(SDIO, "Entering\n");
                sdio_claim_host(sdiodev->func[1]);
-               sdio_claim_irq(sdiodev->func[1], brcmf_sdio_ib_irqhandler);
-               sdio_claim_irq(sdiodev->func[2], brcmf_sdio_dummy_irqhandler);
+               sdio_claim_irq(sdiodev->func[1], brcmf_sdiod_ib_irqhandler);
+               sdio_claim_irq(sdiodev->func[2], brcmf_sdiod_dummy_irqhandler);
                sdio_release_host(sdiodev->func[1]);
        }
 
        return 0;
 }
 
-int brcmf_sdio_intr_unregister(struct brcmf_sdio_dev *sdiodev)
+int brcmf_sdiod_intr_unregister(struct brcmf_sdio_dev *sdiodev)
 {
        brcmf_dbg(SDIO, "Entering\n");
 
        if ((sdiodev->pdata) && (sdiodev->pdata->oob_irq_supported)) {
                sdio_claim_host(sdiodev->func[1]);
-               brcmf_sdio_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, 0, NULL);
-               brcmf_sdio_regwb(sdiodev, SDIO_CCCR_IENx, 0, NULL);
+               brcmf_sdiod_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, 0, NULL);
+               brcmf_sdiod_regwb(sdiodev, SDIO_CCCR_IENx, 0, NULL);
                sdio_release_host(sdiodev->func[1]);
 
                if (sdiodev->oob_irq_requested) {
@@ -160,8 +197,117 @@ int brcmf_sdio_intr_unregister(struct brcmf_sdio_dev *sdiodev)
        return 0;
 }
 
+static inline int brcmf_sdiod_f0_writeb(struct sdio_func *func,
+                                       uint regaddr, u8 byte)
+{
+       int err_ret;
+
+       /*
+        * Can only directly write to some F0 registers.
+        * Handle CCCR_IENx and CCCR_ABORT command
+        * as a special case.
+        */
+       if ((regaddr == SDIO_CCCR_ABORT) ||
+           (regaddr == SDIO_CCCR_IENx))
+               sdio_writeb(func, byte, regaddr, &err_ret);
+       else
+               sdio_f0_writeb(func, byte, regaddr, &err_ret);
+
+       return err_ret;
+}
+
+static int brcmf_sdiod_request_byte(struct brcmf_sdio_dev *sdiodev, uint rw,
+                                   uint func, uint regaddr, u8 *byte)
+{
+       int err_ret;
+
+       brcmf_dbg(SDIO, "rw=%d, func=%d, addr=0x%05x\n", rw, func, regaddr);
+
+       brcmf_sdiod_pm_resume_wait(sdiodev, &sdiodev->request_byte_wait);
+       if (brcmf_sdiod_pm_resume_error(sdiodev))
+               return -EIO;
+
+       if (rw && func == 0) {
+               /* handle F0 separately */
+               err_ret = brcmf_sdiod_f0_writeb(sdiodev->func[func],
+                                               regaddr, *byte);
+       } else {
+               if (rw) /* CMD52 Write */
+                       sdio_writeb(sdiodev->func[func], *byte, regaddr,
+                                   &err_ret);
+               else if (func == 0) {
+                       *byte = sdio_f0_readb(sdiodev->func[func], regaddr,
+                                             &err_ret);
+               } else {
+                       *byte = sdio_readb(sdiodev->func[func], regaddr,
+                                          &err_ret);
+               }
+       }
+
+       if (err_ret) {
+               /*
+                * SleepCSR register access can fail when
+                * waking up the device so reduce this noise
+                * in the logs.
+                */
+               if (regaddr != SBSDIO_FUNC1_SLEEPCSR)
+                       brcmf_err("Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n",
+                                 rw ? "write" : "read", func, regaddr, *byte,
+                                 err_ret);
+               else
+                       brcmf_dbg(SDIO, "Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n",
+                                 rw ? "write" : "read", func, regaddr, *byte,
+                                 err_ret);
+       }
+       return err_ret;
+}
+
+static int brcmf_sdiod_request_word(struct brcmf_sdio_dev *sdiodev, uint rw,
+                                   uint func, uint addr, u32 *word,
+                                   uint nbytes)
+{
+       int err_ret = -EIO;
+
+       if (func == 0) {
+               brcmf_err("Only CMD52 allowed to F0\n");
+               return -EINVAL;
+       }
+
+       brcmf_dbg(SDIO, "rw=%d, func=%d, addr=0x%05x, nbytes=%d\n",
+                 rw, func, addr, nbytes);
+
+       brcmf_sdiod_pm_resume_wait(sdiodev, &sdiodev->request_word_wait);
+       if (brcmf_sdiod_pm_resume_error(sdiodev))
+               return -EIO;
+
+       if (rw) {               /* CMD52 Write */
+               if (nbytes == 4)
+                       sdio_writel(sdiodev->func[func], *word, addr,
+                                   &err_ret);
+               else if (nbytes == 2)
+                       sdio_writew(sdiodev->func[func], (*word & 0xFFFF),
+                                   addr, &err_ret);
+               else
+                       brcmf_err("Invalid nbytes: %d\n", nbytes);
+       } else {                /* CMD52 Read */
+               if (nbytes == 4)
+                       *word = sdio_readl(sdiodev->func[func], addr, &err_ret);
+               else if (nbytes == 2)
+                       *word = sdio_readw(sdiodev->func[func], addr,
+                                          &err_ret) & 0xFFFF;
+               else
+                       brcmf_err("Invalid nbytes: %d\n", nbytes);
+       }
+
+       if (err_ret)
+               brcmf_err("Failed to %s word, Err: 0x%08x\n",
+                         rw ? "write" : "read", err_ret);
+
+       return err_ret;
+}
+
 static int
-brcmf_sdcard_set_sbaddr_window(struct brcmf_sdio_dev *sdiodev, u32 address)
+brcmf_sdiod_set_sbaddr_window(struct brcmf_sdio_dev *sdiodev, u32 address)
 {
        int err = 0, i;
        u8 addr[3];
@@ -176,7 +322,7 @@ brcmf_sdcard_set_sbaddr_window(struct brcmf_sdio_dev *sdiodev, u32 address)
                do {
                        if (retry)
                                usleep_range(1000, 2000);
-                       err = brcmf_sdioh_request_byte(sdiodev, SDIOH_WRITE,
+                       err = brcmf_sdiod_request_byte(sdiodev, SDIOH_WRITE,
                                        SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW + i,
                                        &addr[i]);
                } while (err != 0 && retry++ < SDIOH_API_ACCESS_RETRY_LIMIT);
@@ -192,13 +338,13 @@ brcmf_sdcard_set_sbaddr_window(struct brcmf_sdio_dev *sdiodev, u32 address)
 }
 
 static int
-brcmf_sdio_addrprep(struct brcmf_sdio_dev *sdiodev, uint width, u32 *addr)
+brcmf_sdiod_addrprep(struct brcmf_sdio_dev *sdiodev, uint width, u32 *addr)
 {
        uint bar0 = *addr & ~SBSDIO_SB_OFT_ADDR_MASK;
        int err = 0;
 
        if (bar0 != sdiodev->sbwad) {
-               err = brcmf_sdcard_set_sbaddr_window(sdiodev, bar0);
+               err = brcmf_sdiod_set_sbaddr_window(sdiodev, bar0);
                if (err)
                        return err;
 
@@ -213,9 +359,8 @@ brcmf_sdio_addrprep(struct brcmf_sdio_dev *sdiodev, uint width, u32 *addr)
        return 0;
 }
 
-int
-brcmf_sdio_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr,
-                       void *data, bool write)
+static int brcmf_sdiod_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr,
+                                   void *data, bool write)
 {
        u8 func_num, reg_size;
        s32 retry = 0;
@@ -237,7 +382,7 @@ brcmf_sdio_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr,
                func_num = SDIO_FUNC_1;
                reg_size = 4;
 
-               ret = brcmf_sdio_addrprep(sdiodev, reg_size, &addr);
+               ret = brcmf_sdiod_addrprep(sdiodev, reg_size, &addr);
                if (ret)
                        goto done;
        }
@@ -248,10 +393,10 @@ brcmf_sdio_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr,
                if (retry)      /* wait for 1 ms till bus get settled down */
                        usleep_range(1000, 2000);
                if (reg_size == 1)
-                       ret = brcmf_sdioh_request_byte(sdiodev, write,
+                       ret = brcmf_sdiod_request_byte(sdiodev, write,
                                                       func_num, addr, data);
                else
-                       ret = brcmf_sdioh_request_word(sdiodev, write,
+                       ret = brcmf_sdiod_request_word(sdiodev, write,
                                                       func_num, addr, data, 4);
        } while (ret != 0 && retry++ < SDIOH_API_ACCESS_RETRY_LIMIT);
 
@@ -262,13 +407,13 @@ done:
        return ret;
 }
 
-u8 brcmf_sdio_regrb(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret)
+u8 brcmf_sdiod_regrb(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret)
 {
        u8 data;
        int retval;
 
        brcmf_dbg(SDIO, "addr:0x%08x\n", addr);
-       retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, false);
+       retval = brcmf_sdiod_regrw_helper(sdiodev, addr, &data, false);
        brcmf_dbg(SDIO, "data:0x%02x\n", data);
 
        if (ret)
@@ -277,13 +422,13 @@ u8 brcmf_sdio_regrb(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret)
        return data;
 }
 
-u32 brcmf_sdio_regrl(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret)
+u32 brcmf_sdiod_regrl(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret)
 {
        u32 data;
        int retval;
 
        brcmf_dbg(SDIO, "addr:0x%08x\n", addr);
-       retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, false);
+       retval = brcmf_sdiod_regrw_helper(sdiodev, addr, &data, false);
        brcmf_dbg(SDIO, "data:0x%08x\n", data);
 
        if (ret)
@@ -292,37 +437,37 @@ u32 brcmf_sdio_regrl(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret)
        return data;
 }
 
-void brcmf_sdio_regwb(struct brcmf_sdio_dev *sdiodev, u32 addr,
+void brcmf_sdiod_regwb(struct brcmf_sdio_dev *sdiodev, u32 addr,
                      u8 data, int *ret)
 {
        int retval;
 
        brcmf_dbg(SDIO, "addr:0x%08x, data:0x%02x\n", addr, data);
-       retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, true);
+       retval = brcmf_sdiod_regrw_helper(sdiodev, addr, &data, true);
 
        if (ret)
                *ret = retval;
 }
 
-void brcmf_sdio_regwl(struct brcmf_sdio_dev *sdiodev, u32 addr,
+void brcmf_sdiod_regwl(struct brcmf_sdio_dev *sdiodev, u32 addr,
                      u32 data, int *ret)
 {
        int retval;
 
        brcmf_dbg(SDIO, "addr:0x%08x, data:0x%08x\n", addr, data);
-       retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, true);
+       retval = brcmf_sdiod_regrw_helper(sdiodev, addr, &data, true);
 
        if (ret)
                *ret = retval;
 }
 
-static int brcmf_sdio_buffrw(struct brcmf_sdio_dev *sdiodev, uint fn,
+static int brcmf_sdiod_buffrw(struct brcmf_sdio_dev *sdiodev, uint fn,
                             bool write, u32 addr, struct sk_buff *pkt)
 {
        unsigned int req_sz;
 
-       brcmf_pm_resume_wait(sdiodev, &sdiodev->request_buffer_wait);
-       if (brcmf_pm_resume_error(sdiodev))
+       brcmf_sdiod_pm_resume_wait(sdiodev, &sdiodev->request_buffer_wait);
+       if (brcmf_sdiod_pm_resume_error(sdiodev))
                return -EIO;
 
        /* Single skb use the standard mmc interface */
@@ -345,7 +490,7 @@ static int brcmf_sdio_buffrw(struct brcmf_sdio_dev *sdiodev, uint fn,
 }
 
 /**
- * brcmf_sdio_sglist_rw - SDIO interface function for block data access
+ * brcmf_sdiod_sglist_rw - SDIO interface function for block data access
  * @sdiodev: brcmfmac sdio device
  * @fn: SDIO function number
  * @write: direction flag
@@ -356,9 +501,9 @@ static int brcmf_sdio_buffrw(struct brcmf_sdio_dev *sdiodev, uint fn,
  * stack for block data access. It assumes that the skb passed down by the
  * caller has already been padded and aligned.
  */
-static int brcmf_sdio_sglist_rw(struct brcmf_sdio_dev *sdiodev, uint fn,
-                               bool write, u32 addr,
-                               struct sk_buff_head *pktlist)
+static int brcmf_sdiod_sglist_rw(struct brcmf_sdio_dev *sdiodev, uint fn,
+                                bool write, u32 addr,
+                                struct sk_buff_head *pktlist)
 {
        unsigned int req_sz, func_blk_sz, sg_cnt, sg_data_sz, pkt_offset;
        unsigned int max_req_sz, orig_offset, dst_offset;
@@ -376,8 +521,8 @@ static int brcmf_sdio_sglist_rw(struct brcmf_sdio_dev *sdiodev, uint fn,
        if (!pktlist->qlen)
                return -EINVAL;
 
-       brcmf_pm_resume_wait(sdiodev, &sdiodev->request_buffer_wait);
-       if (brcmf_pm_resume_error(sdiodev))
+       brcmf_sdiod_pm_resume_wait(sdiodev, &sdiodev->request_buffer_wait);
+       if (brcmf_sdiod_pm_resume_error(sdiodev))
                return -EIO;
 
        target_list = pktlist;
@@ -524,9 +669,7 @@ exit:
        return ret;
 }
 
-int
-brcmf_sdcard_recv_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
-                     uint flags, u8 *buf, uint nbytes)
+int brcmf_sdiod_recv_buf(struct brcmf_sdio_dev *sdiodev, u8 *buf, uint nbytes)
 {
        struct sk_buff *mypkt;
        int err;
@@ -538,7 +681,7 @@ brcmf_sdcard_recv_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
                return -EIO;
        }
 
-       err = brcmf_sdcard_recv_pkt(sdiodev, addr, fn, flags, mypkt);
+       err = brcmf_sdiod_recv_pkt(sdiodev, mypkt);
        if (!err)
                memcpy(buf, mypkt->data, nbytes);
 
@@ -546,50 +689,47 @@ brcmf_sdcard_recv_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
        return err;
 }
 
-int
-brcmf_sdcard_recv_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
-                     uint flags, struct sk_buff *pkt)
+int brcmf_sdiod_recv_pkt(struct brcmf_sdio_dev *sdiodev, struct sk_buff *pkt)
 {
-       uint width;
+       u32 addr = sdiodev->sbwad;
        int err = 0;
 
-       brcmf_dbg(SDIO, "fun = %d, addr = 0x%x, size = %d\n",
-                 fn, addr, pkt->len);
+       brcmf_dbg(SDIO, "addr = 0x%x, size = %d\n", addr, pkt->len);
 
-       width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
-       err = brcmf_sdio_addrprep(sdiodev, width, &addr);
+       err = brcmf_sdiod_addrprep(sdiodev, 4, &addr);
        if (err)
                goto done;
 
-       err = brcmf_sdio_buffrw(sdiodev, fn, false, addr, pkt);
+       err = brcmf_sdiod_buffrw(sdiodev, SDIO_FUNC_2, false, addr, pkt);
 
 done:
        return err;
 }
 
-int brcmf_sdcard_recv_chain(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
-                           uint flags, struct sk_buff_head *pktq, uint totlen)
+int brcmf_sdiod_recv_chain(struct brcmf_sdio_dev *sdiodev,
+                          struct sk_buff_head *pktq, uint totlen)
 {
        struct sk_buff *glom_skb;
        struct sk_buff *skb;
-       uint width;
+       u32 addr = sdiodev->sbwad;
        int err = 0;
 
-       brcmf_dbg(SDIO, "fun = %d, addr = 0x%x, size = %d\n",
-                 fn, addr, pktq->qlen);
+       brcmf_dbg(SDIO, "addr = 0x%x, size = %d\n",
+                 addr, pktq->qlen);
 
-       width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
-       err = brcmf_sdio_addrprep(sdiodev, width, &addr);
+       err = brcmf_sdiod_addrprep(sdiodev, 4, &addr);
        if (err)
                goto done;
 
        if (pktq->qlen == 1)
-               err = brcmf_sdio_buffrw(sdiodev, fn, false, addr, pktq->next);
+               err = brcmf_sdiod_buffrw(sdiodev, SDIO_FUNC_2, false, addr,
+                                        pktq->next);
        else if (!sdiodev->sg_support) {
                glom_skb = brcmu_pkt_buf_get_skb(totlen);
                if (!glom_skb)
                        return -ENOMEM;
-               err = brcmf_sdio_buffrw(sdiodev, fn, false, addr, glom_skb);
+               err = brcmf_sdiod_buffrw(sdiodev, SDIO_FUNC_2, false, addr,
+                                        glom_skb);
                if (err)
                        goto done;
 
@@ -598,18 +738,17 @@ int brcmf_sdcard_recv_chain(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
                        skb_pull(glom_skb, skb->len);
                }
        } else
-               err = brcmf_sdio_sglist_rw(sdiodev, fn, false, addr, pktq);
+               err = brcmf_sdiod_sglist_rw(sdiodev, SDIO_FUNC_2, false, addr,
+                                           pktq);
 
 done:
        return err;
 }
 
-int
-brcmf_sdcard_send_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
-                     uint flags, u8 *buf, uint nbytes)
+int brcmf_sdiod_send_buf(struct brcmf_sdio_dev *sdiodev, u8 *buf, uint nbytes)
 {
        struct sk_buff *mypkt;
-       uint width;
+       u32 addr = sdiodev->sbwad;
        int err;
 
        mypkt = brcmu_pkt_buf_get_skb(nbytes);
@@ -621,48 +760,47 @@ brcmf_sdcard_send_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
 
        memcpy(mypkt->data, buf, nbytes);
 
-       width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
-       err = brcmf_sdio_addrprep(sdiodev, width, &addr);
+       err = brcmf_sdiod_addrprep(sdiodev, 4, &addr);
 
        if (!err)
-               err = brcmf_sdio_buffrw(sdiodev, fn, true, addr, mypkt);
+               err = brcmf_sdiod_buffrw(sdiodev, SDIO_FUNC_2, true, addr,
+                                        mypkt);
 
        brcmu_pkt_buf_free_skb(mypkt);
        return err;
 
 }
 
-int
-brcmf_sdcard_send_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
-                     uint flags, struct sk_buff_head *pktq)
+int brcmf_sdiod_send_pkt(struct brcmf_sdio_dev *sdiodev,
+                        struct sk_buff_head *pktq)
 {
        struct sk_buff *skb;
-       uint width;
+       u32 addr = sdiodev->sbwad;
        int err;
 
-       brcmf_dbg(SDIO, "fun = %d, addr = 0x%x, size = %d\n",
-                 fn, addr, pktq->qlen);
+       brcmf_dbg(SDIO, "addr = 0x%x, size = %d\n", addr, pktq->qlen);
 
-       width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
-       err = brcmf_sdio_addrprep(sdiodev, width, &addr);
+       err = brcmf_sdiod_addrprep(sdiodev, 4, &addr);
        if (err)
                return err;
 
        if (pktq->qlen == 1 || !sdiodev->sg_support)
                skb_queue_walk(pktq, skb) {
-                       err = brcmf_sdio_buffrw(sdiodev, fn, true, addr, skb);
+                       err = brcmf_sdiod_buffrw(sdiodev, SDIO_FUNC_2, true,
+                                                addr, skb);
                        if (err)
                                break;
                }
        else
-               err = brcmf_sdio_sglist_rw(sdiodev, fn, true, addr, pktq);
+               err = brcmf_sdiod_sglist_rw(sdiodev, SDIO_FUNC_2, true, addr,
+                                           pktq);
 
        return err;
 }
 
 int
-brcmf_sdio_ramrw(struct brcmf_sdio_dev *sdiodev, bool write, u32 address,
-                u8 *data, uint size)
+brcmf_sdiod_ramrw(struct brcmf_sdio_dev *sdiodev, bool write, u32 address,
+                 u8 *data, uint size)
 {
        int bcmerror = 0;
        struct sk_buff *pkt;
@@ -689,7 +827,7 @@ brcmf_sdio_ramrw(struct brcmf_sdio_dev *sdiodev, bool write, u32 address,
        /* Do the transfer(s) */
        while (size) {
                /* Set the backplane window to include the start address */
-               bcmerror = brcmf_sdcard_set_sbaddr_window(sdiodev, address);
+               bcmerror = brcmf_sdiod_set_sbaddr_window(sdiodev, address);
                if (bcmerror)
                        break;
 
@@ -703,8 +841,8 @@ brcmf_sdio_ramrw(struct brcmf_sdio_dev *sdiodev, bool write, u32 address,
                skb_put(pkt, dsize);
                if (write)
                        memcpy(pkt->data, data, dsize);
-               bcmerror = brcmf_sdio_buffrw(sdiodev, SDIO_FUNC_1, write,
-                                            sdaddr, pkt);
+               bcmerror = brcmf_sdiod_buffrw(sdiodev, SDIO_FUNC_1, write,
+                                             sdaddr, pkt);
                if (bcmerror) {
                        brcmf_err("membytes transfer failed\n");
                        break;
@@ -726,7 +864,7 @@ brcmf_sdio_ramrw(struct brcmf_sdio_dev *sdiodev, bool write, u32 address,
        dev_kfree_skb(pkt);
 
        /* Return the window to backplane enumeration space for core access */
-       if (brcmf_sdcard_set_sbaddr_window(sdiodev, sdiodev->sbwad))
+       if (brcmf_sdiod_set_sbaddr_window(sdiodev, sdiodev->sbwad))
                brcmf_err("FAILED to set window back to 0x%x\n",
                          sdiodev->sbwad);
 
@@ -735,65 +873,337 @@ brcmf_sdio_ramrw(struct brcmf_sdio_dev *sdiodev, bool write, u32 address,
        return bcmerror;
 }
 
-int brcmf_sdcard_abort(struct brcmf_sdio_dev *sdiodev, uint fn)
+int brcmf_sdiod_abort(struct brcmf_sdio_dev *sdiodev, uint fn)
 {
        char t_func = (char)fn;
        brcmf_dbg(SDIO, "Enter\n");
 
        /* issue abort cmd52 command through F0 */
-       brcmf_sdioh_request_byte(sdiodev, SDIOH_WRITE, SDIO_FUNC_0,
+       brcmf_sdiod_request_byte(sdiodev, SDIOH_WRITE, SDIO_FUNC_0,
                                 SDIO_CCCR_ABORT, &t_func);
 
        brcmf_dbg(SDIO, "Exit\n");
        return 0;
 }
 
-int brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
+static int brcmf_sdiod_remove(struct brcmf_sdio_dev *sdiodev)
+{
+       sdiodev->bus_if->state = BRCMF_BUS_DOWN;
+
+       if (sdiodev->bus) {
+               brcmf_sdio_remove(sdiodev->bus);
+               sdiodev->bus = NULL;
+       }
+
+       /* Disable Function 2 */
+       sdio_claim_host(sdiodev->func[2]);
+       sdio_disable_func(sdiodev->func[2]);
+       sdio_release_host(sdiodev->func[2]);
+
+       /* Disable Function 1 */
+       sdio_claim_host(sdiodev->func[1]);
+       sdio_disable_func(sdiodev->func[1]);
+       sdio_release_host(sdiodev->func[1]);
+
+       sdiodev->sbwad = 0;
+
+       return 0;
+}
+
+static int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev)
 {
-       u32 regs = 0;
+       struct sdio_func *func;
+       struct mmc_host *host;
+       uint max_blocks;
        int ret = 0;
 
-       ret = brcmf_sdioh_attach(sdiodev);
-       if (ret)
+       sdiodev->num_funcs = 2;
+
+       sdio_claim_host(sdiodev->func[1]);
+
+       ret = sdio_set_block_size(sdiodev->func[1], SDIO_FUNC1_BLOCKSIZE);
+       if (ret) {
+               brcmf_err("Failed to set F1 blocksize\n");
+               sdio_release_host(sdiodev->func[1]);
+               goto out;
+       }
+       ret = sdio_set_block_size(sdiodev->func[2], SDIO_FUNC2_BLOCKSIZE);
+       if (ret) {
+               brcmf_err("Failed to set F2 blocksize\n");
+               sdio_release_host(sdiodev->func[1]);
+               goto out;
+       }
+
+       /* increase F2 timeout */
+       sdiodev->func[2]->enable_timeout = SDIO_WAIT_F2RDY;
+
+       /* Enable Function 1 */
+       ret = sdio_enable_func(sdiodev->func[1]);
+       sdio_release_host(sdiodev->func[1]);
+       if (ret) {
+               brcmf_err("Failed to enable F1: err=%d\n", ret);
                goto out;
+       }
 
-       regs = SI_ENUM_BASE;
+       /*
+        * determine host related variables after brcmf_sdiod_probe()
+        * as func->cur_blksize is properly set and F2 init has been
+        * completed successfully.
+        */
+       func = sdiodev->func[2];
+       host = func->card->host;
+       sdiodev->sg_support = host->max_segs > 1;
+       max_blocks = min_t(uint, host->max_blk_count, 511u);
+       sdiodev->max_request_size = min_t(uint, host->max_req_size,
+                                         max_blocks * func->cur_blksize);
+       sdiodev->max_segment_count = min_t(uint, host->max_segs,
+                                          SG_MAX_SINGLE_ALLOC);
+       sdiodev->max_segment_size = host->max_seg_size;
 
        /* try to attach to the target device */
-       sdiodev->bus = brcmf_sdbrcm_probe(regs, sdiodev);
+       sdiodev->bus = brcmf_sdio_probe(sdiodev);
        if (!sdiodev->bus) {
-               brcmf_err("device attach failed\n");
                ret = -ENODEV;
                goto out;
        }
 
 out:
        if (ret)
-               brcmf_sdio_remove(sdiodev);
+               brcmf_sdiod_remove(sdiodev);
 
        return ret;
 }
 
-int brcmf_sdio_remove(struct brcmf_sdio_dev *sdiodev)
+/* devices we support, null terminated */
+static const struct sdio_device_id brcmf_sdmmc_ids[] = {
+       {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_43143)},
+       {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_43241)},
+       {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4329)},
+       {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4330)},
+       {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4334)},
+       {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM,
+                    SDIO_DEVICE_ID_BROADCOM_4335_4339)},
+       { /* end: all zeroes */ },
+};
+MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids);
+
+static struct brcmfmac_sdio_platform_data *brcmfmac_sdio_pdata;
+
+
+static int brcmf_ops_sdio_probe(struct sdio_func *func,
+                               const struct sdio_device_id *id)
 {
-       sdiodev->bus_if->state = BRCMF_BUS_DOWN;
+       int err;
+       struct brcmf_sdio_dev *sdiodev;
+       struct brcmf_bus *bus_if;
 
-       if (sdiodev->bus) {
-               brcmf_sdbrcm_disconnect(sdiodev->bus);
-               sdiodev->bus = NULL;
+       brcmf_dbg(SDIO, "Enter\n");
+       brcmf_dbg(SDIO, "Class=%x\n", func->class);
+       brcmf_dbg(SDIO, "sdio vendor ID: 0x%04x\n", func->vendor);
+       brcmf_dbg(SDIO, "sdio device ID: 0x%04x\n", func->device);
+       brcmf_dbg(SDIO, "Function#: %d\n", func->num);
+
+       /* Consume func num 1 but dont do anything with it. */
+       if (func->num == 1)
+               return 0;
+
+       /* Ignore anything but func 2 */
+       if (func->num != 2)
+               return -ENODEV;
+
+       bus_if = kzalloc(sizeof(struct brcmf_bus), GFP_KERNEL);
+       if (!bus_if)
+               return -ENOMEM;
+       sdiodev = kzalloc(sizeof(struct brcmf_sdio_dev), GFP_KERNEL);
+       if (!sdiodev) {
+               kfree(bus_if);
+               return -ENOMEM;
        }
 
-       brcmf_sdioh_detach(sdiodev);
+       /* store refs to functions used. mmc_card does
+        * not hold the F0 function pointer.
+        */
+       sdiodev->func[0] = kmemdup(func, sizeof(*func), GFP_KERNEL);
+       sdiodev->func[0]->num = 0;
+       sdiodev->func[1] = func->card->sdio_func[0];
+       sdiodev->func[2] = func;
+
+       sdiodev->bus_if = bus_if;
+       bus_if->bus_priv.sdio = sdiodev;
+       bus_if->proto_type = BRCMF_PROTO_BCDC;
+       dev_set_drvdata(&func->dev, bus_if);
+       dev_set_drvdata(&sdiodev->func[1]->dev, bus_if);
+       sdiodev->dev = &sdiodev->func[1]->dev;
+       sdiodev->pdata = brcmfmac_sdio_pdata;
+
+       atomic_set(&sdiodev->suspend, false);
+       init_waitqueue_head(&sdiodev->request_byte_wait);
+       init_waitqueue_head(&sdiodev->request_word_wait);
+       init_waitqueue_head(&sdiodev->request_buffer_wait);
+
+       brcmf_dbg(SDIO, "F2 found, calling brcmf_sdiod_probe...\n");
+       err = brcmf_sdiod_probe(sdiodev);
+       if (err) {
+               brcmf_err("F2 error, probe failed %d...\n", err);
+               goto fail;
+       }
 
-       sdiodev->sbwad = 0;
+       brcmf_dbg(SDIO, "F2 init completed...\n");
+       return 0;
+
+fail:
+       dev_set_drvdata(&func->dev, NULL);
+       dev_set_drvdata(&sdiodev->func[1]->dev, NULL);
+       kfree(sdiodev->func[0]);
+       kfree(sdiodev);
+       kfree(bus_if);
+       return err;
+}
+
+static void brcmf_ops_sdio_remove(struct sdio_func *func)
+{
+       struct brcmf_bus *bus_if;
+       struct brcmf_sdio_dev *sdiodev;
+
+       brcmf_dbg(SDIO, "Enter\n");
+       brcmf_dbg(SDIO, "sdio vendor ID: 0x%04x\n", func->vendor);
+       brcmf_dbg(SDIO, "sdio device ID: 0x%04x\n", func->device);
+       brcmf_dbg(SDIO, "Function: %d\n", func->num);
+
+       if (func->num != 1 && func->num != 2)
+               return;
+
+       bus_if = dev_get_drvdata(&func->dev);
+       if (bus_if) {
+               sdiodev = bus_if->bus_priv.sdio;
+               brcmf_sdiod_remove(sdiodev);
+
+               dev_set_drvdata(&sdiodev->func[1]->dev, NULL);
+               dev_set_drvdata(&sdiodev->func[2]->dev, NULL);
+
+               kfree(bus_if);
+               kfree(sdiodev->func[0]);
+               kfree(sdiodev);
+       }
+
+       brcmf_dbg(SDIO, "Exit\n");
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int brcmf_ops_sdio_suspend(struct device *dev)
+{
+       mmc_pm_flag_t sdio_flags;
+       struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+       struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
+       int ret = 0;
+
+       brcmf_dbg(SDIO, "\n");
+
+       atomic_set(&sdiodev->suspend, true);
+
+       sdio_flags = sdio_get_host_pm_caps(sdiodev->func[1]);
+       if (!(sdio_flags & MMC_PM_KEEP_POWER)) {
+               brcmf_err("Host can't keep power while suspended\n");
+               return -EINVAL;
+       }
+
+       ret = sdio_set_host_pm_flags(sdiodev->func[1], MMC_PM_KEEP_POWER);
+       if (ret) {
+               brcmf_err("Failed to set pm_flags\n");
+               return ret;
+       }
+
+       brcmf_sdio_wd_timer(sdiodev->bus, 0);
+
+       return ret;
+}
+
+static int brcmf_ops_sdio_resume(struct device *dev)
+{
+       struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+       struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
+
+       brcmf_sdio_wd_timer(sdiodev->bus, BRCMF_WD_POLL_MS);
+       atomic_set(&sdiodev->suspend, false);
+       return 0;
+}
+
+static const struct dev_pm_ops brcmf_sdio_pm_ops = {
+       .suspend        = brcmf_ops_sdio_suspend,
+       .resume         = brcmf_ops_sdio_resume,
+};
+#endif /* CONFIG_PM_SLEEP */
+
+static struct sdio_driver brcmf_sdmmc_driver = {
+       .probe = brcmf_ops_sdio_probe,
+       .remove = brcmf_ops_sdio_remove,
+       .name = BRCMFMAC_SDIO_PDATA_NAME,
+       .id_table = brcmf_sdmmc_ids,
+#ifdef CONFIG_PM_SLEEP
+       .drv = {
+               .pm = &brcmf_sdio_pm_ops,
+       },
+#endif /* CONFIG_PM_SLEEP */
+};
+
+static int brcmf_sdio_pd_probe(struct platform_device *pdev)
+{
+       brcmf_dbg(SDIO, "Enter\n");
+
+       brcmfmac_sdio_pdata = dev_get_platdata(&pdev->dev);
+
+       if (brcmfmac_sdio_pdata->power_on)
+               brcmfmac_sdio_pdata->power_on();
+
+       return 0;
+}
+
+static int brcmf_sdio_pd_remove(struct platform_device *pdev)
+{
+       brcmf_dbg(SDIO, "Enter\n");
+
+       if (brcmfmac_sdio_pdata->power_off)
+               brcmfmac_sdio_pdata->power_off();
+
+       sdio_unregister_driver(&brcmf_sdmmc_driver);
 
        return 0;
 }
 
-void brcmf_sdio_wdtmr_enable(struct brcmf_sdio_dev *sdiodev, bool enable)
+static struct platform_driver brcmf_sdio_pd = {
+       .remove         = brcmf_sdio_pd_remove,
+       .driver         = {
+               .name   = BRCMFMAC_SDIO_PDATA_NAME,
+               .owner  = THIS_MODULE,
+       }
+};
+
+void brcmf_sdio_register(void)
+{
+       int ret;
+
+       ret = sdio_register_driver(&brcmf_sdmmc_driver);
+       if (ret)
+               brcmf_err("sdio_register_driver failed: %d\n", ret);
+}
+
+void brcmf_sdio_exit(void)
 {
-       if (enable)
-               brcmf_sdbrcm_wd_timer(sdiodev->bus, BRCMF_WD_POLL_MS);
+       brcmf_dbg(SDIO, "Enter\n");
+
+       if (brcmfmac_sdio_pdata)
+               platform_driver_unregister(&brcmf_sdio_pd);
        else
-               brcmf_sdbrcm_wd_timer(sdiodev->bus, 0);
+               sdio_unregister_driver(&brcmf_sdmmc_driver);
+}
+
+void __init brcmf_sdio_init(void)
+{
+       int ret;
+
+       brcmf_dbg(SDIO, "Enter\n");
+
+       ret = platform_driver_probe(&brcmf_sdio_pd, brcmf_sdio_pd_probe);
+       if (ret == -ENODEV)
+               brcmf_dbg(SDIO, "No platform data available.\n");
 }
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c
deleted file mode 100644 (file)
index a511c27..0000000
+++ /dev/null
@@ -1,552 +0,0 @@
-/*
- * 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/netdevice.h>
-#include <linux/mmc/sdio.h>
-#include <linux/mmc/core.h>
-#include <linux/mmc/sdio_func.h>
-#include <linux/mmc/sdio_ids.h>
-#include <linux/mmc/card.h>
-#include <linux/mmc/host.h>
-#include <linux/suspend.h>
-#include <linux/errno.h>
-#include <linux/sched.h>       /* request_irq() */
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/platform_data/brcmfmac-sdio.h>
-#include <net/cfg80211.h>
-
-#include <defs.h>
-#include <brcm_hw_ids.h>
-#include <brcmu_utils.h>
-#include <brcmu_wifi.h>
-#include "sdio_host.h"
-#include "sdio_chip.h"
-#include "dhd_dbg.h"
-#include "dhd_bus.h"
-
-#define SDIO_VENDOR_ID_BROADCOM                0x02d0
-
-#define DMA_ALIGN_MASK 0x03
-
-#define SDIO_FUNC1_BLOCKSIZE           64
-#define SDIO_FUNC2_BLOCKSIZE           512
-
-/* devices we support, null terminated */
-static const struct sdio_device_id brcmf_sdmmc_ids[] = {
-       {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_43143)},
-       {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_43241)},
-       {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4329)},
-       {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4330)},
-       {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4334)},
-       {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM,
-                    SDIO_DEVICE_ID_BROADCOM_4335_4339)},
-       { /* end: all zeroes */ },
-};
-MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids);
-
-static struct brcmfmac_sdio_platform_data *brcmfmac_sdio_pdata;
-
-
-bool
-brcmf_pm_resume_error(struct brcmf_sdio_dev *sdiodev)
-{
-       bool is_err = false;
-#ifdef CONFIG_PM_SLEEP
-       is_err = atomic_read(&sdiodev->suspend);
-#endif
-       return is_err;
-}
-
-void
-brcmf_pm_resume_wait(struct brcmf_sdio_dev *sdiodev, wait_queue_head_t *wq)
-{
-#ifdef CONFIG_PM_SLEEP
-       int retry = 0;
-       while (atomic_read(&sdiodev->suspend) && retry++ != 30)
-               wait_event_timeout(*wq, false, HZ/100);
-#endif
-}
-
-static inline int brcmf_sdioh_f0_write_byte(struct brcmf_sdio_dev *sdiodev,
-                                           uint regaddr, u8 *byte)
-{
-       struct sdio_func *sdfunc = sdiodev->func[0];
-       int err_ret;
-
-       /*
-        * Can only directly write to some F0 registers.
-        * Handle F2 enable/disable and Abort command
-        * as a special case.
-        */
-       if (regaddr == SDIO_CCCR_IOEx) {
-               sdfunc = sdiodev->func[2];
-               if (sdfunc) {
-                       if (*byte & SDIO_FUNC_ENABLE_2) {
-                               /* Enable Function 2 */
-                               err_ret = sdio_enable_func(sdfunc);
-                               if (err_ret)
-                                       brcmf_err("enable F2 failed:%d\n",
-                                                 err_ret);
-                       } else {
-                               /* Disable Function 2 */
-                               err_ret = sdio_disable_func(sdfunc);
-                               if (err_ret)
-                                       brcmf_err("Disable F2 failed:%d\n",
-                                                 err_ret);
-                       }
-               } else {
-                       err_ret = -ENOENT;
-               }
-       } else if ((regaddr == SDIO_CCCR_ABORT) ||
-                  (regaddr == SDIO_CCCR_IENx)) {
-               sdfunc = kmemdup(sdiodev->func[0], sizeof(struct sdio_func),
-                                GFP_KERNEL);
-               if (!sdfunc)
-                       return -ENOMEM;
-               sdfunc->num = 0;
-               sdio_writeb(sdfunc, *byte, regaddr, &err_ret);
-               kfree(sdfunc);
-       } else if (regaddr < 0xF0) {
-               brcmf_err("F0 Wr:0x%02x: write disallowed\n", regaddr);
-               err_ret = -EPERM;
-       } else {
-               sdio_f0_writeb(sdfunc, *byte, regaddr, &err_ret);
-       }
-
-       return err_ret;
-}
-
-int brcmf_sdioh_request_byte(struct brcmf_sdio_dev *sdiodev, uint rw, uint func,
-                            uint regaddr, u8 *byte)
-{
-       int err_ret;
-
-       brcmf_dbg(SDIO, "rw=%d, func=%d, addr=0x%05x\n", rw, func, regaddr);
-
-       brcmf_pm_resume_wait(sdiodev, &sdiodev->request_byte_wait);
-       if (brcmf_pm_resume_error(sdiodev))
-               return -EIO;
-
-       if (rw && func == 0) {
-               /* handle F0 separately */
-               err_ret = brcmf_sdioh_f0_write_byte(sdiodev, regaddr, byte);
-       } else {
-               if (rw) /* CMD52 Write */
-                       sdio_writeb(sdiodev->func[func], *byte, regaddr,
-                                   &err_ret);
-               else if (func == 0) {
-                       *byte = sdio_f0_readb(sdiodev->func[func], regaddr,
-                                             &err_ret);
-               } else {
-                       *byte = sdio_readb(sdiodev->func[func], regaddr,
-                                          &err_ret);
-               }
-       }
-
-       if (err_ret) {
-               /*
-                * SleepCSR register access can fail when
-                * waking up the device so reduce this noise
-                * in the logs.
-                */
-               if (regaddr != SBSDIO_FUNC1_SLEEPCSR)
-                       brcmf_err("Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n",
-                                 rw ? "write" : "read", func, regaddr, *byte,
-                                 err_ret);
-               else
-                       brcmf_dbg(SDIO, "Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n",
-                                 rw ? "write" : "read", func, regaddr, *byte,
-                                 err_ret);
-       }
-       return err_ret;
-}
-
-int brcmf_sdioh_request_word(struct brcmf_sdio_dev *sdiodev,
-                            uint rw, uint func, uint addr, u32 *word,
-                            uint nbytes)
-{
-       int err_ret = -EIO;
-
-       if (func == 0) {
-               brcmf_err("Only CMD52 allowed to F0\n");
-               return -EINVAL;
-       }
-
-       brcmf_dbg(SDIO, "rw=%d, func=%d, addr=0x%05x, nbytes=%d\n",
-                 rw, func, addr, nbytes);
-
-       brcmf_pm_resume_wait(sdiodev, &sdiodev->request_word_wait);
-       if (brcmf_pm_resume_error(sdiodev))
-               return -EIO;
-
-       if (rw) {               /* CMD52 Write */
-               if (nbytes == 4)
-                       sdio_writel(sdiodev->func[func], *word, addr,
-                                   &err_ret);
-               else if (nbytes == 2)
-                       sdio_writew(sdiodev->func[func], (*word & 0xFFFF),
-                                   addr, &err_ret);
-               else
-                       brcmf_err("Invalid nbytes: %d\n", nbytes);
-       } else {                /* CMD52 Read */
-               if (nbytes == 4)
-                       *word = sdio_readl(sdiodev->func[func], addr, &err_ret);
-               else if (nbytes == 2)
-                       *word = sdio_readw(sdiodev->func[func], addr,
-                                          &err_ret) & 0xFFFF;
-               else
-                       brcmf_err("Invalid nbytes: %d\n", nbytes);
-       }
-
-       if (err_ret)
-               brcmf_err("Failed to %s word, Err: 0x%08x\n",
-                         rw ? "write" : "read", err_ret);
-
-       return err_ret;
-}
-
-static int brcmf_sdioh_get_cisaddr(struct brcmf_sdio_dev *sdiodev, u32 regaddr)
-{
-       /* read 24 bits and return valid 17 bit addr */
-       int i, ret;
-       u32 scratch, regdata;
-       __le32 scratch_le;
-       u8 *ptr = (u8 *)&scratch_le;
-
-       for (i = 0; i < 3; i++) {
-               regdata = brcmf_sdio_regrl(sdiodev, regaddr, &ret);
-               if (ret != 0)
-                       brcmf_err("Can't read!\n");
-
-               *ptr++ = (u8) regdata;
-               regaddr++;
-       }
-
-       /* Only the lower 17-bits are valid */
-       scratch = le32_to_cpu(scratch_le);
-       scratch &= 0x0001FFFF;
-       return scratch;
-}
-
-static int brcmf_sdioh_enablefuncs(struct brcmf_sdio_dev *sdiodev)
-{
-       int err_ret;
-       u32 fbraddr;
-       u8 func;
-
-       brcmf_dbg(SDIO, "\n");
-
-       /* Get the Card's common CIS address */
-       sdiodev->func_cis_ptr[0] = brcmf_sdioh_get_cisaddr(sdiodev,
-                                                          SDIO_CCCR_CIS);
-       brcmf_dbg(SDIO, "Card's Common CIS Ptr = 0x%x\n",
-                 sdiodev->func_cis_ptr[0]);
-
-       /* Get the Card's function CIS (for each function) */
-       for (fbraddr = SDIO_FBR_BASE(1), func = 1;
-            func <= sdiodev->num_funcs; func++, fbraddr += SDIOD_FBR_SIZE) {
-               sdiodev->func_cis_ptr[func] =
-                   brcmf_sdioh_get_cisaddr(sdiodev, SDIO_FBR_CIS + fbraddr);
-               brcmf_dbg(SDIO, "Function %d CIS Ptr = 0x%x\n",
-                         func, sdiodev->func_cis_ptr[func]);
-       }
-
-       /* Enable Function 1 */
-       err_ret = sdio_enable_func(sdiodev->func[1]);
-       if (err_ret)
-               brcmf_err("Failed to enable F1 Err: 0x%08x\n", err_ret);
-
-       return false;
-}
-
-/*
- *     Public entry points & extern's
- */
-int brcmf_sdioh_attach(struct brcmf_sdio_dev *sdiodev)
-{
-       int err_ret = 0;
-       struct mmc_host *host;
-       struct sdio_func *func;
-       uint max_blocks;
-
-       brcmf_dbg(SDIO, "\n");
-
-       sdiodev->num_funcs = 2;
-
-       sdio_claim_host(sdiodev->func[1]);
-
-       err_ret = sdio_set_block_size(sdiodev->func[1], SDIO_FUNC1_BLOCKSIZE);
-       if (err_ret) {
-               brcmf_err("Failed to set F1 blocksize\n");
-               goto out;
-       }
-
-       err_ret = sdio_set_block_size(sdiodev->func[2], SDIO_FUNC2_BLOCKSIZE);
-       if (err_ret) {
-               brcmf_err("Failed to set F2 blocksize\n");
-               goto out;
-       }
-
-       brcmf_sdioh_enablefuncs(sdiodev);
-
-       /*
-        * determine host related variables after brcmf_sdio_probe()
-        * as func->cur_blksize is properly set and F2 init has been
-        * completed successfully.
-        */
-       func = sdiodev->func[2];
-       host = func->card->host;
-       sdiodev->sg_support = host->max_segs > 1;
-       max_blocks = min_t(uint, host->max_blk_count, 511u);
-       sdiodev->max_request_size = min_t(uint, host->max_req_size,
-                                         max_blocks * func->cur_blksize);
-       sdiodev->max_segment_count = min_t(uint, host->max_segs,
-                                          SG_MAX_SINGLE_ALLOC);
-       sdiodev->max_segment_size = host->max_seg_size;
-out:
-       sdio_release_host(sdiodev->func[1]);
-       brcmf_dbg(SDIO, "Done\n");
-       return err_ret;
-}
-
-void brcmf_sdioh_detach(struct brcmf_sdio_dev *sdiodev)
-{
-       brcmf_dbg(SDIO, "\n");
-
-       /* Disable Function 2 */
-       sdio_claim_host(sdiodev->func[2]);
-       sdio_disable_func(sdiodev->func[2]);
-       sdio_release_host(sdiodev->func[2]);
-
-       /* Disable Function 1 */
-       sdio_claim_host(sdiodev->func[1]);
-       sdio_disable_func(sdiodev->func[1]);
-       sdio_release_host(sdiodev->func[1]);
-
-}
-
-static int brcmf_ops_sdio_probe(struct sdio_func *func,
-                               const struct sdio_device_id *id)
-{
-       int err;
-       struct brcmf_sdio_dev *sdiodev;
-       struct brcmf_bus *bus_if;
-
-       brcmf_dbg(SDIO, "Enter\n");
-       brcmf_dbg(SDIO, "Class=%x\n", func->class);
-       brcmf_dbg(SDIO, "sdio vendor ID: 0x%04x\n", func->vendor);
-       brcmf_dbg(SDIO, "sdio device ID: 0x%04x\n", func->device);
-       brcmf_dbg(SDIO, "Function#: %d\n", func->num);
-
-       /* Consume func num 1 but dont do anything with it. */
-       if (func->num == 1)
-               return 0;
-
-       /* Ignore anything but func 2 */
-       if (func->num != 2)
-               return -ENODEV;
-
-       bus_if = kzalloc(sizeof(struct brcmf_bus), GFP_KERNEL);
-       if (!bus_if)
-               return -ENOMEM;
-       sdiodev = kzalloc(sizeof(struct brcmf_sdio_dev), GFP_KERNEL);
-       if (!sdiodev) {
-               kfree(bus_if);
-               return -ENOMEM;
-       }
-
-       sdiodev->func[0] = func->card->sdio_func[0];
-       sdiodev->func[1] = func->card->sdio_func[0];
-       sdiodev->func[2] = func;
-
-       sdiodev->bus_if = bus_if;
-       bus_if->bus_priv.sdio = sdiodev;
-       dev_set_drvdata(&func->dev, bus_if);
-       dev_set_drvdata(&sdiodev->func[1]->dev, bus_if);
-       sdiodev->dev = &sdiodev->func[1]->dev;
-       sdiodev->pdata = brcmfmac_sdio_pdata;
-
-       atomic_set(&sdiodev->suspend, false);
-       init_waitqueue_head(&sdiodev->request_byte_wait);
-       init_waitqueue_head(&sdiodev->request_word_wait);
-       init_waitqueue_head(&sdiodev->request_buffer_wait);
-
-       brcmf_dbg(SDIO, "F2 found, calling brcmf_sdio_probe...\n");
-       err = brcmf_sdio_probe(sdiodev);
-       if (err) {
-               brcmf_err("F2 error, probe failed %d...\n", err);
-               goto fail;
-       }
-
-       brcmf_dbg(SDIO, "F2 init completed...\n");
-       return 0;
-
-fail:
-       dev_set_drvdata(&func->dev, NULL);
-       dev_set_drvdata(&sdiodev->func[1]->dev, NULL);
-       kfree(sdiodev);
-       kfree(bus_if);
-       return err;
-}
-
-static void brcmf_ops_sdio_remove(struct sdio_func *func)
-{
-       struct brcmf_bus *bus_if;
-       struct brcmf_sdio_dev *sdiodev;
-
-       brcmf_dbg(SDIO, "Enter\n");
-       brcmf_dbg(SDIO, "sdio vendor ID: 0x%04x\n", func->vendor);
-       brcmf_dbg(SDIO, "sdio device ID: 0x%04x\n", func->device);
-       brcmf_dbg(SDIO, "Function: %d\n", func->num);
-
-       if (func->num != 1 && func->num != 2)
-               return;
-
-       bus_if = dev_get_drvdata(&func->dev);
-       if (bus_if) {
-               sdiodev = bus_if->bus_priv.sdio;
-               brcmf_sdio_remove(sdiodev);
-
-               dev_set_drvdata(&sdiodev->func[1]->dev, NULL);
-               dev_set_drvdata(&sdiodev->func[2]->dev, NULL);
-
-               kfree(bus_if);
-               kfree(sdiodev);
-       }
-
-       brcmf_dbg(SDIO, "Exit\n");
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int brcmf_sdio_suspend(struct device *dev)
-{
-       mmc_pm_flag_t sdio_flags;
-       struct brcmf_bus *bus_if = dev_get_drvdata(dev);
-       struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
-       int ret = 0;
-
-       brcmf_dbg(SDIO, "\n");
-
-       atomic_set(&sdiodev->suspend, true);
-
-       sdio_flags = sdio_get_host_pm_caps(sdiodev->func[1]);
-       if (!(sdio_flags & MMC_PM_KEEP_POWER)) {
-               brcmf_err("Host can't keep power while suspended\n");
-               return -EINVAL;
-       }
-
-       ret = sdio_set_host_pm_flags(sdiodev->func[1], MMC_PM_KEEP_POWER);
-       if (ret) {
-               brcmf_err("Failed to set pm_flags\n");
-               return ret;
-       }
-
-       brcmf_sdio_wdtmr_enable(sdiodev, false);
-
-       return ret;
-}
-
-static int brcmf_sdio_resume(struct device *dev)
-{
-       struct brcmf_bus *bus_if = dev_get_drvdata(dev);
-       struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
-
-       brcmf_sdio_wdtmr_enable(sdiodev, true);
-       atomic_set(&sdiodev->suspend, false);
-       return 0;
-}
-
-static const struct dev_pm_ops brcmf_sdio_pm_ops = {
-       .suspend        = brcmf_sdio_suspend,
-       .resume         = brcmf_sdio_resume,
-};
-#endif /* CONFIG_PM_SLEEP */
-
-static struct sdio_driver brcmf_sdmmc_driver = {
-       .probe = brcmf_ops_sdio_probe,
-       .remove = brcmf_ops_sdio_remove,
-       .name = BRCMFMAC_SDIO_PDATA_NAME,
-       .id_table = brcmf_sdmmc_ids,
-#ifdef CONFIG_PM_SLEEP
-       .drv = {
-               .pm = &brcmf_sdio_pm_ops,
-       },
-#endif /* CONFIG_PM_SLEEP */
-};
-
-static int brcmf_sdio_pd_probe(struct platform_device *pdev)
-{
-       brcmf_dbg(SDIO, "Enter\n");
-
-       brcmfmac_sdio_pdata = dev_get_platdata(&pdev->dev);
-
-       if (brcmfmac_sdio_pdata->power_on)
-               brcmfmac_sdio_pdata->power_on();
-
-       return 0;
-}
-
-static int brcmf_sdio_pd_remove(struct platform_device *pdev)
-{
-       brcmf_dbg(SDIO, "Enter\n");
-
-       if (brcmfmac_sdio_pdata->power_off)
-               brcmfmac_sdio_pdata->power_off();
-
-       sdio_unregister_driver(&brcmf_sdmmc_driver);
-
-       return 0;
-}
-
-static struct platform_driver brcmf_sdio_pd = {
-       .remove         = brcmf_sdio_pd_remove,
-       .driver         = {
-               .name   = BRCMFMAC_SDIO_PDATA_NAME,
-               .owner  = THIS_MODULE,
-       }
-};
-
-void brcmf_sdio_register(void)
-{
-       int ret;
-
-       ret = sdio_register_driver(&brcmf_sdmmc_driver);
-       if (ret)
-               brcmf_err("sdio_register_driver failed: %d\n", ret);
-}
-
-void brcmf_sdio_exit(void)
-{
-       brcmf_dbg(SDIO, "Enter\n");
-
-       if (brcmfmac_sdio_pdata)
-               platform_driver_unregister(&brcmf_sdio_pd);
-       else
-               sdio_unregister_driver(&brcmf_sdmmc_driver);
-}
-
-void __init brcmf_sdio_init(void)
-{
-       int ret;
-
-       brcmf_dbg(SDIO, "Enter\n");
-
-       ret = platform_driver_probe(&brcmf_sdio_pd, brcmf_sdio_pd_probe);
-       if (ret == -ENODEV)
-               brcmf_dbg(SDIO, "No platform data available.\n");
-}
index 6a54905528befd0238ce198acdbd6f9d642d1340..5c12a07673fa55701007be40c5d445abb5c4b5d6 100644 (file)
@@ -24,6 +24,12 @@ enum brcmf_bus_state {
        BRCMF_BUS_DATA          /* Ready for frame transfers */
 };
 
+/* The level of bus communication with the dongle */
+enum brcmf_bus_protocol_type {
+       BRCMF_PROTO_BCDC,
+       BRCMF_PROTO_MSGBUF
+};
+
 struct brcmf_bus_dcmd {
        char *name;
        char *param;
@@ -65,6 +71,7 @@ struct brcmf_bus_ops {
  * struct brcmf_bus - interface structure between common and bus layer
  *
  * @bus_priv: pointer to private bus device.
+ * @proto_type: protocol type, bcdc or msgbuf
  * @dev: device pointer of bus device.
  * @drvr: public driver information.
  * @state: operational state of the bus interface.
@@ -80,6 +87,7 @@ struct brcmf_bus {
                struct brcmf_sdio_dev *sdio;
                struct brcmf_usbdev *usb;
        } bus_priv;
+       enum brcmf_bus_protocol_type proto_type;
        struct device *dev;
        struct brcmf_pub *drvr;
        enum brcmf_bus_state state;
index 0f95f3e79c10f6e04f8a5735a102e3059739e4f8..f214510e3beec2d37ca8684b4d278474abcf4795 100644 (file)
@@ -260,9 +260,6 @@ struct rte_console {
 #define MAX_HDR_READ   (1 << 6)
 #define MAX_RX_DATASZ  2048
 
-/* Maximum milliseconds to wait for F2 to come up */
-#define BRCMF_WAIT_F2RDY       3000
-
 /* Bump up limit on waiting for HT to account for first startup;
  * if the image is doing a CRC calculation before programming the PMU
  * for HT availability, it could take a couple hundred ms more, so
@@ -559,7 +556,7 @@ static const struct brcmf_firmware_names brcmf_fwname_data[] = {
 };
 
 
-static const struct firmware *brcmf_sdbrcm_get_fw(struct brcmf_sdio *bus,
+static const struct firmware *brcmf_sdio_get_fw(struct brcmf_sdio *bus,
                                                  enum brcmf_firmware_type type)
 {
        const struct firmware *fw;
@@ -624,8 +621,8 @@ r_sdreg32(struct brcmf_sdio *bus, u32 *regvar, u32 offset)
        u8 idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV);
        int ret;
 
-       *regvar = brcmf_sdio_regrl(bus->sdiodev,
-                                  bus->ci->c_inf[idx].base + offset, &ret);
+       *regvar = brcmf_sdiod_regrl(bus->sdiodev,
+                                   bus->ci->c_inf[idx].base + offset, &ret);
 
        return ret;
 }
@@ -636,15 +633,15 @@ w_sdreg32(struct brcmf_sdio *bus, u32 regval, u32 reg_offset)
        u8 idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV);
        int ret;
 
-       brcmf_sdio_regwl(bus->sdiodev,
-                        bus->ci->c_inf[idx].base + reg_offset,
-                        regval, &ret);
+       brcmf_sdiod_regwl(bus->sdiodev,
+                         bus->ci->c_inf[idx].base + reg_offset,
+                         regval, &ret);
 
        return ret;
 }
 
 static int
-brcmf_sdbrcm_kso_control(struct brcmf_sdio *bus, bool on)
+brcmf_sdio_kso_control(struct brcmf_sdio *bus, bool on)
 {
        u8 wr_val = 0, rd_val, cmp_val, bmask;
        int err = 0;
@@ -654,8 +651,8 @@ brcmf_sdbrcm_kso_control(struct brcmf_sdio *bus, bool on)
 
        wr_val = (on << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT);
        /* 1st KSO write goes to AOS wake up core if device is asleep  */
-       brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR,
-                        wr_val, &err);
+       brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR,
+                         wr_val, &err);
        if (err) {
                brcmf_err("SDIO_AOS KSO write error: %d\n", err);
                return err;
@@ -685,15 +682,15 @@ brcmf_sdbrcm_kso_control(struct brcmf_sdio *bus, bool on)
                 * just one write attempt may fail,
                 * read it back until it matches written value
                 */
-               rd_val = brcmf_sdio_regrb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR,
-                                         &err);
+               rd_val = brcmf_sdiod_regrb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR,
+                                          &err);
                if (((rd_val & bmask) == cmp_val) && !err)
                        break;
                brcmf_dbg(SDIO, "KSO wr/rd retry:%d (max: %d) ERR:%x\n",
                          try_cnt, MAX_KSO_ATTEMPTS, err);
                udelay(KSO_WAIT_US);
-               brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR,
-                                wr_val, &err);
+               brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR,
+                                 wr_val, &err);
        } while (try_cnt++ < MAX_KSO_ATTEMPTS);
 
        return err;
@@ -704,7 +701,7 @@ brcmf_sdbrcm_kso_control(struct brcmf_sdio *bus, bool on)
 #define HOSTINTMASK            (I_HMB_SW_MASK | I_CHIPACTIVE)
 
 /* Turn backplane clock on or off */
-static int brcmf_sdbrcm_htclk(struct brcmf_sdio *bus, bool on, bool pendok)
+static int brcmf_sdio_htclk(struct brcmf_sdio *bus, bool on, bool pendok)
 {
        int err;
        u8 clkctl, clkreq, devctl;
@@ -724,16 +721,16 @@ static int brcmf_sdbrcm_htclk(struct brcmf_sdio *bus, bool on, bool pendok)
                clkreq =
                    bus->alp_only ? SBSDIO_ALP_AVAIL_REQ : SBSDIO_HT_AVAIL_REQ;
 
-               brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
-                                clkreq, &err);
+               brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
+                                 clkreq, &err);
                if (err) {
                        brcmf_err("HT Avail request error: %d\n", err);
                        return -EBADE;
                }
 
                /* Check current status */
-               clkctl = brcmf_sdio_regrb(bus->sdiodev,
-                                         SBSDIO_FUNC1_CHIPCLKCSR, &err);
+               clkctl = brcmf_sdiod_regrb(bus->sdiodev,
+                                          SBSDIO_FUNC1_CHIPCLKCSR, &err);
                if (err) {
                        brcmf_err("HT Avail read error: %d\n", err);
                        return -EBADE;
@@ -742,8 +739,8 @@ static int brcmf_sdbrcm_htclk(struct brcmf_sdio *bus, bool on, bool pendok)
                /* Go to pending and await interrupt if appropriate */
                if (!SBSDIO_CLKAV(clkctl, bus->alp_only) && pendok) {
                        /* Allow only clock-available interrupt */
-                       devctl = brcmf_sdio_regrb(bus->sdiodev,
-                                                 SBSDIO_DEVICE_CTL, &err);
+                       devctl = brcmf_sdiod_regrb(bus->sdiodev,
+                                                  SBSDIO_DEVICE_CTL, &err);
                        if (err) {
                                brcmf_err("Devctl error setting CA: %d\n",
                                          err);
@@ -751,28 +748,28 @@ static int brcmf_sdbrcm_htclk(struct brcmf_sdio *bus, bool on, bool pendok)
                        }
 
                        devctl |= SBSDIO_DEVCTL_CA_INT_ONLY;
-                       brcmf_sdio_regwb(bus->sdiodev, SBSDIO_DEVICE_CTL,
-                                        devctl, &err);
+                       brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_DEVICE_CTL,
+                                         devctl, &err);
                        brcmf_dbg(SDIO, "CLKCTL: set PENDING\n");
                        bus->clkstate = CLK_PENDING;
 
                        return 0;
                } else if (bus->clkstate == CLK_PENDING) {
                        /* Cancel CA-only interrupt filter */
-                       devctl = brcmf_sdio_regrb(bus->sdiodev,
-                                                 SBSDIO_DEVICE_CTL, &err);
+                       devctl = brcmf_sdiod_regrb(bus->sdiodev,
+                                                  SBSDIO_DEVICE_CTL, &err);
                        devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
-                       brcmf_sdio_regwb(bus->sdiodev, SBSDIO_DEVICE_CTL,
-                                        devctl, &err);
+                       brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_DEVICE_CTL,
+                                         devctl, &err);
                }
 
                /* Otherwise, wait here (polling) for HT Avail */
                timeout = jiffies +
                          msecs_to_jiffies(PMU_MAX_TRANSITION_DLY/1000);
                while (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
-                       clkctl = brcmf_sdio_regrb(bus->sdiodev,
-                                                 SBSDIO_FUNC1_CHIPCLKCSR,
-                                                 &err);
+                       clkctl = brcmf_sdiod_regrb(bus->sdiodev,
+                                                  SBSDIO_FUNC1_CHIPCLKCSR,
+                                                  &err);
                        if (time_after(jiffies, timeout))
                                break;
                        else
@@ -805,16 +802,16 @@ static int brcmf_sdbrcm_htclk(struct brcmf_sdio *bus, bool on, bool pendok)
 
                if (bus->clkstate == CLK_PENDING) {
                        /* Cancel CA-only interrupt filter */
-                       devctl = brcmf_sdio_regrb(bus->sdiodev,
-                                                 SBSDIO_DEVICE_CTL, &err);
+                       devctl = brcmf_sdiod_regrb(bus->sdiodev,
+                                                  SBSDIO_DEVICE_CTL, &err);
                        devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
-                       brcmf_sdio_regwb(bus->sdiodev, SBSDIO_DEVICE_CTL,
-                                        devctl, &err);
+                       brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_DEVICE_CTL,
+                                         devctl, &err);
                }
 
                bus->clkstate = CLK_SDONLY;
-               brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
-                                clkreq, &err);
+               brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
+                                 clkreq, &err);
                brcmf_dbg(SDIO, "CLKCTL: turned OFF\n");
                if (err) {
                        brcmf_err("Failed access turning clock off: %d\n",
@@ -826,7 +823,7 @@ static int brcmf_sdbrcm_htclk(struct brcmf_sdio *bus, bool on, bool pendok)
 }
 
 /* Change idle/active SD state */
-static int brcmf_sdbrcm_sdclk(struct brcmf_sdio *bus, bool on)
+static int brcmf_sdio_sdclk(struct brcmf_sdio *bus, bool on)
 {
        brcmf_dbg(SDIO, "Enter\n");
 
@@ -839,7 +836,7 @@ static int brcmf_sdbrcm_sdclk(struct brcmf_sdio *bus, bool on)
 }
 
 /* Transition SD and backplane clock readiness */
-static int brcmf_sdbrcm_clkctl(struct brcmf_sdio *bus, uint target, bool pendok)
+static int brcmf_sdio_clkctl(struct brcmf_sdio *bus, uint target, bool pendok)
 {
 #ifdef DEBUG
        uint oldstate = bus->clkstate;
@@ -850,7 +847,7 @@ static int brcmf_sdbrcm_clkctl(struct brcmf_sdio *bus, uint target, bool pendok)
        /* Early exit if we're already there */
        if (bus->clkstate == target) {
                if (target == CLK_AVAIL) {
-                       brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS);
+                       brcmf_sdio_wd_timer(bus, BRCMF_WD_POLL_MS);
                        bus->activity = true;
                }
                return 0;
@@ -860,32 +857,32 @@ static int brcmf_sdbrcm_clkctl(struct brcmf_sdio *bus, uint target, bool pendok)
        case CLK_AVAIL:
                /* Make sure SD clock is available */
                if (bus->clkstate == CLK_NONE)
-                       brcmf_sdbrcm_sdclk(bus, true);
+                       brcmf_sdio_sdclk(bus, true);
                /* Now request HT Avail on the backplane */
-               brcmf_sdbrcm_htclk(bus, true, pendok);
-               brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS);
+               brcmf_sdio_htclk(bus, true, pendok);
+               brcmf_sdio_wd_timer(bus, BRCMF_WD_POLL_MS);
                bus->activity = true;
                break;
 
        case CLK_SDONLY:
                /* Remove HT request, or bring up SD clock */
                if (bus->clkstate == CLK_NONE)
-                       brcmf_sdbrcm_sdclk(bus, true);
+                       brcmf_sdio_sdclk(bus, true);
                else if (bus->clkstate == CLK_AVAIL)
-                       brcmf_sdbrcm_htclk(bus, false, false);
+                       brcmf_sdio_htclk(bus, false, false);
                else
                        brcmf_err("request for %d -> %d\n",
                                  bus->clkstate, target);
-               brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS);
+               brcmf_sdio_wd_timer(bus, BRCMF_WD_POLL_MS);
                break;
 
        case CLK_NONE:
                /* Make sure to remove HT request */
                if (bus->clkstate == CLK_AVAIL)
-                       brcmf_sdbrcm_htclk(bus, false, false);
+                       brcmf_sdio_htclk(bus, false, false);
                /* Now remove the SD clock */
-               brcmf_sdbrcm_sdclk(bus, false);
-               brcmf_sdbrcm_wd_timer(bus, 0);
+               brcmf_sdio_sdclk(bus, false);
+               brcmf_sdio_wd_timer(bus, 0);
                break;
        }
 #ifdef DEBUG
@@ -896,7 +893,7 @@ static int brcmf_sdbrcm_clkctl(struct brcmf_sdio *bus, uint target, bool pendok)
 }
 
 static int
-brcmf_sdbrcm_bus_sleep(struct brcmf_sdio *bus, bool sleep, bool pendok)
+brcmf_sdio_bus_sleep(struct brcmf_sdio *bus, bool sleep, bool pendok)
 {
        int err = 0;
        brcmf_dbg(TRACE, "Enter\n");
@@ -919,13 +916,13 @@ brcmf_sdbrcm_bus_sleep(struct brcmf_sdio *bus, bool sleep, bool pendok)
                            brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) &&
                            data_ok(bus)))
                                 return -EBUSY;
-                       err = brcmf_sdbrcm_kso_control(bus, false);
+                       err = brcmf_sdio_kso_control(bus, false);
                        /* disable watchdog */
                        if (!err)
-                               brcmf_sdbrcm_wd_timer(bus, 0);
+                               brcmf_sdio_wd_timer(bus, 0);
                } else {
                        bus->idlecount = 0;
-                       err = brcmf_sdbrcm_kso_control(bus, true);
+                       err = brcmf_sdio_kso_control(bus, true);
                }
                if (!err) {
                        /* Change state */
@@ -943,16 +940,16 @@ end:
        /* control clocks */
        if (sleep) {
                if (!bus->sr_enabled)
-                       brcmf_sdbrcm_clkctl(bus, CLK_NONE, pendok);
+                       brcmf_sdio_clkctl(bus, CLK_NONE, pendok);
        } else {
-               brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, pendok);
+               brcmf_sdio_clkctl(bus, CLK_AVAIL, pendok);
        }
 
        return err;
 
 }
 
-static u32 brcmf_sdbrcm_hostmail(struct brcmf_sdio *bus)
+static u32 brcmf_sdio_hostmail(struct brcmf_sdio *bus)
 {
        u32 intstatus = 0;
        u32 hmb_data;
@@ -1028,7 +1025,7 @@ static u32 brcmf_sdbrcm_hostmail(struct brcmf_sdio *bus)
        return intstatus;
 }
 
-static void brcmf_sdbrcm_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx)
+static void brcmf_sdio_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx)
 {
        uint retries = 0;
        u16 lastrbc;
@@ -1040,18 +1037,18 @@ static void brcmf_sdbrcm_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx)
                  rtx ? ", send NAK" : "");
 
        if (abort)
-               brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2);
+               brcmf_sdiod_abort(bus->sdiodev, SDIO_FUNC_2);
 
-       brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL,
-                        SFC_RF_TERM, &err);
+       brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL,
+                         SFC_RF_TERM, &err);
        bus->sdcnt.f1regdata++;
 
        /* Wait until the packet has been flushed (device/FIFO stable) */
        for (lastrbc = retries = 0xffff; retries > 0; retries--) {
-               hi = brcmf_sdio_regrb(bus->sdiodev,
-                                     SBSDIO_FUNC1_RFRAMEBCHI, &err);
-               lo = brcmf_sdio_regrb(bus->sdiodev,
-                                     SBSDIO_FUNC1_RFRAMEBCLO, &err);
+               hi = brcmf_sdiod_regrb(bus->sdiodev,
+                                      SBSDIO_FUNC1_RFRAMEBCHI, &err);
+               lo = brcmf_sdiod_regrb(bus->sdiodev,
+                                      SBSDIO_FUNC1_RFRAMEBCLO, &err);
                bus->sdcnt.f1regdata += 2;
 
                if ((hi == 0) && (lo == 0))
@@ -1088,7 +1085,7 @@ static void brcmf_sdbrcm_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx)
 }
 
 /* return total length of buffer chain */
-static uint brcmf_sdbrcm_glom_len(struct brcmf_sdio *bus)
+static uint brcmf_sdio_glom_len(struct brcmf_sdio *bus)
 {
        struct sk_buff *p;
        uint total;
@@ -1099,7 +1096,7 @@ static uint brcmf_sdbrcm_glom_len(struct brcmf_sdio *bus)
        return total;
 }
 
-static void brcmf_sdbrcm_free_glom(struct brcmf_sdio *bus)
+static void brcmf_sdio_free_glom(struct brcmf_sdio *bus)
 {
        struct sk_buff *cur, *next;
 
@@ -1187,7 +1184,7 @@ static int brcmf_sdio_hdparse(struct brcmf_sdio *bus, u8 *header,
        if ((u16)(~(len ^ checksum))) {
                brcmf_err("HW header checksum error\n");
                bus->sdcnt.rx_badhdr++;
-               brcmf_sdbrcm_rxfail(bus, false, false);
+               brcmf_sdio_rxfail(bus, false, false);
                return -EIO;
        }
        if (len < SDPCM_HDRLEN) {
@@ -1219,7 +1216,7 @@ static int brcmf_sdio_hdparse(struct brcmf_sdio *bus, u8 *header,
            type != BRCMF_SDIO_FT_SUPER) {
                brcmf_err("HW header length too long\n");
                bus->sdcnt.rx_toolong++;
-               brcmf_sdbrcm_rxfail(bus, false, false);
+               brcmf_sdio_rxfail(bus, false, false);
                rd->len = 0;
                return -EPROTO;
        }
@@ -1238,7 +1235,7 @@ static int brcmf_sdio_hdparse(struct brcmf_sdio *bus, u8 *header,
        if (rd->dat_offset < SDPCM_HDRLEN || rd->dat_offset > rd->len) {
                brcmf_err("seq %d: bad data offset\n", rx_seq);
                bus->sdcnt.rx_badhdr++;
-               brcmf_sdbrcm_rxfail(bus, false, false);
+               brcmf_sdio_rxfail(bus, false, false);
                rd->len = 0;
                return -ENXIO;
        }
@@ -1311,7 +1308,7 @@ static void brcmf_sdio_hdpack(struct brcmf_sdio *bus, u8 *header,
        trace_brcmf_sdpcm_hdr(SDPCM_TX + !!(bus->txglom), header);
 }
 
-static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
+static u8 brcmf_sdio_rxglom(struct brcmf_sdio *bus, u8 rxseq)
 {
        u16 dlen, totlen;
        u8 *dptr, num = 0;
@@ -1391,7 +1388,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
                        }
                        pfirst = pnext = NULL;
                } else {
-                       brcmf_sdbrcm_free_glom(bus);
+                       brcmf_sdio_free_glom(bus);
                        num = 0;
                }
 
@@ -1414,16 +1411,15 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
                }
 
                pfirst = skb_peek(&bus->glom);
-               dlen = (u16) brcmf_sdbrcm_glom_len(bus);
+               dlen = (u16) brcmf_sdio_glom_len(bus);
 
                /* Do an SDIO read for the superframe.  Configurable iovar to
                 * read directly into the chained packet, or allocate a large
                 * packet and and copy into the chain.
                 */
                sdio_claim_host(bus->sdiodev->func[1]);
-               errcode = brcmf_sdcard_recv_chain(bus->sdiodev,
-                               bus->sdiodev->sbwad,
-                               SDIO_FUNC_2, F2SYNC, &bus->glom, dlen);
+               errcode = brcmf_sdiod_recv_chain(bus->sdiodev,
+                                                &bus->glom, dlen);
                sdio_release_host(bus->sdiodev->func[1]);
                bus->sdcnt.f2rxdata++;
 
@@ -1434,12 +1430,12 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
 
                        sdio_claim_host(bus->sdiodev->func[1]);
                        if (bus->glomerr++ < 3) {
-                               brcmf_sdbrcm_rxfail(bus, true, true);
+                               brcmf_sdio_rxfail(bus, true, true);
                        } else {
                                bus->glomerr = 0;
-                               brcmf_sdbrcm_rxfail(bus, true, false);
+                               brcmf_sdio_rxfail(bus, true, false);
                                bus->sdcnt.rxglomfail++;
-                               brcmf_sdbrcm_free_glom(bus);
+                               brcmf_sdio_free_glom(bus);
                        }
                        sdio_release_host(bus->sdiodev->func[1]);
                        return 0;
@@ -1487,12 +1483,12 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
                        if (bus->glomerr++ < 3) {
                                /* Restore superframe header space */
                                skb_push(pfirst, sfdoff);
-                               brcmf_sdbrcm_rxfail(bus, true, true);
+                               brcmf_sdio_rxfail(bus, true, true);
                        } else {
                                bus->glomerr = 0;
-                               brcmf_sdbrcm_rxfail(bus, true, false);
+                               brcmf_sdio_rxfail(bus, true, false);
                                bus->sdcnt.rxglomfail++;
-                               brcmf_sdbrcm_free_glom(bus);
+                               brcmf_sdio_free_glom(bus);
                        }
                        sdio_release_host(bus->sdiodev->func[1]);
                        bus->cur_read.len = 0;
@@ -1536,8 +1532,8 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
        return num;
 }
 
-static int brcmf_sdbrcm_dcmd_resp_wait(struct brcmf_sdio *bus, uint *condition,
-                                       bool *pending)
+static int brcmf_sdio_dcmd_resp_wait(struct brcmf_sdio *bus, uint *condition,
+                                    bool *pending)
 {
        DECLARE_WAITQUEUE(wait, current);
        int timeout = msecs_to_jiffies(DCMD_RESP_TIMEOUT);
@@ -1558,7 +1554,7 @@ static int brcmf_sdbrcm_dcmd_resp_wait(struct brcmf_sdio *bus, uint *condition,
        return timeout;
 }
 
-static int brcmf_sdbrcm_dcmd_resp_wake(struct brcmf_sdio *bus)
+static int brcmf_sdio_dcmd_resp_wake(struct brcmf_sdio *bus)
 {
        if (waitqueue_active(&bus->dcmd_resp_wait))
                wake_up_interruptible(&bus->dcmd_resp_wait);
@@ -1566,7 +1562,7 @@ static int brcmf_sdbrcm_dcmd_resp_wake(struct brcmf_sdio *bus)
        return 0;
 }
 static void
-brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff)
+brcmf_sdio_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff)
 {
        uint rdlen, pad;
        u8 *buf = NULL, *rbuf;
@@ -1604,7 +1600,7 @@ brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff)
        if ((rdlen + BRCMF_FIRSTREAD) > bus->sdiodev->bus_if->maxctl) {
                brcmf_err("%d-byte control read exceeds %d-byte buffer\n",
                          rdlen, bus->sdiodev->bus_if->maxctl);
-               brcmf_sdbrcm_rxfail(bus, false, false);
+               brcmf_sdio_rxfail(bus, false, false);
                goto done;
        }
 
@@ -1612,15 +1608,12 @@ brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff)
                brcmf_err("%d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n",
                          len, len - doff, bus->sdiodev->bus_if->maxctl);
                bus->sdcnt.rx_toolong++;
-               brcmf_sdbrcm_rxfail(bus, false, false);
+               brcmf_sdio_rxfail(bus, false, false);
                goto done;
        }
 
        /* Read remain of frame body */
-       sdret = brcmf_sdcard_recv_buf(bus->sdiodev,
-                               bus->sdiodev->sbwad,
-                               SDIO_FUNC_2,
-                               F2SYNC, rbuf, rdlen);
+       sdret = brcmf_sdiod_recv_buf(bus->sdiodev, rbuf, rdlen);
        bus->sdcnt.f2rxdata++;
 
        /* Control frame failures need retransmission */
@@ -1628,7 +1621,7 @@ brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff)
                brcmf_err("read %d control bytes failed: %d\n",
                          rdlen, sdret);
                bus->sdcnt.rxc_errors++;
-               brcmf_sdbrcm_rxfail(bus, true, true);
+               brcmf_sdio_rxfail(bus, true, true);
                goto done;
        } else
                memcpy(buf + BRCMF_FIRSTREAD, rbuf, rdlen);
@@ -1653,11 +1646,11 @@ gotpkt:
 
 done:
        /* Awake any waiters */
-       brcmf_sdbrcm_dcmd_resp_wake(bus);
+       brcmf_sdio_dcmd_resp_wake(bus);
 }
 
 /* Pad read to blocksize for efficiency */
-static void brcmf_pad(struct brcmf_sdio *bus, u16 *pad, u16 *rdlen)
+static void brcmf_sdio_pad(struct brcmf_sdio *bus, u16 *pad, u16 *rdlen)
 {
        if (bus->roundup && bus->blocksize && *rdlen > bus->blocksize) {
                *pad = bus->blocksize - (*rdlen % bus->blocksize);
@@ -1694,7 +1687,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
                        u8 cnt;
                        brcmf_dbg(GLOM, "calling rxglom: glomd %p, glom %p\n",
                                  bus->glomd, skb_peek(&bus->glom));
-                       cnt = brcmf_sdbrcm_rxglom(bus, rd->seq_num);
+                       cnt = brcmf_sdio_rxglom(bus, rd->seq_num);
                        brcmf_dbg(GLOM, "rxglom returned %d\n", cnt);
                        rd->seq_num += cnt - 1;
                        rxleft = (rxleft > cnt) ? (rxleft - cnt) : 1;
@@ -1705,17 +1698,14 @@ 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) {
-                       ret = brcmf_sdcard_recv_buf(bus->sdiodev,
-                                                     bus->sdiodev->sbwad,
-                                                     SDIO_FUNC_2, F2SYNC,
-                                                     bus->rxhdr,
-                                                     BRCMF_FIRSTREAD);
+                       ret = brcmf_sdiod_recv_buf(bus->sdiodev,
+                                                  bus->rxhdr, BRCMF_FIRSTREAD);
                        bus->sdcnt.f2rxhdrs++;
                        if (ret < 0) {
                                brcmf_err("RXHEADER FAILED: %d\n",
                                          ret);
                                bus->sdcnt.rx_hdrfail++;
-                               brcmf_sdbrcm_rxfail(bus, true, true);
+                               brcmf_sdio_rxfail(bus, true, true);
                                sdio_release_host(bus->sdiodev->func[1]);
                                continue;
                        }
@@ -1734,9 +1724,9 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
                        }
 
                        if (rd->channel == SDPCM_CONTROL_CHANNEL) {
-                               brcmf_sdbrcm_read_control(bus, bus->rxhdr,
-                                                         rd->len,
-                                                         rd->dat_offset);
+                               brcmf_sdio_read_control(bus, bus->rxhdr,
+                                                       rd->len,
+                                                       rd->dat_offset);
                                /* prepare the descriptor for the next read */
                                rd->len = rd->len_nxtfrm << 4;
                                rd->len_nxtfrm = 0;
@@ -1750,14 +1740,14 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
                        head_read = BRCMF_FIRSTREAD;
                }
 
-               brcmf_pad(bus, &pad, &rd->len_left);
+               brcmf_sdio_pad(bus, &pad, &rd->len_left);
 
                pkt = brcmu_pkt_buf_get_skb(rd->len_left + head_read +
                                            bus->head_align);
                if (!pkt) {
                        /* Give up on data, request rtx of events */
                        brcmf_err("brcmu_pkt_buf_get_skb failed\n");
-                       brcmf_sdbrcm_rxfail(bus, false,
+                       brcmf_sdio_rxfail(bus, false,
                                            RETRYCHAN(rd->channel));
                        sdio_release_host(bus->sdiodev->func[1]);
                        continue;
@@ -1765,8 +1755,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
                skb_pull(pkt, head_read);
                pkt_align(pkt, rd->len_left, bus->head_align);
 
-               ret = brcmf_sdcard_recv_pkt(bus->sdiodev, bus->sdiodev->sbwad,
-                                             SDIO_FUNC_2, F2SYNC, pkt);
+               ret = brcmf_sdiod_recv_pkt(bus->sdiodev, pkt);
                bus->sdcnt.f2rxdata++;
                sdio_release_host(bus->sdiodev->func[1]);
 
@@ -1775,7 +1764,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
                                  rd->len, rd->channel, ret);
                        brcmu_pkt_buf_free_skb(pkt);
                        sdio_claim_host(bus->sdiodev->func[1]);
-                       brcmf_sdbrcm_rxfail(bus, true,
+                       brcmf_sdio_rxfail(bus, true,
                                            RETRYCHAN(rd->channel));
                        sdio_release_host(bus->sdiodev->func[1]);
                        continue;
@@ -1800,7 +1789,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
                                          rd->len,
                                          roundup(rd_new.len, 16) >> 4);
                                rd->len = 0;
-                               brcmf_sdbrcm_rxfail(bus, true, true);
+                               brcmf_sdio_rxfail(bus, true, true);
                                sdio_release_host(bus->sdiodev->func[1]);
                                brcmu_pkt_buf_free_skb(pkt);
                                continue;
@@ -1822,7 +1811,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
                                /* Force retry w/normal header read */
                                rd->len = 0;
                                sdio_claim_host(bus->sdiodev->func[1]);
-                               brcmf_sdbrcm_rxfail(bus, false, true);
+                               brcmf_sdio_rxfail(bus, false, true);
                                sdio_release_host(bus->sdiodev->func[1]);
                                brcmu_pkt_buf_free_skb(pkt);
                                continue;
@@ -1847,7 +1836,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
                                brcmf_err("%s: glom superframe w/o "
                                          "descriptor!\n", __func__);
                                sdio_claim_host(bus->sdiodev->func[1]);
-                               brcmf_sdbrcm_rxfail(bus, false, false);
+                               brcmf_sdio_rxfail(bus, false, false);
                                sdio_release_host(bus->sdiodev->func[1]);
                        }
                        /* prepare the descriptor for the next read */
@@ -1891,7 +1880,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
 }
 
 static void
-brcmf_sdbrcm_wait_event_wakeup(struct brcmf_sdio *bus)
+brcmf_sdio_wait_event_wakeup(struct brcmf_sdio *bus)
 {
        if (waitqueue_active(&bus->ctrl_wait))
                wake_up_interruptible(&bus->ctrl_wait);
@@ -2107,8 +2096,8 @@ brcmf_sdio_txpkt_postp(struct brcmf_sdio *bus, struct sk_buff_head *pktq)
 
 /* 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_head *pktq,
-                             uint chan)
+static int brcmf_sdio_txpkt(struct brcmf_sdio *bus, struct sk_buff_head *pktq,
+                           uint chan)
 {
        int ret;
        int i;
@@ -2121,8 +2110,7 @@ static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff_head *pktq,
                goto done;
 
        sdio_claim_host(bus->sdiodev->func[1]);
-       ret = brcmf_sdcard_send_pkt(bus->sdiodev, bus->sdiodev->sbwad,
-                                   SDIO_FUNC_2, F2SYNC, pktq);
+       ret = brcmf_sdiod_send_pkt(bus->sdiodev, pktq);
        bus->sdcnt.f2txdata++;
 
        if (ret < 0) {
@@ -2131,17 +2119,17 @@ static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff_head *pktq,
                          ret);
                bus->sdcnt.tx_sderrs++;
 
-               brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2);
-               brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL,
-                                SFC_WF_TERM, NULL);
+               brcmf_sdiod_abort(bus->sdiodev, SDIO_FUNC_2);
+               brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL,
+                                 SFC_WF_TERM, NULL);
                bus->sdcnt.f1regdata++;
 
                for (i = 0; i < 3; i++) {
                        u8 hi, lo;
-                       hi = brcmf_sdio_regrb(bus->sdiodev,
-                                             SBSDIO_FUNC1_WFRAMEBCHI, NULL);
-                       lo = brcmf_sdio_regrb(bus->sdiodev,
-                                             SBSDIO_FUNC1_WFRAMEBCLO, NULL);
+                       hi = brcmf_sdiod_regrb(bus->sdiodev,
+                                              SBSDIO_FUNC1_WFRAMEBCHI, NULL);
+                       lo = brcmf_sdiod_regrb(bus->sdiodev,
+                                              SBSDIO_FUNC1_WFRAMEBCLO, NULL);
                        bus->sdcnt.f1regdata += 2;
                        if ((hi == 0) && (lo == 0))
                                break;
@@ -2160,7 +2148,7 @@ done:
        return ret;
 }
 
-static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes)
+static uint brcmf_sdio_sendfromq(struct brcmf_sdio *bus, uint maxframes)
 {
        struct sk_buff *pkt;
        struct sk_buff_head pktq;
@@ -2194,7 +2182,7 @@ static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes)
                if (i == 0)
                        break;
 
-               ret = brcmf_sdbrcm_txpkt(bus, &pktq, SDPCM_DATA_CHANNEL);
+               ret = brcmf_sdio_txpkt(bus, &pktq, SDPCM_DATA_CHANNEL);
                cnt += i;
 
                /* In poll mode, need to check for other events */
@@ -2223,7 +2211,7 @@ static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes)
        return cnt;
 }
 
-static void brcmf_sdbrcm_bus_stop(struct device *dev)
+static void brcmf_sdio_bus_stop(struct device *dev)
 {
        u32 local_hostintmask;
        u8 saveclk;
@@ -2243,7 +2231,7 @@ static void brcmf_sdbrcm_bus_stop(struct device *dev)
        sdio_claim_host(bus->sdiodev->func[1]);
 
        /* Enable clock for device interrupts */
-       brcmf_sdbrcm_bus_sleep(bus, false, false);
+       brcmf_sdio_bus_sleep(bus, false, false);
 
        /* Disable and clear interrupts at the chip level also */
        w_sdreg32(bus, 0, offsetof(struct sdpcmd_regs, hostintmask));
@@ -2254,26 +2242,25 @@ static void brcmf_sdbrcm_bus_stop(struct device *dev)
        bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
 
        /* Force clocks on backplane to be sure F2 interrupt propagates */
-       saveclk = brcmf_sdio_regrb(bus->sdiodev,
-                                  SBSDIO_FUNC1_CHIPCLKCSR, &err);
+       saveclk = brcmf_sdiod_regrb(bus->sdiodev,
+                                   SBSDIO_FUNC1_CHIPCLKCSR, &err);
        if (!err) {
-               brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
-                                (saveclk | SBSDIO_FORCE_HT), &err);
+               brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
+                                 (saveclk | SBSDIO_FORCE_HT), &err);
        }
        if (err)
                brcmf_err("Failed to force clock for F2: err %d\n", err);
 
        /* Turn off the bus (F2), free any pending packets */
        brcmf_dbg(INTR, "disable SDIO interrupts\n");
-       brcmf_sdio_regwb(bus->sdiodev, SDIO_CCCR_IOEx, SDIO_FUNC_ENABLE_1,
-                        NULL);
+       sdio_disable_func(bus->sdiodev->func[SDIO_FUNC_2]);
 
        /* Clear any pending interrupts now that F2 is disabled */
        w_sdreg32(bus, local_hostintmask,
                  offsetof(struct sdpcmd_regs, intstatus));
 
        /* Turn off the backplane clock (only) */
-       brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false);
+       brcmf_sdio_clkctl(bus, CLK_SDONLY, false);
        sdio_release_host(bus->sdiodev->func[1]);
 
        /* Clear the data packet queues */
@@ -2282,20 +2269,20 @@ static void brcmf_sdbrcm_bus_stop(struct device *dev)
        /* Clear any held glomming stuff */
        if (bus->glomd)
                brcmu_pkt_buf_free_skb(bus->glomd);
-       brcmf_sdbrcm_free_glom(bus);
+       brcmf_sdio_free_glom(bus);
 
        /* Clear rx control and wake any waiters */
        spin_lock_bh(&bus->rxctl_lock);
        bus->rxlen = 0;
        spin_unlock_bh(&bus->rxctl_lock);
-       brcmf_sdbrcm_dcmd_resp_wake(bus);
+       brcmf_sdio_dcmd_resp_wake(bus);
 
        /* Reset some F2 state stuff */
        bus->rxskip = false;
        bus->tx_seq = bus->rx_seq = 0;
 }
 
-static inline void brcmf_sdbrcm_clrintr(struct brcmf_sdio *bus)
+static inline void brcmf_sdio_clrintr(struct brcmf_sdio *bus)
 {
        unsigned long flags;
 
@@ -2320,7 +2307,7 @@ static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus)
        addr = bus->ci->c_inf[idx].base +
               offsetof(struct sdpcmd_regs, intstatus);
 
-       ret = brcmf_sdio_regrw_helper(bus->sdiodev, addr, &val, false);
+       val = brcmf_sdiod_regrl(bus->sdiodev, addr, &ret);
        bus->sdcnt.f1regdata++;
        if (ret != 0)
                val = 0;
@@ -2330,7 +2317,7 @@ static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus)
 
        /* Clear interrupts */
        if (val) {
-               ret = brcmf_sdio_regrw_helper(bus->sdiodev, addr, &val, true);
+               brcmf_sdiod_regwl(bus->sdiodev, addr, val, &ret);
                bus->sdcnt.f1regdata++;
        }
 
@@ -2344,7 +2331,7 @@ static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus)
        return ret;
 }
 
-static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
+static void brcmf_sdio_dpc(struct brcmf_sdio *bus)
 {
        u32 newstatus = 0;
        unsigned long intstatus;
@@ -2363,8 +2350,8 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
 
 #ifdef DEBUG
                /* Check for inconsistent device control */
-               devctl = brcmf_sdio_regrb(bus->sdiodev,
-                                         SBSDIO_DEVICE_CTL, &err);
+               devctl = brcmf_sdiod_regrb(bus->sdiodev,
+                                          SBSDIO_DEVICE_CTL, &err);
                if (err) {
                        brcmf_err("error reading DEVCTL: %d\n", err);
                        bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
@@ -2372,8 +2359,8 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
 #endif                         /* DEBUG */
 
                /* Read CSR, if clock on switch to AVAIL, else ignore */
-               clkctl = brcmf_sdio_regrb(bus->sdiodev,
-                                         SBSDIO_FUNC1_CHIPCLKCSR, &err);
+               clkctl = brcmf_sdiod_regrb(bus->sdiodev,
+                                          SBSDIO_FUNC1_CHIPCLKCSR, &err);
                if (err) {
                        brcmf_err("error reading CSR: %d\n",
                                  err);
@@ -2384,16 +2371,16 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
                          devctl, clkctl);
 
                if (SBSDIO_HTAV(clkctl)) {
-                       devctl = brcmf_sdio_regrb(bus->sdiodev,
-                                                 SBSDIO_DEVICE_CTL, &err);
+                       devctl = brcmf_sdiod_regrb(bus->sdiodev,
+                                                  SBSDIO_DEVICE_CTL, &err);
                        if (err) {
                                brcmf_err("error reading DEVCTL: %d\n",
                                          err);
                                bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
                        }
                        devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
-                       brcmf_sdio_regwb(bus->sdiodev, SBSDIO_DEVICE_CTL,
-                                        devctl, &err);
+                       brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_DEVICE_CTL,
+                                         devctl, &err);
                        if (err) {
                                brcmf_err("error writing DEVCTL: %d\n",
                                          err);
@@ -2404,7 +2391,7 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
        }
 
        /* Make sure backplane clock is on */
-       brcmf_sdbrcm_bus_sleep(bus, false, true);
+       brcmf_sdio_bus_sleep(bus, false, true);
 
        /* Pending interrupt indicates new device status */
        if (atomic_read(&bus->ipend) > 0) {
@@ -2435,7 +2422,7 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
        /* Handle host mailbox indication */
        if (intstatus & I_HMB_HOST_INT) {
                intstatus &= ~I_HMB_HOST_INT;
-               intstatus |= brcmf_sdbrcm_hostmail(bus);
+               intstatus |= brcmf_sdio_hostmail(bus);
        }
 
        sdio_release_host(bus->sdiodev->func[1]);
@@ -2480,16 +2467,15 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
                        set_bit(n, (unsigned long *)&bus->intstatus.counter);
        }
 
-       brcmf_sdbrcm_clrintr(bus);
+       brcmf_sdio_clrintr(bus);
 
        if (data_ok(bus) && bus->ctrl_frame_stat &&
                (bus->clkstate == CLK_AVAIL)) {
                int i;
 
                sdio_claim_host(bus->sdiodev->func[1]);
-               err = brcmf_sdcard_send_buf(bus->sdiodev, bus->sdiodev->sbwad,
-                       SDIO_FUNC_2, F2SYNC, bus->ctrl_frame_buf,
-                       (u32) bus->ctrl_frame_len);
+               err = brcmf_sdiod_send_buf(bus->sdiodev, bus->ctrl_frame_buf,
+                                          (u32)bus->ctrl_frame_len);
 
                if (err < 0) {
                        /* On failure, abort the command and
@@ -2498,20 +2484,20 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
                                  err);
                        bus->sdcnt.tx_sderrs++;
 
-                       brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2);
+                       brcmf_sdiod_abort(bus->sdiodev, SDIO_FUNC_2);
 
-                       brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL,
-                                        SFC_WF_TERM, &err);
+                       brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL,
+                                         SFC_WF_TERM, &err);
                        bus->sdcnt.f1regdata++;
 
                        for (i = 0; i < 3; i++) {
                                u8 hi, lo;
-                               hi = brcmf_sdio_regrb(bus->sdiodev,
-                                                     SBSDIO_FUNC1_WFRAMEBCHI,
-                                                     &err);
-                               lo = brcmf_sdio_regrb(bus->sdiodev,
-                                                     SBSDIO_FUNC1_WFRAMEBCLO,
-                                                     &err);
+                               hi = brcmf_sdiod_regrb(bus->sdiodev,
+                                                      SBSDIO_FUNC1_WFRAMEBCHI,
+                                                      &err);
+                               lo = brcmf_sdiod_regrb(bus->sdiodev,
+                                                      SBSDIO_FUNC1_WFRAMEBCLO,
+                                                      &err);
                                bus->sdcnt.f1regdata += 2;
                                if ((hi == 0) && (lo == 0))
                                        break;
@@ -2522,7 +2508,7 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
                }
                sdio_release_host(bus->sdiodev->func[1]);
                bus->ctrl_frame_stat = false;
-               brcmf_sdbrcm_wait_event_wakeup(bus);
+               brcmf_sdio_wait_event_wakeup(bus);
        }
        /* Send queued frames (limit 1 if rx may still be pending) */
        else if ((bus->clkstate == CLK_AVAIL) && !atomic_read(&bus->fcstate) &&
@@ -2530,7 +2516,7 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
                 && data_ok(bus)) {
                framecnt = bus->rxpending ? min(txlimit, bus->txminmax) :
                                            txlimit;
-               framecnt = brcmf_sdbrcm_sendfromq(bus, framecnt);
+               framecnt = brcmf_sdio_sendfromq(bus, framecnt);
                txlimit -= framecnt;
        }
 
@@ -2552,12 +2538,12 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
                bus->activity = false;
                brcmf_dbg(SDIO, "idle state\n");
                sdio_claim_host(bus->sdiodev->func[1]);
-               brcmf_sdbrcm_bus_sleep(bus, true, false);
+               brcmf_sdio_bus_sleep(bus, true, false);
                sdio_release_host(bus->sdiodev->func[1]);
        }
 }
 
-static struct pktq *brcmf_sdbrcm_bus_gettxq(struct device *dev)
+static struct pktq *brcmf_sdio_bus_gettxq(struct device *dev)
 {
        struct brcmf_bus *bus_if = dev_get_drvdata(dev);
        struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
@@ -2566,7 +2552,7 @@ static struct pktq *brcmf_sdbrcm_bus_gettxq(struct device *dev)
        return &bus->txq;
 }
 
-static int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt)
+static int brcmf_sdio_bus_txdata(struct device *dev, struct sk_buff *pkt)
 {
        int ret = -EBADE;
        uint datalen, prec;
@@ -2622,7 +2608,7 @@ static int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt)
 #ifdef DEBUG
 #define CONSOLE_LINE_MAX       192
 
-static int brcmf_sdbrcm_readconsole(struct brcmf_sdio *bus)
+static int brcmf_sdio_readconsole(struct brcmf_sdio *bus)
 {
        struct brcmf_console *c = &bus->console;
        u8 line[CONSOLE_LINE_MAX], ch;
@@ -2635,8 +2621,8 @@ static int brcmf_sdbrcm_readconsole(struct brcmf_sdio *bus)
 
        /* Read console log struct */
        addr = bus->console_addr + offsetof(struct rte_console, log_le);
-       rv = brcmf_sdio_ramrw(bus->sdiodev, false, addr, (u8 *)&c->log_le,
-                             sizeof(c->log_le));
+       rv = brcmf_sdiod_ramrw(bus->sdiodev, false, addr, (u8 *)&c->log_le,
+                              sizeof(c->log_le));
        if (rv < 0)
                return rv;
 
@@ -2661,7 +2647,7 @@ static int brcmf_sdbrcm_readconsole(struct brcmf_sdio *bus)
 
        /* Read the console buffer */
        addr = le32_to_cpu(c->log_le.buf);
-       rv = brcmf_sdio_ramrw(bus->sdiodev, false, addr, c->buf, c->bufsize);
+       rv = brcmf_sdiod_ramrw(bus->sdiodev, false, addr, c->buf, c->bufsize);
        if (rv < 0)
                return rv;
 
@@ -2699,14 +2685,13 @@ break2:
 }
 #endif                         /* DEBUG */
 
-static int brcmf_tx_frame(struct brcmf_sdio *bus, u8 *frame, u16 len)
+static int brcmf_sdio_tx_frame(struct brcmf_sdio *bus, u8 *frame, u16 len)
 {
        int i;
        int ret;
 
        bus->ctrl_frame_stat = false;
-       ret = brcmf_sdcard_send_buf(bus->sdiodev, bus->sdiodev->sbwad,
-                                   SDIO_FUNC_2, F2SYNC, frame, len);
+       ret = brcmf_sdiod_send_buf(bus->sdiodev, frame, len);
 
        if (ret < 0) {
                /* On failure, abort the command and terminate the frame */
@@ -2714,18 +2699,18 @@ static int brcmf_tx_frame(struct brcmf_sdio *bus, u8 *frame, u16 len)
                          ret);
                bus->sdcnt.tx_sderrs++;
 
-               brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2);
+               brcmf_sdiod_abort(bus->sdiodev, SDIO_FUNC_2);
 
-               brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL,
-                                SFC_WF_TERM, NULL);
+               brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL,
+                                 SFC_WF_TERM, NULL);
                bus->sdcnt.f1regdata++;
 
                for (i = 0; i < 3; i++) {
                        u8 hi, lo;
-                       hi = brcmf_sdio_regrb(bus->sdiodev,
-                                             SBSDIO_FUNC1_WFRAMEBCHI, NULL);
-                       lo = brcmf_sdio_regrb(bus->sdiodev,
-                                             SBSDIO_FUNC1_WFRAMEBCLO, NULL);
+                       hi = brcmf_sdiod_regrb(bus->sdiodev,
+                                              SBSDIO_FUNC1_WFRAMEBCHI, NULL);
+                       lo = brcmf_sdiod_regrb(bus->sdiodev,
+                                              SBSDIO_FUNC1_WFRAMEBCLO, NULL);
                        bus->sdcnt.f1regdata += 2;
                        if (hi == 0 && lo == 0)
                                break;
@@ -2739,7 +2724,7 @@ static int brcmf_tx_frame(struct brcmf_sdio *bus, u8 *frame, u16 len)
 }
 
 static int
-brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
+brcmf_sdio_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
 {
        u8 *frame;
        u16 len, pad;
@@ -2783,7 +2768,7 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
 
        /* Make sure backplane clock is on */
        sdio_claim_host(bus->sdiodev->func[1]);
-       brcmf_sdbrcm_bus_sleep(bus, false, false);
+       brcmf_sdio_bus_sleep(bus, false, false);
        sdio_release_host(bus->sdiodev->func[1]);
 
        hd_info.len = (u16)msglen;
@@ -2827,7 +2812,7 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
 
                do {
                        sdio_claim_host(bus->sdiodev->func[1]);
-                       ret = brcmf_tx_frame(bus, frame, len);
+                       ret = brcmf_sdio_tx_frame(bus, frame, len);
                        sdio_release_host(bus->sdiodev->func[1]);
                } while (ret < 0 && retries++ < TXRETRIES);
        }
@@ -2837,7 +2822,7 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
                bus->activity = false;
                sdio_claim_host(bus->sdiodev->func[1]);
                brcmf_dbg(INFO, "idle\n");
-               brcmf_sdbrcm_clkctl(bus, CLK_NONE, true);
+               brcmf_sdio_clkctl(bus, CLK_NONE, true);
                sdio_release_host(bus->sdiodev->func[1]);
        }
 
@@ -2871,8 +2856,8 @@ static int brcmf_sdio_readshared(struct brcmf_sdio *bus,
         * address of sdpcm_shared structure
         */
        sdio_claim_host(bus->sdiodev->func[1]);
-       brcmf_sdbrcm_bus_sleep(bus, false, false);
-       rv = brcmf_sdio_ramrw(bus->sdiodev, false, shaddr, (u8 *)&addr_le, 4);
+       brcmf_sdio_bus_sleep(bus, false, false);
+       rv = brcmf_sdiod_ramrw(bus->sdiodev, false, shaddr, (u8 *)&addr_le, 4);
        sdio_release_host(bus->sdiodev->func[1]);
        if (rv < 0)
                return rv;
@@ -2892,8 +2877,8 @@ static int brcmf_sdio_readshared(struct brcmf_sdio *bus,
        }
 
        /* Read hndrte_shared structure */
-       rv = brcmf_sdio_ramrw(bus->sdiodev, false, addr, (u8 *)&sh_le,
-                             sizeof(struct sdpcm_shared_le));
+       rv = brcmf_sdiod_ramrw(bus->sdiodev, false, addr, (u8 *)&sh_le,
+                              sizeof(struct sdpcm_shared_le));
        if (rv < 0)
                return rv;
 
@@ -2929,22 +2914,22 @@ static int brcmf_sdio_dump_console(struct brcmf_sdio *bus,
 
        /* obtain console information from device memory */
        addr = sh->console_addr + offsetof(struct rte_console, log_le);
-       rv = brcmf_sdio_ramrw(bus->sdiodev, false, addr,
-                             (u8 *)&sh_val, sizeof(u32));
+       rv = brcmf_sdiod_ramrw(bus->sdiodev, false, addr,
+                              (u8 *)&sh_val, sizeof(u32));
        if (rv < 0)
                return rv;
        console_ptr = le32_to_cpu(sh_val);
 
        addr = sh->console_addr + offsetof(struct rte_console, log_le.buf_size);
-       rv = brcmf_sdio_ramrw(bus->sdiodev, false, addr,
-                             (u8 *)&sh_val, sizeof(u32));
+       rv = brcmf_sdiod_ramrw(bus->sdiodev, false, addr,
+                              (u8 *)&sh_val, sizeof(u32));
        if (rv < 0)
                return rv;
        console_size = le32_to_cpu(sh_val);
 
        addr = sh->console_addr + offsetof(struct rte_console, log_le.idx);
-       rv = brcmf_sdio_ramrw(bus->sdiodev, false, addr,
-                             (u8 *)&sh_val, sizeof(u32));
+       rv = brcmf_sdiod_ramrw(bus->sdiodev, false, addr,
+                              (u8 *)&sh_val, sizeof(u32));
        if (rv < 0)
                return rv;
        console_index = le32_to_cpu(sh_val);
@@ -2958,8 +2943,8 @@ static int brcmf_sdio_dump_console(struct brcmf_sdio *bus,
 
        /* obtain the console data from device */
        conbuf[console_size] = '\0';
-       rv = brcmf_sdio_ramrw(bus->sdiodev, false, console_ptr, (u8 *)conbuf,
-                             console_size);
+       rv = brcmf_sdiod_ramrw(bus->sdiodev, false, console_ptr, (u8 *)conbuf,
+                              console_size);
        if (rv < 0)
                goto done;
 
@@ -2996,8 +2981,8 @@ static int brcmf_sdio_trap_info(struct brcmf_sdio *bus, struct sdpcm_shared *sh,
                return 0;
        }
 
-       error = brcmf_sdio_ramrw(bus->sdiodev, false, sh->trap_addr, (u8 *)&tr,
-                                sizeof(struct brcmf_trap_info));
+       error = brcmf_sdiod_ramrw(bus->sdiodev, false, sh->trap_addr, (u8 *)&tr,
+                                 sizeof(struct brcmf_trap_info));
        if (error < 0)
                return error;
 
@@ -3040,14 +3025,14 @@ static int brcmf_sdio_assert_info(struct brcmf_sdio *bus,
 
        sdio_claim_host(bus->sdiodev->func[1]);
        if (sh->assert_file_addr != 0) {
-               error = brcmf_sdio_ramrw(bus->sdiodev, false,
-                                        sh->assert_file_addr, (u8 *)file, 80);
+               error = brcmf_sdiod_ramrw(bus->sdiodev, false,
+                                         sh->assert_file_addr, (u8 *)file, 80);
                if (error < 0)
                        return error;
        }
        if (sh->assert_exp_addr != 0) {
-               error = brcmf_sdio_ramrw(bus->sdiodev, false,
-                                        sh->assert_exp_addr, (u8 *)expr, 80);
+               error = brcmf_sdiod_ramrw(bus->sdiodev, false,
+                                         sh->assert_exp_addr, (u8 *)expr, 80);
                if (error < 0)
                        return error;
        }
@@ -3059,7 +3044,7 @@ static int brcmf_sdio_assert_info(struct brcmf_sdio *bus,
        return simple_read_from_buffer(data, count, &pos, buf, res);
 }
 
-static int brcmf_sdbrcm_checkdied(struct brcmf_sdio *bus)
+static int brcmf_sdio_checkdied(struct brcmf_sdio *bus)
 {
        int error;
        struct sdpcm_shared sh;
@@ -3080,8 +3065,8 @@ static int brcmf_sdbrcm_checkdied(struct brcmf_sdio *bus)
        return 0;
 }
 
-static int brcmf_sdbrcm_died_dump(struct brcmf_sdio *bus, char __user *data,
-                                 size_t count, loff_t *ppos)
+static int brcmf_sdio_died_dump(struct brcmf_sdio *bus, char __user *data,
+                               size_t count, loff_t *ppos)
 {
        int error = 0;
        struct sdpcm_shared sh;
@@ -3122,7 +3107,7 @@ static ssize_t brcmf_sdio_forensic_read(struct file *f, char __user *data,
        struct brcmf_sdio *bus = f->private_data;
        int res;
 
-       res = brcmf_sdbrcm_died_dump(bus, data, count, ppos);
+       res = brcmf_sdio_died_dump(bus, data, count, ppos);
        if (res > 0)
                *ppos += res;
        return (ssize_t)res;
@@ -3147,7 +3132,7 @@ static void brcmf_sdio_debugfs_create(struct brcmf_sdio *bus)
        brcmf_debugfs_create_sdio_count(drvr, &bus->sdcnt);
 }
 #else
-static int brcmf_sdbrcm_checkdied(struct brcmf_sdio *bus)
+static int brcmf_sdio_checkdied(struct brcmf_sdio *bus)
 {
        return 0;
 }
@@ -3158,7 +3143,7 @@ static void brcmf_sdio_debugfs_create(struct brcmf_sdio *bus)
 #endif /* DEBUG */
 
 static int
-brcmf_sdbrcm_bus_rxctl(struct device *dev, unsigned char *msg, uint msglen)
+brcmf_sdio_bus_rxctl(struct device *dev, unsigned char *msg, uint msglen)
 {
        int timeleft;
        uint rxlen = 0;
@@ -3171,7 +3156,7 @@ brcmf_sdbrcm_bus_rxctl(struct device *dev, unsigned char *msg, uint msglen)
        brcmf_dbg(TRACE, "Enter\n");
 
        /* Wait until control frame is available */
-       timeleft = brcmf_sdbrcm_dcmd_resp_wait(bus, &bus->rxlen, &pending);
+       timeleft = brcmf_sdio_dcmd_resp_wait(bus, &bus->rxlen, &pending);
 
        spin_lock_bh(&bus->rxctl_lock);
        rxlen = bus->rxlen;
@@ -3188,13 +3173,13 @@ brcmf_sdbrcm_bus_rxctl(struct device *dev, unsigned char *msg, uint msglen)
                          rxlen, msglen);
        } else if (timeleft == 0) {
                brcmf_err("resumed on timeout\n");
-               brcmf_sdbrcm_checkdied(bus);
+               brcmf_sdio_checkdied(bus);
        } else if (pending) {
                brcmf_dbg(CTL, "cancelled\n");
                return -ERESTARTSYS;
        } else {
                brcmf_dbg(CTL, "resumed for unknown reason?\n");
-               brcmf_sdbrcm_checkdied(bus);
+               brcmf_sdio_checkdied(bus);
        }
 
        if (rxlen)
@@ -3205,7 +3190,7 @@ brcmf_sdbrcm_bus_rxctl(struct device *dev, unsigned char *msg, uint msglen)
        return rxlen ? (int)rxlen : -ETIMEDOUT;
 }
 
-static bool brcmf_sdbrcm_download_state(struct brcmf_sdio *bus, bool enter)
+static bool brcmf_sdio_download_state(struct brcmf_sdio *bus, bool enter)
 {
        struct chip_info *ci = bus->ci;
 
@@ -3230,7 +3215,7 @@ static bool brcmf_sdbrcm_download_state(struct brcmf_sdio *bus, bool enter)
        return true;
 }
 
-static int brcmf_sdbrcm_download_code_file(struct brcmf_sdio *bus)
+static int brcmf_sdio_download_code_file(struct brcmf_sdio *bus)
 {
        const struct firmware *fw;
        int err;
@@ -3238,7 +3223,7 @@ static int brcmf_sdbrcm_download_code_file(struct brcmf_sdio *bus)
        int address;
        int len;
 
-       fw = brcmf_sdbrcm_get_fw(bus, BRCMF_FIRMWARE_BIN);
+       fw = brcmf_sdio_get_fw(bus, BRCMF_FIRMWARE_BIN);
        if (fw == NULL)
                return -ENOENT;
 
@@ -3252,8 +3237,8 @@ static int brcmf_sdbrcm_download_code_file(struct brcmf_sdio *bus)
        while (offset < fw->size) {
                len = ((offset + MEMBLOCK) < fw->size) ? MEMBLOCK :
                      fw->size - offset;
-               err = brcmf_sdio_ramrw(bus->sdiodev, true, address,
-                                      (u8 *)&fw->data[offset], len);
+               err = brcmf_sdiod_ramrw(bus->sdiodev, true, address,
+                                       (u8 *)&fw->data[offset], len);
                if (err) {
                        brcmf_err("error %d on writing %d membytes at 0x%08x\n",
                                  err, len, address);
@@ -3278,8 +3263,8 @@ failure:
  * by two NULs.
 */
 
-static int brcmf_process_nvram_vars(struct brcmf_sdio *bus,
-                                   const struct firmware *nv)
+static int brcmf_sdio_strip_nvram(struct brcmf_sdio *bus,
+                                 const struct firmware *nv)
 {
        char *varbuf;
        char *dp;
@@ -3343,44 +3328,48 @@ err:
        return ret;
 }
 
-static int brcmf_sdbrcm_download_nvram(struct brcmf_sdio *bus)
+static int brcmf_sdio_download_nvram(struct brcmf_sdio *bus)
 {
        const struct firmware *nv;
        int ret;
 
-       nv = brcmf_sdbrcm_get_fw(bus, BRCMF_FIRMWARE_NVRAM);
+       nv = brcmf_sdio_get_fw(bus, BRCMF_FIRMWARE_NVRAM);
        if (nv == NULL)
                return -ENOENT;
 
-       ret = brcmf_process_nvram_vars(bus, nv);
+       ret = brcmf_sdio_strip_nvram(bus, nv);
 
        release_firmware(nv);
 
        return ret;
 }
 
-static int _brcmf_sdbrcm_download_firmware(struct brcmf_sdio *bus)
+static int brcmf_sdio_download_firmware(struct brcmf_sdio *bus)
 {
-       int bcmerror = -1;
+       int bcmerror = -EFAULT;
+
+
+       sdio_claim_host(bus->sdiodev->func[1]);
+       brcmf_sdio_clkctl(bus, CLK_AVAIL, false);
 
        /* Keep arm in reset */
-       if (!brcmf_sdbrcm_download_state(bus, true)) {
+       if (!brcmf_sdio_download_state(bus, true)) {
                brcmf_err("error placing ARM core in reset\n");
                goto err;
        }
 
-       if (brcmf_sdbrcm_download_code_file(bus)) {
+       if (brcmf_sdio_download_code_file(bus)) {
                brcmf_err("dongle image file download failed\n");
                goto err;
        }
 
-       if (brcmf_sdbrcm_download_nvram(bus)) {
+       if (brcmf_sdio_download_nvram(bus)) {
                brcmf_err("dongle nvram file download failed\n");
                goto err;
        }
 
        /* Take arm out of reset */
-       if (!brcmf_sdbrcm_download_state(bus, false)) {
+       if (!brcmf_sdio_download_state(bus, false)) {
                brcmf_err("error getting out of ARM core reset\n");
                goto err;
        }
@@ -3388,10 +3377,12 @@ static int _brcmf_sdbrcm_download_firmware(struct brcmf_sdio *bus)
        bcmerror = 0;
 
 err:
+       brcmf_sdio_clkctl(bus, CLK_SDONLY, false);
+       sdio_release_host(bus->sdiodev->func[1]);
        return bcmerror;
 }
 
-static bool brcmf_sdbrcm_sr_capable(struct brcmf_sdio *bus)
+static bool brcmf_sdio_sr_capable(struct brcmf_sdio *bus)
 {
        u32 addr, reg;
 
@@ -3403,47 +3394,45 @@ static bool brcmf_sdbrcm_sr_capable(struct brcmf_sdio *bus)
 
        /* read PMU chipcontrol register 3*/
        addr = CORE_CC_REG(bus->ci->c_inf[0].base, chipcontrol_addr);
-       brcmf_sdio_regwl(bus->sdiodev, addr, 3, NULL);
+       brcmf_sdiod_regwl(bus->sdiodev, addr, 3, NULL);
        addr = CORE_CC_REG(bus->ci->c_inf[0].base, chipcontrol_data);
-       reg = brcmf_sdio_regrl(bus->sdiodev, addr, NULL);
+       reg = brcmf_sdiod_regrl(bus->sdiodev, addr, NULL);
 
        return (bool)reg;
 }
 
-static void brcmf_sdbrcm_sr_init(struct brcmf_sdio *bus)
+static void brcmf_sdio_sr_init(struct brcmf_sdio *bus)
 {
        int err = 0;
        u8 val;
 
        brcmf_dbg(TRACE, "Enter\n");
 
-       val = brcmf_sdio_regrb(bus->sdiodev, SBSDIO_FUNC1_WAKEUPCTRL,
-                              &err);
+       val = brcmf_sdiod_regrb(bus->sdiodev, SBSDIO_FUNC1_WAKEUPCTRL, &err);
        if (err) {
                brcmf_err("error reading SBSDIO_FUNC1_WAKEUPCTRL\n");
                return;
        }
 
        val |= 1 << SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT;
-       brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_WAKEUPCTRL,
-                        val, &err);
+       brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_WAKEUPCTRL, val, &err);
        if (err) {
                brcmf_err("error writing SBSDIO_FUNC1_WAKEUPCTRL\n");
                return;
        }
 
        /* Add CMD14 Support */
-       brcmf_sdio_regwb(bus->sdiodev, SDIO_CCCR_BRCM_CARDCAP,
-                        (SDIO_CCCR_BRCM_CARDCAP_CMD14_SUPPORT |
-                         SDIO_CCCR_BRCM_CARDCAP_CMD14_EXT),
-                        &err);
+       brcmf_sdiod_regwb(bus->sdiodev, SDIO_CCCR_BRCM_CARDCAP,
+                         (SDIO_CCCR_BRCM_CARDCAP_CMD14_SUPPORT |
+                          SDIO_CCCR_BRCM_CARDCAP_CMD14_EXT),
+                         &err);
        if (err) {
                brcmf_err("error writing SDIO_CCCR_BRCM_CARDCAP\n");
                return;
        }
 
-       brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
-                        SBSDIO_FORCE_HT, &err);
+       brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
+                         SBSDIO_FORCE_HT, &err);
        if (err) {
                brcmf_err("error writing SBSDIO_FUNC1_CHIPCLKCSR\n");
                return;
@@ -3455,7 +3444,7 @@ static void brcmf_sdbrcm_sr_init(struct brcmf_sdio *bus)
 }
 
 /* enable KSO bit */
-static int brcmf_sdbrcm_kso_init(struct brcmf_sdio *bus)
+static int brcmf_sdio_kso_init(struct brcmf_sdio *bus)
 {
        u8 val;
        int err = 0;
@@ -3466,8 +3455,7 @@ static int brcmf_sdbrcm_kso_init(struct brcmf_sdio *bus)
        if (bus->ci->c_inf[1].rev < 12)
                return 0;
 
-       val = brcmf_sdio_regrb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR,
-                              &err);
+       val = brcmf_sdiod_regrb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR, &err);
        if (err) {
                brcmf_err("error reading SBSDIO_FUNC1_SLEEPCSR\n");
                return err;
@@ -3476,8 +3464,8 @@ static int brcmf_sdbrcm_kso_init(struct brcmf_sdio *bus)
        if (!(val & SBSDIO_FUNC1_SLEEPCSR_KSO_MASK)) {
                val |= (SBSDIO_FUNC1_SLEEPCSR_KSO_EN <<
                        SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT);
-               brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR,
-                                val, &err);
+               brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR,
+                                 val, &err);
                if (err) {
                        brcmf_err("error writing SBSDIO_FUNC1_SLEEPCSR\n");
                        return err;
@@ -3488,25 +3476,7 @@ static int brcmf_sdbrcm_kso_init(struct brcmf_sdio *bus)
 }
 
 
-static bool
-brcmf_sdbrcm_download_firmware(struct brcmf_sdio *bus)
-{
-       bool ret;
-
-       sdio_claim_host(bus->sdiodev->func[1]);
-
-       brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
-
-       ret = _brcmf_sdbrcm_download_firmware(bus) == 0;
-
-       brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false);
-
-       sdio_release_host(bus->sdiodev->func[1]);
-
-       return ret;
-}
-
-static int brcmf_sdbrcm_bus_preinit(struct device *dev)
+static int brcmf_sdio_bus_preinit(struct device *dev)
 {
        struct brcmf_bus *bus_if = dev_get_drvdata(dev);
        struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
@@ -3565,13 +3535,11 @@ done:
        return err;
 }
 
-static int brcmf_sdbrcm_bus_init(struct device *dev)
+static int brcmf_sdio_bus_init(struct device *dev)
 {
        struct brcmf_bus *bus_if = dev_get_drvdata(dev);
        struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
        struct brcmf_sdio *bus = sdiodev->bus;
-       unsigned long timeout;
-       u8 ready, enable;
        int err, ret = 0;
        u8 saveclk;
 
@@ -3579,8 +3547,9 @@ static int brcmf_sdbrcm_bus_init(struct device *dev)
 
        /* try to download image and nvram to the dongle */
        if (bus_if->state == BRCMF_BUS_DOWN) {
-               if (!(brcmf_sdbrcm_download_firmware(bus)))
-                       return -1;
+               err = brcmf_sdio_download_firmware(bus);
+               if (err)
+                       return err;
        }
 
        if (!bus->sdiodev->bus_if->drvr)
@@ -3588,21 +3557,21 @@ static int brcmf_sdbrcm_bus_init(struct device *dev)
 
        /* Start the watchdog timer */
        bus->sdcnt.tickcnt = 0;
-       brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS);
+       brcmf_sdio_wd_timer(bus, BRCMF_WD_POLL_MS);
 
        sdio_claim_host(bus->sdiodev->func[1]);
 
        /* Make sure backplane clock is on, needed to generate F2 interrupt */
-       brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
+       brcmf_sdio_clkctl(bus, CLK_AVAIL, false);
        if (bus->clkstate != CLK_AVAIL)
                goto exit;
 
        /* Force clocks on backplane to be sure F2 interrupt propagates */
-       saveclk = brcmf_sdio_regrb(bus->sdiodev,
-                                  SBSDIO_FUNC1_CHIPCLKCSR, &err);
+       saveclk = brcmf_sdiod_regrb(bus->sdiodev,
+                                   SBSDIO_FUNC1_CHIPCLKCSR, &err);
        if (!err) {
-               brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
-                                (saveclk | SBSDIO_FORCE_HT), &err);
+               brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
+                                 (saveclk | SBSDIO_FORCE_HT), &err);
        }
        if (err) {
                brcmf_err("Failed to force clock for F2: err %d\n", err);
@@ -3612,56 +3581,42 @@ static int brcmf_sdbrcm_bus_init(struct device *dev)
        /* Enable function 2 (frame transfers) */
        w_sdreg32(bus, SDPCM_PROT_VERSION << SMB_DATA_VERSION_SHIFT,
                  offsetof(struct sdpcmd_regs, tosbmailboxdata));
-       enable = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2);
-
-       brcmf_sdio_regwb(bus->sdiodev, SDIO_CCCR_IOEx, enable, NULL);
+       err = sdio_enable_func(bus->sdiodev->func[SDIO_FUNC_2]);
 
-       timeout = jiffies + msecs_to_jiffies(BRCMF_WAIT_F2RDY);
-       ready = 0;
-       while (enable != ready) {
-               ready = brcmf_sdio_regrb(bus->sdiodev,
-                                        SDIO_CCCR_IORx, NULL);
-               if (time_after(jiffies, timeout))
-                       break;
-               else if (time_after(jiffies, timeout - BRCMF_WAIT_F2RDY + 50))
-                       /* prevent busy waiting if it takes too long */
-                       msleep_interruptible(20);
-       }
 
-       brcmf_dbg(INFO, "enable 0x%02x, ready 0x%02x\n", enable, ready);
+       brcmf_dbg(INFO, "enable F2: err=%d\n", err);
 
        /* If F2 successfully enabled, set core and enable interrupts */
-       if (ready == enable) {
+       if (!err) {
                /* Set up the interrupt mask and enable interrupts */
                bus->hostintmask = HOSTINTMASK;
                w_sdreg32(bus, bus->hostintmask,
                          offsetof(struct sdpcmd_regs, hostintmask));
 
-               brcmf_sdio_regwb(bus->sdiodev, SBSDIO_WATERMARK, 8, &err);
+               brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_WATERMARK, 8, &err);
        } else {
                /* Disable F2 again */
-               enable = SDIO_FUNC_ENABLE_1;
-               brcmf_sdio_regwb(bus->sdiodev, SDIO_CCCR_IOEx, enable, NULL);
+               sdio_disable_func(bus->sdiodev->func[SDIO_FUNC_2]);
                ret = -ENODEV;
        }
 
-       if (brcmf_sdbrcm_sr_capable(bus)) {
-               brcmf_sdbrcm_sr_init(bus);
+       if (brcmf_sdio_sr_capable(bus)) {
+               brcmf_sdio_sr_init(bus);
        } else {
                /* Restore previous clock setting */
-               brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
-                                saveclk, &err);
+               brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
+                                 saveclk, &err);
        }
 
        if (ret == 0) {
-               ret = brcmf_sdio_intr_register(bus->sdiodev);
+               ret = brcmf_sdiod_intr_register(bus->sdiodev);
                if (ret != 0)
                        brcmf_err("intr register failed:%d\n", ret);
        }
 
        /* If we didn't come up, turn off backplane clock */
        if (bus_if->state != BRCMF_BUS_DATA)
-               brcmf_sdbrcm_clkctl(bus, CLK_NONE, false);
+               brcmf_sdio_clkctl(bus, CLK_NONE, false);
 
 exit:
        sdio_release_host(bus->sdiodev->func[1]);
@@ -3669,10 +3624,8 @@ exit:
        return ret;
 }
 
-void brcmf_sdbrcm_isr(void *arg)
+void brcmf_sdio_isr(struct brcmf_sdio *bus)
 {
-       struct brcmf_sdio *bus = (struct brcmf_sdio *) arg;
-
        brcmf_dbg(TRACE, "Enter\n");
 
        if (!bus) {
@@ -3702,7 +3655,7 @@ void brcmf_sdbrcm_isr(void *arg)
        queue_work(bus->brcmf_wq, &bus->datawork);
 }
 
-static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus)
+static bool brcmf_sdio_bus_watchdog(struct brcmf_sdio *bus)
 {
 #ifdef DEBUG
        struct brcmf_bus *bus_if = dev_get_drvdata(bus->sdiodev->dev);
@@ -3726,9 +3679,9 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus)
                                u8 devpend;
 
                                sdio_claim_host(bus->sdiodev->func[1]);
-                               devpend = brcmf_sdio_regrb(bus->sdiodev,
-                                                          SDIO_CCCR_INTx,
-                                                          NULL);
+                               devpend = brcmf_sdiod_regrb(bus->sdiodev,
+                                                           SDIO_CCCR_INTx,
+                                                           NULL);
                                sdio_release_host(bus->sdiodev->func[1]);
                                intstatus =
                                    devpend & (INTR_STATUS_FUNC1 |
@@ -3758,8 +3711,8 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus)
                        bus->console.count -= bus->console_interval;
                        sdio_claim_host(bus->sdiodev->func[1]);
                        /* Make sure backplane clock is on */
-                       brcmf_sdbrcm_bus_sleep(bus, false, false);
-                       if (brcmf_sdbrcm_readconsole(bus) < 0)
+                       brcmf_sdio_bus_sleep(bus, false, false);
+                       if (brcmf_sdio_readconsole(bus) < 0)
                                /* stop on error */
                                bus->console_interval = 0;
                        sdio_release_host(bus->sdiodev->func[1]);
@@ -3773,11 +3726,11 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus)
                        bus->idlecount = 0;
                        if (bus->activity) {
                                bus->activity = false;
-                               brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS);
+                               brcmf_sdio_wd_timer(bus, BRCMF_WD_POLL_MS);
                        } else {
                                brcmf_dbg(SDIO, "idle\n");
                                sdio_claim_host(bus->sdiodev->func[1]);
-                               brcmf_sdbrcm_bus_sleep(bus, true, false);
+                               brcmf_sdio_bus_sleep(bus, true, false);
                                sdio_release_host(bus->sdiodev->func[1]);
                        }
                }
@@ -3792,12 +3745,12 @@ static void brcmf_sdio_dataworker(struct work_struct *work)
                                              datawork);
 
        while (atomic_read(&bus->dpc_tskcnt)) {
-               brcmf_sdbrcm_dpc(bus);
+               brcmf_sdio_dpc(bus);
                atomic_dec(&bus->dpc_tskcnt);
        }
 }
 
-static void brcmf_sdbrcm_release_malloc(struct brcmf_sdio *bus)
+static void brcmf_sdio_release_malloc(struct brcmf_sdio *bus)
 {
        brcmf_dbg(TRACE, "Enter\n");
 
@@ -3806,7 +3759,7 @@ static void brcmf_sdbrcm_release_malloc(struct brcmf_sdio *bus)
        bus->rxlen = 0;
 }
 
-static bool brcmf_sdbrcm_probe_malloc(struct brcmf_sdio *bus)
+static bool brcmf_sdio_probe_malloc(struct brcmf_sdio *bus)
 {
        brcmf_dbg(TRACE, "Enter\n");
 
@@ -3823,7 +3776,7 @@ static bool brcmf_sdbrcm_probe_malloc(struct brcmf_sdio *bus)
 }
 
 static bool
-brcmf_sdbrcm_probe_attach(struct brcmf_sdio *bus, u32 regsva)
+brcmf_sdio_probe_attach(struct brcmf_sdio *bus)
 {
        u8 clkctl = 0;
        int err = 0;
@@ -3836,18 +3789,18 @@ brcmf_sdbrcm_probe_attach(struct brcmf_sdio *bus, u32 regsva)
        sdio_claim_host(bus->sdiodev->func[1]);
 
        pr_debug("F1 signature read @0x18000000=0x%4x\n",
-                brcmf_sdio_regrl(bus->sdiodev, SI_ENUM_BASE, NULL));
+                brcmf_sdiod_regrl(bus->sdiodev, SI_ENUM_BASE, NULL));
 
        /*
         * Force PLL off until brcmf_sdio_chip_attach()
         * programs PLL control regs
         */
 
-       brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
-                        BRCMF_INIT_CLKCTL1, &err);
+       brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
+                         BRCMF_INIT_CLKCTL1, &err);
        if (!err)
-               clkctl = brcmf_sdio_regrb(bus->sdiodev,
-                                         SBSDIO_FUNC1_CHIPCLKCSR, &err);
+               clkctl = brcmf_sdiod_regrb(bus->sdiodev,
+                                          SBSDIO_FUNC1_CHIPCLKCSR, &err);
 
        if (err || ((clkctl & ~SBSDIO_AVBITS) != BRCMF_INIT_CLKCTL1)) {
                brcmf_err("ChipClkCSR access: err %d wrote 0x%02x read 0x%02x\n",
@@ -3855,12 +3808,12 @@ brcmf_sdbrcm_probe_attach(struct brcmf_sdio *bus, u32 regsva)
                goto fail;
        }
 
-       if (brcmf_sdio_chip_attach(bus->sdiodev, &bus->ci, regsva)) {
+       if (brcmf_sdio_chip_attach(bus->sdiodev, &bus->ci)) {
                brcmf_err("brcmf_sdio_chip_attach failed!\n");
                goto fail;
        }
 
-       if (brcmf_sdbrcm_kso_init(bus)) {
+       if (brcmf_sdio_kso_init(bus)) {
                brcmf_err("error enabling KSO\n");
                goto fail;
        }
@@ -3879,33 +3832,33 @@ brcmf_sdbrcm_probe_attach(struct brcmf_sdio *bus, u32 regsva)
        }
 
        /* Set card control so an SDIO card reset does a WLAN backplane reset */
-       reg_val = brcmf_sdio_regrb(bus->sdiodev,
-                                  SDIO_CCCR_BRCM_CARDCTRL, &err);
+       reg_val = brcmf_sdiod_regrb(bus->sdiodev,
+                                   SDIO_CCCR_BRCM_CARDCTRL, &err);
        if (err)
                goto fail;
 
        reg_val |= SDIO_CCCR_BRCM_CARDCTRL_WLANRESET;
 
-       brcmf_sdio_regwb(bus->sdiodev,
-                        SDIO_CCCR_BRCM_CARDCTRL, reg_val, &err);
+       brcmf_sdiod_regwb(bus->sdiodev,
+                         SDIO_CCCR_BRCM_CARDCTRL, reg_val, &err);
        if (err)
                goto fail;
 
        /* set PMUControl so a backplane reset does PMU state reload */
        reg_addr = CORE_CC_REG(bus->ci->c_inf[0].base,
                               pmucontrol);
-       reg_val = brcmf_sdio_regrl(bus->sdiodev,
-                                  reg_addr,
-                                  &err);
+       reg_val = brcmf_sdiod_regrl(bus->sdiodev,
+                                   reg_addr,
+                                   &err);
        if (err)
                goto fail;
 
        reg_val |= (BCMA_CC_PMU_CTL_RES_RELOAD << BCMA_CC_PMU_CTL_RES_SHIFT);
 
-       brcmf_sdio_regwl(bus->sdiodev,
-                        reg_addr,
-                        reg_val,
-                        &err);
+       brcmf_sdiod_regwl(bus->sdiodev,
+                         reg_addr,
+                         reg_val,
+                         &err);
        if (err)
                goto fail;
 
@@ -3935,21 +3888,20 @@ fail:
        return false;
 }
 
-static bool brcmf_sdbrcm_probe_init(struct brcmf_sdio *bus)
+static bool brcmf_sdio_probe_init(struct brcmf_sdio *bus)
 {
        brcmf_dbg(TRACE, "Enter\n");
 
        sdio_claim_host(bus->sdiodev->func[1]);
 
        /* Disable F2 to clear any intermediate frame state on the dongle */
-       brcmf_sdio_regwb(bus->sdiodev, SDIO_CCCR_IOEx,
-                        SDIO_FUNC_ENABLE_1, NULL);
+       sdio_disable_func(bus->sdiodev->func[SDIO_FUNC_2]);
 
        bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
        bus->rxflow = false;
 
        /* Done with backplane-dependent accesses, can drop clock... */
-       brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL);
+       brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL);
 
        sdio_release_host(bus->sdiodev->func[1]);
 
@@ -3970,7 +3922,7 @@ static bool brcmf_sdbrcm_probe_init(struct brcmf_sdio *bus)
 }
 
 static int
-brcmf_sdbrcm_watchdog_thread(void *data)
+brcmf_sdio_watchdog_thread(void *data)
 {
        struct brcmf_sdio *bus = (struct brcmf_sdio *)data;
 
@@ -3980,7 +3932,7 @@ brcmf_sdbrcm_watchdog_thread(void *data)
                if (kthread_should_stop())
                        break;
                if (!wait_for_completion_interruptible(&bus->watchdog_wait)) {
-                       brcmf_sdbrcm_bus_watchdog(bus);
+                       brcmf_sdio_bus_watchdog(bus);
                        /* Count the tick for reference */
                        bus->sdcnt.tickcnt++;
                } else
@@ -3990,7 +3942,7 @@ brcmf_sdbrcm_watchdog_thread(void *data)
 }
 
 static void
-brcmf_sdbrcm_watchdog(unsigned long data)
+brcmf_sdio_watchdog(unsigned long data)
 {
        struct brcmf_sdio *bus = (struct brcmf_sdio *)data;
 
@@ -4003,14 +3955,14 @@ brcmf_sdbrcm_watchdog(unsigned long data)
        }
 }
 
-static void brcmf_sdbrcm_release_dongle(struct brcmf_sdio *bus)
+static void brcmf_sdio_release_dongle(struct brcmf_sdio *bus)
 {
        brcmf_dbg(TRACE, "Enter\n");
 
        if (bus->ci) {
                sdio_claim_host(bus->sdiodev->func[1]);
-               brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
-               brcmf_sdbrcm_clkctl(bus, CLK_NONE, false);
+               brcmf_sdio_clkctl(bus, CLK_AVAIL, false);
+               brcmf_sdio_clkctl(bus, CLK_NONE, false);
                sdio_release_host(bus->sdiodev->func[1]);
                brcmf_sdio_chip_detach(&bus->ci);
                if (bus->vars && bus->varsz)
@@ -4021,53 +3973,23 @@ static void brcmf_sdbrcm_release_dongle(struct brcmf_sdio *bus)
        brcmf_dbg(TRACE, "Disconnected\n");
 }
 
-/* Detach and free everything */
-static void brcmf_sdbrcm_release(struct brcmf_sdio *bus)
-{
-       brcmf_dbg(TRACE, "Enter\n");
-
-       if (bus) {
-               /* De-register interrupt handler */
-               brcmf_sdio_intr_unregister(bus->sdiodev);
-
-               cancel_work_sync(&bus->datawork);
-               if (bus->brcmf_wq)
-                       destroy_workqueue(bus->brcmf_wq);
-
-               if (bus->sdiodev->bus_if->drvr) {
-                       brcmf_detach(bus->sdiodev->dev);
-                       brcmf_sdbrcm_release_dongle(bus);
-               }
-
-               brcmu_pkt_buf_free_skb(bus->txglom_sgpad);
-               brcmf_sdbrcm_release_malloc(bus);
-               kfree(bus->hdrbuf);
-               kfree(bus);
-       }
-
-       brcmf_dbg(TRACE, "Disconnected\n");
-}
-
 static struct brcmf_bus_ops brcmf_sdio_bus_ops = {
-       .stop = brcmf_sdbrcm_bus_stop,
-       .preinit = brcmf_sdbrcm_bus_preinit,
-       .init = brcmf_sdbrcm_bus_init,
-       .txdata = brcmf_sdbrcm_bus_txdata,
-       .txctl = brcmf_sdbrcm_bus_txctl,
-       .rxctl = brcmf_sdbrcm_bus_rxctl,
-       .gettxq = brcmf_sdbrcm_bus_gettxq,
+       .stop = brcmf_sdio_bus_stop,
+       .preinit = brcmf_sdio_bus_preinit,
+       .init = brcmf_sdio_bus_init,
+       .txdata = brcmf_sdio_bus_txdata,
+       .txctl = brcmf_sdio_bus_txctl,
+       .rxctl = brcmf_sdio_bus_rxctl,
+       .gettxq = brcmf_sdio_bus_gettxq,
 };
 
-void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev)
+struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
 {
        int ret;
        struct brcmf_sdio *bus;
 
        brcmf_dbg(TRACE, "Enter\n");
 
-       /* We make an assumption about address window mappings:
-        * regsva == SI_ENUM_BASE*/
-
        /* Allocate private bus interface state */
        bus = kzalloc(sizeof(struct brcmf_sdio), GFP_ATOMIC);
        if (!bus)
@@ -4101,8 +4023,8 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev)
        }
 
        /* attempt to attach to the dongle */
-       if (!(brcmf_sdbrcm_probe_attach(bus, regsva))) {
-               brcmf_err("brcmf_sdbrcm_probe_attach failed\n");
+       if (!(brcmf_sdio_probe_attach(bus))) {
+               brcmf_err("brcmf_sdio_probe_attach failed\n");
                goto fail;
        }
 
@@ -4114,11 +4036,11 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev)
        /* Set up the watchdog timer */
        init_timer(&bus->timer);
        bus->timer.data = (unsigned long)bus;
-       bus->timer.function = brcmf_sdbrcm_watchdog;
+       bus->timer.function = brcmf_sdio_watchdog;
 
        /* Initialize watchdog thread */
        init_completion(&bus->watchdog_wait);
-       bus->watchdog_tsk = kthread_run(brcmf_sdbrcm_watchdog_thread,
+       bus->watchdog_tsk = kthread_run(brcmf_sdio_watchdog_thread,
                                        bus, "brcmf_watchdog");
        if (IS_ERR(bus->watchdog_tsk)) {
                pr_warn("brcmf_watchdog thread failed to start\n");
@@ -4144,13 +4066,13 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev)
        }
 
        /* Allocate buffers */
-       if (!(brcmf_sdbrcm_probe_malloc(bus))) {
-               brcmf_err("brcmf_sdbrcm_probe_malloc failed\n");
+       if (!(brcmf_sdio_probe_malloc(bus))) {
+               brcmf_err("brcmf_sdio_probe_malloc failed\n");
                goto fail;
        }
 
-       if (!(brcmf_sdbrcm_probe_init(bus))) {
-               brcmf_err("brcmf_sdbrcm_probe_init failed\n");
+       if (!(brcmf_sdio_probe_init(bus))) {
+               brcmf_err("brcmf_sdio_probe_init failed\n");
                goto fail;
        }
 
@@ -4167,24 +4089,38 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev)
        return bus;
 
 fail:
-       brcmf_sdbrcm_release(bus);
+       brcmf_sdio_remove(bus);
        return NULL;
 }
 
-void brcmf_sdbrcm_disconnect(void *ptr)
+/* Detach and free everything */
+void brcmf_sdio_remove(struct brcmf_sdio *bus)
 {
-       struct brcmf_sdio *bus = (struct brcmf_sdio *)ptr;
-
        brcmf_dbg(TRACE, "Enter\n");
 
-       if (bus)
-               brcmf_sdbrcm_release(bus);
+       if (bus) {
+               /* De-register interrupt handler */
+               brcmf_sdiod_intr_unregister(bus->sdiodev);
+
+               cancel_work_sync(&bus->datawork);
+               if (bus->brcmf_wq)
+                       destroy_workqueue(bus->brcmf_wq);
+
+               if (bus->sdiodev->bus_if->drvr) {
+                       brcmf_detach(bus->sdiodev->dev);
+                       brcmf_sdio_release_dongle(bus);
+               }
+
+               brcmu_pkt_buf_free_skb(bus->txglom_sgpad);
+               brcmf_sdio_release_malloc(bus);
+               kfree(bus->hdrbuf);
+               kfree(bus);
+       }
 
        brcmf_dbg(TRACE, "Disconnected\n");
 }
 
-void
-brcmf_sdbrcm_wd_timer(struct brcmf_sdio *bus, uint wdtick)
+void brcmf_sdio_wd_timer(struct brcmf_sdio *bus, uint wdtick)
 {
        /* Totally stop the timer */
        if (!wdtick && bus->wd_timer_valid) {
index b72d3395499a3c1e713af54a4379f86e93ca407a..22adbe311d206df979a592419d7d247280474ec6 100644 (file)
@@ -68,7 +68,7 @@ brcmf_fil_cmd_data_set(struct brcmf_if *ifp, u32 cmd, void *data, u32 len)
 
        brcmf_dbg(FIL, "cmd=%d, len=%d\n", cmd, len);
        brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
-                          min_t(uint, len, MAX_HEX_DUMP_LEN), "data");
+                          min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");
 
        err = brcmf_fil_cmd_data(ifp, cmd, data, len, true);
        mutex_unlock(&ifp->drvr->proto_block);
@@ -86,7 +86,7 @@ brcmf_fil_cmd_data_get(struct brcmf_if *ifp, u32 cmd, void *data, u32 len)
 
        brcmf_dbg(FIL, "cmd=%d, len=%d\n", cmd, len);
        brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
-                          min_t(uint, len, MAX_HEX_DUMP_LEN), "data");
+                          min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");
 
        mutex_unlock(&ifp->drvr->proto_block);
 
@@ -155,7 +155,7 @@ brcmf_fil_iovar_data_set(struct brcmf_if *ifp, char *name, void *data,
 
        brcmf_dbg(FIL, "name=%s, len=%d\n", name, len);
        brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
-                          min_t(uint, len, MAX_HEX_DUMP_LEN), "data");
+                          min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");
 
        buflen = brcmf_create_iovar(name, data, len, drvr->proto_buf,
                                    sizeof(drvr->proto_buf));
@@ -195,7 +195,7 @@ brcmf_fil_iovar_data_get(struct brcmf_if *ifp, char *name, void *data,
 
        brcmf_dbg(FIL, "name=%s, len=%d\n", name, len);
        brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
-                          min_t(uint, len, MAX_HEX_DUMP_LEN), "data");
+                          min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");
 
        mutex_unlock(&drvr->proto_block);
        return err;
@@ -278,7 +278,7 @@ brcmf_fil_bsscfg_data_set(struct brcmf_if *ifp, char *name,
 
        brcmf_dbg(FIL, "bssidx=%d, name=%s, len=%d\n", ifp->bssidx, name, len);
        brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
-                          min_t(uint, len, MAX_HEX_DUMP_LEN), "data");
+                          min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");
 
        buflen = brcmf_create_bsscfg(ifp->bssidx, name, data, len,
                                     drvr->proto_buf, sizeof(drvr->proto_buf));
@@ -317,7 +317,7 @@ brcmf_fil_bsscfg_data_get(struct brcmf_if *ifp, char *name,
        }
        brcmf_dbg(FIL, "bssidx=%d, name=%s, len=%d\n", ifp->bssidx, name, len);
        brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
-                          min_t(uint, len, MAX_HEX_DUMP_LEN), "data");
+                          min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");
 
        mutex_unlock(&drvr->proto_block);
        return err;
index e9bdfdb95d8f06915fc734dd27053a3e092c046e..7918c10336622bf7fb005dbcfb5cbc85918b2b9a 100644 (file)
@@ -838,7 +838,7 @@ static void brcmf_fws_cleanup(struct brcmf_fws_info *fws, int ifidx)
        brcmf_fws_hanger_cleanup(fws, matchfn, ifidx);
 }
 
-static int brcmf_fws_hdrpush(struct brcmf_fws_info *fws, struct sk_buff *skb)
+static u8 brcmf_fws_hdrpush(struct brcmf_fws_info *fws, struct sk_buff *skb)
 {
        struct brcmf_fws_mac_descriptor *entry = brcmf_skbcb(skb)->mac;
        u8 *wlh;
@@ -887,9 +887,7 @@ static int brcmf_fws_hdrpush(struct brcmf_fws_info *fws, struct sk_buff *skb)
        if (fillers)
                memset(wlh, BRCMF_FWS_TYPE_FILLER, fillers);
 
-       brcmf_proto_hdrpush(fws->drvr, brcmf_skb_if_flags_get_field(skb, INDEX),
-                           data_offset >> 2, skb);
-       return 0;
+       return (u8)(data_offset >> 2);
 }
 
 static bool brcmf_fws_tim_update(struct brcmf_fws_info *fws,
@@ -897,10 +895,11 @@ static bool brcmf_fws_tim_update(struct brcmf_fws_info *fws,
                                 int fifo, bool send_immediately)
 {
        struct sk_buff *skb;
-       struct brcmf_bus *bus;
        struct brcmf_skbuff_cb *skcb;
        s32 err;
        u32 len;
+       u8 data_offset;
+       int ifidx;
 
        /* check delayedQ and suppressQ in one call using bitmap */
        if (brcmu_pktq_mlen(&entry->psq, 3 << (fifo * 2)) == 0)
@@ -928,13 +927,11 @@ static bool brcmf_fws_tim_update(struct brcmf_fws_info *fws,
                skcb->state = BRCMF_FWS_SKBSTATE_TIM;
                skcb->htod = 0;
                skcb->htod_seq = 0;
-               bus = fws->drvr->bus_if;
-               err = brcmf_fws_hdrpush(fws, skb);
-               if (err == 0) {
-                       brcmf_fws_unlock(fws);
-                       err = brcmf_bus_txdata(bus, skb);
-                       brcmf_fws_lock(fws);
-               }
+               data_offset = brcmf_fws_hdrpush(fws, skb);
+               ifidx = brcmf_skb_if_flags_get_field(skb, INDEX);
+               brcmf_fws_unlock(fws);
+               err = brcmf_proto_txdata(fws->drvr, ifidx, data_offset, skb);
+               brcmf_fws_lock(fws);
                if (err)
                        brcmu_pkt_buf_free_skb(skb);
                return true;
@@ -1393,7 +1390,7 @@ static int brcmf_fws_txstatus_suppressed(struct brcmf_fws_info *fws, int fifo,
        entry->generation = genbit;
 
        ret = brcmf_proto_hdrpull(fws->drvr, false, &ifidx, skb);
-       if (ret == 0)
+       if (ret == 0) {
                brcmf_skb_htod_tag_set_field(skb, GENERATION, genbit);
                brcmf_skbcb(skb)->htod_seq = seq;
                if (brcmf_skb_htod_seq_get_field(skb, FROMFW)) {
@@ -1404,6 +1401,8 @@ static int brcmf_fws_txstatus_suppressed(struct brcmf_fws_info *fws, int fifo,
                }
                ret = brcmf_fws_enq(fws, BRCMF_FWS_SKBSTATE_SUPPRESSED, fifo,
                                    skb);
+       }
+
        if (ret != 0) {
                /* suppress q is full or hdrpull failed, drop this packet */
                brcmf_fws_hanger_poppkt(&fws->hanger, hslot, &skb,
@@ -1717,7 +1716,7 @@ int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len,
        return 0;
 }
 
-static void brcmf_fws_precommit_skb(struct brcmf_fws_info *fws, int fifo,
+static u8 brcmf_fws_precommit_skb(struct brcmf_fws_info *fws, int fifo,
                                   struct sk_buff *p)
 {
        struct brcmf_skbuff_cb *skcb = brcmf_skbcb(p);
@@ -1735,7 +1734,7 @@ static void brcmf_fws_precommit_skb(struct brcmf_fws_info *fws, int fifo,
                flags |= BRCMF_FWS_HTOD_FLAG_PKT_REQUESTED;
        }
        brcmf_skb_htod_tag_set_field(p, FLAGS, flags);
-       brcmf_fws_hdrpush(fws, p);
+       return brcmf_fws_hdrpush(fws, p);
 }
 
 static void brcmf_fws_rollback_toq(struct brcmf_fws_info *fws,
@@ -1803,20 +1802,21 @@ static int brcmf_fws_commit_skb(struct brcmf_fws_info *fws, int fifo,
 {
        struct brcmf_skbuff_cb *skcb = brcmf_skbcb(skb);
        struct brcmf_fws_mac_descriptor *entry;
-       struct brcmf_bus *bus = fws->drvr->bus_if;
        int rc;
        u8 ifidx;
+       u8 data_offset;
 
        entry = skcb->mac;
        if (IS_ERR(entry))
                return PTR_ERR(entry);
 
-       brcmf_fws_precommit_skb(fws, fifo, skb);
+       data_offset = brcmf_fws_precommit_skb(fws, fifo, skb);
        entry->transit_count++;
        if (entry->suppressed)
                entry->suppr_transit_count++;
+       ifidx = brcmf_skb_if_flags_get_field(skb, INDEX);
        brcmf_fws_unlock(fws);
-       rc = brcmf_bus_txdata(bus, skb);
+       rc = brcmf_proto_txdata(fws->drvr, ifidx, data_offset, skb);
        brcmf_fws_lock(fws);
        brcmf_dbg(DATA, "%s flags %X htod %X bus_tx %d\n", entry->name,
                  skcb->if_flags, skcb->htod, rc);
@@ -1977,10 +1977,9 @@ static void brcmf_fws_dequeue_worker(struct work_struct *worker)
                                                        &skb, true);
                                ifidx = brcmf_skb_if_flags_get_field(skb,
                                                                     INDEX);
-                               brcmf_proto_hdrpush(drvr, ifidx, 0, skb);
-                               /* Use bus module to send data frame */
+                               /* Use proto layer to send data frame */
                                brcmf_fws_unlock(fws);
-                               ret = brcmf_bus_txdata(drvr->bus_if, skb);
+                               ret = brcmf_proto_txdata(drvr, ifidx, 0, skb);
                                brcmf_fws_lock(fws);
                                if (ret < 0)
                                        brcmf_txfinalize(drvr, skb, false);
index 87eb2bd4c072077d8b234cd1b17abcdd54142aa2..b6b4641849463a9e383946c8a482072de9cd21fe 100644 (file)
@@ -39,7 +39,7 @@ int brcmf_proto_attach(struct brcmf_pub *drvr)
        if (brcmf_proto_bcdc_attach(drvr))
                goto fail;
 
-       if ((proto->hdrpush == NULL) || (proto->hdrpull == NULL) ||
+       if ((proto->txdata == NULL) || (proto->hdrpull == NULL) ||
            (proto->query_dcmd == NULL) || (proto->set_dcmd == NULL)) {
                brcmf_err("Not all proto handlers have been installed\n");
                goto fail;
index 8de1b3bce228fbd61906bc201289eb855b434fc0..482fb0ba4a30f3b8afd7958fd65a1b485344014a 100644 (file)
 #define BRCMFMAC_PROTO_H
 
 struct brcmf_proto {
-       void (*hdrpush)(struct brcmf_pub *drvr, int ifidx, u8 offset,
-                       struct sk_buff *skb);
        int (*hdrpull)(struct brcmf_pub *drvr, bool do_fws, u8 *ifidx,
                       struct sk_buff *skb);
        int (*query_dcmd)(struct brcmf_pub *drvr, int ifidx, uint cmd,
                          void *buf, uint len);
        int (*set_dcmd)(struct brcmf_pub *drvr, int ifidx, uint cmd, void *buf,
                        uint len);
+       int (*txdata)(struct brcmf_pub *drvr, int ifidx, u8 offset,
+                     struct sk_buff *skb);
        void *pd;
 };
 
@@ -32,11 +32,6 @@ struct brcmf_proto {
 int brcmf_proto_attach(struct brcmf_pub *drvr);
 void brcmf_proto_detach(struct brcmf_pub *drvr);
 
-static inline void brcmf_proto_hdrpush(struct brcmf_pub *drvr, int ifidx,
-                                      u8 offset, struct sk_buff *skb)
-{
-       drvr->proto->hdrpush(drvr, ifidx, offset, skb);
-}
 static inline int brcmf_proto_hdrpull(struct brcmf_pub *drvr, bool do_fws,
                                      u8 *ifidx, struct sk_buff *skb)
 {
@@ -52,6 +47,11 @@ static inline int brcmf_proto_set_dcmd(struct brcmf_pub *drvr, int ifidx,
 {
        return drvr->proto->set_dcmd(drvr, ifidx, cmd, buf, len);
 }
+static inline int brcmf_proto_txdata(struct brcmf_pub *drvr, int ifidx,
+                                      u8 offset, struct sk_buff *skb)
+{
+       return drvr->proto->txdata(drvr, ifidx, offset, skb);
+}
 
 
 #endif /* BRCMFMAC_PROTO_H */
index 2096a14ef1fba5fcaf156140a64b2f52f4b67757..5f39f28e6efbe2c2e8bb7b84868a78e6ba024918 100644 (file)
@@ -112,9 +112,9 @@ brcmf_sdio_sb_corerev(struct brcmf_sdio_dev *sdiodev,
 
        idx = brcmf_sdio_chip_getinfidx(ci, coreid);
 
-       regdata = brcmf_sdio_regrl(sdiodev,
-                                  CORE_SB(ci->c_inf[idx].base, sbidhigh),
-                                  NULL);
+       regdata = brcmf_sdiod_regrl(sdiodev,
+                                   CORE_SB(ci->c_inf[idx].base, sbidhigh),
+                                   NULL);
        return SBCOREREV(regdata);
 }
 
@@ -140,9 +140,9 @@ brcmf_sdio_sb_iscoreup(struct brcmf_sdio_dev *sdiodev,
        if (idx == BRCMF_MAX_CORENUM)
                return false;
 
-       regdata = brcmf_sdio_regrl(sdiodev,
-                                  CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
-                                  NULL);
+       regdata = brcmf_sdiod_regrl(sdiodev,
+                                   CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
+                                   NULL);
        regdata &= (SSB_TMSLOW_RESET | SSB_TMSLOW_REJECT |
                    SSB_IMSTATE_REJECT | SSB_TMSLOW_CLOCK);
        return (SSB_TMSLOW_CLOCK == regdata);
@@ -160,13 +160,13 @@ brcmf_sdio_ai_iscoreup(struct brcmf_sdio_dev *sdiodev,
        if (idx == BRCMF_MAX_CORENUM)
                return false;
 
-       regdata = brcmf_sdio_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
-                                  NULL);
+       regdata = brcmf_sdiod_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
+                                   NULL);
        ret = (regdata & (BCMA_IOCTL_FGC | BCMA_IOCTL_CLK)) == BCMA_IOCTL_CLK;
 
-       regdata = brcmf_sdio_regrl(sdiodev,
-                                  ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
-                                  NULL);
+       regdata = brcmf_sdiod_regrl(sdiodev,
+                                   ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
+                                   NULL);
        ret = ret && ((regdata & BCMA_RESET_CTL_RESET) == 0);
 
        return ret;
@@ -182,79 +182,79 @@ brcmf_sdio_sb_coredisable(struct brcmf_sdio_dev *sdiodev,
        idx = brcmf_sdio_chip_getinfidx(ci, coreid);
        base = ci->c_inf[idx].base;
 
-       regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbtmstatelow), NULL);
+       regdata = brcmf_sdiod_regrl(sdiodev, CORE_SB(base, sbtmstatelow), NULL);
        if (regdata & SSB_TMSLOW_RESET)
                return;
 
-       regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbtmstatelow), NULL);
+       regdata = brcmf_sdiod_regrl(sdiodev, CORE_SB(base, sbtmstatelow), NULL);
        if ((regdata & SSB_TMSLOW_CLOCK) != 0) {
                /*
                 * set target reject and spin until busy is clear
                 * (preserve core-specific bits)
                 */
-               regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbtmstatelow),
-                                          NULL);
-               brcmf_sdio_regwl(sdiodev, CORE_SB(base, sbtmstatelow),
-                                regdata | SSB_TMSLOW_REJECT, NULL);
+               regdata = brcmf_sdiod_regrl(sdiodev,
+                                           CORE_SB(base, sbtmstatelow), NULL);
+               brcmf_sdiod_regwl(sdiodev, CORE_SB(base, sbtmstatelow),
+                                 regdata | SSB_TMSLOW_REJECT, NULL);
 
-               regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbtmstatelow),
-                                          NULL);
+               regdata = brcmf_sdiod_regrl(sdiodev,
+                                           CORE_SB(base, sbtmstatelow), NULL);
                udelay(1);
-               SPINWAIT((brcmf_sdio_regrl(sdiodev,
-                                          CORE_SB(base, sbtmstatehigh),
-                                          NULL) &
-                       SSB_TMSHIGH_BUSY), 100000);
-
-               regdata = brcmf_sdio_regrl(sdiodev,
-                                          CORE_SB(base, sbtmstatehigh),
-                                          NULL);
+               SPINWAIT((brcmf_sdiod_regrl(sdiodev,
+                                           CORE_SB(base, sbtmstatehigh),
+                                           NULL) &
+                         SSB_TMSHIGH_BUSY), 100000);
+
+               regdata = brcmf_sdiod_regrl(sdiodev,
+                                           CORE_SB(base, sbtmstatehigh),
+                                           NULL);
                if (regdata & SSB_TMSHIGH_BUSY)
                        brcmf_err("core state still busy\n");
 
-               regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbidlow),
-                                          NULL);
+               regdata = brcmf_sdiod_regrl(sdiodev, CORE_SB(base, sbidlow),
+                                           NULL);
                if (regdata & SSB_IDLOW_INITIATOR) {
-                       regdata = brcmf_sdio_regrl(sdiodev,
-                                                  CORE_SB(base, sbimstate),
-                                                  NULL);
+                       regdata = brcmf_sdiod_regrl(sdiodev,
+                                                   CORE_SB(base, sbimstate),
+                                                   NULL);
                        regdata |= SSB_IMSTATE_REJECT;
-                       brcmf_sdio_regwl(sdiodev, CORE_SB(base, sbimstate),
-                                        regdata, NULL);
-                       regdata = brcmf_sdio_regrl(sdiodev,
-                                                  CORE_SB(base, sbimstate),
-                                                  NULL);
+                       brcmf_sdiod_regwl(sdiodev, CORE_SB(base, sbimstate),
+                                         regdata, NULL);
+                       regdata = brcmf_sdiod_regrl(sdiodev,
+                                                   CORE_SB(base, sbimstate),
+                                                   NULL);
                        udelay(1);
-                       SPINWAIT((brcmf_sdio_regrl(sdiodev,
-                                                  CORE_SB(base, sbimstate),
-                                                  NULL) &
-                               SSB_IMSTATE_BUSY), 100000);
+                       SPINWAIT((brcmf_sdiod_regrl(sdiodev,
+                                                   CORE_SB(base, sbimstate),
+                                                   NULL) &
+                                 SSB_IMSTATE_BUSY), 100000);
                }
 
                /* set reset and reject while enabling the clocks */
                regdata = SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK |
                          SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET;
-               brcmf_sdio_regwl(sdiodev, CORE_SB(base, sbtmstatelow),
-                                regdata, NULL);
-               regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbtmstatelow),
-                                          NULL);
+               brcmf_sdiod_regwl(sdiodev, CORE_SB(base, sbtmstatelow),
+                                 regdata, NULL);
+               regdata = brcmf_sdiod_regrl(sdiodev,
+                                           CORE_SB(base, sbtmstatelow), NULL);
                udelay(10);
 
                /* clear the initiator reject bit */
-               regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbidlow),
-                                          NULL);
+               regdata = brcmf_sdiod_regrl(sdiodev, CORE_SB(base, sbidlow),
+                                           NULL);
                if (regdata & SSB_IDLOW_INITIATOR) {
-                       regdata = brcmf_sdio_regrl(sdiodev,
-                                                  CORE_SB(base, sbimstate),
-                                                  NULL);
+                       regdata = brcmf_sdiod_regrl(sdiodev,
+                                                   CORE_SB(base, sbimstate),
+                                                   NULL);
                        regdata &= ~SSB_IMSTATE_REJECT;
-                       brcmf_sdio_regwl(sdiodev, CORE_SB(base, sbimstate),
-                                        regdata, NULL);
+                       brcmf_sdiod_regwl(sdiodev, CORE_SB(base, sbimstate),
+                                         regdata, NULL);
                }
        }
 
        /* leave reset and reject asserted */
-       brcmf_sdio_regwl(sdiodev, CORE_SB(base, sbtmstatelow),
-                        (SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET), NULL);
+       brcmf_sdiod_regwl(sdiodev, CORE_SB(base, sbtmstatelow),
+                         (SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET), NULL);
        udelay(1);
 }
 
@@ -270,9 +270,9 @@ brcmf_sdio_ai_coredisable(struct brcmf_sdio_dev *sdiodev,
                return;
 
        /* if core is already in reset, just return */
-       regdata = brcmf_sdio_regrl(sdiodev,
-                                  ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
-                                  NULL);
+       regdata = brcmf_sdiod_regrl(sdiodev,
+                                   ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
+                                   NULL);
        if ((regdata & BCMA_RESET_CTL_RESET) != 0)
                return;
 
@@ -281,24 +281,24 @@ brcmf_sdio_ai_coredisable(struct brcmf_sdio_dev *sdiodev,
         * extra 10ms is taken into account for firmware load stage
         * after 10300us carry on disabling the core anyway
         */
-       SPINWAIT(brcmf_sdio_regrl(sdiodev,
-                                 ci->c_inf[idx].wrapbase+BCMA_RESET_ST,
-                                 NULL), 10300);
-       regdata = brcmf_sdio_regrl(sdiodev,
+       SPINWAIT(brcmf_sdiod_regrl(sdiodev,
                                   ci->c_inf[idx].wrapbase+BCMA_RESET_ST,
-                                  NULL);
+                                  NULL), 10300);
+       regdata = brcmf_sdiod_regrl(sdiodev,
+                                   ci->c_inf[idx].wrapbase+BCMA_RESET_ST,
+                                   NULL);
        if (regdata)
                brcmf_err("disabling core 0x%x with reset status %x\n",
                          coreid, regdata);
 
-       brcmf_sdio_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
-                        BCMA_RESET_CTL_RESET, NULL);
+       brcmf_sdiod_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
+                         BCMA_RESET_CTL_RESET, NULL);
        udelay(1);
 
-       brcmf_sdio_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
-                        core_bits, NULL);
-       regdata = brcmf_sdio_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
-                                  NULL);
+       brcmf_sdiod_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
+                         core_bits, NULL);
+       regdata = brcmf_sdiod_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
+                                   NULL);
        usleep_range(10, 20);
 
 }
@@ -325,47 +325,47 @@ brcmf_sdio_sb_resetcore(struct brcmf_sdio_dev *sdiodev,
         * set reset while enabling the clock and
         * forcing them on throughout the core
         */
-       brcmf_sdio_regwl(sdiodev,
-                        CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
-                        SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK | SSB_TMSLOW_RESET,
-                        NULL);
-       regdata = brcmf_sdio_regrl(sdiodev,
-                                  CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
-                                  NULL);
+       brcmf_sdiod_regwl(sdiodev,
+                         CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
+                         SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK | SSB_TMSLOW_RESET,
+                         NULL);
+       regdata = brcmf_sdiod_regrl(sdiodev,
+                                   CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
+                                   NULL);
        udelay(1);
 
        /* clear any serror */
-       regdata = brcmf_sdio_regrl(sdiodev,
-                                  CORE_SB(ci->c_inf[idx].base, sbtmstatehigh),
-                                  NULL);
+       regdata = brcmf_sdiod_regrl(sdiodev,
+                                   CORE_SB(ci->c_inf[idx].base, sbtmstatehigh),
+                                   NULL);
        if (regdata & SSB_TMSHIGH_SERR)
-               brcmf_sdio_regwl(sdiodev,
-                                CORE_SB(ci->c_inf[idx].base, sbtmstatehigh),
-                                0, NULL);
+               brcmf_sdiod_regwl(sdiodev,
+                                 CORE_SB(ci->c_inf[idx].base, sbtmstatehigh),
+                                 0, NULL);
 
-       regdata = brcmf_sdio_regrl(sdiodev,
-                                  CORE_SB(ci->c_inf[idx].base, sbimstate),
-                                  NULL);
+       regdata = brcmf_sdiod_regrl(sdiodev,
+                                   CORE_SB(ci->c_inf[idx].base, sbimstate),
+                                   NULL);
        if (regdata & (SSB_IMSTATE_IBE | SSB_IMSTATE_TO))
-               brcmf_sdio_regwl(sdiodev,
-                                CORE_SB(ci->c_inf[idx].base, sbimstate),
-                                regdata & ~(SSB_IMSTATE_IBE | SSB_IMSTATE_TO),
-                                NULL);
+               brcmf_sdiod_regwl(sdiodev,
+                                 CORE_SB(ci->c_inf[idx].base, sbimstate),
+                                 regdata & ~(SSB_IMSTATE_IBE | SSB_IMSTATE_TO),
+                                 NULL);
 
        /* clear reset and allow it to propagate throughout the core */
-       brcmf_sdio_regwl(sdiodev, CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
-                        SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK, NULL);
-       regdata = brcmf_sdio_regrl(sdiodev,
-                                  CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
-                                  NULL);
+       brcmf_sdiod_regwl(sdiodev, CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
+                         SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK, NULL);
+       regdata = brcmf_sdiod_regrl(sdiodev,
+                                   CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
+                                   NULL);
        udelay(1);
 
        /* leave clock enabled */
-       brcmf_sdio_regwl(sdiodev, CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
-                        SSB_TMSLOW_CLOCK, NULL);
-       regdata = brcmf_sdio_regrl(sdiodev,
-                                  CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
-                                  NULL);
+       brcmf_sdiod_regwl(sdiodev, CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
+                         SSB_TMSLOW_CLOCK, NULL);
+       regdata = brcmf_sdiod_regrl(sdiodev,
+                                   CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
+                                   NULL);
        udelay(1);
 }
 
@@ -384,21 +384,21 @@ brcmf_sdio_ai_resetcore(struct brcmf_sdio_dev *sdiodev,
        brcmf_sdio_ai_coredisable(sdiodev, ci, coreid, core_bits);
 
        /* now do initialization sequence */
-       brcmf_sdio_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
-                        core_bits | BCMA_IOCTL_FGC | BCMA_IOCTL_CLK, NULL);
-       regdata = brcmf_sdio_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
-                                  NULL);
-       brcmf_sdio_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
-                        0, NULL);
-       regdata = brcmf_sdio_regrl(sdiodev,
-                                  ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
-                                  NULL);
+       brcmf_sdiod_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
+                         core_bits | BCMA_IOCTL_FGC | BCMA_IOCTL_CLK, NULL);
+       regdata = brcmf_sdiod_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
+                                   NULL);
+       brcmf_sdiod_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
+                         0, NULL);
+       regdata = brcmf_sdiod_regrl(sdiodev,
+                                   ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
+                                   NULL);
        udelay(1);
 
-       brcmf_sdio_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
-                        core_bits | BCMA_IOCTL_CLK, NULL);
-       regdata = brcmf_sdio_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
-                                  NULL);
+       brcmf_sdiod_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
+                         core_bits | BCMA_IOCTL_CLK, NULL);
+       regdata = brcmf_sdiod_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
+                                   NULL);
        udelay(1);
 }
 
@@ -438,7 +438,7 @@ static inline int brcmf_sdio_chip_cichk(struct chip_info *ci)
 #endif
 
 static int brcmf_sdio_chip_recognition(struct brcmf_sdio_dev *sdiodev,
-                                      struct chip_info *ci, u32 regs)
+                                      struct chip_info *ci)
 {
        u32 regdata;
        int ret;
@@ -449,10 +449,10 @@ static int brcmf_sdio_chip_recognition(struct brcmf_sdio_dev *sdiodev,
         * other ways of recognition should be added here.
         */
        ci->c_inf[0].id = BCMA_CORE_CHIPCOMMON;
-       ci->c_inf[0].base = regs;
-       regdata = brcmf_sdio_regrl(sdiodev,
-                                  CORE_CC_REG(ci->c_inf[0].base, chipid),
-                                  NULL);
+       ci->c_inf[0].base = SI_ENUM_BASE;
+       regdata = brcmf_sdiod_regrl(sdiodev,
+                                   CORE_CC_REG(ci->c_inf[0].base, chipid),
+                                   NULL);
        ci->chip = regdata & CID_ID_MASK;
        ci->chiprev = (regdata & CID_REV_MASK) >> CID_REV_SHIFT;
        if (sdiodev->func[0]->device == SDIO_DEVICE_ID_BROADCOM_4335_4339 &&
@@ -607,7 +607,7 @@ brcmf_sdio_chip_buscoreprep(struct brcmf_sdio_dev *sdiodev)
 
        /* Try forcing SDIO core to do ALPAvail request only */
        clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ;
-       brcmf_sdio_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
+       brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
        if (err) {
                brcmf_err("error writing for HT off\n");
                return err;
@@ -615,8 +615,8 @@ brcmf_sdio_chip_buscoreprep(struct brcmf_sdio_dev *sdiodev)
 
        /* If register supported, wait for ALPAvail and then force ALP */
        /* This may take up to 15 milliseconds */
-       clkval = brcmf_sdio_regrb(sdiodev,
-                                 SBSDIO_FUNC1_CHIPCLKCSR, NULL);
+       clkval = brcmf_sdiod_regrb(sdiodev,
+                                  SBSDIO_FUNC1_CHIPCLKCSR, NULL);
 
        if ((clkval & ~SBSDIO_AVBITS) != clkset) {
                brcmf_err("ChipClkCSR access: wrote 0x%02x read 0x%02x\n",
@@ -624,8 +624,8 @@ brcmf_sdio_chip_buscoreprep(struct brcmf_sdio_dev *sdiodev)
                return -EACCES;
        }
 
-       SPINWAIT(((clkval = brcmf_sdio_regrb(sdiodev,
-                                            SBSDIO_FUNC1_CHIPCLKCSR, NULL)),
+       SPINWAIT(((clkval = brcmf_sdiod_regrb(sdiodev,
+                                             SBSDIO_FUNC1_CHIPCLKCSR, NULL)),
                        !SBSDIO_ALPAV(clkval)),
                        PMU_MAX_TRANSITION_DLY);
        if (!SBSDIO_ALPAV(clkval)) {
@@ -635,11 +635,11 @@ brcmf_sdio_chip_buscoreprep(struct brcmf_sdio_dev *sdiodev)
        }
 
        clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP;
-       brcmf_sdio_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
+       brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
        udelay(65);
 
        /* Also, disable the extra SDIO pull-ups */
-       brcmf_sdio_regwb(sdiodev, SBSDIO_FUNC1_SDIOPULLUP, 0, NULL);
+       brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_SDIOPULLUP, 0, NULL);
 
        return 0;
 }
@@ -654,16 +654,16 @@ brcmf_sdio_chip_buscoresetup(struct brcmf_sdio_dev *sdiodev,
        ci->c_inf[0].rev = ci->corerev(sdiodev, ci, ci->c_inf[0].id);
 
        /* get chipcommon capabilites */
-       ci->c_inf[0].caps = brcmf_sdio_regrl(sdiodev,
-                                            CORE_CC_REG(base, capabilities),
-                                            NULL);
+       ci->c_inf[0].caps = brcmf_sdiod_regrl(sdiodev,
+                                             CORE_CC_REG(base, capabilities),
+                                             NULL);
 
        /* get pmu caps & rev */
        if (ci->c_inf[0].caps & CC_CAP_PMU) {
                ci->pmucaps =
-                       brcmf_sdio_regrl(sdiodev,
-                                        CORE_CC_REG(base, pmucapabilities),
-                                        NULL);
+                       brcmf_sdiod_regrl(sdiodev,
+                                         CORE_CC_REG(base, pmucapabilities),
+                                         NULL);
                ci->pmurev = ci->pmucaps & PCAP_REV_MASK;
        }
 
@@ -681,7 +681,7 @@ brcmf_sdio_chip_buscoresetup(struct brcmf_sdio_dev *sdiodev,
 }
 
 int brcmf_sdio_chip_attach(struct brcmf_sdio_dev *sdiodev,
-                          struct chip_info **ci_ptr, u32 regs)
+                          struct chip_info **ci_ptr)
 {
        int ret;
        struct chip_info *ci;
@@ -697,16 +697,16 @@ int brcmf_sdio_chip_attach(struct brcmf_sdio_dev *sdiodev,
        if (ret != 0)
                goto err;
 
-       ret = brcmf_sdio_chip_recognition(sdiodev, ci, regs);
+       ret = brcmf_sdio_chip_recognition(sdiodev, ci);
        if (ret != 0)
                goto err;
 
        brcmf_sdio_chip_buscoresetup(sdiodev, ci);
 
-       brcmf_sdio_regwl(sdiodev, CORE_CC_REG(ci->c_inf[0].base, gpiopullup),
-                        0, NULL);
-       brcmf_sdio_regwl(sdiodev, CORE_CC_REG(ci->c_inf[0].base, gpiopulldown),
-                        0, NULL);
+       brcmf_sdiod_regwl(sdiodev, CORE_CC_REG(ci->c_inf[0].base, gpiopullup),
+                         0, NULL);
+       brcmf_sdiod_regwl(sdiodev, CORE_CC_REG(ci->c_inf[0].base, gpiopulldown),
+                         0, NULL);
 
        *ci_ptr = ci;
        return 0;
@@ -784,12 +784,12 @@ brcmf_sdio_chip_drivestrengthinit(struct brcmf_sdio_dev *sdiodev,
                        }
                }
                addr = CORE_CC_REG(base, chipcontrol_addr);
-               brcmf_sdio_regwl(sdiodev, addr, 1, NULL);
-               cc_data_temp = brcmf_sdio_regrl(sdiodev, addr, NULL);
+               brcmf_sdiod_regwl(sdiodev, addr, 1, NULL);
+               cc_data_temp = brcmf_sdiod_regrl(sdiodev, addr, NULL);
                cc_data_temp &= ~str_mask;
                drivestrength_sel <<= str_shift;
                cc_data_temp |= drivestrength_sel;
-               brcmf_sdio_regwl(sdiodev, addr, cc_data_temp, NULL);
+               brcmf_sdiod_regwl(sdiodev, addr, cc_data_temp, NULL);
 
                brcmf_dbg(INFO, "SDIO: %d mA (req=%d mA) drive strength selected, set to 0x%08x\n",
                          str_tab[i].strength, drivestrength, cc_data_temp);
@@ -816,8 +816,8 @@ brcmf_sdio_chip_verifynvram(struct brcmf_sdio_dev *sdiodev, u32 nvram_addr,
        memset(nvram_ularray, 0xaa, nvram_sz);
 
        /* Read the vars list to temp buffer for comparison */
-       err = brcmf_sdio_ramrw(sdiodev, false, nvram_addr, nvram_ularray,
-                              nvram_sz);
+       err = brcmf_sdiod_ramrw(sdiodev, false, nvram_addr, nvram_ularray,
+                               nvram_sz);
        if (err) {
                brcmf_err("error %d on reading %d nvram bytes at 0x%08x\n",
                          err, nvram_sz, nvram_addr);
@@ -850,7 +850,7 @@ static bool brcmf_sdio_chip_writenvram(struct brcmf_sdio_dev *sdiodev,
        nvram_addr = (ci->ramsize - 4) - nvram_sz + ci->rambase;
 
        /* Write the vars list */
-       err = brcmf_sdio_ramrw(sdiodev, true, nvram_addr, nvram_dat, nvram_sz);
+       err = brcmf_sdiod_ramrw(sdiodev, true, nvram_addr, nvram_dat, nvram_sz);
        if (err) {
                brcmf_err("error %d on writing %d nvram bytes at 0x%08x\n",
                          err, nvram_sz, nvram_addr);
@@ -874,8 +874,8 @@ static bool brcmf_sdio_chip_writenvram(struct brcmf_sdio_dev *sdiodev,
                  nvram_addr, nvram_sz, token);
 
        /* Write the length token to the last word */
-       if (brcmf_sdio_ramrw(sdiodev, true, (ci->ramsize - 4 + ci->rambase),
-                            (u8 *)&token_le, 4))
+       if (brcmf_sdiod_ramrw(sdiodev, true, (ci->ramsize - 4 + ci->rambase),
+                             (u8 *)&token_le, 4))
                return false;
 
        return true;
@@ -891,7 +891,7 @@ brcmf_sdio_chip_cm3_enterdl(struct brcmf_sdio_dev *sdiodev,
        ci->resetcore(sdiodev, ci, BCMA_CORE_INTERNAL_MEM, 0);
 
        /* clear length token */
-       brcmf_sdio_ramrw(sdiodev, true, ci->ramsize - 4, (u8 *)&zeros, 4);
+       brcmf_sdiod_ramrw(sdiodev, true, ci->ramsize - 4, (u8 *)&zeros, 4);
 }
 
 static bool
@@ -913,7 +913,7 @@ brcmf_sdio_chip_cm3_exitdl(struct brcmf_sdio_dev *sdiodev, struct chip_info *ci,
        core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_SDIO_DEV);
        reg_addr = ci->c_inf[core_idx].base;
        reg_addr += offsetof(struct sdpcmd_regs, intstatus);
-       brcmf_sdio_regwl(sdiodev, reg_addr, 0xFFFFFFFF, NULL);
+       brcmf_sdiod_regwl(sdiodev, reg_addr, 0xFFFFFFFF, NULL);
 
        ci->resetcore(sdiodev, ci, BCMA_CORE_ARM_CM3, 0);
 
@@ -942,11 +942,11 @@ brcmf_sdio_chip_cr4_exitdl(struct brcmf_sdio_dev *sdiodev, struct chip_info *ci,
        core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_SDIO_DEV);
        reg_addr = ci->c_inf[core_idx].base;
        reg_addr += offsetof(struct sdpcmd_regs, intstatus);
-       brcmf_sdio_regwl(sdiodev, reg_addr, 0xFFFFFFFF, NULL);
+       brcmf_sdiod_regwl(sdiodev, reg_addr, 0xFFFFFFFF, NULL);
 
        /* Write reset vector to address 0 */
-       brcmf_sdio_ramrw(sdiodev, true, 0, (void *)&ci->rst_vec,
-                        sizeof(ci->rst_vec));
+       brcmf_sdiod_ramrw(sdiodev, true, 0, (void *)&ci->rst_vec,
+                         sizeof(ci->rst_vec));
 
        /* restore ARM */
        ci->resetcore(sdiodev, ci, BCMA_CORE_ARM_CR4, 0);
index 507c61c991fa06c96b6adb1a0f99acefa5f74068..d0f4b45b24c740f282961697951998038607ddd7 100644 (file)
@@ -224,7 +224,7 @@ struct sdpcmd_regs {
 };
 
 int brcmf_sdio_chip_attach(struct brcmf_sdio_dev *sdiodev,
-                          struct chip_info **ci_ptr, u32 regs);
+                          struct chip_info **ci_ptr);
 void brcmf_sdio_chip_detach(struct chip_info **ci_ptr);
 void brcmf_sdio_chip_drivestrengthinit(struct brcmf_sdio_dev *sdiodev,
                                       struct chip_info *ci, u32 drivestrength);
index fc0d4f0129db269dd7d7139c286fa90063c3bab3..a0981b32c729d14c98d80487c36d1b6d8e9a29c6 100644 (file)
@@ -164,9 +164,8 @@ struct brcmf_sdio;
 struct brcmf_sdio_dev {
        struct sdio_func *func[SDIO_MAX_FUNCS];
        u8 num_funcs;                   /* Supported funcs on client */
-       u32 func_cis_ptr[SDIOD_MAX_IOFUNCS];
        u32 sbwad;                      /* Save backplane window address */
-       void *bus;
+       struct brcmf_sdio *bus;
        atomic_t suspend;               /* suspend flag */
        wait_queue_head_t request_byte_wait;
        wait_queue_head_t request_word_wait;
@@ -185,22 +184,19 @@ struct brcmf_sdio_dev {
 };
 
 /* Register/deregister interrupt handler. */
-int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev);
-int brcmf_sdio_intr_unregister(struct brcmf_sdio_dev *sdiodev);
+int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev);
+int brcmf_sdiod_intr_unregister(struct brcmf_sdio_dev *sdiodev);
 
 /* sdio device register access interface */
-u8 brcmf_sdio_regrb(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret);
-u32 brcmf_sdio_regrl(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret);
-void brcmf_sdio_regwb(struct brcmf_sdio_dev *sdiodev, u32 addr, u8 data,
-                     int *ret);
-void brcmf_sdio_regwl(struct brcmf_sdio_dev *sdiodev, u32 addr, u32 data,
-                     int *ret);
-int brcmf_sdio_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr,
-                           void *data, bool write);
+u8 brcmf_sdiod_regrb(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret);
+u32 brcmf_sdiod_regrl(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret);
+void brcmf_sdiod_regwb(struct brcmf_sdio_dev *sdiodev, u32 addr, u8 data,
+                      int *ret);
+void brcmf_sdiod_regwl(struct brcmf_sdio_dev *sdiodev, u32 addr, u32 data,
+                      int *ret);
 
 /* Buffer transfer to/from device (client) core via cmd53.
  *   fn:       function number
- *   addr:     backplane address (i.e. >= regsva from attach)
  *   flags:    backplane width, address increment, sync/async
  *   buf:      pointer to memory data buffer
  *   nbytes:   number of bytes to transfer to/from buf
@@ -210,17 +206,14 @@ int brcmf_sdio_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr,
  * Returns 0 or error code.
  * NOTE: Async operation is not currently supported.
  */
-int brcmf_sdcard_send_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
-                         uint flags, struct sk_buff_head *pktq);
-int brcmf_sdcard_send_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
-                         uint flags, u8 *buf, uint nbytes);
-
-int brcmf_sdcard_recv_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
-                         uint flags, struct sk_buff *pkt);
-int brcmf_sdcard_recv_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
-                         uint flags, u8 *buf, uint nbytes);
-int brcmf_sdcard_recv_chain(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
-                           uint flags, struct sk_buff_head *pktq, uint totlen);
+int brcmf_sdiod_send_pkt(struct brcmf_sdio_dev *sdiodev,
+                        struct sk_buff_head *pktq);
+int brcmf_sdiod_send_buf(struct brcmf_sdio_dev *sdiodev, u8 *buf, uint nbytes);
+
+int brcmf_sdiod_recv_pkt(struct brcmf_sdio_dev *sdiodev, struct sk_buff *pkt);
+int brcmf_sdiod_recv_buf(struct brcmf_sdio_dev *sdiodev, u8 *buf, uint nbytes);
+int brcmf_sdiod_recv_chain(struct brcmf_sdio_dev *sdiodev,
+                          struct sk_buff_head *pktq, uint totlen);
 
 /* Flags bits */
 
@@ -236,43 +229,16 @@ int brcmf_sdcard_recv_chain(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
  *   nbytes:   number of bytes to transfer to/from buf
  * Returns 0 or error code.
  */
-int brcmf_sdcard_rwdata(struct brcmf_sdio_dev *sdiodev, uint rw, u32 addr,
-                       u8 *buf, uint nbytes);
-int brcmf_sdio_ramrw(struct brcmf_sdio_dev *sdiodev, bool write, u32 address,
-                    u8 *data, uint size);
+int brcmf_sdiod_ramrw(struct brcmf_sdio_dev *sdiodev, bool write, u32 address,
+                     u8 *data, uint size);
 
 /* Issue an abort to the specified function */
-int brcmf_sdcard_abort(struct brcmf_sdio_dev *sdiodev, uint fn);
-
-/* platform specific/high level functions */
-int brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev);
-int brcmf_sdio_remove(struct brcmf_sdio_dev *sdiodev);
-
-/* attach, return handler on success, NULL if failed.
- *  The handler shall be provided by all subsequent calls. No local cache
- *  cfghdl points to the starting address of pci device mapped memory
- */
-int brcmf_sdioh_attach(struct brcmf_sdio_dev *sdiodev);
-void brcmf_sdioh_detach(struct brcmf_sdio_dev *sdiodev);
-
-/* read or write one byte using cmd52 */
-int brcmf_sdioh_request_byte(struct brcmf_sdio_dev *sdiodev, uint rw, uint fnc,
-                            uint addr, u8 *byte);
-
-/* read or write 2/4 bytes using cmd53 */
-int brcmf_sdioh_request_word(struct brcmf_sdio_dev *sdiodev, uint rw, uint fnc,
-                            uint addr, u32 *word, uint nbyte);
-
-/* Watchdog timer interface for pm ops */
-void brcmf_sdio_wdtmr_enable(struct brcmf_sdio_dev *sdiodev, bool enable);
+int brcmf_sdiod_abort(struct brcmf_sdio_dev *sdiodev, uint fn);
 
-void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev);
-void brcmf_sdbrcm_disconnect(void *ptr);
-void brcmf_sdbrcm_isr(void *arg);
+struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev);
+void brcmf_sdio_remove(struct brcmf_sdio *bus);
+void brcmf_sdio_isr(struct brcmf_sdio *bus);
 
-void brcmf_sdbrcm_wd_timer(struct brcmf_sdio *bus, uint wdtick);
+void brcmf_sdio_wd_timer(struct brcmf_sdio *bus, uint wdtick);
 
-void brcmf_pm_resume_wait(struct brcmf_sdio_dev *sdiodev,
-                         wait_queue_head_t *wq);
-bool brcmf_pm_resume_error(struct brcmf_sdio_dev *sdiodev);
 #endif                         /* _BRCM_SDH_H_ */
index 51c4de054b15e9c89c154acb93e3fff79e0c4ffa..c345c32eb6311cc528f4261375ac53b555b3a0f4 100644 (file)
@@ -1253,6 +1253,7 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo)
        bus->ops = &brcmf_usb_bus_ops;
        bus->chip = bus_pub->devid;
        bus->chiprev = bus_pub->chiprev;
+       bus->proto_type = BRCMF_PROTO_BCDC;
 
        /* Attach to the common driver interface */
        ret = brcmf_attach(dev);
index 217f1ca321a0fecb7aaa876a5a22b5ec214b5818..9f4239d31c088a8d58406b11283c83779cc4e4ea 100644 (file)
@@ -322,12 +322,6 @@ static void iwlagn_mac_stop(struct ieee80211_hw *hw)
 
        flush_workqueue(priv->workqueue);
 
-       /* User space software may expect getting rfkill changes
-        * even if interface is down, trans->down will leave the RF
-        * kill interrupt enabled
-        */
-       iwl_trans_stop_hw(priv->trans, false);
-
        IWL_DEBUG_MAC80211(priv, "leave\n");
 }
 
index 7aad766865cf5d09fb5f0ab7b150189039bccd53..fd9f6cf96cfdd29f199383927f82fb6f6624be8b 100644 (file)
@@ -1313,7 +1313,7 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
        }
 
        /* Reset chip to save power until we load uCode during "up". */
-       iwl_trans_stop_hw(priv->trans, false);
+       iwl_trans_stop_device(priv->trans);
 
        priv->nvm_data = iwl_parse_eeprom_data(priv->trans->dev, priv->cfg,
                                                  priv->eeprom_blob,
@@ -1458,7 +1458,7 @@ static void iwl_op_mode_dvm_stop(struct iwl_op_mode *op_mode)
 
        dev_kfree_skb(priv->beacon_skb);
 
-       iwl_trans_stop_hw(priv->trans, true);
+       iwl_trans_op_mode_leave(priv->trans);
        ieee80211_free_hw(priv->hw);
 }
 
index 3c34a72a5d64769b8bbf156f9a74d4748fcb0228..5fb37724c096fb879b601770356050a6b16f0d72 100644 (file)
@@ -108,7 +108,7 @@ static const struct iwl_base_params iwl7000_base_params = {
 };
 
 static const struct iwl_ht_params iwl7000_ht_params = {
-       .use_rts_for_aggregation = true, /* use rts/cts protection */
+       .stbc = true,
        .ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ),
 };
 
index 0b916249669ed25139db177649e5adcd98f74b7b..e05440ff5cd46d2c4add28faab7255b97c88b7f2 100644 (file)
@@ -162,12 +162,14 @@ struct iwl_base_params {
 };
 
 /*
+ * @stbc: support Tx STBC and 1*SS Rx STBC
  * @use_rts_for_aggregation: use rts/cts protection for HT traffic
  * @ht40_bands: bitmap of bands (using %IEEE80211_BAND_*) that support HT40
  */
 struct iwl_ht_params {
        enum ieee80211_smps_mode smps_mode;
        const bool ht_greenfield_support; /* if used set to true */
+       const bool stbc;
        bool use_rts_for_aggregation;
        u8 ht40_bands;
 };
index ff570027e9dd9fa02f3e8360af6966b480c68069..4bebfb58fc7be083f72e0492b3b0aa4df7f34710 100644 (file)
@@ -322,6 +322,41 @@ static void set_sec_offset(struct iwl_firmware_pieces *pieces,
        pieces->img[type].sec[sec].offset = offset;
 }
 
+static int iwl_store_cscheme(struct iwl_fw *fw, const u8 *data, const u32 len)
+{
+       int i, j;
+       struct iwl_fw_cscheme_list *l = (struct iwl_fw_cscheme_list *)data;
+       struct iwl_fw_cipher_scheme *fwcs;
+       struct ieee80211_cipher_scheme *cs;
+       u32 cipher;
+
+       if (len < sizeof(*l) ||
+           len < sizeof(l->size) + l->size * sizeof(l->cs[0]))
+               return -EINVAL;
+
+       for (i = 0, j = 0; i < IWL_UCODE_MAX_CS && i < l->size; i++) {
+               fwcs = &l->cs[j];
+               cipher = le32_to_cpu(fwcs->cipher);
+
+               /* we skip schemes with zero cipher suite selector */
+               if (!cipher)
+                       continue;
+
+               cs = &fw->cs[j++];
+               cs->cipher = cipher;
+               cs->iftype = BIT(NL80211_IFTYPE_STATION);
+               cs->hdr_len = fwcs->hdr_len;
+               cs->pn_len = fwcs->pn_len;
+               cs->pn_off = fwcs->pn_off;
+               cs->key_idx_off = fwcs->key_idx_off;
+               cs->key_idx_mask = fwcs->key_idx_mask;
+               cs->key_idx_shift = fwcs->key_idx_shift;
+               cs->mic_len = fwcs->mic_len;
+       }
+
+       return 0;
+}
+
 /*
  * Gets uCode section from tlv.
  */
@@ -729,6 +764,10 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
                                return -EINVAL;
                        }
                        break;
+               case IWL_UCODE_TLV_CSCHEME:
+                       if (iwl_store_cscheme(&drv->fw, tlv_data, tlv_len))
+                               goto invalid_tlv_len;
+                       break;
                default:
                        IWL_DEBUG_INFO(drv, "unknown TLV: %d\n", tlv_type);
                        break;
index f4a6d317a023aad241ac4f15351a1cc2deae7a2c..4380c16580ebe4303b6bd8a679686c2c6ef94cc4 100644 (file)
@@ -751,6 +751,13 @@ void iwl_init_ht_hw_capab(const struct iwl_cfg *cfg,
        ht_info->ht_supported = true;
        ht_info->cap = IEEE80211_HT_CAP_DSSSCCK40;
 
+       if (cfg->ht_params->stbc) {
+               ht_info->cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
+
+               if (tx_chains > 1)
+                       ht_info->cap |= IEEE80211_HT_CAP_TX_STBC;
+       }
+
        if (iwlwifi_mod_params.amsdu_size_8K)
                ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU;
 
index 6c6c35c5228cabd71d1520f533af7bd3adf8ad26..4f95734b28118b93e3b144c58e1b41aa682b9890 100644 (file)
@@ -125,6 +125,7 @@ enum iwl_ucode_tlv_type {
        IWL_UCODE_TLV_SECURE_SEC_INIT   = 25,
        IWL_UCODE_TLV_SECURE_SEC_WOWLAN = 26,
        IWL_UCODE_TLV_NUM_OF_CPU        = 27,
+       IWL_UCODE_TLV_CSCHEME           = 28,
 };
 
 struct iwl_ucode_tlv {
index 75db087120c30fc8f2201f1f4de1be4d3e8e270c..8704e3042ca137a8bd4e647c70411f964a8b47ff 100644 (file)
@@ -92,6 +92,9 @@
  * @IWL_UCODE_TLV_FLAGS_STA_KEY_CMD: new ADD_STA and ADD_STA_KEY command API
  * @IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD: support device wide power command
  *     containing CAM (Continuous Active Mode) indication.
+ * @IWL_UCODE_TLV_FLAGS_P2P_PS: P2P client power save is supported (only on a
+ *     single bound interface).
+ * @IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD: P2P client supports uAPSD power save
  */
 enum iwl_ucode_tlv_flag {
        IWL_UCODE_TLV_FLAGS_PAN                 = BIT(0),
@@ -113,7 +116,9 @@ enum iwl_ucode_tlv_flag {
        IWL_UCODE_TLV_FLAGS_SCHED_SCAN          = BIT(17),
        IWL_UCODE_TLV_FLAGS_STA_KEY_CMD         = BIT(19),
        IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD       = BIT(20),
+       IWL_UCODE_TLV_FLAGS_P2P_PS              = BIT(21),
        IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT       = BIT(24),
+       IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD        = BIT(26),
 };
 
 /* The default calibrate table size if not specified by firmware file */
@@ -209,6 +214,44 @@ enum iwl_fw_phy_cfg {
        FW_PHY_CFG_RX_CHAIN = 0xf << FW_PHY_CFG_RX_CHAIN_POS,
 };
 
+#define IWL_UCODE_MAX_CS               1
+
+/**
+ * struct iwl_fw_cipher_scheme - a cipher scheme supported by FW.
+ * @cipher: a cipher suite selector
+ * @flags: cipher scheme flags (currently reserved for a future use)
+ * @hdr_len: a size of MPDU security header
+ * @pn_len: a size of PN
+ * @pn_off: an offset of pn from the beginning of the security header
+ * @key_idx_off: an offset of key index byte in the security header
+ * @key_idx_mask: a bit mask of key_idx bits
+ * @key_idx_shift: bit shift needed to get key_idx
+ * @mic_len: mic length in bytes
+ * @hw_cipher: a HW cipher index used in host commands
+ */
+struct iwl_fw_cipher_scheme {
+       __le32 cipher;
+       u8 flags;
+       u8 hdr_len;
+       u8 pn_len;
+       u8 pn_off;
+       u8 key_idx_off;
+       u8 key_idx_mask;
+       u8 key_idx_shift;
+       u8 mic_len;
+       u8 hw_cipher;
+} __packed;
+
+/**
+ * struct iwl_fw_cscheme_list - a cipher scheme list
+ * @size: a number of entries
+ * @cs: cipher scheme entries
+ */
+struct iwl_fw_cscheme_list {
+       u8 size;
+       struct iwl_fw_cipher_scheme cs[];
+} __packed;
+
 /**
  * struct iwl_fw - variables associated with the firmware
  *
@@ -224,6 +267,7 @@ enum iwl_fw_phy_cfg {
  * @inst_evtlog_size: event log size for runtime ucode.
  * @inst_errlog_ptr: error log offfset for runtime ucode.
  * @mvm_fw: indicates this is MVM firmware
+ * @cipher_scheme: optional external cipher scheme.
  */
 struct iwl_fw {
        u32 ucode_ver;
@@ -243,6 +287,8 @@ struct iwl_fw {
        u32 phy_config;
 
        bool mvm_fw;
+
+       struct ieee80211_cipher_scheme cs[IWL_UCODE_MAX_CS];
 };
 
 static inline u8 iwl_fw_valid_tx_ant(const struct iwl_fw *fw)
index 94aef22df73a9f772429f536aa11e71ca98d51d2..a48decc6c68f9d9291cf68bdf9e61d0a403c6218 100644 (file)
@@ -263,13 +263,20 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
                                  struct iwl_nvm_data *data,
                                  struct ieee80211_sta_vht_cap *vht_cap)
 {
+       int num_ants = num_of_ant(data->valid_rx_ant);
+       int bf_sts_cap = num_ants - 1;
+
        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 |
+                      bf_sts_cap << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT |
                       7 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT;
 
+       if (num_ants > 1)
+               vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC;
+
        if (iwlwifi_mod_params.amsdu_size_8K)
                vht_cap->cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991;
 
@@ -283,16 +290,22 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
                            IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 |
                            IEEE80211_VHT_MCS_NOT_SUPPORTED << 14);
 
-       if (num_of_ant(data->valid_rx_ant) == 1 ||
+       /* Max rate for Long GI NSS=2 80Mhz is 780Mbps */
+       vht_cap->vht_mcs.rx_highest = cpu_to_le16(780);
+
+       if (num_ants == 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);
+               /* Max rate for Long GI NSS=1 80Mhz is 390Mbps */
+               vht_cap->vht_mcs.rx_highest = cpu_to_le16(390);
        }
 
        vht_cap->vht_mcs.tx_mcs_map = vht_cap->vht_mcs.rx_mcs_map;
+       vht_cap->vht_mcs.tx_highest = vht_cap->vht_mcs.rx_highest;
 }
 
 static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
index 976448a57d02649a7263b499bcc4974a5a1db18c..f50e6c62ebc5b7dd7e6b009e3da82503a14794b5 100644 (file)
@@ -155,14 +155,12 @@ void iwl_opmode_deregister(const char *name);
 
 /**
  * struct iwl_op_mode - operational mode
+ * @ops - pointer to its own ops
  *
  * This holds an implementation of the mac80211 / fw API.
- *
- * @ops - pointer to its own ops
  */
 struct iwl_op_mode {
        const struct iwl_op_mode_ops *ops;
-       const struct iwl_trans *trans;
 
        char op_mode_specific[0] __aligned(sizeof(void *));
 };
index 143292b4dbbffeac763f86d5c9d9b1badae1aecc..0c3647858909dc53ce1697072cce6d9947808633 100644 (file)
@@ -70,6 +70,7 @@
 #include "iwl-debug.h"
 #include "iwl-config.h"
 #include "iwl-fw.h"
+#include "iwl-op-mode.h"
 
 /**
  * DOC: Transport layer - what is it ?
  *        start_fw
  *
  *     5) Then when finished (or reset):
- *        stop_fw (a.k.a. stop device for the moment)
- *        stop_hw
+ *        stop_device
  *
  *     6) Eventually, the free function will be called.
  */
@@ -317,6 +317,24 @@ enum iwl_d3_status {
        IWL_D3_STATUS_RESET,
 };
 
+/**
+ * enum iwl_trans_status: transport status flags
+ * @STATUS_SYNC_HCMD_ACTIVE: a SYNC command is being processed
+ * @STATUS_DEVICE_ENABLED: APM is enabled
+ * @STATUS_TPOWER_PMI: the device might be asleep (need to wake it up)
+ * @STATUS_INT_ENABLED: interrupts are enabled
+ * @STATUS_RFKILL: the HW RFkill switch is in KILL position
+ * @STATUS_FW_ERROR: the fw is in error state
+ */
+enum iwl_trans_status {
+       STATUS_SYNC_HCMD_ACTIVE,
+       STATUS_DEVICE_ENABLED,
+       STATUS_TPOWER_PMI,
+       STATUS_INT_ENABLED,
+       STATUS_RFKILL,
+       STATUS_FW_ERROR,
+};
+
 /**
  * struct iwl_trans_config - transport configuration
  *
@@ -361,9 +379,7 @@ struct iwl_trans;
  *
  * @start_hw: starts the HW- from that point on, the HW can send interrupts
  *     May sleep
- * @stop_hw: stops the HW- from that point on, the HW will be in low power but
- *     will still issue interrupt if the HW RF kill is triggered unless
- *     op_mode_leaving is true.
+ * @op_mode_leave: Turn off the HW RF kill indication if on
  *     May sleep
  * @start_fw: allocates and inits all the resources for the transport
  *     layer. Also kick a fw image.
@@ -371,8 +387,11 @@ struct iwl_trans;
  * @fw_alive: called when the fw sends alive notification. If the fw provides
  *     the SCD base address in SRAM, then provide it here, or 0 otherwise.
  *     May sleep
- * @stop_device:stops the whole device (embedded CPU put to reset)
- *     May sleep
+ * @stop_device: stops the whole device (embedded CPU put to reset) and stops
+ *     the HW. From that point on, the HW will be in low power but will still
+ *     issue interrupt if the HW RF kill is triggered. This callback must do
+ *     the right thing and not crash even if start_hw() was called but not
+ *     start_fw(). May sleep
  * @d3_suspend: put the device into the correct mode for WoWLAN during
  *     suspend. This is optional, if not implemented WoWLAN will not be
  *     supported. This callback may sleep.
@@ -418,7 +437,7 @@ struct iwl_trans;
 struct iwl_trans_ops {
 
        int (*start_hw)(struct iwl_trans *iwl_trans);
-       void (*stop_hw)(struct iwl_trans *iwl_trans, bool op_mode_leaving);
+       void (*op_mode_leave)(struct iwl_trans *iwl_trans);
        int (*start_fw)(struct iwl_trans *trans, const struct fw_img *fw,
                        bool run_in_rfkill);
        void (*fw_alive)(struct iwl_trans *trans, u32 scd_addr);
@@ -479,6 +498,7 @@ enum iwl_trans_state {
  * @ops - pointer to iwl_trans_ops
  * @op_mode - pointer to the op_mode
  * @cfg - pointer to the configuration
+ * @status: a bit-mask of transport status flags
  * @dev - pointer to struct device * that represents the device
  * @hw_id: a u32 with the ID of the device / subdevice.
  *     Set during transport allocation.
@@ -499,6 +519,7 @@ struct iwl_trans {
        struct iwl_op_mode *op_mode;
        const struct iwl_cfg *cfg;
        enum iwl_trans_state state;
+       unsigned long status;
 
        struct device *dev;
        u32 hw_rev;
@@ -540,15 +561,14 @@ static inline int iwl_trans_start_hw(struct iwl_trans *trans)
        return trans->ops->start_hw(trans);
 }
 
-static inline void iwl_trans_stop_hw(struct iwl_trans *trans,
-                                    bool op_mode_leaving)
+static inline void iwl_trans_op_mode_leave(struct iwl_trans *trans)
 {
        might_sleep();
 
-       trans->ops->stop_hw(trans, op_mode_leaving);
+       if (trans->ops->op_mode_leave)
+               trans->ops->op_mode_leave(trans);
 
-       if (op_mode_leaving)
-               trans->op_mode = NULL;
+       trans->op_mode = NULL;
 
        trans->state = IWL_TRANS_NO_FW;
 }
@@ -570,6 +590,7 @@ static inline int iwl_trans_start_fw(struct iwl_trans *trans,
 
        WARN_ON_ONCE(!trans->rx_mpdu_cmd);
 
+       clear_bit(STATUS_FW_ERROR, &trans->status);
        return trans->ops->start_fw(trans, fw, run_in_rfkill);
 }
 
@@ -601,6 +622,9 @@ static inline int iwl_trans_send_cmd(struct iwl_trans *trans,
 {
        int ret;
 
+       if (unlikely(test_bit(STATUS_FW_ERROR, &trans->status)))
+               return -EIO;
+
        if (unlikely(trans->state != IWL_TRANS_FW_ALIVE)) {
                IWL_ERR(trans, "%s bad state = %d", __func__, trans->state);
                return -EIO;
@@ -640,6 +664,9 @@ static inline void iwl_trans_free_tx_cmd(struct iwl_trans *trans,
 static inline int iwl_trans_tx(struct iwl_trans *trans, struct sk_buff *skb,
                               struct iwl_device_cmd *dev_cmd, int queue)
 {
+       if (unlikely(test_bit(STATUS_FW_ERROR, &trans->status)))
+               return -EIO;
+
        if (unlikely(trans->state != IWL_TRANS_FW_ALIVE))
                IWL_ERR(trans, "%s bad state = %d", __func__, trans->state);
 
@@ -760,7 +787,8 @@ static inline u32 iwl_trans_write_mem32(struct iwl_trans *trans, u32 addr,
 
 static inline void iwl_trans_set_pmi(struct iwl_trans *trans, bool state)
 {
-       trans->ops->set_pmi(trans, state);
+       if (trans->ops->set_pmi)
+               trans->ops->set_pmi(trans, state);
 }
 
 static inline void
@@ -780,6 +808,16 @@ iwl_trans_release_nic_access(struct iwl_trans *trans, unsigned long *flags)
        __release(nic_access);
 }
 
+static inline void iwl_trans_fw_error(struct iwl_trans *trans)
+{
+       if (WARN_ON_ONCE(!trans->op_mode))
+               return;
+
+       /* prevent double restarts due to the same erroneous FW */
+       if (!test_and_set_bit(STATUS_FW_ERROR, &trans->status))
+               iwl_op_mode_nic_error(trans->op_mode);
+}
+
 /*****************************************************
 * driver (transport) register/unregister functions
 ******************************************************/
index 285d8c7486f5a8262209f641d704424036fecce7..f98ec2b238989da818cb1b4af67f6c6a319c8de4 100644 (file)
@@ -1,10 +1,9 @@
 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 += utils.o rx.o tx.o binding.o quota.o sta.o sf.o
 iwlmvm-y += scan.o time-event.o rs.o
 iwlmvm-y += power.o power_legacy.o bt-coex.o
 iwlmvm-y += led.o tt.o
-iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o
 iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o debugfs-vif.o
 iwlmvm-$(CONFIG_PM_SLEEP) += d3.o
 
index 93fd1457954bcd43cc5f833de4f8b1b188b84d96..57d3eed86efa99edbf4c729f41db9d0fb6b89c5c 100644 (file)
@@ -183,15 +183,29 @@ int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
        if (WARN_ON_ONCE(!mvmvif->phy_ctxt))
                return -EINVAL;
 
+       /*
+        * Update SF - Disable if needed. if this fails, SF might still be on
+        * while many macs are bound, which is forbidden - so fail the binding.
+        */
+       if (iwl_mvm_sf_update(mvm, vif, false))
+               return -EINVAL;
+
        return iwl_mvm_binding_update(mvm, vif, mvmvif->phy_ctxt, true);
 }
 
 int iwl_mvm_binding_remove_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
 {
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+       int ret;
 
        if (WARN_ON_ONCE(!mvmvif->phy_ctxt))
                return -EINVAL;
 
-       return iwl_mvm_binding_update(mvm, vif, mvmvif->phy_ctxt, false);
+       ret = iwl_mvm_binding_update(mvm, vif, mvmvif->phy_ctxt, false);
+
+       if (!ret)
+               if (iwl_mvm_sf_update(mvm, vif, true))
+                       IWL_ERR(mvm, "Failed to update SF state\n");
+
+       return ret;
 }
index 67f6a207165315d709cda315c9205de286c88789..b8667575bc109046fae37001c7776958e664ab7c 100644 (file)
 #include "mvm.h"
 #include "debugfs.h"
 
+static void iwl_dbgfs_update_pm(struct iwl_mvm *mvm,
+                                struct ieee80211_vif *vif,
+                                enum iwl_dbgfs_pm_mask param, int val)
+{
+       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+       struct iwl_dbgfs_pm *dbgfs_pm = &mvmvif->dbgfs_pm;
+
+       dbgfs_pm->mask |= param;
+
+       switch (param) {
+       case MVM_DEBUGFS_PM_KEEP_ALIVE: {
+               struct ieee80211_hw *hw = mvm->hw;
+               int dtimper = hw->conf.ps_dtim_period ?: 1;
+               int dtimper_msec = dtimper * vif->bss_conf.beacon_int;
+
+               IWL_DEBUG_POWER(mvm, "debugfs: set keep_alive= %d sec\n", val);
+               if (val * MSEC_PER_SEC < 3 * dtimper_msec)
+                       IWL_WARN(mvm,
+                                "debugfs: keep alive period (%ld msec) is less than minimum required (%d msec)\n",
+                                val * MSEC_PER_SEC, 3 * dtimper_msec);
+               dbgfs_pm->keep_alive_seconds = val;
+               break;
+       }
+       case MVM_DEBUGFS_PM_SKIP_OVER_DTIM:
+               IWL_DEBUG_POWER(mvm, "skip_over_dtim %s\n",
+                               val ? "enabled" : "disabled");
+               dbgfs_pm->skip_over_dtim = val;
+               break;
+       case MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS:
+               IWL_DEBUG_POWER(mvm, "skip_dtim_periods=%d\n", val);
+               dbgfs_pm->skip_dtim_periods = val;
+               break;
+       case MVM_DEBUGFS_PM_RX_DATA_TIMEOUT:
+               IWL_DEBUG_POWER(mvm, "rx_data_timeout=%d\n", val);
+               dbgfs_pm->rx_data_timeout = val;
+               break;
+       case MVM_DEBUGFS_PM_TX_DATA_TIMEOUT:
+               IWL_DEBUG_POWER(mvm, "tx_data_timeout=%d\n", val);
+               dbgfs_pm->tx_data_timeout = val;
+               break;
+       case MVM_DEBUGFS_PM_DISABLE_POWER_OFF:
+               IWL_DEBUG_POWER(mvm, "disable_power_off=%d\n", val);
+               dbgfs_pm->disable_power_off = val;
+               break;
+       case MVM_DEBUGFS_PM_LPRX_ENA:
+               IWL_DEBUG_POWER(mvm, "lprx %s\n", val ? "enabled" : "disabled");
+               dbgfs_pm->lprx_ena = val;
+               break;
+       case MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD:
+               IWL_DEBUG_POWER(mvm, "lprx_rssi_threshold=%d\n", val);
+               dbgfs_pm->lprx_rssi_threshold = val;
+               break;
+       case MVM_DEBUGFS_PM_SNOOZE_ENABLE:
+               IWL_DEBUG_POWER(mvm, "snooze_enable=%d\n", val);
+               dbgfs_pm->snooze_ena = val;
+               break;
+       case MVM_DEBUGFS_PM_UAPSD_MISBEHAVING:
+               IWL_DEBUG_POWER(mvm, "uapsd_misbehaving_enable=%d\n", val);
+               dbgfs_pm->uapsd_misbehaving = val;
+               break;
+       }
+}
+
+static ssize_t iwl_dbgfs_pm_params_write(struct ieee80211_vif *vif, char *buf,
+                                        size_t count, loff_t *ppos)
+{
+       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+       struct iwl_mvm *mvm = mvmvif->mvm;
+       enum iwl_dbgfs_pm_mask param;
+       int val, ret;
+
+       if (!strncmp("keep_alive=", buf, 11)) {
+               if (sscanf(buf + 11, "%d", &val) != 1)
+                       return -EINVAL;
+               param = MVM_DEBUGFS_PM_KEEP_ALIVE;
+       } else if (!strncmp("skip_over_dtim=", buf, 15)) {
+               if (sscanf(buf + 15, "%d", &val) != 1)
+                       return -EINVAL;
+               param = MVM_DEBUGFS_PM_SKIP_OVER_DTIM;
+       } else if (!strncmp("skip_dtim_periods=", buf, 18)) {
+               if (sscanf(buf + 18, "%d", &val) != 1)
+                       return -EINVAL;
+               param = MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS;
+       } else if (!strncmp("rx_data_timeout=", buf, 16)) {
+               if (sscanf(buf + 16, "%d", &val) != 1)
+                       return -EINVAL;
+               param = MVM_DEBUGFS_PM_RX_DATA_TIMEOUT;
+       } else if (!strncmp("tx_data_timeout=", buf, 16)) {
+               if (sscanf(buf + 16, "%d", &val) != 1)
+                       return -EINVAL;
+               param = MVM_DEBUGFS_PM_TX_DATA_TIMEOUT;
+       } else if (!strncmp("disable_power_off=", buf, 18) &&
+                  !(mvm->fw->ucode_capa.flags &
+                    IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD)) {
+               if (sscanf(buf + 18, "%d", &val) != 1)
+                       return -EINVAL;
+               param = MVM_DEBUGFS_PM_DISABLE_POWER_OFF;
+       } else if (!strncmp("lprx=", buf, 5)) {
+               if (sscanf(buf + 5, "%d", &val) != 1)
+                       return -EINVAL;
+               param = MVM_DEBUGFS_PM_LPRX_ENA;
+       } else if (!strncmp("lprx_rssi_threshold=", buf, 20)) {
+               if (sscanf(buf + 20, "%d", &val) != 1)
+                       return -EINVAL;
+               if (val > POWER_LPRX_RSSI_THRESHOLD_MAX || val <
+                   POWER_LPRX_RSSI_THRESHOLD_MIN)
+                       return -EINVAL;
+               param = MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD;
+       } else if (!strncmp("snooze_enable=", buf, 14)) {
+               if (sscanf(buf + 14, "%d", &val) != 1)
+                       return -EINVAL;
+               param = MVM_DEBUGFS_PM_SNOOZE_ENABLE;
+       } else if (!strncmp("uapsd_misbehaving=", buf, 18)) {
+               if (sscanf(buf + 18, "%d", &val) != 1)
+                       return -EINVAL;
+               param = MVM_DEBUGFS_PM_UAPSD_MISBEHAVING;
+       } else {
+               return -EINVAL;
+       }
+
+       mutex_lock(&mvm->mutex);
+       iwl_dbgfs_update_pm(mvm, vif, param, val);
+       ret = iwl_mvm_power_update_mode(mvm, vif);
+       mutex_unlock(&mvm->mutex);
+
+       return ret ?: count;
+}
+
+static ssize_t iwl_dbgfs_pm_params_read(struct file *file,
+                                       char __user *user_buf,
+                                       size_t count, loff_t *ppos)
+{
+       struct ieee80211_vif *vif = file->private_data;
+       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+       struct iwl_mvm *mvm = mvmvif->mvm;
+       char buf[512];
+       int bufsz = sizeof(buf);
+       int pos;
+
+       pos = iwl_mvm_power_dbgfs_read(mvm, vif, buf, bufsz);
+
+       return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
 static ssize_t iwl_dbgfs_mac_params_read(struct file *file,
                                         char __user *user_buf,
                                         size_t count, loff_t *ppos)
@@ -98,14 +242,17 @@ static ssize_t iwl_dbgfs_mac_params_read(struct file *file,
        if (vif->type == NL80211_IFTYPE_STATION &&
            ap_sta_id != IWL_MVM_STATION_COUNT) {
                struct ieee80211_sta *sta;
-               struct iwl_mvm_sta *mvm_sta;
 
                sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[ap_sta_id],
                                                lockdep_is_held(&mvm->mutex));
-               mvm_sta = (void *)sta->drv_priv;
-               pos += scnprintf(buf+pos, bufsz-pos,
-                                "ap_sta_id %d - reduced Tx power %d\n",
-                                ap_sta_id, mvm_sta->bt_reduced_txpower);
+               if (!IS_ERR_OR_NULL(sta)) {
+                       struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv;
+
+                       pos += scnprintf(buf+pos, bufsz-pos,
+                                        "ap_sta_id %d - reduced Tx power %d\n",
+                                        ap_sta_id,
+                                        mvm_sta->bt_reduced_txpower);
+               }
        }
 
        rcu_read_lock();
@@ -122,6 +269,201 @@ static ssize_t iwl_dbgfs_mac_params_read(struct file *file,
        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 }
 
+static void iwl_dbgfs_update_bf(struct ieee80211_vif *vif,
+                               enum iwl_dbgfs_bf_mask param, int value)
+{
+       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+       struct iwl_dbgfs_bf *dbgfs_bf = &mvmvif->dbgfs_bf;
+
+       dbgfs_bf->mask |= param;
+
+       switch (param) {
+       case MVM_DEBUGFS_BF_ENERGY_DELTA:
+               dbgfs_bf->bf_energy_delta = value;
+               break;
+       case MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA:
+               dbgfs_bf->bf_roaming_energy_delta = value;
+               break;
+       case MVM_DEBUGFS_BF_ROAMING_STATE:
+               dbgfs_bf->bf_roaming_state = value;
+               break;
+       case MVM_DEBUGFS_BF_TEMP_THRESHOLD:
+               dbgfs_bf->bf_temp_threshold = value;
+               break;
+       case MVM_DEBUGFS_BF_TEMP_FAST_FILTER:
+               dbgfs_bf->bf_temp_fast_filter = value;
+               break;
+       case MVM_DEBUGFS_BF_TEMP_SLOW_FILTER:
+               dbgfs_bf->bf_temp_slow_filter = value;
+               break;
+       case MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER:
+               dbgfs_bf->bf_enable_beacon_filter = value;
+               break;
+       case MVM_DEBUGFS_BF_DEBUG_FLAG:
+               dbgfs_bf->bf_debug_flag = value;
+               break;
+       case MVM_DEBUGFS_BF_ESCAPE_TIMER:
+               dbgfs_bf->bf_escape_timer = value;
+               break;
+       case MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT:
+               dbgfs_bf->ba_enable_beacon_abort = value;
+               break;
+       case MVM_DEBUGFS_BA_ESCAPE_TIMER:
+               dbgfs_bf->ba_escape_timer = value;
+               break;
+       }
+}
+
+static ssize_t iwl_dbgfs_bf_params_write(struct ieee80211_vif *vif, char *buf,
+                                        size_t count, loff_t *ppos)
+{
+       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+       struct iwl_mvm *mvm = mvmvif->mvm;
+       enum iwl_dbgfs_bf_mask param;
+       int value, ret = 0;
+
+       if (!strncmp("bf_energy_delta=", buf, 16)) {
+               if (sscanf(buf+16, "%d", &value) != 1)
+                       return -EINVAL;
+               if (value < IWL_BF_ENERGY_DELTA_MIN ||
+                   value > IWL_BF_ENERGY_DELTA_MAX)
+                       return -EINVAL;
+               param = MVM_DEBUGFS_BF_ENERGY_DELTA;
+       } else if (!strncmp("bf_roaming_energy_delta=", buf, 24)) {
+               if (sscanf(buf+24, "%d", &value) != 1)
+                       return -EINVAL;
+               if (value < IWL_BF_ROAMING_ENERGY_DELTA_MIN ||
+                   value > IWL_BF_ROAMING_ENERGY_DELTA_MAX)
+                       return -EINVAL;
+               param = MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA;
+       } else if (!strncmp("bf_roaming_state=", buf, 17)) {
+               if (sscanf(buf+17, "%d", &value) != 1)
+                       return -EINVAL;
+               if (value < IWL_BF_ROAMING_STATE_MIN ||
+                   value > IWL_BF_ROAMING_STATE_MAX)
+                       return -EINVAL;
+               param = MVM_DEBUGFS_BF_ROAMING_STATE;
+       } else if (!strncmp("bf_temp_threshold=", buf, 18)) {
+               if (sscanf(buf+18, "%d", &value) != 1)
+                       return -EINVAL;
+               if (value < IWL_BF_TEMP_THRESHOLD_MIN ||
+                   value > IWL_BF_TEMP_THRESHOLD_MAX)
+                       return -EINVAL;
+               param = MVM_DEBUGFS_BF_TEMP_THRESHOLD;
+       } else if (!strncmp("bf_temp_fast_filter=", buf, 20)) {
+               if (sscanf(buf+20, "%d", &value) != 1)
+                       return -EINVAL;
+               if (value < IWL_BF_TEMP_FAST_FILTER_MIN ||
+                   value > IWL_BF_TEMP_FAST_FILTER_MAX)
+                       return -EINVAL;
+               param = MVM_DEBUGFS_BF_TEMP_FAST_FILTER;
+       } else if (!strncmp("bf_temp_slow_filter=", buf, 20)) {
+               if (sscanf(buf+20, "%d", &value) != 1)
+                       return -EINVAL;
+               if (value < IWL_BF_TEMP_SLOW_FILTER_MIN ||
+                   value > IWL_BF_TEMP_SLOW_FILTER_MAX)
+                       return -EINVAL;
+               param = MVM_DEBUGFS_BF_TEMP_SLOW_FILTER;
+       } else if (!strncmp("bf_enable_beacon_filter=", buf, 24)) {
+               if (sscanf(buf+24, "%d", &value) != 1)
+                       return -EINVAL;
+               if (value < 0 || value > 1)
+                       return -EINVAL;
+               param = MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER;
+       } else if (!strncmp("bf_debug_flag=", buf, 14)) {
+               if (sscanf(buf+14, "%d", &value) != 1)
+                       return -EINVAL;
+               if (value < 0 || value > 1)
+                       return -EINVAL;
+               param = MVM_DEBUGFS_BF_DEBUG_FLAG;
+       } else if (!strncmp("bf_escape_timer=", buf, 16)) {
+               if (sscanf(buf+16, "%d", &value) != 1)
+                       return -EINVAL;
+               if (value < IWL_BF_ESCAPE_TIMER_MIN ||
+                   value > IWL_BF_ESCAPE_TIMER_MAX)
+                       return -EINVAL;
+               param = MVM_DEBUGFS_BF_ESCAPE_TIMER;
+       } else if (!strncmp("ba_escape_timer=", buf, 16)) {
+               if (sscanf(buf+16, "%d", &value) != 1)
+                       return -EINVAL;
+               if (value < IWL_BA_ESCAPE_TIMER_MIN ||
+                   value > IWL_BA_ESCAPE_TIMER_MAX)
+                       return -EINVAL;
+               param = MVM_DEBUGFS_BA_ESCAPE_TIMER;
+       } else if (!strncmp("ba_enable_beacon_abort=", buf, 23)) {
+               if (sscanf(buf+23, "%d", &value) != 1)
+                       return -EINVAL;
+               if (value < 0 || value > 1)
+                       return -EINVAL;
+               param = MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT;
+       } else {
+               return -EINVAL;
+       }
+
+       mutex_lock(&mvm->mutex);
+       iwl_dbgfs_update_bf(vif, param, value);
+       if (param == MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER && !value)
+               ret = iwl_mvm_disable_beacon_filter(mvm, vif);
+       else
+               ret = iwl_mvm_enable_beacon_filter(mvm, vif);
+       mutex_unlock(&mvm->mutex);
+
+       return ret ?: count;
+}
+
+static ssize_t iwl_dbgfs_bf_params_read(struct file *file,
+                                       char __user *user_buf,
+                                       size_t count, loff_t *ppos)
+{
+       struct ieee80211_vif *vif = file->private_data;
+       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+       char buf[256];
+       int pos = 0;
+       const size_t bufsz = sizeof(buf);
+       struct iwl_beacon_filter_cmd cmd = {
+               IWL_BF_CMD_CONFIG_DEFAULTS,
+               .bf_enable_beacon_filter =
+                       cpu_to_le32(IWL_BF_ENABLE_BEACON_FILTER_DEFAULT),
+               .ba_enable_beacon_abort =
+                       cpu_to_le32(IWL_BA_ENABLE_BEACON_ABORT_DEFAULT),
+       };
+
+       iwl_mvm_beacon_filter_debugfs_parameters(vif, &cmd);
+       if (mvmvif->bf_data.bf_enabled)
+               cmd.bf_enable_beacon_filter = cpu_to_le32(1);
+       else
+               cmd.bf_enable_beacon_filter = 0;
+
+       pos += scnprintf(buf+pos, bufsz-pos, "bf_energy_delta = %d\n",
+                        le32_to_cpu(cmd.bf_energy_delta));
+       pos += scnprintf(buf+pos, bufsz-pos, "bf_roaming_energy_delta = %d\n",
+                        le32_to_cpu(cmd.bf_roaming_energy_delta));
+       pos += scnprintf(buf+pos, bufsz-pos, "bf_roaming_state = %d\n",
+                        le32_to_cpu(cmd.bf_roaming_state));
+       pos += scnprintf(buf+pos, bufsz-pos, "bf_temp_threshold = %d\n",
+                        le32_to_cpu(cmd.bf_temp_threshold));
+       pos += scnprintf(buf+pos, bufsz-pos, "bf_temp_fast_filter = %d\n",
+                        le32_to_cpu(cmd.bf_temp_fast_filter));
+       pos += scnprintf(buf+pos, bufsz-pos, "bf_temp_slow_filter = %d\n",
+                        le32_to_cpu(cmd.bf_temp_slow_filter));
+       pos += scnprintf(buf+pos, bufsz-pos, "bf_enable_beacon_filter = %d\n",
+                        le32_to_cpu(cmd.bf_enable_beacon_filter));
+       pos += scnprintf(buf+pos, bufsz-pos, "bf_debug_flag = %d\n",
+                        le32_to_cpu(cmd.bf_debug_flag));
+       pos += scnprintf(buf+pos, bufsz-pos, "bf_escape_timer = %d\n",
+                        le32_to_cpu(cmd.bf_escape_timer));
+       pos += scnprintf(buf+pos, bufsz-pos, "ba_escape_timer = %d\n",
+                        le32_to_cpu(cmd.ba_escape_timer));
+       pos += scnprintf(buf+pos, bufsz-pos, "ba_enable_beacon_abort = %d\n",
+                        le32_to_cpu(cmd.ba_enable_beacon_abort));
+
+       return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
+#define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \
+       _MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif)
+#define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \
+       _MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif)
 #define MVM_DEBUGFS_ADD_FILE_VIF(name, parent, mode) do {              \
                if (!debugfs_create_file(#name, mode, parent, vif,      \
                                         &iwl_dbgfs_##name##_ops))      \
@@ -129,6 +471,8 @@ static ssize_t iwl_dbgfs_mac_params_read(struct file *file,
        } while (0)
 
 MVM_DEBUGFS_READ_FILE_OPS(mac_params);
+MVM_DEBUGFS_READ_WRITE_FILE_OPS(pm_params, 32);
+MVM_DEBUGFS_READ_WRITE_FILE_OPS(bf_params, 256);
 
 void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
 {
@@ -152,9 +496,21 @@ void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
                return;
        }
 
+       if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM &&
+           ((vif->type == NL80211_IFTYPE_STATION && !vif->p2p) ||
+            (vif->type == NL80211_IFTYPE_STATION && vif->p2p &&
+             mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_P2P_PS)))
+               MVM_DEBUGFS_ADD_FILE_VIF(pm_params, mvmvif->dbgfs_dir, S_IWUSR |
+                                        S_IRUSR);
+
        MVM_DEBUGFS_ADD_FILE_VIF(mac_params, mvmvif->dbgfs_dir,
                                 S_IRUSR);
 
+       if (vif->type == NL80211_IFTYPE_STATION && !vif->p2p &&
+           mvmvif == mvm->bf_allowed_vif)
+               MVM_DEBUGFS_ADD_FILE_VIF(bf_params, mvmvif->dbgfs_dir,
+                                        S_IRUSR | S_IWUSR);
+
        /*
         * Create symlink for convenience pointing to interface specific
         * debugfs entries for the driver. For example, under
index 5cb93ae5cd2f73bfff7a1daf5d381f6e9ccc987b..cb78e5539357646089e0db87d7470fcbe8fb681c 100644 (file)
@@ -85,6 +85,8 @@
  *             PBW Snoozing enabled
  * @POWER_FLAGS_ADVANCE_PM_ENA_MSK: Advanced PM (uAPSD) enable mask
  * @POWER_FLAGS_LPRX_ENA_MSK: Low Power RX enable.
+ * @POWER_FLAGS_AP_UAPSD_MISBEHAVING_ENA_MSK: AP/GO's uAPSD misbehaving
+ *             detection enablement
 */
 enum iwl_power_flags {
        POWER_FLAGS_POWER_SAVE_ENA_MSK          = BIT(0),
@@ -94,6 +96,7 @@ enum iwl_power_flags {
        POWER_FLAGS_BT_SCO_ENA                  = BIT(8),
        POWER_FLAGS_ADVANCE_PM_ENA_MSK          = BIT(9),
        POWER_FLAGS_LPRX_ENA_MSK                = BIT(11),
+       POWER_FLAGS_UAPSD_MISBEHAVING_ENA_MSK   = BIT(12),
 };
 
 #define IWL_POWER_VEC_SIZE 5
@@ -228,6 +231,19 @@ struct iwl_mac_power_cmd {
        u8 reserved;
 } __packed;
 
+/*
+ * struct iwl_uapsd_misbehaving_ap_notif - FW sends this notification when
+ * associated AP is identified as improperly implementing uAPSD protocol.
+ * PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION = 0x78
+ * @sta_id: index of station in uCode's station table - associated AP ID in
+ *         this context.
+ */
+struct iwl_uapsd_misbehaving_ap_notif {
+       __le32 sta_id;
+       u8 mac_id;
+       u8 reserved[3];
+} __packed;
+
 /**
  * struct iwl_beacon_filter_cmd
  * REPLY_BEACON_FILTERING_CMD = 0xd2 (command)
index 4aca5933a65d1619fc3e2e419ced4ddddc3d44c1..8c73ba74b6fd1ec1f53cee998492951ccfa51783 100644 (file)
@@ -138,7 +138,14 @@ enum iwl_sta_flags {
 
 /**
  * enum iwl_sta_key_flag - key flags for the ADD_STA host command
- * @STA_KEY_FLG_EN_MSK: mask for encryption algorithm
+ * @STA_KEY_FLG_NO_ENC: no encryption
+ * @STA_KEY_FLG_WEP: WEP encryption algorithm
+ * @STA_KEY_FLG_CCM: CCMP encryption algorithm
+ * @STA_KEY_FLG_TKIP: TKIP encryption algorithm
+ * @STA_KEY_FLG_EXT: extended cipher algorithm (depends on the FW support)
+ * @STA_KEY_FLG_CMAC: CMAC encryption algorithm
+ * @STA_KEY_FLG_ENC_UNKNOWN: unknown encryption algorithm
+ * @STA_KEY_FLG_EN_MSK: mask for encryption algorithmi value
  * @STA_KEY_FLG_WEP_KEY_MAP: wep is either a group key (0 - legacy WEP) or from
  *     station info array (1 - n 1X mode)
  * @STA_KEY_FLG_KEYID_MSK: the index of the key
@@ -152,6 +159,7 @@ enum iwl_sta_key_flag {
        STA_KEY_FLG_WEP                 = (1 << 0),
        STA_KEY_FLG_CCM                 = (2 << 0),
        STA_KEY_FLG_TKIP                = (3 << 0),
+       STA_KEY_FLG_EXT                 = (4 << 0),
        STA_KEY_FLG_CMAC                = (6 << 0),
        STA_KEY_FLG_ENC_UNKNOWN         = (7 << 0),
        STA_KEY_FLG_EN_MSK              = (7 << 0),
index d606197bde8f41aeba9c7580b9c9f4d8dc8dd959..22864671d66c4115c415a1cf38460fc9d6ecffff 100644 (file)
@@ -132,6 +132,7 @@ enum iwl_tx_flags {
 #define TX_CMD_SEC_WEP                 0x01
 #define TX_CMD_SEC_CCM                 0x02
 #define TX_CMD_SEC_TKIP                        0x03
+#define TX_CMD_SEC_EXT                 0x04
 #define TX_CMD_SEC_MSK                 0x07
 #define TX_CMD_SEC_WEP_KEY_IDX_POS     6
 #define TX_CMD_SEC_WEP_KEY_IDX_MSK     0xc0
index bad5a552dd8d10412f5d9d874026215d6c6e9359..1c3079714c2b766f1fabe811027edf620afe6df6 100644 (file)
@@ -141,6 +141,7 @@ enum {
 
        /* Power - legacy power table command */
        POWER_TABLE_CMD = 0x77,
+       PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION = 0x78,
 
        /* Thermal Throttling*/
        REPLY_THERMAL_MNG_BACKOFF = 0x7e,
@@ -183,6 +184,7 @@ enum {
        BT_PROFILE_NOTIFICATION = 0xce,
        BT_COEX_CI = 0x5d,
 
+       REPLY_SF_CFG_CMD = 0xd1,
        REPLY_BEACON_FILTERING_CMD = 0xd2,
 
        REPLY_DEBUG_CMD = 0xf0,
@@ -1052,6 +1054,7 @@ enum iwl_mvm_rx_status {
        RX_MPDU_RES_STATUS_SEC_WEP_ENC                  = (1 << 8),
        RX_MPDU_RES_STATUS_SEC_CCM_ENC                  = (2 << 8),
        RX_MPDU_RES_STATUS_SEC_TKIP_ENC                 = (3 << 8),
+       RX_MPDU_RES_STATUS_SEC_EXT_ENC                  = (4 << 8),
        RX_MPDU_RES_STATUS_SEC_CCM_CMAC_ENC             = (6 << 8),
        RX_MPDU_RES_STATUS_SEC_ENC_ERR                  = (7 << 8),
        RX_MPDU_RES_STATUS_SEC_ENC_MSK                  = (7 << 8),
@@ -1131,6 +1134,7 @@ struct iwl_set_calib_default_cmd {
 } __packed; /* PHY_CALIB_OVERRIDE_VALUES_S */
 
 #define MAX_PORT_ID_NUM        2
+#define MAX_MCAST_FILTERING_ADDRESSES 256
 
 /**
  * struct iwl_mcast_filter_cmd - configure multicast filter.
@@ -1363,4 +1367,65 @@ struct iwl_notif_statistics { /* STATISTICS_NTFY_API_S_VER_8 */
        struct mvm_statistics_general general;
 } __packed;
 
+/***********************************
+ * Smart Fifo API
+ ***********************************/
+/* Smart Fifo state */
+enum iwl_sf_state {
+       SF_LONG_DELAY_ON = 0, /* should never be called by driver */
+       SF_FULL_ON,
+       SF_UNINIT,
+       SF_INIT_OFF,
+       SF_HW_NUM_STATES
+};
+
+/* Smart Fifo possible scenario */
+enum iwl_sf_scenario {
+       SF_SCENARIO_SINGLE_UNICAST,
+       SF_SCENARIO_AGG_UNICAST,
+       SF_SCENARIO_MULTICAST,
+       SF_SCENARIO_BA_RESP,
+       SF_SCENARIO_TX_RESP,
+       SF_NUM_SCENARIO
+};
+
+#define SF_TRANSIENT_STATES_NUMBER 2   /* SF_LONG_DELAY_ON and SF_FULL_ON */
+#define SF_NUM_TIMEOUT_TYPES 2         /* Aging timer and Idle timer */
+
+/* smart FIFO default values */
+#define SF_W_MARK_SISO 4096
+#define SF_W_MARK_MIMO2 8192
+#define SF_W_MARK_MIMO3 6144
+#define SF_W_MARK_LEGACY 4096
+#define SF_W_MARK_SCAN 4096
+
+/* SF Scenarios timers for FULL_ON state (aligned to 32 uSec) */
+#define SF_SINGLE_UNICAST_IDLE_TIMER 320       /* 300 uSec  */
+#define SF_SINGLE_UNICAST_AGING_TIMER 2016     /* 2 mSec */
+#define SF_AGG_UNICAST_IDLE_TIMER 320          /* 300 uSec */
+#define SF_AGG_UNICAST_AGING_TIMER 2016                /* 2 mSec */
+#define SF_MCAST_IDLE_TIMER 2016               /* 2 mSec */
+#define SF_MCAST_AGING_TIMER 10016             /* 10 mSec */
+#define SF_BA_IDLE_TIMER 320                   /* 300 uSec */
+#define SF_BA_AGING_TIMER 2016                 /* 2 mSec */
+#define SF_TX_RE_IDLE_TIMER 320                        /* 300 uSec */
+#define SF_TX_RE_AGING_TIMER 2016              /* 2 mSec */
+
+#define SF_LONG_DELAY_AGING_TIMER 1000000      /* 1 Sec */
+
+/**
+ * Smart Fifo configuration command.
+ * @state: smart fifo state, types listed in iwl_sf_sate.
+ * @watermark: Minimum allowed availabe free space in RXF for transient state.
+ * @long_delay_timeouts: aging and idle timer values for each scenario
+ * in long delay state.
+ * @full_on_timeouts: timer values for each scenario in full on state.
+ */
+struct iwl_sf_cfg_cmd {
+       enum iwl_sf_state state;
+       __le32 watermark[SF_TRANSIENT_STATES_NUMBER];
+       __le32 long_delay_timeouts[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES];
+       __le32 full_on_timeouts[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES];
+} __packed; /* SF_CFG_API_S_VER_2 */
+
 #endif /* __fw_api_h__ */
index 70e5297646b29b9d2410699b53b5daa7ed3fab3a..27ba104a3540e36b23968e0f86f652ea93d0ab4b 100644 (file)
@@ -241,7 +241,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
 
        lockdep_assert_held(&mvm->mutex);
 
-       if (mvm->init_ucode_complete)
+       if (WARN_ON_ONCE(mvm->init_ucode_complete))
                return 0;
 
        iwl_init_notification_wait(&mvm->notif_wait,
@@ -287,7 +287,8 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
                IWL_DEBUG_RF_KILL(mvm,
                                  "jump over all phy activities due to RF kill\n");
                iwl_remove_notification(&mvm->notif_wait, &calib_wait);
-               return 1;
+               ret = 1;
+               goto out;
        }
 
        /* Send TX valid antennas before triggering calibrations */
@@ -319,9 +320,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
 error:
        iwl_remove_notification(&mvm->notif_wait, &calib_wait);
 out:
-       if (!iwlmvm_mod_params.init_dbg) {
-               iwl_trans_stop_device(mvm->trans);
-       } else if (!mvm->nvm_data) {
+       if (iwlmvm_mod_params.init_dbg && !mvm->nvm_data) {
                /* we want to debug INIT and we have no NVM - fake */
                mvm->nvm_data = kzalloc(sizeof(struct iwl_nvm_data) +
                                        sizeof(struct ieee80211_channel) +
@@ -370,11 +369,16 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
                                ret = -ERFKILL;
                        goto error;
                }
-               /* should stop & start HW since that INIT image just loaded */
-               iwl_trans_stop_hw(mvm->trans, false);
-               ret = iwl_trans_start_hw(mvm->trans);
-               if (ret)
-                       return ret;
+               if (!iwlmvm_mod_params.init_dbg) {
+                       /*
+                        * should stop and start HW since that INIT
+                        * image just loaded
+                        */
+                       iwl_trans_stop_device(mvm->trans);
+                       ret = iwl_trans_start_hw(mvm->trans);
+                       if (ret)
+                               return ret;
+               }
        }
 
        if (iwlmvm_mod_params.init_dbg)
@@ -386,6 +390,10 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
                goto error;
        }
 
+       ret = iwl_mvm_sf_update(mvm, NULL, false);
+       if (ret)
+               IWL_ERR(mvm, "Failed to initialize Smart Fifo\n");
+
        ret = iwl_send_tx_ant_cfg(mvm, iwl_fw_valid_tx_ant(mvm->fw));
        if (ret)
                goto error;
index afc4419be46dd1eaff2f1b419dae01e4b231b1cb..2f5269359dced3dd678f7e911c636be20a7a67cb 100644 (file)
@@ -261,6 +261,12 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
 
        mvm->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;
 
+       /* currently FW API supports only one optional cipher scheme */
+       if (mvm->fw->cs && mvm->fw->cs->cipher) {
+               mvm->hw->n_cipher_schemes = 1;
+               mvm->hw->cipher_schemes = mvm->fw->cs;
+       }
+
 #ifdef CONFIG_PM_SLEEP
        if (mvm->fw->img[IWL_UCODE_WOWLAN].sec[0].len &&
            mvm->trans->ops->d3_suspend &&
@@ -399,7 +405,6 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac,
 static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
 {
        iwl_trans_stop_device(mvm->trans);
-       iwl_trans_stop_hw(mvm->trans, false);
 
        mvm->scan_status = IWL_MVM_SCAN_NONE;
 
@@ -471,7 +476,6 @@ static void iwl_mvm_mac_stop(struct ieee80211_hw *hw)
        cancel_work_sync(&mvm->roc_done_wk);
 
        iwl_trans_stop_device(mvm->trans);
-       iwl_trans_stop_hw(mvm->trans, false);
 
        iwl_mvm_async_handlers_purge(mvm);
        /* async_handlers_list is empty and will stay empty: HW is stopped */
@@ -488,17 +492,6 @@ static void iwl_mvm_mac_stop(struct ieee80211_hw *hw)
        cancel_work_sync(&mvm->async_handlers_wk);
 }
 
-static void iwl_mvm_pm_disable_iterator(void *data, u8 *mac,
-                                       struct ieee80211_vif *vif)
-{
-       struct iwl_mvm *mvm = data;
-       int ret;
-
-       ret = iwl_mvm_power_disable(mvm, vif);
-       if (ret)
-               IWL_ERR(mvm, "failed to disable power management\n");
-}
-
 static void iwl_mvm_power_update_iterator(void *data, u8 *mac,
                                          struct ieee80211_vif *vif)
 {
@@ -521,6 +514,20 @@ static struct iwl_mvm_phy_ctxt *iwl_mvm_get_free_phy_ctxt(struct iwl_mvm *mvm)
        return NULL;
 }
 
+static int iwl_mvm_set_tx_power(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+                               s8 tx_power)
+{
+       /* FW is in charge of regulatory enforcement */
+       struct iwl_reduce_tx_power_cmd reduce_txpwr_cmd = {
+               .mac_context_id = iwl_mvm_vif_from_mac80211(vif)->id,
+               .pwr_restriction = cpu_to_le16(tx_power),
+       };
+
+       return iwl_mvm_send_cmd_pdu(mvm, REDUCE_TX_POWER_CMD, CMD_SYNC,
+                                   sizeof(reduce_txpwr_cmd),
+                                   &reduce_txpwr_cmd);
+}
+
 static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
                                     struct ieee80211_vif *vif)
 {
@@ -541,26 +548,9 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
        if (ret)
                goto out_unlock;
 
-       /*
-        * TODO: remove this temporary code.
-        * Currently MVM FW supports power management only on single MAC.
-        * If new interface added, disable PM on existing interface.
-        * P2P device is a special case, since it is handled by FW similary to
-        * scan. If P2P deviced is added, PM remains enabled on existing
-        * interface.
-        * Note: the method below does not count the new interface being added
-        * at this moment.
-        */
+       /* Counting number of interfaces is needed for legacy PM */
        if (vif->type != NL80211_IFTYPE_P2P_DEVICE)
                mvm->vif_count++;
-       if (mvm->vif_count > 1) {
-               IWL_DEBUG_MAC80211(mvm,
-                                  "Disable power on existing interfaces\n");
-               ieee80211_iterate_active_interfaces_atomic(
-                                           mvm->hw,
-                                           IEEE80211_IFACE_ITER_NORMAL,
-                                           iwl_mvm_pm_disable_iterator, mvm);
-       }
 
        /*
         * The AP binding flow can be done only after the beacon
@@ -591,11 +581,7 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
        if (ret)
                goto out_release;
 
-       /*
-        * Update power state on the new interface. Admittedly, based on
-        * mac80211 logics this power update will disable power management
-        */
-       iwl_mvm_power_update_mode(mvm, vif);
+       iwl_mvm_power_disable(mvm, vif);
 
        /* beacon filtering */
        ret = iwl_mvm_disable_beacon_filter(mvm, vif);
@@ -656,9 +642,12 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
  out_release:
        if (vif->type != NL80211_IFTYPE_P2P_DEVICE)
                mvm->vif_count--;
+
+       /* TODO: remove this when legacy PM will be discarded */
        ieee80211_iterate_active_interfaces(
                mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
                iwl_mvm_power_update_iterator, mvm);
+
        iwl_mvm_mac_ctxt_release(mvm, vif);
  out_unlock:
        mutex_unlock(&mvm->mutex);
@@ -744,21 +733,13 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,
                mvmvif->phy_ctxt = NULL;
        }
 
-       /*
-        * TODO: remove this temporary code.
-        * Currently MVM FW supports power management only on single MAC.
-        * Check if only one additional interface remains after removing
-        * current one. Update power mode on the remaining interface.
-        */
        if (mvm->vif_count && vif->type != NL80211_IFTYPE_P2P_DEVICE)
                mvm->vif_count--;
-       IWL_DEBUG_MAC80211(mvm, "Currently %d interfaces active\n",
-                          mvm->vif_count);
-       if (mvm->vif_count == 1) {
-               ieee80211_iterate_active_interfaces(
-                                       mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
-                                       iwl_mvm_power_update_iterator, mvm);
-       }
+
+       /* TODO: remove this when legacy PM will be discarded */
+       ieee80211_iterate_active_interfaces(
+               mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
+               iwl_mvm_power_update_iterator, mvm);
 
        iwl_mvm_mac_ctxt_remove(mvm, vif);
 
@@ -767,23 +748,91 @@ out_release:
        mutex_unlock(&mvm->mutex);
 }
 
-static int iwl_mvm_set_tx_power(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
-                               s8 tx_power)
+static int iwl_mvm_mac_config(struct ieee80211_hw *hw, u32 changed)
 {
-       /* FW is in charge of regulatory enforcement */
-       struct iwl_reduce_tx_power_cmd reduce_txpwr_cmd = {
-               .mac_context_id = iwl_mvm_vif_from_mac80211(vif)->id,
-               .pwr_restriction = cpu_to_le16(tx_power),
+       return 0;
+}
+
+struct iwl_mvm_mc_iter_data {
+       struct iwl_mvm *mvm;
+       int port_id;
+};
+
+static void iwl_mvm_mc_iface_iterator(void *_data, u8 *mac,
+                                     struct ieee80211_vif *vif)
+{
+       struct iwl_mvm_mc_iter_data *data = _data;
+       struct iwl_mvm *mvm = data->mvm;
+       struct iwl_mcast_filter_cmd *cmd = mvm->mcast_filter_cmd;
+       int ret, len;
+
+       /* if we don't have free ports, mcast frames will be dropped */
+       if (WARN_ON_ONCE(data->port_id >= MAX_PORT_ID_NUM))
+               return;
+
+       if (vif->type != NL80211_IFTYPE_STATION ||
+           !vif->bss_conf.assoc)
+               return;
+
+       cmd->port_id = data->port_id++;
+       memcpy(cmd->bssid, vif->bss_conf.bssid, ETH_ALEN);
+       len = roundup(sizeof(*cmd) + cmd->count * ETH_ALEN, 4);
+
+       ret = iwl_mvm_send_cmd_pdu(mvm, MCAST_FILTER_CMD, CMD_SYNC, len, cmd);
+       if (ret)
+               IWL_ERR(mvm, "mcast filter cmd error. ret=%d\n", ret);
+}
+
+static void iwl_mvm_recalc_multicast(struct iwl_mvm *mvm)
+{
+       struct iwl_mvm_mc_iter_data iter_data = {
+               .mvm = mvm,
        };
 
-       return iwl_mvm_send_cmd_pdu(mvm, REDUCE_TX_POWER_CMD, CMD_SYNC,
-                                   sizeof(reduce_txpwr_cmd),
-                                   &reduce_txpwr_cmd);
+       lockdep_assert_held(&mvm->mutex);
+
+       if (WARN_ON_ONCE(!mvm->mcast_filter_cmd))
+               return;
+
+       ieee80211_iterate_active_interfaces(
+               mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
+               iwl_mvm_mc_iface_iterator, &iter_data);
 }
 
-static int iwl_mvm_mac_config(struct ieee80211_hw *hw, u32 changed)
+static u64 iwl_mvm_prepare_multicast(struct ieee80211_hw *hw,
+                                    struct netdev_hw_addr_list *mc_list)
 {
-       return 0;
+       struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+       struct iwl_mcast_filter_cmd *cmd;
+       struct netdev_hw_addr *addr;
+       int addr_count = netdev_hw_addr_list_count(mc_list);
+       bool pass_all = false;
+       int len;
+
+       if (addr_count > MAX_MCAST_FILTERING_ADDRESSES) {
+               pass_all = true;
+               addr_count = 0;
+       }
+
+       len = roundup(sizeof(*cmd) + addr_count * ETH_ALEN, 4);
+       cmd = kzalloc(len, GFP_ATOMIC);
+       if (!cmd)
+               return 0;
+
+       if (pass_all) {
+               cmd->pass_all = 1;
+               return (u64)(unsigned long)cmd;
+       }
+
+       netdev_hw_addr_list_for_each(addr, mc_list) {
+               IWL_DEBUG_MAC80211(mvm, "mcast addr (%d): %pM\n",
+                                  cmd->count, addr->addr);
+               memcpy(&cmd->addr_list[cmd->count * ETH_ALEN],
+                      addr->addr, ETH_ALEN);
+               cmd->count++;
+       }
+
+       return (u64)(unsigned long)cmd;
 }
 
 static void iwl_mvm_configure_filter(struct ieee80211_hw *hw,
@@ -791,21 +840,22 @@ static void iwl_mvm_configure_filter(struct ieee80211_hw *hw,
                                     unsigned int *total_flags,
                                     u64 multicast)
 {
-       *total_flags = 0;
-}
+       struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+       struct iwl_mcast_filter_cmd *cmd = (void *)(unsigned long)multicast;
 
-static int iwl_mvm_configure_mcast_filter(struct iwl_mvm *mvm,
-                                         struct ieee80211_vif *vif)
-{
-       struct iwl_mcast_filter_cmd mcast_filter_cmd = {
-               .pass_all = 1,
-       };
+       mutex_lock(&mvm->mutex);
+
+       /* replace previous configuration */
+       kfree(mvm->mcast_filter_cmd);
+       mvm->mcast_filter_cmd = cmd;
 
-       memcpy(mcast_filter_cmd.bssid, vif->bss_conf.bssid, ETH_ALEN);
+       if (!cmd)
+               goto out;
 
-       return iwl_mvm_send_cmd_pdu(mvm, MCAST_FILTER_CMD, CMD_SYNC,
-                                   sizeof(mcast_filter_cmd),
-                                   &mcast_filter_cmd);
+       iwl_mvm_recalc_multicast(mvm);
+out:
+       mutex_unlock(&mvm->mutex);
+       *total_flags = 0;
 }
 
 static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
@@ -828,7 +878,6 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
                                IWL_ERR(mvm, "failed to update quotas\n");
                                return;
                        }
-                       iwl_mvm_configure_mcast_filter(mvm, vif);
 
                        if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART,
                                     &mvm->status)) {
@@ -850,7 +899,17 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
                                iwl_mvm_protect_session(mvm, vif, dur, dur,
                                                        5 * dur);
                        }
+
+                       iwl_mvm_sf_update(mvm, vif, false);
+                       iwl_mvm_power_vif_assoc(mvm, vif);
                } else if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) {
+                       /*
+                        * If update fails - SF might be running in associated
+                        * mode while disassociated - which is forbidden.
+                        */
+                       WARN_ONCE(iwl_mvm_sf_update(mvm, vif, false),
+                                 "Failed to update SF upon disassociation\n");
+
                        /* remove AP station now that the MAC is unassoc */
                        ret = iwl_mvm_rm_sta_id(mvm, vif, mvmvif->ap_sta_id);
                        if (ret)
@@ -862,6 +921,8 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
                                IWL_ERR(mvm, "failed to update quotas\n");
                }
 
+               iwl_mvm_recalc_multicast(mvm);
+
                /* reset rssi values */
                mvmvif->bf_data.ave_beacon_signal = 0;
 
@@ -882,7 +943,8 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
                 */
                iwl_mvm_remove_time_event(mvm, mvmvif,
                                          &mvmvif->time_event_data);
-       } else if (changes & (BSS_CHANGED_PS | BSS_CHANGED_QOS)) {
+       } else if (changes & (BSS_CHANGED_PS | BSS_CHANGED_P2P_PS |
+                             BSS_CHANGED_QOS)) {
                ret = iwl_mvm_power_update_mode(mvm, vif);
                if (ret)
                        IWL_ERR(mvm, "failed to update power mode\n");
@@ -991,11 +1053,16 @@ iwl_mvm_bss_info_changed_ap_ibss(struct iwl_mvm *mvm,
                                 struct ieee80211_bss_conf *bss_conf,
                                 u32 changes)
 {
+       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
        enum ieee80211_bss_change ht_change = BSS_CHANGED_ERP_CTS_PROT |
                                              BSS_CHANGED_HT |
                                              BSS_CHANGED_BANDWIDTH;
        int ret;
 
+       /* Changes will be applied when the AP/IBSS is started */
+       if (!mvmvif->ap_ibss_active)
+               return;
+
        if (changes & ht_change) {
                ret = iwl_mvm_mac_ctxt_changed(mvm, vif);
                if (ret)
@@ -1114,6 +1181,28 @@ static void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw,
        }
 }
 
+static void iwl_mvm_sta_pre_rcu_remove(struct ieee80211_hw *hw,
+                                      struct ieee80211_vif *vif,
+                                      struct ieee80211_sta *sta)
+{
+       struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+       struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv;
+
+       /*
+        * This is called before mac80211 does RCU synchronisation,
+        * so here we already invalidate our internal RCU-protected
+        * station pointer. The rest of the code will thus no longer
+        * be able to find the station this way, and we don't rely
+        * on further RCU synchronisation after the sta_state()
+        * callback deleted the station.
+        */
+       mutex_lock(&mvm->mutex);
+       if (sta == rcu_access_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id]))
+               rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id],
+                                  ERR_PTR(-ENOENT));
+       mutex_unlock(&mvm->mutex);
+}
+
 static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
                                 struct ieee80211_vif *vif,
                                 struct ieee80211_sta *sta,
@@ -1200,6 +1289,17 @@ static int iwl_mvm_mac_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
        return 0;
 }
 
+static void iwl_mvm_sta_rc_update(struct ieee80211_hw *hw,
+                                 struct ieee80211_vif *vif,
+                                 struct ieee80211_sta *sta, u32 changed)
+{
+       struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+
+       if (vif->type == NL80211_IFTYPE_STATION &&
+           changed & IEEE80211_RC_NSS_CHANGED)
+               iwl_mvm_sf_update(mvm, vif, false);
+}
+
 static int iwl_mvm_mac_conf_tx(struct ieee80211_hw *hw,
                               struct ieee80211_vif *vif, u16 ac,
                               const struct ieee80211_tx_queue_params *params)
@@ -1322,7 +1422,12 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
                 */
                return 0;
        default:
-               return -EOPNOTSUPP;
+               /* currently FW supports only one optional cipher scheme */
+               if (hw->n_cipher_schemes &&
+                   hw->cipher_schemes->cipher == key->cipher)
+                       key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;
+               else
+                       return -EOPNOTSUPP;
        }
 
        mutex_lock(&mvm->mutex);
@@ -1528,7 +1633,7 @@ static int iwl_mvm_add_chanctx(struct ieee80211_hw *hw,
                goto out;
        }
 
-       ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx->def,
+       ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx->min_def,
                                       ctx->rx_chains_static,
                                       ctx->rx_chains_dynamic);
        if (ret) {
@@ -1572,7 +1677,7 @@ static void iwl_mvm_change_chanctx(struct ieee80211_hw *hw,
                return;
 
        mutex_lock(&mvm->mutex);
-       iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx->def,
+       iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx->min_def,
                                 ctx->rx_chains_static,
                                 ctx->rx_chains_dynamic);
        iwl_mvm_bt_coex_vif_change(mvm);
@@ -1615,7 +1720,13 @@ static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw,
                goto out_unlock;
 
        /*
-        * Setting the quota at this stage is only required for monitor
+        * Power state must be updated before quotas,
+        * otherwise fw will complain.
+        */
+       mvm->bound_vif_cnt++;
+       iwl_mvm_power_update_binding(mvm, vif, true);
+
+       /* Setting the quota at this stage is only required for monitor
         * interfaces. For the other types, the bss_info changed flow
         * will handle quota settings.
         */
@@ -1630,6 +1741,8 @@ static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw,
 
  out_remove_binding:
        iwl_mvm_binding_remove_vif(mvm, vif);
+       mvm->bound_vif_cnt--;
+       iwl_mvm_power_update_binding(mvm, vif, false);
  out_unlock:
        mutex_unlock(&mvm->mutex);
        if (ret)
@@ -1663,6 +1776,9 @@ static void iwl_mvm_unassign_vif_chanctx(struct ieee80211_hw *hw,
        iwl_mvm_binding_remove_vif(mvm, vif);
 out_unlock:
        mvmvif->phy_ctxt = NULL;
+       mvm->bound_vif_cnt--;
+       iwl_mvm_power_update_binding(mvm, vif, false);
+
        mutex_unlock(&mvm->mutex);
 }
 
@@ -1757,14 +1873,17 @@ struct ieee80211_ops iwl_mvm_hw_ops = {
        .add_interface = iwl_mvm_mac_add_interface,
        .remove_interface = iwl_mvm_mac_remove_interface,
        .config = iwl_mvm_mac_config,
+       .prepare_multicast = iwl_mvm_prepare_multicast,
        .configure_filter = iwl_mvm_configure_filter,
        .bss_info_changed = iwl_mvm_bss_info_changed,
        .hw_scan = iwl_mvm_mac_hw_scan,
        .cancel_hw_scan = iwl_mvm_mac_cancel_hw_scan,
+       .sta_pre_rcu_remove = iwl_mvm_sta_pre_rcu_remove,
        .sta_state = iwl_mvm_mac_sta_state,
        .sta_notify = iwl_mvm_mac_sta_notify,
        .allow_buffered_frames = iwl_mvm_mac_allow_buffered_frames,
        .set_rts_threshold = iwl_mvm_mac_set_rts_threshold,
+       .sta_rc_update = iwl_mvm_sta_rc_update,
        .conf_tx = iwl_mvm_mac_conf_tx,
        .mgd_prepare_tx = iwl_mvm_mac_mgd_prepare_tx,
        .sched_scan_start = iwl_mvm_mac_sched_scan_start,
index 7dc57cfe58035cfc5128e1fa8f3969f46584d7c9..84edf3649ad29bdafb21ff2fda366d1ce46b53dc 100644 (file)
@@ -163,6 +163,8 @@ struct iwl_mvm_power_ops {
                                 struct ieee80211_vif *vif);
        int (*power_update_device_mode)(struct iwl_mvm *mvm);
        int (*power_disable)(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
+       void (*power_update_binding)(struct iwl_mvm *mvm,
+                                    struct ieee80211_vif *vif, bool assign);
 #ifdef CONFIG_IWLWIFI_DEBUGFS
        int (*power_dbgfs_read)(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
                                char *buf, int bufsz);
@@ -181,6 +183,7 @@ enum iwl_dbgfs_pm_mask {
        MVM_DEBUGFS_PM_LPRX_ENA = BIT(6),
        MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD = BIT(7),
        MVM_DEBUGFS_PM_SNOOZE_ENABLE = BIT(8),
+       MVM_DEBUGFS_PM_UAPSD_MISBEHAVING = BIT(9),
 };
 
 struct iwl_dbgfs_pm {
@@ -193,6 +196,7 @@ struct iwl_dbgfs_pm {
        bool lprx_ena;
        u32 lprx_rssi_threshold;
        bool snooze_ena;
+       bool uapsd_misbehaving;
        int mask;
 };
 
@@ -269,8 +273,8 @@ struct iwl_mvm_vif_bf_data {
  * @bcast_sta: station used for broadcast packets. Used by the following
  *  vifs: P2P_DEVICE, GO and AP.
  * @beacon_skb: the skb used to hold the AP/GO beacon template
- * @smps_requests: the requests of of differents parts of the driver, regard
      the desired smps mode.
+ * @smps_requests: the SMPS requests of differents parts of the driver,
*     combined on update to yield the overall request to mac80211.
  */
 struct iwl_mvm_vif {
        u16 id;
@@ -331,6 +335,11 @@ struct iwl_mvm_vif {
 #endif
 
        enum ieee80211_smps_mode smps_requests[NUM_IWL_MVM_SMPS_REQ];
+
+       /* FW identified misbehaving AP */
+       u8 uapsd_misbehaving_bssid[ETH_ALEN];
+
+       bool pm_prevented;
 };
 
 static inline struct iwl_mvm_vif *
@@ -479,6 +488,7 @@ struct iwl_mvm {
        /* Scan status, cmd (pre-allocated) and auxiliary station */
        enum iwl_scan_status scan_status;
        struct iwl_scan_cmd *scan_cmd;
+       struct iwl_mcast_filter_cmd *mcast_filter_cmd;
 
        /* rx chain antennas set through debugfs for the scan command */
        u8 scan_rx_ant;
@@ -489,6 +499,9 @@ struct iwl_mvm {
        u8 scan_last_antenna_idx; /* to toggle TX between antennas */
        u8 mgmt_last_antenna_idx;
 
+       /* last smart fifo state that was successfully sent to firmware */
+       enum iwl_sf_state sf_state;
+
 #ifdef CONFIG_IWLWIFI_DEBUGFS
        struct dentry *debugfs_dir;
        u32 dbgfs_sram_offset, dbgfs_sram_len;
@@ -512,12 +525,6 @@ struct iwl_mvm {
         */
        unsigned long fw_key_table[BITS_TO_LONGS(STA_KEY_MAX_NUM)];
 
-       /*
-        * This counter of created interfaces is referenced only in conjunction
-        * with FW limitation related to power management. Currently PM is
-        * supported only on a single interface.
-        * IMPORTANT: this variable counts all interfaces except P2P device.
-        */
        u8 vif_count;
 
        /* -1 for always, 0 for never, >0 for that many times */
@@ -560,6 +567,11 @@ struct iwl_mvm {
        u8 aux_queue;
        u8 first_agg_queue;
        u8 last_agg_queue;
+
+       u8 bound_vif_cnt;
+
+       /* Indicate if device power save is allowed */
+       bool ps_prevented;
 };
 
 /* Extract MVM priv from op_mode and _hw */
@@ -778,6 +790,19 @@ static inline int iwl_mvm_power_update_device_mode(struct iwl_mvm *mvm)
        return 0;
 }
 
+static inline void iwl_mvm_power_update_binding(struct iwl_mvm *mvm,
+                                               struct ieee80211_vif *vif,
+                                               bool assign)
+{
+       if (mvm->pm_ops->power_update_binding)
+               mvm->pm_ops->power_update_binding(mvm, vif, assign);
+}
+
+void iwl_mvm_power_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
+int iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm,
+                                            struct iwl_rx_cmd_buffer *rxb,
+                                            struct iwl_device_cmd *cmd);
+
 #ifdef CONFIG_IWLWIFI_DEBUGFS
 static inline int iwl_mvm_power_dbgfs_read(struct iwl_mvm *mvm,
                                            struct ieee80211_vif *vif,
@@ -869,4 +894,8 @@ void iwl_mvm_tt_initialize(struct iwl_mvm *mvm);
 void iwl_mvm_tt_exit(struct iwl_mvm *mvm);
 void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state);
 
+/* smart fifo */
+int iwl_mvm_sf_update(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+                     bool added_vif);
+
 #endif /* __IWL_MVM_H__ */
index d86083c6f445ac40cbcf824df4892b597ee11f35..a362430477a006c01d69ade2ecbc7d916fc9c2ef 100644 (file)
@@ -236,6 +236,8 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {
                   false),
 
        RX_HANDLER(REPLY_ERROR, iwl_mvm_rx_fw_error, false),
+       RX_HANDLER(PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION,
+                  iwl_mvm_power_uapsd_misbehaving_ap_notif, false),
 };
 #undef RX_HANDLER
 #define CMD(x) [x] = #x
@@ -311,6 +313,7 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = {
        CMD(REPLY_THERMAL_MNG_BACKOFF),
        CMD(MAC_PM_POWER_TABLE),
        CMD(BT_COEX_CI),
+       CMD(PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION),
 };
 #undef CMD
 
@@ -341,7 +344,6 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
 
        op_mode = hw->priv;
        op_mode->ops = &iwl_mvm_ops;
-       op_mode->trans = trans;
 
        mvm = IWL_OP_MODE_GET_MVM(op_mode);
        mvm->dev = trans->dev;
@@ -359,6 +361,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
                mvm->aux_queue = 11;
                mvm->first_agg_queue = 12;
        }
+       mvm->sf_state = SF_UNINIT;
 
        mutex_init(&mvm->mutex);
        spin_lock_init(&mvm->async_handlers_lock);
@@ -424,7 +427,9 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
         * there is no need to unnecessarily power up the NIC at driver load
         */
        if (iwlwifi_mod_params.nvm_file) {
-                       iwl_nvm_init(mvm);
+               err = iwl_nvm_init(mvm);
+               if (err)
+                       goto out_free;
        } else {
                err = iwl_trans_start_hw(mvm->trans);
                if (err)
@@ -432,16 +437,13 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
 
                mutex_lock(&mvm->mutex);
                err = iwl_run_init_mvm_ucode(mvm, true);
+               iwl_trans_stop_device(trans);
                mutex_unlock(&mvm->mutex);
                /* returns 0 if successful, 1 if success but in rfkill */
                if (err < 0 && !iwlmvm_mod_params.init_dbg) {
                        IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", err);
                        goto out_free;
                }
-
-               /* Stop the hw after the ALIVE and NVM has been read */
-               if (!iwlmvm_mod_params.init_dbg)
-                       iwl_trans_stop_hw(mvm->trans, false);
        }
 
        scan_size = sizeof(struct iwl_scan_cmd) +
@@ -474,7 +476,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
        iwl_phy_db_free(mvm->phy_db);
        kfree(mvm->scan_cmd);
        if (!iwlwifi_mod_params.nvm_file)
-               iwl_trans_stop_hw(trans, true);
+               iwl_trans_op_mode_leave(trans);
        ieee80211_free_hw(mvm->hw);
        return NULL;
 }
@@ -491,12 +493,14 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode)
        ieee80211_unregister_hw(mvm->hw);
 
        kfree(mvm->scan_cmd);
+       kfree(mvm->mcast_filter_cmd);
+       mvm->mcast_filter_cmd = NULL;
 
 #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_IWLWIFI_DEBUGFS)
        kfree(mvm->d3_resume_sram);
 #endif
 
-       iwl_trans_stop_hw(mvm->trans, true);
+       iwl_trans_op_mode_leave(mvm->trans);
 
        iwl_phy_db_free(mvm->phy_db);
        mvm->phy_db = NULL;
index 550824aa84ea4bde8794b267bda27401c6b6f058..483ecc67501fc359682599dbc4173c7cc5a59128 100644 (file)
@@ -186,6 +186,92 @@ static void iwl_mvm_power_log(struct iwl_mvm *mvm,
        }
 }
 
+static void iwl_mvm_power_configure_uapsd(struct iwl_mvm *mvm,
+                                         struct ieee80211_vif *vif,
+                                         struct iwl_mac_power_cmd *cmd)
+{
+       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+       enum ieee80211_ac_numbers ac;
+       bool tid_found = false;
+
+       for (ac = IEEE80211_AC_VO; ac <= IEEE80211_AC_BK; ac++) {
+               if (!mvmvif->queue_params[ac].uapsd)
+                       continue;
+
+               if (mvm->cur_ucode != IWL_UCODE_WOWLAN)
+                       cmd->flags |=
+                               cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK);
+
+               cmd->uapsd_ac_flags |= BIT(ac);
+
+               /* QNDP TID - the highest TID with no admission control */
+               if (!tid_found && !mvmvif->queue_params[ac].acm) {
+                       tid_found = true;
+                       switch (ac) {
+                       case IEEE80211_AC_VO:
+                               cmd->qndp_tid = 6;
+                               break;
+                       case IEEE80211_AC_VI:
+                               cmd->qndp_tid = 5;
+                               break;
+                       case IEEE80211_AC_BE:
+                               cmd->qndp_tid = 0;
+                               break;
+                       case IEEE80211_AC_BK:
+                               cmd->qndp_tid = 1;
+                               break;
+                       }
+               }
+       }
+
+       if (!(cmd->flags & cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK)))
+               return;
+
+       cmd->flags |= cpu_to_le16(POWER_FLAGS_UAPSD_MISBEHAVING_ENA_MSK);
+
+       if (cmd->uapsd_ac_flags == (BIT(IEEE80211_AC_VO) |
+                                   BIT(IEEE80211_AC_VI) |
+                                   BIT(IEEE80211_AC_BE) |
+                                   BIT(IEEE80211_AC_BK))) {
+               cmd->flags |= cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK);
+               cmd->snooze_interval = cpu_to_le16(IWL_MVM_PS_SNOOZE_INTERVAL);
+               cmd->snooze_window = (mvm->cur_ucode == IWL_UCODE_WOWLAN) ?
+                       cpu_to_le16(IWL_MVM_WOWLAN_PS_SNOOZE_WINDOW) :
+                       cpu_to_le16(IWL_MVM_PS_SNOOZE_WINDOW);
+       }
+
+       cmd->uapsd_max_sp = IWL_UAPSD_MAX_SP;
+
+       if (mvm->cur_ucode == IWL_UCODE_WOWLAN || cmd->flags &
+           cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK)) {
+               cmd->rx_data_timeout_uapsd =
+                       cpu_to_le32(IWL_MVM_WOWLAN_PS_RX_DATA_TIMEOUT);
+               cmd->tx_data_timeout_uapsd =
+                       cpu_to_le32(IWL_MVM_WOWLAN_PS_TX_DATA_TIMEOUT);
+       } else {
+               cmd->rx_data_timeout_uapsd =
+                       cpu_to_le32(IWL_MVM_UAPSD_RX_DATA_TIMEOUT);
+               cmd->tx_data_timeout_uapsd =
+                       cpu_to_le32(IWL_MVM_UAPSD_TX_DATA_TIMEOUT);
+       }
+
+       if (cmd->flags & cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK)) {
+               cmd->heavy_tx_thld_packets =
+                       IWL_MVM_PS_SNOOZE_HEAVY_TX_THLD_PACKETS;
+               cmd->heavy_rx_thld_packets =
+                       IWL_MVM_PS_SNOOZE_HEAVY_RX_THLD_PACKETS;
+       } else {
+               cmd->heavy_tx_thld_packets =
+                       IWL_MVM_PS_HEAVY_TX_THLD_PACKETS;
+               cmd->heavy_rx_thld_packets =
+                       IWL_MVM_PS_HEAVY_RX_THLD_PACKETS;
+       }
+       cmd->heavy_tx_thld_percentage =
+               IWL_MVM_PS_HEAVY_TX_THLD_PERCENT;
+       cmd->heavy_rx_thld_percentage =
+               IWL_MVM_PS_HEAVY_RX_THLD_PERCENT;
+}
+
 static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
                                    struct ieee80211_vif *vif,
                                    struct iwl_mac_power_cmd *cmd)
@@ -198,8 +284,7 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
        bool radar_detect = false;
        struct iwl_mvm_vif *mvmvif __maybe_unused =
                iwl_mvm_vif_from_mac80211(vif);
-       enum ieee80211_ac_numbers ac;
-       bool tid_found = false;
+       bool allow_uapsd = true;
 
        cmd->id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,
                                                            mvmvif->color));
@@ -217,7 +302,8 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
        keep_alive = DIV_ROUND_UP(keep_alive, MSEC_PER_SEC);
        cmd->keep_alive_seconds = cpu_to_le16(keep_alive);
 
-       if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM)
+       if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM ||
+           mvm->ps_prevented)
                return;
 
        cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK);
@@ -227,7 +313,7 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
            mvmvif->dbgfs_pm.disable_power_off)
                cmd->flags &= cpu_to_le16(~POWER_FLAGS_POWER_SAVE_ENA_MSK);
 #endif
-       if (!vif->bss_conf.ps)
+       if (!vif->bss_conf.ps || mvmvif->pm_prevented)
                return;
 
        cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK);
@@ -269,81 +355,24 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
                        cpu_to_le32(IWL_MVM_WOWLAN_PS_TX_DATA_TIMEOUT);
        }
 
-       for (ac = IEEE80211_AC_VO; ac <= IEEE80211_AC_BK; ac++) {
-               if (!mvmvif->queue_params[ac].uapsd)
-                       continue;
-
-               if (mvm->cur_ucode != IWL_UCODE_WOWLAN)
-                       cmd->flags |=
-                               cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK);
-
-               cmd->uapsd_ac_flags |= BIT(ac);
+       if (!memcmp(mvmvif->uapsd_misbehaving_bssid, vif->bss_conf.bssid,
+                   ETH_ALEN))
+               allow_uapsd = false;
 
-               /* QNDP TID - the highest TID with no admission control */
-               if (!tid_found && !mvmvif->queue_params[ac].acm) {
-                       tid_found = true;
-                       switch (ac) {
-                       case IEEE80211_AC_VO:
-                               cmd->qndp_tid = 6;
-                               break;
-                       case IEEE80211_AC_VI:
-                               cmd->qndp_tid = 5;
-                               break;
-                       case IEEE80211_AC_BE:
-                               cmd->qndp_tid = 0;
-                               break;
-                       case IEEE80211_AC_BK:
-                               cmd->qndp_tid = 1;
-                               break;
-                       }
-               }
-       }
-
-       if (cmd->flags & cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK)) {
-               if (cmd->uapsd_ac_flags == (BIT(IEEE80211_AC_VO) |
-                                           BIT(IEEE80211_AC_VI) |
-                                           BIT(IEEE80211_AC_BE) |
-                                           BIT(IEEE80211_AC_BK))) {
-                       cmd->flags |= cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK);
-                       cmd->snooze_interval =
-                               cpu_to_le16(IWL_MVM_PS_SNOOZE_INTERVAL);
-                       cmd->snooze_window =
-                               (mvm->cur_ucode == IWL_UCODE_WOWLAN) ?
-                               cpu_to_le16(IWL_MVM_WOWLAN_PS_SNOOZE_WINDOW) :
-                               cpu_to_le16(IWL_MVM_PS_SNOOZE_WINDOW);
-               }
-
-               cmd->uapsd_max_sp = IWL_UAPSD_MAX_SP;
-
-               if (mvm->cur_ucode == IWL_UCODE_WOWLAN || cmd->flags &
-                   cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK)) {
-                       cmd->rx_data_timeout_uapsd =
-                               cpu_to_le32(IWL_MVM_WOWLAN_PS_RX_DATA_TIMEOUT);
-                       cmd->tx_data_timeout_uapsd =
-                               cpu_to_le32(IWL_MVM_WOWLAN_PS_TX_DATA_TIMEOUT);
-               } else {
-                       cmd->rx_data_timeout_uapsd =
-                               cpu_to_le32(IWL_MVM_UAPSD_RX_DATA_TIMEOUT);
-                       cmd->tx_data_timeout_uapsd =
-                               cpu_to_le32(IWL_MVM_UAPSD_TX_DATA_TIMEOUT);
-               }
+       if (vif->p2p &&
+           !(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD))
+               allow_uapsd = false;
+       /*
+        * Avoid using uAPSD if P2P client is associated to GO that uses
+        * opportunistic power save. This is due to current FW limitation.
+        */
+       if (vif->p2p &&
+           vif->bss_conf.p2p_noa_attr.oppps_ctwindow &
+           IEEE80211_P2P_OPPPS_ENABLE_BIT)
+               allow_uapsd = false;
 
-               if (cmd->flags & cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK)) {
-                       cmd->heavy_tx_thld_packets =
-                               IWL_MVM_PS_SNOOZE_HEAVY_TX_THLD_PACKETS;
-                       cmd->heavy_rx_thld_packets =
-                               IWL_MVM_PS_SNOOZE_HEAVY_RX_THLD_PACKETS;
-               } else {
-                       cmd->heavy_tx_thld_packets =
-                               IWL_MVM_PS_HEAVY_TX_THLD_PACKETS;
-                       cmd->heavy_rx_thld_packets =
-                               IWL_MVM_PS_HEAVY_RX_THLD_PACKETS;
-               }
-               cmd->heavy_tx_thld_percentage =
-                       IWL_MVM_PS_HEAVY_TX_THLD_PERCENT;
-               cmd->heavy_rx_thld_percentage =
-                       IWL_MVM_PS_HEAVY_RX_THLD_PERCENT;
-       }
+       if (allow_uapsd)
+               iwl_mvm_power_configure_uapsd(mvm, vif, cmd);
 
 #ifdef CONFIG_IWLWIFI_DEBUGFS
        if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_KEEP_ALIVE)
@@ -381,6 +410,13 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
                        cmd->flags &=
                                cpu_to_le16(~POWER_FLAGS_SNOOZE_ENA_MSK);
        }
+       if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_UAPSD_MISBEHAVING) {
+               u16 flag = POWER_FLAGS_UAPSD_MISBEHAVING_ENA_MSK;
+               if (mvmvif->dbgfs_pm.uapsd_misbehaving)
+                       cmd->flags |= cpu_to_le16(flag);
+               else
+                       cmd->flags &= cpu_to_le16(flag);
+       }
 #endif /* CONFIG_IWLWIFI_DEBUGFS */
 }
 
@@ -391,18 +427,11 @@ static int iwl_mvm_power_mac_update_mode(struct iwl_mvm *mvm,
        bool ba_enable;
        struct iwl_mac_power_cmd cmd = {};
 
-       if (vif->type != NL80211_IFTYPE_STATION || vif->p2p)
+       if (vif->type != NL80211_IFTYPE_STATION)
                return 0;
 
-       /*
-        * TODO: The following vif_count verification is temporary condition.
-        * Avoid power mode update if more than one interface is currently
-        * active. Remove this condition when FW will support power management
-        * on multiple MACs.
-        */
-       IWL_DEBUG_POWER(mvm, "Currently %d interfaces active\n",
-                       mvm->vif_count);
-       if (mvm->vif_count > 1)
+       if (vif->p2p &&
+           !(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_P2P_PS))
                return 0;
 
        iwl_mvm_power_build_cmd(mvm, vif, &cmd);
@@ -446,7 +475,7 @@ static int iwl_mvm_power_mac_disable(struct iwl_mvm *mvm,
                                    sizeof(cmd), &cmd);
 }
 
-static int iwl_mvm_power_update_device(struct iwl_mvm *mvm)
+static int _iwl_mvm_power_update_device(struct iwl_mvm *mvm, bool force_disable)
 {
        struct iwl_device_power_cmd cmd = {
                .flags = cpu_to_le16(DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK),
@@ -455,7 +484,8 @@ static int iwl_mvm_power_update_device(struct iwl_mvm *mvm)
        if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD))
                return 0;
 
-       if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM)
+       if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM ||
+           force_disable)
                cmd.flags |= cpu_to_le16(DEVICE_POWER_FLAGS_CAM_MSK);
 
 #ifdef CONFIG_IWLWIFI_DEBUGFS
@@ -472,6 +502,78 @@ static int iwl_mvm_power_update_device(struct iwl_mvm *mvm)
                                    &cmd);
 }
 
+static int iwl_mvm_power_update_device(struct iwl_mvm *mvm)
+{
+       return _iwl_mvm_power_update_device(mvm, false);
+}
+
+void iwl_mvm_power_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
+{
+       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
+       if (memcmp(vif->bss_conf.bssid, mvmvif->uapsd_misbehaving_bssid,
+                  ETH_ALEN))
+               memset(mvmvif->uapsd_misbehaving_bssid, 0, ETH_ALEN);
+}
+
+static void iwl_mvm_power_uapsd_misbehav_ap_iterator(void *_data, u8 *mac,
+                                                    struct ieee80211_vif *vif)
+{
+       u8 *ap_sta_id = _data;
+       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
+       /* The ap_sta_id is not expected to change during current association
+        * so no explicit protection is needed
+        */
+       if (mvmvif->ap_sta_id == *ap_sta_id)
+               memcpy(mvmvif->uapsd_misbehaving_bssid, vif->bss_conf.bssid,
+                      ETH_ALEN);
+}
+
+int iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm,
+                                            struct iwl_rx_cmd_buffer *rxb,
+                                            struct iwl_device_cmd *cmd)
+{
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       struct iwl_uapsd_misbehaving_ap_notif *notif = (void *)pkt->data;
+       u8 ap_sta_id = le32_to_cpu(notif->sta_id);
+
+       ieee80211_iterate_active_interfaces_atomic(
+               mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
+               iwl_mvm_power_uapsd_misbehav_ap_iterator, &ap_sta_id);
+
+       return 0;
+}
+
+static void iwl_mvm_power_binding_iterator(void *_data, u8 *mac,
+                                          struct ieee80211_vif *vif)
+{
+       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+       struct iwl_mvm *mvm = _data;
+       int ret;
+
+       mvmvif->pm_prevented = (mvm->bound_vif_cnt <= 1) ? false : true;
+
+       ret = iwl_mvm_power_mac_update_mode(mvm, vif);
+       WARN_ONCE(ret, "Failed to update power parameters on a specific vif\n");
+}
+
+static void _iwl_mvm_power_update_binding(struct iwl_mvm *mvm,
+                                         struct ieee80211_vif *vif,
+                                         bool assign)
+{
+       if (vif->type == NL80211_IFTYPE_MONITOR) {
+               int ret = _iwl_mvm_power_update_device(mvm, assign);
+               mvm->ps_prevented = assign;
+               WARN_ONCE(ret, "Failed to update power device state\n");
+       }
+
+       ieee80211_iterate_active_interfaces(mvm->hw,
+                                           IEEE80211_IFACE_ITER_NORMAL,
+                                           iwl_mvm_power_binding_iterator,
+                                           mvm);
+}
+
 #ifdef CONFIG_IWLWIFI_DEBUGFS
 static int iwl_mvm_power_mac_dbgfs_read(struct iwl_mvm *mvm,
                                        struct ieee80211_vif *vif, char *buf,
@@ -494,70 +596,58 @@ static int iwl_mvm_power_mac_dbgfs_read(struct iwl_mvm *mvm,
        pos += scnprintf(buf+pos, bufsz-pos, "keep_alive = %d\n",
                         le16_to_cpu(cmd.keep_alive_seconds));
 
-       if (cmd.flags & cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)) {
-               pos += scnprintf(buf+pos, bufsz-pos, "skip_over_dtim = %d\n",
-                                (cmd.flags &
-                                cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK)) ?
-                                1 : 0);
-               pos += scnprintf(buf+pos, bufsz-pos, "skip_dtim_periods = %d\n",
-                                cmd.skip_dtim_periods);
-               if (!(cmd.flags &
-                     cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK))) {
-                       pos += scnprintf(buf+pos, bufsz-pos,
-                                        "rx_data_timeout = %d\n",
-                                        le32_to_cpu(cmd.rx_data_timeout));
-                       pos += scnprintf(buf+pos, bufsz-pos,
-                                        "tx_data_timeout = %d\n",
-                                        le32_to_cpu(cmd.tx_data_timeout));
-               }
-               if (cmd.flags & cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK))
-                       pos += scnprintf(buf+pos, bufsz-pos,
-                                        "lprx_rssi_threshold = %d\n",
-                                        cmd.lprx_rssi_threshold);
-               if (cmd.flags & cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK)) {
-                       pos +=
-                       scnprintf(buf+pos, bufsz-pos,
-                                 "rx_data_timeout_uapsd = %d\n",
-                                 le32_to_cpu(cmd.rx_data_timeout_uapsd));
-                       pos +=
-                       scnprintf(buf+pos, bufsz-pos,
-                                 "tx_data_timeout_uapsd = %d\n",
-                                 le32_to_cpu(cmd.tx_data_timeout_uapsd));
-                       pos += scnprintf(buf+pos, bufsz-pos, "qndp_tid = %d\n",
-                                        cmd.qndp_tid);
-                       pos += scnprintf(buf+pos, bufsz-pos,
-                                        "uapsd_ac_flags = 0x%x\n",
-                                        cmd.uapsd_ac_flags);
-                       pos += scnprintf(buf+pos, bufsz-pos,
-                                        "uapsd_max_sp = %d\n",
-                                        cmd.uapsd_max_sp);
-                       pos += scnprintf(buf+pos, bufsz-pos,
-                                        "heavy_tx_thld_packets = %d\n",
-                                        cmd.heavy_tx_thld_packets);
-                       pos += scnprintf(buf+pos, bufsz-pos,
-                                        "heavy_rx_thld_packets = %d\n",
-                                        cmd.heavy_rx_thld_packets);
-                       pos += scnprintf(buf+pos, bufsz-pos,
-                                        "heavy_tx_thld_percentage = %d\n",
-                                        cmd.heavy_tx_thld_percentage);
-                       pos += scnprintf(buf+pos, bufsz-pos,
-                                        "heavy_rx_thld_percentage = %d\n",
-                                        cmd.heavy_rx_thld_percentage);
-                       pos +=
-                       scnprintf(buf+pos, bufsz-pos, "snooze_enable = %d\n",
-                                 (cmd.flags &
-                                  cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK)) ?
-                                 1 : 0);
-               }
-               if (cmd.flags & cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK)) {
-                       pos += scnprintf(buf+pos, bufsz-pos,
-                                        "snooze_interval = %d\n",
-                                        cmd.snooze_interval);
-                       pos += scnprintf(buf+pos, bufsz-pos,
-                                        "snooze_window = %d\n",
-                                        cmd.snooze_window);
-               }
+       if (!(cmd.flags & cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)))
+               return pos;
+
+       pos += scnprintf(buf+pos, bufsz-pos, "skip_over_dtim = %d\n",
+                        (cmd.flags &
+                        cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK)) ? 1 : 0);
+       pos += scnprintf(buf+pos, bufsz-pos, "skip_dtim_periods = %d\n",
+                        cmd.skip_dtim_periods);
+       if (!(cmd.flags & cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK))) {
+               pos += scnprintf(buf+pos, bufsz-pos, "rx_data_timeout = %d\n",
+                                le32_to_cpu(cmd.rx_data_timeout));
+               pos += scnprintf(buf+pos, bufsz-pos, "tx_data_timeout = %d\n",
+                                le32_to_cpu(cmd.tx_data_timeout));
        }
+       if (cmd.flags & cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK))
+               pos += scnprintf(buf+pos, bufsz-pos,
+                                "lprx_rssi_threshold = %d\n",
+                                cmd.lprx_rssi_threshold);
+
+       if (!(cmd.flags & cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK)))
+               return pos;
+
+       pos += scnprintf(buf+pos, bufsz-pos, "rx_data_timeout_uapsd = %d\n",
+                        le32_to_cpu(cmd.rx_data_timeout_uapsd));
+       pos += scnprintf(buf+pos, bufsz-pos, "tx_data_timeout_uapsd = %d\n",
+                        le32_to_cpu(cmd.tx_data_timeout_uapsd));
+       pos += scnprintf(buf+pos, bufsz-pos, "qndp_tid = %d\n", cmd.qndp_tid);
+       pos += scnprintf(buf+pos, bufsz-pos, "uapsd_ac_flags = 0x%x\n",
+                        cmd.uapsd_ac_flags);
+       pos += scnprintf(buf+pos, bufsz-pos, "uapsd_max_sp = %d\n",
+                        cmd.uapsd_max_sp);
+       pos += scnprintf(buf+pos, bufsz-pos, "heavy_tx_thld_packets = %d\n",
+                        cmd.heavy_tx_thld_packets);
+       pos += scnprintf(buf+pos, bufsz-pos, "heavy_rx_thld_packets = %d\n",
+                        cmd.heavy_rx_thld_packets);
+       pos += scnprintf(buf+pos, bufsz-pos, "heavy_tx_thld_percentage = %d\n",
+                        cmd.heavy_tx_thld_percentage);
+       pos += scnprintf(buf+pos, bufsz-pos, "heavy_rx_thld_percentage = %d\n",
+                        cmd.heavy_rx_thld_percentage);
+       pos += scnprintf(buf+pos, bufsz-pos, "uapsd_misbehaving_enable = %d\n",
+                        (cmd.flags &
+                         cpu_to_le16(POWER_FLAGS_UAPSD_MISBEHAVING_ENA_MSK)) ?
+                        1 : 0);
+
+       if (!(cmd.flags & cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK)))
+               return pos;
+
+       pos += scnprintf(buf+pos, bufsz-pos, "snooze_interval = %d\n",
+                        cmd.snooze_interval);
+       pos += scnprintf(buf+pos, bufsz-pos, "snooze_window = %d\n",
+                        cmd.snooze_window);
+
        return pos;
 }
 
@@ -654,6 +744,7 @@ const struct iwl_mvm_power_ops pm_mac_ops = {
        .power_update_mode = iwl_mvm_power_mac_update_mode,
        .power_update_device_mode = iwl_mvm_power_update_device,
        .power_disable = iwl_mvm_power_mac_disable,
+       .power_update_binding = _iwl_mvm_power_update_binding,
 #ifdef CONFIG_IWLWIFI_DEBUGFS
        .power_dbgfs_read = iwl_mvm_power_mac_dbgfs_read,
 #endif
index bf6e29f5b4d0af23d6422f73f07fa13163936d35..d6d28d7b442b2373ef2660f8ae5b9c05c4a34508 100644 (file)
 
 #define RS_NAME "iwl-mvm-rs"
 
-#define NUM_TRY_BEFORE_ANT_TOGGLE 1
-#define IWL_NUMBER_TRY      1
-#define IWL_HT_NUMBER_TRY   3
+#define NUM_TRY_BEFORE_ANT_TOGGLE       1
+#define RS_LEGACY_RETRIES_PER_RATE      1
+#define RS_HT_VHT_RETRIES_PER_RATE      2
+#define RS_HT_VHT_RETRIES_PER_RATE_TW   1
+#define RS_INITIAL_MIMO_NUM_RATES       3
+#define RS_INITIAL_SISO_NUM_RATES       3
+#define RS_INITIAL_LEGACY_NUM_RATES     LINK_QUAL_MAX_RETRY_NUM
+#define RS_SECONDARY_LEGACY_NUM_RATES   LINK_QUAL_MAX_RETRY_NUM
+#define RS_SECONDARY_SISO_NUM_RATES     3
+#define RS_SECONDARY_SISO_RETRIES       1
 
 #define IWL_RATE_MAX_WINDOW            62      /* # tx in history window */
 #define IWL_RATE_MIN_FAILURE_TH                3       /* min failures to calc tpt */
@@ -123,6 +130,12 @@ static const struct iwl_rs_rate_info iwl_rates[IWL_RATE_COUNT] = {
        IWL_DECLARE_MCS_RATE(9),                 /* MCS 9 */
 };
 
+enum rs_action {
+       RS_ACTION_STAY = 0,
+       RS_ACTION_DOWNSCALE = -1,
+       RS_ACTION_UPSCALE = 1,
+};
+
 enum rs_column_mode {
        RS_INVALID = 0,
        RS_LEGACY,
@@ -351,20 +364,12 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
                                   struct sk_buff *skb,
                                   struct ieee80211_sta *sta,
                                   struct iwl_lq_sta *lq_sta);
-static void rs_fill_link_cmd(struct iwl_mvm *mvm,
-                            struct ieee80211_sta *sta,
-                            struct iwl_lq_sta *lq_sta, u32 rate_n_flags);
+static void rs_fill_lq_cmd(struct iwl_mvm *mvm,
+                          struct ieee80211_sta *sta,
+                          struct iwl_lq_sta *lq_sta,
+                          const struct rs_rate *initial_rate);
 static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search);
 
-#ifdef CONFIG_MAC80211_DEBUGFS
-static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
-                            u32 *rate_n_flags);
-#else
-static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
-                            u32 *rate_n_flags)
-{}
-#endif
-
 /**
  * The following tables contain the expected throughput metrics for all rates
  *
@@ -504,30 +509,6 @@ static inline u8 rs_is_valid_ant(u8 valid_antenna, u8 ant_type)
        return (ant_type & valid_antenna) == ant_type;
 }
 
-#ifdef CONFIG_MAC80211_DEBUGFS
-/**
- * Program the device to use fixed rate for frame transmit
- * This is for debugging/testing only
- * once the device start use fixed rate, we need to reload the module
- * to being back the normal operation.
- */
-static void rs_program_fix_rate(struct iwl_mvm *mvm,
-                               struct iwl_lq_sta *lq_sta)
-{
-       lq_sta->active_legacy_rate = 0x0FFF;    /* 1 - 54 MBits, includes CCK */
-       lq_sta->active_siso_rate   = 0x1FD0;    /* 6 - 60 MBits, no 9, no CCK */
-       lq_sta->active_mimo2_rate  = 0x1FD0;    /* 6 - 60 MBits, no 9, no CCK */
-
-       IWL_DEBUG_RATE(mvm, "sta_id %d rate 0x%X\n",
-                      lq_sta->lq.sta_id, lq_sta->dbg_fixed_rate);
-
-       if (lq_sta->dbg_fixed_rate) {
-               rs_fill_link_cmd(NULL, NULL, lq_sta, lq_sta->dbg_fixed_rate);
-               iwl_mvm_send_lq_cmd(lq_sta->drv, &lq_sta->lq, false);
-       }
-}
-#endif
-
 static int rs_tl_turn_on_agg_for_tid(struct iwl_mvm *mvm,
                                      struct iwl_lq_sta *lq_data, u8 tid,
                                      struct ieee80211_sta *sta)
@@ -658,7 +639,7 @@ static int rs_collect_tx_data(struct iwl_scale_tbl_info *tbl,
 
 /* Convert rs_rate object into ucode rate bitmask */
 static u32 ucode_rate_from_rs_rate(struct iwl_mvm *mvm,
-                                  struct rs_rate *rate)
+                                 struct rs_rate *rate)
 {
        u32 ucode_rate = 0;
        int index = rate->index;
@@ -785,8 +766,7 @@ static int rs_rate_from_ucode_rate(const u32 ucode_rate,
 
 /* switch to another antenna/antennas and return 1 */
 /* if no other valid antenna found, return 0 */
-static int rs_toggle_antenna(u32 valid_ant, u32 *ucode_rate,
-                            struct rs_rate *rate)
+static int rs_toggle_antenna(u32 valid_ant, struct rs_rate *rate)
 {
        u8 new_ant_type;
 
@@ -807,9 +787,6 @@ static int rs_toggle_antenna(u32 valid_ant, u32 *ucode_rate,
 
        rate->ant = new_ant_type;
 
-       /* TODO: get rid of ucode_rate here. This should handle only rs_rate */
-       *ucode_rate &= ~RATE_MCS_ANT_ABC_MSK;
-       *ucode_rate |= new_ant_type << RATE_MCS_ANT_POS;
        return 1;
 }
 
@@ -883,65 +860,73 @@ static u16 rs_get_adjacent_rate(struct iwl_mvm *mvm, u8 index, u16 rate_mask,
        return (high << 8) | low;
 }
 
-static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta,
-                            struct rs_rate *rate,
-                            u8 scale_index, u8 ht_possible)
+static inline bool rs_rate_supported(struct iwl_lq_sta *lq_sta,
+                                    struct rs_rate *rate)
 {
-       s32 low;
-       u16 rate_mask;
+       return BIT(rate->index) & rs_get_supported_rates(lq_sta, rate);
+}
+
+/* Get the next supported lower rate in the current column.
+ * Return true if bottom rate in the current column was reached
+ */
+static bool rs_get_lower_rate_in_column(struct iwl_lq_sta *lq_sta,
+                                       struct rs_rate *rate)
+{
+       u8 low;
        u16 high_low;
-       u8 switch_to_legacy = 0;
+       u16 rate_mask;
        struct iwl_mvm *mvm = lq_sta->drv;
 
-       /* check if we need to switch from HT to legacy rates.
-        * assumption is that mandatory rates (1Mbps or 6Mbps)
-        * are always supported (spec demand) */
-       if (!is_legacy(rate) && (!ht_possible || !scale_index)) {
-               switch_to_legacy = 1;
-               WARN_ON_ONCE(scale_index < IWL_RATE_MCS_0_INDEX &&
-                            scale_index > IWL_RATE_MCS_9_INDEX);
-               scale_index = rs_ht_to_legacy[scale_index];
+       rate_mask = rs_get_supported_rates(lq_sta, rate);
+       high_low = rs_get_adjacent_rate(mvm, rate->index, rate_mask,
+                                       rate->type);
+       low = high_low & 0xff;
+
+       /* Bottom rate of column reached */
+       if (low == IWL_RATE_INVALID)
+               return true;
+
+       rate->index = low;
+       return false;
+}
+
+/* Get the next rate to use following a column downgrade */
+static void rs_get_lower_rate_down_column(struct iwl_lq_sta *lq_sta,
+                                         struct rs_rate *rate)
+{
+       struct iwl_mvm *mvm = lq_sta->drv;
+
+       if (is_legacy(rate)) {
+               /* No column to downgrade from Legacy */
+               return;
+       } else if (is_siso(rate)) {
+               /* Downgrade to Legacy if we were in SISO */
                if (lq_sta->band == IEEE80211_BAND_5GHZ)
                        rate->type = LQ_LEGACY_A;
                else
                        rate->type = LQ_LEGACY_G;
 
-               if (num_of_ant(rate->ant) > 1)
-                       rate->ant =
-                           first_antenna(iwl_fw_valid_tx_ant(mvm->fw));
-
                rate->bw = RATE_MCS_CHAN_WIDTH_20;
-               rate->sgi = false;
-       }
 
-       rate_mask = rs_get_supported_rates(lq_sta, rate);
+               WARN_ON_ONCE(rate->index < IWL_RATE_MCS_0_INDEX &&
+                            rate->index > IWL_RATE_MCS_9_INDEX);
 
-       /* Mask with station rate restriction */
-       if (is_legacy(rate)) {
-               /* supp_rates has no CCK bits in A mode */
-               if (lq_sta->band == IEEE80211_BAND_5GHZ)
-                       rate_mask = (u16)(rate_mask &
-                          (lq_sta->supp_rates << IWL_FIRST_OFDM_RATE));
-               else
-                       rate_mask = (u16)(rate_mask & lq_sta->supp_rates);
+               rate->index = rs_ht_to_legacy[rate->index];
+       } else {
+               /* Downgrade to SISO with same MCS if in MIMO  */
+               rate->type = is_vht_mimo2(rate) ?
+                       LQ_VHT_SISO : LQ_HT_SISO;
        }
 
-       /* If we switched from HT to legacy, check current rate */
-       if (switch_to_legacy && (rate_mask & (1 << scale_index))) {
-               low = scale_index;
-               goto out;
-       }
 
-       high_low = rs_get_adjacent_rate(lq_sta->drv, scale_index, rate_mask,
-                                       rate->type);
-       low = high_low & 0xff;
+       if (num_of_ant(rate->ant) > 1)
+               rate->ant = first_antenna(iwl_fw_valid_tx_ant(mvm->fw));
 
-       if (low == IWL_RATE_INVALID)
-               low = scale_index;
+       /* Relevant in both switching to SISO or Legacy */
+       rate->sgi = false;
 
-out:
-       rate->index = low;
-       return ucode_rate_from_rs_rate(lq_sta->drv, rate);
+       if (!rs_rate_supported(lq_sta, rate))
+               rs_get_lower_rate_in_column(lq_sta, rate);
 }
 
 /* Simple function to compare two rate scale table types */
@@ -1137,14 +1122,9 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband,
                                tmp_tbl = curr_tbl;
                        else if (rs_rate_match(&rate, &other_tbl->rate))
                                tmp_tbl = other_tbl;
-                       else {
-                               IWL_DEBUG_RATE(mvm,
-                                              "Tx packet rate doesn't match ACTIVE or SEARCH tables\n");
-                               rs_dump_rate(mvm, &rate, "Tx PACKET:");
-                               rs_dump_rate(mvm, &curr_tbl->rate, "CURRENT:");
-                               rs_dump_rate(mvm, &other_tbl->rate, "OTHER:");
+                       else
                                continue;
-                       }
+
                        rs_collect_tx_data(tmp_tbl, rate.index, 1,
                                           i < retries ? 0 : legacy_success);
                }
@@ -1471,10 +1451,7 @@ static void rs_update_rate_tbl(struct iwl_mvm *mvm,
                               struct iwl_lq_sta *lq_sta,
                               struct rs_rate *rate)
 {
-       u32 ucode_rate;
-
-       ucode_rate = ucode_rate_from_rs_rate(mvm, rate);
-       rs_fill_link_cmd(mvm, sta, lq_sta, ucode_rate);
+       rs_fill_lq_cmd(mvm, sta, lq_sta, rate);
        iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, false);
 }
 
@@ -1634,10 +1611,6 @@ static int rs_switch_to_column(struct iwl_mvm *mvm,
                rate->index = rate_idx;
        }
 
-       /* TODO: remove current_rate and keep using rs_rate all the way until
-        * we need to fill in the rs_table in the LQ command
-        */
-       search_tbl->current_rate = ucode_rate_from_rs_rate(mvm, rate);
        IWL_DEBUG_RATE(mvm, "Switched to column %d: Index %d\n",
                       col_id, rate->index);
 
@@ -1649,6 +1622,97 @@ err:
        return -1;
 }
 
+static enum rs_action rs_get_rate_action(struct iwl_mvm *mvm,
+                                        struct iwl_scale_tbl_info *tbl,
+                                        s32 sr, int low, int high,
+                                        int current_tpt,
+                                        int low_tpt, int high_tpt)
+{
+       enum rs_action action = RS_ACTION_STAY;
+
+       /* Too many failures, decrease rate */
+       if ((sr <= RS_SR_FORCE_DECREASE) || (current_tpt == 0)) {
+               IWL_DEBUG_RATE(mvm,
+                              "decrease rate because of low SR\n");
+               action = RS_ACTION_DOWNSCALE;
+       /* No throughput measured yet for adjacent rates; try increase. */
+       } else if ((low_tpt == IWL_INVALID_VALUE) &&
+                  (high_tpt == IWL_INVALID_VALUE)) {
+               if (high != IWL_RATE_INVALID && sr >= IWL_RATE_INCREASE_TH) {
+                       IWL_DEBUG_RATE(mvm,
+                                      "Good SR and no high rate measurement. "
+                                      "Increase rate\n");
+                       action = RS_ACTION_UPSCALE;
+               } else if (low != IWL_RATE_INVALID) {
+                       IWL_DEBUG_RATE(mvm,
+                                      "Remain in current rate\n");
+                       action = RS_ACTION_STAY;
+               }
+       }
+
+       /* Both adjacent throughputs are measured, but neither one has better
+        * throughput; we're using the best rate, don't change it!
+        */
+       else if ((low_tpt != IWL_INVALID_VALUE) &&
+                (high_tpt != IWL_INVALID_VALUE) &&
+                (low_tpt < current_tpt) &&
+                (high_tpt < current_tpt)) {
+               IWL_DEBUG_RATE(mvm,
+                              "Both high and low are worse. "
+                              "Maintain rate\n");
+               action = RS_ACTION_STAY;
+       }
+
+       /* At least one adjacent rate's throughput is measured,
+        * and may have better performance.
+        */
+       else {
+               /* Higher adjacent rate's throughput is measured */
+               if (high_tpt != IWL_INVALID_VALUE) {
+                       /* Higher rate has better throughput */
+                       if (high_tpt > current_tpt &&
+                           sr >= IWL_RATE_INCREASE_TH) {
+                               IWL_DEBUG_RATE(mvm,
+                                              "Higher rate is better and good "
+                                              "SR. Increate rate\n");
+                               action = RS_ACTION_UPSCALE;
+                       } else {
+                               IWL_DEBUG_RATE(mvm,
+                                              "Higher rate isn't better OR "
+                                              "no good SR. Maintain rate\n");
+                               action = RS_ACTION_STAY;
+                       }
+
+               /* Lower adjacent rate's throughput is measured */
+               } else if (low_tpt != IWL_INVALID_VALUE) {
+                       /* Lower rate has better throughput */
+                       if (low_tpt > current_tpt) {
+                               IWL_DEBUG_RATE(mvm,
+                                              "Lower rate is better. "
+                                              "Decrease rate\n");
+                               action = RS_ACTION_DOWNSCALE;
+                       } else if (sr >= IWL_RATE_INCREASE_TH) {
+                               IWL_DEBUG_RATE(mvm,
+                                              "Lower rate isn't better and "
+                                              "good SR. Increase rate\n");
+                               action = RS_ACTION_UPSCALE;
+                       }
+               }
+       }
+
+       /* Sanity check; asked for decrease, but success rate or throughput
+        * has been good at old rate.  Don't change it.
+        */
+       if ((action == RS_ACTION_DOWNSCALE) && (low != IWL_RATE_INVALID) &&
+           ((sr > IWL_RATE_HIGH_TH) ||
+            (current_tpt > (100 * tbl->expected_tpt[low])))) {
+               IWL_DEBUG_RATE(mvm,
+                              "Sanity check failed. Maintain rate\n");
+               action = RS_ACTION_STAY;
+       }
+
+       return action;
+}
 
 /*
  * Do rate scaling and search for new modulation mode.
@@ -1669,11 +1733,10 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
        int low_tpt = IWL_INVALID_VALUE;
        int high_tpt = IWL_INVALID_VALUE;
        u32 fail_count;
-       s8 scale_action = 0;
+       enum rs_action scale_action = RS_ACTION_STAY;
        u16 rate_mask;
        u8 update_lq = 0;
        struct iwl_scale_tbl_info *tbl, *tbl1;
-       u16 rate_scale_index_msk = 0;
        u8 active_tbl = 0;
        u8 done_search = 0;
        u16 high_low;
@@ -1690,8 +1753,6 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
            info->flags & IEEE80211_TX_CTL_NO_ACK)
                return;
 
-       lq_sta->supp_rates = sta->supp_rates[lq_sta->band];
-
        tid = rs_get_tid(lq_sta, hdr);
        if ((tid != IWL_MAX_TID_COUNT) &&
            (lq_sta->tx_agg_tid_en & (1 << tid))) {
@@ -1730,33 +1791,13 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
        /* rates available for this association, and for modulation mode */
        rate_mask = rs_get_supported_rates(lq_sta, rate);
 
-       /* mask with station rate restriction */
-       if (is_legacy(rate)) {
-               if (lq_sta->band == IEEE80211_BAND_5GHZ)
-                       /* supp_rates has no CCK bits in A mode */
-                       rate_scale_index_msk = (u16) (rate_mask &
-                               (lq_sta->supp_rates << IWL_FIRST_OFDM_RATE));
-               else
-                       rate_scale_index_msk = (u16) (rate_mask &
-                                                     lq_sta->supp_rates);
-
-       } else {
-               rate_scale_index_msk = rate_mask;
-       }
-
-       if (!rate_scale_index_msk)
-               rate_scale_index_msk = rate_mask;
-
-       if (!((BIT(index) & rate_scale_index_msk))) {
+       if (!(BIT(index) & rate_mask)) {
                IWL_ERR(mvm, "Current Rate is not valid\n");
                if (lq_sta->search_better_tbl) {
                        /* revert to active table if search table is not valid*/
                        rate->type = LQ_NONE;
                        lq_sta->search_better_tbl = 0;
                        tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
-                       /* get "active" rate info */
-                       index = iwl_hwrate_to_plcp_idx(tbl->current_rate);
-                       tbl->rate.index = index;
                        rs_update_rate_tbl(mvm, sta, lq_sta, &tbl->rate);
                }
                return;
@@ -1847,7 +1888,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
                        tbl = &(lq_sta->lq_info[active_tbl]);
 
                        /* Revert to "active" rate and throughput info */
-                       index = iwl_hwrate_to_plcp_idx(tbl->current_rate);
+                       index = tbl->rate.index;
                        current_tpt = lq_sta->last_tpt;
 
                        /* Need to set up a new rate table in uCode */
@@ -1863,8 +1904,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
 
        /* (Else) not in search of better modulation mode, try for better
         * starting rate, while staying in this mode. */
-       high_low = rs_get_adjacent_rate(mvm, index, rate_scale_index_msk,
-                                       rate->type);
+       high_low = rs_get_adjacent_rate(mvm, index, rate_mask, rate->type);
        low = high_low & 0xff;
        high = (high_low >> 8) & 0xff;
 
@@ -1887,85 +1927,8 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
                       rs_pretty_lq_type(rate->type), index, current_tpt, sr,
                       low, high, low_tpt, high_tpt);
 
-       scale_action = 0;
-
-       /* Too many failures, decrease rate */
-       if ((sr <= RS_SR_FORCE_DECREASE) || (current_tpt == 0)) {
-               IWL_DEBUG_RATE(mvm,
-                              "decrease rate because of low SR\n");
-               scale_action = -1;
-       /* No throughput measured yet for adjacent rates; try increase. */
-       } else if ((low_tpt == IWL_INVALID_VALUE) &&
-                  (high_tpt == IWL_INVALID_VALUE)) {
-               if (high != IWL_RATE_INVALID && sr >= IWL_RATE_INCREASE_TH) {
-                       IWL_DEBUG_RATE(mvm,
-                                      "Good SR and no high rate measurement. "
-                                      "Increase rate\n");
-                       scale_action = 1;
-               } else if (low != IWL_RATE_INVALID) {
-                       IWL_DEBUG_RATE(mvm,
-                                      "Remain in current rate\n");
-                       scale_action = 0;
-               }
-       }
-
-       /* Both adjacent throughputs are measured, but neither one has better
-        * throughput; we're using the best rate, don't change it! */
-       else if ((low_tpt != IWL_INVALID_VALUE) &&
-                (high_tpt != IWL_INVALID_VALUE) &&
-                (low_tpt < current_tpt) &&
-                (high_tpt < current_tpt)) {
-               IWL_DEBUG_RATE(mvm,
-                              "Both high and low are worse. "
-                              "Maintain rate\n");
-               scale_action = 0;
-       }
-
-       /* At least one adjacent rate's throughput is measured,
-        * and may have better performance. */
-       else {
-               /* Higher adjacent rate's throughput is measured */
-               if (high_tpt != IWL_INVALID_VALUE) {
-                       /* Higher rate has better throughput */
-                       if (high_tpt > current_tpt &&
-                           sr >= IWL_RATE_INCREASE_TH) {
-                               IWL_DEBUG_RATE(mvm,
-                                              "Higher rate is better and good "
-                                              "SR. Increate rate\n");
-                               scale_action = 1;
-                       } else {
-                               IWL_DEBUG_RATE(mvm,
-                                              "Higher rate isn't better OR "
-                                              "no good SR. Maintain rate\n");
-                               scale_action = 0;
-                       }
-
-               /* Lower adjacent rate's throughput is measured */
-               } else if (low_tpt != IWL_INVALID_VALUE) {
-                       /* Lower rate has better throughput */
-                       if (low_tpt > current_tpt) {
-                               IWL_DEBUG_RATE(mvm,
-                                              "Lower rate is better. "
-                                              "Decrease rate\n");
-                               scale_action = -1;
-                       } else if (sr >= IWL_RATE_INCREASE_TH) {
-                               IWL_DEBUG_RATE(mvm,
-                                              "Lower rate isn't better and "
-                                              "good SR. Increase rate\n");
-                               scale_action = 1;
-                       }
-               }
-       }
-
-       /* Sanity check; asked for decrease, but success rate or throughput
-        * has been good at old rate.  Don't change it. */
-       if ((scale_action == -1) && (low != IWL_RATE_INVALID) &&
-           ((sr > IWL_RATE_HIGH_TH) ||
-            (current_tpt > (100 * tbl->expected_tpt[low])))) {
-               IWL_DEBUG_RATE(mvm,
-                              "Sanity check failed. Maintain rate\n");
-               scale_action = 0;
-       }
+       scale_action = rs_get_rate_action(mvm, tbl, sr, low, high,
+                                         current_tpt, low_tpt, high_tpt);
 
        /* Force a search in case BT doesn't like us being in MIMO */
        if (is_mimo(rate) &&
@@ -1977,7 +1940,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
        }
 
        switch (scale_action) {
-       case -1:
+       case RS_ACTION_DOWNSCALE:
                /* Decrease starting rate, update uCode's rate table */
                if (low != IWL_RATE_INVALID) {
                        update_lq = 1;
@@ -1988,7 +1951,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
                }
 
                break;
-       case 1:
+       case RS_ACTION_UPSCALE:
                /* Increase starting rate, update uCode's rate table */
                if (high != IWL_RATE_INVALID) {
                        update_lq = 1;
@@ -1999,7 +1962,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
                }
 
                break;
-       case 0:
+       case RS_ACTION_STAY:
                /* No change */
        default:
                break;
@@ -2053,11 +2016,11 @@ lq_update:
                                rs_rate_scale_clear_window(&(tbl->win[i]));
 
                        /* Use new "search" start rate */
-                       index = iwl_hwrate_to_plcp_idx(tbl->current_rate);
+                       index = tbl->rate.index;
 
                        rs_dump_rate(mvm, &tbl->rate,
                                     "Switch to SEARCH TABLE:");
-                       rs_fill_link_cmd(mvm, sta, lq_sta, tbl->current_rate);
+                       rs_fill_lq_cmd(mvm, sta, lq_sta, &tbl->rate);
                        iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, false);
                } else {
                        done_search = 1;
@@ -2095,8 +2058,6 @@ lq_update:
        }
 
 out:
-       tbl->rate.index = index;
-       tbl->current_rate = ucode_rate_from_rs_rate(mvm, &tbl->rate);
        lq_sta->last_txrate_idx = index;
 }
 
@@ -2123,7 +2084,6 @@ static void rs_initialize_lq(struct iwl_mvm *mvm,
        struct iwl_scale_tbl_info *tbl;
        struct rs_rate *rate;
        int i;
-       u32 ucode_rate;
        u8 active_tbl = 0;
        u8 valid_tx_ant;
 
@@ -2154,9 +2114,6 @@ static void rs_initialize_lq(struct iwl_mvm *mvm,
        else
                rate->type = LQ_LEGACY_G;
 
-       ucode_rate = ucode_rate_from_rs_rate(mvm, rate);
-       tbl->current_rate = ucode_rate;
-
        WARN_ON_ONCE(rate->ant != ANT_A && rate->ant != ANT_B);
        if (rate->ant == ANT_A)
                tbl->column = RS_COLUMN_LEGACY_ANT_A;
@@ -2164,7 +2121,7 @@ static void rs_initialize_lq(struct iwl_mvm *mvm,
                tbl->column = RS_COLUMN_LEGACY_ANT_B;
 
        rs_set_expected_tpt_table(lq_sta, tbl);
-       rs_fill_link_cmd(NULL, NULL, lq_sta, ucode_rate);
+       rs_fill_lq_cmd(NULL, NULL, lq_sta, rate);
        /* TODO restore station should remember the lq cmd */
        iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, init);
 }
@@ -2250,6 +2207,10 @@ static void rs_vht_set_enabled_rates(struct ieee80211_sta *sta,
                        if (i == IWL_RATE_9M_INDEX)
                                continue;
 
+                       /* Disable MCS9 as a workaround */
+                       if (i == IWL_RATE_MCS_9_INDEX)
+                               continue;
+
                        /* VHT MCS9 isn't valid for 20Mhz for NSS=1,2 */
                        if (i == IWL_RATE_MCS_9_INDEX &&
                            sta->bandwidth == IEEE80211_STA_RX_BW_20)
@@ -2268,6 +2229,10 @@ static void rs_vht_set_enabled_rates(struct ieee80211_sta *sta,
                        if (i == IWL_RATE_9M_INDEX)
                                continue;
 
+                       /* Disable MCS9 as a workaround */
+                       if (i == IWL_RATE_MCS_9_INDEX)
+                               continue;
+
                        /* VHT MCS9 isn't valid for 20Mhz for NSS=1,2 */
                        if (i == IWL_RATE_MCS_9_INDEX &&
                            sta->bandwidth == IEEE80211_STA_RX_BW_20)
@@ -2306,7 +2271,6 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
                        rs_rate_scale_clear_window(&lq_sta->lq_info[j].win[i]);
 
        lq_sta->flush_timer = 0;
-       lq_sta->supp_rates = sta->supp_rates[sband->band];
 
        IWL_DEBUG_RATE(mvm,
                       "LQ: *** rate scale station global init for station %d ***\n",
@@ -2395,112 +2359,164 @@ static void rs_rate_update(void *mvm_r,
        iwl_mvm_rs_rate_init(mvm, sta, sband->band, false);
 }
 
-static void rs_fill_link_cmd(struct iwl_mvm *mvm,
-                            struct ieee80211_sta *sta,
-                            struct iwl_lq_sta *lq_sta, u32 new_rate)
+#ifdef CONFIG_MAC80211_DEBUGFS
+static void rs_build_rates_table_from_fixed(struct iwl_mvm *mvm,
+                                           struct iwl_lq_cmd *lq_cmd,
+                                           enum ieee80211_band band,
+                                           u32 ucode_rate)
 {
        struct rs_rate rate;
-       int index = 0;
-       int repeat_rate = 0;
-       u8 ant_toggle_cnt = 0;
-       u8 use_ht_possible = 1;
-       u8 valid_tx_ant = 0;
-       struct iwl_lq_cmd *lq_cmd = &lq_sta->lq;
+       int i;
+       int num_rates = ARRAY_SIZE(lq_cmd->rs_table);
+       __le32 ucode_rate_le32 = cpu_to_le32(ucode_rate);
 
-       /* Override starting rate (index 0) if needed for debug purposes */
-       rs_dbgfs_set_mcs(lq_sta, &new_rate);
+       for (i = 0; i < num_rates; i++)
+               lq_cmd->rs_table[i] = ucode_rate_le32;
 
-       rs_rate_from_ucode_rate(new_rate, lq_sta->band, &rate);
+       rs_rate_from_ucode_rate(ucode_rate, band, &rate);
 
-       /* How many times should we repeat the initial rate? */
-       if (is_legacy(&rate)) {
-               ant_toggle_cnt = 1;
-               repeat_rate = IWL_NUMBER_TRY;
-       } else {
-               repeat_rate = min(IWL_HT_NUMBER_TRY,
-                                 LINK_QUAL_AGG_DISABLE_START_DEF - 1);
+       if (is_mimo(&rate))
+               lq_cmd->mimo_delim = num_rates - 1;
+       else
+               lq_cmd->mimo_delim = 0;
+}
+#endif /* CONFIG_MAC80211_DEBUGFS */
+
+static void rs_fill_rates_for_column(struct iwl_mvm *mvm,
+                                    struct iwl_lq_sta *lq_sta,
+                                    struct rs_rate *rate,
+                                    __le32 *rs_table, int *rs_table_index,
+                                    int num_rates, int num_retries,
+                                    u8 valid_tx_ant, bool toggle_ant)
+{
+       int i, j;
+       __le32 ucode_rate;
+       bool bottom_reached = false;
+       int prev_rate_idx = rate->index;
+       int end = LINK_QUAL_MAX_RETRY_NUM;
+       int index = *rs_table_index;
+
+       for (i = 0; i < num_rates && index < end; i++) {
+               ucode_rate = cpu_to_le32(ucode_rate_from_rs_rate(mvm, rate));
+               for (j = 0; j < num_retries && index < end; j++, index++)
+                       rs_table[index] = ucode_rate;
+
+               if (toggle_ant)
+                       rs_toggle_antenna(valid_tx_ant, rate);
+
+               prev_rate_idx = rate->index;
+               bottom_reached = rs_get_lower_rate_in_column(lq_sta, rate);
+               if (bottom_reached && !is_legacy(rate))
+                       break;
        }
 
-       lq_cmd->mimo_delim = is_mimo(&rate) ? 1 : 0;
+       if (!bottom_reached)
+               rate->index = prev_rate_idx;
 
-       /* Fill 1st table entry (index 0) */
-       lq_cmd->rs_table[index] = cpu_to_le32(new_rate);
+       *rs_table_index = index;
+}
 
-       if (num_of_ant(rate.ant) == 1)
-               lq_cmd->single_stream_ant_msk = rate.ant;
-       /* otherwise we don't modify the existing value */
+/* Building the rate table is non trivial. When we're in MIMO2/VHT/80Mhz/SGI
+ * column the rate table should look like this:
+ *
+ * rate[0] 0x400D019 VHT | ANT: AB BW: 80Mhz MCS: 9 NSS: 2 SGI
+ * rate[1] 0x400D019 VHT | ANT: AB BW: 80Mhz MCS: 9 NSS: 2 SGI
+ * rate[2] 0x400D018 VHT | ANT: AB BW: 80Mhz MCS: 8 NSS: 2 SGI
+ * rate[3] 0x400D018 VHT | ANT: AB BW: 80Mhz MCS: 8 NSS: 2 SGI
+ * rate[4] 0x400D017 VHT | ANT: AB BW: 80Mhz MCS: 7 NSS: 2 SGI
+ * rate[5] 0x400D017 VHT | ANT: AB BW: 80Mhz MCS: 7 NSS: 2 SGI
+ * rate[6] 0x4005007 VHT | ANT: A BW: 80Mhz MCS: 7 NSS: 1 NGI
+ * rate[7] 0x4009006 VHT | ANT: B BW: 80Mhz MCS: 6 NSS: 1 NGI
+ * rate[8] 0x4005005 VHT | ANT: A BW: 80Mhz MCS: 5 NSS: 1 NGI
+ * rate[9] 0x800B Legacy | ANT: B Rate: 36 Mbps
+ * rate[10] 0x4009 Legacy | ANT: A Rate: 24 Mbps
+ * rate[11] 0x8007 Legacy | ANT: B Rate: 18 Mbps
+ * rate[12] 0x4005 Legacy | ANT: A Rate: 12 Mbps
+ * rate[13] 0x800F Legacy | ANT: B Rate: 9 Mbps
+ * rate[14] 0x400D Legacy | ANT: A Rate: 6 Mbps
+ * rate[15] 0x800D Legacy | ANT: B Rate: 6 Mbps
+ */
+static void rs_build_rates_table(struct iwl_mvm *mvm,
+                                struct iwl_lq_sta *lq_sta,
+                                const struct rs_rate *initial_rate)
+{
+       struct rs_rate rate;
+       int num_rates, num_retries, index = 0;
+       u8 valid_tx_ant = 0;
+       struct iwl_lq_cmd *lq_cmd = &lq_sta->lq;
+       bool toggle_ant = false;
+
+       memcpy(&rate, initial_rate, sizeof(struct rs_rate));
 
-       index++;
-       repeat_rate--;
        if (mvm)
                valid_tx_ant = iwl_fw_valid_tx_ant(mvm->fw);
 
-       /* Fill rest of rate table */
-       while (index < LINK_QUAL_MAX_RETRY_NUM) {
-               /* Repeat initial/next rate.
-                * For legacy IWL_NUMBER_TRY == 1, this loop will not execute.
-                * For HT IWL_HT_NUMBER_TRY == 3, this executes twice. */
-               while (repeat_rate > 0 && (index < LINK_QUAL_MAX_RETRY_NUM)) {
-                       if (is_legacy(&rate)) {
-                               if (ant_toggle_cnt < NUM_TRY_BEFORE_ANT_TOGGLE)
-                                       ant_toggle_cnt++;
-                               else if (mvm &&
-                                        rs_toggle_antenna(valid_tx_ant,
-                                                       &new_rate, &rate))
-                                       ant_toggle_cnt = 1;
-                       }
+       if (is_siso(&rate)) {
+               num_rates = RS_INITIAL_SISO_NUM_RATES;
+               num_retries = RS_HT_VHT_RETRIES_PER_RATE;
+       } else if (is_mimo(&rate)) {
+               num_rates = RS_INITIAL_MIMO_NUM_RATES;
+               num_retries = RS_HT_VHT_RETRIES_PER_RATE;
+       } else {
+               num_rates = RS_INITIAL_LEGACY_NUM_RATES;
+               num_retries = RS_LEGACY_RETRIES_PER_RATE;
+               toggle_ant = true;
+       }
 
-                       /* Override next rate if needed for debug purposes */
-                       rs_dbgfs_set_mcs(lq_sta, &new_rate);
+       rs_fill_rates_for_column(mvm, lq_sta, &rate, lq_cmd->rs_table, &index,
+                                num_rates, num_retries, valid_tx_ant,
+                                toggle_ant);
 
-                       /* Fill next table entry */
-                       lq_cmd->rs_table[index] =
-                                       cpu_to_le32(new_rate);
-                       repeat_rate--;
-                       index++;
-               }
+       rs_get_lower_rate_down_column(lq_sta, &rate);
 
-               rs_rate_from_ucode_rate(new_rate, lq_sta->band, &rate);
+       if (is_siso(&rate)) {
+               num_rates = RS_SECONDARY_SISO_NUM_RATES;
+               num_retries = RS_SECONDARY_SISO_RETRIES;
+       } else if (is_legacy(&rate)) {
+               num_rates = RS_SECONDARY_LEGACY_NUM_RATES;
+               num_retries = RS_LEGACY_RETRIES_PER_RATE;
+       } else {
+               WARN_ON_ONCE(1);
+       }
 
-               /* Indicate to uCode which entries might be MIMO.
-                * If initial rate was MIMO, this will finally end up
-                * as (IWL_HT_NUMBER_TRY * 2), after 2nd pass, otherwise 0. */
-               if (is_mimo(&rate))
-                       lq_cmd->mimo_delim = index;
+       toggle_ant = true;
 
-               /* Get next rate */
-               new_rate = rs_get_lower_rate(lq_sta, &rate, rate.index,
-                                            use_ht_possible);
+       rs_fill_rates_for_column(mvm, lq_sta, &rate, lq_cmd->rs_table, &index,
+                                num_rates, num_retries, valid_tx_ant,
+                                toggle_ant);
 
-               /* How many times should we repeat the next rate? */
-               if (is_legacy(&rate)) {
-                       if (ant_toggle_cnt < NUM_TRY_BEFORE_ANT_TOGGLE)
-                               ant_toggle_cnt++;
-                       else if (mvm &&
-                                rs_toggle_antenna(valid_tx_ant,
-                                                  &new_rate, &rate))
-                               ant_toggle_cnt = 1;
+       rs_get_lower_rate_down_column(lq_sta, &rate);
 
-                       repeat_rate = IWL_NUMBER_TRY;
-               } else {
-                       repeat_rate = IWL_HT_NUMBER_TRY;
-               }
+       num_rates = RS_SECONDARY_LEGACY_NUM_RATES;
+       num_retries = RS_LEGACY_RETRIES_PER_RATE;
 
-               /* Don't allow HT rates after next pass.
-                * rs_get_lower_rate() will change type to LQ_LEGACY_A
-                * or LQ_LEGACY_G.
-                */
-               use_ht_possible = 0;
+       rs_fill_rates_for_column(mvm, lq_sta, &rate, lq_cmd->rs_table, &index,
+                                num_rates, num_retries, valid_tx_ant,
+                                toggle_ant);
 
-               /* Override next rate if needed for debug purposes */
-               rs_dbgfs_set_mcs(lq_sta, &new_rate);
+}
 
-               /* Fill next table entry */
-               lq_cmd->rs_table[index] = cpu_to_le32(new_rate);
+static void rs_fill_lq_cmd(struct iwl_mvm *mvm,
+                          struct ieee80211_sta *sta,
+                          struct iwl_lq_sta *lq_sta,
+                          const struct rs_rate *initial_rate)
+{
+       struct iwl_lq_cmd *lq_cmd = &lq_sta->lq;
+       u8 ant = initial_rate->ant;
 
-               index++;
-               repeat_rate--;
-       }
+#ifdef CONFIG_MAC80211_DEBUGFS
+       if (lq_sta->dbg_fixed_rate) {
+               rs_build_rates_table_from_fixed(mvm, lq_cmd,
+                                               lq_sta->band,
+                                               lq_sta->dbg_fixed_rate);
+               ant = (lq_sta->dbg_fixed_rate & RATE_MCS_ANT_ABC_MSK) >>
+                       RATE_MCS_ANT_POS;
+       } else
+#endif
+               rs_build_rates_table(mvm, lq_sta, initial_rate);
+
+       if (num_of_ant(ant) == 1)
+               lq_cmd->single_stream_ant_msk = ant;
 
        lq_cmd->agg_frame_cnt_limit = LINK_QUAL_AGG_FRAME_LIMIT_DEF;
        lq_cmd->agg_disable_start_th = LINK_QUAL_AGG_DISABLE_START_DEF;
@@ -2534,31 +2550,6 @@ static void rs_free_sta(void *mvm_r, struct ieee80211_sta *sta,
 }
 
 #ifdef CONFIG_MAC80211_DEBUGFS
-static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
-                            u32 *rate_n_flags)
-{
-       struct iwl_mvm *mvm;
-       u8 valid_tx_ant;
-       u8 ant_sel_tx;
-
-       mvm = lq_sta->drv;
-       valid_tx_ant = iwl_fw_valid_tx_ant(mvm->fw);
-       if (lq_sta->dbg_fixed_rate) {
-               ant_sel_tx =
-                 ((lq_sta->dbg_fixed_rate & RATE_MCS_ANT_ABC_MSK)
-                 >> RATE_MCS_ANT_POS);
-               if ((valid_tx_ant & ant_sel_tx) == ant_sel_tx) {
-                       *rate_n_flags = lq_sta->dbg_fixed_rate;
-               } else {
-                       lq_sta->dbg_fixed_rate = 0;
-                       IWL_ERR(mvm,
-                               "Invalid antenna selection 0x%X, Valid is 0x%X\n",
-                               ant_sel_tx, valid_tx_ant);
-                       IWL_DEBUG_RATE(mvm, "Fixed rate OFF\n");
-               }
-       }
-}
-
 static int rs_pretty_print_rate(char *buf, const u32 rate)
 {
 
@@ -2612,6 +2603,31 @@ static int rs_pretty_print_rate(char *buf, const u32 rate)
                       (rate & RATE_MCS_ZLF_MSK) ? "ZLF " : "");
 }
 
+/**
+ * Program the device to use fixed rate for frame transmit
+ * This is for debugging/testing only
+ * once the device start use fixed rate, we need to reload the module
+ * to being back the normal operation.
+ */
+static void rs_program_fix_rate(struct iwl_mvm *mvm,
+                               struct iwl_lq_sta *lq_sta)
+{
+       lq_sta->active_legacy_rate = 0x0FFF;    /* 1 - 54 MBits, includes CCK */
+       lq_sta->active_siso_rate   = 0x1FD0;    /* 6 - 60 MBits, no 9, no CCK */
+       lq_sta->active_mimo2_rate  = 0x1FD0;    /* 6 - 60 MBits, no 9, no CCK */
+
+       IWL_DEBUG_RATE(mvm, "sta_id %d rate 0x%X\n",
+                      lq_sta->lq.sta_id, lq_sta->dbg_fixed_rate);
+
+       if (lq_sta->dbg_fixed_rate) {
+               struct rs_rate rate;
+               rs_rate_from_ucode_rate(lq_sta->dbg_fixed_rate,
+                                       lq_sta->band, &rate);
+               rs_fill_lq_cmd(NULL, NULL, lq_sta, &rate);
+               iwl_mvm_send_lq_cmd(lq_sta->drv, &lq_sta->lq, false);
+       }
+}
+
 static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file,
                        const char __user *user_buf, size_t count, loff_t *ppos)
 {
@@ -2702,12 +2718,10 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
                        lq_sta->lq.initial_rate_index[3]);
 
        for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
-               u32 rate = le32_to_cpu(lq_sta->lq.rs_table[i]);
-               desc += sprintf(buff+desc,
-                               " rate[%d] 0x%X ",
-                               i, rate);
+               u32 r = le32_to_cpu(lq_sta->lq.rs_table[i]);
 
-               desc += rs_pretty_print_rate(buff+desc, rate);
+               desc += sprintf(buff+desc, " rate[%d] 0x%X ", i, r);
+               desc += rs_pretty_print_rate(buff+desc, r);
        }
 
        ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc);
@@ -2741,14 +2755,14 @@ static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file,
                rate = &tbl->rate;
                desc += sprintf(buff+desc,
                                "%s type=%d SGI=%d BW=%s DUP=0\n"
-                               "rate=0x%X\n",
+                               "index=%d\n",
                                lq_sta->active_tbl == i ? "*" : "x",
                                rate->type,
                                rate->sgi,
                                is_ht20(rate) ? "20Mhz" :
                                is_ht40(rate) ? "40Mhz" :
                                is_ht80(rate) ? "80Mhz" : "ERR",
-                               tbl->current_rate);
+                               rate->index);
                for (j = 0; j < IWL_RATE_COUNT; j++) {
                        desc += sprintf(buff+desc,
                                "counter=%d success=%d %%=%d\n",
index b32960796384e15331fcd4b8149fbd1fb8cc91a0..c31aa59728ea37afe8ae9a8fb1d16abd10b5c248 100644 (file)
@@ -278,7 +278,6 @@ struct iwl_scale_tbl_info {
        struct rs_rate rate;
        enum rs_column column;
        s32 *expected_tpt;      /* throughput metrics; expected_tpt_G, etc. */
-       u32 current_rate;  /* rate_n_flags, uCode API format */
        struct iwl_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */
 };
 
@@ -315,7 +314,6 @@ struct iwl_lq_sta {
        enum ieee80211_band band;
 
        /* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */
-       u32 supp_rates;
        u16 active_legacy_rate;
        u16 active_siso_rate;
        u16 active_mimo2_rate;
index 3a1f3982109d1dbc02bccba42588545e000b8271..454341cc3b274c0a2c27ab6354d566a9c10d0a3a 100644 (file)
@@ -251,6 +251,12 @@ static u32 iwl_mvm_set_mac80211_rx_flag(struct iwl_mvm *mvm,
                stats->flag |= RX_FLAG_DECRYPTED;
                return 0;
 
+       case RX_MPDU_RES_STATUS_SEC_EXT_ENC:
+               if (!(rx_pkt_status & RX_MPDU_RES_STATUS_MIC_OK))
+                       return -1;
+               stats->flag |= RX_FLAG_DECRYPTED;
+               return 0;
+
        default:
                IWL_ERR(mvm, "Unhandled alg: 0x%x\n", rx_pkt_status);
        }
diff --git a/drivers/net/wireless/iwlwifi/mvm/sf.c b/drivers/net/wireless/iwlwifi/mvm/sf.c
new file mode 100644 (file)
index 0000000..97bb3c3
--- /dev/null
@@ -0,0 +1,291 @@
+/******************************************************************************
+ *
+ * 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 "mvm.h"
+
+/* For counting bound interfaces */
+struct iwl_mvm_active_iface_iterator_data {
+       struct ieee80211_vif *ignore_vif;
+       u8 sta_vif_ap_sta_id;
+       enum iwl_sf_state sta_vif_state;
+       int num_active_macs;
+};
+
+/*
+ * Count bound interfaces which are not p2p, besides data->ignore_vif.
+ * data->station_vif will point to one bound vif of type station, if exists.
+ */
+static void iwl_mvm_bound_iface_iterator(void *_data, u8 *mac,
+                                        struct ieee80211_vif *vif)
+{
+       struct iwl_mvm_active_iface_iterator_data *data = _data;
+       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
+       if (vif == data->ignore_vif || !mvmvif->phy_ctxt ||
+           vif->type == NL80211_IFTYPE_P2P_DEVICE)
+               return;
+
+       data->num_active_macs++;
+
+       if (vif->type == NL80211_IFTYPE_STATION) {
+               data->sta_vif_ap_sta_id = mvmvif->ap_sta_id;
+               if (vif->bss_conf.assoc)
+                       data->sta_vif_state = SF_FULL_ON;
+               else
+                       data->sta_vif_state = SF_INIT_OFF;
+       }
+}
+
+/*
+ * Aging and idle timeouts for the different possible scenarios
+ * in SF_FULL_ON state.
+ */
+static const __le32 sf_full_timeout[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES] = {
+       {
+               cpu_to_le32(SF_SINGLE_UNICAST_AGING_TIMER),
+               cpu_to_le32(SF_SINGLE_UNICAST_IDLE_TIMER)
+       },
+       {
+               cpu_to_le32(SF_AGG_UNICAST_AGING_TIMER),
+               cpu_to_le32(SF_AGG_UNICAST_IDLE_TIMER)
+       },
+       {
+               cpu_to_le32(SF_MCAST_AGING_TIMER),
+               cpu_to_le32(SF_MCAST_IDLE_TIMER)
+       },
+       {
+               cpu_to_le32(SF_BA_AGING_TIMER),
+               cpu_to_le32(SF_BA_IDLE_TIMER)
+       },
+       {
+               cpu_to_le32(SF_TX_RE_AGING_TIMER),
+               cpu_to_le32(SF_TX_RE_IDLE_TIMER)
+       },
+};
+
+static void iwl_mvm_fill_sf_command(struct iwl_sf_cfg_cmd *sf_cmd,
+                                   struct ieee80211_sta *sta)
+{
+       int i, j, watermark;
+
+       sf_cmd->watermark[SF_LONG_DELAY_ON] = cpu_to_le32(SF_W_MARK_SCAN);
+
+       /*
+        * If we are in association flow - check antenna configuration
+        * capabilities of the AP station, and choose the watermark accordingly.
+        */
+       if (sta) {
+               if (sta->ht_cap.ht_supported || sta->vht_cap.vht_supported) {
+                       switch (sta->rx_nss) {
+                       case 1:
+                               watermark = SF_W_MARK_SISO;
+                               break;
+                       case 2:
+                               watermark = SF_W_MARK_MIMO2;
+                               break;
+                       default:
+                               watermark = SF_W_MARK_MIMO3;
+                               break;
+                       }
+               } else {
+                       watermark = SF_W_MARK_LEGACY;
+               }
+       /* default watermark value for unassociated mode. */
+       } else {
+               watermark = SF_W_MARK_MIMO2;
+       }
+       sf_cmd->watermark[SF_FULL_ON] = cpu_to_le32(watermark);
+
+       for (i = 0; i < SF_NUM_SCENARIO; i++) {
+               for (j = 0; j < SF_NUM_TIMEOUT_TYPES; j++) {
+                       sf_cmd->long_delay_timeouts[i][j] =
+                                       cpu_to_le32(SF_LONG_DELAY_AGING_TIMER);
+               }
+       }
+       BUILD_BUG_ON(sizeof(sf_full_timeout) !=
+                    sizeof(__le32) * SF_NUM_SCENARIO * SF_NUM_TIMEOUT_TYPES);
+
+       memcpy(sf_cmd->full_on_timeouts, sf_full_timeout,
+              sizeof(sf_full_timeout));
+}
+
+static int iwl_mvm_sf_config(struct iwl_mvm *mvm, u8 sta_id,
+                            enum iwl_sf_state new_state)
+{
+       struct iwl_sf_cfg_cmd sf_cmd = {
+               .state = new_state,
+       };
+       struct ieee80211_sta *sta;
+       int ret = 0;
+
+       /*
+        * If an associated AP sta changed its antenna configuration, the state
+        * will remain FULL_ON but SF parameters need to be reconsidered.
+        */
+       if (new_state != SF_FULL_ON && mvm->sf_state == new_state)
+               return 0;
+
+       switch (new_state) {
+       case SF_UNINIT:
+               break;
+       case SF_FULL_ON:
+               if (sta_id == IWL_MVM_STATION_COUNT) {
+                       IWL_ERR(mvm,
+                               "No station: Cannot switch SF to FULL_ON\n");
+                       return -EINVAL;
+               }
+               rcu_read_lock();
+               sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);
+               if (IS_ERR_OR_NULL(sta)) {
+                       IWL_ERR(mvm, "Invalid station id\n");
+                       rcu_read_unlock();
+                       return -EINVAL;
+               }
+               iwl_mvm_fill_sf_command(&sf_cmd, sta);
+               rcu_read_unlock();
+               break;
+       case SF_INIT_OFF:
+               iwl_mvm_fill_sf_command(&sf_cmd, NULL);
+               break;
+       default:
+               WARN_ONCE(1, "Invalid state: %d. not sending Smart Fifo cmd\n",
+                         new_state);
+               return -EINVAL;
+       }
+
+       ret = iwl_mvm_send_cmd_pdu(mvm, REPLY_SF_CFG_CMD, CMD_ASYNC,
+                                  sizeof(sf_cmd), &sf_cmd);
+       if (!ret)
+               mvm->sf_state = new_state;
+
+       return ret;
+}
+
+/*
+ * Update Smart fifo:
+ * Count bound interfaces that are not to be removed, ignoring p2p devices,
+ * and set new state accordingly.
+ */
+int iwl_mvm_sf_update(struct iwl_mvm *mvm, struct ieee80211_vif *changed_vif,
+                     bool remove_vif)
+{
+       enum iwl_sf_state new_state;
+       u8 sta_id = IWL_MVM_STATION_COUNT;
+       struct iwl_mvm_vif *mvmvif = NULL;
+       struct iwl_mvm_active_iface_iterator_data data = {
+               .ignore_vif = changed_vif,
+               .sta_vif_state = SF_UNINIT,
+               .sta_vif_ap_sta_id = IWL_MVM_STATION_COUNT,
+       };
+
+       if (IWL_UCODE_API(mvm->fw->ucode_ver) < 8)
+               return 0;
+
+       /*
+        * Ignore the call if we are in HW Restart flow, or if the handled
+        * vif is a p2p device.
+        */
+       if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) ||
+           (changed_vif && changed_vif->type == NL80211_IFTYPE_P2P_DEVICE))
+               return 0;
+
+       ieee80211_iterate_active_interfaces_atomic(mvm->hw,
+                                                  IEEE80211_IFACE_ITER_NORMAL,
+                                                  iwl_mvm_bound_iface_iterator,
+                                                  &data);
+
+       /* If changed_vif exists and is not to be removed, add to the count */
+       if (changed_vif && !remove_vif)
+               data.num_active_macs++;
+
+       switch (data.num_active_macs) {
+       case 0:
+               /* If there are no active macs - change state to SF_INIT_OFF */
+               new_state = SF_INIT_OFF;
+               break;
+       case 1:
+               if (remove_vif) {
+                       /* The one active mac left is of type station
+                        * and we filled the relevant data during iteration
+                        */
+                       new_state = data.sta_vif_state;
+                       sta_id = data.sta_vif_ap_sta_id;
+               } else {
+                       if (WARN_ON(!changed_vif))
+                               return -EINVAL;
+                       if (changed_vif->type != NL80211_IFTYPE_STATION) {
+                               new_state = SF_UNINIT;
+                       } else if (changed_vif->bss_conf.assoc) {
+                               mvmvif = iwl_mvm_vif_from_mac80211(changed_vif);
+                               sta_id = mvmvif->ap_sta_id;
+                               new_state = SF_FULL_ON;
+                       } else {
+                               new_state = SF_INIT_OFF;
+                       }
+               }
+               break;
+       default:
+               /* If there are multiple active macs - change to SF_UNINIT */
+               new_state = SF_UNINIT;
+       }
+       return iwl_mvm_sf_config(mvm, sta_id, new_state);
+}
index 7a5b7473eafa615e946d3d4fe0802129149858bc..0a8af2083ddc5653e8124a2148619d9b527236d7 100644 (file)
@@ -452,8 +452,15 @@ void iwl_mvm_sta_drained_wk(struct work_struct *wk)
                        rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id],
                                                  lockdep_is_held(&mvm->mutex));
 
-               /* This station is in use */
-               if (!IS_ERR(sta))
+               /*
+                * This station is in use or RCU-removed; the latter happens in
+                * managed mode, where mac80211 removes the station before we
+                * can remove it from firmware (we can only do that after the
+                * MAC is marked unassociated), and possibly while the deauth
+                * frame to disconnect from the AP is still queued. Then, the
+                * station pointer is -ENOENT when the last skb is reclaimed.
+                */
+               if (!IS_ERR(sta) || PTR_ERR(sta) == -ENOENT)
                        continue;
 
                if (PTR_ERR(sta) == -EINVAL) {
@@ -932,19 +939,6 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
        IWL_DEBUG_HT(mvm, "Tx aggregation enabled on ra = %pM tid = %d\n",
                     sta->addr, tid);
 
-       if (mvm->cfg->ht_params->use_rts_for_aggregation) {
-               /*
-                * switch to RTS/CTS if it is the prefer protection
-                * method for HT traffic
-                * this function also sends the LQ command
-                */
-               return iwl_mvm_tx_protection(mvm, mvmsta, true);
-               /*
-                * TODO: remove the TLC_RTS flag when we tear down the last
-                * AGG session (agg_tids_count in DVM)
-                */
-       }
-
        return iwl_mvm_send_lq_cmd(mvm, &mvmsta->lq_sta.lq, false);
 }
 
@@ -1123,8 +1117,8 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm,
                memcpy(cmd.key, keyconf->key, keyconf->keylen);
                break;
        default:
-               WARN_ON(1);
-               return -EINVAL;
+               key_flags |= cpu_to_le16(STA_KEY_FLG_EXT);
+               memcpy(cmd.key, keyconf->key, keyconf->keylen);
        }
 
        if (!(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE))
@@ -1288,8 +1282,8 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
                                           0, NULL, CMD_SYNC);
                break;
        default:
-               IWL_ERR(mvm, "Unknown cipher %x\n", keyconf->cipher);
-               ret = -EINVAL;
+               ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf,
+                                          sta_id, 0, NULL, CMD_SYNC);
        }
 
        if (ret)
index 18be04da8e3fe5449307d4c63c5e6714e0e032e1..a0ec7b3473bddac890d4940c6f511a1464da0243 100644 (file)
@@ -340,7 +340,7 @@ static void check_exit_ctkill(struct work_struct *work)
 
        iwl_trans_start_hw(mvm->trans);
        temp = check_nic_temperature(mvm);
-       iwl_trans_stop_hw(mvm->trans, false);
+       iwl_trans_stop_device(mvm->trans);
 
        if (temp < MIN_TEMPERATURE || temp > MAX_TEMPERATURE) {
                IWL_DEBUG_TEMP(mvm, "Failed to measure NIC temperature\n");
index d87649ac88e1419fde870f4f7fdb4abc1d520fab..735f86da79856d6a97180641f21468117c39c5d5 100644 (file)
@@ -253,8 +253,7 @@ static void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm,
                memcpy(&tx_cmd->key[3], keyconf->key, keyconf->keylen);
                break;
        default:
-               IWL_ERR(mvm, "Unknown encode cipher %x\n", keyconf->cipher);
-               break;
+               tx_cmd->sec_ctl |= TX_CMD_SEC_EXT;
        }
 }
 
index 56cf819bc0c7003d970a16b08b493804d6e2544b..f4aff56a36da6e02a420963a5516c9e94bd03415 100644 (file)
@@ -518,6 +518,11 @@ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
        int i;
 
        lockdep_assert_held(&mvm->mutex);
+
+       /* SMPS is irrelevant for NICs that don't have at least 2 RX antenna */
+       if (num_of_ant(iwl_fw_valid_rx_ant(mvm->fw)) == 1)
+               return;
+
        mvmvif = iwl_mvm_vif_from_mac80211(vif);
        mvmvif->smps_requests[req_type] = smps_request;
        for (i = 0; i < NUM_IWL_MVM_SMPS_REQ; i++) {
index 051268c037b1d4f7d03715cdbf13b68311f883ff..674c75b0d002f23244f12de07d66f35aa7254073 100644 (file)
@@ -256,7 +256,6 @@ iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx)
  * @hw_base: pci hardware address support
  * @ucode_write_complete: indicates that the ucode has been copied.
  * @ucode_write_waitq: wait queue for uCode load
- * @status - transport specific status flags
  * @cmd_queue - command queue number
  * @rx_buf_size_8k: 8 kB RX buffer size
  * @bc_table_dword: true if the BC table expects DWORD (as opposed to bytes)
@@ -296,7 +295,6 @@ struct iwl_trans_pcie {
        wait_queue_head_t ucode_write_waitq;
        wait_queue_head_t wait_command_queue;
 
-       unsigned long status;
        u8 cmd_queue;
        u8 cmd_fifo;
        u8 n_no_reclaim_cmds;
@@ -315,24 +313,6 @@ struct iwl_trans_pcie {
        spinlock_t reg_lock;
 };
 
-/**
- * enum iwl_pcie_status: status of the PCIe transport
- * @STATUS_HCMD_ACTIVE: a SYNC command is being processed
- * @STATUS_DEVICE_ENABLED: APM is enabled
- * @STATUS_TPOWER_PMI: the device might be asleep (need to wake it up)
- * @STATUS_INT_ENABLED: interrupts are enabled
- * @STATUS_RFKILL: the HW RFkill switch is in KILL position
- * @STATUS_FW_ERROR: the fw is in error state
- */
-enum iwl_pcie_status {
-       STATUS_HCMD_ACTIVE,
-       STATUS_DEVICE_ENABLED,
-       STATUS_TPOWER_PMI,
-       STATUS_INT_ENABLED,
-       STATUS_RFKILL,
-       STATUS_FW_ERROR,
-};
-
 #define IWL_TRANS_GET_PCIE_TRANS(_iwl_trans) \
        ((struct iwl_trans_pcie *) ((_iwl_trans)->trans_specific))
 
@@ -399,8 +379,7 @@ void iwl_pcie_dump_csr(struct iwl_trans *trans);
 ******************************************************/
 static inline void iwl_disable_interrupts(struct iwl_trans *trans)
 {
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       clear_bit(STATUS_INT_ENABLED, &trans_pcie->status);
+       clear_bit(STATUS_INT_ENABLED, &trans->status);
 
        /* disable interrupts from uCode/NIC to host */
        iwl_write32(trans, CSR_INT_MASK, 0x00000000);
@@ -417,7 +396,7 @@ static inline void iwl_enable_interrupts(struct iwl_trans *trans)
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
 
        IWL_DEBUG_ISR(trans, "Enabling interrupts\n");
-       set_bit(STATUS_INT_ENABLED, &trans_pcie->status);
+       set_bit(STATUS_INT_ENABLED, &trans->status);
        iwl_write32(trans, CSR_INT_MASK, trans_pcie->inta_mask);
 }
 
@@ -477,12 +456,4 @@ static inline bool iwl_is_rfkill_set(struct iwl_trans *trans)
                CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW);
 }
 
-static inline void iwl_nic_error(struct iwl_trans *trans)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-
-       set_bit(STATUS_FW_ERROR, &trans_pcie->status);
-       iwl_op_mode_nic_error(trans->op_mode);
-}
-
 #endif /* __iwl_trans_int_pcie_h__ */
index 1d6bf7b98e2d0075c1e09f05b5f4ee96dce71474..7aeec5ccefa5a34082a3115bed773ad279a236a4 100644 (file)
@@ -162,11 +162,8 @@ static void iwl_pcie_rxq_inc_wr_ptr(struct iwl_trans *trans,
                rxq->write_actual = (rxq->write & ~0x7);
                iwl_write32(trans, FH_RSCSR_CHNL0_WPTR, rxq->write_actual);
        } else {
-               struct iwl_trans_pcie *trans_pcie =
-                       IWL_TRANS_GET_PCIE_TRANS(trans);
-
                /* If power-saving is in use, make sure device is awake */
-               if (test_bit(STATUS_TPOWER_PMI, &trans_pcie->status)) {
+               if (test_bit(STATUS_TPOWER_PMI, &trans->status)) {
                        reg = iwl_read32(trans, CSR_UCODE_DRV_GP1);
 
                        if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
@@ -222,7 +219,7 @@ static void iwl_pcie_rxq_restock(struct iwl_trans *trans)
         * stopped, we cannot access the HW (in particular not prph).
         * So don't try to restock if the APM has been already stopped.
         */
-       if (!test_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status))
+       if (!test_bit(STATUS_DEVICE_ENABLED, &trans->status))
                return;
 
        spin_lock_irqsave(&rxq->lock, flags);
@@ -791,7 +788,7 @@ static void iwl_pcie_irq_handle_error(struct iwl_trans *trans)
                             APMS_CLK_VAL_MRB_FUNC_MODE) ||
             (iwl_read_prph(trans, APMG_PS_CTRL_REG) &
                            APMG_PS_CTRL_VAL_RESET_REQ))) {
-               clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status);
+               clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status);
                iwl_op_mode_wimax_active(trans->op_mode);
                wake_up(&trans_pcie->wait_command_queue);
                return;
@@ -800,14 +797,14 @@ static void iwl_pcie_irq_handle_error(struct iwl_trans *trans)
        iwl_pcie_dump_csr(trans);
        iwl_dump_fh(trans, NULL);
 
-       /* set the ERROR bit before we wake up the caller */
-       set_bit(STATUS_FW_ERROR, &trans_pcie->status);
-       clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status);
-       wake_up(&trans_pcie->wait_command_queue);
-
        local_bh_disable();
-       iwl_nic_error(trans);
+       /* The STATUS_FW_ERROR bit is set in this function. This must happen
+        * before we wake up the command caller, to ensure a proper cleanup. */
+       iwl_trans_fw_error(trans);
        local_bh_enable();
+
+       clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status);
+       wake_up(&trans_pcie->wait_command_queue);
 }
 
 irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id)
@@ -894,14 +891,14 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id)
 
                iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
                if (hw_rfkill) {
-                       set_bit(STATUS_RFKILL, &trans_pcie->status);
-                       if (test_and_clear_bit(STATUS_HCMD_ACTIVE,
-                                              &trans_pcie->status))
+                       set_bit(STATUS_RFKILL, &trans->status);
+                       if (test_and_clear_bit(STATUS_SYNC_HCMD_ACTIVE,
+                                              &trans->status))
                                IWL_DEBUG_RF_KILL(trans,
                                                  "Rfkill while SYNC HCMD in flight\n");
                        wake_up(&trans_pcie->wait_command_queue);
                } else {
-                       clear_bit(STATUS_RFKILL, &trans_pcie->status);
+                       clear_bit(STATUS_RFKILL, &trans->status);
                }
 
                handled |= CSR_INT_BIT_RF_KILL;
@@ -1005,7 +1002,7 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id)
 
        /* Re-enable all interrupts */
        /* only Re-enable if disabled by irq */
-       if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status))
+       if (test_bit(STATUS_INT_ENABLED, &trans->status))
                iwl_enable_interrupts(trans);
        /* Re-enable RF_KILL if it occurred */
        else if (handled & CSR_INT_BIT_RF_KILL)
@@ -1160,7 +1157,7 @@ static irqreturn_t iwl_pcie_isr(int irq, void *data)
                 * the handler can be scheduled because of a previous
                 * interrupt.
                 */
-               if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) &&
+               if (test_bit(STATUS_INT_ENABLED, &trans->status) &&
                    !trans_pcie->inta)
                        iwl_enable_interrupts(trans);
                return IRQ_NONE;
@@ -1290,7 +1287,7 @@ irqreturn_t iwl_pcie_isr_ict(int irq, void *data)
        /* re-enable interrupts here since we don't have anything to service.
         * only Re-enable if disabled by irq.
         */
-       if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) &&
+       if (test_bit(STATUS_INT_ENABLED, &trans->status) &&
            !trans_pcie->inta)
                iwl_enable_interrupts(trans);
 
index cde9c16f6e4febb26c66c2206068bdba973c708a..eecd38e3f15f3cac1bd09f56e39996fb1f255537 100644 (file)
@@ -150,7 +150,6 @@ static void iwl_pcie_apm_config(struct iwl_trans *trans)
  */
 static int iwl_pcie_apm_init(struct iwl_trans *trans)
 {
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        int ret = 0;
        IWL_DEBUG_INFO(trans, "Init card's basic functions\n");
 
@@ -223,7 +222,7 @@ static int iwl_pcie_apm_init(struct iwl_trans *trans)
        /* Clear the interrupt in APMG if the NIC is in RFKILL */
        iwl_write_prph(trans, APMG_RTC_INT_STT_REG, APMG_RTC_INT_STT_RFKILL);
 
-       set_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status);
+       set_bit(STATUS_DEVICE_ENABLED, &trans->status);
 
 out:
        return ret;
@@ -249,10 +248,9 @@ static int iwl_pcie_apm_stop_master(struct iwl_trans *trans)
 
 static void iwl_pcie_apm_stop(struct iwl_trans *trans)
 {
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        IWL_DEBUG_INFO(trans, "Stop card, put in low power state\n");
 
-       clear_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status);
+       clear_bit(STATUS_DEVICE_ENABLED, &trans->status);
 
        /* Stop device's DMA activity */
        iwl_pcie_apm_stop_master(trans);
@@ -582,7 +580,6 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans,
 static int iwl_trans_pcie_start_fw(struct iwl_trans *trans,
                                   const struct fw_img *fw, bool run_in_rfkill)
 {
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        int ret;
        bool hw_rfkill;
 
@@ -592,16 +589,14 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans,
                return -EIO;
        }
 
-       clear_bit(STATUS_FW_ERROR, &trans_pcie->status);
-
        iwl_enable_rfkill_int(trans);
 
        /* If platform's RF_KILL switch is NOT set to KILL */
        hw_rfkill = iwl_is_rfkill_set(trans);
        if (hw_rfkill)
-               set_bit(STATUS_RFKILL, &trans_pcie->status);
+               set_bit(STATUS_RFKILL, &trans->status);
        else
-               clear_bit(STATUS_RFKILL, &trans_pcie->status);
+               clear_bit(STATUS_RFKILL, &trans->status);
        iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
        if (hw_rfkill && !run_in_rfkill)
                return -ERFKILL;
@@ -641,6 +636,7 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        unsigned long flags;
+       bool hw_rfkill;
 
        /* tell the device to stop sending interrupts */
        spin_lock_irqsave(&trans_pcie->irq_lock, flags);
@@ -657,7 +653,7 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
         * restart. So don't process again if the device is
         * already dead.
         */
-       if (test_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status)) {
+       if (test_bit(STATUS_DEVICE_ENABLED, &trans->status)) {
                iwl_pcie_tx_stop(trans);
                iwl_pcie_rx_stop(trans);
 
@@ -681,17 +677,34 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
        iwl_disable_interrupts(trans);
        spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
 
-       iwl_enable_rfkill_int(trans);
-
        /* stop and reset the on-board processor */
        iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
 
        /* clear all status bits */
-       clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status);
-       clear_bit(STATUS_INT_ENABLED, &trans_pcie->status);
-       clear_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status);
-       clear_bit(STATUS_TPOWER_PMI, &trans_pcie->status);
-       clear_bit(STATUS_RFKILL, &trans_pcie->status);
+       clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status);
+       clear_bit(STATUS_INT_ENABLED, &trans->status);
+       clear_bit(STATUS_DEVICE_ENABLED, &trans->status);
+       clear_bit(STATUS_TPOWER_PMI, &trans->status);
+       clear_bit(STATUS_RFKILL, &trans->status);
+
+       /*
+        * Even if we stop the HW, we still want the RF kill
+        * interrupt
+        */
+       iwl_enable_rfkill_int(trans);
+
+       /*
+        * Check again since the RF kill state may have changed while
+        * all the interrupts were disabled, in this case we couldn't
+        * receive the RF kill interrupt and update the state in the
+        * op_mode.
+        */
+       hw_rfkill = iwl_is_rfkill_set(trans);
+       if (hw_rfkill)
+               set_bit(STATUS_RFKILL, &trans->status);
+       else
+               clear_bit(STATUS_RFKILL, &trans->status);
+       iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
 }
 
 static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test)
@@ -776,7 +789,6 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans,
 
 static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)
 {
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        bool hw_rfkill;
        int err;
 
@@ -798,21 +810,20 @@ static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)
 
        hw_rfkill = iwl_is_rfkill_set(trans);
        if (hw_rfkill)
-               set_bit(STATUS_RFKILL, &trans_pcie->status);
+               set_bit(STATUS_RFKILL, &trans->status);
        else
-               clear_bit(STATUS_RFKILL, &trans_pcie->status);
+               clear_bit(STATUS_RFKILL, &trans->status);
        iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
 
        return 0;
 }
 
-static void iwl_trans_pcie_stop_hw(struct iwl_trans *trans,
-                                  bool op_mode_leaving)
+static void iwl_trans_pcie_op_mode_leave(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       bool hw_rfkill;
        unsigned long flags;
 
+       /* disable interrupts - don't enable HW RF kill interrupt */
        spin_lock_irqsave(&trans_pcie->irq_lock, flags);
        iwl_disable_interrupts(trans);
        spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
@@ -824,27 +835,6 @@ static void iwl_trans_pcie_stop_hw(struct iwl_trans *trans,
        spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
 
        iwl_pcie_disable_ict(trans);
-
-       if (!op_mode_leaving) {
-               /*
-                * Even if we stop the HW, we still want the RF kill
-                * interrupt
-                */
-               iwl_enable_rfkill_int(trans);
-
-               /*
-                * Check again since the RF kill state may have changed while
-                * all the interrupts were disabled, in this case we couldn't
-                * receive the RF kill interrupt and update the state in the
-                * op_mode.
-                */
-               hw_rfkill = iwl_is_rfkill_set(trans);
-               if (hw_rfkill)
-                       set_bit(STATUS_RFKILL, &trans_pcie->status);
-               else
-                       clear_bit(STATUS_RFKILL, &trans_pcie->status);
-               iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
-       }
 }
 
 static void iwl_trans_pcie_write8(struct iwl_trans *trans, u32 ofs, u8 val)
@@ -928,12 +918,10 @@ void iwl_trans_pcie_free(struct iwl_trans *trans)
 
 static void iwl_trans_pcie_set_pmi(struct iwl_trans *trans, bool state)
 {
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-
        if (state)
-               set_bit(STATUS_TPOWER_PMI, &trans_pcie->status);
+               set_bit(STATUS_TPOWER_PMI, &trans->status);
        else
-               clear_bit(STATUS_TPOWER_PMI, &trans_pcie->status);
+               clear_bit(STATUS_TPOWER_PMI, &trans->status);
 }
 
 static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, bool silent,
@@ -1457,7 +1445,7 @@ static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,
 
 static const struct iwl_trans_ops trans_ops_pcie = {
        .start_hw = iwl_trans_pcie_start_hw,
-       .stop_hw = iwl_trans_pcie_stop_hw,
+       .op_mode_leave = iwl_trans_pcie_op_mode_leave,
        .fw_alive = iwl_trans_pcie_fw_alive,
        .start_fw = iwl_trans_pcie_start_fw,
        .stop_device = iwl_trans_pcie_stop_device,
index a4ef5cc1110010d76439a670242c8d9a22888094..8df24787c1416b30675c275d3a7082613303865b 100644 (file)
@@ -207,7 +207,7 @@ static void iwl_pcie_txq_stuck_timer(unsigned long data)
                IWL_ERR(trans, "scratch %d = 0x%08x\n", i,
                        le32_to_cpu(txq->scratchbufs[i].scratch));
 
-       iwl_nic_error(trans);
+       iwl_trans_fw_error(trans);
 }
 
 /*
@@ -300,10 +300,8 @@ void iwl_pcie_txq_inc_wr_ptr(struct iwl_trans *trans, struct iwl_txq *txq)
                iwl_write32(trans, HBUS_TARG_WRPTR,
                            txq->q.write_ptr | (txq_id << 8));
        } else {
-               struct iwl_trans_pcie *trans_pcie =
-                       IWL_TRANS_GET_PCIE_TRANS(trans);
                /* if we're trying to save power */
-               if (test_bit(STATUS_TPOWER_PMI, &trans_pcie->status)) {
+               if (test_bit(STATUS_TPOWER_PMI, &trans->status)) {
                        /* wake up nic if it's powered down ...
                         * uCode will wake up, and interrupt us again, so next
                         * time we'll skip this part. */
@@ -1023,7 +1021,7 @@ static void iwl_pcie_cmdq_reclaim(struct iwl_trans *trans, int txq_id, int idx)
                if (nfreed++ > 0) {
                        IWL_ERR(trans, "HCMD skipped: index (%d) %d %d\n",
                                idx, q->write_ptr, q->read_ptr);
-                       iwl_nic_error(trans);
+                       iwl_trans_fw_error(trans);
                }
        }
 
@@ -1449,12 +1447,12 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans,
        iwl_pcie_cmdq_reclaim(trans, txq_id, index);
 
        if (!(meta->flags & CMD_ASYNC)) {
-               if (!test_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status)) {
+               if (!test_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status)) {
                        IWL_WARN(trans,
                                 "HCMD_ACTIVE already clear for command %s\n",
                                 get_cmd_string(trans_pcie, cmd->hdr.cmd));
                }
-               clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status);
+               clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status);
                IWL_DEBUG_INFO(trans, "Clearing HCMD_ACTIVE for command %s\n",
                               get_cmd_string(trans_pcie, cmd->hdr.cmd));
                wake_up(&trans_pcie->wait_command_queue);
@@ -1499,8 +1497,8 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans,
        IWL_DEBUG_INFO(trans, "Attempting to send sync command %s\n",
                       get_cmd_string(trans_pcie, cmd->id));
 
-       if (WARN(test_and_set_bit(STATUS_HCMD_ACTIVE,
-                                 &trans_pcie->status),
+       if (WARN(test_and_set_bit(STATUS_SYNC_HCMD_ACTIVE,
+                                 &trans->status),
                 "Command %s: a command is already active!\n",
                 get_cmd_string(trans_pcie, cmd->id)))
                return -EIO;
@@ -1511,7 +1509,7 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans,
        cmd_idx = iwl_pcie_enqueue_hcmd(trans, cmd);
        if (cmd_idx < 0) {
                ret = cmd_idx;
-               clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status);
+               clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status);
                IWL_ERR(trans,
                        "Error sending %s: enqueue_hcmd failed: %d\n",
                        get_cmd_string(trans_pcie, cmd->id), ret);
@@ -1523,8 +1521,8 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans,
 
                timeout -= COMMAND_POKE_TIMEOUT;
                ret = wait_event_timeout(trans_pcie->wait_command_queue,
-                                        !test_bit(STATUS_HCMD_ACTIVE,
-                                                  &trans_pcie->status),
+                                        !test_bit(STATUS_SYNC_HCMD_ACTIVE,
+                                                  &trans->status),
                                         COMMAND_POKE_TIMEOUT);
                if (ret)
                        break;
@@ -1552,17 +1550,17 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans,
                IWL_ERR(trans, "Current CMD queue read_ptr %d write_ptr %d\n",
                        q->read_ptr, q->write_ptr);
 
-               clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status);
+               clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status);
                IWL_DEBUG_INFO(trans, "Clearing HCMD_ACTIVE for command %s\n",
                               get_cmd_string(trans_pcie, cmd->id));
                ret = -ETIMEDOUT;
 
-               iwl_nic_error(trans);
+               iwl_trans_fw_error(trans);
 
                goto cancel;
        }
 
-       if (test_bit(STATUS_FW_ERROR, &trans_pcie->status)) {
+       if (test_bit(STATUS_FW_ERROR, &trans->status)) {
                IWL_ERR(trans, "FW error in SYNC CMD %s\n",
                        get_cmd_string(trans_pcie, cmd->id));
                dump_stack();
@@ -1571,7 +1569,7 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans,
        }
 
        if (!(cmd->flags & CMD_SEND_IN_RFKILL) &&
-           test_bit(STATUS_RFKILL, &trans_pcie->status)) {
+           test_bit(STATUS_RFKILL, &trans->status)) {
                IWL_DEBUG_RF_KILL(trans, "RFKILL in SYNC CMD... no rsp\n");
                ret = -ERFKILL;
                goto cancel;
@@ -1608,13 +1606,8 @@ cancel:
 
 int iwl_trans_pcie_send_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
 {
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-
-       if (test_bit(STATUS_FW_ERROR, &trans_pcie->status))
-               return -EIO;
-
        if (!(cmd->flags & CMD_SEND_IN_RFKILL) &&
-           test_bit(STATUS_RFKILL, &trans_pcie->status)) {
+           test_bit(STATUS_RFKILL, &trans->status)) {
                IWL_DEBUG_RF_KILL(trans, "Dropping CMD 0x%x: RF KILL\n",
                                  cmd->id);
                return -ERFKILL;
index 4d23647faef0451ef227804dbe1464bbd2442161..b994679abce0a2685dbe74098580e2efcef6076e 100644 (file)
@@ -538,23 +538,40 @@ static void mwifiex_reg_notifier(struct wiphy *wiphy,
                                 struct regulatory_request *request)
 {
        struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy);
+       struct mwifiex_private *priv = mwifiex_get_priv(adapter,
+                                                       MWIFIEX_BSS_ROLE_ANY);
 
        wiphy_dbg(wiphy, "info: cfg80211 regulatory domain callback for %c%c\n",
                  request->alpha2[0], request->alpha2[1]);
 
-       memcpy(adapter->country_code, request->alpha2, sizeof(request->alpha2));
-
        switch (request->initiator) {
        case NL80211_REGDOM_SET_BY_DRIVER:
        case NL80211_REGDOM_SET_BY_CORE:
        case NL80211_REGDOM_SET_BY_USER:
-               break;
-               /* Todo: apply driver specific changes in channel flags based
-                  on the request initiator if necessary. */
        case NL80211_REGDOM_SET_BY_COUNTRY_IE:
                break;
+       default:
+               wiphy_err(wiphy, "unknown regdom initiator: %d\n",
+                         request->initiator);
+               return;
+       }
+
+       /* Don't send world or same regdom info to firmware */
+       if (strncmp(request->alpha2, "00", 2) &&
+           strncmp(request->alpha2, adapter->country_code,
+                   sizeof(request->alpha2))) {
+               memcpy(adapter->country_code, request->alpha2,
+                      sizeof(request->alpha2));
+               mwifiex_send_domain_info_cmd_fw(wiphy);
+
+               if (adapter->dt_node) {
+                       char txpwr[] = {"marvell,00_txpwrlimit"};
+
+                       memcpy(&txpwr[8], adapter->country_code, 2);
+                       mwifiex_dnld_dt_cfgdata(priv, adapter->dt_node,
+                                               txpwr);
+               }
        }
-       mwifiex_send_domain_info_cmd_fw(wiphy);
 }
 
 /*
@@ -1171,10 +1188,10 @@ static int mwifiex_cfg80211_set_bitrate_mask(struct wiphy *wiphy,
        else
                bitmap_rates[1] = mask->control[band].legacy;
 
-       /* Fill MCS rates */
-       bitmap_rates[2] = mask->control[band].mcs[0];
+       /* Fill HT MCS rates */
+       bitmap_rates[2] = mask->control[band].ht_mcs[0];
        if (priv->adapter->hw_dev_mcs_support == HT_STREAM_2X2)
-               bitmap_rates[2] |= mask->control[band].mcs[1] << 8;
+               bitmap_rates[2] |= mask->control[band].ht_mcs[1] << 8;
 
        return mwifiex_send_cmd_sync(priv, HostCmd_CMD_TX_RATE_CFG,
                                     HostCmd_ACT_GEN_SET, 0, bitmap_rates);
index 8fcb500fa09b37c7e253906350141972998c5c9e..4cee6ceb7e9e9c10c0ca15773033df1f1156e18d 100644 (file)
@@ -468,8 +468,6 @@ enum P2P_MODES {
 #define MWIFIEX_CRITERIA_UNICAST       BIT(1)
 #define MWIFIEX_CRITERIA_MULTICAST     BIT(3)
 
-#define CFG_DATA_TYPE_CAL              2
-
 struct mwifiex_ie_types_header {
        __le16 type;
        __le16 len;
@@ -1592,12 +1590,6 @@ struct mwifiex_ie_list {
        struct mwifiex_ie ie_list[MAX_MGMT_IE_INDEX];
 } __packed;
 
-struct host_cmd_ds_802_11_cfg_data {
-       __le16 action;
-       __le16 type;
-       __le16 data_len;
-} __packed;
-
 struct coalesce_filt_field_param {
        u8 operation;
        u8 operand_len;
@@ -1678,7 +1670,6 @@ struct host_cmd_ds_command {
                struct host_cmd_ds_sys_config uap_sys_config;
                struct host_cmd_ds_sta_deauth sta_deauth;
                struct host_cmd_11ac_vht_cfg vht_cfg;
-               struct host_cmd_ds_802_11_cfg_data cfg_data;
                struct host_cmd_ds_coalesce_cfg coalesce_cfg;
        } params;
 } __packed;
index dc34457557f38452de46f47276d6194d4ff766e1..ab3416449bfd3c0f2668d312df9854cb3281eb9d 100644 (file)
@@ -32,6 +32,7 @@
 #include <net/lib80211.h>
 #include <linux/firmware.h>
 #include <linux/ctype.h>
+#include <linux/of.h>
 
 #include "decl.h"
 #include "ioctl.h"
@@ -739,6 +740,7 @@ struct mwifiex_adapter {
        u8 scan_delay_cnt;
        u8 empty_tx_q_cnt;
        const struct firmware *cal_data;
+       struct device_node *dt_node;
 
        /* 11AC */
        u32 is_hw_11ac_capable;
@@ -1151,6 +1153,8 @@ void mwifiex_uap_del_sta_data(struct mwifiex_private *priv,
 void mwifiex_11h_process_join(struct mwifiex_private *priv, u8 **buffer,
                              struct mwifiex_bssdescriptor *bss_desc);
 int mwifiex_11h_handle_event_chanswann(struct mwifiex_private *priv);
+int mwifiex_dnld_dt_cfgdata(struct mwifiex_private *priv,
+                           struct device_node *node, const char *prefix);
 
 extern const struct ethtool_ops mwifiex_ethtool_ops;
 
index 1efa43ec1c6ec3921d143752b3fb7ab3d6511902..9c2404cd755f34dcfd85922c4b7c9bf8a816dbb8 100644 (file)
@@ -1156,30 +1156,61 @@ static u32 mwifiex_parse_cal_cfg(u8 *src, size_t len, u8 *dst)
        return d - dst;
 }
 
+int mwifiex_dnld_dt_cfgdata(struct mwifiex_private *priv,
+                           struct device_node *node, const char *prefix)
+{
+#ifdef CONFIG_OF
+       struct property *prop;
+       size_t len = strlen(prefix);
+       int ret;
+
+       /* look for all matching property names */
+       for_each_property_of_node(node, prop) {
+               if (len > strlen(prop->name) ||
+                   strncmp(prop->name, prefix, len))
+                       continue;
+
+               /* property header is 6 bytes */
+               if (prop && prop->value && prop->length > 6) {
+                       ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_CFG_DATA,
+                                                   HostCmd_ACT_GEN_SET, 0,
+                                                   prop);
+                       if (ret)
+                               return ret;
+               }
+       }
+#endif
+       return 0;
+}
+
 /* This function prepares command of set_cfg_data. */
 static int mwifiex_cmd_cfg_data(struct mwifiex_private *priv,
-                               struct host_cmd_ds_command *cmd,
-                               u16 cmd_action)
+                               struct host_cmd_ds_command *cmd, void *data_buf)
 {
-       struct host_cmd_ds_802_11_cfg_data *cfg_data = &cmd->params.cfg_data;
        struct mwifiex_adapter *adapter = priv->adapter;
-       u32 len, cal_data_offset;
-       u8 *tmp_cmd = (u8 *)cmd;
+       struct property *prop = data_buf;
+       u32 len;
+       u8 *data = (u8 *)cmd + S_DS_GEN;
+       int ret;
 
-       cal_data_offset = S_DS_GEN + sizeof(*cfg_data);
-       if ((adapter->cal_data->data) && (adapter->cal_data->size > 0))
+       if (prop) {
+               len = prop->length;
+               ret = of_property_read_u8_array(adapter->dt_node, prop->name,
+                                               data, len);
+               if (ret)
+                       return ret;
+               dev_dbg(adapter->dev,
+                       "download cfg_data from device tree: %s\n", prop->name);
+       } else if (adapter->cal_data->data && adapter->cal_data->size > 0) {
                len = mwifiex_parse_cal_cfg((u8 *)adapter->cal_data->data,
-                                           adapter->cal_data->size,
-                                           (u8 *)(tmp_cmd + cal_data_offset));
-       else
+                                           adapter->cal_data->size, data);
+               dev_dbg(adapter->dev, "download cfg_data from config file\n");
+       } else {
                return -1;
-
-       cfg_data->action = cpu_to_le16(cmd_action);
-       cfg_data->type = cpu_to_le16(CFG_DATA_TYPE_CAL);
-       cfg_data->data_len = cpu_to_le16(len);
+       }
 
        cmd->command = cpu_to_le16(HostCmd_CMD_CFG_DATA);
-       cmd->size = cpu_to_le16(S_DS_GEN + sizeof(*cfg_data) + len);
+       cmd->size = cpu_to_le16(S_DS_GEN + len);
 
        return 0;
 }
@@ -1267,7 +1298,7 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
                ret = mwifiex_cmd_get_hw_spec(priv, cmd_ptr);
                break;
        case HostCmd_CMD_CFG_DATA:
-               ret = mwifiex_cmd_cfg_data(priv, cmd_ptr, cmd_action);
+               ret = mwifiex_cmd_cfg_data(priv, cmd_ptr, data_buf);
                break;
        case HostCmd_CMD_MAC_CONTROL:
                ret = mwifiex_cmd_mac_control(priv, cmd_ptr, cmd_action,
@@ -1527,7 +1558,19 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta)
                if (ret)
                        return -1;
 
-               /* Download calibration data to firmware */
+               /* Download calibration data to firmware.
+                * The cal-data can be read from device tree and/or
+                * a configuration file and downloaded to firmware.
+                */
+               adapter->dt_node =
+                               of_find_node_by_name(NULL, "marvell_cfgdata");
+               if (adapter->dt_node) {
+                       ret = mwifiex_dnld_dt_cfgdata(priv, adapter->dt_node,
+                                                     "marvell,caldata");
+                       if (ret)
+                               return -1;
+               }
+
                if (adapter->cal_data) {
                        ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_CFG_DATA,
                                                HostCmd_ACT_GEN_SET, 0, NULL);
index a09398fe9e2a67218f50530af8a0b4616443cbbb..3edc92fad319ab21c4e1dd04aa9d65a0235e4c4c 100644 (file)
@@ -205,6 +205,14 @@ static int mwifiex_process_country_ie(struct mwifiex_private *priv,
                return 0;
        }
 
+       if (!strncmp(priv->adapter->country_code, &country_ie[2], 2)) {
+               rcu_read_unlock();
+               wiphy_dbg(priv->wdev->wiphy,
+                         "11D: skip setting domain info in FW\n");
+               return 0;
+       }
+       memcpy(priv->adapter->country_code, &country_ie[2], 2);
+
        domain_info->country_code[0] = country_ie[2];
        domain_info->country_code[1] = country_ie[3];
        domain_info->country_code[2] = ' ';
@@ -226,6 +234,13 @@ static int mwifiex_process_country_ie(struct mwifiex_private *priv,
                return -1;
        }
 
+       if (priv->adapter->dt_node) {
+               char txpwr[] = {"marvell,00_txpwrlimit"};
+
+               memcpy(&txpwr[8], priv->adapter->country_code, 2);
+               mwifiex_dnld_dt_cfgdata(priv, priv->adapter->dt_node, txpwr);
+       }
+
        return 0;
 }
 
index e9abc7b536cdebb5434caae1cbd487378ad0dfe1..80a10212b1b9bee63eafcae9d3142e6aee18d9e2 100644 (file)
@@ -747,6 +747,8 @@ enum station_parameters_apply_mask {
  * @supported_channels_len: number of supported channels
  * @supported_oper_classes: supported oper classes in IEEE 802.11 format
  * @supported_oper_classes_len: number of supported operating classes
+ * @opmode_notif: operating mode field from Operating Mode Notification
+ * @opmode_notif_used: information if operating mode field is used
  */
 struct station_parameters {
        const u8 *supported_rates;
@@ -770,6 +772,8 @@ struct station_parameters {
        u8 supported_channels_len;
        const u8 *supported_oper_classes;
        u8 supported_oper_classes_len;
+       u8 opmode_notif;
+       bool opmode_notif_used;
 };
 
 /**
@@ -1762,7 +1766,8 @@ enum wiphy_params_flags {
 struct cfg80211_bitrate_mask {
        struct {
                u32 legacy;
-               u8 mcs[IEEE80211_HT_MCS_MASK_LEN];
+               u8 ht_mcs[IEEE80211_HT_MCS_MASK_LEN];
+               u16 vht_mcs[NL80211_VHT_NSS_MAX];
        } control[IEEE80211_NUM_BANDS];
 };
 /**
@@ -2675,6 +2680,34 @@ struct wiphy_coalesce_support {
        int max_pkt_offset;
 };
 
+/**
+ * enum wiphy_vendor_command_flags - validation flags for vendor commands
+ * @WIPHY_VENDOR_CMD_NEED_WDEV: vendor command requires wdev
+ * @WIPHY_VENDOR_CMD_NEED_NETDEV: vendor command requires netdev
+ * @WIPHY_VENDOR_CMD_NEED_RUNNING: interface/wdev must be up & running
+ *     (must be combined with %_WDEV or %_NETDEV)
+ */
+enum wiphy_vendor_command_flags {
+       WIPHY_VENDOR_CMD_NEED_WDEV = BIT(0),
+       WIPHY_VENDOR_CMD_NEED_NETDEV = BIT(1),
+       WIPHY_VENDOR_CMD_NEED_RUNNING = BIT(2),
+};
+
+/**
+ * struct wiphy_vendor_command - vendor command definition
+ * @info: vendor command identifying information, as used in nl80211
+ * @flags: flags, see &enum wiphy_vendor_command_flags
+ * @doit: callback for the operation, note that wdev is %NULL if the
+ *     flags didn't ask for a wdev and non-%NULL otherwise; the data
+ *     pointer may be %NULL if userspace provided no data at all
+ */
+struct wiphy_vendor_command {
+       struct nl80211_vendor_cmd_info info;
+       u32 flags;
+       int (*doit)(struct wiphy *wiphy, struct wireless_dev *wdev,
+                   const void *data, int data_len);
+};
+
 /**
  * struct wiphy - wireless hardware description
  * @reg_notifier: the driver's regulatory notification callback,
@@ -2788,6 +2821,9 @@ struct wiphy_coalesce_support {
  * @extended_capabilities_mask: mask of the valid values
  * @extended_capabilities_len: length of the extended capabilities
  * @coalesce: packet coalescing support information
+ *
+ * @vendor_commands: array of vendor commands supported by the hardware
+ * @n_vendor_commands: number of vendor commands
  */
 struct wiphy {
        /* assign these fields before you register the wiphy */
@@ -2899,6 +2935,9 @@ struct wiphy {
 
        const struct wiphy_coalesce_support *coalesce;
 
+       const struct wiphy_vendor_command *vendor_commands;
+       int n_vendor_commands;
+
        char priv[0] __aligned(NETDEV_ALIGN);
 };
 
@@ -3843,6 +3882,75 @@ void wiphy_rfkill_start_polling(struct wiphy *wiphy);
  */
 void wiphy_rfkill_stop_polling(struct wiphy *wiphy);
 
+/**
+ * DOC: Vendor commands
+ *
+ * Occasionally, there are special protocol or firmware features that
+ * can't be implemented very openly. For this and similar cases, the
+ * vendor command functionality allows implementing the features with
+ * (typically closed-source) userspace and firmware, using nl80211 as
+ * the configuration mechanism.
+ *
+ * A driver supporting vendor commands must register them as an array
+ * in struct wiphy, with handlers for each one, each command has an
+ * OUI and sub command ID to identify it.
+ *
+ * Note that this feature should not be (ab)used to implement protocol
+ * features that could openly be shared across drivers. In particular,
+ * it must never be required to use vendor commands to implement any
+ * "normal" functionality that higher-level userspace like connection
+ * managers etc. need.
+ */
+
+struct sk_buff *__cfg80211_alloc_reply_skb(struct wiphy *wiphy,
+                                          enum nl80211_commands cmd,
+                                          enum nl80211_attrs attr,
+                                          int approxlen);
+
+/**
+ * cfg80211_vendor_cmd_alloc_reply_skb - allocate vendor command reply
+ * @wiphy: the wiphy
+ * @approxlen: an upper bound of the length of the data that will
+ *     be put into the skb
+ *
+ * This function allocates and pre-fills an skb for a reply to
+ * a vendor command. Since it is intended for a reply, calling
+ * it outside of a vendor command's doit() operation is invalid.
+ *
+ * The returned skb is pre-filled with some identifying data in
+ * a way that any data that is put into the skb (with skb_put(),
+ * nla_put() or similar) will end up being within the
+ * %NL80211_ATTR_VENDOR_DATA attribute, so all that needs to be done
+ * with the skb is adding data for the corresponding userspace tool
+ * which can then read that data out of the vendor data attribute.
+ * You must not modify the skb in any other way.
+ *
+ * When done, call cfg80211_vendor_cmd_reply() with the skb and return
+ * its error code as the result of the doit() operation.
+ *
+ * Return: An allocated and pre-filled skb. %NULL if any errors happen.
+ */
+static inline struct sk_buff *
+cfg80211_vendor_cmd_alloc_reply_skb(struct wiphy *wiphy, int approxlen)
+{
+       return __cfg80211_alloc_reply_skb(wiphy, NL80211_CMD_VENDOR,
+                                         NL80211_ATTR_VENDOR_DATA, approxlen);
+}
+
+/**
+ * cfg80211_vendor_cmd_reply - send the reply skb
+ * @skb: The skb, must have been allocated with
+ *     cfg80211_vendor_cmd_alloc_reply_skb()
+ *
+ * Since calling this function will usually be the last thing
+ * before returning from the vendor command doit() you should
+ * return the error code.  Note that this function consumes the
+ * skb regardless of the return value.
+ *
+ * Return: An error code or 0 on success.
+ */
+int cfg80211_vendor_cmd_reply(struct sk_buff *skb);
+
 #ifdef CONFIG_NL80211_TESTMODE
 /**
  * DOC: Test mode
@@ -3878,8 +3986,12 @@ void wiphy_rfkill_stop_polling(struct wiphy *wiphy);
  *
  * Return: An allocated and pre-filled skb. %NULL if any errors happen.
  */
-struct sk_buff *cfg80211_testmode_alloc_reply_skb(struct wiphy *wiphy,
-                                                 int approxlen);
+static inline struct sk_buff *
+cfg80211_testmode_alloc_reply_skb(struct wiphy *wiphy, int approxlen)
+{
+       return __cfg80211_alloc_reply_skb(wiphy, NL80211_CMD_TESTMODE,
+                                         NL80211_ATTR_TESTDATA, approxlen);
+}
 
 /**
  * cfg80211_testmode_reply - send the reply skb
@@ -3893,7 +4005,10 @@ struct sk_buff *cfg80211_testmode_alloc_reply_skb(struct wiphy *wiphy,
  *
  * Return: An error code or 0 on success.
  */
-int cfg80211_testmode_reply(struct sk_buff *skb);
+static inline int cfg80211_testmode_reply(struct sk_buff *skb)
+{
+       return cfg80211_vendor_cmd_reply(skb);
+}
 
 /**
  * cfg80211_testmode_alloc_event_skb - allocate testmode event
index 3cd408b326de7400b00e6284be2524955beefe27..531785f5819ecb0ba0e665dd9be444ea8276b03d 100644 (file)
@@ -1162,6 +1162,19 @@ static inline bool ieee80211_vif_is_mesh(struct ieee80211_vif *vif)
        return false;
 }
 
+/**
+ * wdev_to_ieee80211_vif - return a vif struct from a wdev
+ * @wdev: the wdev to get the vif for
+ *
+ * This can be used by mac80211 drivers with direct cfg80211 APIs
+ * (like the vendor commands) that get a wdev.
+ *
+ * Note that this function may return %NULL if the given wdev isn't
+ * associated with a vif that the driver knows about (e.g. monitor
+ * or AP_VLAN interfaces.)
+ */
+struct ieee80211_vif *wdev_to_ieee80211_vif(struct wireless_dev *wdev);
+
 /**
  * enum ieee80211_key_flags - key flags
  *
@@ -1600,6 +1613,9 @@ enum ieee80211_hw_flags {
  * @extra_tx_headroom: headroom to reserve in each transmit skb
  *     for use by the driver (e.g. for transmit headers.)
  *
+ * @extra_beacon_tailroom: tailroom to reserve in each beacon tx skb.
+ *     Can be used by drivers to add extra IEs.
+ *
  * @channel_change_time: time (in microseconds) it takes to change channels.
  *
  * @max_signal: Maximum value for signal (rssi) in RX information, used
@@ -1682,6 +1698,7 @@ struct ieee80211_hw {
        void *priv;
        u32 flags;
        unsigned int extra_tx_headroom;
+       unsigned int extra_beacon_tailroom;
        int channel_change_time;
        int vif_data_size;
        int sta_data_size;
@@ -2398,9 +2415,6 @@ enum ieee80211_roc_type {
  *     See the section "Frame filtering" for more information.
  *     This callback must be implemented and can sleep.
  *
- * @set_multicast_list: Configure the device's interface specific RX multicast
- *     filter. This callback is optional. This callback must be atomic.
- *
  * @set_tim: Set TIM bit. mac80211 calls this function when a TIM bit
  *     must be set or cleared for a given STA. Must be atomic.
  *
@@ -2485,7 +2499,11 @@ enum ieee80211_roc_type {
  *     AP, IBSS/WDS/mesh peer etc. This callback can sleep.
  *
  * @sta_remove: Notifies low level driver about removal of an associated
- *     station, AP, IBSS/WDS/mesh peer etc. This callback can sleep.
+ *     station, AP, IBSS/WDS/mesh peer etc. Note that after the callback
+ *     returns it isn't safe to use the pointer, not even RCU protected;
+ *     no RCU grace period is guaranteed between returning here and freeing
+ *     the station. See @sta_pre_rcu_remove if needed.
+ *     This callback can sleep.
  *
  * @sta_add_debugfs: Drivers can use this callback to add debugfs files
  *     when a station is added to mac80211's station list. This callback
@@ -2504,7 +2522,17 @@ enum ieee80211_roc_type {
  *     station (which can be the AP, a client, IBSS/WDS/mesh peer etc.)
  *     This callback is mutually exclusive with @sta_add/@sta_remove.
  *     It must not fail for down transitions but may fail for transitions
- *     up the list of states.
+ *     up the list of states. Also note that after the callback returns it
+ *     isn't safe to use the pointer, not even RCU protected - no RCU grace
+ *     period is guaranteed between returning here and freeing the station.
+ *     See @sta_pre_rcu_remove if needed.
+ *     The callback can sleep.
+ *
+ * @sta_pre_rcu_remove: Notify driver about station removal before RCU
+ *     synchronisation. This is useful if a driver needs to have station
+ *     pointers protected using RCU, it can then use this call to clear
+ *     the pointers instead of waiting for an RCU grace period to elapse
+ *     in @sta_state.
  *     The callback can sleep.
  *
  * @sta_rc_update: Notifies the driver of changes to the bitrates that can be
@@ -2764,10 +2792,6 @@ struct ieee80211_ops {
                                 unsigned int changed_flags,
                                 unsigned int *total_flags,
                                 u64 multicast);
-       void (*set_multicast_list)(struct ieee80211_hw *hw,
-                                  struct ieee80211_vif *vif, bool allmulti,
-                                  struct netdev_hw_addr_list *mc_list);
-
        int (*set_tim)(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
                       bool set);
        int (*set_key)(struct ieee80211_hw *hw, enum set_key_cmd cmd,
@@ -2821,6 +2845,9 @@ struct ieee80211_ops {
                         struct ieee80211_sta *sta,
                         enum ieee80211_sta_state old_state,
                         enum ieee80211_sta_state new_state);
+       void (*sta_pre_rcu_remove)(struct ieee80211_hw *hw,
+                                  struct ieee80211_vif *vif,
+                                  struct ieee80211_sta *sta);
        void (*sta_rc_update)(struct ieee80211_hw *hw,
                              struct ieee80211_vif *vif,
                              struct ieee80211_sta *sta,
index 129b7b08714848279f3638019892a4dc0e9e6d65..e1307909ecf118728434286aa2150da73d4d0225 100644 (file)
  *     other station that transmission must be blocked until the channel
  *     switch is complete.
  *
+ * @NL80211_CMD_VENDOR: Vendor-specified command/event. The command is specified
+ *     by the %NL80211_ATTR_VENDOR_ID attribute and a sub-command in
+ *     %NL80211_ATTR_VENDOR_SUBCMD. Parameter(s) can be transported in
+ *     %NL80211_ATTR_VENDOR_DATA.
+ *     For feature advertisement, the %NL80211_ATTR_VENDOR_DATA attribute is
+ *     used in the wiphy data as a nested attribute containing descriptions
+ *     (&struct nl80211_vendor_cmd_info) of the supported vendor commands.
+ *     This may also be sent as an event with the same attributes.
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -860,6 +869,8 @@ enum nl80211_commands {
 
        NL80211_CMD_CHANNEL_SWITCH,
 
+       NL80211_CMD_VENDOR,
+
        /* add new commands above here */
 
        /* used to define NL80211_CMD_MAX below */
@@ -1520,6 +1531,16 @@ enum nl80211_commands {
  * @NL80211_ATTR_SUPPORT_10_MHZ: A flag indicating that the device supports
  *     10 MHz channel bandwidth.
  *
+ * @NL80211_ATTR_OPMODE_NOTIF: Operating mode field from Operating Mode
+ *     Notification Element based on association request when used with
+ *     %NL80211_CMD_NEW_STATION; u8 attribute.
+ *
+ * @NL80211_ATTR_VENDOR_ID: The vendor ID, either a 24-bit OUI or, if
+ *     %NL80211_VENDOR_ID_IS_LINUX is set, a special Linux ID (not used yet)
+ * @NL80211_ATTR_VENDOR_SUBCMD: vendor sub-command
+ * @NL80211_ATTR_VENDOR_DATA: data for the vendor command, if any; this
+ *     attribute is also used for vendor command feature advertisement
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -1839,6 +1860,12 @@ enum nl80211_attrs {
        NL80211_ATTR_SUPPORT_5_MHZ,
        NL80211_ATTR_SUPPORT_10_MHZ,
 
+       NL80211_ATTR_OPMODE_NOTIF,
+
+       NL80211_ATTR_VENDOR_ID,
+       NL80211_ATTR_VENDOR_SUBCMD,
+       NL80211_ATTR_VENDOR_DATA,
+
        /* add attributes here, update the policy in nl80211.c */
 
        __NL80211_ATTR_AFTER_LAST,
@@ -3083,21 +3110,35 @@ enum nl80211_key_attributes {
  *     in an array of rates as defined in IEEE 802.11 7.3.2.2 (u8 values with
  *     1 = 500 kbps) but without the IE length restriction (at most
  *     %NL80211_MAX_SUPP_RATES in a single array).
- * @NL80211_TXRATE_MCS: HT (MCS) rates allowed for TX rate selection
+ * @NL80211_TXRATE_HT: HT (MCS) rates allowed for TX rate selection
  *     in an array of MCS numbers.
+ * @NL80211_TXRATE_VHT: VHT rates allowed for TX rate selection,
+ *     see &struct nl80211_txrate_vht
  * @__NL80211_TXRATE_AFTER_LAST: internal
  * @NL80211_TXRATE_MAX: highest TX rate attribute
  */
 enum nl80211_tx_rate_attributes {
        __NL80211_TXRATE_INVALID,
        NL80211_TXRATE_LEGACY,
-       NL80211_TXRATE_MCS,
+       NL80211_TXRATE_HT,
+       NL80211_TXRATE_VHT,
 
        /* keep last */
        __NL80211_TXRATE_AFTER_LAST,
        NL80211_TXRATE_MAX = __NL80211_TXRATE_AFTER_LAST - 1
 };
 
+#define NL80211_TXRATE_MCS NL80211_TXRATE_HT
+#define NL80211_VHT_NSS_MAX            8
+
+/**
+ * struct nl80211_txrate_vht - VHT MCS/NSS txrate bitmap
+ * @mcs: MCS bitmap table for each NSS (array index 0 for 1 stream, etc.)
+ */
+struct nl80211_txrate_vht {
+       __u16 mcs[NL80211_VHT_NSS_MAX];
+};
+
 /**
  * enum nl80211_band - Frequency band
  * @NL80211_BAND_2GHZ: 2.4 GHz ISM band
@@ -3959,4 +4000,24 @@ enum nl80211_rxmgmt_flags {
        NL80211_RXMGMT_FLAG_ANSWERED = 1 << 0,
 };
 
+/*
+ * If this flag is unset, the lower 24 bits are an OUI, if set
+ * a Linux nl80211 vendor ID is used (no such IDs are allocated
+ * yet, so that's not valid so far)
+ */
+#define NL80211_VENDOR_ID_IS_LINUX     0x80000000
+
+/**
+ * struct nl80211_vendor_cmd_info - vendor command data
+ * @vendor_id: If the %NL80211_VENDOR_ID_IS_LINUX flag is clear, then the
+ *     value is a 24-bit OUI; if it is set then a separately allocated ID
+ *     may be used, but no such IDs are allocated yet. New IDs should be
+ *     added to this file when needed.
+ * @subcmd: sub-command ID for the command
+ */
+struct nl80211_vendor_cmd_info {
+       __u32 vendor_id;
+       __u32 subcmd;
+};
+
 #endif /* __LINUX_NL80211_H */
index f80e8c4c6bcd303762781ed8a2aa613ff763f5fa..ac185286842d67de981da089b07edcde0ccaf87f 100644 (file)
@@ -301,9 +301,10 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
                if (!sta)
                        goto out;
 
-               if (pairwise)
+               if (pairwise && key_idx < NUM_DEFAULT_KEYS)
                        key = rcu_dereference(sta->ptk[key_idx]);
-               else if (key_idx < NUM_DEFAULT_KEYS)
+               else if (!pairwise &&
+                        key_idx < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS)
                        key = rcu_dereference(sta->gtk[key_idx]);
        } else
                key = rcu_dereference(sdata->keys[key_idx]);
@@ -873,8 +874,8 @@ static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata,
        return 0;
 }
 
-int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata,
-                           struct cfg80211_beacon_data *params)
+static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata,
+                                  struct cfg80211_beacon_data *params)
 {
        struct beacon_data *new, *old;
        int new_head_len, new_tail_len;
@@ -1097,17 +1098,8 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
        if (old_probe_resp)
                kfree_rcu(old_probe_resp, rcu_head);
 
-       list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
-               sta_info_flush_defer(vlan);
-       sta_info_flush_defer(sdata);
-       synchronize_net();
-       rcu_barrier();
-       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);
+       __sta_info_flush(sdata, true);
+       ieee80211_free_keys(sdata, true);
 
        sdata->vif.bss_conf.enable_beacon = false;
        sdata->vif.bss_conf.ssid_len = 0;
@@ -2587,8 +2579,8 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy,
                int j;
 
                sdata->rc_rateidx_mask[i] = mask->control[i].legacy;
-               memcpy(sdata->rc_rateidx_mcs_mask[i], mask->control[i].mcs,
-                      sizeof(mask->control[i].mcs));
+               memcpy(sdata->rc_rateidx_mcs_mask[i], mask->control[i].ht_mcs,
+                      sizeof(mask->control[i].ht_mcs));
 
                sdata->rc_has_mcs_mask[i] = false;
                if (!sband)
@@ -3047,8 +3039,8 @@ unlock:
        sdata_unlock(sdata);
 }
 
-static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
-                                   struct cfg80211_csa_settings *params)
+int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
+                            struct cfg80211_csa_settings *params)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_local *local = sdata->local;
index 5d03c47c0a4cb4fa60e861750956c64bb8c90337..ef8b385eff04e4c7a279a92722fedc3f84163f6c 100644 (file)
@@ -242,22 +242,6 @@ static inline u64 drv_prepare_multicast(struct ieee80211_local *local,
        return ret;
 }
 
-static inline void drv_set_multicast_list(struct ieee80211_local *local,
-                                         struct ieee80211_sub_if_data *sdata,
-                                         struct netdev_hw_addr_list *mc_list)
-{
-       bool allmulti = sdata->flags & IEEE80211_SDATA_ALLMULTI;
-
-       trace_drv_set_multicast_list(local, sdata, mc_list->count);
-
-       check_sdata_in_driver(sdata);
-
-       if (local->ops->set_multicast_list)
-               local->ops->set_multicast_list(&local->hw, &sdata->vif,
-                                              allmulti, mc_list);
-       trace_drv_return_void(local);
-}
-
 static inline void drv_configure_filter(struct ieee80211_local *local,
                                        unsigned int changed_flags,
                                        unsigned int *total_flags,
@@ -550,6 +534,22 @@ static inline void drv_sta_remove_debugfs(struct ieee80211_local *local,
 }
 #endif
 
+static inline void drv_sta_pre_rcu_remove(struct ieee80211_local *local,
+                                         struct ieee80211_sub_if_data *sdata,
+                                         struct sta_info *sta)
+{
+       might_sleep();
+
+       sdata = get_bss_sdata(sdata);
+       check_sdata_in_driver(sdata);
+
+       trace_drv_sta_pre_rcu_remove(local, sdata, &sta->sta);
+       if (local->ops->sta_pre_rcu_remove)
+               local->ops->sta_pre_rcu_remove(&local->hw, &sdata->vif,
+                                              &sta->sta);
+       trace_drv_return_void(local);
+}
+
 static inline __must_check
 int drv_sta_state(struct ieee80211_local *local,
                  struct ieee80211_sub_if_data *sdata,
index 2eda7b13124abb7469a8b7b86503de07c0155623..d6ba841437b6e41986163976e71650a9c911bbbf 100644 (file)
@@ -522,7 +522,7 @@ int ieee80211_ibss_csa_beacon(struct ieee80211_sub_if_data *sdata,
        if (csa_settings)
                ieee80211_send_action_csa(sdata, csa_settings);
 
-       ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
+       return BSS_CHANGED_BEACON;
  out:
        return ret;
 }
@@ -534,7 +534,8 @@ int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata)
        int err;
        u16 capability;
 
-       sdata_lock(sdata);
+       sdata_assert_lock(sdata);
+
        /* update cfg80211 bss information with the new channel */
        if (!is_zero_ether_addr(ifibss->bssid)) {
                capability = WLAN_CAPABILITY_IBSS;
@@ -559,10 +560,12 @@ int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata)
 
        /* generate the beacon */
        err = ieee80211_ibss_csa_beacon(sdata, NULL);
-       sdata_unlock(sdata);
        if (err < 0)
                return err;
 
+       if (err)
+               ieee80211_bss_info_change_notify(sdata, err);
+
        return 0;
 }
 
@@ -753,12 +756,16 @@ static void ieee80211_csa_connection_drop_work(struct work_struct *work)
                container_of(work, struct ieee80211_sub_if_data,
                             u.ibss.csa_connection_drop_work);
 
+       sdata_lock(sdata);
+
        ieee80211_ibss_disconnect(sdata);
        synchronize_rcu();
        skb_queue_purge(&sdata->skb_queue);
 
        /* trigger a scan to find another IBSS network to join */
        ieee80211_queue_work(&sdata->local->hw, &sdata->work);
+
+       sdata_unlock(sdata);
 }
 
 static void ieee80211_ibss_csa_mark_radar(struct ieee80211_sub_if_data *sdata)
@@ -784,18 +791,10 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,
        struct cfg80211_csa_settings params;
        struct ieee80211_csa_ie csa_ie;
        struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
-       struct ieee80211_chanctx_conf *chanctx_conf;
-       struct ieee80211_chanctx *chanctx;
        enum nl80211_channel_type ch_type;
-       int err, num_chanctx;
+       int err;
        u32 sta_flags;
 
-       if (sdata->vif.csa_active)
-               return true;
-
-       if (!sdata->vif.bss_conf.ibss_joined)
-               return false;
-
        sta_flags = IEEE80211_STA_DISABLE_VHT;
        switch (ifibss->chandef.width) {
        case NL80211_CHAN_WIDTH_5:
@@ -830,9 +829,6 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,
        params.count = csa_ie.count;
        params.chandef = csa_ie.chandef;
 
-       if (ifibss->chandef.chan->band != params.chandef.chan->band)
-               goto disconnect;
-
        switch (ifibss->chandef.width) {
        case NL80211_CHAN_WIDTH_20_NOHT:
        case NL80211_CHAN_WIDTH_20:
@@ -888,28 +884,12 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,
                params.radar_required = true;
        }
 
-       rcu_read_lock();
-       chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
-       if (!chanctx_conf) {
-               rcu_read_unlock();
-               goto disconnect;
-       }
-
-       /* don't handle for multi-VIF cases */
-       chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf);
-       if (chanctx->refcount > 1) {
-               rcu_read_unlock();
-               goto disconnect;
-       }
-       num_chanctx = 0;
-       list_for_each_entry_rcu(chanctx, &sdata->local->chanctx_list, list)
-               num_chanctx++;
-
-       if (num_chanctx > 1) {
-               rcu_read_unlock();
-               goto disconnect;
+       if (cfg80211_chandef_identical(&params.chandef,
+                                      &sdata->vif.bss_conf.chandef)) {
+               ibss_dbg(sdata,
+                        "received csa with an identical chandef, ignoring\n");
+               return true;
        }
-       rcu_read_unlock();
 
        /* all checks done, now perform the channel switch. */
        ibss_dbg(sdata,
@@ -918,19 +898,9 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 
        params.block_tx = !!csa_ie.mode;
 
-       ieee80211_ibss_csa_beacon(sdata, &params);
-       sdata->csa_radar_required = params.radar_required;
-
-       if (params.block_tx)
-               ieee80211_stop_queues_by_reason(&sdata->local->hw,
-                               IEEE80211_MAX_QUEUE_MAP,
-                               IEEE80211_QUEUE_STOP_REASON_CSA);
-
-       sdata->csa_chandef = params.chandef;
-       sdata->vif.csa_active = true;
-
-       ieee80211_bss_info_change_notify(sdata, err);
-       drv_channel_switch_beacon(sdata, &params.chandef);
+       if (ieee80211_channel_switch(sdata->local->hw.wiphy, sdata->dev,
+                                    &params))
+               goto disconnect;
 
        ieee80211_ibss_csa_mark_radar(sdata);
 
@@ -966,7 +936,8 @@ ieee80211_rx_mgmt_spectrum_mgmt(struct ieee80211_sub_if_data *sdata,
        if (len < required_len)
                return;
 
-       ieee80211_ibss_process_chanswitch(sdata, elems, false);
+       if (!sdata->vif.csa_active)
+               ieee80211_ibss_process_chanswitch(sdata, elems, false);
 }
 
 static void ieee80211_rx_mgmt_deauth_ibss(struct ieee80211_sub_if_data *sdata,
@@ -1147,7 +1118,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
                goto put_bss;
 
        /* process channel switch */
-       if (ieee80211_ibss_process_chanswitch(sdata, elems, true))
+       if (sdata->vif.csa_active ||
+           ieee80211_ibss_process_chanswitch(sdata, elems, true))
                goto put_bss;
 
        /* same BSSID */
index ed5bf8b4b5c2bfb8d4253a0dbaa15b76aac309dd..fb5dbcb79a12264295622603e6134f4ec12bede0 100644 (file)
@@ -232,6 +232,7 @@ struct ieee80211_rx_data {
 struct beacon_data {
        u8 *head, *tail;
        int head_len, tail_len;
+       struct ieee80211_meshconf_ie *meshconf;
        struct rcu_head rcu_head;
 };
 
@@ -540,7 +541,10 @@ struct ieee80211_mesh_sync_ops {
                             struct ieee80211_mgmt *mgmt,
                             struct ieee802_11_elems *elems,
                             struct ieee80211_rx_status *rx_status);
-       void (*adjust_tbtt)(struct ieee80211_sub_if_data *sdata);
+
+       /* should be called with beacon_data under RCU read lock */
+       void (*adjust_tbtt)(struct ieee80211_sub_if_data *sdata,
+                           struct beacon_data *beacon);
        /* add other framework functions here */
 };
 
@@ -614,6 +618,9 @@ struct ieee80211_if_mesh {
        bool chsw_init;
        u8 chsw_ttl;
        u16 pre_value;
+
+       /* offset from skb->data while building IE */
+       int meshconf_offset;
 };
 
 #ifdef CONFIG_MAC80211_MESH
@@ -776,10 +783,6 @@ struct ieee80211_sub_if_data {
                u32 mntr_flags;
        } u;
 
-       spinlock_t cleanup_stations_lock;
-       struct list_head cleanup_stations;
-       struct work_struct cleanup_stations_wk;
-
 #ifdef CONFIG_MAC80211_DEBUGFS
        struct {
                struct dentry *subdir_stations;
@@ -1117,6 +1120,7 @@ struct ieee80211_local {
 
        struct work_struct sched_scan_stopped_work;
        struct ieee80211_sub_if_data __rcu *sched_scan_sdata;
+       struct cfg80211_sched_scan_request *sched_scan_req;
 
        unsigned long leave_oper_channel_time;
        enum mac80211_scan_state next_scan_state;
@@ -1425,6 +1429,9 @@ void ieee80211_rx_bss_put(struct ieee80211_local *local,
                          struct ieee80211_bss *bss);
 
 /* scheduled scan handling */
+int
+__ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
+                                    struct cfg80211_sched_scan_request *req);
 int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
                                       struct cfg80211_sched_scan_request *req);
 int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata);
@@ -1443,6 +1450,8 @@ void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc);
 
 /* channel switch handling */
 void ieee80211_csa_finalize_work(struct work_struct *work);
+int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
+                            struct cfg80211_csa_settings *params);
 
 /* interface handling */
 int ieee80211_iface_init(void);
@@ -1465,8 +1474,6 @@ void ieee80211_del_virtual_monitor(struct ieee80211_local *local);
 
 bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata);
 void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata);
-int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata,
-                           struct cfg80211_beacon_data *params);
 
 static inline bool ieee80211_sdata_running(struct ieee80211_sub_if_data *sdata)
 {
index a4f98123d0bf20b7bc49540cf9fb9225218e6ba7..d624ed49a7d9322e5615249ece049785e950e384 100644 (file)
@@ -786,10 +786,8 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
         * This is relevant only in WDS mode, in all other modes we've
         * already removed all stations when disconnecting or similar,
         * so warn otherwise.
-        *
-        * We call sta_info_flush_cleanup() later, to combine RCU waits.
         */
-       flushed = sta_info_flush_defer(sdata);
+       flushed = sta_info_flush(sdata);
        WARN_ON_ONCE((sdata->vif.type != NL80211_IFTYPE_WDS && flushed > 0) ||
                     (sdata->vif.type == NL80211_IFTYPE_WDS && flushed != 1));
 
@@ -891,23 +889,15 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
                cancel_work_sync(&sdata->work);
                /*
                 * When we get here, the interface is marked down.
+                * Free the remaining keys, if there are any
+                * (shouldn't be, except maybe in WDS mode?)
                 *
-                * sta_info_flush_cleanup() requires rcu_barrier()
-                * first to wait for the station call_rcu() calls
-                * to complete, and we also need synchronize_rcu()
-                * to wait for the RX path in case it is using the
-                * interface and enqueuing frames at this very time on
+                * Force the key freeing to always synchronize_net()
+                * to wait for the RX path in case it is using this
+                * interface enqueuing frames * at this very time on
                 * another CPU.
                 */
-               synchronize_rcu();
-               rcu_barrier();
-               sta_info_flush_cleanup(sdata);
-
-               /*
-                * Free all remaining keys, there shouldn't be any,
-                * except maybe in WDS mode?
-                */
-               ieee80211_free_keys(sdata);
+               ieee80211_free_keys(sdata, true);
 
                /* fall through */
        case NL80211_IFTYPE_AP:
@@ -1018,17 +1008,6 @@ static void ieee80211_set_multicast_list(struct net_device *dev)
                        atomic_dec(&local->iff_promiscs);
                sdata->flags ^= IEEE80211_SDATA_PROMISC;
        }
-
-       /*
-        * TODO: If somebody needs this on AP interfaces,
-        *       it can be enabled easily but multicast
-        *       addresses from VLANs need to be synced.
-        */
-       if (sdata->vif.type != NL80211_IFTYPE_MONITOR &&
-           sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
-           sdata->vif.type != NL80211_IFTYPE_AP)
-               drv_set_multicast_list(local, sdata, &dev->mc);
-
        spin_lock_bh(&local->filter_lock);
        __hw_addr_sync(&local->mc_list, &dev->mc, dev->addr_len);
        spin_unlock_bh(&local->filter_lock);
@@ -1044,7 +1023,7 @@ static void ieee80211_teardown_sdata(struct ieee80211_sub_if_data *sdata)
        int i;
 
        /* free extra data */
-       ieee80211_free_keys(sdata);
+       ieee80211_free_keys(sdata, false);
 
        ieee80211_debugfs_remove_netdev(sdata);
 
@@ -1578,15 +1557,6 @@ static void ieee80211_assign_perm_addr(struct ieee80211_local *local,
        mutex_unlock(&local->iflist_mtx);
 }
 
-static void ieee80211_cleanup_sdata_stas_wk(struct work_struct *wk)
-{
-       struct ieee80211_sub_if_data *sdata;
-
-       sdata = container_of(wk, struct ieee80211_sub_if_data, cleanup_stations_wk);
-
-       ieee80211_cleanup_sdata_stas(sdata);
-}
-
 int ieee80211_if_add(struct ieee80211_local *local, const char *name,
                     struct wireless_dev **new_wdev, enum nl80211_iftype type,
                     struct vif_params *params)
@@ -1659,9 +1629,6 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
 
        INIT_LIST_HEAD(&sdata->key_list);
 
-       spin_lock_init(&sdata->cleanup_stations_lock);
-       INIT_LIST_HEAD(&sdata->cleanup_stations);
-       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,
index e568d98167d0244e499e53c0b2a3aad1263b1ea0..6ff65a1ebaa905ffecfbdedebc7428882aecc551 100644 (file)
@@ -589,14 +589,10 @@ void ieee80211_iter_keys(struct ieee80211_hw *hw,
 }
 EXPORT_SYMBOL(ieee80211_iter_keys);
 
-void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata)
+static void ieee80211_free_keys_iface(struct ieee80211_sub_if_data *sdata,
+                                     struct list_head *keys)
 {
        struct ieee80211_key *key, *tmp;
-       LIST_HEAD(keys);
-
-       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;
@@ -608,28 +604,51 @@ void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata)
                ieee80211_key_replace(key->sdata, key->sta,
                                key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE,
                                key, NULL);
-               list_add_tail(&key->list, &keys);
+               list_add_tail(&key->list, keys);
        }
 
        ieee80211_debugfs_key_update_default(sdata);
+}
 
-       if (!list_empty(&keys)) {
-               synchronize_net();
-               list_for_each_entry_safe(key, tmp, &keys, list)
-                       __ieee80211_key_destroy(key, false);
+void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata,
+                        bool force_synchronize)
+{
+       struct ieee80211_local *local = sdata->local;
+       struct ieee80211_sub_if_data *vlan;
+       struct ieee80211_key *key, *tmp;
+       LIST_HEAD(keys);
+
+       cancel_delayed_work_sync(&sdata->dec_tailroom_needed_wk);
+
+       mutex_lock(&local->key_mtx);
+
+       ieee80211_free_keys_iface(sdata, &keys);
+
+       if (sdata->vif.type == NL80211_IFTYPE_AP) {
+               list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
+                       ieee80211_free_keys_iface(vlan, &keys);
        }
 
+       if (!list_empty(&keys) || force_synchronize)
+               synchronize_net();
+       list_for_each_entry_safe(key, tmp, &keys, list)
+               __ieee80211_key_destroy(key, false);
+
        WARN_ON_ONCE(sdata->crypto_tx_tailroom_needed_cnt ||
                     sdata->crypto_tx_tailroom_pending_dec);
+       if (sdata->vif.type == NL80211_IFTYPE_AP) {
+               list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
+                       WARN_ON_ONCE(vlan->crypto_tx_tailroom_needed_cnt ||
+                                    vlan->crypto_tx_tailroom_pending_dec);
+       }
 
-       mutex_unlock(&sdata->local->key_mtx);
+       mutex_unlock(&local->key_mtx);
 }
 
 void ieee80211_free_sta_keys(struct ieee80211_local *local,
                             struct sta_info *sta)
 {
-       struct ieee80211_key *key, *tmp;
-       LIST_HEAD(keys);
+       struct ieee80211_key *key;
        int i;
 
        mutex_lock(&local->key_mtx);
@@ -640,7 +659,7 @@ void ieee80211_free_sta_keys(struct ieee80211_local *local,
                ieee80211_key_replace(key->sdata, key->sta,
                                key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE,
                                key, NULL);
-               list_add(&key->list, &keys);
+               __ieee80211_key_destroy(key, true);
        }
 
        for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
@@ -650,17 +669,8 @@ void ieee80211_free_sta_keys(struct ieee80211_local *local,
                ieee80211_key_replace(key->sdata, key->sta,
                                key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE,
                                key, NULL);
-               list_add(&key->list, &keys);
-       }
-
-       /*
-        * NB: the station code relies on this being
-        * done even if there aren't any keys
-        */
-       synchronize_net();
-
-       list_for_each_entry_safe(key, tmp, &keys, list)
                __ieee80211_key_destroy(key, true);
+       }
 
        mutex_unlock(&local->key_mtx);
 }
index 0aebb889cabae566d6f33e00e59a2f299c9baa69..19db68663d7555461768eeae45a0afad8b0b163b 100644 (file)
@@ -136,7 +136,8 @@ void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx,
                               bool uni, bool multi);
 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_free_keys(struct ieee80211_sub_if_data *sdata,
+                        bool force_synchronize);
 void ieee80211_free_sta_keys(struct ieee80211_local *local,
                             struct sta_info *sta);
 void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata);
index fa34cd2344b98b9615a940a00e78363b494bc06c..2bd5b552b2f6c41629022876265bdd9a10e8890e 100644 (file)
@@ -250,12 +250,8 @@ static void ieee80211_restart_work(struct work_struct *work)
        /* wait for scan work complete */
        flush_workqueue(local->workqueue);
 
-       mutex_lock(&local->mtx);
-       WARN(test_bit(SCAN_HW_SCANNING, &local->scanning) ||
-            rcu_dereference_protected(local->sched_scan_sdata,
-                                      lockdep_is_held(&local->mtx)),
-               "%s called with hardware scan in progress\n", __func__);
-       mutex_unlock(&local->mtx);
+       WARN(test_bit(SCAN_HW_SCANNING, &local->scanning),
+            "%s called with hardware scan in progress\n", __func__);
 
        rtnl_lock();
        ieee80211_scan_cancel(local);
index 89df62b2b6896f05a2d3170bce62a40fff23cf8c..5a74b249ba35d0f47a499b08d4d0f04d75d4a5ec 100644 (file)
@@ -259,6 +259,9 @@ int mesh_add_meshconf_ie(struct ieee80211_sub_if_data *sdata,
        *pos++ = WLAN_EID_MESH_CONFIG;
        *pos++ = meshconf_len;
 
+       /* save a pointer for quick updates in pre-tbtt */
+       ifmsh->meshconf_offset = pos - skb->data;
+
        /* Active path selection protocol ID */
        *pos++ = ifmsh->mesh_pp_id;
        /* Active path selection metric ID   */
@@ -723,6 +726,8 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
 
        bcn->tail_len = skb->len;
        memcpy(bcn->tail, skb->data, bcn->tail_len);
+       bcn->meshconf = (struct ieee80211_meshconf_ie *)
+                                       (bcn->tail + ifmsh->meshconf_offset);
 
        dev_kfree_skb(skb);
        rcu_assign_pointer(ifmsh->beacon, bcn);
index d1cf2d5534998957c13cfbd5ca23c630d7c9f6a7..2bc5dc25d5adc79a92cd29bc94d058e141d011c6 100644 (file)
@@ -164,12 +164,15 @@ no_sync:
        rcu_read_unlock();
 }
 
-static void mesh_sync_offset_adjust_tbtt(struct ieee80211_sub_if_data *sdata)
+static void mesh_sync_offset_adjust_tbtt(struct ieee80211_sub_if_data *sdata,
+                                        struct beacon_data *beacon)
 {
        struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+       u8 cap;
 
        WARN_ON(ifmsh->mesh_sp_id != IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET);
        BUG_ON(!rcu_read_lock_held());
+       cap = beacon->meshconf->meshconf_cap;
 
        spin_lock_bh(&ifmsh->sync_offset_lock);
 
@@ -194,6 +197,10 @@ static void mesh_sync_offset_adjust_tbtt(struct ieee80211_sub_if_data *sdata)
                ifmsh->adjusting_tbtt = false;
        }
        spin_unlock_bh(&ifmsh->sync_offset_lock);
+
+       beacon->meshconf->meshconf_cap = ifmsh->adjusting_tbtt ?
+                       IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING | cap :
+                       ~IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING & cap;
 }
 
 static const struct sync_method sync_methods[] = {
index 900ead344f5bd526fa5f9a54b438a8cae52012e6..9c2c7ee2cc30815e47014ddb47bcd6cf1d66caf2 100644 (file)
@@ -1698,7 +1698,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
        memset(ifmgd->bssid, 0, ETH_ALEN);
 
        /* remove AP and TDLS peers */
-       sta_info_flush_defer(sdata);
+       sta_info_flush(sdata);
 
        /* finally reset all BSS / config parameters */
        changed |= ieee80211_reset_erp_info(sdata);
index 340126204343a063902bb205675cc14bea743a4c..af64fb8e8addb58e5933cc3a45a8043f55659f81 100644 (file)
@@ -37,9 +37,8 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
                                        IEEE80211_MAX_QUEUE_MAP,
                                        IEEE80211_QUEUE_STOP_REASON_SUSPEND);
 
-       /* flush out all packets and station cleanup call_rcu()s */
+       /* flush out all packets */
        synchronize_net();
-       rcu_barrier();
 
        ieee80211_flush_queues(local, NULL);
 
index 2dfa755227339533d2c105313ba8ab4ea3ba67b5..5a2afe9583a806d5f9059c390e0cc70ae7799e22 100644 (file)
@@ -1963,20 +1963,17 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
                }
        }
 
-       if (skb) {
-               int align __maybe_unused;
-
 #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
-               /*
-                * '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; 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)
+       if (skb) {
+               /* '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; 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 ether_addr_equal)
                 */
-               align = ((unsigned long)(skb->data + sizeof(struct ethhdr))) & 3;
+               int align;
+
+               align = (unsigned long)(skb->data + sizeof(struct ethhdr)) & 3;
                if (align) {
                        if (WARN_ON(skb_headroom(skb) < 3)) {
                                dev_kfree_skb(skb);
@@ -1989,14 +1986,14 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
                                skb_set_tail_pointer(skb, len);
                        }
                }
+       }
 #endif
 
-               if (skb) {
-                       /* deliver to local stack */
-                       skb->protocol = eth_type_trans(skb, dev);
-                       memset(skb->cb, 0, sizeof(skb->cb));
-                       netif_receive_skb(skb);
-               }
+       if (skb) {
+               /* deliver to local stack */
+               skb->protocol = eth_type_trans(skb, dev);
+               memset(skb->cb, 0, sizeof(skb->cb));
+               netif_receive_skb(skb);
        }
 
        if (xmit_skb) {
index 4d73c46df86262a385ad5fb9a5912c6a8168831e..88c81616f8f758595e90cced1d503448ce6ba969 100644 (file)
@@ -271,10 +271,11 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_local *local)
        return true;
 }
 
-static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted,
-                                      bool was_hw_scan)
+static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
 {
        struct ieee80211_local *local = hw_to_local(hw);
+       bool hw_scan = local->ops->hw_scan;
+       bool was_scanning = local->scanning;
 
        lockdep_assert_held(&local->mtx);
 
@@ -290,7 +291,7 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted,
        if (WARN_ON(!local->scan_req))
                return;
 
-       if (was_hw_scan && !aborted && ieee80211_prep_hw_scan(local)) {
+       if (hw_scan && !aborted && ieee80211_prep_hw_scan(local)) {
                int rc;
 
                rc = drv_hw_scan(local,
@@ -316,7 +317,7 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted,
        /* Set power back to normal operating levels. */
        ieee80211_hw_config(local, 0);
 
-       if (!was_hw_scan) {
+       if (!hw_scan) {
                ieee80211_configure_filter(local);
                drv_sw_scan_complete(local);
                ieee80211_offchannel_return(local);
@@ -327,7 +328,8 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted,
        ieee80211_mlme_notify_scan_completed(local);
        ieee80211_ibss_notify_scan_completed(local);
        ieee80211_mesh_notify_scan_completed(local);
-       ieee80211_start_next_roc(local);
+       if (was_scanning)
+               ieee80211_start_next_roc(local);
 }
 
 void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
@@ -747,7 +749,7 @@ void ieee80211_scan_work(struct work_struct *work)
                container_of(work, struct ieee80211_local, scan_work.work);
        struct ieee80211_sub_if_data *sdata;
        unsigned long next_delay = 0;
-       bool aborted, hw_scan;
+       bool aborted;
 
        mutex_lock(&local->mtx);
 
@@ -785,14 +787,6 @@ void ieee80211_scan_work(struct work_struct *work)
                        goto out;
        }
 
-       /*
-        * Avoid re-scheduling when the sdata is going away.
-        */
-       if (!ieee80211_sdata_running(sdata)) {
-               aborted = true;
-               goto out_complete;
-       }
-
        /*
         * as long as no delay is required advance immediately
         * without scheduling a new work
@@ -834,8 +828,7 @@ void ieee80211_scan_work(struct work_struct *work)
        goto out;
 
 out_complete:
-       hw_scan = test_bit(SCAN_HW_SCANNING, &local->scanning);
-       __ieee80211_scan_completed(&local->hw, aborted, hw_scan);
+       __ieee80211_scan_completed(&local->hw, aborted);
 out:
        mutex_unlock(&local->mtx);
 }
@@ -973,13 +966,13 @@ void ieee80211_scan_cancel(struct ieee80211_local *local)
         */
        cancel_delayed_work(&local->scan_work);
        /* and clean up */
-       __ieee80211_scan_completed(&local->hw, true, false);
+       __ieee80211_scan_completed(&local->hw, true);
 out:
        mutex_unlock(&local->mtx);
 }
 
-int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
-                                      struct cfg80211_sched_scan_request *req)
+int __ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
+                                       struct cfg80211_sched_scan_request *req)
 {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_sched_scan_ies sched_scan_ies = {};
@@ -989,17 +982,10 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
        iebufsz = 2 + IEEE80211_MAX_SSID_LEN +
                  local->scan_ies_len + req->ie_len;
 
-       mutex_lock(&local->mtx);
-
-       if (rcu_access_pointer(local->sched_scan_sdata)) {
-               ret = -EBUSY;
-               goto out;
-       }
+       lockdep_assert_held(&local->mtx);
 
-       if (!local->ops->sched_scan_start) {
-               ret = -ENOTSUPP;
-               goto out;
-       }
+       if (!local->ops->sched_scan_start)
+               return -ENOTSUPP;
 
        for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
                if (!local->hw.wiphy->bands[i])
@@ -1020,13 +1006,39 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
        }
 
        ret = drv_sched_scan_start(local, sdata, req, &sched_scan_ies);
-       if (ret == 0)
+       if (ret == 0) {
                rcu_assign_pointer(local->sched_scan_sdata, sdata);
+               local->sched_scan_req = req;
+       }
 
 out_free:
        while (i > 0)
                kfree(sched_scan_ies.ie[--i]);
-out:
+
+       if (ret) {
+               /* Clean in case of failure after HW restart or upon resume. */
+               rcu_assign_pointer(local->sched_scan_sdata, NULL);
+               local->sched_scan_req = NULL;
+       }
+
+       return ret;
+}
+
+int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
+                                      struct cfg80211_sched_scan_request *req)
+{
+       struct ieee80211_local *local = sdata->local;
+       int ret;
+
+       mutex_lock(&local->mtx);
+
+       if (rcu_access_pointer(local->sched_scan_sdata)) {
+               mutex_unlock(&local->mtx);
+               return -EBUSY;
+       }
+
+       ret = __ieee80211_request_sched_scan_start(sdata, req);
+
        mutex_unlock(&local->mtx);
        return ret;
 }
@@ -1043,6 +1055,9 @@ int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata)
                goto out;
        }
 
+       /* We don't want to restart sched scan anymore. */
+       local->sched_scan_req = NULL;
+
        if (rcu_access_pointer(local->sched_scan_sdata))
                drv_sched_scan_stop(local, sdata);
 
@@ -1077,6 +1092,9 @@ void ieee80211_sched_scan_stopped_work(struct work_struct *work)
 
        rcu_assign_pointer(local->sched_scan_sdata, NULL);
 
+       /* If sched scan was aborted by the driver. */
+       local->sched_scan_req = NULL;
+
        mutex_unlock(&local->mtx);
 
        cfg80211_sched_scan_stopped(local->hw.wiphy);
index 8ed97f76c3cfade5f0986fa2d17c8275753b3c35..4576ba0ff2211af31664b10dd40e996e490286df 100644 (file)
@@ -99,23 +99,6 @@ static void cleanup_single_sta(struct sta_info *sta)
        struct ieee80211_local *local = sdata->local;
        struct ps_data *ps;
 
-       /*
-        * At this point, when being called as call_rcu callback,
-        * neither mac80211 nor the driver can reference this
-        * sta struct any more except by still existing timers
-        * associated with this station that we clean up below.
-        *
-        * Note though that this still uses the sdata and even
-        * calls the driver in AP and mesh mode, so interfaces
-        * of those types mush use call sta_info_flush_cleanup()
-        * (typically via sta_info_flush()) before deconfiguring
-        * the driver.
-        *
-        * In station mode, nothing happens here so it doesn't
-        * have to (and doesn't) do that, this is intentional to
-        * speed up roaming.
-        */
-
        if (test_sta_flag(sta, WLAN_STA_PS_STA)) {
                if (sta->sdata->vif.type == NL80211_IFTYPE_AP ||
                    sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
@@ -160,37 +143,6 @@ static void cleanup_single_sta(struct sta_info *sta)
        sta_info_free(local, sta);
 }
 
-void ieee80211_cleanup_sdata_stas(struct ieee80211_sub_if_data *sdata)
-{
-       struct sta_info *sta;
-
-       spin_lock_bh(&sdata->cleanup_stations_lock);
-       while (!list_empty(&sdata->cleanup_stations)) {
-               sta = list_first_entry(&sdata->cleanup_stations,
-                                      struct sta_info, list);
-               list_del(&sta->list);
-               spin_unlock_bh(&sdata->cleanup_stations_lock);
-
-               cleanup_single_sta(sta);
-
-               spin_lock_bh(&sdata->cleanup_stations_lock);
-       }
-
-       spin_unlock_bh(&sdata->cleanup_stations_lock);
-}
-
-static void free_sta_rcu(struct rcu_head *h)
-{
-       struct sta_info *sta = container_of(h, struct sta_info, rcu_head);
-       struct ieee80211_sub_if_data *sdata = sta->sdata;
-
-       spin_lock(&sdata->cleanup_stations_lock);
-       list_add_tail(&sta->list, &sdata->cleanup_stations);
-       spin_unlock(&sdata->cleanup_stations_lock);
-
-       ieee80211_queue_work(&sdata->local->hw, &sdata->cleanup_stations_wk);
-}
-
 /* protected by RCU */
 struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata,
                              const u8 *addr)
@@ -842,7 +794,7 @@ static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
        return have_buffered;
 }
 
-int __must_check __sta_info_destroy(struct sta_info *sta)
+static int __must_check __sta_info_destroy_part1(struct sta_info *sta)
 {
        struct ieee80211_local *local;
        struct ieee80211_sub_if_data *sdata;
@@ -868,12 +820,35 @@ int __must_check __sta_info_destroy(struct sta_info *sta)
        ieee80211_sta_tear_down_BA_sessions(sta, AGG_STOP_DESTROY_STA);
 
        ret = sta_info_hash_del(local, sta);
-       if (ret)
+       if (WARN_ON(ret))
                return ret;
 
        list_del_rcu(&sta->list);
 
-       /* this always calls synchronize_net() */
+       drv_sta_pre_rcu_remove(local, sta->sdata, sta);
+
+       if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
+           rcu_access_pointer(sdata->u.vlan.sta) == sta)
+               RCU_INIT_POINTER(sdata->u.vlan.sta, NULL);
+
+       return 0;
+}
+
+static void __sta_info_destroy_part2(struct sta_info *sta)
+{
+       struct ieee80211_local *local = sta->local;
+       struct ieee80211_sub_if_data *sdata = sta->sdata;
+       int ret;
+
+       /*
+        * NOTE: This assumes at least synchronize_net() was done
+        *       after _part1 and before _part2!
+        */
+
+       might_sleep();
+       lockdep_assert_held(&local->sta_mtx);
+
+       /* now keys can no longer be reached */
        ieee80211_free_sta_keys(local, sta);
 
        sta->dead = true;
@@ -881,9 +856,6 @@ int __must_check __sta_info_destroy(struct sta_info *sta)
        local->num_sta--;
        local->sta_generation++;
 
-       if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
-               RCU_INIT_POINTER(sdata->u.vlan.sta, NULL);
-
        while (sta->sta_state > IEEE80211_STA_NONE) {
                ret = sta_info_move_state(sta, sta->sta_state - 1);
                if (ret) {
@@ -906,7 +878,19 @@ int __must_check __sta_info_destroy(struct sta_info *sta)
        ieee80211_sta_debugfs_remove(sta);
        ieee80211_recalc_min_chandef(sdata);
 
-       call_rcu(&sta->rcu_head, free_sta_rcu);
+       cleanup_single_sta(sta);
+}
+
+int __must_check __sta_info_destroy(struct sta_info *sta)
+{
+       int err = __sta_info_destroy_part1(sta);
+
+       if (err)
+               return err;
+
+       synchronize_net();
+
+       __sta_info_destroy_part2(sta);
 
        return 0;
 }
@@ -976,32 +960,38 @@ void sta_info_stop(struct ieee80211_local *local)
 }
 
 
-int sta_info_flush_defer(struct ieee80211_sub_if_data *sdata)
+int __sta_info_flush(struct ieee80211_sub_if_data *sdata, bool vlans)
 {
        struct ieee80211_local *local = sdata->local;
        struct sta_info *sta, *tmp;
+       LIST_HEAD(free_list);
        int ret = 0;
 
        might_sleep();
 
+       WARN_ON(vlans && sdata->vif.type != NL80211_IFTYPE_AP);
+       WARN_ON(vlans && !sdata->bss);
+
        mutex_lock(&local->sta_mtx);
        list_for_each_entry_safe(sta, tmp, &local->sta_list, list) {
-               if (sdata == sta->sdata) {
-                       WARN_ON(__sta_info_destroy(sta));
+               if (sdata == sta->sdata ||
+                   (vlans && sdata->bss == sta->sdata->bss)) {
+                       if (!WARN_ON(__sta_info_destroy_part1(sta)))
+                               list_add(&sta->free_list, &free_list);
                        ret++;
                }
        }
+
+       if (!list_empty(&free_list)) {
+               synchronize_net();
+               list_for_each_entry_safe(sta, tmp, &free_list, free_list)
+                       __sta_info_destroy_part2(sta);
+       }
        mutex_unlock(&local->sta_mtx);
 
        return ret;
 }
 
-void sta_info_flush_cleanup(struct ieee80211_sub_if_data *sdata)
-{
-       ieee80211_cleanup_sdata_stas(sdata);
-       cancel_work_sync(&sdata->cleanup_stations_wk);
-}
-
 void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata,
                          unsigned long exp_time)
 {
index 0218caf5c14a793ef14045da6c0db6a13781b259..d77ff70906303855458734a5bfac0526460056eb 100644 (file)
@@ -247,6 +247,7 @@ struct ieee80211_tx_latency_stat {
  * mac80211 is communicating with.
  *
  * @list: global linked list entry
+ * @free_list: list entry for keeping track of stations to free
  * @hnext: hash table linked list pointer
  * @local: pointer to the global information
  * @sdata: virtual interface this station belongs to
@@ -329,7 +330,7 @@ struct ieee80211_tx_latency_stat {
  */
 struct sta_info {
        /* General information, mostly static */
-       struct list_head list;
+       struct list_head list, free_list;
        struct rcu_head rcu_head;
        struct sta_info __rcu *hnext;
        struct ieee80211_local *local;
@@ -605,21 +606,6 @@ void sta_info_recalc_tim(struct sta_info *sta);
 
 void sta_info_init(struct ieee80211_local *local);
 void sta_info_stop(struct ieee80211_local *local);
-int sta_info_flush_defer(struct ieee80211_sub_if_data *sdata);
-
-/**
- * sta_info_flush_cleanup - flush the sta_info cleanup queue
- * @sdata: the interface
- *
- * Flushes the sta_info cleanup queue for a given interface;
- * this is necessary before the interface is removed or, for
- * AP/mesh interfaces, before it is deconfigured.
- *
- * Note an rcu_barrier() must precede the function, after all
- * stations have been flushed/removed to ensure the call_rcu()
- * calls that add stations to the cleanup queue have completed.
- */
-void sta_info_flush_cleanup(struct ieee80211_sub_if_data *sdata);
 
 /**
  * sta_info_flush - flush matching STA entries from the STA table
@@ -627,15 +613,13 @@ void sta_info_flush_cleanup(struct ieee80211_sub_if_data *sdata);
  * Returns the number of removed STA entries.
  *
  * @sdata: sdata to remove all stations from
+ * @vlans: if the given interface is an AP interface, also flush VLANs
  */
+int __sta_info_flush(struct ieee80211_sub_if_data *sdata, bool vlans);
+
 static inline int sta_info_flush(struct ieee80211_sub_if_data *sdata)
 {
-       int ret = sta_info_flush_defer(sdata);
-
-       rcu_barrier();
-       sta_info_flush_cleanup(sdata);
-
-       return ret;
+       return __sta_info_flush(sdata, false);
 }
 
 void sta_set_rate_info_tx(struct sta_info *sta,
@@ -651,6 +635,4 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta);
 void ieee80211_sta_ps_deliver_poll_response(struct sta_info *sta);
 void ieee80211_sta_ps_deliver_uapsd(struct sta_info *sta);
 
-void ieee80211_cleanup_sdata_stas(struct ieee80211_sub_if_data *sdata);
-
 #endif /* STA_INFO_H */
index e9ccf22f6dd972c8b0517c5d35a345085eb45ec6..3a669d7ec7adc423501539bd682ce705451b74c1 100644 (file)
@@ -443,30 +443,6 @@ TRACE_EVENT(drv_prepare_multicast,
        )
 );
 
-TRACE_EVENT(drv_set_multicast_list,
-       TP_PROTO(struct ieee80211_local *local,
-                struct ieee80211_sub_if_data *sdata, int mc_count),
-
-       TP_ARGS(local, sdata, mc_count),
-
-       TP_STRUCT__entry(
-               LOCAL_ENTRY
-               __field(bool, allmulti)
-               __field(int, mc_count)
-       ),
-
-       TP_fast_assign(
-               LOCAL_ASSIGN;
-               __entry->allmulti = sdata->flags & IEEE80211_SDATA_ALLMULTI;
-               __entry->mc_count = mc_count;
-       ),
-
-       TP_printk(
-               LOCAL_PR_FMT " configure mc filter, count=%d, allmulti=%d",
-               LOCAL_PR_ARG, __entry->mc_count, __entry->allmulti
-       )
-);
-
 TRACE_EVENT(drv_configure_filter,
        TP_PROTO(struct ieee80211_local *local,
                 unsigned int changed_flags,
@@ -790,7 +766,7 @@ TRACE_EVENT(drv_sta_rc_update,
        )
 );
 
-TRACE_EVENT(drv_sta_add,
+DECLARE_EVENT_CLASS(sta_event,
        TP_PROTO(struct ieee80211_local *local,
                 struct ieee80211_sub_if_data *sdata,
                 struct ieee80211_sta *sta),
@@ -815,29 +791,25 @@ TRACE_EVENT(drv_sta_add,
        )
 );
 
-TRACE_EVENT(drv_sta_remove,
+DEFINE_EVENT(sta_event, drv_sta_add,
        TP_PROTO(struct ieee80211_local *local,
                 struct ieee80211_sub_if_data *sdata,
                 struct ieee80211_sta *sta),
+       TP_ARGS(local, sdata, sta)
+);
 
-       TP_ARGS(local, sdata, sta),
-
-       TP_STRUCT__entry(
-               LOCAL_ENTRY
-               VIF_ENTRY
-               STA_ENTRY
-       ),
-
-       TP_fast_assign(
-               LOCAL_ASSIGN;
-               VIF_ASSIGN;
-               STA_ASSIGN;
-       ),
+DEFINE_EVENT(sta_event, drv_sta_remove,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata,
+                struct ieee80211_sta *sta),
+       TP_ARGS(local, sdata, sta)
+);
 
-       TP_printk(
-               LOCAL_PR_FMT  VIF_PR_FMT  STA_PR_FMT,
-               LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG
-       )
+DEFINE_EVENT(sta_event, drv_sta_pre_rcu_remove,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata,
+                struct ieee80211_sta *sta),
+       TP_ARGS(local, sdata, sta)
 );
 
 TRACE_EVENT(drv_conf_tx,
index 6d59e21cdb9fe8b686fdcef53ddc83a83738d0cf..2f0e176e79897f36499f48e9418127e4cddd6c51 100644 (file)
@@ -2549,7 +2549,8 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
                         */
                        skb = dev_alloc_skb(local->tx_headroom +
                                            beacon->head_len +
-                                           beacon->tail_len + 256);
+                                           beacon->tail_len + 256 +
+                                           local->hw.extra_beacon_tailroom);
                        if (!skb)
                                goto out;
 
@@ -2581,7 +2582,8 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
                        ieee80211_update_csa(sdata, presp);
 
 
-               skb = dev_alloc_skb(local->tx_headroom + presp->head_len);
+               skb = dev_alloc_skb(local->tx_headroom + presp->head_len +
+                                   local->hw.extra_beacon_tailroom);
                if (!skb)
                        goto out;
                skb_reserve(skb, local->tx_headroom);
@@ -2602,13 +2604,13 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
                        ieee80211_update_csa(sdata, bcn);
 
                if (ifmsh->sync_ops)
-                       ifmsh->sync_ops->adjust_tbtt(
-                                               sdata);
+                       ifmsh->sync_ops->adjust_tbtt(sdata, bcn);
 
                skb = dev_alloc_skb(local->tx_headroom +
                                    bcn->head_len +
                                    256 + /* TIM IE */
-                                   bcn->tail_len);
+                                   bcn->tail_len +
+                                   local->hw.extra_beacon_tailroom);
                if (!skb)
                        goto out;
                skb_reserve(skb, local->tx_headroom);
index 875e172c001c697a72f85941fd0db8ef1b28b86a..591b46b724621dedfba73cedeb9791c0608339b8 100644 (file)
@@ -642,6 +642,17 @@ void ieee80211_iterate_active_interfaces_rtnl(
 }
 EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_rtnl);
 
+struct ieee80211_vif *wdev_to_ieee80211_vif(struct wireless_dev *wdev)
+{
+       struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
+
+       if (!ieee80211_sdata_running(sdata) ||
+           !(sdata->flags & IEEE80211_SDATA_IN_DRIVER))
+               return NULL;
+       return &sdata->vif;
+}
+EXPORT_SYMBOL_GPL(wdev_to_ieee80211_vif);
+
 /*
  * Nothing should have been stuffed into the workqueue during
  * the suspend->resume cycle. If this WARN is seen then there
@@ -1451,6 +1462,8 @@ int ieee80211_reconfig(struct ieee80211_local *local)
        struct sta_info *sta;
        int res, i;
        bool reconfig_due_to_wowlan = false;
+       struct ieee80211_sub_if_data *sched_scan_sdata;
+       bool sched_scan_stopped = false;
 
 #ifdef CONFIG_PM
        if (local->suspended)
@@ -1754,6 +1767,27 @@ int ieee80211_reconfig(struct ieee80211_local *local)
 #else
        WARN_ON(1);
 #endif
+
+       /*
+        * Reconfigure sched scan if it was interrupted by FW restart or
+        * suspend.
+        */
+       mutex_lock(&local->mtx);
+       sched_scan_sdata = rcu_dereference_protected(local->sched_scan_sdata,
+                                               lockdep_is_held(&local->mtx));
+       if (sched_scan_sdata && local->sched_scan_req)
+               /*
+                * Sched scan stopped, but we don't want to report it. Instead,
+                * we're trying to reschedule.
+                */
+               if (__ieee80211_request_sched_scan_start(sched_scan_sdata,
+                                                        local->sched_scan_req))
+                       sched_scan_stopped = true;
+       mutex_unlock(&local->mtx);
+
+       if (sched_scan_stopped)
+               cfg80211_sched_scan_stopped(local->hw.wiphy);
+
        return 0;
 }
 
index 06db6eb5258aefc332fb4fb09ed165562ea8cd7d..d89dee2259b5994b9237100425aae0a3f21b20af 100644 (file)
@@ -203,17 +203,8 @@ void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev,
 
        rdev->opencount--;
 
-       if (rdev->scan_req && rdev->scan_req->wdev == wdev) {
-               /*
-                * If the scan request wasn't notified as done, set it
-                * to aborted and leak it after a warning. The driver
-                * should have notified us that it ended at the latest
-                * during rdev_stop_p2p_device().
-                */
-               if (WARN_ON(!rdev->scan_req->notified))
-                       rdev->scan_req->aborted = true;
-               ___cfg80211_scan_done(rdev, !rdev->scan_req->notified);
-       }
+       WARN_ON(rdev->scan_req && rdev->scan_req->wdev == wdev &&
+               !rdev->scan_req->notified);
 }
 
 static int cfg80211_rfkill_set_block(void *data, bool blocked)
@@ -765,13 +756,16 @@ void cfg80211_leave(struct cfg80211_registered_device *rdev,
 {
        struct net_device *dev = wdev->netdev;
 
+       ASSERT_RTNL();
+
        switch (wdev->iftype) {
        case NL80211_IFTYPE_ADHOC:
                cfg80211_leave_ibss(rdev, dev, true);
                break;
        case NL80211_IFTYPE_P2P_CLIENT:
        case NL80211_IFTYPE_STATION:
-               __cfg80211_stop_sched_scan(rdev, false);
+               if (rdev->sched_scan_req && dev == rdev->sched_scan_req->dev)
+                       __cfg80211_stop_sched_scan(rdev, false);
 
                wdev_lock(wdev);
 #ifdef CONFIG_CFG80211_WEXT
@@ -865,11 +859,8 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
                break;
        case NETDEV_DOWN:
                cfg80211_update_iface_num(rdev, wdev->iftype, -1);
-               if (rdev->scan_req && rdev->scan_req->wdev == wdev) {
-                       if (WARN_ON(!rdev->scan_req->notified))
-                               rdev->scan_req->aborted = true;
-                       ___cfg80211_scan_done(rdev, true);
-               }
+               WARN_ON(rdev->scan_req && rdev->scan_req->wdev == wdev &&
+                       !rdev->scan_req->notified);
 
                if (WARN_ON(rdev->sched_scan_req &&
                            rdev->sched_scan_req->dev == wdev->netdev)) {
index 0a277c33bb027a879d854492ddde295be2c663a0..37ec16d7bb1ab6bf6e4948259aad19eb6e5a58cf 100644 (file)
@@ -67,9 +67,7 @@ struct cfg80211_registered_device {
        struct work_struct scan_done_wk;
        struct work_struct sched_scan_results_wk;
 
-#ifdef CONFIG_NL80211_TESTMODE
-       struct genl_info *testmode_info;
-#endif
+       struct genl_info *cur_cmd_info;
 
        struct work_struct conn_work;
        struct work_struct event_work;
@@ -363,7 +361,7 @@ int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
                                   struct key_params *params, int key_idx,
                                   bool pairwise, const u8 *mac_addr);
 void __cfg80211_scan_done(struct work_struct *wk);
-void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak);
+void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev);
 void __cfg80211_sched_scan_results(struct work_struct *wk);
 int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev,
                               bool driver_initiated);
index b0e1869de7de0b0775561c445389f4f2013beb58..9c7a11ae79368894899ce9e4d2b84c0b0d133c68 100644 (file)
@@ -99,6 +99,7 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
                         const struct mesh_config *conf)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
+       u8 radar_detect_width = 0;
        int err;
 
        BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN != IEEE80211_MAX_MESH_ID_LEN);
@@ -177,8 +178,16 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
        if (!cfg80211_reg_can_beacon(&rdev->wiphy, &setup->chandef))
                return -EINVAL;
 
-       err = cfg80211_can_use_chan(rdev, wdev, setup->chandef.chan,
-                                   CHAN_MODE_SHARED);
+       err = cfg80211_chandef_dfs_required(wdev->wiphy, &setup->chandef);
+       if (err < 0)
+               return err;
+       if (err)
+               radar_detect_width = BIT(setup->chandef.width);
+
+       err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
+                                          setup->chandef.chan,
+                                          CHAN_MODE_SHARED,
+                                          radar_detect_width);
        if (err)
                return err;
 
index a693f86e59704016e9c8419eb82a8c43185d9642..04681a46eda8fc974997041e52b2709882755720 100644 (file)
@@ -376,6 +376,10 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
        [NL80211_ATTR_STA_SUPPORTED_CHANNELS] = { .type = NLA_BINARY },
        [NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES] = { .type = NLA_BINARY },
        [NL80211_ATTR_HANDLE_DFS] = { .type = NLA_FLAG },
+       [NL80211_ATTR_OPMODE_NOTIF] = { .type = NLA_U8 },
+       [NL80211_ATTR_VENDOR_ID] = { .type = NLA_U32 },
+       [NL80211_ATTR_VENDOR_SUBCMD] = { .type = NLA_U32 },
+       [NL80211_ATTR_VENDOR_DATA] = { .type = NLA_BINARY },
 };
 
 /* policy for the key attributes */
@@ -1184,6 +1188,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
        struct nlattr *nl_bands, *nl_band;
        struct nlattr *nl_freqs, *nl_freq;
        struct nlattr *nl_cmds;
+       struct nlattr *nl_vendor_cmds;
        enum ieee80211_band band;
        struct ieee80211_channel *chan;
        int i;
@@ -1579,6 +1584,19 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
                    (nla_put_flag(msg, NL80211_ATTR_SUPPORT_5_MHZ) ||
                     nla_put_flag(msg, NL80211_ATTR_SUPPORT_10_MHZ)))
                        goto nla_put_failure;
+               state->split_start++;
+               break;
+       case 11:
+               nl_vendor_cmds = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
+               if (!nl_vendor_cmds)
+                       goto nla_put_failure;
+
+               for (i = 0; i < dev->wiphy.n_vendor_commands; i++)
+                       if (nla_put(msg, i + 1,
+                                   sizeof(struct nl80211_vendor_cmd_info),
+                                   &dev->wiphy.vendor_commands[i].info))
+                               goto nla_put_failure;
+               nla_nest_end(msg, nl_vendor_cmds);
 
                /* done */
                state->split_start = 0;
@@ -4151,6 +4169,12 @@ 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_OPMODE_NOTIF]) {
+               params.opmode_notif_used = true;
+               params.opmode_notif =
+                       nla_get_u8(info->attrs[NL80211_ATTR_OPMODE_NOTIF]);
+       }
+
        if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) {
                params.plink_action =
                        nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]);
@@ -5667,8 +5691,13 @@ static int nl80211_start_radar_detection(struct sk_buff *skb,
        struct net_device *dev = info->user_ptr[1];
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct cfg80211_chan_def chandef;
+       enum nl80211_dfs_regions dfs_region;
        int err;
 
+       dfs_region = reg_get_dfs_region(wdev->wiphy);
+       if (dfs_region == NL80211_DFS_UNSET)
+               return -EINVAL;
+
        err = nl80211_parse_chandef(rdev, info, &chandef);
        if (err)
                return err;
@@ -6693,6 +6722,40 @@ static int nl80211_set_mcast_rate(struct sk_buff *skb, struct genl_info *info)
        return err;
 }
 
+static struct sk_buff *
+__cfg80211_alloc_vendor_skb(struct cfg80211_registered_device *rdev,
+                           int approxlen, u32 portid, u32 seq,
+                           enum nl80211_commands cmd,
+                           enum nl80211_attrs attr, gfp_t gfp)
+{
+       struct sk_buff *skb;
+       void *hdr;
+       struct nlattr *data;
+
+       skb = nlmsg_new(approxlen + 100, gfp);
+       if (!skb)
+               return NULL;
+
+       hdr = nl80211hdr_put(skb, portid, seq, 0, cmd);
+       if (!hdr) {
+               kfree_skb(skb);
+               return NULL;
+       }
+
+       if (nla_put_u32(skb, NL80211_ATTR_WIPHY, rdev->wiphy_idx))
+               goto nla_put_failure;
+       data = nla_nest_start(skb, attr);
+
+       ((void **)skb->cb)[0] = rdev;
+       ((void **)skb->cb)[1] = hdr;
+       ((void **)skb->cb)[2] = data;
+
+       return skb;
+
+ nla_put_failure:
+       kfree_skb(skb);
+       return NULL;
+}
 
 #ifdef CONFIG_NL80211_TESTMODE
 static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info)
@@ -6717,11 +6780,11 @@ static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info)
        if (!info->attrs[NL80211_ATTR_TESTDATA])
                return -EINVAL;
 
-       rdev->testmode_info = info;
+       rdev->cur_cmd_info = info;
        err = rdev_testmode_cmd(rdev, wdev,
                                nla_data(info->attrs[NL80211_ATTR_TESTDATA]),
                                nla_len(info->attrs[NL80211_ATTR_TESTDATA]));
-       rdev->testmode_info = NULL;
+       rdev->cur_cmd_info = NULL;
 
        return err;
 }
@@ -6821,77 +6884,14 @@ static int nl80211_testmode_dump(struct sk_buff *skb,
        return err;
 }
 
-static struct sk_buff *
-__cfg80211_testmode_alloc_skb(struct cfg80211_registered_device *rdev,
-                             int approxlen, u32 portid, u32 seq, gfp_t gfp)
-{
-       struct sk_buff *skb;
-       void *hdr;
-       struct nlattr *data;
-
-       skb = nlmsg_new(approxlen + 100, gfp);
-       if (!skb)
-               return NULL;
-
-       hdr = nl80211hdr_put(skb, portid, seq, 0, NL80211_CMD_TESTMODE);
-       if (!hdr) {
-               kfree_skb(skb);
-               return NULL;
-       }
-
-       if (nla_put_u32(skb, NL80211_ATTR_WIPHY, rdev->wiphy_idx))
-               goto nla_put_failure;
-       data = nla_nest_start(skb, NL80211_ATTR_TESTDATA);
-
-       ((void **)skb->cb)[0] = rdev;
-       ((void **)skb->cb)[1] = hdr;
-       ((void **)skb->cb)[2] = data;
-
-       return skb;
-
- nla_put_failure:
-       kfree_skb(skb);
-       return NULL;
-}
-
-struct sk_buff *cfg80211_testmode_alloc_reply_skb(struct wiphy *wiphy,
-                                                 int approxlen)
-{
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
-
-       if (WARN_ON(!rdev->testmode_info))
-               return NULL;
-
-       return __cfg80211_testmode_alloc_skb(rdev, approxlen,
-                               rdev->testmode_info->snd_portid,
-                               rdev->testmode_info->snd_seq,
-                               GFP_KERNEL);
-}
-EXPORT_SYMBOL(cfg80211_testmode_alloc_reply_skb);
-
-int cfg80211_testmode_reply(struct sk_buff *skb)
-{
-       struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0];
-       void *hdr = ((void **)skb->cb)[1];
-       struct nlattr *data = ((void **)skb->cb)[2];
-
-       if (WARN_ON(!rdev->testmode_info)) {
-               kfree_skb(skb);
-               return -EINVAL;
-       }
-
-       nla_nest_end(skb, data);
-       genlmsg_end(skb, hdr);
-       return genlmsg_reply(skb, rdev->testmode_info);
-}
-EXPORT_SYMBOL(cfg80211_testmode_reply);
-
 struct sk_buff *cfg80211_testmode_alloc_event_skb(struct wiphy *wiphy,
                                                  int approxlen, gfp_t gfp)
 {
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
 
-       return __cfg80211_testmode_alloc_skb(rdev, approxlen, 0, 0, gfp);
+       return __cfg80211_alloc_vendor_skb(rdev, approxlen, 0, 0,
+                                          NL80211_CMD_TESTMODE,
+                                          NL80211_ATTR_TESTDATA, gfp);
 }
 EXPORT_SYMBOL(cfg80211_testmode_alloc_event_skb);
 
@@ -7328,11 +7328,72 @@ static bool ht_rateset_to_mask(struct ieee80211_supported_band *sband,
        return true;
 }
 
+static u16 vht_mcs_map_to_mcs_mask(u8 vht_mcs_map)
+{
+       u16 mcs_mask = 0;
+
+       switch (vht_mcs_map) {
+       case IEEE80211_VHT_MCS_NOT_SUPPORTED:
+               break;
+       case IEEE80211_VHT_MCS_SUPPORT_0_7:
+               mcs_mask = 0x00FF;
+               break;
+       case IEEE80211_VHT_MCS_SUPPORT_0_8:
+               mcs_mask = 0x01FF;
+               break;
+       case IEEE80211_VHT_MCS_SUPPORT_0_9:
+               mcs_mask = 0x03FF;
+               break;
+       default:
+               break;
+       }
+
+       return mcs_mask;
+}
+
+static void vht_build_mcs_mask(u16 vht_mcs_map,
+                              u16 vht_mcs_mask[NL80211_VHT_NSS_MAX])
+{
+       u8 nss;
+
+       for (nss = 0; nss < NL80211_VHT_NSS_MAX; nss++) {
+               vht_mcs_mask[nss] = vht_mcs_map_to_mcs_mask(vht_mcs_map & 0x03);
+               vht_mcs_map >>= 2;
+       }
+}
+
+static bool vht_set_mcs_mask(struct ieee80211_supported_band *sband,
+                            struct nl80211_txrate_vht *txrate,
+                            u16 mcs[NL80211_VHT_NSS_MAX])
+{
+       u16 tx_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map);
+       u16 tx_mcs_mask[NL80211_VHT_NSS_MAX] = {};
+       u8 i;
+
+       if (!sband->vht_cap.vht_supported)
+               return false;
+
+       memset(mcs, 0, sizeof(u16) * NL80211_VHT_NSS_MAX);
+
+       /* Build vht_mcs_mask from VHT capabilities */
+       vht_build_mcs_mask(tx_mcs_map, tx_mcs_mask);
+
+       for (i = 0; i < NL80211_VHT_NSS_MAX; i++) {
+               if ((tx_mcs_mask[i] & txrate->mcs[i]) == txrate->mcs[i])
+                       mcs[i] = txrate->mcs[i];
+               else
+                       return false;
+       }
+
+       return true;
+}
+
 static const struct nla_policy nl80211_txattr_policy[NL80211_TXRATE_MAX + 1] = {
        [NL80211_TXRATE_LEGACY] = { .type = NLA_BINARY,
                                    .len = NL80211_MAX_SUPP_RATES },
-       [NL80211_TXRATE_MCS] = { .type = NLA_BINARY,
-                                .len = NL80211_MAX_SUPP_HT_RATES },
+       [NL80211_TXRATE_HT] = { .type = NLA_BINARY,
+                               .len = NL80211_MAX_SUPP_HT_RATES },
+       [NL80211_TXRATE_VHT] = { .len = sizeof(struct nl80211_txrate_vht)},
 };
 
 static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
@@ -7345,9 +7406,7 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
        struct net_device *dev = info->user_ptr[1];
        struct nlattr *tx_rates;
        struct ieee80211_supported_band *sband;
-
-       if (info->attrs[NL80211_ATTR_TX_RATES] == NULL)
-               return -EINVAL;
+       u16 vht_tx_mcs_map;
 
        if (!rdev->ops->set_bitrate_mask)
                return -EOPNOTSUPP;
@@ -7356,17 +7415,26 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
        /* Default to all rates enabled */
        for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
                sband = rdev->wiphy.bands[i];
-               mask.control[i].legacy =
-                       sband ? (1 << sband->n_bitrates) - 1 : 0;
-               if (sband)
-                       memcpy(mask.control[i].mcs,
-                              sband->ht_cap.mcs.rx_mask,
-                              sizeof(mask.control[i].mcs));
-               else
-                       memset(mask.control[i].mcs, 0,
-                              sizeof(mask.control[i].mcs));
+
+               if (!sband)
+                       continue;
+
+               mask.control[i].legacy = (1 << sband->n_bitrates) - 1;
+               memcpy(mask.control[i].ht_mcs,
+                      sband->ht_cap.mcs.rx_mask,
+                      sizeof(mask.control[i].ht_mcs));
+
+               if (!sband->vht_cap.vht_supported)
+                       continue;
+
+               vht_tx_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map);
+               vht_build_mcs_mask(vht_tx_mcs_map, mask.control[i].vht_mcs);
        }
 
+       /* if no rates are given set it back to the defaults */
+       if (!info->attrs[NL80211_ATTR_TX_RATES])
+               goto out;
+
        /*
         * The nested attribute uses enum nl80211_band as the index. This maps
         * directly to the enum ieee80211_band values used in cfg80211.
@@ -7391,31 +7459,44 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
                            nla_len(tb[NL80211_TXRATE_LEGACY]))
                                return -EINVAL;
                }
-               if (tb[NL80211_TXRATE_MCS]) {
+               if (tb[NL80211_TXRATE_HT]) {
                        if (!ht_rateset_to_mask(
                                        sband,
-                                       nla_data(tb[NL80211_TXRATE_MCS]),
-                                       nla_len(tb[NL80211_TXRATE_MCS]),
-                                       mask.control[band].mcs))
+                                       nla_data(tb[NL80211_TXRATE_HT]),
+                                       nla_len(tb[NL80211_TXRATE_HT]),
+                                       mask.control[band].ht_mcs))
+                               return -EINVAL;
+               }
+               if (tb[NL80211_TXRATE_VHT]) {
+                       if (!vht_set_mcs_mask(
+                                       sband,
+                                       nla_data(tb[NL80211_TXRATE_VHT]),
+                                       mask.control[band].vht_mcs))
                                return -EINVAL;
                }
 
                if (mask.control[band].legacy == 0) {
-                       /* don't allow empty legacy rates if HT
-                        * is not even supported. */
-                       if (!rdev->wiphy.bands[band]->ht_cap.ht_supported)
+                       /* don't allow empty legacy rates if HT or VHT
+                        * are not even supported.
+                        */
+                       if (!(rdev->wiphy.bands[band]->ht_cap.ht_supported ||
+                             rdev->wiphy.bands[band]->vht_cap.vht_supported))
                                return -EINVAL;
 
                        for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
-                               if (mask.control[band].mcs[i])
-                                       break;
+                               if (mask.control[band].ht_mcs[i])
+                                       goto out;
+
+                       for (i = 0; i < NL80211_VHT_NSS_MAX; i++)
+                               if (mask.control[band].vht_mcs[i])
+                                       goto out;
 
                        /* legacy and mcs rates may not be both empty */
-                       if (i == IEEE80211_HT_MCS_MASK_LEN)
-                               return -EINVAL;
+                       return -EINVAL;
                }
        }
 
+out:
        return rdev_set_bitrate_mask(rdev, dev, NULL, &mask);
 }
 
@@ -8875,6 +8956,111 @@ static int nl80211_crit_protocol_stop(struct sk_buff *skb,
        return 0;
 }
 
+static int nl80211_vendor_cmd(struct sk_buff *skb, struct genl_info *info)
+{
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct wireless_dev *wdev =
+               __cfg80211_wdev_from_attrs(genl_info_net(info), info->attrs);
+       int i, err;
+       u32 vid, subcmd;
+
+       if (!rdev->wiphy.vendor_commands)
+               return -EOPNOTSUPP;
+
+       if (IS_ERR(wdev)) {
+               err = PTR_ERR(wdev);
+               if (err != -EINVAL)
+                       return err;
+               wdev = NULL;
+       } else if (wdev->wiphy != &rdev->wiphy) {
+               return -EINVAL;
+       }
+
+       if (!info->attrs[NL80211_ATTR_VENDOR_ID] ||
+           !info->attrs[NL80211_ATTR_VENDOR_SUBCMD])
+               return -EINVAL;
+
+       vid = nla_get_u32(info->attrs[NL80211_ATTR_VENDOR_ID]);
+       subcmd = nla_get_u32(info->attrs[NL80211_ATTR_VENDOR_SUBCMD]);
+       for (i = 0; i < rdev->wiphy.n_vendor_commands; i++) {
+               const struct wiphy_vendor_command *vcmd;
+               void *data = NULL;
+               int len = 0;
+
+               vcmd = &rdev->wiphy.vendor_commands[i];
+
+               if (vcmd->info.vendor_id != vid || vcmd->info.subcmd != subcmd)
+                       continue;
+
+               if (vcmd->flags & (WIPHY_VENDOR_CMD_NEED_WDEV |
+                                  WIPHY_VENDOR_CMD_NEED_NETDEV)) {
+                       if (!wdev)
+                               return -EINVAL;
+                       if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_NETDEV &&
+                           !wdev->netdev)
+                               return -EINVAL;
+
+                       if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_RUNNING) {
+                               if (wdev->netdev &&
+                                   !netif_running(wdev->netdev))
+                                       return -ENETDOWN;
+                               if (!wdev->netdev && !wdev->p2p_started)
+                                       return -ENETDOWN;
+                       }
+               } else {
+                       wdev = NULL;
+               }
+
+               if (info->attrs[NL80211_ATTR_VENDOR_DATA]) {
+                       data = nla_data(info->attrs[NL80211_ATTR_VENDOR_DATA]);
+                       len = nla_len(info->attrs[NL80211_ATTR_VENDOR_DATA]);
+               }
+
+               rdev->cur_cmd_info = info;
+               err = rdev->wiphy.vendor_commands[i].doit(&rdev->wiphy, wdev,
+                                                         data, len);
+               rdev->cur_cmd_info = NULL;
+               return err;
+       }
+
+       return -EOPNOTSUPP;
+}
+
+struct sk_buff *__cfg80211_alloc_reply_skb(struct wiphy *wiphy,
+                                          enum nl80211_commands cmd,
+                                          enum nl80211_attrs attr,
+                                          int approxlen)
+{
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+
+       if (WARN_ON(!rdev->cur_cmd_info))
+               return NULL;
+
+       return __cfg80211_alloc_vendor_skb(rdev, approxlen,
+                                          rdev->cur_cmd_info->snd_portid,
+                                          rdev->cur_cmd_info->snd_seq,
+                                          cmd, attr, GFP_KERNEL);
+}
+EXPORT_SYMBOL(__cfg80211_alloc_reply_skb);
+
+int cfg80211_vendor_cmd_reply(struct sk_buff *skb)
+{
+       struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0];
+       void *hdr = ((void **)skb->cb)[1];
+       struct nlattr *data = ((void **)skb->cb)[2];
+
+       if (WARN_ON(!rdev->cur_cmd_info)) {
+               kfree_skb(skb);
+               return -EINVAL;
+       }
+
+       nla_nest_end(skb, data);
+       genlmsg_end(skb, hdr);
+       return genlmsg_reply(skb, rdev->cur_cmd_info);
+}
+EXPORT_SYMBOL_GPL(cfg80211_vendor_cmd_reply);
+
+
 #define NL80211_FLAG_NEED_WIPHY                0x01
 #define NL80211_FLAG_NEED_NETDEV       0x02
 #define NL80211_FLAG_NEED_RTNL         0x04
@@ -9599,6 +9785,14 @@ static const struct genl_ops nl80211_ops[] = {
                .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
                                  NL80211_FLAG_NEED_RTNL,
        },
+       {
+               .cmd = NL80211_CMD_VENDOR,
+               .doit = nl80211_vendor_cmd,
+               .policy = nl80211_policy,
+               .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_WIPHY |
+                                 NL80211_FLAG_NEED_RTNL,
+       },
 };
 
 /* notification functions */
index ec54e1aac8e29c01e89ab4d0c6e9078bf112b5f9..7d20d844ca60e47e09bfea602a6bdca659d01ce6 100644 (file)
@@ -135,6 +135,33 @@ static const char *reg_dfs_region_str(enum nl80211_dfs_regions dfs_region)
        return "Unknown";
 }
 
+enum nl80211_dfs_regions reg_get_dfs_region(struct wiphy *wiphy)
+{
+       const struct ieee80211_regdomain *regd = NULL;
+       const struct ieee80211_regdomain *wiphy_regd = NULL;
+
+       regd = get_cfg80211_regdom();
+       if (!wiphy)
+               goto out;
+
+       wiphy_regd = get_wiphy_regdom(wiphy);
+       if (!wiphy_regd)
+               goto out;
+
+       if (wiphy_regd->dfs_region == regd->dfs_region)
+               goto out;
+
+       REG_DBG_PRINT("%s: device specific dfs_region "
+                     "(%s) disagrees with cfg80211's "
+                     "central dfs_region (%s)\n",
+                     dev_name(&wiphy->dev),
+                     reg_dfs_region_str(wiphy_regd->dfs_region),
+                     reg_dfs_region_str(regd->dfs_region));
+
+out:
+       return regd->dfs_region;
+}
+
 static void rcu_free_regdom(const struct ieee80211_regdomain *r)
 {
        if (!r)
index cc4c2c0a67236cd2801f954e0a8e15dc4b5adea5..02bd8f4b0921dafca98c4e1bc23b729045b036db 100644 (file)
@@ -21,6 +21,7 @@ extern const struct ieee80211_regdomain __rcu *cfg80211_regdomain;
 bool reg_is_valid_request(const char *alpha2);
 bool is_world_regdom(const char *alpha2);
 bool reg_supported_dfs_region(enum nl80211_dfs_regions dfs_region);
+enum nl80211_dfs_regions reg_get_dfs_region(struct wiphy *wiphy);
 
 int regulatory_hint_user(const char *alpha2,
                         enum nl80211_user_reg_hint_type user_reg_hint_type);
index d4397eba5408ea4325ac3404a251b8617d878309..a32d52a04c275c6c148e71ab0a31edd9aae3020d 100644 (file)
@@ -161,7 +161,7 @@ static void __cfg80211_bss_expire(struct cfg80211_registered_device *dev,
                dev->bss_generation++;
 }
 
-void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak)
+void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev)
 {
        struct cfg80211_scan_request *request;
        struct wireless_dev *wdev;
@@ -210,17 +210,7 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak)
                dev_put(wdev->netdev);
 
        rdev->scan_req = NULL;
-
-       /*
-        * OK. If this is invoked with "leak" then we can't
-        * free this ... but we've cleaned it up anyway. The
-        * driver failed to call the scan_done callback, so
-        * all bets are off, it might still be trying to use
-        * the scan request or not ... if it accesses the dev
-        * in there (it shouldn't anyway) then it may crash.
-        */
-       if (!leak)
-               kfree(request);
+       kfree(request);
 }
 
 void __cfg80211_scan_done(struct work_struct *wk)
@@ -231,7 +221,7 @@ void __cfg80211_scan_done(struct work_struct *wk)
                            scan_done_wk);
 
        rtnl_lock();
-       ___cfg80211_scan_done(rdev, false);
+       ___cfg80211_scan_done(rdev);
        rtnl_unlock();
 }