Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
authorDavid S. Miller <davem@davemloft.net>
Tue, 24 Nov 2009 23:01:29 +0000 (15:01 -0800)
committerDavid S. Miller <davem@davemloft.net>
Tue, 24 Nov 2009 23:01:29 +0000 (15:01 -0800)
125 files changed:
drivers/net/wireless/ath/ar9170/main.c
drivers/net/wireless/ath/ar9170/usb.c
drivers/net/wireless/ath/ath5k/phy.c
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/common.c
drivers/net/wireless/ath/ath9k/common.h
drivers/net/wireless/ath/ath9k/debug.c
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/ath/ath9k/hw.h
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/phy.c
drivers/net/wireless/ath/ath9k/phy.h
drivers/net/wireless/ath/ath9k/rc.c
drivers/net/wireless/ath/ath9k/rc.h
drivers/net/wireless/ath/ath9k/virtual.c
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/ath/regd.c
drivers/net/wireless/b43/dma.c
drivers/net/wireless/b43/dma.h
drivers/net/wireless/ipw2x00/ipw2100.c
drivers/net/wireless/ipw2x00/ipw2200.c
drivers/net/wireless/ipw2x00/libipw.h
drivers/net/wireless/ipw2x00/libipw_module.c
drivers/net/wireless/iwlwifi/iwl-1000.c
drivers/net/wireless/iwlwifi/iwl-3945.h
drivers/net/wireless/iwlwifi/iwl-4965.c
drivers/net/wireless/iwlwifi/iwl-5000.c
drivers/net/wireless/iwlwifi/iwl-6000.c
drivers/net/wireless/iwlwifi/iwl-agn-rs.c
drivers/net/wireless/iwlwifi/iwl-agn.c
drivers/net/wireless/iwlwifi/iwl-calib.c
drivers/net/wireless/iwlwifi/iwl-commands.h
drivers/net/wireless/iwlwifi/iwl-core.c
drivers/net/wireless/iwlwifi/iwl-core.h
drivers/net/wireless/iwlwifi/iwl-csr.h
drivers/net/wireless/iwlwifi/iwl-debug.h
drivers/net/wireless/iwlwifi/iwl-debugfs.c
drivers/net/wireless/iwlwifi/iwl-dev.h
drivers/net/wireless/iwlwifi/iwl-devtrace.c
drivers/net/wireless/iwlwifi/iwl-devtrace.h
drivers/net/wireless/iwlwifi/iwl-eeprom.c
drivers/net/wireless/iwlwifi/iwl-eeprom.h
drivers/net/wireless/iwlwifi/iwl-io.h
drivers/net/wireless/iwlwifi/iwl-led.c
drivers/net/wireless/iwlwifi/iwl-power.c
drivers/net/wireless/iwlwifi/iwl-rx.c
drivers/net/wireless/iwlwifi/iwl-sta.c
drivers/net/wireless/iwlwifi/iwl-sta.h
drivers/net/wireless/iwlwifi/iwl-tx.c
drivers/net/wireless/iwlwifi/iwl3945-base.c
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/p54/main.c
drivers/net/wireless/rndis_wlan.c
drivers/net/wireless/rt2x00/rt2800usb.c
drivers/net/wireless/rt2x00/rt2x00dev.c
drivers/net/wireless/rt2x00/rt2x00lib.h
drivers/net/wireless/rt2x00/rt2x00mac.c
drivers/net/wireless/rt2x00/rt2x00queue.c
drivers/net/wireless/rt2x00/rt2x00queue.h
drivers/net/wireless/wl12xx/wl1251.h
drivers/net/wireless/wl12xx/wl1251_acx.c
drivers/net/wireless/wl12xx/wl1251_acx.h
drivers/net/wireless/wl12xx/wl1251_boot.c
drivers/net/wireless/wl12xx/wl1251_event.c
drivers/net/wireless/wl12xx/wl1251_init.c
drivers/net/wireless/wl12xx/wl1251_main.c
drivers/net/wireless/wl12xx/wl1251_ps.c
drivers/net/wireless/wl12xx/wl1251_ps.h
drivers/net/wireless/wl12xx/wl1251_reg.h
drivers/net/wireless/wl12xx/wl1251_rx.c
drivers/net/wireless/wl12xx/wl1251_spi.c
drivers/net/wireless/wl3501_cs.c
drivers/ssb/main.c
drivers/ssb/scan.c
drivers/ssb/sprom.c
drivers/ssb/ssb_private.h
include/linux/ieee80211.h
include/linux/if.h
include/linux/rfkill.h
include/linux/spi/wl12xx.h
include/net/cfg80211.h
include/net/mac80211.h
net/bridge/br_if.c
net/mac80211/Makefile
net/mac80211/agg-rx.c
net/mac80211/agg-tx.c
net/mac80211/cfg.c
net/mac80211/debugfs.c
net/mac80211/debugfs_sta.c
net/mac80211/driver-ops.h
net/mac80211/driver-trace.h
net/mac80211/ht.c
net/mac80211/ibss.c
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/main.c
net/mac80211/mesh.c
net/mac80211/mesh.h
net/mac80211/mesh_hwmp.c
net/mac80211/mesh_pathtbl.c
net/mac80211/mesh_plink.c
net/mac80211/mlme.c
net/mac80211/rate.c
net/mac80211/rate.h
net/mac80211/rx.c
net/mac80211/spectmgmt.c
net/mac80211/sta_info.c
net/mac80211/sta_info.h
net/mac80211/status.c [new file with mode: 0644]
net/mac80211/tkip.c
net/mac80211/tx.c
net/mac80211/util.c
net/mac80211/wep.c
net/mac80211/wpa.c
net/rfkill/core.c
net/wireless/Kconfig
net/wireless/core.c
net/wireless/core.h
net/wireless/ibss.c
net/wireless/mlme.c
net/wireless/nl80211.c
net/wireless/reg.c
net/wireless/scan.c
net/wireless/util.c
net/wireless/wext-compat.c

index 7e59b82..f9d6db8 100644 (file)
@@ -850,6 +850,7 @@ static int ar9170_rx_mac_status(struct ar9170 *ar,
                }
                break;
 
+       case AR9170_RX_STATUS_MODULATION_DUPOFDM:
        case AR9170_RX_STATUS_MODULATION_OFDM:
                switch (head->plcp[0] & 0xf) {
                case 0xb:
@@ -897,8 +898,7 @@ static int ar9170_rx_mac_status(struct ar9170 *ar,
                status->flag |= RX_FLAG_HT;
                break;
 
-       case AR9170_RX_STATUS_MODULATION_DUPOFDM:
-               /* XXX */
+       default:
                if (ar9170_nag_limiter(ar))
                        printk(KERN_ERR "%s: invalid modulation\n",
                               wiphy_name(ar->hw->wiphy));
@@ -2441,6 +2441,7 @@ static int ar9170_conf_tx(struct ieee80211_hw *hw, u16 queue,
 }
 
 static int ar9170_ampdu_action(struct ieee80211_hw *hw,
+                              struct ieee80211_vif *vif,
                               enum ieee80211_ampdu_mlme_action action,
                               struct ieee80211_sta *sta, u16 tid, u16 *ssn)
 {
@@ -2470,7 +2471,7 @@ static int ar9170_ampdu_action(struct ieee80211_hw *hw,
                tid_info->state = AR9170_TID_STATE_PROGRESS;
                tid_info->active = false;
                spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
-               ieee80211_start_tx_ba_cb_irqsafe(hw, sta->addr, tid);
+               ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
                break;
 
        case IEEE80211_AMPDU_TX_STOP:
@@ -2480,7 +2481,7 @@ static int ar9170_ampdu_action(struct ieee80211_hw *hw,
                tid_info->active = false;
                skb_queue_purge(&tid_info->queue);
                spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
-               ieee80211_stop_tx_ba_cb_irqsafe(hw, sta->addr, tid);
+               ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
                break;
 
        case IEEE80211_AMPDU_TX_OPERATIONAL:
index 6bdcdf6..e0799d9 100644 (file)
@@ -68,8 +68,10 @@ static struct usb_device_id ar9170_usb_ids[] = {
        { USB_DEVICE(0x0cf3, 0x1002) },
        /* Cace Airpcap NX */
        { USB_DEVICE(0xcace, 0x0300) },
-       /* D-Link DWA 160A */
+       /* D-Link DWA 160 A1 */
        { USB_DEVICE(0x07d1, 0x3c10) },
+       /* D-Link DWA 160 A2 */
+       { USB_DEVICE(0x07d1, 0x3a09) },
        /* Netgear WNDA3100 */
        { USB_DEVICE(0x0846, 0x9010) },
        /* Netgear WN111 v2 */
index 721ec5e..bbfdcd5 100644 (file)
@@ -1399,7 +1399,7 @@ static int ath5k_hw_rf511x_calibrate(struct ath5k_hw *ah,
        if (i_coffd == 0 || q_coffd == 0)
                goto done;
 
-       i_coff = ((-iq_corr) / i_coffd) & 0x3f;
+       i_coff = ((-iq_corr) / i_coffd);
 
        /* Boundary check */
        if (i_coff > 31)
@@ -1407,7 +1407,7 @@ static int ath5k_hw_rf511x_calibrate(struct ath5k_hw *ah,
        if (i_coff < -32)
                i_coff = -32;
 
-       q_coff = (((s32)i_pwr / q_coffd) - 128) & 0x1f;
+       q_coff = (((s32)i_pwr / q_coffd) - 128);
 
        /* Boundary check */
        if (q_coff > 15)
index d9bcc3a..2a40fa2 100644 (file)
@@ -198,18 +198,8 @@ struct ath_txq {
        struct list_head axq_q;
        spinlock_t axq_lock;
        u32 axq_depth;
-       u8 axq_aggr_depth;
        bool stopped;
        bool axq_tx_inprogress;
-       struct ath_buf *axq_linkbuf;
-
-       /* first desc of the last descriptor that contains CTS */
-       struct ath_desc *axq_lastdsWithCTS;
-
-       /* final desc of the gating desc that determines whether
-          lastdsWithCTS has been DMA'ed or not */
-       struct ath_desc *axq_gatingds;
-
        struct list_head axq_acq;
 };
 
index 2f1e161..4a13632 100644 (file)
@@ -231,26 +231,35 @@ void ath9k_cmn_rx_skb_postprocess(struct ath_common *common,
 {
        struct ath_hw *ah = common->ah;
        struct ieee80211_hdr *hdr;
-       int hdrlen, padsize;
+       int hdrlen, padpos, padsize;
        u8 keyix;
        __le16 fc;
 
        /* see if any padding is done by the hw and remove it */
        hdr = (struct ieee80211_hdr *) skb->data;
        hdrlen = ieee80211_get_hdrlen_from_skb(skb);
+       padpos = 24;
        fc = hdr->frame_control;
+       if ((fc & cpu_to_le16(IEEE80211_FCTL_FROMDS|IEEE80211_FCTL_TODS)) ==
+           cpu_to_le16(IEEE80211_FCTL_FROMDS|IEEE80211_FCTL_TODS)) {
+         padpos += 6; /* ETH_ALEN */
+       }
+       if ((fc & cpu_to_le16(IEEE80211_STYPE_QOS_DATA|IEEE80211_FCTL_FTYPE)) ==
+           cpu_to_le16(IEEE80211_STYPE_QOS_DATA|IEEE80211_FTYPE_DATA)) {
+         padpos += 2;
+       }
 
        /* The MAC header is padded to have 32-bit boundary if the
         * packet payload is non-zero. The general calculation for
         * padsize would take into account odd header lengths:
-        * padsize = (4 - hdrlen % 4) % 4; However, since only
+        * padsize = (4 - padpos % 4) % 4; However, since only
         * even-length headers are used, padding can only be 0 or 2
         * bytes and we can optimize this a bit. In addition, we must
         * not try to remove padding from short control frames that do
         * not have payload. */
-       padsize = hdrlen & 3;
-       if (padsize && hdrlen >= 24) {
-               memmove(skb->data + padsize, skb->data, hdrlen);
+       padsize = padpos & 3;
+       if (padsize && skb->len>=padpos+padsize+FCS_LEN) {
+               memmove(skb->data + padsize, skb->data, padpos);
                skb_pull(skb, padsize);
        }
 
index 292e3d8..4e11760 100644 (file)
@@ -81,6 +81,7 @@ struct ath_buf {
        u16 bf_flags;
        struct ath_buf_state bf_state;
        dma_addr_t bf_dmacontext;
+       struct ath_wiphy *aphy;
 };
 
 struct ath_atx_tid {
index 84f4426..06f1fcf 100644 (file)
@@ -257,14 +257,17 @@ static const struct file_operations fops_interrupt = {
 
 void ath_debug_stat_rc(struct ath_softc *sc, struct sk_buff *skb)
 {
-       struct ath_tx_info_priv *tx_info_priv = NULL;
        struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
        struct ieee80211_tx_rate *rates = tx_info->status.rates;
-       int final_ts_idx, idx;
+       int final_ts_idx = 0, idx, i;
        struct ath_rc_stats *stats;
 
-       tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
-       final_ts_idx = tx_info_priv->tx.ts_rateindex;
+       for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
+               if (!rates[i].count)
+                       break;
+
+               final_ts_idx = i;
+       }
        idx = rates[final_ts_idx].idx;
        stats = &sc->debug.stats.rcstats[idx];
        stats->success++;
index b25eedf..53a7b98 100644 (file)
@@ -390,8 +390,6 @@ static void ath9k_hw_init_config(struct ath_hw *ah)
        ah->config.cck_trig_high = 200;
        ah->config.cck_trig_low = 100;
        ah->config.enable_ani = 1;
-       ah->config.diversity_control = ATH9K_ANT_VARIABLE;
-       ah->config.antenna_switch_swap = 0;
 
        for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
                ah->config.spurchans[i][0] = AR_NO_SPUR;
@@ -446,9 +444,6 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah)
        ah->acktimeout = (u32) -1;
        ah->ctstimeout = (u32) -1;
        ah->globaltxtimeout = (u32) -1;
-
-       ah->gbeacon_rate = 0;
-
        ah->power_mode = ATH9K_PM_UNDEFINED;
 }
 
@@ -1151,7 +1146,7 @@ static void ath9k_hw_init_chain_masks(struct ath_hw *ah)
                REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP,
                            AR_PHY_SWAP_ALT_CHAIN);
        case 0x3:
-               if (((ah)->hw_version.macVersion <= AR_SREV_VERSION_9160)) {
+               if (ah->hw_version.macVersion == AR_SREV_REVISION_5416_10) {
                        REG_WRITE(ah, AR_PHY_RX_CHAINMASK, 0x7);
                        REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, 0x7);
                        break;
@@ -2056,9 +2051,6 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        ah->ath9k_hw_spur_mitigate_freq(ah, chan);
        ah->eep_ops->set_board_values(ah, chan);
 
-       if (AR_SREV_5416(ah))
-               ath9k_hw_decrease_chain_power(ah, chan);
-
        REG_WRITE(ah, AR_STA_ID0, get_unaligned_le32(common->macaddr));
        REG_WRITE(ah, AR_STA_ID1, get_unaligned_le16(common->macaddr + 4)
                  | macStaId1
@@ -3518,51 +3510,6 @@ void ath9k_hw_setantenna(struct ath_hw *ah, u32 antenna)
 }
 EXPORT_SYMBOL(ath9k_hw_setantenna);
 
-bool ath9k_hw_setantennaswitch(struct ath_hw *ah,
-                              enum ath9k_ant_setting settings,
-                              struct ath9k_channel *chan,
-                              u8 *tx_chainmask,
-                              u8 *rx_chainmask,
-                              u8 *antenna_cfgd)
-{
-       static u8 tx_chainmask_cfg, rx_chainmask_cfg;
-
-       if (AR_SREV_9280(ah)) {
-               if (!tx_chainmask_cfg) {
-
-                       tx_chainmask_cfg = *tx_chainmask;
-                       rx_chainmask_cfg = *rx_chainmask;
-               }
-
-               switch (settings) {
-               case ATH9K_ANT_FIXED_A:
-                       *tx_chainmask = ATH9K_ANTENNA0_CHAINMASK;
-                       *rx_chainmask = ATH9K_ANTENNA0_CHAINMASK;
-                       *antenna_cfgd = true;
-                       break;
-               case ATH9K_ANT_FIXED_B:
-                       if (ah->caps.tx_chainmask >
-                           ATH9K_ANTENNA1_CHAINMASK) {
-                               *tx_chainmask = ATH9K_ANTENNA1_CHAINMASK;
-                       }
-                       *rx_chainmask = ATH9K_ANTENNA1_CHAINMASK;
-                       *antenna_cfgd = true;
-                       break;
-               case ATH9K_ANT_VARIABLE:
-                       *tx_chainmask = tx_chainmask_cfg;
-                       *rx_chainmask = rx_chainmask_cfg;
-                       *antenna_cfgd = true;
-                       break;
-               default:
-                       break;
-               }
-       } else {
-               ah->config.diversity_control = settings;
-       }
-
-       return true;
-}
-
 /*********************/
 /* General Operation */
 /*********************/
index abaa2f0..f8f5e99 100644 (file)
@@ -148,21 +148,6 @@ enum wireless_mode {
        ATH9K_MODE_MAX,
 };
 
-/**
- * ath9k_ant_setting - transmit antenna settings
- *
- * Configures the antenna setting to use for transmit.
- *
- * @ATH9K_ANT_VARIABLE: this means transmit on all active antennas
- * @ATH9K_ANT_FIXED_A: this means transmit on the first antenna only
- * @ATH9K_ANT_FIXED_B: this means transmit on the second antenna only
- */
-enum ath9k_ant_setting {
-       ATH9K_ANT_VARIABLE = 0,
-       ATH9K_ANT_FIXED_A,
-       ATH9K_ANT_FIXED_B
-};
-
 enum ath9k_hw_caps {
        ATH9K_HW_CAP_MIC_AESCCM                 = BIT(0),
        ATH9K_HW_CAP_MIC_CKIP                   = BIT(1),
@@ -226,8 +211,6 @@ struct ath9k_ops_config {
        u32 cck_trig_high;
        u32 cck_trig_low;
        u32 enable_ani;
-       enum ath9k_ant_setting diversity_control;
-       u16 antenna_switch_swap;
        int serialize_regmode;
        bool intr_mitigation;
 #define SPUR_DISABLE           0
@@ -572,7 +555,6 @@ struct ath_hw {
        u32 acktimeout;
        u32 ctstimeout;
        u32 globaltxtimeout;
-       u8 gbeacon_rate;
 
        /* ANI */
        u32 proc_phyerr;
@@ -659,11 +641,6 @@ void ath9k_hw_cfg_output(struct ath_hw *ah, u32 gpio,
 void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val);
 u32 ath9k_hw_getdefantenna(struct ath_hw *ah);
 void ath9k_hw_setantenna(struct ath_hw *ah, u32 antenna);
-bool ath9k_hw_setantennaswitch(struct ath_hw *ah,
-                              enum ath9k_ant_setting settings,
-                              struct ath9k_channel *chan,
-                              u8 *tx_chainmask, u8 *rx_chainmask,
-                              u8 *antenna_cfgd);
 
 /* General Operation */
 bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout);
index 3c02b97..cbf5d2a 100644 (file)
@@ -1893,6 +1893,8 @@ void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
                BIT(NL80211_IFTYPE_ADHOC) |
                BIT(NL80211_IFTYPE_MESH_POINT);
 
+       hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
+
        hw->queues = 4;
        hw->max_rates = 4;
        hw->channel_change_time = 5000;
@@ -2956,90 +2958,62 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
        struct ath_vif *avp = (void *)vif->drv_priv;
-       u32 rfilt = 0;
-       int error, i;
+       int error;
 
        mutex_lock(&sc->mutex);
 
-       /*
-        * TODO: Need to decide which hw opmode to use for
-        *       multi-interface cases
-        * XXX: This belongs into add_interface!
-        */
-       if (vif->type == NL80211_IFTYPE_AP &&
-           ah->opmode != NL80211_IFTYPE_AP) {
-               ah->opmode = NL80211_IFTYPE_STATION;
-               ath9k_hw_setopmode(ah);
-               memcpy(common->curbssid, common->macaddr, ETH_ALEN);
+       if (changed & BSS_CHANGED_BSSID) {
+               /* Set BSSID */
+               memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
+               memcpy(avp->bssid, bss_conf->bssid, ETH_ALEN);
                common->curaid = 0;
                ath9k_hw_write_associd(ah);
-               /* Request full reset to get hw opmode changed properly */
-               sc->sc_flags |= SC_OP_FULL_RESET;
-       }
 
-       if ((changed & BSS_CHANGED_BSSID) &&
-           !is_zero_ether_addr(bss_conf->bssid)) {
-               switch (vif->type) {
-               case NL80211_IFTYPE_STATION:
-               case NL80211_IFTYPE_ADHOC:
-               case NL80211_IFTYPE_MESH_POINT:
-                       /* Set BSSID */
-                       memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
-                       memcpy(avp->bssid, bss_conf->bssid, ETH_ALEN);
-                       common->curaid = 0;
-                       ath9k_hw_write_associd(ah);
+               /* Set aggregation protection mode parameters */
+               sc->config.ath_aggr_prot = 0;
 
-                       /* Set aggregation protection mode parameters */
-                       sc->config.ath_aggr_prot = 0;
+               /* Only legacy IBSS for now */
+               if (vif->type == NL80211_IFTYPE_ADHOC)
+                       ath_update_chainmask(sc, 0);
 
-                       ath_print(common, ATH_DBG_CONFIG,
-                                 "RX filter 0x%x bssid %pM aid 0x%x\n",
-                                 rfilt, common->curbssid, common->curaid);
+               ath_print(common, ATH_DBG_CONFIG,
+                         "BSSID: %pM aid: 0x%x\n",
+                         common->curbssid, common->curaid);
 
-                       /* need to reconfigure the beacon */
-                       sc->sc_flags &= ~SC_OP_BEACONS ;
+               /* need to reconfigure the beacon */
+               sc->sc_flags &= ~SC_OP_BEACONS ;
+       }
 
-                       break;
-               default:
-                       break;
-               }
+       /* Enable transmission of beacons (AP, IBSS, MESH) */
+       if ((changed & BSS_CHANGED_BEACON) ||
+           ((changed & BSS_CHANGED_BEACON_ENABLED) && bss_conf->enable_beacon)) {
+               ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
+               error = ath_beacon_alloc(aphy, vif);
+               if (!error)
+                       ath_beacon_config(sc, vif);
        }
 
-       if ((vif->type == NL80211_IFTYPE_ADHOC) ||
-           (vif->type == NL80211_IFTYPE_AP) ||
-           (vif->type == NL80211_IFTYPE_MESH_POINT)) {
-               if ((changed & BSS_CHANGED_BEACON) ||
-                   (changed & BSS_CHANGED_BEACON_ENABLED &&
-                    bss_conf->enable_beacon)) {
-                       /*
-                        * Allocate and setup the beacon frame.
-                        *
-                        * Stop any previous beacon DMA.  This may be
-                        * necessary, for example, when an ibss merge
-                        * causes reconfiguration; we may be called
-                        * with beacon transmission active.
-                        */
-                       ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
+       /* Disable transmission of beacons */
+       if ((changed & BSS_CHANGED_BEACON_ENABLED) && !bss_conf->enable_beacon)
+               ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
 
+       if (changed & BSS_CHANGED_BEACON_INT) {
+               sc->beacon_interval = bss_conf->beacon_int;
+               /*
+                * In case of AP mode, the HW TSF has to be reset
+                * when the beacon interval changes.
+                */
+               if (vif->type == NL80211_IFTYPE_AP) {
+                       sc->sc_flags |= SC_OP_TSF_RESET;
+                       ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
                        error = ath_beacon_alloc(aphy, vif);
                        if (!error)
                                ath_beacon_config(sc, vif);
+               } else {
+                       ath_beacon_config(sc, vif);
                }
        }
 
-       /* Check for WLAN_CAPABILITY_PRIVACY ? */
-       if ((avp->av_opmode != NL80211_IFTYPE_STATION)) {
-               for (i = 0; i < IEEE80211_WEP_NKID; i++)
-                       if (ath9k_hw_keyisvalid(sc->sc_ah, (u16)i))
-                               ath9k_hw_keysetmac(sc->sc_ah,
-                                                  (u16)i,
-                                                  common->curbssid);
-       }
-
-       /* Only legacy IBSS for now */
-       if (vif->type == NL80211_IFTYPE_ADHOC)
-               ath_update_chainmask(sc, 0);
-
        if (changed & BSS_CHANGED_ERP_PREAMBLE) {
                ath_print(common, ATH_DBG_CONFIG, "BSS Changed PREAMBLE %d\n",
                          bss_conf->use_short_preamble);
@@ -3065,18 +3039,6 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
                ath9k_bss_assoc_info(sc, vif, bss_conf);
        }
 
-       /*
-        * The HW TSF has to be reset when the beacon interval changes.
-        * We set the flag here, and ath_beacon_config_ap() would take this
-        * into account when it gets called through the subsequent
-        * config_interface() call - with IFCC_BEACON in the changed field.
-        */
-
-       if (changed & BSS_CHANGED_BEACON_INT) {
-               sc->sc_flags |= SC_OP_TSF_RESET;
-               sc->beacon_interval = bss_conf->beacon_int;
-       }
-
        mutex_unlock(&sc->mutex);
 }
 
@@ -3118,6 +3080,7 @@ static void ath9k_reset_tsf(struct ieee80211_hw *hw)
 }
 
 static int ath9k_ampdu_action(struct ieee80211_hw *hw,
+                             struct ieee80211_vif *vif,
                              enum ieee80211_ampdu_mlme_action action,
                              struct ieee80211_sta *sta,
                              u16 tid, u16 *ssn)
@@ -3135,11 +3098,11 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
                break;
        case IEEE80211_AMPDU_TX_START:
                ath_tx_aggr_start(sc, sta, tid, ssn);
-               ieee80211_start_tx_ba_cb_irqsafe(hw, sta->addr, tid);
+               ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
                break;
        case IEEE80211_AMPDU_TX_STOP:
                ath_tx_aggr_stop(sc, sta, tid);
-               ieee80211_stop_tx_ba_cb_irqsafe(hw, sta->addr, tid);
+               ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
                break;
        case IEEE80211_AMPDU_TX_OPERATIONAL:
                ath_tx_aggr_resume(sc, sta, tid);
index 13ab4d7..c3b5939 100644 (file)
@@ -528,95 +528,6 @@ static void ath9k_hw_force_bias(struct ath_hw *ah, u16 synth_freq)
 }
 
 /**
- * ath9k_hw_decrease_chain_power()
- *
- * @ah: atheros hardware structure
- * @chan:
- *
- * Only used on the AR5416 and AR5418 with the external AR2133/AR5133 radios.
- *
- * Sets a chain internal RF path to the lowest output power. Any
- * further writes to bank6 after this setting will override these
- * changes. Thus this function must be the last function in the
- * sequence to modify bank 6.
- *
- * This function must be called after ar5416SetRfRegs() which is
- * called from ath9k_hw_process_ini() due to swizzling of bank 6.
- * Depends on ah->analogBank6Data being initialized by
- * ath9k_hw_set_rf_regs()
- *
- * Additional additive reduction in power -
- * change chain's switch table so chain's tx state is actually the rx
- * state value. May produce different results in 2GHz/5GHz as well as
- * board to board but in general should be a reduction.
- *
- * Activated by #ifdef ALTER_SWITCH.  Not tried yet.  If so, must be
- * called after ah->eep_ops->set_board_values() due to RMW of
- * PHY_SWITCH_CHAIN_0.
- */
-void ath9k_hw_decrease_chain_power(struct ath_hw *ah,
-                                  struct ath9k_channel *chan)
-{
-       int i, regWrites = 0;
-       u32 bank6SelMask;
-       u32 *bank6Temp = ah->bank6Temp;
-
-       BUG_ON(AR_SREV_9280_10_OR_LATER(ah));
-
-       switch (ah->config.diversity_control) {
-       case ATH9K_ANT_FIXED_A:
-               bank6SelMask =
-                   (ah->config.antenna_switch_swap & ANTSWAP_AB) ?
-                       REDUCE_CHAIN_0 : /* swapped, reduce chain 0 */
-                       REDUCE_CHAIN_1; /* normal, select chain 1/2 to reduce */
-               break;
-       case ATH9K_ANT_FIXED_B:
-               bank6SelMask =
-                   (ah->config.antenna_switch_swap & ANTSWAP_AB) ?
-                       REDUCE_CHAIN_1 : /* swapped, reduce chain 1/2 */
-                       REDUCE_CHAIN_0; /* normal, select chain 0 to reduce */
-               break;
-       case ATH9K_ANT_VARIABLE:
-               return; /* do not change anything */
-               break;
-       default:
-               return; /* do not change anything */
-               break;
-       }
-
-       for (i = 0; i < ah->iniBank6.ia_rows; i++)
-               bank6Temp[i] = ah->analogBank6Data[i];
-
-       /* Write Bank 5 to switch Bank 6 write to selected chain only */
-       REG_WRITE(ah, AR_PHY_BASE + 0xD8, bank6SelMask);
-
-       /*
-        * Modify Bank6 selected chain to use lowest amplification.
-        * Modifies the parameters to a value of 1.
-        * Depends on existing bank 6 values to be cached in
-        * ah->analogBank6Data
-        */
-       ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 189, 0);
-       ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 190, 0);
-       ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 191, 0);
-       ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 192, 0);
-       ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 193, 0);
-       ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 222, 0);
-       ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 245, 0);
-       ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 246, 0);
-       ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 247, 0);
-
-       REG_WRITE_RF_ARRAY(&ah->iniBank6, bank6Temp, regWrites);
-
-       REG_WRITE(ah, AR_PHY_BASE + 0xD8, 0x00000053);
-#ifdef ALTER_SWITCH
-       REG_WRITE(ah, PHY_SWITCH_CHAIN_0,
-                 (REG_READ(ah, PHY_SWITCH_CHAIN_0) & ~0x38)
-                 | ((REG_READ(ah, PHY_SWITCH_CHAIN_0) >> 3) & 0x38));
-#endif
-}
-
-/**
  * ath9k_hw_set_channel - tune to a channel on the external AR2133/AR5133 radios
  * @ah: atheros hardware stucture
  * @chan:
@@ -687,7 +598,6 @@ int ath9k_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
        }
 
        ath9k_hw_force_bias(ah, freq);
-       ath9k_hw_decrease_chain_power(ah, chan);
 
        reg32 =
            (channelSel << 8) | (aModeRefSel << 2) | (bModeSynth << 1) |
index dc145a1..31de27d 100644 (file)
@@ -35,9 +35,6 @@ bool ath9k_hw_set_rf_regs(struct ath_hw *ah,
                          struct ath9k_channel *chan,
                          u16 modesIndex);
 
-void ath9k_hw_decrease_chain_power(struct ath_hw *ah,
-                                  struct ath9k_channel *chan);
-
 #define AR_PHY_BASE     0x9800
 #define AR_PHY(_n)      (AR_PHY_BASE + ((_n)<<2))
 
index bb72b46..1d96777 100644 (file)
@@ -859,12 +859,12 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
 static bool ath_rc_update_per(struct ath_softc *sc,
                              const struct ath_rate_table *rate_table,
                              struct ath_rate_priv *ath_rc_priv,
-                             struct ath_tx_info_priv *tx_info_priv,
+                                 struct ieee80211_tx_info *tx_info,
                              int tx_rate, int xretries, int retries,
                              u32 now_msec)
 {
        bool state_change = false;
-       int count;
+       int count, n_bad_frames;
        u8 last_per;
        static u32 nretry_to_per_lookup[10] = {
                100 * 0 / 1,
@@ -880,6 +880,7 @@ static bool ath_rc_update_per(struct ath_softc *sc,
        };
 
        last_per = ath_rc_priv->per[tx_rate];
+       n_bad_frames = tx_info->status.ampdu_len - tx_info->status.ampdu_ack_len;
 
        if (xretries) {
                if (xretries == 1) {
@@ -907,7 +908,7 @@ static bool ath_rc_update_per(struct ath_softc *sc,
                if (retries >= count)
                        retries = count - 1;
 
-               if (tx_info_priv->n_bad_frames) {
+               if (n_bad_frames) {
                        /* new_PER = 7/8*old_PER + 1/8*(currentPER)
                         * Assuming that n_frames is not 0.  The current PER
                         * from the retries is 100 * retries / (retries+1),
@@ -920,14 +921,14 @@ static bool ath_rc_update_per(struct ath_softc *sc,
                         * the above PER.  The expression below is a
                         * simplified version of the sum of these two terms.
                         */
-                       if (tx_info_priv->n_frames > 0) {
-                               int n_frames, n_bad_frames;
+                       if (tx_info->status.ampdu_len > 0) {
+                               int n_frames, n_bad_tries;
                                u8 cur_per, new_per;
 
-                               n_bad_frames = retries * tx_info_priv->n_frames +
-                                       tx_info_priv->n_bad_frames;
-                               n_frames = tx_info_priv->n_frames * (retries + 1);
-                               cur_per = (100 * n_bad_frames / n_frames) >> 3;
+                               n_bad_tries = retries * tx_info->status.ampdu_len +
+                                       n_bad_frames;
+                               n_frames = tx_info->status.ampdu_len * (retries + 1);
+                               cur_per = (100 * n_bad_tries / n_frames) >> 3;
                                new_per = (u8)(last_per - (last_per >> 3) + cur_per);
                                ath_rc_priv->per[tx_rate] = new_per;
                        }
@@ -943,8 +944,7 @@ static bool ath_rc_update_per(struct ath_softc *sc,
                 * this was a probe.  Otherwise, ignore the probe.
                 */
                if (ath_rc_priv->probe_rate && ath_rc_priv->probe_rate == tx_rate) {
-                       if (retries > 0 || 2 * tx_info_priv->n_bad_frames >
-                               tx_info_priv->n_frames) {
+                       if (retries > 0 || 2 * n_bad_frames > tx_info->status.ampdu_len) {
                                /*
                                 * Since we probed with just a single attempt,
                                 * any retries means the probe failed.  Also,
@@ -1003,7 +1003,7 @@ static bool ath_rc_update_per(struct ath_softc *sc,
 
 static void ath_rc_update_ht(struct ath_softc *sc,
                             struct ath_rate_priv *ath_rc_priv,
-                            struct ath_tx_info_priv *tx_info_priv,
+                            struct ieee80211_tx_info *tx_info,
                             int tx_rate, int xretries, int retries)
 {
        u32 now_msec = jiffies_to_msecs(jiffies);
@@ -1020,7 +1020,7 @@ static void ath_rc_update_ht(struct ath_softc *sc,
 
        /* Update PER first */
        state_change = ath_rc_update_per(sc, rate_table, ath_rc_priv,
-                                        tx_info_priv, tx_rate, xretries,
+                                        tx_info, tx_rate, xretries,
                                         retries, now_msec);
 
        /*
@@ -1098,7 +1098,6 @@ static void ath_rc_tx_status(struct ath_softc *sc,
                             struct ieee80211_tx_info *tx_info,
                             int final_ts_idx, int xretries, int long_retry)
 {
-       struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
        const struct ath_rate_table *rate_table;
        struct ieee80211_tx_rate *rates = tx_info->status.rates;
        u8 flags;
@@ -1124,9 +1123,8 @@ static void ath_rc_tx_status(struct ath_softc *sc,
                                        return;
 
                                rix = ath_rc_get_rateindex(rate_table, &rates[i]);
-                               ath_rc_update_ht(sc, ath_rc_priv,
-                                               tx_info_priv, rix,
-                                               xretries ? 1 : 2,
+                               ath_rc_update_ht(sc, ath_rc_priv, tx_info,
+                                               rix, xretries ? 1 : 2,
                                                rates[i].count);
                        }
                }
@@ -1149,8 +1147,7 @@ static void ath_rc_tx_status(struct ath_softc *sc,
                return;
 
        rix = ath_rc_get_rateindex(rate_table, &rates[i]);
-       ath_rc_update_ht(sc, ath_rc_priv, tx_info_priv, rix,
-                        xretries, long_retry);
+       ath_rc_update_ht(sc, ath_rc_priv, tx_info, rix, xretries, long_retry);
 }
 
 static const
@@ -1301,23 +1298,30 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,
 {
        struct ath_softc *sc = priv;
        struct ath_rate_priv *ath_rc_priv = priv_sta;
-       struct ath_tx_info_priv *tx_info_priv = NULL;
        struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
        struct ieee80211_hdr *hdr;
-       int final_ts_idx, tx_status = 0, is_underrun = 0;
+       int final_ts_idx = 0, tx_status = 0, is_underrun = 0;
+       int long_retry = 0;
        __le16 fc;
+       int i;
 
        hdr = (struct ieee80211_hdr *)skb->data;
        fc = hdr->frame_control;
-       tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
-       final_ts_idx = tx_info_priv->tx.ts_rateindex;
+       for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
+               struct ieee80211_tx_rate *rate = &tx_info->status.rates[i];
+               if (!rate->count)
+                       break;
+
+               final_ts_idx = i;
+               long_retry = rate->count - 1;
+       }
 
        if (!priv_sta || !ieee80211_is_data(fc) ||
-           !tx_info_priv->update_rc)
-               goto exit;
+           !(tx_info->pad[0] & ATH_TX_INFO_UPDATE_RC))
+               return;
 
-       if (tx_info_priv->tx.ts_status & ATH9K_TXERR_FILT)
-               goto exit;
+       if (tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED)
+               return;
 
        /*
         * If underrun error is seen assume it as an excessive retry only
@@ -1325,20 +1329,17 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,
         * Adjust the long retry as if the frame was tried hw->max_rate_tries
         * times. This affects how ratectrl updates PER for the failed rate.
         */
-       if (tx_info_priv->tx.ts_flags &
-           (ATH9K_TX_DATA_UNDERRUN | ATH9K_TX_DELIM_UNDERRUN) &&
-           ((sc->sc_ah->tx_trig_level) >= ath_rc_priv->tx_triglevel_max)) {
+       if ((tx_info->pad[0] & ATH_TX_INFO_UNDERRUN) &&
+           (sc->sc_ah->tx_trig_level >= ath_rc_priv->tx_triglevel_max)) {
                tx_status = 1;
                is_underrun = 1;
        }
 
-       if ((tx_info_priv->tx.ts_status & ATH9K_TXERR_XRETRY) ||
-           (tx_info_priv->tx.ts_status & ATH9K_TXERR_FIFO))
+       if (tx_info->pad[0] & ATH_TX_INFO_XRETRY)
                tx_status = 1;
 
        ath_rc_tx_status(sc, ath_rc_priv, tx_info, final_ts_idx, tx_status,
-                        (is_underrun) ? sc->hw->max_rate_tries :
-                        tx_info_priv->tx.ts_longretry);
+                        (is_underrun) ? sc->hw->max_rate_tries : long_retry);
 
        /* Check if aggregation has to be enabled for this tid */
        if (conf_is_ht(&sc->hw->conf) &&
@@ -1352,13 +1353,11 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,
                        an = (struct ath_node *)sta->drv_priv;
 
                        if(ath_tx_aggr_check(sc, an, tid))
-                               ieee80211_start_tx_ba_session(sc->hw, hdr->addr1, tid);
+                               ieee80211_start_tx_ba_session(sta, tid);
                }
        }
 
        ath_debug_stat_rc(sc, skb);
-exit:
-       kfree(tx_info_priv);
 }
 
 static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband,
index 94cb9f8..51f85ec 100644 (file)
@@ -167,24 +167,18 @@ struct ath_rate_priv {
        struct ath_rate_softc *asc;
 };
 
+#define ATH_TX_INFO_FRAME_TYPE_INTERNAL        (1 << 0)
+#define ATH_TX_INFO_FRAME_TYPE_PAUSE   (1 << 1)
+#define ATH_TX_INFO_UPDATE_RC          (1 << 2)
+#define ATH_TX_INFO_XRETRY             (1 << 3)
+#define ATH_TX_INFO_UNDERRUN           (1 << 4)
+
 enum ath9k_internal_frame_type {
        ATH9K_NOT_INTERNAL,
        ATH9K_INT_PAUSE,
        ATH9K_INT_UNPAUSE
 };
 
-struct ath_tx_info_priv {
-       struct ath_wiphy *aphy;
-       struct ath_tx_status tx;
-       int n_frames;
-       int n_bad_frames;
-       bool update_rc;
-       enum ath9k_internal_frame_type frame_type;
-};
-
-#define ATH_TX_INFO_PRIV(tx_info) \
-       ((struct ath_tx_info_priv *)((tx_info)->rate_driver_data[0]))
-
 void ath_rate_attach(struct ath_softc *sc);
 u8 ath_rate_findrateix(struct ath_softc *sc, u8 dot11_rate);
 int ath_rate_control_register(void);
index 0a36b57..cd26caa 100644 (file)
@@ -338,13 +338,11 @@ void ath9k_wiphy_chan_work(struct work_struct *work)
 void ath9k_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
        struct ath_wiphy *aphy = hw->priv;
-       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
-       struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
 
-       if (tx_info_priv && tx_info_priv->frame_type == ATH9K_INT_PAUSE &&
+       if ((tx_info->pad[0] & ATH_TX_INFO_FRAME_TYPE_PAUSE) &&
            aphy->state == ATH_WIPHY_PAUSING) {
-               if (!(info->flags & IEEE80211_TX_STAT_ACK)) {
+               if (!(tx_info->flags & IEEE80211_TX_STAT_ACK)) {
                        printk(KERN_DEBUG "ath9k: %s: no ACK for pause "
                               "frame\n", wiphy_name(hw->wiphy));
                        /*
@@ -363,9 +361,6 @@ void ath9k_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
                }
        }
 
-       kfree(tx_info_priv);
-       tx_info->rate_driver_data[0] = NULL;
-
        dev_kfree_skb(skb);
 }
 
index 86b54dd..745d919 100644 (file)
@@ -251,6 +251,7 @@ static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf)
 
        ATH_TXBUF_RESET(tbf);
 
+       tbf->aphy = bf->aphy;
        tbf->bf_mpdu = bf->bf_mpdu;
        tbf->bf_buf_addr = bf->bf_buf_addr;
        *(tbf->bf_desc) = *(bf->bf_desc);
@@ -270,7 +271,6 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
        struct ieee80211_hw *hw;
        struct ieee80211_hdr *hdr;
        struct ieee80211_tx_info *tx_info;
-       struct ath_tx_info_priv *tx_info_priv;
        struct ath_atx_tid *tid = NULL;
        struct ath_buf *bf_next, *bf_last = bf->bf_lastbf;
        struct ath_desc *ds = bf_last->bf_desc;
@@ -284,8 +284,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
        hdr = (struct ieee80211_hdr *)skb->data;
 
        tx_info = IEEE80211_SKB_CB(skb);
-       tx_info_priv = (struct ath_tx_info_priv *) tx_info->rate_driver_data[0];
-       hw = tx_info_priv->aphy->hw;
+       hw = bf->aphy->hw;
 
        rcu_read_lock();
 
@@ -464,7 +463,6 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
        struct sk_buff *skb;
        struct ieee80211_tx_info *tx_info;
        struct ieee80211_tx_rate *rates;
-       struct ath_tx_info_priv *tx_info_priv;
        u32 max_4ms_framelen, frmlen;
        u16 aggr_limit, legacy = 0;
        int i;
@@ -472,7 +470,6 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
        skb = bf->bf_mpdu;
        tx_info = IEEE80211_SKB_CB(skb);
        rates = tx_info->control.rates;
-       tx_info_priv = (struct ath_tx_info_priv *)tx_info->rate_driver_data[0];
 
        /*
         * Find the lowest frame length among the rate series that will have a
@@ -702,7 +699,6 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
                /* anchor last desc of aggregate */
                ath9k_hw_set11n_aggr_last(sc->sc_ah, bf->bf_lastbf->bf_desc);
 
-               txq->axq_aggr_depth++;
                ath_tx_txqaddbuf(sc, txq, &bf_q);
                TX_STAT_INC(txq->axq_qnum, a_aggr);
 
@@ -878,8 +874,6 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
                INIT_LIST_HEAD(&txq->axq_acq);
                spin_lock_init(&txq->axq_lock);
                txq->axq_depth = 0;
-               txq->axq_aggr_depth = 0;
-               txq->axq_linkbuf = NULL;
                txq->axq_tx_inprogress = false;
                sc->tx.txqsetup |= 1<<qnum;
        }
@@ -1014,7 +1008,6 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
 
                if (list_empty(&txq->axq_q)) {
                        txq->axq_link = NULL;
-                       txq->axq_linkbuf = NULL;
                        spin_unlock_bh(&txq->axq_lock);
                        break;
                }
@@ -1199,7 +1192,6 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
 
        list_splice_tail_init(head, &txq->axq_q);
        txq->axq_depth++;
-       txq->axq_linkbuf = list_entry(txq->axq_q.prev, struct ath_buf, list);
 
        ath_print(common, ATH_DBG_QUEUE,
                  "qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth);
@@ -1560,21 +1552,26 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,
        struct ath_softc *sc = aphy->sc;
        struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-       struct ath_tx_info_priv *tx_info_priv;
        int hdrlen;
        __le16 fc;
 
-       tx_info_priv = kzalloc(sizeof(*tx_info_priv), GFP_ATOMIC);
-       if (unlikely(!tx_info_priv))
-               return -ENOMEM;
-       tx_info->rate_driver_data[0] = tx_info_priv;
-       tx_info_priv->aphy = aphy;
-       tx_info_priv->frame_type = txctl->frame_type;
+       tx_info->pad[0] = 0;
+       switch (txctl->frame_type) {
+       case ATH9K_NOT_INTERNAL:
+               break;
+       case ATH9K_INT_PAUSE:
+               tx_info->pad[0] |= ATH_TX_INFO_FRAME_TYPE_PAUSE;
+               /* fall through */
+       case ATH9K_INT_UNPAUSE:
+               tx_info->pad[0] |= ATH_TX_INFO_FRAME_TYPE_INTERNAL;
+               break;
+       }
        hdrlen = ieee80211_get_hdrlen_from_skb(skb);
        fc = hdr->frame_control;
 
        ATH_TXBUF_RESET(bf);
 
+       bf->aphy = aphy;
        bf->bf_frmlen = skb->len + FCS_LEN - (hdrlen & 3);
 
        if (conf_is_ht(&hw->conf) && !is_pae(skb))
@@ -1599,8 +1596,6 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,
                                           skb->len, DMA_TO_DEVICE);
        if (unlikely(dma_mapping_error(sc->dev, bf->bf_dmacontext))) {
                bf->bf_mpdu = NULL;
-               kfree(tx_info_priv);
-               tx_info->rate_driver_data[0] = NULL;
                ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
                          "dma_mapping_error() on TX\n");
                return -ENOMEM;
@@ -1781,27 +1776,17 @@ exit:
 /*****************/
 
 static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
-                           int tx_flags)
+                           struct ath_wiphy *aphy, int tx_flags)
 {
        struct ieee80211_hw *hw = sc->hw;
        struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
-       struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        int hdrlen, padsize;
-       int frame_type = ATH9K_NOT_INTERNAL;
 
        ath_print(common, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb);
 
-       if (tx_info_priv) {
-               hw = tx_info_priv->aphy->hw;
-               frame_type = tx_info_priv->frame_type;
-       }
-
-       if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK ||
-           tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) {
-               kfree(tx_info_priv);
-               tx_info->rate_driver_data[0] = NULL;
-       }
+       if (aphy)
+               hw = aphy->hw;
 
        if (tx_flags & ATH_TX_BAR)
                tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
@@ -1833,10 +1818,10 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
                                        SC_OP_WAIT_FOR_TX_ACK));
        }
 
-       if (frame_type == ATH9K_NOT_INTERNAL)
-               ieee80211_tx_status(hw, skb);
-       else
+       if (unlikely(tx_info->pad[0] & ATH_TX_INFO_FRAME_TYPE_INTERNAL))
                ath9k_tx_status(hw, skb);
+       else
+               ieee80211_tx_status(hw, skb);
 }
 
 static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
@@ -1859,7 +1844,7 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
        }
 
        dma_unmap_single(sc->dev, bf->bf_dmacontext, skb->len, DMA_TO_DEVICE);
-       ath_tx_complete(sc, skb, tx_flags);
+       ath_tx_complete(sc, skb, bf->aphy, tx_flags);
        ath_debug_stat_tx(sc, txq, bf);
 
        /*
@@ -1907,8 +1892,7 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds,
        struct sk_buff *skb = bf->bf_mpdu;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
        struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
-       struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
-       struct ieee80211_hw *hw = tx_info_priv->aphy->hw;
+       struct ieee80211_hw *hw = bf->aphy->hw;
        u8 i, tx_rateindex;
 
        if (txok)
@@ -1917,17 +1901,22 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds,
        tx_rateindex = ds->ds_txstat.ts_rateindex;
        WARN_ON(tx_rateindex >= hw->max_rates);
 
-       tx_info_priv->update_rc = update_rc;
+       if (update_rc)
+               tx_info->pad[0] |= ATH_TX_INFO_UPDATE_RC;
        if (ds->ds_txstat.ts_status & ATH9K_TXERR_FILT)
                tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
 
        if ((ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) == 0 &&
            (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0 && update_rc) {
                if (ieee80211_is_data(hdr->frame_control)) {
-                       memcpy(&tx_info_priv->tx, &ds->ds_txstat,
-                              sizeof(tx_info_priv->tx));
-                       tx_info_priv->n_frames = bf->bf_nframes;
-                       tx_info_priv->n_bad_frames = nbad;
+                       if (ds->ds_txstat.ts_flags &
+                           (ATH9K_TX_DATA_UNDERRUN | ATH9K_TX_DELIM_UNDERRUN))
+                               tx_info->pad[0] |= ATH_TX_INFO_UNDERRUN;
+                       if ((ds->ds_txstat.ts_status & ATH9K_TXERR_XRETRY) ||
+                           (ds->ds_txstat.ts_status & ATH9K_TXERR_FIFO))
+                               tx_info->pad[0] |= ATH_TX_INFO_XRETRY;
+                       tx_info->status.ampdu_len = bf->bf_nframes;
+                       tx_info->status.ampdu_ack_len = bf->bf_nframes - nbad;
                }
        }
 
@@ -1971,7 +1960,6 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
                spin_lock_bh(&txq->axq_lock);
                if (list_empty(&txq->axq_q)) {
                        txq->axq_link = NULL;
-                       txq->axq_linkbuf = NULL;
                        spin_unlock_bh(&txq->axq_lock);
                        break;
                }
@@ -2005,10 +1993,6 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
                        spin_unlock_bh(&txq->axq_lock);
                        break;
                }
-               if (bf->bf_desc == txq->axq_lastdsWithCTS)
-                       txq->axq_lastdsWithCTS = NULL;
-               if (ds == txq->axq_gatingds)
-                       txq->axq_gatingds = NULL;
 
                /*
                 * Remove ath_buf's of the same transmit unit from txq,
@@ -2022,9 +2006,6 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
                                &txq->axq_q, lastbf->list.prev);
 
                txq->axq_depth--;
-               if (bf_isaggr(bf))
-                       txq->axq_aggr_depth--;
-
                txok = (ds->ds_txstat.ts_status == 0);
                txq->axq_tx_inprogress = false;
                spin_unlock_bh(&txq->axq_lock);
index 077bcc1..039ac49 100644 (file)
@@ -450,7 +450,7 @@ ath_regd_init_wiphy(struct ath_regulatory *reg,
        const struct ieee80211_regdomain *regd;
 
        wiphy->reg_notifier = reg_notifier;
-       wiphy->strict_regulatory = true;
+       wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY;
 
        if (ath_is_world_regd(reg)) {
                /*
@@ -458,8 +458,7 @@ ath_regd_init_wiphy(struct ath_regulatory *reg,
                 * saved on the wiphy orig_* parameters
                 */
                regd = ath_world_regdomain(reg);
-               wiphy->custom_regulatory = true;
-               wiphy->strict_regulatory = false;
+               wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
        } else {
                /*
                 * This gets applied in the case of the absense of CRDA,
index b5cd7f5..027be27 100644 (file)
@@ -383,44 +383,160 @@ static inline
        }
 }
 
+/* Check if a DMA region fits the device constraints.
+ * Returns true, if the region is OK for usage with this device. */
+static inline bool b43_dma_address_ok(struct b43_dmaring *ring,
+                                     dma_addr_t addr, size_t size)
+{
+       switch (ring->type) {
+       case B43_DMA_30BIT:
+               if ((u64)addr + size > (1ULL << 30))
+                       return 0;
+               break;
+       case B43_DMA_32BIT:
+               if ((u64)addr + size > (1ULL << 32))
+                       return 0;
+               break;
+       case B43_DMA_64BIT:
+               /* Currently we can't have addresses beyond
+                * 64bit in the kernel. */
+               break;
+       }
+       return 1;
+}
+
+#define is_4k_aligned(addr)    (((u64)(addr) & 0x0FFFull) == 0)
+#define is_8k_aligned(addr)    (((u64)(addr) & 0x1FFFull) == 0)
+
+static void b43_unmap_and_free_ringmem(struct b43_dmaring *ring, void *base,
+                                      dma_addr_t dmaaddr, size_t size)
+{
+       ssb_dma_unmap_single(ring->dev->dev, dmaaddr, size, DMA_TO_DEVICE);
+       free_pages((unsigned long)base, get_order(size));
+}
+
+static void * __b43_get_and_map_ringmem(struct b43_dmaring *ring,
+                                       dma_addr_t *dmaaddr, size_t size,
+                                       gfp_t gfp_flags)
+{
+       void *base;
+
+       base = (void *)__get_free_pages(gfp_flags, get_order(size));
+       if (!base)
+               return NULL;
+       memset(base, 0, size);
+       *dmaaddr = ssb_dma_map_single(ring->dev->dev, base, size,
+                                     DMA_TO_DEVICE);
+       if (ssb_dma_mapping_error(ring->dev->dev, *dmaaddr)) {
+               free_pages((unsigned long)base, get_order(size));
+               return NULL;
+       }
+
+       return base;
+}
+
+static void * b43_get_and_map_ringmem(struct b43_dmaring *ring,
+                                     dma_addr_t *dmaaddr, size_t size)
+{
+       void *base;
+
+       base = __b43_get_and_map_ringmem(ring, dmaaddr, size,
+                                        GFP_KERNEL);
+       if (!base) {
+               b43err(ring->dev->wl, "Failed to allocate or map pages "
+                      "for DMA ringmemory\n");
+               return NULL;
+       }
+       if (!b43_dma_address_ok(ring, *dmaaddr, size)) {
+               /* The memory does not fit our device constraints.
+                * Retry with GFP_DMA set to get lower memory. */
+               b43_unmap_and_free_ringmem(ring, base, *dmaaddr, size);
+               base = __b43_get_and_map_ringmem(ring, dmaaddr, size,
+                                                GFP_KERNEL | GFP_DMA);
+               if (!base) {
+                       b43err(ring->dev->wl, "Failed to allocate or map pages "
+                              "in the GFP_DMA region for DMA ringmemory\n");
+                       return NULL;
+               }
+               if (!b43_dma_address_ok(ring, *dmaaddr, size)) {
+                       b43_unmap_and_free_ringmem(ring, base, *dmaaddr, size);
+                       b43err(ring->dev->wl, "Failed to allocate DMA "
+                              "ringmemory that fits device constraints\n");
+                       return NULL;
+               }
+       }
+       /* We expect the memory to be 4k aligned, at least. */
+       if (B43_WARN_ON(!is_4k_aligned(*dmaaddr))) {
+               b43_unmap_and_free_ringmem(ring, base, *dmaaddr, size);
+               return NULL;
+       }
+
+       return base;
+}
+
 static int alloc_ringmemory(struct b43_dmaring *ring)
 {
-       gfp_t flags = GFP_KERNEL;
-
-       /* The specs call for 4K buffers for 30- and 32-bit DMA with 4K
-        * alignment and 8K buffers for 64-bit DMA with 8K alignment. Testing
-        * has shown that 4K is sufficient for the latter as long as the buffer
-        * does not cross an 8K boundary.
-        *
-        * For unknown reasons - possibly a hardware error - the BCM4311 rev
-        * 02, which uses 64-bit DMA, needs the ring buffer in very low memory,
-        * which accounts for the GFP_DMA flag below.
-        *
-        * The flags here must match the flags in free_ringmemory below!
+       unsigned int required;
+       void *base;
+       dma_addr_t dmaaddr;
+
+       /* There are several requirements to the descriptor ring memory:
+        * - The memory region needs to fit the address constraints for the
+        *   device (same as for frame buffers).
+        * - For 30/32bit DMA devices, the descriptor ring must be 4k aligned.
+        * - For 64bit DMA devices, the descriptor ring must be 8k aligned.
         */
+
        if (ring->type == B43_DMA_64BIT)
-               flags |= GFP_DMA;
-       ring->descbase = ssb_dma_alloc_consistent(ring->dev->dev,
-                                                 B43_DMA_RINGMEMSIZE,
-                                                 &(ring->dmabase), flags);
-       if (!ring->descbase) {
-               b43err(ring->dev->wl, "DMA ringmemory allocation failed\n");
+               required = ring->nr_slots * sizeof(struct b43_dmadesc64);
+       else
+               required = ring->nr_slots * sizeof(struct b43_dmadesc32);
+       if (B43_WARN_ON(required > 0x1000))
+               return -ENOMEM;
+
+       ring->alloc_descsize = 0x1000;
+       base = b43_get_and_map_ringmem(ring, &dmaaddr, ring->alloc_descsize);
+       if (!base)
+               return -ENOMEM;
+       ring->alloc_descbase = base;
+       ring->alloc_dmabase = dmaaddr;
+
+       if ((ring->type != B43_DMA_64BIT) || is_8k_aligned(dmaaddr)) {
+               /* We're on <=32bit DMA, or we already got 8k aligned memory.
+                * That's all we need, so we're fine. */
+               ring->descbase = base;
+               ring->dmabase = dmaaddr;
+               return 0;
+       }
+       b43_unmap_and_free_ringmem(ring, base, dmaaddr, ring->alloc_descsize);
+
+       /* Ok, we failed at the 8k alignment requirement.
+        * Try to force-align the memory region now. */
+       ring->alloc_descsize = 0x2000;
+       base = b43_get_and_map_ringmem(ring, &dmaaddr, ring->alloc_descsize);
+       if (!base)
                return -ENOMEM;
+       ring->alloc_descbase = base;
+       ring->alloc_dmabase = dmaaddr;
+
+       if (is_8k_aligned(dmaaddr)) {
+               /* We're already 8k aligned. That Ok, too. */
+               ring->descbase = base;
+               ring->dmabase = dmaaddr;
+               return 0;
        }
-       memset(ring->descbase, 0, B43_DMA_RINGMEMSIZE);
+       /* Force-align it to 8k */
+       ring->descbase = (void *)((u8 *)base + 0x1000);
+       ring->dmabase = dmaaddr + 0x1000;
+       B43_WARN_ON(!is_8k_aligned(ring->dmabase));
 
        return 0;
 }
 
 static void free_ringmemory(struct b43_dmaring *ring)
 {
-       gfp_t flags = GFP_KERNEL;
-
-       if (ring->type == B43_DMA_64BIT)
-               flags |= GFP_DMA;
-
-       ssb_dma_free_consistent(ring->dev->dev, B43_DMA_RINGMEMSIZE,
-                               ring->descbase, ring->dmabase, flags);
+       b43_unmap_and_free_ringmem(ring, ring->alloc_descbase,
+                                  ring->alloc_dmabase, ring->alloc_descsize);
 }
 
 /* Reset the RX DMA channel */
@@ -530,29 +646,14 @@ static bool b43_dma_mapping_error(struct b43_dmaring *ring,
        if (unlikely(ssb_dma_mapping_error(ring->dev->dev, addr)))
                return 1;
 
-       switch (ring->type) {
-       case B43_DMA_30BIT:
-               if ((u64)addr + buffersize > (1ULL << 30))
-                       goto address_error;
-               break;
-       case B43_DMA_32BIT:
-               if ((u64)addr + buffersize > (1ULL << 32))
-                       goto address_error;
-               break;
-       case B43_DMA_64BIT:
-               /* Currently we can't have addresses beyond
-                * 64bit in the kernel. */
-               break;
+       if (!b43_dma_address_ok(ring, addr, buffersize)) {
+               /* We can't support this address. Unmap it again. */
+               unmap_descbuffer(ring, addr, buffersize, dma_to_device);
+               return 1;
        }
 
        /* The address is OK. */
        return 0;
-
-address_error:
-       /* We can't support this address. Unmap it again. */
-       unmap_descbuffer(ring, addr, buffersize, dma_to_device);
-
-       return 1;
 }
 
 static bool b43_rx_buffer_is_poisoned(struct b43_dmaring *ring, struct sk_buff *skb)
@@ -614,6 +715,9 @@ static int setup_rx_descbuffer(struct b43_dmaring *ring,
        meta->dmaaddr = dmaaddr;
        ring->ops->fill_descriptor(ring, desc, dmaaddr,
                                   ring->rx_buffersize, 0, 0, 0);
+       ssb_dma_sync_single_for_device(ring->dev->dev,
+                                      ring->alloc_dmabase,
+                                      ring->alloc_descsize, DMA_TO_DEVICE);
 
        return 0;
 }
@@ -770,7 +874,7 @@ static void free_all_descbuffers(struct b43_dmaring *ring)
        for (i = 0; i < ring->nr_slots; i++) {
                desc = ring->ops->idx2desc(ring, i, &meta);
 
-               if (!meta->skb) {
+               if (!meta->skb || b43_dma_ptr_is_poisoned(meta->skb)) {
                        B43_WARN_ON(!ring->tx);
                        continue;
                }
@@ -822,7 +926,7 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
                                      enum b43_dmatype type)
 {
        struct b43_dmaring *ring;
-       int err;
+       int i, err;
        dma_addr_t dma_test;
 
        ring = kzalloc(sizeof(*ring), GFP_KERNEL);
@@ -837,6 +941,8 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
                             GFP_KERNEL);
        if (!ring->meta)
                goto err_kfree_ring;
+       for (i = 0; i < ring->nr_slots; i++)
+               ring->meta->skb = B43_DMA_PTR_POISON;
 
        ring->type = type;
        ring->dev = dev;
@@ -1147,11 +1253,13 @@ struct b43_dmaring *parse_cookie(struct b43_wldev *dev, u16 cookie, int *slot)
        case 0x5000:
                ring = dma->tx_ring_mcast;
                break;
-       default:
-               B43_WARN_ON(1);
        }
        *slot = (cookie & 0x0FFF);
-       B43_WARN_ON(!(ring && *slot >= 0 && *slot < ring->nr_slots));
+       if (unlikely(!ring || *slot < 0 || *slot >= ring->nr_slots)) {
+               b43dbg(dev->wl, "TX-status contains "
+                      "invalid cookie: 0x%04X\n", cookie);
+               return NULL;
+       }
 
        return ring;
 }
@@ -1246,6 +1354,9 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
        }
        /* Now transfer the whole frame. */
        wmb();
+       ssb_dma_sync_single_for_device(ring->dev->dev,
+                                      ring->alloc_dmabase,
+                                      ring->alloc_descsize, DMA_TO_DEVICE);
        ops->poke_tx(ring, next_slot(ring, slot));
        return 0;
 
@@ -1387,19 +1498,40 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
        struct b43_dmaring *ring;
        struct b43_dmadesc_generic *desc;
        struct b43_dmadesc_meta *meta;
-       int slot;
+       int slot, firstused;
        bool frame_succeed;
 
        ring = parse_cookie(dev, status->cookie, &slot);
        if (unlikely(!ring))
                return;
-
        B43_WARN_ON(!ring->tx);
+
+       /* Sanity check: TX packets are processed in-order on one ring.
+        * Check if the slot deduced from the cookie really is the first
+        * used slot. */
+       firstused = ring->current_slot - ring->used_slots + 1;
+       if (firstused < 0)
+               firstused = ring->nr_slots + firstused;
+       if (unlikely(slot != firstused)) {
+               /* This possibly is a firmware bug and will result in
+                * malfunction, memory leaks and/or stall of DMA functionality. */
+               b43dbg(dev->wl, "Out of order TX status report on DMA ring %d. "
+                      "Expected %d, but got %d\n",
+                      ring->index, firstused, slot);
+               return;
+       }
+
        ops = ring->ops;
        while (1) {
-               B43_WARN_ON(!(slot >= 0 && slot < ring->nr_slots));
+               B43_WARN_ON(slot < 0 || slot >= ring->nr_slots);
                desc = ops->idx2desc(ring, slot, &meta);
 
+               if (b43_dma_ptr_is_poisoned(meta->skb)) {
+                       b43dbg(dev->wl, "Poisoned TX slot %d (first=%d) "
+                              "on ring %d\n",
+                              slot, firstused, ring->index);
+                       break;
+               }
                if (meta->skb) {
                        struct b43_private_tx_info *priv_info =
                                b43_get_priv_tx_info(IEEE80211_SKB_CB(meta->skb));
@@ -1415,7 +1547,14 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
                if (meta->is_last_fragment) {
                        struct ieee80211_tx_info *info;
 
-                       BUG_ON(!meta->skb);
+                       if (unlikely(!meta->skb)) {
+                               /* This is a scatter-gather fragment of a frame, so
+                                * the skb pointer must not be NULL. */
+                               b43dbg(dev->wl, "TX status unexpected NULL skb "
+                                      "at slot %d (first=%d) on ring %d\n",
+                                      slot, firstused, ring->index);
+                               break;
+                       }
 
                        info = IEEE80211_SKB_CB(meta->skb);
 
@@ -1433,20 +1572,29 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
 #endif /* DEBUG */
                        ieee80211_tx_status(dev->wl->hw, meta->skb);
 
-                       /* skb is freed by ieee80211_tx_status() */
-                       meta->skb = NULL;
+                       /* skb will be freed by ieee80211_tx_status().
+                        * Poison our pointer. */
+                       meta->skb = B43_DMA_PTR_POISON;
                } else {
                        /* No need to call free_descriptor_buffer here, as
                         * this is only the txhdr, which is not allocated.
                         */
-                       B43_WARN_ON(meta->skb);
+                       if (unlikely(meta->skb)) {
+                               b43dbg(dev->wl, "TX status unexpected non-NULL skb "
+                                      "at slot %d (first=%d) on ring %d\n",
+                                      slot, firstused, ring->index);
+                               break;
+                       }
                }
 
                /* Everything unmapped and free'd. So it's not used anymore. */
                ring->used_slots--;
 
-               if (meta->is_last_fragment)
+               if (meta->is_last_fragment) {
+                       /* This is the last scatter-gather
+                        * fragment of the frame. We are done. */
                        break;
+               }
                slot = next_slot(ring, slot);
        }
        if (ring->stopped) {
index f0b0838..e607b39 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef B43_DMA_H_
 #define B43_DMA_H_
 
-#include <linux/ieee80211.h>
+#include <linux/err.h>
 
 #include "b43.h"
 
@@ -157,7 +157,6 @@ struct b43_dmadesc_generic {
 } __attribute__ ((__packed__));
 
 /* Misc DMA constants */
-#define B43_DMA_RINGMEMSIZE            PAGE_SIZE
 #define B43_DMA0_RX_FRAMEOFFSET                30
 
 /* DMA engine tuning knobs */
@@ -165,6 +164,10 @@ struct b43_dmadesc_generic {
 #define B43_RXRING_SLOTS               64
 #define B43_DMA0_RX_BUFFERSIZE         IEEE80211_MAX_FRAME_LEN
 
+/* Pointer poison */
+#define B43_DMA_PTR_POISON             ((void *)ERR_PTR(-ENOMEM))
+#define b43_dma_ptr_is_poisoned(ptr)   (unlikely((ptr) == B43_DMA_PTR_POISON))
+
 
 struct sk_buff;
 struct b43_private;
@@ -243,6 +246,12 @@ struct b43_dmaring {
        /* The QOS priority assigned to this ring. Only used for TX rings.
         * This is the mac80211 "queue" value. */
        u8 queue_prio;
+       /* Pointers and size of the originally allocated and mapped memory
+        * region for the descriptor ring. */
+       void *alloc_descbase;
+       dma_addr_t alloc_dmabase;
+       unsigned int alloc_descsize;
+       /* Pointer to our wireless device. */
        struct b43_wldev *dev;
 #ifdef CONFIG_B43_DEBUG
        /* Maximum number of used slots. */
index b740837..6c836c8 100644 (file)
@@ -296,6 +296,33 @@ static const char *command_types[] = {
 };
 #endif
 
+#define WEXT_USECHANNELS 1
+
+static const long ipw2100_frequencies[] = {
+       2412, 2417, 2422, 2427,
+       2432, 2437, 2442, 2447,
+       2452, 2457, 2462, 2467,
+       2472, 2484
+};
+
+#define FREQ_COUNT     ARRAY_SIZE(ipw2100_frequencies)
+
+static const long ipw2100_rates_11b[] = {
+       1000000,
+       2000000,
+       5500000,
+       11000000
+};
+
+static struct ieee80211_rate ipw2100_bg_rates[] = {
+       { .bitrate = 10 },
+       { .bitrate = 20, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+       { .bitrate = 55, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+       { .bitrate = 110, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+};
+
+#define RATE_COUNT ARRAY_SIZE(ipw2100_rates_11b)
+
 /* Pre-decl until we get the code solid and then we can clean it up */
 static void ipw2100_tx_send_commands(struct ipw2100_priv *priv);
 static void ipw2100_tx_send_data(struct ipw2100_priv *priv);
@@ -1141,6 +1168,7 @@ static int rf_kill_active(struct ipw2100_priv *priv)
        int i;
 
        if (!(priv->hw_features & HW_FEATURE_RFKILL)) {
+               wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, false);
                priv->status &= ~STATUS_RF_KILL_HW;
                return 0;
        }
@@ -1151,10 +1179,13 @@ static int rf_kill_active(struct ipw2100_priv *priv)
                value = (value << 1) | ((reg & IPW_BIT_GPIO_RF_KILL) ? 0 : 1);
        }
 
-       if (value == 0)
+       if (value == 0) {
+               wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, true);
                priv->status |= STATUS_RF_KILL_HW;
-       else
+       } else {
+               wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, false);
                priv->status &= ~STATUS_RF_KILL_HW;
+       }
 
        return (value == 0);
 }
@@ -1814,13 +1845,6 @@ static int ipw2100_up(struct ipw2100_priv *priv, int deferred)
        return rc;
 }
 
-/* Called by register_netdev() */
-static int ipw2100_net_init(struct net_device *dev)
-{
-       struct ipw2100_priv *priv = libipw_priv(dev);
-       return ipw2100_up(priv, 1);
-}
-
 static void ipw2100_down(struct ipw2100_priv *priv)
 {
        unsigned long flags;
@@ -1875,6 +1899,64 @@ static void ipw2100_down(struct ipw2100_priv *priv)
        netif_stop_queue(priv->net_dev);
 }
 
+/* Called by register_netdev() */
+static int ipw2100_net_init(struct net_device *dev)
+{
+       struct ipw2100_priv *priv = libipw_priv(dev);
+       const struct libipw_geo *geo = libipw_get_geo(priv->ieee);
+       struct wireless_dev *wdev = &priv->ieee->wdev;
+       int ret;
+       int i;
+
+       ret = ipw2100_up(priv, 1);
+       if (ret)
+               return ret;
+
+       memcpy(wdev->wiphy->perm_addr, priv->mac_addr, ETH_ALEN);
+
+       /* fill-out priv->ieee->bg_band */
+       if (geo->bg_channels) {
+               struct ieee80211_supported_band *bg_band = &priv->ieee->bg_band;
+
+               bg_band->band = IEEE80211_BAND_2GHZ;
+               bg_band->n_channels = geo->bg_channels;
+               bg_band->channels =
+                       kzalloc(geo->bg_channels *
+                               sizeof(struct ieee80211_channel), GFP_KERNEL);
+               /* translate geo->bg to bg_band.channels */
+               for (i = 0; i < geo->bg_channels; i++) {
+                       bg_band->channels[i].band = IEEE80211_BAND_2GHZ;
+                       bg_band->channels[i].center_freq = geo->bg[i].freq;
+                       bg_band->channels[i].hw_value = geo->bg[i].channel;
+                       bg_band->channels[i].max_power = geo->bg[i].max_power;
+                       if (geo->bg[i].flags & LIBIPW_CH_PASSIVE_ONLY)
+                               bg_band->channels[i].flags |=
+                                       IEEE80211_CHAN_PASSIVE_SCAN;
+                       if (geo->bg[i].flags & LIBIPW_CH_NO_IBSS)
+                               bg_band->channels[i].flags |=
+                                       IEEE80211_CHAN_NO_IBSS;
+                       if (geo->bg[i].flags & LIBIPW_CH_RADAR_DETECT)
+                               bg_band->channels[i].flags |=
+                                       IEEE80211_CHAN_RADAR;
+                       /* No equivalent for LIBIPW_CH_80211H_RULES,
+                          LIBIPW_CH_UNIFORM_SPREADING, or
+                          LIBIPW_CH_B_ONLY... */
+               }
+               /* point at bitrate info */
+               bg_band->bitrates = ipw2100_bg_rates;
+               bg_band->n_bitrates = RATE_COUNT;
+
+               wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = bg_band;
+       }
+
+       set_wiphy_dev(wdev->wiphy, &priv->pci_dev->dev);
+       if (wiphy_register(wdev->wiphy)) {
+               ipw2100_down(priv);
+               return -EIO;
+       }
+       return 0;
+}
+
 static void ipw2100_reset_adapter(struct work_struct *work)
 {
        struct ipw2100_priv *priv =
@@ -2090,6 +2172,7 @@ static void isr_indicate_rf_kill(struct ipw2100_priv *priv, u32 status)
                       priv->net_dev->name);
 
        /* RF_KILL is now enabled (else we wouldn't be here) */
+       wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, true);
        priv->status |= STATUS_RF_KILL_HW;
 
        /* Make sure the RF Kill check timer is running */
@@ -6029,7 +6112,7 @@ static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev,
        struct ipw2100_priv *priv;
        struct net_device *dev;
 
-       dev = alloc_ieee80211(sizeof(struct ipw2100_priv));
+       dev = alloc_ieee80211(sizeof(struct ipw2100_priv), 0);
        if (!dev)
                return NULL;
        priv = libipw_priv(dev);
@@ -6342,7 +6425,7 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
                sysfs_remove_group(&pci_dev->dev.kobj,
                                   &ipw2100_attribute_group);
 
-               free_ieee80211(dev);
+               free_ieee80211(dev, 0);
                pci_set_drvdata(pci_dev, NULL);
        }
 
@@ -6400,7 +6483,10 @@ static void __devexit ipw2100_pci_remove_one(struct pci_dev *pci_dev)
                if (dev->base_addr)
                        iounmap((void __iomem *)dev->base_addr);
 
-               free_ieee80211(dev);
+               /* wiphy_unregister needs to be here, before free_ieee80211 */
+               wiphy_unregister(priv->ieee->wdev.wiphy);
+               kfree(priv->ieee->bg_band.channels);
+               free_ieee80211(dev, 0);
        }
 
        pci_release_regions(pci_dev);
@@ -6601,26 +6687,6 @@ static void __exit ipw2100_exit(void)
 module_init(ipw2100_init);
 module_exit(ipw2100_exit);
 
-#define WEXT_USECHANNELS 1
-
-static const long ipw2100_frequencies[] = {
-       2412, 2417, 2422, 2427,
-       2432, 2437, 2442, 2447,
-       2452, 2457, 2462, 2467,
-       2472, 2484
-};
-
-#define FREQ_COUNT     ARRAY_SIZE(ipw2100_frequencies)
-
-static const long ipw2100_rates_11b[] = {
-       1000000,
-       2000000,
-       5500000,
-       11000000
-};
-
-#define RATE_COUNT ARRAY_SIZE(ipw2100_rates_11b)
-
 static int ipw2100_wx_get_name(struct net_device *dev,
                               struct iw_request_info *info,
                               union iwreq_data *wrqu, char *extra)
index 9fe0e80..c28984a 100644 (file)
@@ -109,6 +109,25 @@ static int antenna = CFG_SYS_ANTENNA_BOTH;
 static int rtap_iface = 0;     /* def: 0 -- do not create rtap interface */
 #endif
 
+static struct ieee80211_rate ipw2200_rates[] = {
+       { .bitrate = 10 },
+       { .bitrate = 20, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+       { .bitrate = 55, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+       { .bitrate = 110, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+       { .bitrate = 60 },
+       { .bitrate = 90 },
+       { .bitrate = 120 },
+       { .bitrate = 180 },
+       { .bitrate = 240 },
+       { .bitrate = 360 },
+       { .bitrate = 480 },
+       { .bitrate = 540 }
+};
+
+#define ipw2200_a_rates                (ipw2200_rates + 4)
+#define ipw2200_num_a_rates    8
+#define ipw2200_bg_rates       (ipw2200_rates + 0)
+#define ipw2200_num_bg_rates   12
 
 #ifdef CONFIG_IPW2200_QOS
 static int qos_enable = 0;
@@ -1739,10 +1758,13 @@ static DEVICE_ATTR(direct_dword, S_IWUSR | S_IRUGO,
 
 static int rf_kill_active(struct ipw_priv *priv)
 {
-       if (0 == (ipw_read32(priv, 0x30) & 0x10000))
+       if (0 == (ipw_read32(priv, 0x30) & 0x10000)) {
                priv->status |= STATUS_RF_KILL_HW;
-       else
+               wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, true);
+       } else {
                priv->status &= ~STATUS_RF_KILL_HW;
+               wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, false);
+       }
 
        return (priv->status & STATUS_RF_KILL_HW) ? 1 : 0;
 }
@@ -2025,6 +2047,7 @@ static void ipw_irq_tasklet(struct ipw_priv *priv)
        if (inta & IPW_INTA_BIT_RF_KILL_DONE) {
                IPW_DEBUG_RF_KILL("RF_KILL_DONE\n");
                priv->status |= STATUS_RF_KILL_HW;
+               wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, true);
                wake_up_interruptible(&priv->wait_command_queue);
                priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
                cancel_delayed_work(&priv->request_scan);
@@ -8660,24 +8683,6 @@ static int ipw_sw_reset(struct ipw_priv *priv, int option)
  *
  */
 
-static int ipw_wx_get_name(struct net_device *dev,
-                          struct iw_request_info *info,
-                          union iwreq_data *wrqu, char *extra)
-{
-       struct ipw_priv *priv = libipw_priv(dev);
-       mutex_lock(&priv->mutex);
-       if (priv->status & STATUS_RF_KILL_MASK)
-               strcpy(wrqu->name, "radio off");
-       else if (!(priv->status & STATUS_ASSOCIATED))
-               strcpy(wrqu->name, "unassociated");
-       else
-               snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11%c",
-                        ipw_modes[priv->assoc_request.ieee_mode]);
-       IPW_DEBUG_WX("Name: %s\n", wrqu->name);
-       mutex_unlock(&priv->mutex);
-       return 0;
-}
-
 static int ipw_set_channel(struct ipw_priv *priv, u8 channel)
 {
        if (channel == 0) {
@@ -9977,7 +9982,7 @@ static int ipw_wx_sw_reset(struct net_device *dev,
 /* Rebase the WE IOCTLs to zero for the handler array */
 #define IW_IOCTL(x) [(x)-SIOCSIWCOMMIT]
 static iw_handler ipw_wx_handlers[] = {
-       IW_IOCTL(SIOCGIWNAME) = ipw_wx_get_name,
+       IW_IOCTL(SIOCGIWNAME) = (iw_handler) cfg80211_wext_giwname,
        IW_IOCTL(SIOCSIWFREQ) = ipw_wx_set_freq,
        IW_IOCTL(SIOCGIWFREQ) = ipw_wx_get_freq,
        IW_IOCTL(SIOCSIWMODE) = ipw_wx_set_mode,
@@ -11422,16 +11427,100 @@ static void ipw_bg_down(struct work_struct *work)
 /* Called by register_netdev() */
 static int ipw_net_init(struct net_device *dev)
 {
+       int i, rc = 0;
        struct ipw_priv *priv = libipw_priv(dev);
+       const struct libipw_geo *geo = libipw_get_geo(priv->ieee);
+       struct wireless_dev *wdev = &priv->ieee->wdev;
        mutex_lock(&priv->mutex);
 
        if (ipw_up(priv)) {
-               mutex_unlock(&priv->mutex);
-               return -EIO;
+               rc = -EIO;
+               goto out;
+       }
+
+       memcpy(wdev->wiphy->perm_addr, priv->mac_addr, ETH_ALEN);
+
+       /* fill-out priv->ieee->bg_band */
+       if (geo->bg_channels) {
+               struct ieee80211_supported_band *bg_band = &priv->ieee->bg_band;
+
+               bg_band->band = IEEE80211_BAND_2GHZ;
+               bg_band->n_channels = geo->bg_channels;
+               bg_band->channels =
+                       kzalloc(geo->bg_channels *
+                               sizeof(struct ieee80211_channel), GFP_KERNEL);
+               /* translate geo->bg to bg_band.channels */
+               for (i = 0; i < geo->bg_channels; i++) {
+                       bg_band->channels[i].band = IEEE80211_BAND_2GHZ;
+                       bg_band->channels[i].center_freq = geo->bg[i].freq;
+                       bg_band->channels[i].hw_value = geo->bg[i].channel;
+                       bg_band->channels[i].max_power = geo->bg[i].max_power;
+                       if (geo->bg[i].flags & LIBIPW_CH_PASSIVE_ONLY)
+                               bg_band->channels[i].flags |=
+                                       IEEE80211_CHAN_PASSIVE_SCAN;
+                       if (geo->bg[i].flags & LIBIPW_CH_NO_IBSS)
+                               bg_band->channels[i].flags |=
+                                       IEEE80211_CHAN_NO_IBSS;
+                       if (geo->bg[i].flags & LIBIPW_CH_RADAR_DETECT)
+                               bg_band->channels[i].flags |=
+                                       IEEE80211_CHAN_RADAR;
+                       /* No equivalent for LIBIPW_CH_80211H_RULES,
+                          LIBIPW_CH_UNIFORM_SPREADING, or
+                          LIBIPW_CH_B_ONLY... */
+               }
+               /* point at bitrate info */
+               bg_band->bitrates = ipw2200_bg_rates;
+               bg_band->n_bitrates = ipw2200_num_bg_rates;
+
+               wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = bg_band;
        }
 
+       /* fill-out priv->ieee->a_band */
+       if (geo->a_channels) {
+               struct ieee80211_supported_band *a_band = &priv->ieee->a_band;
+
+               a_band->band = IEEE80211_BAND_5GHZ;
+               a_band->n_channels = geo->a_channels;
+               a_band->channels =
+                       kzalloc(geo->a_channels *
+                               sizeof(struct ieee80211_channel), GFP_KERNEL);
+               /* translate geo->bg to a_band.channels */
+               for (i = 0; i < geo->a_channels; i++) {
+                       a_band->channels[i].band = IEEE80211_BAND_2GHZ;
+                       a_band->channels[i].center_freq = geo->a[i].freq;
+                       a_band->channels[i].hw_value = geo->a[i].channel;
+                       a_band->channels[i].max_power = geo->a[i].max_power;
+                       if (geo->a[i].flags & LIBIPW_CH_PASSIVE_ONLY)
+                               a_band->channels[i].flags |=
+                                       IEEE80211_CHAN_PASSIVE_SCAN;
+                       if (geo->a[i].flags & LIBIPW_CH_NO_IBSS)
+                               a_band->channels[i].flags |=
+                                       IEEE80211_CHAN_NO_IBSS;
+                       if (geo->a[i].flags & LIBIPW_CH_RADAR_DETECT)
+                               a_band->channels[i].flags |=
+                                       IEEE80211_CHAN_RADAR;
+                       /* No equivalent for LIBIPW_CH_80211H_RULES,
+                          LIBIPW_CH_UNIFORM_SPREADING, or
+                          LIBIPW_CH_B_ONLY... */
+               }
+               /* point at bitrate info */
+               a_band->bitrates = ipw2200_a_rates;
+               a_band->n_bitrates = ipw2200_num_a_rates;
+
+               wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = a_band;
+       }
+
+       set_wiphy_dev(wdev->wiphy, &priv->pci_dev->dev);
+
+       /* With that information in place, we can now register the wiphy... */
+       if (wiphy_register(wdev->wiphy)) {
+               rc = -EIO;
+               goto out;
+       }
+
+out:
        mutex_unlock(&priv->mutex);
-       return 0;
+       return rc;
 }
 
 /* PCI driver stuff */
@@ -11562,7 +11651,7 @@ static int ipw_prom_alloc(struct ipw_priv *priv)
        if (priv->prom_net_dev)
                return -EPERM;
 
-       priv->prom_net_dev = alloc_ieee80211(sizeof(struct ipw_prom_priv));
+       priv->prom_net_dev = alloc_ieee80211(sizeof(struct ipw_prom_priv), 1);
        if (priv->prom_net_dev == NULL)
                return -ENOMEM;
 
@@ -11581,7 +11670,7 @@ static int ipw_prom_alloc(struct ipw_priv *priv)
 
        rc = register_netdev(priv->prom_net_dev);
        if (rc) {
-               free_ieee80211(priv->prom_net_dev);
+               free_ieee80211(priv->prom_net_dev, 1);
                priv->prom_net_dev = NULL;
                return rc;
        }
@@ -11595,7 +11684,7 @@ static void ipw_prom_free(struct ipw_priv *priv)
                return;
 
        unregister_netdev(priv->prom_net_dev);
-       free_ieee80211(priv->prom_net_dev);
+       free_ieee80211(priv->prom_net_dev, 1);
 
        priv->prom_net_dev = NULL;
 }
@@ -11623,7 +11712,7 @@ static int __devinit ipw_pci_probe(struct pci_dev *pdev,
        struct ipw_priv *priv;
        int i;
 
-       net_dev = alloc_ieee80211(sizeof(struct ipw_priv));
+       net_dev = alloc_ieee80211(sizeof(struct ipw_priv), 0);
        if (net_dev == NULL) {
                err = -ENOMEM;
                goto out;
@@ -11771,7 +11860,7 @@ static int __devinit ipw_pci_probe(struct pci_dev *pdev,
        pci_disable_device(pdev);
        pci_set_drvdata(pdev, NULL);
       out_free_ieee80211:
-       free_ieee80211(priv->net_dev);
+       free_ieee80211(priv->net_dev, 0);
       out:
        return err;
 }
@@ -11838,7 +11927,11 @@ static void __devexit ipw_pci_remove(struct pci_dev *pdev)
        pci_release_regions(pdev);
        pci_disable_device(pdev);
        pci_set_drvdata(pdev, NULL);
-       free_ieee80211(priv->net_dev);
+       /* wiphy_unregister needs to be here, before free_ieee80211 */
+       wiphy_unregister(priv->ieee->wdev.wiphy);
+       kfree(priv->ieee->a_band.channels);
+       kfree(priv->ieee->bg_band.channels);
+       free_ieee80211(priv->net_dev, 0);
        free_firmware();
 }
 
index 1e334ff..bf45391 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/ieee80211.h>
 
 #include <net/lib80211.h>
+#include <net/cfg80211.h>
 
 #define LIBIPW_VERSION "git-1.1.13"
 
@@ -783,12 +784,15 @@ struct libipw_geo {
 
 struct libipw_device {
        struct net_device *dev;
+       struct wireless_dev wdev;
        struct libipw_security sec;
 
        /* Bookkeeping structures */
        struct libipw_stats ieee_stats;
 
        struct libipw_geo geo;
+       struct ieee80211_supported_band bg_band;
+       struct ieee80211_supported_band a_band;
 
        /* Probe / Beacon management */
        struct list_head network_free_list;
@@ -1014,8 +1018,8 @@ static inline int libipw_is_cck_rate(u8 rate)
 }
 
 /* ieee80211.c */
-extern void free_ieee80211(struct net_device *dev);
-extern struct net_device *alloc_ieee80211(int sizeof_priv);
+extern void free_ieee80211(struct net_device *dev, int monitor);
+extern struct net_device *alloc_ieee80211(int sizeof_priv, int monitor);
 extern int libipw_change_mtu(struct net_device *dev, int new_mtu);
 
 extern void libipw_networks_age(struct libipw_device *ieee,
index eb2b608..e8a1ac5 100644 (file)
@@ -62,6 +62,9 @@ MODULE_DESCRIPTION(DRV_DESCRIPTION);
 MODULE_AUTHOR(DRV_COPYRIGHT);
 MODULE_LICENSE("GPL");
 
+struct cfg80211_ops libipw_config_ops = { };
+void *libipw_wiphy_privid = &libipw_wiphy_privid;
+
 static int libipw_networks_allocate(struct libipw_device *ieee)
 {
        if (ieee->networks)
@@ -140,7 +143,7 @@ int libipw_change_mtu(struct net_device *dev, int new_mtu)
 }
 EXPORT_SYMBOL(libipw_change_mtu);
 
-struct net_device *alloc_ieee80211(int sizeof_priv)
+struct net_device *alloc_ieee80211(int sizeof_priv, int monitor)
 {
        struct libipw_device *ieee;
        struct net_device *dev;
@@ -157,10 +160,31 @@ struct net_device *alloc_ieee80211(int sizeof_priv)
 
        ieee->dev = dev;
 
+       if (!monitor) {
+               ieee->wdev.wiphy = wiphy_new(&libipw_config_ops, 0);
+               if (!ieee->wdev.wiphy) {
+                       LIBIPW_ERROR("Unable to allocate wiphy.\n");
+                       goto failed_free_netdev;
+               }
+
+               ieee->dev->ieee80211_ptr = &ieee->wdev;
+               ieee->wdev.iftype = NL80211_IFTYPE_STATION;
+
+               /* Fill-out wiphy structure bits we know...  Not enough info
+                  here to call set_wiphy_dev or set MAC address or channel info
+                  -- have to do that in ->ndo_init... */
+               ieee->wdev.wiphy->privid = libipw_wiphy_privid;
+
+               ieee->wdev.wiphy->max_scan_ssids = 1;
+               ieee->wdev.wiphy->max_scan_ie_len = 0;
+               ieee->wdev.wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION)
+                                               | BIT(NL80211_IFTYPE_ADHOC);
+       }
+
        err = libipw_networks_allocate(ieee);
        if (err) {
                LIBIPW_ERROR("Unable to allocate beacon storage: %d\n", err);
-               goto failed_free_netdev;
+               goto failed_free_wiphy;
        }
        libipw_networks_initialize(ieee);
 
@@ -193,19 +217,27 @@ struct net_device *alloc_ieee80211(int sizeof_priv)
 
        return dev;
 
+failed_free_wiphy:
+       if (!monitor)
+               wiphy_free(ieee->wdev.wiphy);
 failed_free_netdev:
        free_netdev(dev);
 failed:
        return NULL;
 }
 
-void free_ieee80211(struct net_device *dev)
+void free_ieee80211(struct net_device *dev, int monitor)
 {
        struct libipw_device *ieee = netdev_priv(dev);
 
        lib80211_crypt_info_free(&ieee->crypt_info);
 
        libipw_networks_free(ieee);
+
+       /* free cfg80211 resources */
+       if (!monitor)
+               wiphy_free(ieee->wdev.wiphy);
+
        free_netdev(dev);
 }
 
index 8f82537..8414178 100644 (file)
@@ -173,6 +173,7 @@ struct iwl_cfg iwl1000_bgn_cfg = {
        .use_rts_for_ht = true, /* use rts/cts protection */
        .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
        .support_ct_kill_exit = true,
+       .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
 };
 
 struct iwl_cfg iwl1000_bg_cfg = {
index 2b0d65c..ecc23ec 100644 (file)
@@ -221,22 +221,13 @@ struct iwl3945_ibss_seq {
  * for use by iwl-*.c
  *
  *****************************************************************************/
-extern int iwl3945_power_init_handle(struct iwl_priv *priv);
-extern int iwl3945_eeprom_init(struct iwl_priv *priv);
 extern int iwl3945_calc_db_from_ratio(int sig_ratio);
 extern int iwl3945_calc_sig_qual(int rssi_dbm, int noise_dbm);
-extern int iwl3945_tx_queue_init(struct iwl_priv *priv,
-                            struct iwl_tx_queue *txq, int count, u32 id);
 extern void iwl3945_rx_replenish(void *data);
 extern void iwl3945_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
-extern void iwl3945_tx_queue_free(struct iwl_priv *priv, struct iwl_tx_queue *txq);
-extern int iwl3945_send_cmd_pdu(struct iwl_priv *priv, u8 id, u16 len,
-                           const void *data);
-extern int __must_check iwl3945_send_cmd(struct iwl_priv *priv,
-                                        struct iwl_host_cmd *cmd);
 extern unsigned int iwl3945_fill_beacon_frame(struct iwl_priv *priv,
                                        struct ieee80211_hdr *hdr,int left);
-extern void iwl3945_dump_nic_event_log(struct iwl_priv *priv);
+extern void iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log);
 extern void iwl3945_dump_nic_error_log(struct iwl_priv *priv);
 
 /*
index cc39424..386513b 100644 (file)
@@ -1818,8 +1818,9 @@ static u16 iwl4965_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data)
        addsta->add_immediate_ba_tid = cmd->add_immediate_ba_tid;
        addsta->remove_immediate_ba_tid = cmd->remove_immediate_ba_tid;
        addsta->add_immediate_ba_ssn = cmd->add_immediate_ba_ssn;
+       addsta->sleep_tx_count = cmd->sleep_tx_count;
        addsta->reserved1 = cpu_to_le16(0);
-       addsta->reserved2 = cpu_to_le32(0);
+       addsta->reserved2 = cpu_to_le16(0);
 
        return (u16)sizeof(struct iwl4965_addsta_cmd);
 }
@@ -1865,8 +1866,7 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv,
                info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]);
                info->status.rates[0].count = tx_resp->failure_frame + 1;
                info->flags &= ~IEEE80211_TX_CTL_AMPDU;
-               info->flags |= iwl_is_tx_success(status) ?
-                       IEEE80211_TX_STAT_ACK : 0;
+               info->flags |= iwl_tx_status_to_mac80211(status);
                iwl_hwrate_to_tx_control(priv, rate_n_flags, info);
                /* FIXME: code repetition end */
 
@@ -2021,8 +2021,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
                }
        } else {
                info->status.rates[0].count = tx_resp->failure_frame + 1;
-               info->flags |= iwl_is_tx_success(status) ?
-                                       IEEE80211_TX_STAT_ACK : 0;
+               info->flags |= iwl_tx_status_to_mac80211(status);
                iwl_hwrate_to_tx_control(priv,
                                        le32_to_cpu(tx_resp->rate_n_flags),
                                        info);
@@ -2240,6 +2239,7 @@ struct iwl_cfg iwl4965_agn_cfg = {
        .broken_powersave = true,
        .led_compensation = 61,
        .chain_noise_num_beacons = IWL4965_CAL_NUM_BEACONS,
+       .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
 };
 
 /* Module firmware */
index e23d301..e2f8615 100644 (file)
@@ -994,8 +994,7 @@ static int iwl5000_tx_status_reply_tx(struct iwl_priv *priv,
                info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]);
                info->status.rates[0].count = tx_resp->failure_frame + 1;
                info->flags &= ~IEEE80211_TX_CTL_AMPDU;
-               info->flags |= iwl_is_tx_success(status) ?
-                                       IEEE80211_TX_STAT_ACK : 0;
+               info->flags |= iwl_tx_status_to_mac80211(status);
                iwl_hwrate_to_tx_control(priv, rate_n_flags, info);
 
                /* FIXME: code repetition end */
@@ -1140,8 +1139,7 @@ static void iwl5000_rx_reply_tx(struct iwl_priv *priv,
                BUG_ON(txq_id != txq->swq_id);
 
                info->status.rates[0].count = tx_resp->failure_frame + 1;
-               info->flags |= iwl_is_tx_success(status) ?
-                                       IEEE80211_TX_STAT_ACK : 0;
+               info->flags |= iwl_tx_status_to_mac80211(status);
                iwl_hwrate_to_tx_control(priv,
                                        le32_to_cpu(tx_resp->rate_n_flags),
                                        info);
@@ -1251,6 +1249,22 @@ int  iwl5000_send_tx_power(struct iwl_priv *priv)
 
        /* half dBm need to multiply */
        tx_power_cmd.global_lmt = (s8)(2 * priv->tx_power_user_lmt);
+
+       if (priv->tx_power_lmt_in_half_dbm &&
+           priv->tx_power_lmt_in_half_dbm < tx_power_cmd.global_lmt) {
+               /*
+                * For the newer devices which using enhanced/extend tx power
+                * table in EEPROM, the format is in half dBm. driver need to
+                * convert to dBm format before report to mac80211.
+                * By doing so, there is a possibility of 1/2 dBm resolution
+                * lost. driver will perform "round-up" operation before
+                * reporting, but it will cause 1/2 dBm tx power over the
+                * regulatory limit. Perform the checking here, if the
+                * "tx_power_user_lmt" is higher than EEPROM value (in
+                * half-dBm format), lower the tx power based on EEPROM
+                */
+               tx_power_cmd.global_lmt = priv->tx_power_lmt_in_half_dbm;
+       }
        tx_power_cmd.flags = IWL50_TX_POWER_NO_CLOSED;
        tx_power_cmd.srv_chan_lmt = IWL50_TX_POWER_AUTO;
 
@@ -1584,14 +1598,15 @@ struct iwl_cfg iwl5300_agn_cfg = {
        .ht_greenfield_support = true,
        .led_compensation = 51,
        .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+       .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
 };
 
-struct iwl_cfg iwl5100_bg_cfg = {
-       .name = "5100BG",
+struct iwl_cfg iwl5100_bgn_cfg = {
+       .name = "5100BGN",
        .fw_name_pre = IWL5000_FW_PRE,
        .ucode_api_max = IWL5000_UCODE_API_MAX,
        .ucode_api_min = IWL5000_UCODE_API_MIN,
-       .sku = IWL_SKU_G,
+       .sku = IWL_SKU_G|IWL_SKU_N,
        .ops = &iwl5000_ops,
        .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
        .eeprom_ver = EEPROM_5000_EEPROM_VERSION,
@@ -1627,7 +1642,6 @@ struct iwl_cfg iwl5100_abg_cfg = {
        .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
        .set_l0s = true,
        .use_bsm = false,
-       .ht_greenfield_support = true,
        .led_compensation = 51,
        .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
 };
@@ -1653,6 +1667,7 @@ struct iwl_cfg iwl5100_agn_cfg = {
        .ht_greenfield_support = true,
        .led_compensation = 51,
        .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+       .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
 };
 
 struct iwl_cfg iwl5350_agn_cfg = {
@@ -1676,6 +1691,7 @@ struct iwl_cfg iwl5350_agn_cfg = {
        .ht_greenfield_support = true,
        .led_compensation = 51,
        .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+       .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
 };
 
 struct iwl_cfg iwl5150_agn_cfg = {
@@ -1699,6 +1715,29 @@ struct iwl_cfg iwl5150_agn_cfg = {
        .ht_greenfield_support = true,
        .led_compensation = 51,
        .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+       .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
+};
+
+struct iwl_cfg iwl5150_abg_cfg = {
+       .name = "5150ABG",
+       .fw_name_pre = IWL5150_FW_PRE,
+       .ucode_api_max = IWL5150_UCODE_API_MAX,
+       .ucode_api_min = IWL5150_UCODE_API_MIN,
+       .sku = IWL_SKU_A|IWL_SKU_G,
+       .ops = &iwl5150_ops,
+       .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+       .eeprom_ver = EEPROM_5050_EEPROM_VERSION,
+       .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION,
+       .num_of_queues = IWL50_NUM_QUEUES,
+       .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
+       .mod_params = &iwl50_mod_params,
+       .valid_tx_ant = ANT_A,
+       .valid_rx_ant = ANT_AB,
+       .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
+       .set_l0s = true,
+       .use_bsm = false,
+       .led_compensation = 51,
+       .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
 };
 
 MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX));
index f732f6d..74e5710 100644 (file)
@@ -306,6 +306,7 @@ struct iwl_cfg iwl6000i_2agn_cfg = {
        .supports_idle = true,
        .adv_thermal_throttle = true,
        .support_ct_kill_exit = true,
+       .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
 };
 
 struct iwl_cfg iwl6000i_2abg_cfg = {
@@ -394,8 +395,7 @@ struct iwl_cfg iwl6050_2agn_cfg = {
        .supports_idle = true,
        .adv_thermal_throttle = true,
        .support_ct_kill_exit = true,
-       .support_sm_ps = true,
-       .support_wimax_coexist = true,
+       .sm_ps_mode = WLAN_HT_CAP_SM_PS_DYNAMIC,
 };
 
 struct iwl_cfg iwl6050_2abg_cfg = {
@@ -425,7 +425,6 @@ struct iwl_cfg iwl6050_2abg_cfg = {
        .supports_idle = true,
        .adv_thermal_throttle = true,
        .support_ct_kill_exit = true,
-       .support_wimax_coexist = true,
 };
 
 struct iwl_cfg iwl6000_3agn_cfg = {
@@ -456,38 +455,7 @@ struct iwl_cfg iwl6000_3agn_cfg = {
        .supports_idle = true,
        .adv_thermal_throttle = true,
        .support_ct_kill_exit = true,
-};
-
-struct iwl_cfg iwl6050_3agn_cfg = {
-       .name = "6050 Series 3x3 AGN",
-       .fw_name_pre = IWL6050_FW_PRE,
-       .ucode_api_max = IWL6050_UCODE_API_MAX,
-       .ucode_api_min = IWL6050_UCODE_API_MIN,
-       .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
-       .ops = &iwl6050_ops,
-       .eeprom_size = OTP_LOW_IMAGE_SIZE,
-       .eeprom_ver = EEPROM_6050_EEPROM_VERSION,
-       .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
-       .num_of_queues = IWL50_NUM_QUEUES,
-       .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
-       .mod_params = &iwl50_mod_params,
-       .valid_tx_ant = ANT_ABC,
-       .valid_rx_ant = ANT_ABC,
-       .pll_cfg_val = 0,
-       .set_l0s = true,
-       .use_bsm = false,
-       .pa_type = IWL_PA_SYSTEM,
-       .max_ll_items = OTP_MAX_LL_ITEMS_6x50,
-       .shadow_ram_support = true,
-       .ht_greenfield_support = true,
-       .led_compensation = 51,
-       .use_rts_for_ht = true, /* use rts/cts protection */
-       .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
-       .supports_idle = true,
-       .adv_thermal_throttle = true,
-       .support_ct_kill_exit = true,
-       .support_sm_ps = true,
-       .support_wimax_coexist = true,
+       .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
 };
 
 MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX));
index 43edd8f..fe511cb 100644 (file)
@@ -301,7 +301,7 @@ static void rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv,
        if (rs_tl_get_load(lq_data, tid) > IWL_AGG_LOAD_THRESHOLD) {
                IWL_DEBUG_HT(priv, "Starting Tx agg: STA: %pM tid: %d\n",
                                sta->addr, tid);
-               ieee80211_start_tx_ba_session(priv->hw, sta->addr, tid);
+               ieee80211_start_tx_ba_session(sta, tid);
        }
 }
 
@@ -2964,16 +2964,16 @@ static void rs_add_debugfs(void *priv, void *priv_sta,
 {
        struct iwl_lq_sta *lq_sta = priv_sta;
        lq_sta->rs_sta_dbgfs_scale_table_file =
-               debugfs_create_file("rate_scale_table", 0600, dir,
+               debugfs_create_file("rate_scale_table", S_IRUSR | S_IWUSR, dir,
                                lq_sta, &rs_sta_dbgfs_scale_table_ops);
        lq_sta->rs_sta_dbgfs_stats_table_file =
-               debugfs_create_file("rate_stats_table", 0600, dir,
+               debugfs_create_file("rate_stats_table", S_IRUSR, dir,
                        lq_sta, &rs_sta_dbgfs_stats_table_ops);
        lq_sta->rs_sta_dbgfs_rate_scale_data_file =
-               debugfs_create_file("rate_scale_data", 0600, dir,
+               debugfs_create_file("rate_scale_data", S_IRUSR, dir,
                        lq_sta, &rs_sta_dbgfs_rate_scale_data_ops);
        lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file =
-               debugfs_create_u8("tx_agg_tid_enable", 0600, dir,
+               debugfs_create_u8("tx_agg_tid_enable", S_IRUSR | S_IWUSR, dir,
                &lq_sta->tx_agg_tid_en);
 
 }
index 29f7510..c96513b 100644 (file)
@@ -311,7 +311,7 @@ static void iwl_free_frame(struct iwl_priv *priv, struct iwl_frame *frame)
        list_add(&frame->list, &priv->free_frames);
 }
 
-static unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv,
+static u32 iwl_fill_beacon_frame(struct iwl_priv *priv,
                                          struct ieee80211_hdr *hdr,
                                          int left)
 {
@@ -328,34 +328,74 @@ static unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv,
        return priv->ibss_beacon->len;
 }
 
+/* Parse the beacon frame to find the TIM element and set tim_idx & tim_size */
+static void iwl_set_beacon_tim(struct iwl_priv *priv,
+               struct iwl_tx_beacon_cmd *tx_beacon_cmd,
+               u8 *beacon, u32 frame_size)
+{
+       u16 tim_idx;
+       struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)beacon;
+
+       /*
+        * The index is relative to frame start but we start looking at the
+        * variable-length part of the beacon.
+        */
+       tim_idx = mgmt->u.beacon.variable - beacon;
+
+       /* Parse variable-length elements of beacon to find WLAN_EID_TIM */
+       while ((tim_idx < (frame_size - 2)) &&
+                       (beacon[tim_idx] != WLAN_EID_TIM))
+               tim_idx += beacon[tim_idx+1] + 2;
+
+       /* If TIM field was found, set variables */
+       if ((tim_idx < (frame_size - 1)) && (beacon[tim_idx] == WLAN_EID_TIM)) {
+               tx_beacon_cmd->tim_idx = cpu_to_le16(tim_idx);
+               tx_beacon_cmd->tim_size = beacon[tim_idx+1];
+       } else
+               IWL_WARN(priv, "Unable to find TIM Element in beacon\n");
+}
+
 static unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv,
-                                      struct iwl_frame *frame, u8 rate)
+                                      struct iwl_frame *frame)
 {
        struct iwl_tx_beacon_cmd *tx_beacon_cmd;
-       unsigned int frame_size;
+       u32 frame_size;
+       u32 rate_flags;
+       u32 rate;
+       /*
+        * We have to set up the TX command, the TX Beacon command, and the
+        * beacon contents.
+        */
 
+       /* Initialize memory */
        tx_beacon_cmd = &frame->u.beacon;
        memset(tx_beacon_cmd, 0, sizeof(*tx_beacon_cmd));
 
-       tx_beacon_cmd->tx.sta_id = priv->hw_params.bcast_sta_id;
-       tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
-
+       /* Set up TX beacon contents */
        frame_size = iwl_fill_beacon_frame(priv, tx_beacon_cmd->frame,
                                sizeof(frame->u) - sizeof(*tx_beacon_cmd));
+       if (WARN_ON_ONCE(frame_size > MAX_MPDU_SIZE))
+               return 0;
 
-       BUG_ON(frame_size > MAX_MPDU_SIZE);
+       /* Set up TX command fields */
        tx_beacon_cmd->tx.len = cpu_to_le16((u16)frame_size);
+       tx_beacon_cmd->tx.sta_id = priv->hw_params.bcast_sta_id;
+       tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
+       tx_beacon_cmd->tx.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK |
+               TX_CMD_FLG_TSF_MSK | TX_CMD_FLG_STA_RATE_MSK;
 
-       if ((rate == IWL_RATE_1M_PLCP) || (rate >= IWL_RATE_2M_PLCP))
-               tx_beacon_cmd->tx.rate_n_flags =
-                       iwl_hw_set_rate_n_flags(rate, RATE_MCS_CCK_MSK);
-       else
-               tx_beacon_cmd->tx.rate_n_flags =
-                       iwl_hw_set_rate_n_flags(rate, 0);
+       /* Set up TX beacon command fields */
+       iwl_set_beacon_tim(priv, tx_beacon_cmd, (u8 *)tx_beacon_cmd->frame,
+                       frame_size);
 
-       tx_beacon_cmd->tx.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK |
-                                    TX_CMD_FLG_TSF_MSK |
-                                    TX_CMD_FLG_STA_RATE_MSK;
+       /* Set up packet rate and flags */
+       rate = iwl_rate_get_lowest_plcp(priv);
+       priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant);
+       rate_flags = iwl_ant_idx_to_flags(priv->mgmt_tx_ant);
+       if ((rate >= IWL_FIRST_CCK_RATE) && (rate <= IWL_LAST_CCK_RATE))
+               rate_flags |= RATE_MCS_CCK_MSK;
+       tx_beacon_cmd->tx.rate_n_flags = iwl_hw_set_rate_n_flags(rate,
+                       rate_flags);
 
        return sizeof(*tx_beacon_cmd) + frame_size;
 }
@@ -364,19 +404,20 @@ static int iwl_send_beacon_cmd(struct iwl_priv *priv)
        struct iwl_frame *frame;
        unsigned int frame_size;
        int rc;
-       u8 rate;
 
        frame = iwl_get_free_frame(priv);
-
        if (!frame) {
                IWL_ERR(priv, "Could not obtain free frame buffer for beacon "
                          "command.\n");
                return -ENOMEM;
        }
 
-       rate = iwl_rate_get_lowest_plcp(priv);
-
-       frame_size = iwl_hw_get_beacon_cmd(priv, frame, rate);
+       frame_size = iwl_hw_get_beacon_cmd(priv, frame);
+       if (!frame_size) {
+               IWL_ERR(priv, "Error configuring the beacon command\n");
+               iwl_free_frame(priv, frame);
+               return -EINVAL;
+       }
 
        rc = iwl_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size,
                              &frame->u.cmd[0]);
@@ -613,7 +654,7 @@ static void iwl_bg_statistics_periodic(unsigned long data)
        if (!iwl_is_ready_rf(priv))
                return;
 
-       iwl_send_statistics_request(priv, CMD_ASYNC);
+       iwl_send_statistics_request(priv, CMD_ASYNC, false);
 }
 
 static void iwl_rx_beacon_notif(struct iwl_priv *priv,
@@ -730,7 +771,7 @@ static void iwl_setup_rx_handlers(struct iwl_priv *priv)
         * statistics request from the host as well as for the periodic
         * statistics notifications (after received beacons) from the uCode.
         */
-       priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl_rx_statistics;
+       priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl_reply_statistics;
        priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl_rx_statistics;
 
        iwl_setup_spectrum_handlers(priv);
@@ -1038,7 +1079,6 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
        if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) {
                iwl_rx_handle(priv);
                priv->isr_stats.rx++;
-               iwl_leds_background(priv);
                handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX);
        }
 
@@ -1226,19 +1266,27 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
                 * 3- update RX shared data to indicate last write index.
                 * 4- send interrupt.
                 * This could lead to RX race, driver could receive RX interrupt
-                * but the shared data changes does not reflect this.
-                * this could lead to RX race, RX periodic will solve this race
+                * but the shared data changes does not reflect this;
+                * periodic interrupt will detect any dangling Rx activity.
                 */
-               iwl_write32(priv, CSR_INT_PERIODIC_REG,
+
+               /* Disable periodic interrupt; we use it as just a one-shot. */
+               iwl_write8(priv, CSR_INT_PERIODIC_REG,
                            CSR_INT_PERIODIC_DIS);
                iwl_rx_handle(priv);
-               /* Only set RX periodic if real RX is received. */
+
+               /*
+                * Enable periodic interrupt in 8 msec only if we received
+                * real RX interrupt (instead of just periodic int), to catch
+                * any dangling Rx interrupt.  If it was just the periodic
+                * interrupt, there was no dangling Rx activity, and no need
+                * to extend the periodic interrupt; one-shot is enough.
+                */
                if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX))
-                       iwl_write32(priv, CSR_INT_PERIODIC_REG,
+                       iwl_write8(priv, CSR_INT_PERIODIC_REG,
                                    CSR_INT_PERIODIC_ENA);
 
                priv->isr_stats.rx++;
-               iwl_leds_background(priv);
        }
 
        /* This "Tx" DMA channel is used only for loading uCode */
@@ -1557,7 +1605,6 @@ static int iwl_read_ucode(struct iwl_priv *priv)
        return ret;
 }
 
-#ifdef CONFIG_IWLWIFI_DEBUG
 static const char *desc_lookup_text[] = {
        "OK",
        "FAIL",
@@ -1710,10 +1757,42 @@ static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
        spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
 }
 
+/**
+ * iwl_print_last_event_logs - Dump the newest # of event log to syslog
+ */
+static void iwl_print_last_event_logs(struct iwl_priv *priv, u32 capacity,
+                                     u32 num_wraps, u32 next_entry,
+                                     u32 size, u32 mode)
+{
+       /*
+        * display the newest DEFAULT_LOG_ENTRIES entries
+        * i.e the entries just before the next ont that uCode would fill.
+        */
+       if (num_wraps) {
+               if (next_entry < size) {
+                       iwl_print_event_log(priv,
+                                       capacity - (size - next_entry),
+                                       size - next_entry, mode);
+                       iwl_print_event_log(priv, 0,
+                                   next_entry, mode);
+               } else
+                       iwl_print_event_log(priv, next_entry - size,
+                                   size, mode);
+       } else {
+               if (next_entry < size)
+                       iwl_print_event_log(priv, 0, next_entry, mode);
+               else
+                       iwl_print_event_log(priv, next_entry - size,
+                                           size, mode);
+       }
+}
+
 /* For sanity check only.  Actual size is determined by uCode, typ. 512 */
 #define MAX_EVENT_LOG_SIZE (512)
 
-void iwl_dump_nic_event_log(struct iwl_priv *priv)
+#define DEFAULT_DUMP_EVENT_LOG_ENTRIES (20)
+
+void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log)
 {
        u32 base;       /* SRAM byte address of event log header */
        u32 capacity;   /* event log capacity in # entries */
@@ -1758,19 +1837,37 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv)
                return;
        }
 
-       IWL_ERR(priv, "Start IWL Event Log Dump: display count %d, wraps %d\n",
-                       size, num_wraps);
-
-       /* if uCode has wrapped back to top of log, start at the oldest entry,
-        * i.e the next one that uCode would fill. */
-       if (num_wraps)
-               iwl_print_event_log(priv, next_entry,
-                                       capacity - next_entry, mode);
-       /* (then/else) start at top of log */
-       iwl_print_event_log(priv, 0, next_entry, mode);
+#ifdef CONFIG_IWLWIFI_DEBUG
+       if (!(iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS))
+               size = (size > DEFAULT_DUMP_EVENT_LOG_ENTRIES)
+                       ? DEFAULT_DUMP_EVENT_LOG_ENTRIES : size;
+#else
+       size = (size > DEFAULT_DUMP_EVENT_LOG_ENTRIES)
+               ? DEFAULT_DUMP_EVENT_LOG_ENTRIES : size;
+#endif
+       IWL_ERR(priv, "Start IWL Event Log Dump: display last %u entries\n",
+               size);
 
-}
+#ifdef CONFIG_IWLWIFI_DEBUG
+       if ((iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) || full_log) {
+               /*
+                * if uCode has wrapped back to top of log,
+                * start at the oldest entry,
+                * i.e the next one that uCode would fill.
+                */
+               if (num_wraps)
+                       iwl_print_event_log(priv, next_entry,
+                                           capacity - next_entry, mode);
+               /* (then/else) start at top of log */
+               iwl_print_event_log(priv, 0, next_entry, mode);
+       } else
+               iwl_print_last_event_logs(priv, capacity, num_wraps,
+                                       next_entry, size, mode);
+#else
+       iwl_print_last_event_logs(priv, capacity, num_wraps,
+                               next_entry, size, mode);
 #endif
+}
 
 /**
  * iwl_alive_start - called after REPLY_ALIVE notification received
@@ -2360,16 +2457,14 @@ static int iwl_setup_mac(struct iwl_priv *priv)
                BIT(NL80211_IFTYPE_STATION) |
                BIT(NL80211_IFTYPE_ADHOC);
 
-       hw->wiphy->custom_regulatory = true;
-
-       /* Firmware does not support this */
-       hw->wiphy->disable_beacon_hints = true;
+       hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY |
+                           WIPHY_FLAG_DISABLE_BEACON_HINTS;
 
        /*
         * For now, disable PS by default because it affects
         * RX performance significantly.
         */
-       hw->wiphy->ps_default = false;
+       hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
 
        hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX;
        /* we create the 802.11 header and a zero-length SSID element */
@@ -2523,6 +2618,10 @@ void iwl_config_ap(struct iwl_priv *priv)
                        IWL_WARN(priv, "REPLY_RXON_TIMING failed - "
                                        "Attempting to continue.\n");
 
+               /* AP has all antennas */
+               priv->chain_noise_data.active_chains =
+                       priv->hw_params.valid_rx_ant;
+               iwl_set_rxon_ht(priv, &priv->current_ht_config);
                if (priv->cfg->ops->hcmd->set_rxon_chain)
                        priv->cfg->ops->hcmd->set_rxon_chain(priv);
 
@@ -2551,6 +2650,7 @@ void iwl_config_ap(struct iwl_priv *priv)
                /* restore RXON assoc */
                priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
                iwlcore_commit_rxon(priv);
+               iwl_reset_qos(priv);
                spin_lock_irqsave(&priv->lock, flags);
                iwl_activate_qos(priv, 1);
                spin_unlock_irqrestore(&priv->lock, flags);
@@ -2646,6 +2746,7 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 }
 
 static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
+                               struct ieee80211_vif *vif,
                             enum ieee80211_ampdu_mlme_action action,
                             struct ieee80211_sta *sta, u16 tid, u16 *ssn)
 {
@@ -2699,6 +2800,45 @@ static int iwl_mac_get_stats(struct ieee80211_hw *hw,
        return 0;
 }
 
+static void iwl_mac_sta_notify(struct ieee80211_hw *hw,
+                              struct ieee80211_vif *vif,
+                              enum sta_notify_cmd cmd,
+                              struct ieee80211_sta *sta)
+{
+       struct iwl_priv *priv = hw->priv;
+       struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
+       int sta_id;
+
+       /*
+        * TODO: We really should use this callback to
+        *       actually maintain the station table in
+        *       the device.
+        */
+
+       switch (cmd) {
+       case STA_NOTIFY_ADD:
+               atomic_set(&sta_priv->pending_frames, 0);
+               if (vif->type == NL80211_IFTYPE_AP)
+                       sta_priv->client = true;
+               break;
+       case STA_NOTIFY_SLEEP:
+               WARN_ON(!sta_priv->client);
+               sta_priv->asleep = true;
+               if (atomic_read(&sta_priv->pending_frames) > 0)
+                       ieee80211_sta_block_awake(hw, sta, true);
+               break;
+       case STA_NOTIFY_AWAKE:
+               WARN_ON(!sta_priv->client);
+               sta_priv->asleep = false;
+               sta_id = iwl_find_station(priv, sta->addr);
+               if (sta_id != IWL_INVALID_STATION)
+                       iwl_sta_modify_ps_wake(priv, sta_id);
+               break;
+       default:
+               break;
+       }
+}
+
 /*****************************************************************************
  *
  * sysfs attributes
@@ -2893,7 +3033,7 @@ static ssize_t show_statistics(struct device *d,
                return -EAGAIN;
 
        mutex_lock(&priv->mutex);
-       rc = iwl_send_statistics_request(priv, 0);
+       rc = iwl_send_statistics_request(priv, CMD_SYNC, false);
        mutex_unlock(&priv->mutex);
 
        if (rc) {
@@ -3045,10 +3185,6 @@ static int iwl_init_drv(struct iwl_priv *priv)
        priv->band = IEEE80211_BAND_2GHZ;
 
        priv->iw_mode = NL80211_IFTYPE_STATION;
-       if (priv->cfg->support_sm_ps)
-               priv->current_ht_config.sm_ps = WLAN_HT_CAP_SM_PS_DYNAMIC;
-       else
-               priv->current_ht_config.sm_ps = WLAN_HT_CAP_SM_PS_DISABLED;
 
        /* Choose which receivers/antennas to use */
        if (priv->cfg->ops->hcmd->set_rxon_chain)
@@ -3130,7 +3266,8 @@ static struct ieee80211_ops iwl_hw_ops = {
        .reset_tsf = iwl_mac_reset_tsf,
        .bss_info_changed = iwl_bss_info_changed,
        .ampdu_action = iwl_mac_ampdu_action,
-       .hw_scan = iwl_mac_hw_scan
+       .hw_scan = iwl_mac_hw_scan,
+       .sta_notify = iwl_mac_sta_notify,
 };
 
 static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
@@ -3454,23 +3591,63 @@ static struct pci_device_id iwl_hw_card_ids[] = {
        {IWL_PCI_DEVICE(0x4230, PCI_ANY_ID, iwl4965_agn_cfg)},
 #endif /* CONFIG_IWL4965 */
 #ifdef CONFIG_IWL5000
-       {IWL_PCI_DEVICE(0x4232, 0x1205, iwl5100_bg_cfg)},
-       {IWL_PCI_DEVICE(0x4232, 0x1305, iwl5100_bg_cfg)},
-       {IWL_PCI_DEVICE(0x4232, 0x1206, iwl5100_abg_cfg)},
-       {IWL_PCI_DEVICE(0x4232, 0x1306, iwl5100_abg_cfg)},
-       {IWL_PCI_DEVICE(0x4232, 0x1326, iwl5100_abg_cfg)},
-       {IWL_PCI_DEVICE(0x4237, 0x1216, iwl5100_abg_cfg)},
-       {IWL_PCI_DEVICE(0x4232, PCI_ANY_ID, iwl5100_agn_cfg)},
-       {IWL_PCI_DEVICE(0x4235, PCI_ANY_ID, iwl5300_agn_cfg)},
-       {IWL_PCI_DEVICE(0x4236, PCI_ANY_ID, iwl5300_agn_cfg)},
-       {IWL_PCI_DEVICE(0x4237, PCI_ANY_ID, iwl5100_agn_cfg)},
-/* 5350 WiFi/WiMax */
-       {IWL_PCI_DEVICE(0x423A, 0x1001, iwl5350_agn_cfg)},
-       {IWL_PCI_DEVICE(0x423A, 0x1021, iwl5350_agn_cfg)},
-       {IWL_PCI_DEVICE(0x423B, 0x1011, iwl5350_agn_cfg)},
-/* 5150 Wifi/WiMax */
-       {IWL_PCI_DEVICE(0x423C, PCI_ANY_ID, iwl5150_agn_cfg)},
-       {IWL_PCI_DEVICE(0x423D, PCI_ANY_ID, iwl5150_agn_cfg)},
+/* 5100 Series WiFi */
+       {IWL_PCI_DEVICE(0x4232, 0x1201, iwl5100_agn_cfg)}, /* Mini Card */
+       {IWL_PCI_DEVICE(0x4232, 0x1301, iwl5100_agn_cfg)}, /* Half Mini Card */
+       {IWL_PCI_DEVICE(0x4232, 0x1204, iwl5100_agn_cfg)}, /* Mini Card */
+       {IWL_PCI_DEVICE(0x4232, 0x1304, iwl5100_agn_cfg)}, /* Half Mini Card */
+       {IWL_PCI_DEVICE(0x4232, 0x1205, iwl5100_bgn_cfg)}, /* Mini Card */
+       {IWL_PCI_DEVICE(0x4232, 0x1305, iwl5100_bgn_cfg)}, /* Half Mini Card */
+       {IWL_PCI_DEVICE(0x4232, 0x1206, iwl5100_abg_cfg)}, /* Mini Card */
+       {IWL_PCI_DEVICE(0x4232, 0x1306, iwl5100_abg_cfg)}, /* Half Mini Card */
+       {IWL_PCI_DEVICE(0x4232, 0x1221, iwl5100_agn_cfg)}, /* Mini Card */
+       {IWL_PCI_DEVICE(0x4232, 0x1321, iwl5100_agn_cfg)}, /* Half Mini Card */
+       {IWL_PCI_DEVICE(0x4232, 0x1224, iwl5100_agn_cfg)}, /* Mini Card */
+       {IWL_PCI_DEVICE(0x4232, 0x1324, iwl5100_agn_cfg)}, /* Half Mini Card */
+       {IWL_PCI_DEVICE(0x4232, 0x1225, iwl5100_bgn_cfg)}, /* Mini Card */
+       {IWL_PCI_DEVICE(0x4232, 0x1325, iwl5100_bgn_cfg)}, /* Half Mini Card */
+       {IWL_PCI_DEVICE(0x4232, 0x1226, iwl5100_abg_cfg)}, /* Mini Card */
+       {IWL_PCI_DEVICE(0x4232, 0x1326, iwl5100_abg_cfg)}, /* Half Mini Card */
+       {IWL_PCI_DEVICE(0x4237, 0x1211, iwl5100_agn_cfg)}, /* Mini Card */
+       {IWL_PCI_DEVICE(0x4237, 0x1311, iwl5100_agn_cfg)}, /* Half Mini Card */
+       {IWL_PCI_DEVICE(0x4237, 0x1214, iwl5100_agn_cfg)}, /* Mini Card */
+       {IWL_PCI_DEVICE(0x4237, 0x1314, iwl5100_agn_cfg)}, /* Half Mini Card */
+       {IWL_PCI_DEVICE(0x4237, 0x1215, iwl5100_bgn_cfg)}, /* Mini Card */
+       {IWL_PCI_DEVICE(0x4237, 0x1315, iwl5100_bgn_cfg)}, /* Half Mini Card */
+       {IWL_PCI_DEVICE(0x4237, 0x1216, iwl5100_abg_cfg)}, /* Mini Card */
+       {IWL_PCI_DEVICE(0x4237, 0x1316, iwl5100_abg_cfg)}, /* Half Mini Card */
+
+/* 5300 Series WiFi */
+       {IWL_PCI_DEVICE(0x4235, 0x1021, iwl5300_agn_cfg)}, /* Mini Card */
+       {IWL_PCI_DEVICE(0x4235, 0x1121, iwl5300_agn_cfg)}, /* Half Mini Card */
+       {IWL_PCI_DEVICE(0x4235, 0x1024, iwl5300_agn_cfg)}, /* Mini Card */
+       {IWL_PCI_DEVICE(0x4235, 0x1124, iwl5300_agn_cfg)}, /* Half Mini Card */
+       {IWL_PCI_DEVICE(0x4235, 0x1001, iwl5300_agn_cfg)}, /* Mini Card */
+       {IWL_PCI_DEVICE(0x4235, 0x1101, iwl5300_agn_cfg)}, /* Half Mini Card */
+       {IWL_PCI_DEVICE(0x4235, 0x1004, iwl5300_agn_cfg)}, /* Mini Card */
+       {IWL_PCI_DEVICE(0x4235, 0x1104, iwl5300_agn_cfg)}, /* Half Mini Card */
+       {IWL_PCI_DEVICE(0x4236, 0x1011, iwl5300_agn_cfg)}, /* Mini Card */
+       {IWL_PCI_DEVICE(0x4236, 0x1111, iwl5300_agn_cfg)}, /* Half Mini Card */
+       {IWL_PCI_DEVICE(0x4236, 0x1014, iwl5300_agn_cfg)}, /* Mini Card */
+       {IWL_PCI_DEVICE(0x4236, 0x1114, iwl5300_agn_cfg)}, /* Half Mini Card */
+
+/* 5350 Series WiFi/WiMax */
+       {IWL_PCI_DEVICE(0x423A, 0x1001, iwl5350_agn_cfg)}, /* Mini Card */
+       {IWL_PCI_DEVICE(0x423A, 0x1021, iwl5350_agn_cfg)}, /* Mini Card */
+       {IWL_PCI_DEVICE(0x423B, 0x1011, iwl5350_agn_cfg)}, /* Mini Card */
+
+/* 5150 Series Wifi/WiMax */
+       {IWL_PCI_DEVICE(0x423C, 0x1201, iwl5150_agn_cfg)}, /* Mini Card */
+       {IWL_PCI_DEVICE(0x423C, 0x1301, iwl5150_agn_cfg)}, /* Half Mini Card */
+       {IWL_PCI_DEVICE(0x423C, 0x1206, iwl5150_abg_cfg)}, /* Mini Card */
+       {IWL_PCI_DEVICE(0x423C, 0x1306, iwl5150_abg_cfg)}, /* Half Mini Card */
+       {IWL_PCI_DEVICE(0x423C, 0x1221, iwl5150_agn_cfg)}, /* Mini Card */
+       {IWL_PCI_DEVICE(0x423C, 0x1321, iwl5150_agn_cfg)}, /* Half Mini Card */
+
+       {IWL_PCI_DEVICE(0x423D, 0x1211, iwl5150_agn_cfg)}, /* Mini Card */
+       {IWL_PCI_DEVICE(0x423D, 0x1311, iwl5150_agn_cfg)}, /* Half Mini Card */
+       {IWL_PCI_DEVICE(0x423D, 0x1216, iwl5150_abg_cfg)}, /* Mini Card */
+       {IWL_PCI_DEVICE(0x423D, 0x1316, iwl5150_abg_cfg)}, /* Half Mini Card */
 
 /* 6x00 Series */
        {IWL_PCI_DEVICE(0x422B, 0x1101, iwl6000_3agn_cfg)},
@@ -3485,13 +3662,10 @@ static struct pci_device_id iwl_hw_card_ids[] = {
        {IWL_PCI_DEVICE(0x4239, 0x1316, iwl6000i_2abg_cfg)},
 
 /* 6x50 WiFi/WiMax Series */
-       {IWL_PCI_DEVICE(0x0086, 0x1101, iwl6050_3agn_cfg)},
-       {IWL_PCI_DEVICE(0x0086, 0x1121, iwl6050_3agn_cfg)},
        {IWL_PCI_DEVICE(0x0087, 0x1301, iwl6050_2agn_cfg)},
        {IWL_PCI_DEVICE(0x0087, 0x1306, iwl6050_2abg_cfg)},
        {IWL_PCI_DEVICE(0x0087, 0x1321, iwl6050_2agn_cfg)},
        {IWL_PCI_DEVICE(0x0087, 0x1326, iwl6050_2abg_cfg)},
-       {IWL_PCI_DEVICE(0x0088, 0x1111, iwl6050_3agn_cfg)},
        {IWL_PCI_DEVICE(0x0089, 0x1311, iwl6050_2agn_cfg)},
        {IWL_PCI_DEVICE(0x0089, 0x1316, iwl6050_2abg_cfg)},
 
index d994de7..95a57b3 100644 (file)
@@ -900,7 +900,7 @@ void iwl_reset_run_time_calib(struct iwl_priv *priv)
 
        /* Ask for statistics now, the uCode will send notification
         * periodically after association */
-       iwl_send_statistics_request(priv, CMD_ASYNC);
+       iwl_send_statistics_request(priv, CMD_ASYNC, true);
 }
 EXPORT_SYMBOL(iwl_reset_run_time_calib);
 
index 2857287..e915075 100644 (file)
@@ -977,6 +977,7 @@ struct iwl_qosparam_cmd {
 #define        STA_MODIFY_TX_RATE_MSK          0x04
 #define STA_MODIFY_ADDBA_TID_MSK       0x08
 #define STA_MODIFY_DELBA_TID_MSK       0x10
+#define STA_MODIFY_SLEEP_TX_COUNT_MSK  0x20
 
 /* Receiver address (actually, Rx station's index into station table),
  * combined with Traffic ID (QOS priority), in format used by Tx Scheduler */
@@ -1107,7 +1108,14 @@ struct iwl4965_addsta_cmd {
         * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */
        __le16 add_immediate_ba_ssn;
 
-       __le32 reserved2;
+       /*
+        * Number of packets OK to transmit to station even though
+        * it is asleep -- used to synchronise PS-poll and u-APSD
+        * responses while ucode keeps track of STA sleep state.
+        */
+       __le16 sleep_tx_count;
+
+       __le16 reserved2;
 } __attribute__ ((packed));
 
 /* 5000 */
@@ -1138,7 +1146,14 @@ struct iwl_addsta_cmd {
         * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */
        __le16 add_immediate_ba_ssn;
 
-       __le32 reserved2;
+       /*
+        * Number of packets OK to transmit to station even though
+        * it is asleep -- used to synchronise PS-poll and u-APSD
+        * responses while ucode keeps track of STA sleep state.
+        */
+       __le16 sleep_tx_count;
+
+       __le16 reserved2;
 } __attribute__ ((packed));
 
 
@@ -1690,6 +1705,21 @@ enum {
        TX_ABORT_REQUIRED_MSK = 0x80000000,     /* bits 31:31 */
 };
 
+static inline u32 iwl_tx_status_to_mac80211(u32 status)
+{
+       status &= TX_STATUS_MSK;
+
+       switch (status) {
+       case TX_STATUS_SUCCESS:
+       case TX_STATUS_DIRECT_DONE:
+               return IEEE80211_TX_STAT_ACK;
+       case TX_STATUS_FAIL_DEST_PS:
+               return IEEE80211_TX_STAT_TX_FILTERED;
+       default:
+               return 0;
+       }
+}
+
 static inline bool iwl_is_tx_success(u32 status)
 {
        status &= TX_STATUS_MSK;
@@ -3071,6 +3101,10 @@ struct statistics_general {
        __le32 reserved3;
 } __attribute__ ((packed));
 
+#define UCODE_STATISTICS_CLEAR_MSK             (0x1 << 0)
+#define UCODE_STATISTICS_FREQUENCY_MSK         (0x1 << 1)
+#define UCODE_STATISTICS_NARROW_BAND_MSK       (0x1 << 2)
+
 /*
  * REPLY_STATISTICS_CMD = 0x9c,
  * 3945 and 4965 identical.
index 6b18aab..574d366 100644 (file)
@@ -209,6 +209,7 @@ u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant)
        }
        return ant;
 }
+EXPORT_SYMBOL(iwl_toggle_tx_ant);
 
 const u8 iwl_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
 EXPORT_SYMBOL(iwl_bcast_addr);
@@ -255,7 +256,10 @@ int iwl_hw_nic_init(struct iwl_priv *priv)
        /* nic_init */
        spin_lock_irqsave(&priv->lock, flags);
        priv->cfg->ops->lib->apm_ops.init(priv);
-       iwl_write32(priv, CSR_INT_COALESCING, 512 / 32);
+
+       /* Set interrupt coalescing timer to 512 usecs */
+       iwl_write8(priv, CSR_INT_COALESCING, 512 / 32);
+
        spin_unlock_irqrestore(&priv->lock, flags);
 
        ret = priv->cfg->ops->lib->apm_ops.set_pwr_src(priv, IWL_PWR_SRC_VMAIN);
@@ -446,13 +450,8 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv,
        if (priv->cfg->ht_greenfield_support)
                ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD;
        ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
-       if (priv->cfg->support_sm_ps)
-               ht_info->cap |= (IEEE80211_HT_CAP_SM_PS &
-                                    (WLAN_HT_CAP_SM_PS_DYNAMIC << 2));
-       else
-               ht_info->cap |= (IEEE80211_HT_CAP_SM_PS &
-                                    (WLAN_HT_CAP_SM_PS_DISABLED << 2));
-
+       ht_info->cap |= (IEEE80211_HT_CAP_SM_PS &
+                            (priv->cfg->sm_ps_mode << 2));
        max_bit_rate = MAX_BIT_RATE_20_MHZ;
        if (priv->hw_params.ht40_channel & BIT(band)) {
                ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
@@ -1007,25 +1006,23 @@ static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt)
        int idle_cnt = active_cnt;
        bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status);
 
-       if (priv->cfg->support_sm_ps) {
-               /* # Rx chains when idling and maybe trying to save power */
-               switch (priv->current_ht_config.sm_ps) {
-               case WLAN_HT_CAP_SM_PS_STATIC:
-               case WLAN_HT_CAP_SM_PS_DYNAMIC:
-                       idle_cnt = (is_cam) ? IWL_NUM_IDLE_CHAINS_DUAL :
-                               IWL_NUM_IDLE_CHAINS_SINGLE;
-                       break;
-               case WLAN_HT_CAP_SM_PS_DISABLED:
-                       idle_cnt = (is_cam) ? active_cnt :
-                               IWL_NUM_IDLE_CHAINS_SINGLE;
-                       break;
-               case WLAN_HT_CAP_SM_PS_INVALID:
-               default:
-                       IWL_ERR(priv, "invalid sm_ps mode %d\n",
-                               priv->current_ht_config.sm_ps);
-                       WARN_ON(1);
-                       break;
-               }
+       /* # Rx chains when idling and maybe trying to save power */
+       switch (priv->cfg->sm_ps_mode) {
+       case WLAN_HT_CAP_SM_PS_STATIC:
+               idle_cnt = (is_cam) ? active_cnt : IWL_NUM_IDLE_CHAINS_SINGLE;
+               break;
+       case WLAN_HT_CAP_SM_PS_DYNAMIC:
+               idle_cnt = (is_cam) ? IWL_NUM_IDLE_CHAINS_DUAL :
+                       IWL_NUM_IDLE_CHAINS_SINGLE;
+               break;
+       case WLAN_HT_CAP_SM_PS_DISABLED:
+               break;
+       case WLAN_HT_CAP_SM_PS_INVALID:
+       default:
+               IWL_ERR(priv, "invalid sm_ps mode %u\n",
+                       priv->cfg->sm_ps_mode);
+               WARN_ON(1);
+               break;
        }
        return idle_cnt;
 }
@@ -1365,12 +1362,11 @@ void iwl_irq_handle_error(struct iwl_priv *priv)
        /* Cancel currently queued command. */
        clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
 
+       priv->cfg->ops->lib->dump_nic_error_log(priv);
+       priv->cfg->ops->lib->dump_nic_event_log(priv, false);
 #ifdef CONFIG_IWLWIFI_DEBUG
-       if (iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) {
-               priv->cfg->ops->lib->dump_nic_error_log(priv);
-               priv->cfg->ops->lib->dump_nic_event_log(priv);
+       if (iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS)
                iwl_print_rx_config_cmd(priv);
-       }
 #endif
 
        wake_up_interruptible(&priv->wait_command_queue);
@@ -1991,16 +1987,21 @@ int iwl_send_bt_config(struct iwl_priv *priv)
 }
 EXPORT_SYMBOL(iwl_send_bt_config);
 
-int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags)
+int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags, bool clear)
 {
-       u32 stat_flags = 0;
-       struct iwl_host_cmd cmd = {
-               .id = REPLY_STATISTICS_CMD,
-               .flags = flags,
-               .len = sizeof(stat_flags),
-               .data = (u8 *) &stat_flags,
+       struct iwl_statistics_cmd statistics_cmd = {
+               .configuration_flags =
+                       clear ? IWL_STATS_CONF_CLEAR_STATS : 0,
        };
-       return iwl_send_cmd(priv, &cmd);
+
+       if (flags & CMD_ASYNC)
+               return iwl_send_cmd_pdu_async(priv, REPLY_STATISTICS_CMD,
+                                              sizeof(struct iwl_statistics_cmd),
+                                              &statistics_cmd, NULL);
+       else
+               return iwl_send_cmd_pdu(priv, REPLY_STATISTICS_CMD,
+                                       sizeof(struct iwl_statistics_cmd),
+                                       &statistics_cmd);
 }
 EXPORT_SYMBOL(iwl_send_statistics_request);
 
@@ -2477,6 +2478,16 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
                } else {
                        priv->assoc_id = 0;
                        iwl_led_disassociate(priv);
+
+                       /*
+                        * inform the ucode that there is no longer an
+                        * association and that no more packets should be
+                        * send
+                        */
+                       priv->staging_rxon.filter_flags &=
+                               ~RXON_FILTER_ASSOC_MSK;
+                       priv->staging_rxon.assoc_id = 0;
+                       iwlcore_commit_rxon(priv);
                }
        }
 
@@ -2492,6 +2503,14 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
                }
        }
 
+       if ((changes & BSS_CHANGED_BEACON_ENABLED) &&
+           vif->bss_conf.enable_beacon) {
+               memcpy(priv->staging_rxon.bssid_addr,
+                      bss_conf->bssid, ETH_ALEN);
+               memcpy(priv->bssid, bss_conf->bssid, ETH_ALEN);
+               iwlcore_config_ap(priv);
+       }
+
        mutex_unlock(&priv->mutex);
 
        IWL_DEBUG_MAC80211(priv, "leave\n");
@@ -3070,15 +3089,11 @@ const char *get_ctrl_string(int cmd)
        }
 }
 
-void iwl_clear_tx_stats(struct iwl_priv *priv)
+void iwl_clear_traffic_stats(struct iwl_priv *priv)
 {
        memset(&priv->tx_stats, 0, sizeof(struct traffic_stats));
-
-}
-
-void iwl_clear_rx_stats(struct iwl_priv *priv)
-{
        memset(&priv->rx_stats, 0, sizeof(struct traffic_stats));
+       priv->led_tpt = 0;
 }
 
 /*
@@ -3171,6 +3186,7 @@ void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, u16 len)
                stats->data_cnt++;
                stats->data_bytes += len;
        }
+       iwl_leds_background(priv);
 }
 EXPORT_SYMBOL(iwl_update_stats);
 #endif
index 3f97036..cf7d3df 100644 (file)
@@ -167,7 +167,7 @@ struct iwl_lib_ops {
        int (*is_valid_rtc_data_addr)(u32 addr);
        /* 1st ucode load */
        int (*load_ucode)(struct iwl_priv *priv);
-       void (*dump_nic_event_log)(struct iwl_priv *priv);
+       void (*dump_nic_event_log)(struct iwl_priv *priv, bool full_log);
        void (*dump_nic_error_log)(struct iwl_priv *priv);
        int (*set_channel_switch)(struct iwl_priv *priv, u16 channel);
        /* power management */
@@ -228,7 +228,7 @@ struct iwl_mod_params {
  * @chain_noise_num_beacons: number of beacons used to compute chain noise
  * @adv_thermal_throttle: support advance thermal throttle
  * @support_ct_kill_exit: support ct kill exit condition
- * @support_sm_ps: support spatial multiplexing power save
+ * @sm_ps_mode: spatial multiplexing power save mode
  * @support_wimax_coexist: support wimax/wifi co-exist
  *
  * We enable the driver to be backward compatible wrt API version. The
@@ -285,7 +285,7 @@ struct iwl_cfg {
        const bool supports_idle;
        bool adv_thermal_throttle;
        bool support_ct_kill_exit;
-       bool support_sm_ps;
+       u8 sm_ps_mode;
        const bool support_wimax_coexist;
 };
 
@@ -353,8 +353,7 @@ void iwl_dbg_log_rx_data_frame(struct iwl_priv *priv,
                                u16 length, struct ieee80211_hdr *header);
 const char *get_mgmt_string(int cmd);
 const char *get_ctrl_string(int cmd);
-void iwl_clear_tx_stats(struct iwl_priv *priv);
-void iwl_clear_rx_stats(struct iwl_priv *priv);
+void iwl_clear_traffic_stats(struct iwl_priv *priv);
 void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc,
                      u16 len);
 #else
@@ -390,6 +389,7 @@ static inline void iwl_update_stats(struct iwl_priv *priv, bool is_tx,
                /* data */
                stats->data_bytes += len;
        }
+       iwl_leds_background(priv);
 }
 #endif
 /*****************************************************
@@ -425,6 +425,8 @@ void iwl_rx_missed_beacon_notif(struct iwl_priv *priv,
                               struct iwl_rx_mem_buffer *rxb);
 void iwl_rx_statistics(struct iwl_priv *priv,
                              struct iwl_rx_mem_buffer *rxb);
+void iwl_reply_statistics(struct iwl_priv *priv,
+                         struct iwl_rx_mem_buffer *rxb);
 void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb);
 
 /* TX helpers */
@@ -576,19 +578,11 @@ int iwl_pci_resume(struct pci_dev *pdev);
 /*****************************************************
 *  Error Handling Debugging
 ******************************************************/
-#ifdef CONFIG_IWLWIFI_DEBUG
-void iwl_dump_nic_event_log(struct iwl_priv *priv);
 void iwl_dump_nic_error_log(struct iwl_priv *priv);
+void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log);
+#ifdef CONFIG_IWLWIFI_DEBUG
 void iwl_print_rx_config_cmd(struct iwl_priv *priv);
 #else
-static inline void iwl_dump_nic_event_log(struct iwl_priv *priv)
-{
-}
-
-static inline void iwl_dump_nic_error_log(struct iwl_priv *priv)
-{
-}
-
 static inline void iwl_print_rx_config_cmd(struct iwl_priv *priv)
 {
 }
@@ -669,7 +663,8 @@ static inline int iwl_is_ready_rf(struct iwl_priv *priv)
 
 extern void iwl_rf_kill_ct_config(struct iwl_priv *priv);
 extern int iwl_send_bt_config(struct iwl_priv *priv);
-extern int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags);
+extern int iwl_send_statistics_request(struct iwl_priv *priv,
+                                      u8 flags, bool clear);
 extern int iwl_verify_ucode(struct iwl_priv *priv);
 extern int iwl_send_lq_cmd(struct iwl_priv *priv,
                struct iwl_link_quality_cmd *lq, u8 flags);
index b6ed5a3..a7bfae0 100644 (file)
  *****************************************************************************/
 #ifndef __iwl_csr_h__
 #define __iwl_csr_h__
-/*=== CSR (control and status registers) ===*/
+/*
+ * CSR (control and status registers)
+ *
+ * CSR registers are mapped directly into PCI bus space, and are accessible
+ * whenever platform supplies power to device, even when device is in
+ * low power states due to driver-invoked device resets
+ * (e.g. CSR_RESET_REG_FLAG_SW_RESET) or uCode-driven power-saving modes.
+ *
+ * Use iwl_write32() and iwl_read32() family to access these registers;
+ * these provide simple PCI bus access, without waking up the MAC.
+ * Do not use iwl_write_direct32() family for these registers;
+ * no need to "grab nic access" via CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ.
+ * The MAC (uCode processor, etc.) does not need to be powered up for accessing
+ * the CSR registers.
+ *
+ * NOTE:  Newer devices using one-time-programmable (OTP) memory
+ *        require device to be awake in order to read this memory
+ *        via CSR_EEPROM and CSR_OTP registers
+ */
 #define CSR_BASE    (0x000)
 
 #define CSR_HW_IF_CONFIG_REG    (CSR_BASE+0x000) /* hardware interface config */
-#define CSR_INT_COALESCING     (CSR_BASE+0x004) /* accum ints, 32-usec units */
+#define CSR_INT_COALESCING      (CSR_BASE+0x004) /* accum ints, 32-usec units */
 #define CSR_INT                 (CSR_BASE+0x008) /* host interrupt status/ack */
 #define CSR_INT_MASK            (CSR_BASE+0x00c) /* host interrupt enable */
 #define CSR_FH_INT_STATUS       (CSR_BASE+0x010) /* busmaster int status/ack*/
 #define CSR_RESET               (CSR_BASE+0x020) /* busmaster enable, NMI, etc*/
 #define CSR_GP_CNTRL            (CSR_BASE+0x024)
 
+/* 2nd byte of CSR_INT_COALESCING, not accessible via iwl_write32()! */
+#define CSR_INT_PERIODIC_REG   (CSR_BASE+0x005)
+
 /*
  * Hardware revision info
  * Bit fields:
  * 31-8:  Reserved
- *  7-4:  Type of device:  0x0 = 4965, 0xd = 3945
+ *  7-4:  Type of device:  see CSR_HW_REV_TYPE_xxx definitions
  *  3-2:  Revision step:  0 = A, 1 = B, 2 = C, 3 = D
- *  1-0:  "Dash" value, as in A-1, etc.
+ *  1-0:  "Dash" (-) value, as in A-1, etc.
  *
  * NOTE:  Revision step affects calculation of CCK txpower for 4965.
+ * NOTE:  See also CSR_HW_REV_WA_REG (work-around for bug in 4965).
  */
 #define CSR_HW_REV              (CSR_BASE+0x028)
 
-/* EEPROM reads */
+/*
+ * EEPROM and OTP (one-time-programmable) memory reads
+ *
+ * NOTE:  For (newer) devices using OTP, device must be awake, initialized via
+ *        apm_ops.init() in order to read.  Older devices (3945/4965/5000)
+ *        use EEPROM and do not require this.
+ */
 #define CSR_EEPROM_REG          (CSR_BASE+0x02c)
 #define CSR_EEPROM_GP           (CSR_BASE+0x030)
 #define CSR_OTP_GP_REG         (CSR_BASE+0x034)
+
 #define CSR_GIO_REG            (CSR_BASE+0x03C)
 #define CSR_GP_UCODE_REG       (CSR_BASE+0x048)
 #define CSR_GP_DRIVER_REG      (CSR_BASE+0x050)
+
+/*
+ * UCODE-DRIVER GP (general purpose) mailbox registers.
+ * SET/CLR registers set/clear bit(s) if "1" is written.
+ */
 #define CSR_UCODE_DRV_GP1       (CSR_BASE+0x054)
 #define CSR_UCODE_DRV_GP1_SET   (CSR_BASE+0x058)
 #define CSR_UCODE_DRV_GP1_CLR   (CSR_BASE+0x05c)
 #define CSR_UCODE_DRV_GP2       (CSR_BASE+0x060)
+
 #define CSR_LED_REG             (CSR_BASE+0x094)
 #define CSR_DRAM_INT_TBL_REG   (CSR_BASE+0x0A0)
+
+/* GIO Chicken Bits (PCI Express bus link power management) */
 #define CSR_GIO_CHICKEN_BITS    (CSR_BASE+0x100)
 
-#define CSR_INT_PERIODIC_REG   (CSR_BASE+0x005)
 /* Analog phase-lock-loop configuration  */
 #define CSR_ANA_PLL_CFG         (CSR_BASE+0x20c)
+
 /*
- * Indicates hardware rev, to determine CCK backoff for txpower calculation.
+ * CSR Hardware Revision Workaround Register.  Indicates hardware rev;
+ * "step" determines CCK backoff for txpower calculation.  Used for 4965 only.
+ * See also CSR_HW_REV register.
  * Bit fields:
  *  3-2:  0 = A, 1 = B, 2 = C, 3 = D step
+ *  1-0:  "Dash" (-) value, as in C-1, etc.
  */
 #define CSR_HW_REV_WA_REG              (CSR_BASE+0x22C)
+
 #define CSR_DBG_HPET_MEM_REG           (CSR_BASE+0x240)
 #define CSR_DBG_LINK_PWR_MGMT_REG      (CSR_BASE+0x250)
 
 #define CSR39_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_A    (0x00000000)
 #define CSR39_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_B    (0x00001000)
 
-#define CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A          (0x00080000)
-#define CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM                (0x00200000)
-#define CSR_HW_IF_CONFIG_REG_BIT_NIC_READY             (0x00400000)
-#define CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE      (0x02000000)
-#define CSR_HW_IF_CONFIG_REG_PREPARE                   (0x08000000)
+#define CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A  (0x00080000)
+#define CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM        (0x00200000)
+#define CSR_HW_IF_CONFIG_REG_BIT_NIC_READY     (0x00400000) /* PCI_OWN_SEM */
+#define CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE (0x02000000) /* ME_OWN */
+#define CSR_HW_IF_CONFIG_REG_PREPARE             (0x08000000) /* WAKE_ME */
 
-#define CSR_INT_PERIODIC_DIS                   (0x00)
-#define CSR_INT_PERIODIC_ENA                   (0xFF)
+#define CSR_INT_PERIODIC_DIS                   (0x00) /* disable periodic int*/
+#define CSR_INT_PERIODIC_ENA                   (0xFF) /* 255*32 usec ~ 8 msec*/
 
 /* interrupt flags in INTA, set by uCode or hardware (e.g. dma),
  * acknowledged (reset) by host writing "1" to flagged bits. */
 #define CSR_RESET_REG_FLAG_STOP_MASTER               (0x00000200)
 #define CSR_RESET_LINK_PWR_MGMT_DISABLED             (0x80000000)
 
-/* GP (general purpose) CONTROL */
+/*
+ * GP (general purpose) CONTROL REGISTER
+ * Bit fields:
+ *    27:  HW_RF_KILL_SW
+ *         Indicates state of (platform's) hardware RF-Kill switch
+ * 26-24:  POWER_SAVE_TYPE
+ *         Indicates current power-saving mode:
+ *         000 -- No power saving
+ *         001 -- MAC power-down
+ *         010 -- PHY (radio) power-down
+ *         011 -- Error
+ *   9-6:  SYS_CONFIG
+ *         Indicates current system configuration, reflecting pins on chip
+ *         as forced high/low by device circuit board.
+ *     4:  GOING_TO_SLEEP
+ *         Indicates MAC is entering a power-saving sleep power-down.
+ *         Not a good time to access device-internal resources.
+ *     3:  MAC_ACCESS_REQ
+ *         Host sets this to request and maintain MAC wakeup, to allow host
+ *         access to device-internal resources.  Host must wait for
+ *         MAC_CLOCK_READY (and !GOING_TO_SLEEP) before accessing non-CSR
+ *         device registers.
+ *     2:  INIT_DONE
+ *         Host sets this to put device into fully operational D0 power mode.
+ *         Host resets this after SW_RESET to put device into low power mode.
+ *     0:  MAC_CLOCK_READY
+ *         Indicates MAC (ucode processor, etc.) is powered up and can run.
+ *         Internal resources are accessible.
+ *         NOTE:  This does not indicate that the processor is actually running.
+ *         NOTE:  This does not indicate that 4965 or 3945 has completed
+ *                init or post-power-down restore of internal SRAM memory.
+ *                Use CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP as indication that
+ *                SRAM is restored and uCode is in normal operation mode.
+ *                Later devices (5xxx/6xxx/1xxx) use non-volatile SRAM, and
+ *                do not need to save/restore it.
+ *         NOTE:  After device reset, this bit remains "0" until host sets
+ *                INIT_DONE
+ */
 #define CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY        (0x00000001)
 #define CSR_GP_CNTRL_REG_FLAG_INIT_DONE              (0x00000004)
 #define CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ         (0x00000008)
 #define CSR_EEPROM_REG_MSK_DATA                (0xFFFF0000)
 
 /* EEPROM GP */
-#define CSR_EEPROM_GP_VALID_MSK                (0x00000007)
+#define CSR_EEPROM_GP_VALID_MSK                (0x00000007) /* signature */
 #define CSR_EEPROM_GP_IF_OWNER_MSK     (0x00000180)
+#define CSR_EEPROM_GP_BAD_SIGNATURE_BOTH_EEP_AND_OTP   (0x00000000)
+#define CSR_EEPROM_GP_BAD_SIG_EEP_GOOD_SIG_OTP         (0x00000001)
+#define CSR_EEPROM_GP_GOOD_SIG_EEP_LESS_THAN_4K                (0x00000002)
+#define CSR_EEPROM_GP_GOOD_SIG_EEP_MORE_THAN_4K                (0x00000004)
+
+/* One-time-programmable memory general purpose reg */
 #define CSR_OTP_GP_REG_DEVICE_SELECT   (0x00010000) /* 0 - EEPROM, 1 - OTP */
 #define CSR_OTP_GP_REG_OTP_ACCESS_MODE (0x00020000) /* 0 - absolute, 1 - relative */
 #define CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK          (0x00100000) /* bit 20 */
 #define CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK        (0x00200000) /* bit 21 */
+
+/* GP REG */
 #define CSR_GP_REG_POWER_SAVE_STATUS_MSK            (0x03000000) /* bit 24/25 */
 #define CSR_GP_REG_NO_POWER_SAVE            (0x00000000)
 #define CSR_GP_REG_MAC_POWER_SAVE           (0x01000000)
 #define CSR_GP_REG_PHY_POWER_SAVE           (0x02000000)
 #define CSR_GP_REG_POWER_SAVE_ERROR         (0x03000000)
 
-/* EEPROM signature */
-#define CSR_EEPROM_GP_BAD_SIGNATURE_BOTH_EEP_AND_OTP   (0x00000000)
-#define CSR_EEPROM_GP_BAD_SIG_EEP_GOOD_SIG_OTP         (0x00000001)
-#define CSR_EEPROM_GP_GOOD_SIG_EEP_LESS_THAN_4K                (0x00000002)
-#define CSR_EEPROM_GP_GOOD_SIG_EEP_MORE_THAN_4K                (0x00000004)
 
 /* CSR GIO */
 #define CSR_GIO_REG_VAL_L0S_ENABLED    (0x00000002)
 
-/* UCODE DRV GP */
+/*
+ * UCODE-DRIVER GP (general purpose) mailbox register 1
+ * Host driver and uCode write and/or read this register to communicate with
+ * each other.
+ * Bit fields:
+ *     4:  UCODE_DISABLE
+ *         Host sets this to request permanent halt of uCode, same as
+ *         sending CARD_STATE command with "halt" bit set.
+ *     3:  CT_KILL_EXIT
+ *         Host sets this to request exit from CT_KILL state, i.e. host thinks
+ *         device temperature is low enough to continue normal operation.
+ *     2:  CMD_BLOCKED
+ *         Host sets this during RF KILL power-down sequence (HW, SW, CT KILL)
+ *         to release uCode to clear all Tx and command queues, enter
+ *         unassociated mode, and power down.
+ *         NOTE:  Some devices also use HBUS_TARG_MBX_C register for this bit.
+ *     1:  SW_BIT_RFKILL
+ *         Host sets this when issuing CARD_STATE command to request
+ *         device sleep.
+ *     0:  MAC_SLEEP
+ *         uCode sets this when preparing a power-saving power-down.
+ *         uCode resets this when power-up is complete and SRAM is sane.
+ *         NOTE:  3945/4965 saves internal SRAM data to host when powering down,
+ *                and must restore this data after powering back up.
+ *                MAC_SLEEP is the best indication that restore is complete.
+ *                Later devices (5xxx/6xxx/1xxx) use non-volatile SRAM, and
+ *                do not need to save/restore it.
+ */
 #define CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP             (0x00000001)
 #define CSR_UCODE_SW_BIT_RFKILL                     (0x00000002)
 #define CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED           (0x00000004)
 #define CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_IPA            (0x00000002)
 
 
-/* GI Chicken Bits */
+/* GIO Chicken Bits (PCI Express bus link power management) */
 #define CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX  (0x00800000)
 #define CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER  (0x20000000)
 
 #define CSR_DRAM_INT_TBL_ENABLE                (1 << 31)
 #define CSR_DRAM_INIT_TBL_WRAP_CHECK   (1 << 27)
 
-/*=== HBUS (Host-side Bus) ===*/
+/*
+ * HBUS (Host-side Bus)
+ *
+ * HBUS registers are mapped directly into PCI bus space, but are used
+ * to indirectly access device's internal memory or registers that
+ * may be powered-down.
+ *
+ * Use iwl_write_direct32()/iwl_read_direct32() family for these registers;
+ * host must "grab nic access" via CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ
+ * to make sure the MAC (uCode processor, etc.) is powered up for accessing
+ * internal resources.
+ *
+ * Do not use iwl_write32()/iwl_read32() family to access these registers;
+ * these provide only simple PCI bus access, without waking up the MAC.
+ */
 #define HBUS_BASE      (0x400)
+
 /*
  * Registers for accessing device's internal SRAM memory (e.g. SCD SRAM
  * structures, error log, event log, verifying uCode load).
 #define HBUS_TARG_MEM_WDAT      (HBUS_BASE+0x018)
 #define HBUS_TARG_MEM_RDAT      (HBUS_BASE+0x01c)
 
+/* Mailbox C, used as workaround alternative to CSR_UCODE_DRV_GP1 mailbox */
+#define HBUS_TARG_MBX_C         (HBUS_BASE+0x030)
+#define HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED         (0x00000004)
+
 /*
  * Registers for accessing device's internal peripheral registers
  * (e.g. SCD, BSM, etc.).  First write to address register,
 #define HBUS_TARG_PRPH_RDAT     (HBUS_BASE+0x050)
 
 /*
- * Per-Tx-queue write pointer (index, really!) (3945 and 4965).
+ * Per-Tx-queue write pointer (index, really!)
  * Indicates index to next TFD that driver will fill (1 past latest filled).
  * Bit usage:
  *  0-7:  queue write index
  * 11-8:  queue selector
  */
 #define HBUS_TARG_WRPTR         (HBUS_BASE+0x060)
-#define HBUS_TARG_MBX_C         (HBUS_BASE+0x030)
-
-#define HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED         (0x00000004)
-
 
 #endif /* !__iwl_csr_h__ */
index 96c92ea..d61293a 100644 (file)
@@ -107,6 +107,8 @@ struct iwl_debugfs {
                struct dentry *file_chain_noise;
                struct dentry *file_tx_power;
                struct dentry *file_power_save_status;
+               struct dentry *file_clear_ucode_statistics;
+               struct dentry *file_clear_traffic_statistics;
        } dbgfs_debug_files;
        u32 sram_offset;
        u32 sram_len;
index 8784911..21e0f66 100644 (file)
@@ -47,9 +47,9 @@
                goto err;                                               \
 } while (0)
 
-#define DEBUGFS_ADD_FILE(name, parent) do {                             \
+#define DEBUGFS_ADD_FILE(name, parent, mode) do {                       \
        dbgfs->dbgfs_##parent##_files.file_##name =                     \
-       debugfs_create_file(#name, S_IWUSR | S_IRUSR,                   \
+       debugfs_create_file(#name, mode,                                \
                                dbgfs->dir_##parent, priv,              \
                                &iwl_dbgfs_##name##_ops);               \
        if (!(dbgfs->dbgfs_##parent##_files.file_##name))               \
@@ -131,21 +131,22 @@ static ssize_t iwl_dbgfs_tx_statistics_read(struct file *file,
 
        int cnt;
        ssize_t ret;
-       const size_t bufsz = 100 + sizeof(char) * 24 * (MANAGEMENT_MAX + CONTROL_MAX);
+       const size_t bufsz = 100 +
+               sizeof(char) * 50 * (MANAGEMENT_MAX + CONTROL_MAX);
        buf = kzalloc(bufsz, GFP_KERNEL);
        if (!buf)
                return -ENOMEM;
        pos += scnprintf(buf + pos, bufsz - pos, "Management:\n");
        for (cnt = 0; cnt < MANAGEMENT_MAX; cnt++) {
                pos += scnprintf(buf + pos, bufsz - pos,
-                                "\t%s\t\t: %u\n",
+                                "\t%25s\t\t: %u\n",
                                 get_mgmt_string(cnt),
                                 priv->tx_stats.mgmt[cnt]);
        }
        pos += scnprintf(buf + pos, bufsz - pos, "Control\n");
        for (cnt = 0; cnt < CONTROL_MAX; cnt++) {
                pos += scnprintf(buf + pos, bufsz - pos,
-                                "\t%s\t\t: %u\n",
+                                "\t%25s\t\t: %u\n",
                                 get_ctrl_string(cnt),
                                 priv->tx_stats.ctrl[cnt]);
        }
@@ -159,7 +160,7 @@ static ssize_t iwl_dbgfs_tx_statistics_read(struct file *file,
        return ret;
 }
 
-static ssize_t iwl_dbgfs_tx_statistics_write(struct file *file,
+static ssize_t iwl_dbgfs_clear_traffic_statistics_write(struct file *file,
                                        const char __user *user_buf,
                                        size_t count, loff_t *ppos)
 {
@@ -174,8 +175,7 @@ static ssize_t iwl_dbgfs_tx_statistics_write(struct file *file,
                return -EFAULT;
        if (sscanf(buf, "%x", &clear_flag) != 1)
                return -EFAULT;
-       if (clear_flag == 1)
-               iwl_clear_tx_stats(priv);
+       iwl_clear_traffic_stats(priv);
 
        return count;
 }
@@ -190,7 +190,7 @@ static ssize_t iwl_dbgfs_rx_statistics_read(struct file *file,
        int cnt;
        ssize_t ret;
        const size_t bufsz = 100 +
-               sizeof(char) * 24 * (MANAGEMENT_MAX + CONTROL_MAX);
+               sizeof(char) * 50 * (MANAGEMENT_MAX + CONTROL_MAX);
        buf = kzalloc(bufsz, GFP_KERNEL);
        if (!buf)
                return -ENOMEM;
@@ -198,14 +198,14 @@ static ssize_t iwl_dbgfs_rx_statistics_read(struct file *file,
        pos += scnprintf(buf + pos, bufsz - pos, "Management:\n");
        for (cnt = 0; cnt < MANAGEMENT_MAX; cnt++) {
                pos += scnprintf(buf + pos, bufsz - pos,
-                                "\t%s\t\t: %u\n",
+                                "\t%25s\t\t: %u\n",
                                 get_mgmt_string(cnt),
                                 priv->rx_stats.mgmt[cnt]);
        }
        pos += scnprintf(buf + pos, bufsz - pos, "Control:\n");
        for (cnt = 0; cnt < CONTROL_MAX; cnt++) {
                pos += scnprintf(buf + pos, bufsz - pos,
-                                "\t%s\t\t: %u\n",
+                                "\t%25s\t\t: %u\n",
                                 get_ctrl_string(cnt),
                                 priv->rx_stats.ctrl[cnt]);
        }
@@ -220,26 +220,6 @@ static ssize_t iwl_dbgfs_rx_statistics_read(struct file *file,
        return ret;
 }
 
-static ssize_t iwl_dbgfs_rx_statistics_write(struct file *file,
-                                       const char __user *user_buf,
-                                       size_t count, loff_t *ppos)
-{
-       struct iwl_priv *priv = file->private_data;
-       u32 clear_flag;
-       char buf[8];
-       int buf_size;
-
-       memset(buf, 0, sizeof(buf));
-       buf_size = min(count, sizeof(buf) -  1);
-       if (copy_from_user(buf, user_buf, buf_size))
-               return -EFAULT;
-       if (sscanf(buf, "%x", &clear_flag) != 1)
-               return -EFAULT;
-       if (clear_flag == 1)
-               iwl_clear_rx_stats(priv);
-       return count;
-}
-
 #define BYTE1_MASK 0x000000ff;
 #define BYTE2_MASK 0x0000ffff;
 #define BYTE3_MASK 0x00ffffff;
@@ -248,13 +228,29 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file,
                                        size_t count, loff_t *ppos)
 {
        u32 val;
-       char buf[1024];
+       char *buf;
        ssize_t ret;
        int i;
        int pos = 0;
        struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
-       const size_t bufsz = sizeof(buf);
-
+       size_t bufsz;
+
+       /* default is to dump the entire data segment */
+       if (!priv->dbgfs->sram_offset && !priv->dbgfs->sram_len) {
+               priv->dbgfs->sram_offset = 0x800000;
+               if (priv->ucode_type == UCODE_INIT)
+                       priv->dbgfs->sram_len = priv->ucode_init_data.len;
+               else
+                       priv->dbgfs->sram_len = priv->ucode_data.len;
+       }
+       bufsz =  30 + priv->dbgfs->sram_len * sizeof(char) * 10;
+       buf = kmalloc(bufsz, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+       pos += scnprintf(buf + pos, bufsz - pos, "sram_len: 0x%x\n",
+                       priv->dbgfs->sram_len);
+       pos += scnprintf(buf + pos, bufsz - pos, "sram_offset: 0x%x\n",
+                       priv->dbgfs->sram_offset);
        for (i = priv->dbgfs->sram_len; i > 0; i -= 4) {
                val = iwl_read_targ_mem(priv, priv->dbgfs->sram_offset + \
                                        priv->dbgfs->sram_len - i);
@@ -271,11 +267,14 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file,
                                break;
                        }
                }
+               if (!(i % 16))
+                       pos += scnprintf(buf + pos, bufsz - pos, "\n");
                pos += scnprintf(buf + pos, bufsz - pos, "0x%08x ", val);
        }
        pos += scnprintf(buf + pos, bufsz - pos, "\n");
 
        ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+       kfree(buf);
        return ret;
 }
 
@@ -335,8 +334,6 @@ static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf,
                        pos += scnprintf(buf + pos, bufsz - pos,
                                        "flags: 0x%x\n",
                                        station->sta.station_flags_msk);
-                       pos += scnprintf(buf + pos, bufsz - pos,
-                                       "ps_status: %u\n", station->ps_status);
                        pos += scnprintf(buf + pos, bufsz - pos, "tid data:\n");
                        pos += scnprintf(buf + pos, bufsz - pos,
                                        "seq_num\t\ttxq_id");
@@ -439,7 +436,7 @@ static ssize_t iwl_dbgfs_log_event_write(struct file *file,
        if (sscanf(buf, "%d", &event_log_flag) != 1)
                return -EFAULT;
        if (event_log_flag == 1)
-               priv->cfg->ops->lib->dump_nic_event_log(priv);
+               priv->cfg->ops->lib->dump_nic_event_log(priv, true);
 
        return count;
 }
@@ -986,7 +983,7 @@ static ssize_t iwl_dbgfs_tx_queue_read(struct file *file,
        int pos = 0;
        int cnt;
        int ret;
-       const size_t bufsz = sizeof(char) * 60 * priv->cfg->num_of_queues;
+       const size_t bufsz = sizeof(char) * 64 * priv->cfg->num_of_queues;
 
        if (!priv->txq) {
                IWL_ERR(priv, "txq not ready\n");
@@ -1042,10 +1039,6 @@ static ssize_t iwl_dbgfs_rx_queue_read(struct file *file,
        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 }
 
-#define UCODE_STATISTICS_CLEAR_MSK             (0x1 << 0)
-#define UCODE_STATISTICS_FREQUENCY_MSK         (0x1 << 1)
-#define UCODE_STATISTICS_NARROW_BAND_MSK       (0x1 << 2)
-
 static int iwl_dbgfs_statistics_flag(struct iwl_priv *priv, char *buf,
                                     int bufsz)
 {
@@ -1092,7 +1085,7 @@ static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file,
 
        /* make request to uCode to retrieve statistics information */
        mutex_lock(&priv->mutex);
-       ret = iwl_send_statistics_request(priv, 0);
+       ret = iwl_send_statistics_request(priv, CMD_SYNC, false);
        mutex_unlock(&priv->mutex);
 
        if (ret) {
@@ -1398,7 +1391,7 @@ static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file,
 
        /* make request to uCode to retrieve statistics information */
        mutex_lock(&priv->mutex);
-       ret = iwl_send_statistics_request(priv, 0);
+       ret = iwl_send_statistics_request(priv, CMD_SYNC, false);
        mutex_unlock(&priv->mutex);
 
        if (ret) {
@@ -1542,7 +1535,7 @@ static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file,
 
        /* make request to uCode to retrieve statistics information */
        mutex_lock(&priv->mutex);
-       ret = iwl_send_statistics_request(priv, 0);
+       ret = iwl_send_statistics_request(priv, CMD_SYNC, false);
        mutex_unlock(&priv->mutex);
 
        if (ret) {
@@ -1770,7 +1763,7 @@ static ssize_t iwl_dbgfs_tx_power_read(struct file *file,
        else {
                /* make request to uCode to retrieve statistics information */
                mutex_lock(&priv->mutex);
-               ret = iwl_send_statistics_request(priv, 0);
+               ret = iwl_send_statistics_request(priv, CMD_SYNC, false);
                mutex_unlock(&priv->mutex);
 
                if (ret) {
@@ -1828,8 +1821,32 @@ static ssize_t iwl_dbgfs_power_save_status_read(struct file *file,
        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 }
 
-DEBUGFS_READ_WRITE_FILE_OPS(rx_statistics);
-DEBUGFS_READ_WRITE_FILE_OPS(tx_statistics);
+static ssize_t iwl_dbgfs_clear_ucode_statistics_write(struct file *file,
+                                        const char __user *user_buf,
+                                        size_t count, loff_t *ppos)
+{
+       struct iwl_priv *priv = file->private_data;
+       char buf[8];
+       int buf_size;
+       int clear;
+
+       memset(buf, 0, sizeof(buf));
+       buf_size = min(count, sizeof(buf) -  1);
+       if (copy_from_user(buf, user_buf, buf_size))
+               return -EFAULT;
+       if (sscanf(buf, "%d", &clear) != 1)
+               return -EFAULT;
+
+       /* make request to uCode to retrieve statistics information */
+       mutex_lock(&priv->mutex);
+       iwl_send_statistics_request(priv, CMD_SYNC, true);
+       mutex_unlock(&priv->mutex);
+
+       return count;
+}
+
+DEBUGFS_READ_FILE_OPS(rx_statistics);
+DEBUGFS_READ_FILE_OPS(tx_statistics);
 DEBUGFS_READ_WRITE_FILE_OPS(traffic_log);
 DEBUGFS_READ_FILE_OPS(rx_queue);
 DEBUGFS_READ_FILE_OPS(tx_queue);
@@ -1840,6 +1857,8 @@ DEBUGFS_READ_FILE_OPS(sensitivity);
 DEBUGFS_READ_FILE_OPS(chain_noise);
 DEBUGFS_READ_FILE_OPS(tx_power);
 DEBUGFS_READ_FILE_OPS(power_save_status);
+DEBUGFS_WRITE_FILE_OPS(clear_ucode_statistics);
+DEBUGFS_WRITE_FILE_OPS(clear_traffic_statistics);
 
 /*
  * Create the debugfs files and directories
@@ -1868,32 +1887,34 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
        DEBUGFS_ADD_DIR(data, dbgfs->dir_drv);
        DEBUGFS_ADD_DIR(rf, dbgfs->dir_drv);
        DEBUGFS_ADD_DIR(debug, dbgfs->dir_drv);
-       DEBUGFS_ADD_FILE(nvm, data);
-       DEBUGFS_ADD_FILE(sram, data);
-       DEBUGFS_ADD_FILE(log_event, data);
-       DEBUGFS_ADD_FILE(stations, data);
-       DEBUGFS_ADD_FILE(channels, data);
-       DEBUGFS_ADD_FILE(status, data);
-       DEBUGFS_ADD_FILE(interrupt, data);
-       DEBUGFS_ADD_FILE(qos, data);
-       DEBUGFS_ADD_FILE(led, data);
-       DEBUGFS_ADD_FILE(sleep_level_override, data);
-       DEBUGFS_ADD_FILE(current_sleep_command, data);
-       DEBUGFS_ADD_FILE(thermal_throttling, data);
-       DEBUGFS_ADD_FILE(disable_ht40, data);
-       DEBUGFS_ADD_FILE(rx_statistics, debug);
-       DEBUGFS_ADD_FILE(tx_statistics, debug);
-       DEBUGFS_ADD_FILE(traffic_log, debug);
-       DEBUGFS_ADD_FILE(rx_queue, debug);
-       DEBUGFS_ADD_FILE(tx_queue, debug);
-       DEBUGFS_ADD_FILE(tx_power, debug);
-       DEBUGFS_ADD_FILE(power_save_status, debug);
+       DEBUGFS_ADD_FILE(nvm, data, S_IRUSR);
+       DEBUGFS_ADD_FILE(sram, data, S_IWUSR | S_IRUSR);
+       DEBUGFS_ADD_FILE(log_event, data, S_IWUSR);
+       DEBUGFS_ADD_FILE(stations, data, S_IRUSR);
+       DEBUGFS_ADD_FILE(channels, data, S_IRUSR);
+       DEBUGFS_ADD_FILE(status, data, S_IRUSR);
+       DEBUGFS_ADD_FILE(interrupt, data, S_IWUSR | S_IRUSR);
+       DEBUGFS_ADD_FILE(qos, data, S_IRUSR);
+       DEBUGFS_ADD_FILE(led, data, S_IRUSR);
+       DEBUGFS_ADD_FILE(sleep_level_override, data, S_IWUSR | S_IRUSR);
+       DEBUGFS_ADD_FILE(current_sleep_command, data, S_IRUSR);
+       DEBUGFS_ADD_FILE(thermal_throttling, data, S_IRUSR);
+       DEBUGFS_ADD_FILE(disable_ht40, data, S_IWUSR | S_IRUSR);
+       DEBUGFS_ADD_FILE(rx_statistics, debug, S_IRUSR);
+       DEBUGFS_ADD_FILE(tx_statistics, debug, S_IRUSR);
+       DEBUGFS_ADD_FILE(traffic_log, debug, S_IWUSR | S_IRUSR);
+       DEBUGFS_ADD_FILE(rx_queue, debug, S_IRUSR);
+       DEBUGFS_ADD_FILE(tx_queue, debug, S_IRUSR);
+       DEBUGFS_ADD_FILE(tx_power, debug, S_IRUSR);
+       DEBUGFS_ADD_FILE(power_save_status, debug, S_IRUSR);
+       DEBUGFS_ADD_FILE(clear_ucode_statistics, debug, S_IWUSR);
+       DEBUGFS_ADD_FILE(clear_traffic_statistics, debug, S_IWUSR);
        if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) {
-               DEBUGFS_ADD_FILE(ucode_rx_stats, debug);
-               DEBUGFS_ADD_FILE(ucode_tx_stats, debug);
-               DEBUGFS_ADD_FILE(ucode_general_stats, debug);
-               DEBUGFS_ADD_FILE(sensitivity, debug);
-               DEBUGFS_ADD_FILE(chain_noise, debug);
+               DEBUGFS_ADD_FILE(ucode_rx_stats, debug, S_IRUSR);
+               DEBUGFS_ADD_FILE(ucode_tx_stats, debug, S_IRUSR);
+               DEBUGFS_ADD_FILE(ucode_general_stats, debug, S_IRUSR);
+               DEBUGFS_ADD_FILE(sensitivity, debug, S_IRUSR);
+               DEBUGFS_ADD_FILE(chain_noise, debug, S_IRUSR);
        }
        DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal);
        DEBUGFS_ADD_BOOL(disable_chain_noise, rf,
@@ -1941,6 +1962,10 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv)
        DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_queue);
        DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_power);
        DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_power_save_status);
+       DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.
+                       file_clear_ucode_statistics);
+       DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.
+                       file_clear_traffic_statistics);
        if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) {
                DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.
                        file_ucode_rx_stats);
index 9dea8fa..2673e9a 100644 (file)
@@ -52,19 +52,16 @@ extern struct iwl_cfg iwl4965_agn_cfg;
 extern struct iwl_cfg iwl5300_agn_cfg;
 extern struct iwl_cfg iwl5100_agn_cfg;
 extern struct iwl_cfg iwl5350_agn_cfg;
-extern struct iwl_cfg iwl5100_bg_cfg;
+extern struct iwl_cfg iwl5100_bgn_cfg;
 extern struct iwl_cfg iwl5100_abg_cfg;
 extern struct iwl_cfg iwl5150_agn_cfg;
-extern struct iwl_cfg iwl6000h_2agn_cfg;
-extern struct iwl_cfg iwl6000h_2abg_cfg;
-extern struct iwl_cfg iwl6000h_2bg_cfg;
+extern struct iwl_cfg iwl5150_abg_cfg;
 extern struct iwl_cfg iwl6000i_2agn_cfg;
 extern struct iwl_cfg iwl6000i_2abg_cfg;
 extern struct iwl_cfg iwl6000i_2bg_cfg;
 extern struct iwl_cfg iwl6000_3agn_cfg;
 extern struct iwl_cfg iwl6050_2agn_cfg;
 extern struct iwl_cfg iwl6050_2abg_cfg;
-extern struct iwl_cfg iwl6050_3agn_cfg;
 extern struct iwl_cfg iwl1000_bgn_cfg;
 extern struct iwl_cfg iwl1000_bg_cfg;
 
@@ -295,9 +292,6 @@ struct iwl_channel_info {
 
        /* HT40 channel info */
        s8 ht40_max_power_avg;  /* (dBm) regul. eeprom, normal Tx, any rate */
-       s8 ht40_curr_txpow;     /* (dBm) regulatory/spectrum/user (not h/w) */
-       s8 ht40_min_power;      /* always 0 */
-       s8 ht40_scan_power;     /* (dBm) eeprom, direct scans, any rate */
        u8 ht40_flags;          /* flags copied from EEPROM */
        u8 ht40_extension_channel; /* HT_IE_EXT_CHANNEL_* */
 
@@ -518,7 +512,6 @@ struct iwl_ht_config {
        bool is_ht;
        bool is_40mhz;
        bool single_chain_sufficient;
-       u8 sm_ps;
        /* BSS related data */
        u8 extension_chan_offset;
        u8 ht_protection;
@@ -552,23 +545,10 @@ struct iwl_qos_info {
        struct iwl_qosparam_cmd def_qos_parm;
 };
 
-#define STA_PS_STATUS_WAKE             0
-#define STA_PS_STATUS_SLEEP            1
-
-
-struct iwl3945_station_entry {
-       struct iwl3945_addsta_cmd sta;
-       struct iwl_tid_data tid[MAX_TID_COUNT];
-       u8 used;
-       u8 ps_status;
-       struct iwl_hw_key keyinfo;
-};
-
 struct iwl_station_entry {
        struct iwl_addsta_cmd sta;
        struct iwl_tid_data tid[MAX_TID_COUNT];
        u8 used;
-       u8 ps_status;
        struct iwl_hw_key keyinfo;
 };
 
@@ -578,11 +558,12 @@ struct iwl_station_entry {
  * When mac80211 creates a station it reserves some space (hw->sta_data_size)
  * in the structure for use by driver. This structure is places in that
  * space.
- *
- * At the moment use it for the station's rate scaling information.
  */
 struct iwl_station_priv {
        struct iwl_lq_sta lq_sta;
+       atomic_t pending_frames;
+       bool client;
+       bool asleep;
 };
 
 /* one for each uCode image (inst/data, boot/init/runtime) */
@@ -1254,6 +1235,7 @@ struct iwl_priv {
        /* TX Power */
        s8 tx_power_user_lmt;
        s8 tx_power_device_lmt;
+       s8 tx_power_lmt_in_half_dbm; /* max tx power in half-dBm format */
 
 
 #ifdef CONFIG_IWLWIFI_DEBUG
index 4ef5aca..e7d88d1 100644 (file)
@@ -5,6 +5,7 @@
 #define CREATE_TRACE_POINTS
 #include "iwl-devtrace.h"
 
+EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_iowrite8);
 EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ioread32);
 EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_iowrite32);
 EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_rx);
index 8c71592..2136196 100644 (file)
@@ -14,7 +14,7 @@ static inline void trace_ ## name(proto) {}
 #define PRIV_ASSIGN    __entry->priv = priv
 
 #undef TRACE_SYSTEM
-#define TRACE_SYSTEM iwlwifi
+#define TRACE_SYSTEM iwlwifi_io
 
 TRACE_EVENT(iwlwifi_dev_ioread32,
        TP_PROTO(struct iwl_priv *priv, u32 offs, u32 val),
@@ -32,6 +32,22 @@ TRACE_EVENT(iwlwifi_dev_ioread32,
        TP_printk("[%p] read io[%#x] = %#x", __entry->priv, __entry->offs, __entry->val)
 );
 
+TRACE_EVENT(iwlwifi_dev_iowrite8,
+       TP_PROTO(struct iwl_priv *priv, u32 offs, u8 val),
+       TP_ARGS(priv, offs, val),
+       TP_STRUCT__entry(
+               PRIV_ENTRY
+               __field(u32, offs)
+               __field(u8, val)
+       ),
+       TP_fast_assign(
+               PRIV_ASSIGN;
+               __entry->offs = offs;
+               __entry->val = val;
+       ),
+       TP_printk("[%p] write io[%#x] = %#x)", __entry->priv, __entry->offs, __entry->val)
+);
+
 TRACE_EVENT(iwlwifi_dev_iowrite32,
        TP_PROTO(struct iwl_priv *priv, u32 offs, u32 val),
        TP_ARGS(priv, offs, val),
@@ -48,6 +64,9 @@ TRACE_EVENT(iwlwifi_dev_iowrite32,
        TP_printk("[%p] write io[%#x] = %#x)", __entry->priv, __entry->offs, __entry->val)
 );
 
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM iwlwifi
+
 TRACE_EVENT(iwlwifi_dev_hcmd,
        TP_PROTO(struct iwl_priv *priv, void *hcmd, size_t len, u32 flags),
        TP_ARGS(priv, hcmd, len, flags),
index 8a0709e..3946e5c 100644 (file)
@@ -518,6 +518,11 @@ int iwl_eeprom_init(struct iwl_priv *priv)
        }
        e = (u16 *)priv->eeprom;
 
+       if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) {
+               /* OTP reads require powered-up chip */
+               priv->cfg->ops->lib->apm_ops.init(priv);
+       }
+
        ret = priv->cfg->ops->lib->eeprom_ops.verify_signature(priv);
        if (ret < 0) {
                IWL_ERR(priv, "EEPROM not found, EEPROM_GP=0x%08x\n", gp);
@@ -532,10 +537,8 @@ int iwl_eeprom_init(struct iwl_priv *priv)
                ret = -ENOENT;
                goto err;
        }
-       if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) {
 
-               /* OTP reads require powered-up chip */
-               priv->cfg->ops->lib->apm_ops.init(priv);
+       if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) {
 
                ret = iwl_init_otp_access(priv);
                if (ret) {
@@ -751,9 +754,6 @@ static int iwl_mod_ht40_chan_info(struct iwl_priv *priv,
 
        ch_info->ht40_eeprom = *eeprom_ch;
        ch_info->ht40_max_power_avg = eeprom_ch->max_power_avg;
-       ch_info->ht40_curr_txpow = eeprom_ch->max_power_avg;
-       ch_info->ht40_min_power = 0;
-       ch_info->ht40_scan_power = eeprom_ch->max_power_avg;
        ch_info->ht40_flags = eeprom_ch->flags;
        ch_info->ht40_extension_channel &= ~clear_ht40_extension_channel;
 
@@ -765,7 +765,8 @@ static int iwl_mod_ht40_chan_info(struct iwl_priv *priv,
  *     find the highest tx power from all chains for the channel
  */
 static s8 iwl_get_max_txpower_avg(struct iwl_priv *priv,
-               struct iwl_eeprom_enhanced_txpwr *enhanced_txpower, int element)
+               struct iwl_eeprom_enhanced_txpwr *enhanced_txpower,
+               int element, s8 *max_txpower_in_half_dbm)
 {
        s8 max_txpower_avg = 0; /* (dBm) */
 
@@ -797,10 +798,14 @@ static s8 iwl_get_max_txpower_avg(struct iwl_priv *priv,
            (enhanced_txpower[element].mimo3_max > max_txpower_avg))
                max_txpower_avg = enhanced_txpower[element].mimo3_max;
 
-       /* max. tx power in EEPROM is in 1/2 dBm format
-        * convert from 1/2 dBm to dBm
+       /*
+        * max. tx power in EEPROM is in 1/2 dBm format
+        * convert from 1/2 dBm to dBm (round-up convert)
+        * but we also do not want to loss 1/2 dBm resolution which
+        * will impact performance
         */
-       return max_txpower_avg >> 1;
+       *max_txpower_in_half_dbm = max_txpower_avg;
+       return (max_txpower_avg & 0x01) + (max_txpower_avg >> 1);
 }
 
 /**
@@ -809,7 +814,7 @@ static s8 iwl_get_max_txpower_avg(struct iwl_priv *priv,
  */
 static s8 iwl_update_common_txpower(struct iwl_priv *priv,
                struct iwl_eeprom_enhanced_txpwr *enhanced_txpower,
-               int section, int element)
+               int section, int element, s8 *max_txpower_in_half_dbm)
 {
        struct iwl_channel_info *ch_info;
        int ch;
@@ -823,25 +828,25 @@ static s8 iwl_update_common_txpower(struct iwl_priv *priv,
        if (element == EEPROM_TXPOWER_COMMON_HT40_INDEX)
                is_ht40 = true;
        max_txpower_avg =
-               iwl_get_max_txpower_avg(priv, enhanced_txpower, element);
+               iwl_get_max_txpower_avg(priv, enhanced_txpower,
+                                       element, max_txpower_in_half_dbm);
+
        ch_info = priv->channel_info;
 
        for (ch = 0; ch < priv->channel_count; ch++) {
                /* find matching band and update tx power if needed */
                if ((ch_info->band == enhinfo[section].band) &&
-                   (ch_info->max_power_avg < max_txpower_avg) && (!is_ht40)) {
+                   (ch_info->max_power_avg < max_txpower_avg) &&
+                   (!is_ht40)) {
                        /* Update regulatory-based run-time data */
                        ch_info->max_power_avg = ch_info->curr_txpow =
-                           max_txpower_avg;
+                               max_txpower_avg;
                        ch_info->scan_power = max_txpower_avg;
                }
                if ((ch_info->band == enhinfo[section].band) && is_ht40 &&
-                   ch_info->ht40_max_power_avg &&
                    (ch_info->ht40_max_power_avg < max_txpower_avg)) {
                        /* Update regulatory-based run-time data */
                        ch_info->ht40_max_power_avg = max_txpower_avg;
-                       ch_info->ht40_curr_txpow = max_txpower_avg;
-                       ch_info->ht40_scan_power = max_txpower_avg;
                }
                ch_info++;
        }
@@ -854,7 +859,7 @@ static s8 iwl_update_common_txpower(struct iwl_priv *priv,
  */
 static s8 iwl_update_channel_txpower(struct iwl_priv *priv,
                struct iwl_eeprom_enhanced_txpwr *enhanced_txpower,
-               int section, int element)
+               int section, int element, s8 *max_txpower_in_half_dbm)
 {
        struct iwl_channel_info *ch_info;
        int ch;
@@ -863,7 +868,8 @@ static s8 iwl_update_channel_txpower(struct iwl_priv *priv,
 
        channel = enhinfo[section].iwl_eeprom_section_channel[element];
        max_txpower_avg =
-               iwl_get_max_txpower_avg(priv, enhanced_txpower, element);
+               iwl_get_max_txpower_avg(priv, enhanced_txpower,
+                                       element, max_txpower_in_half_dbm);
 
        ch_info = priv->channel_info;
        for (ch = 0; ch < priv->channel_count; ch++) {
@@ -877,12 +883,9 @@ static s8 iwl_update_channel_txpower(struct iwl_priv *priv,
                                ch_info->scan_power = max_txpower_avg;
                        }
                        if ((enhinfo[section].is_ht40) &&
-                           (ch_info->ht40_max_power_avg) &&
                            (ch_info->ht40_max_power_avg < max_txpower_avg)) {
                                /* Update regulatory-based run-time data */
                                ch_info->ht40_max_power_avg = max_txpower_avg;
-                               ch_info->ht40_curr_txpow = max_txpower_avg;
-                               ch_info->ht40_scan_power = max_txpower_avg;
                        }
                        break;
                }
@@ -901,6 +904,7 @@ void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv)
        struct iwl_eeprom_enhanced_txpwr *enhanced_txpower;
        u32 offset;
        s8 max_txpower_avg; /* (dBm) */
+       s8 max_txpower_in_half_dbm; /* (half-dBm) */
 
        /* Loop through all the sections
         * adjust bands and channel's max tx power
@@ -913,20 +917,43 @@ void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv)
                enhanced_txpower = (struct iwl_eeprom_enhanced_txpwr *)
                                iwl_eeprom_query_addr(priv, offset);
 
+               /*
+                * check for valid entry -
+                * different version of EEPROM might contain different set
+                * of enhanced tx power table
+                * always check for valid entry before process
+                * the information
+                */
+               if (!enhanced_txpower->common || enhanced_txpower->reserved)
+                       continue;
+
                for (element = 0; element < eeprom_section_count; element++) {
                        if (enhinfo[section].is_common)
                                max_txpower_avg =
                                        iwl_update_common_txpower(priv,
-                                       enhanced_txpower, section, element);
+                                               enhanced_txpower, section,
+                                               element,
+                                               &max_txpower_in_half_dbm);
                        else
                                max_txpower_avg =
                                        iwl_update_channel_txpower(priv,
-                                       enhanced_txpower, section, element);
+                                               enhanced_txpower, section,
+                                               element,
+                                               &max_txpower_in_half_dbm);
 
                        /* Update the tx_power_user_lmt to the highest power
                         * supported by any channel */
                        if (max_txpower_avg > priv->tx_power_user_lmt)
                                priv->tx_power_user_lmt = max_txpower_avg;
+
+                       /*
+                        * Update the tx_power_lmt_in_half_dbm to
+                        * the highest power supported by any channel
+                        */
+                       if (max_txpower_in_half_dbm >
+                           priv->tx_power_lmt_in_half_dbm)
+                               priv->tx_power_lmt_in_half_dbm =
+                                       max_txpower_in_half_dbm;
                }
        }
 }
index 5ba5a4e..5cd2b66 100644 (file)
@@ -127,19 +127,21 @@ struct iwl_eeprom_channel {
  *    Enhanced regulatory tx power portion of eeprom image can be broken down
  *    into individual structures; each one is 8 bytes in size and contain the
  *    following information
+ * @common: (desc + channel) not used by driver, should _NOT_ be "zero"
  * @chain_a_max_pwr: chain a max power in 1/2 dBm
  * @chain_b_max_pwr: chain b max power in 1/2 dBm
  * @chain_c_max_pwr: chain c max power in 1/2 dBm
+ * @reserved: not used, should be "zero"
  * @mimo2_max_pwr: mimo2 max power in 1/2 dBm
  * @mimo3_max_pwr: mimo3 max power in 1/2 dBm
  *
  */
 struct iwl_eeprom_enhanced_txpwr {
-       u16 reserved;
+       u16 common;
        s8 chain_a_max;
        s8 chain_b_max;
        s8 chain_c_max;
-       s8 reserved1;
+       s8 reserved;
        s8 mimo2_max;
        s8 mimo3_max;
 } __attribute__ ((packed));
index d0a358c..e552d4c 100644 (file)
  *
  */
 
+static inline void _iwl_write8(struct iwl_priv *priv, u32 ofs, u8 val)
+{
+       trace_iwlwifi_dev_iowrite8(priv, ofs, val);
+       iowrite8(val, priv->hw_base + ofs);
+}
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+static inline void __iwl_write8(const char *f, u32 l, struct iwl_priv *priv,
+                                u32 ofs, u8 val)
+{
+       IWL_DEBUG_IO(priv, "write8(0x%08X, 0x%02X) - %s %d\n", ofs, val, f, l);
+       _iwl_write8(priv, ofs, val);
+}
+#define iwl_write8(priv, ofs, val) \
+       __iwl_write8(__FILE__, __LINE__, priv, ofs, val)
+#else
+#define iwl_write8(priv, ofs, val) _iwl_write8(priv, ofs, val)
+#endif
+
+
 static inline void _iwl_write32(struct iwl_priv *priv, u32 ofs, u32 val)
 {
        trace_iwlwifi_dev_iowrite32(priv, ofs, val);
index 478c905..46c7a95 100644 (file)
@@ -219,7 +219,6 @@ EXPORT_SYMBOL(iwl_leds_background);
 void iwl_leds_init(struct iwl_priv *priv)
 {
        priv->last_blink_rate = 0;
-       priv->led_tpt = 0;
        priv->last_blink_time = 0;
        priv->allow_blinking = 0;
 }
index 9bce2c1..8ccc0bb 100644 (file)
@@ -506,7 +506,7 @@ static void iwl_prepare_ct_kill_task(struct iwl_priv *priv)
 {
        IWL_DEBUG_POWER(priv, "Prepare to enter IWL_TI_CT_KILL\n");
        /* make request to retrieve statistics information */
-       iwl_send_statistics_request(priv, 0);
+       iwl_send_statistics_request(priv, CMD_SYNC, false);
        /* Reschedule the ct_kill wait timer */
        mod_timer(&priv->thermal_throttle.ct_kill_waiting_tm,
                 jiffies + msecs_to_jiffies(CT_KILL_WAITING_DURATION));
index 61b3b0e..6090bc1 100644 (file)
@@ -477,7 +477,8 @@ int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
                           (rb_timeout << FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS)|
                           (rfdnlog << FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS));
 
-       iwl_write32(priv, CSR_INT_COALESCING, 0x40);
+       /* Set interrupt coalescing timer to 64 x 32 = 2048 usecs */
+       iwl_write8(priv, CSR_INT_COALESCING, 0x40);
 
        return 0;
 }
@@ -635,6 +636,24 @@ void iwl_rx_statistics(struct iwl_priv *priv,
 }
 EXPORT_SYMBOL(iwl_rx_statistics);
 
+void iwl_reply_statistics(struct iwl_priv *priv,
+                             struct iwl_rx_mem_buffer *rxb)
+{
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+
+       if (le32_to_cpu(pkt->u.stats.flag) & UCODE_STATISTICS_CLEAR_MSK) {
+               memset(&priv->statistics, 0,
+                       sizeof(struct iwl_notif_statistics));
+#ifdef CONFIG_IWLWIFI_DEBUG
+               memset(&priv->accum_statistics, 0,
+                       sizeof(struct iwl_notif_statistics));
+#endif
+               IWL_DEBUG_RX(priv, "Statistics have been cleared\n");
+       }
+       iwl_rx_statistics(priv, rxb);
+}
+EXPORT_SYMBOL(iwl_reply_statistics);
+
 #define PERFECT_RSSI (-20) /* dBm */
 #define WORST_RSSI (-95)   /* dBm */
 #define RSSI_RANGE (PERFECT_RSSI - WORST_RSSI)
@@ -1010,7 +1029,6 @@ void iwl_rx_reply_rx(struct iwl_priv *priv,
        struct iwl4965_rx_mpdu_res_start *amsdu;
        u32 len;
        u32 ampdu_status;
-       u16 fc;
        u32 rate_n_flags;
 
        /**
@@ -1143,20 +1161,8 @@ void iwl_rx_reply_rx(struct iwl_priv *priv,
                priv->last_tsf = le64_to_cpu(phy_res->timestamp);
        }
 
-       fc = le16_to_cpu(header->frame_control);
-       switch (fc & IEEE80211_FCTL_FTYPE) {
-       case IEEE80211_FTYPE_MGMT:
-       case IEEE80211_FTYPE_DATA:
-               if (priv->iw_mode == NL80211_IFTYPE_AP)
-                       iwl_update_ps_mode(priv, fc  & IEEE80211_FCTL_PM,
-                                               header->addr2);
-               /* fall through */
-       default:
-               iwl_pass_packet_to_mac80211(priv, header, len, ampdu_status,
-                               rxb, &rx_status);
-               break;
-
-       }
+       iwl_pass_packet_to_mac80211(priv, header, len, ampdu_status,
+                                   rxb, &rx_status);
 }
 EXPORT_SYMBOL(iwl_rx_reply_rx);
 
index eba36f7..cd6a690 100644 (file)
@@ -1216,7 +1216,7 @@ int iwl_sta_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid)
 }
 EXPORT_SYMBOL(iwl_sta_rx_agg_stop);
 
-static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id)
+void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id)
 {
        unsigned long flags;
 
@@ -1224,27 +1224,26 @@ static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id)
        priv->stations[sta_id].sta.station_flags &= ~STA_FLG_PWR_SAVE_MSK;
        priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK;
        priv->stations[sta_id].sta.sta.modify_mask = 0;
+       priv->stations[sta_id].sta.sleep_tx_count = 0;
        priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
        spin_unlock_irqrestore(&priv->sta_lock, flags);
 
        iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
 }
+EXPORT_SYMBOL(iwl_sta_modify_ps_wake);
 
-void iwl_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr)
+void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt)
 {
-       /* FIXME: need locking over ps_status ??? */
-       u8 sta_id = iwl_find_station(priv, addr);
+       unsigned long flags;
 
-       if (sta_id != IWL_INVALID_STATION) {
-               u8 sta_awake = priv->stations[sta_id].
-                               ps_status == STA_PS_STATUS_WAKE;
+       spin_lock_irqsave(&priv->sta_lock, flags);
+       priv->stations[sta_id].sta.station_flags |= STA_FLG_PWR_SAVE_MSK;
+       priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK;
+       priv->stations[sta_id].sta.sta.modify_mask =
+                                       STA_MODIFY_SLEEP_TX_COUNT_MSK;
+       priv->stations[sta_id].sta.sleep_tx_count = cpu_to_le16(cnt);
+       priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+       spin_unlock_irqrestore(&priv->sta_lock, flags);
 
-               if (sta_awake && ps_bit)
-                       priv->stations[sta_id].ps_status = STA_PS_STATUS_SLEEP;
-               else if (!sta_awake && !ps_bit) {
-                       iwl_sta_modify_ps_wake(priv, sta_id);
-                       priv->stations[sta_id].ps_status = STA_PS_STATUS_WAKE;
-               }
-       }
+       iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
 }
-
index 1c382de..8d052de 100644 (file)
@@ -66,5 +66,6 @@ void iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid);
 int iwl_sta_rx_agg_start(struct iwl_priv *priv,
                         const u8 *addr, int tid, u16 ssn);
 int iwl_sta_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid);
-void iwl_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr);
+void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id);
+void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt);
 #endif /* __iwl_sta_h__ */
index 6199bf6..888a8e9 100644 (file)
@@ -710,6 +710,8 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       struct ieee80211_sta *sta = info->control.sta;
+       struct iwl_station_priv *sta_priv = NULL;
        struct iwl_tx_queue *txq;
        struct iwl_queue *q;
        struct iwl_device_cmd *out_cmd;
@@ -772,6 +774,24 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
 
        IWL_DEBUG_TX(priv, "station Id %d\n", sta_id);
 
+       if (sta)
+               sta_priv = (void *)sta->drv_priv;
+
+       if (sta_priv && sta_id != priv->hw_params.bcast_sta_id &&
+           sta_priv->asleep) {
+               WARN_ON(!(info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE));
+               /*
+                * This sends an asynchronous command to the device,
+                * but we can rely on it being processed before the
+                * next frame is processed -- and the next frame to
+                * this station is the one that will consume this
+                * counter.
+                * For now set the counter to just 1 since we do not
+                * support uAPSD yet.
+                */
+               iwl_sta_modify_sleep_tx_count(priv, sta_id, 1);
+       }
+
        txq_id = skb_get_queue_mapping(skb);
        if (ieee80211_is_data_qos(fc)) {
                qc = ieee80211_get_qos_ctl(hdr);
@@ -931,6 +951,17 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
        ret = iwl_txq_update_write_ptr(priv, txq);
        spin_unlock_irqrestore(&priv->lock, flags);
 
+       /*
+        * At this point the frame is "transmitted" successfully
+        * and we will get a TX status notification eventually,
+        * regardless of the value of ret. "ret" only indicates
+        * whether or not we should update the write pointer.
+        */
+
+       /* avoid atomic ops if it isn't an associated client */
+       if (sta_priv && sta_priv->client)
+               atomic_inc(&sta_priv->pending_frames);
+
        if (ret)
                return ret;
 
@@ -992,7 +1023,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
        }
 
        if (iwl_queue_space(q) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) {
-               IWL_ERR(priv, "No space for Tx\n");
+               IWL_ERR(priv, "No space in command queue\n");
                if (iwl_within_ct_kill_margin(priv))
                        iwl_tt_enter_ct_kill(priv);
                else {
@@ -1075,6 +1106,24 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
        return ret ? ret : idx;
 }
 
+static void iwl_tx_status(struct iwl_priv *priv, struct sk_buff *skb)
+{
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       struct ieee80211_sta *sta;
+       struct iwl_station_priv *sta_priv;
+
+       sta = ieee80211_find_sta(priv->vif, hdr->addr1);
+       if (sta) {
+               sta_priv = (void *)sta->drv_priv;
+               /* avoid atomic ops if this isn't a client */
+               if (sta_priv->client &&
+                   atomic_dec_return(&sta_priv->pending_frames) == 0)
+                       ieee80211_sta_block_awake(priv->hw, sta, false);
+       }
+
+       ieee80211_tx_status_irqsafe(priv->hw, skb);
+}
+
 int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
 {
        struct iwl_tx_queue *txq = &priv->txq[txq_id];
@@ -1094,7 +1143,7 @@ int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
             q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
 
                tx_info = &txq->txb[txq->q.read_ptr];
-               ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb[0]);
+               iwl_tx_status(priv, tx_info->skb[0]);
                tx_info->skb[0] = NULL;
 
                if (priv->cfg->ops->lib->txq_inval_byte_cnt_tbl)
@@ -1264,7 +1313,7 @@ int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn)
        if (tid_data->tfds_in_queue == 0) {
                IWL_DEBUG_HT(priv, "HW queue is empty\n");
                tid_data->agg.state = IWL_AGG_ON;
-               ieee80211_start_tx_ba_cb_irqsafe(priv->hw, ra, tid);
+               ieee80211_start_tx_ba_cb_irqsafe(priv->vif, ra, tid);
        } else {
                IWL_DEBUG_HT(priv, "HW queue is NOT empty: %d packets in HW queue\n",
                             tid_data->tfds_in_queue);
@@ -1329,7 +1378,7 @@ int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid)
        if (ret)
                return ret;
 
-       ieee80211_stop_tx_ba_cb_irqsafe(priv->hw, ra, tid);
+       ieee80211_stop_tx_ba_cb_irqsafe(priv->vif, ra, tid);
 
        return 0;
 }
@@ -1353,7 +1402,7 @@ int iwl_txq_check_empty(struct iwl_priv *priv, int sta_id, u8 tid, int txq_id)
                        priv->cfg->ops->lib->txq_agg_disable(priv, txq_id,
                                                             ssn, tx_fifo);
                        tid_data->agg.state = IWL_AGG_OFF;
-                       ieee80211_stop_tx_ba_cb_irqsafe(priv->hw, addr, tid);
+                       ieee80211_stop_tx_ba_cb_irqsafe(priv->vif, addr, tid);
                }
                break;
        case IWL_EMPTYING_HW_QUEUE_ADDBA:
@@ -1361,7 +1410,7 @@ int iwl_txq_check_empty(struct iwl_priv *priv, int sta_id, u8 tid, int txq_id)
                if (tid_data->tfds_in_queue == 0) {
                        IWL_DEBUG_HT(priv, "HW queue empty: continue ADDBA flow\n");
                        tid_data->agg.state = IWL_AGG_ON;
-                       ieee80211_start_tx_ba_cb_irqsafe(priv->hw, addr, tid);
+                       ieee80211_start_tx_ba_cb_irqsafe(priv->vif, addr, tid);
                }
                break;
        }
index 5d26330..0db9b79 100644 (file)
@@ -1483,7 +1483,6 @@ static inline void iwl_synchronize_irq(struct iwl_priv *priv)
        tasklet_kill(&priv->irq_tasklet);
 }
 
-#ifdef CONFIG_IWLWIFI_DEBUG
 static const char *desc_lookup(int i)
 {
        switch (i) {
@@ -1614,10 +1613,42 @@ static void iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx,
        spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
 }
 
+/**
+ * iwl3945_print_last_event_logs - Dump the newest # of event log to syslog
+ */
+static void iwl3945_print_last_event_logs(struct iwl_priv *priv, u32 capacity,
+                                     u32 num_wraps, u32 next_entry,
+                                     u32 size, u32 mode)
+{
+       /*
+        * display the newest DEFAULT_LOG_ENTRIES entries
+        * i.e the entries just before the next ont that uCode would fill.
+        */
+       if (num_wraps) {
+               if (next_entry < size) {
+                       iwl3945_print_event_log(priv,
+                                       capacity - (size - next_entry),
+                                       size - next_entry, mode);
+                       iwl3945_print_event_log(priv, 0,
+                                   next_entry, mode);
+               } else
+                       iwl3945_print_event_log(priv, next_entry - size,
+                                   size, mode);
+       } else {
+               if (next_entry < size)
+                       iwl3945_print_event_log(priv, 0, next_entry, mode);
+               else
+                       iwl3945_print_event_log(priv, next_entry - size,
+                                           size, mode);
+       }
+}
+
 /* For sanity check only.  Actual size is determined by uCode, typ. 512 */
 #define IWL3945_MAX_EVENT_LOG_SIZE (512)
 
-void iwl3945_dump_nic_event_log(struct iwl_priv *priv)
+#define DEFAULT_IWL3945_DUMP_EVENT_LOG_ENTRIES (20)
+
+void iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log)
 {
        u32 base;       /* SRAM byte address of event log header */
        u32 capacity;   /* event log capacity in # entries */
@@ -1658,8 +1689,17 @@ void iwl3945_dump_nic_event_log(struct iwl_priv *priv)
                return;
        }
 
-       IWL_ERR(priv, "Start IWL Event Log Dump: display count %d, wraps %d\n",
-                 size, num_wraps);
+#ifdef CONFIG_IWLWIFI_DEBUG
+       if (!(iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS))
+               size = (size > DEFAULT_IWL3945_DUMP_EVENT_LOG_ENTRIES)
+                       ? DEFAULT_IWL3945_DUMP_EVENT_LOG_ENTRIES : size;
+#else
+       size = (size > DEFAULT_IWL3945_DUMP_EVENT_LOG_ENTRIES)
+               ? DEFAULT_IWL3945_DUMP_EVENT_LOG_ENTRIES : size;
+#endif
+
+       IWL_ERR(priv, "Start IWL Event Log Dump: display last %d count\n",
+                 size);
 
        /* if uCode has wrapped back to top of log, start at the oldest entry,
         * i.e the next one that uCode would fill. */
@@ -1670,18 +1710,28 @@ void iwl3945_dump_nic_event_log(struct iwl_priv *priv)
        /* (then/else) start at top of log */
        iwl3945_print_event_log(priv, 0, next_entry, mode);
 
-}
+#ifdef CONFIG_IWLWIFI_DEBUG
+       if ((iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) || full_log) {
+               /* if uCode has wrapped back to top of log,
+                * start at the oldest entry,
+                * i.e the next one that uCode would fill.
+                */
+               if (num_wraps)
+                       iwl3945_print_event_log(priv, next_entry,
+                                   capacity - next_entry, mode);
+
+               /* (then/else) start at top of log */
+               iwl3945_print_event_log(priv, 0, next_entry, mode);
+       } else
+               iwl3945_print_last_event_logs(priv, capacity, num_wraps,
+                                       next_entry, size, mode);
 #else
-void iwl3945_dump_nic_event_log(struct iwl_priv *priv)
-{
-}
+       iwl3945_print_last_event_logs(priv, capacity, num_wraps,
+                               next_entry, size, mode);
+#endif
 
-void iwl3945_dump_nic_error_log(struct iwl_priv *priv)
-{
 }
 
-#endif
-
 static void iwl3945_irq_tasklet(struct iwl_priv *priv)
 {
        u32 inta, handled = 0;
@@ -2494,7 +2544,7 @@ static void iwl3945_alive_start(struct iwl_priv *priv)
        priv->active_rate = priv->rates_mask;
        priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK;
 
-       iwl_power_update_mode(priv, false);
+       iwl_power_update_mode(priv, true);
 
        if (iwl_is_associated(priv)) {
                struct iwl3945_rxon_cmd *active_rxon =
@@ -3650,7 +3700,7 @@ static ssize_t show_statistics(struct device *d,
                return -EAGAIN;
 
        mutex_lock(&priv->mutex);
-       rc = iwl_send_statistics_request(priv, 0);
+       rc = iwl_send_statistics_request(priv, CMD_SYNC, false);
        mutex_unlock(&priv->mutex);
 
        if (rc) {
@@ -3905,10 +3955,8 @@ static int iwl3945_setup_mac(struct iwl_priv *priv)
                BIT(NL80211_IFTYPE_STATION) |
                BIT(NL80211_IFTYPE_ADHOC);
 
-       hw->wiphy->custom_regulatory = true;
-
-       /* Firmware does not support this */
-       hw->wiphy->disable_beacon_hints = true;
+       hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY |
+                           WIPHY_FLAG_DISABLE_BEACON_HINTS;
 
        hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX_3945;
        /* we create the 802.11 header and a zero-length SSID element */
index fc4ec48..88e4117 100644 (file)
@@ -1146,46 +1146,46 @@ static int __init init_mac80211_hwsim(void)
                        break;
                case HWSIM_REGTEST_WORLD_ROAM:
                        if (i == 0) {
-                               hw->wiphy->custom_regulatory = true;
+                               hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
                                wiphy_apply_custom_regulatory(hw->wiphy,
                                        &hwsim_world_regdom_custom_01);
                        }
                        break;
                case HWSIM_REGTEST_CUSTOM_WORLD:
-                       hw->wiphy->custom_regulatory = true;
+                       hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
                        wiphy_apply_custom_regulatory(hw->wiphy,
                                &hwsim_world_regdom_custom_01);
                        break;
                case HWSIM_REGTEST_CUSTOM_WORLD_2:
                        if (i == 0) {
-                               hw->wiphy->custom_regulatory = true;
+                               hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
                                wiphy_apply_custom_regulatory(hw->wiphy,
                                        &hwsim_world_regdom_custom_01);
                        } else if (i == 1) {
-                               hw->wiphy->custom_regulatory = true;
+                               hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
                                wiphy_apply_custom_regulatory(hw->wiphy,
                                        &hwsim_world_regdom_custom_02);
                        }
                        break;
                case HWSIM_REGTEST_STRICT_ALL:
-                       hw->wiphy->strict_regulatory = true;
+                       hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY;
                        break;
                case HWSIM_REGTEST_STRICT_FOLLOW:
                case HWSIM_REGTEST_STRICT_AND_DRIVER_REG:
                        if (i == 0)
-                               hw->wiphy->strict_regulatory = true;
+                               hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY;
                        break;
                case HWSIM_REGTEST_ALL:
                        if (i == 0) {
-                               hw->wiphy->custom_regulatory = true;
+                               hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
                                wiphy_apply_custom_regulatory(hw->wiphy,
                                        &hwsim_world_regdom_custom_01);
                        } else if (i == 1) {
-                               hw->wiphy->custom_regulatory = true;
+                               hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
                                wiphy_apply_custom_regulatory(hw->wiphy,
                                        &hwsim_world_regdom_custom_02);
                        } else if (i == 4)
-                               hw->wiphy->strict_regulatory = true;
+                               hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY;
                        break;
                default:
                        break;
index 4d486bf..18012db 100644 (file)
@@ -579,7 +579,7 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len)
         * For now, disable PS by default because it affects
         * link stability significantly.
         */
-       dev->wiphy->ps_default = false;
+       dev->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
 
        mutex_init(&priv->conf_mutex);
        mutex_init(&priv->eeprom_mutex);
index aa1880a..2ecbedb 100644 (file)
@@ -83,11 +83,11 @@ MODULE_PARM_DESC(roamdelta,
        "set roaming tendency: 0=aggressive, 1=moderate, "
                                "2=conservative (default: moderate)");
 
-static int modparam_workaround_interval = 500;
+static int modparam_workaround_interval;
 module_param_named(workaround_interval, modparam_workaround_interval,
                                                        int, 0444);
 MODULE_PARM_DESC(workaround_interval,
-       "set stall workaround interval in msecs (default: 500)");
+       "set stall workaround interval in msecs (0=disabled) (default: 0)");
 
 
 /* various RNDIS OID defs */
@@ -733,12 +733,13 @@ static int rndis_query_oid(struct usbnet *dev, __le32 oid, void *data, int *len)
                        le32_to_cpu(u.get_c->status));
 
        if (ret == 0) {
+               memcpy(data, u.buf + le32_to_cpu(u.get_c->offset) + 8, *len);
+
                ret = le32_to_cpu(u.get_c->len);
                if (ret > *len)
                        *len = ret;
-               memcpy(data, u.buf + le32_to_cpu(u.get_c->offset) + 8, *len);
-               ret = rndis_error_status(u.get_c->status);
 
+               ret = rndis_error_status(u.get_c->status);
                if (ret < 0)
                        devdbg(dev, "rndis_query_oid(%s): device returned "
                                "error,  0x%08x (%d)", oid_to_string(oid),
@@ -2549,7 +2550,7 @@ static void rndis_device_poller(struct work_struct *work)
        /* Workaround transfer stalls on poor quality links.
         * TODO: find right way to fix these stalls (as stalls do not happen
         * with ndiswrapper/windows driver). */
-       if (priv->last_qual <= 25) {
+       if (priv->param_workaround_interval > 0 && priv->last_qual <= 25) {
                /* Decrease stats worker interval to catch stalls.
                 * faster. Faster than 400-500ms causes packet loss,
                 * Slower doesn't catch stalls fast enough.
index b1d6393..9ab15c4 100644 (file)
@@ -824,17 +824,23 @@ static struct usb_device_id rt2800usb_device_table[] = {
        { USB_DEVICE(0x0e0b, 0x9041), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Amit */
        { USB_DEVICE(0x15c5, 0x0008), USB_DEVICE_DATA(&rt2800usb_ops) },
+       /* Askey */
+       { USB_DEVICE(0x1690, 0x0740), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x1690, 0x0744), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0930, 0x0a07), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* ASUS */
        { USB_DEVICE(0x0b05, 0x1731), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x0b05, 0x1732), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x0b05, 0x1742), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x0b05, 0x1760), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x0b05, 0x1761), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0b05, 0x1784), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* AzureWave */
        { USB_DEVICE(0x13d3, 0x3247), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x13d3, 0x3262), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x13d3, 0x3273), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x13d3, 0x3284), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x13d3, 0x3305), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Belkin */
        { USB_DEVICE(0x050d, 0x8053), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x050d, 0x805c), USB_DEVICE_DATA(&rt2800usb_ops) },
@@ -843,6 +849,8 @@ static struct usb_device_id rt2800usb_device_table[] = {
        /* Buffalo */
        { USB_DEVICE(0x0411, 0x00e8), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x0411, 0x012e), USB_DEVICE_DATA(&rt2800usb_ops) },
+       /* Cisco */
+       { USB_DEVICE(0x167b, 0x4001), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Conceptronic */
        { USB_DEVICE(0x14b2, 0x3c06), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x14b2, 0x3c07), USB_DEVICE_DATA(&rt2800usb_ops) },
@@ -858,6 +866,8 @@ static struct usb_device_id rt2800usb_device_table[] = {
        { USB_DEVICE(0x07aa, 0x002f), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x07aa, 0x003c), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x07aa, 0x003f), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x07aa, 0x0041), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x07aa, 0x0042), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x18c5, 0x0008), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x18c5, 0x0012), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* D-Link */
@@ -869,18 +879,24 @@ static struct usb_device_id rt2800usb_device_table[] = {
        { USB_DEVICE(0x07d1, 0x3c0f), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x07d1, 0x3c11), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x07d1, 0x3c13), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x07d1, 0x3c15), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Edimax */
        { USB_DEVICE(0x7392, 0x7711), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x7392, 0x7717), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x7392, 0x7718), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Encore */
        { USB_DEVICE(0x203d, 0x1480), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x203d, 0x14a1), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x203d, 0x14a9), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* EnGenius */
        { USB_DEVICE(0X1740, 0x9701), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x1740, 0x9702), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x1740, 0x9703), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x1740, 0x9705), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x1740, 0x9706), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x1740, 0x9707), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x1740, 0x9708), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x1740, 0x9709), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x1740, 0x9801), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Gemtek */
        { USB_DEVICE(0x15a9, 0x0010), USB_DEVICE_DATA(&rt2800usb_ops) },
@@ -894,7 +910,10 @@ static struct usb_device_id rt2800usb_device_table[] = {
        { USB_DEVICE(0x0e66, 0x0009), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x0e66, 0x000b), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* I-O DATA */
+       { USB_DEVICE(0x04bb, 0x0944), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x04bb, 0x0945), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x04bb, 0x0947), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x04bb, 0x0948), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* LevelOne */
        { USB_DEVICE(0x1740, 0x0605), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x1740, 0x0615), USB_DEVICE_DATA(&rt2800usb_ops) },
@@ -909,8 +928,18 @@ static struct usb_device_id rt2800usb_device_table[] = {
        /* Motorola */
        { USB_DEVICE(0x100d, 0x9031), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x100d, 0x9032), USB_DEVICE_DATA(&rt2800usb_ops) },
+       /* MSI */
+       { USB_DEVICE(0x0db0, 0x3820), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0db0, 0x3821), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0db0, 0x3870), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0db0, 0x6899), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0db0, 0x821a), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0db0, 0x870a), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0db0, 0x899a), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Ovislink */
        { USB_DEVICE(0x1b75, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) },
+       /* Para */
+       { USB_DEVICE(0x20b8, 0x8888), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Pegatron */
        { USB_DEVICE(0x1d4d, 0x0002), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x1d4d, 0x000c), USB_DEVICE_DATA(&rt2800usb_ops) },
@@ -926,8 +955,6 @@ static struct usb_device_id rt2800usb_device_table[] = {
        /* Quanta */
        { USB_DEVICE(0x1a32, 0x0304), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Ralink */
-       { USB_DEVICE(0x0db0, 0x3820), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0db0, 0x6899), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x148f, 0x2070), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x148f, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x148f, 0x2870), USB_DEVICE_DATA(&rt2800usb_ops) },
@@ -951,7 +978,12 @@ static struct usb_device_id rt2800usb_device_table[] = {
        { USB_DEVICE(0x0df6, 0x003e), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x0df6, 0x003f), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x0df6, 0x0040), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0df6, 0x0041), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x0df6, 0x0042), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0df6, 0x0047), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0df6, 0x0048), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0df6, 0x004a), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0df6, 0x004d), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* SMC */
        { USB_DEVICE(0x083a, 0x6618), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x083a, 0x7511), USB_DEVICE_DATA(&rt2800usb_ops) },
@@ -960,6 +992,8 @@ static struct usb_device_id rt2800usb_device_table[] = {
        { USB_DEVICE(0x083a, 0x8522), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x083a, 0xa512), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x083a, 0xa618), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x083a, 0xa701), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x083a, 0xa702), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x083a, 0xb522), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x083a, 0xc522), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Sparklan */
@@ -977,6 +1011,7 @@ static struct usb_device_id rt2800usb_device_table[] = {
        { USB_DEVICE(0x5a57, 0x0280), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x5a57, 0x0282), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x5a57, 0x0283), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x5a57, 0x0284), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x5a57, 0x5257), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Zyxel */
        { USB_DEVICE(0x0586, 0x3416), USB_DEVICE_DATA(&rt2800usb_ops) },
index 6c6d0ac..4a4b7e4 100644 (file)
@@ -205,6 +205,7 @@ void rt2x00lib_txdone(struct queue_entry *entry,
        enum data_queue_qid qid = skb_get_queue_mapping(entry->skb);
        unsigned int header_length = ieee80211_get_hdrlen_from_skb(entry->skb);
        u8 rate_idx, rate_flags, retry_rates;
+       u8 skbdesc_flags = skbdesc->flags;
        unsigned int i;
        bool success;
 
@@ -287,12 +288,12 @@ void rt2x00lib_txdone(struct queue_entry *entry,
        }
 
        /*
-        * Only send the status report to mac80211 when TX status was
-        * requested by it. If this was a extra frame coming through
-        * a mac80211 library call (RTS/CTS) then we should not send the
-        * status report back.
+        * Only send the status report to mac80211 when it's a frame
+        * that originated in mac80211. If this was a extra frame coming
+        * through a mac80211 library call (RTS/CTS) then we should not
+        * send the status report back.
         */
-       if (tx_info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)
+       if (!(skbdesc_flags & SKBDESC_NOT_MAC80211))
                ieee80211_tx_status_irqsafe(rt2x00dev->hw, entry->skb);
        else
                dev_kfree_skb_irq(entry->skb);
index c1f48ac..be2e37f 100644 (file)
@@ -162,8 +162,10 @@ void rt2x00queue_remove_l2pad(struct sk_buff *skb, unsigned int header_length);
  * rt2x00queue_write_tx_frame - Write TX frame to hardware
  * @queue: Queue over which the frame should be send
  * @skb: The skb to send
+ * @local: frame is not from mac80211
  */
-int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb);
+int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb,
+                              bool local);
 
 /**
  * rt2x00queue_update_beacon - Send new beacon from mac80211 to hardware
index eed093d..9c90ceb 100644 (file)
@@ -66,7 +66,6 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev,
        rts_info = IEEE80211_SKB_CB(skb);
        rts_info->control.rates[0].flags &= ~IEEE80211_TX_RC_USE_RTS_CTS;
        rts_info->control.rates[0].flags &= ~IEEE80211_TX_RC_USE_CTS_PROTECT;
-       rts_info->flags &= ~IEEE80211_TX_CTL_REQ_TX_STATUS;
 
        if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)
                rts_info->flags |= IEEE80211_TX_CTL_NO_ACK;
@@ -91,7 +90,7 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev,
                                  frag_skb->data, data_length, tx_info,
                                  (struct ieee80211_rts *)(skb->data));
 
-       retval = rt2x00queue_write_tx_frame(queue, skb);
+       retval = rt2x00queue_write_tx_frame(queue, skb, true);
        if (retval) {
                dev_kfree_skb_any(skb);
                WARNING(rt2x00dev, "Failed to send RTS/CTS frame.\n");
@@ -153,7 +152,7 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
                        goto exit_fail;
        }
 
-       if (rt2x00queue_write_tx_frame(queue, skb))
+       if (rt2x00queue_write_tx_frame(queue, skb, false))
                goto exit_fail;
 
        if (rt2x00queue_threshold(queue))
index 02972a0..eaedee8 100644 (file)
@@ -454,7 +454,8 @@ static void rt2x00queue_write_tx_descriptor(struct queue_entry *entry,
                rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, queue->qid);
 }
 
-int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb)
+int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb,
+                              bool local)
 {
        struct ieee80211_tx_info *tx_info;
        struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX);
@@ -495,6 +496,9 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb)
        skbdesc->tx_rate_idx = rate_idx;
        skbdesc->tx_rate_flags = rate_flags;
 
+       if (local)
+               skbdesc->flags |= SKBDESC_NOT_MAC80211;
+
        /*
         * When hardware encryption is supported, and this frame
         * is to be encrypted, we should strip the IV/EIV data from
index 97c7895..70775e5 100644 (file)
@@ -94,12 +94,15 @@ enum data_queue_qid {
  *     mac80211 but was stripped for processing by the driver.
  * @SKBDESC_L2_PADDED: Payload has been padded for 4-byte alignment,
  *     the padded bytes are located between header and payload.
+ * @SKBDESC_NOT_MAC80211: Frame didn't originate from mac80211,
+ *     don't try to pass it back.
  */
 enum skb_frame_desc_flags {
        SKBDESC_DMA_MAPPED_RX = 1 << 0,
        SKBDESC_DMA_MAPPED_TX = 1 << 1,
        SKBDESC_IV_STRIPPED = 1 << 2,
-       SKBDESC_L2_PADDED = 1 << 3
+       SKBDESC_L2_PADDED = 1 << 3,
+       SKBDESC_NOT_MAC80211 = 1 << 4,
 };
 
 /**
index 998e4b6..054533f 100644 (file)
@@ -269,6 +269,7 @@ struct wl1251 {
 
        void (*set_power)(bool enable);
        int irq;
+       bool use_eeprom;
 
        enum wl1251_state state;
        struct mutex mutex;
@@ -354,6 +355,8 @@ struct wl1251 {
        /* is firmware in elp mode */
        bool elp;
 
+       struct delayed_work elp_work;
+
        /* we can be in psm, but not in elp, we have to differentiate */
        bool psm;
 
@@ -374,6 +377,8 @@ struct wl1251 {
        u8 buffer_busyword[WL1251_BUSY_WORD_LEN];
        struct wl1251_rx_descriptor *rx_descriptor;
 
+       struct ieee80211_vif *vif;
+
        u32 chip_id;
        char fw_ver[21];
 };
index 10b26c4..acfa086 100644 (file)
@@ -494,7 +494,7 @@ out:
        return ret;
 }
 
-int wl1251_acx_beacon_filter_opt(struct wl1251 *wl)
+int wl1251_acx_beacon_filter_opt(struct wl1251 *wl, bool enable_filter)
 {
        struct acx_beacon_filter_option *beacon_filter;
        int ret;
@@ -507,7 +507,7 @@ int wl1251_acx_beacon_filter_opt(struct wl1251 *wl)
                goto out;
        }
 
-       beacon_filter->enable = 0;
+       beacon_filter->enable = enable_filter;
        beacon_filter->max_num_beacons = 0;
 
        ret = wl1251_cmd_configure(wl, ACX_BEACON_FILTER_OPT,
@@ -525,6 +525,7 @@ out:
 int wl1251_acx_beacon_filter_table(struct wl1251 *wl)
 {
        struct acx_beacon_filter_ie_table *ie_table;
+       int idx = 0;
        int ret;
 
        wl1251_debug(DEBUG_ACX, "acx beacon filter table");
@@ -535,8 +536,10 @@ int wl1251_acx_beacon_filter_table(struct wl1251 *wl)
                goto out;
        }
 
-       ie_table->num_ie = 0;
-       memset(ie_table->table, 0, BEACON_FILTER_TABLE_MAX_SIZE);
+       /* configure default beacon pass-through rules */
+       ie_table->num_ie = 1;
+       ie_table->table[idx++] = BEACON_FILTER_IE_ID_CHANNEL_SWITCH_ANN;
+       ie_table->table[idx++] = BEACON_RULE_PASS_ON_APPEARANCE;
 
        ret = wl1251_cmd_configure(wl, ACX_BEACON_FILTER_TABLE,
                                   ie_table, sizeof(*ie_table));
@@ -550,6 +553,35 @@ out:
        return ret;
 }
 
+int wl1251_acx_conn_monit_params(struct wl1251 *wl)
+{
+       struct acx_conn_monit_params *acx;
+       int ret;
+
+       wl1251_debug(DEBUG_ACX, "acx connection monitor parameters");
+
+       acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+       if (!acx) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       acx->synch_fail_thold = SYNCH_FAIL_DEFAULT_THRESHOLD;
+       acx->bss_lose_timeout = NO_BEACON_DEFAULT_TIMEOUT;
+
+       ret = wl1251_cmd_configure(wl, ACX_CONN_MONIT_PARAMS,
+                                  acx, sizeof(*acx));
+       if (ret < 0) {
+               wl1251_warning("failed to set connection monitor "
+                              "parameters: %d", ret);
+               goto out;
+       }
+
+out:
+       kfree(acx);
+       return ret;
+}
+
 int wl1251_acx_sg_enable(struct wl1251 *wl)
 {
        struct acx_bt_wlan_coex *pta;
@@ -916,3 +948,31 @@ out:
        kfree(mem_conf);
        return ret;
 }
+
+int wl1251_acx_wr_tbtt_and_dtim(struct wl1251 *wl, u16 tbtt, u8 dtim)
+{
+       struct wl1251_acx_wr_tbtt_and_dtim *acx;
+       int ret;
+
+       wl1251_debug(DEBUG_ACX, "acx tbtt and dtim");
+
+       acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+       if (!acx) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       acx->tbtt = tbtt;
+       acx->dtim = dtim;
+
+       ret = wl1251_cmd_configure(wl, ACX_WR_TBTT_AND_DTIM,
+                                  acx, sizeof(*acx));
+       if (ret < 0) {
+               wl1251_warning("failed to set tbtt and dtim: %d", ret);
+               goto out;
+       }
+
+out:
+       kfree(acx);
+       return ret;
+}
index cafb914..6523714 100644 (file)
@@ -450,6 +450,11 @@ struct acx_beacon_filter_option {
                           (BEACON_FILTER_TABLE_MAX_VENDOR_SPECIFIC_IE_NUM * \
                            BEACON_FILTER_TABLE_EXTRA_VENDOR_SPECIFIC_IE_SIZE))
 
+#define BEACON_RULE_PASS_ON_CHANGE                     BIT(0)
+#define BEACON_RULE_PASS_ON_APPEARANCE                 BIT(1)
+
+#define BEACON_FILTER_IE_ID_CHANNEL_SWITCH_ANN         (37)
+
 struct acx_beacon_filter_ie_table {
        struct acx_header header;
 
@@ -458,6 +463,16 @@ struct acx_beacon_filter_ie_table {
        u8 pad[3];
 } __attribute__ ((packed));
 
+#define SYNCH_FAIL_DEFAULT_THRESHOLD    10     /* number of beacons */
+#define NO_BEACON_DEFAULT_TIMEOUT       (500) /* in microseconds */
+
+struct acx_conn_monit_params {
+       struct acx_header header;
+
+       u32 synch_fail_thold; /* number of beacons missed */
+       u32 bss_lose_timeout; /* number of TU's from synch fail */
+};
+
 enum {
        SG_ENABLE = 0,
        SG_DISABLE,
@@ -1134,6 +1149,23 @@ struct wl1251_acx_mem_map {
        u32 num_rx_mem_blocks;
 } __attribute__ ((packed));
 
+
+struct wl1251_acx_wr_tbtt_and_dtim {
+
+       struct acx_header header;
+
+       /* Time in TUs between two consecutive beacons */
+       u16 tbtt;
+
+       /*
+        * DTIM period
+        * For BSS: Number of TBTTs in a DTIM period (range: 1-10)
+        * For IBSS: value shall be set to 1
+       */
+       u8  dtim;
+       u8  padding;
+} __attribute__ ((packed));
+
 /*************************************************************************
 
     Host Interrupt Register (WiLink -> Host)
@@ -1273,8 +1305,9 @@ int wl1251_acx_slot(struct wl1251 *wl, enum acx_slot_type slot_time);
 int wl1251_acx_group_address_tbl(struct wl1251 *wl);
 int wl1251_acx_service_period_timeout(struct wl1251 *wl);
 int wl1251_acx_rts_threshold(struct wl1251 *wl, u16 rts_threshold);
-int wl1251_acx_beacon_filter_opt(struct wl1251 *wl);
+int wl1251_acx_beacon_filter_opt(struct wl1251 *wl, bool enable_filter);
 int wl1251_acx_beacon_filter_table(struct wl1251 *wl);
+int wl1251_acx_conn_monit_params(struct wl1251 *wl);
 int wl1251_acx_sg_enable(struct wl1251 *wl);
 int wl1251_acx_sg_cfg(struct wl1251 *wl);
 int wl1251_acx_cca_threshold(struct wl1251 *wl);
@@ -1288,5 +1321,6 @@ int wl1251_acx_statistics(struct wl1251 *wl, struct acx_statistics *stats);
 int wl1251_acx_tsf_info(struct wl1251 *wl, u64 *mactime);
 int wl1251_acx_rate_policies(struct wl1251 *wl);
 int wl1251_acx_mem_cfg(struct wl1251 *wl);
+int wl1251_acx_wr_tbtt_and_dtim(struct wl1251 *wl, u16 tbtt, u8 dtim);
 
 #endif /* __WL1251_ACX_H__ */
index 452d748..2e733e7 100644 (file)
@@ -296,8 +296,12 @@ int wl1251_boot_run_firmware(struct wl1251 *wl)
                WL1251_ACX_INTR_INIT_COMPLETE;
        wl1251_boot_target_enable_interrupts(wl);
 
-       /* unmask all mbox events  */
-       wl->event_mask = 0xffffffff;
+       wl->event_mask = SCAN_COMPLETE_EVENT_ID | BSS_LOSE_EVENT_ID |
+               SYNCHRONIZATION_TIMEOUT_EVENT_ID |
+               ROAMING_TRIGGER_LOW_RSSI_EVENT_ID |
+               ROAMING_TRIGGER_REGAINED_RSSI_EVENT_ID |
+               REGAINED_BSS_EVENT_ID | BT_PTA_SENSE_EVENT_ID |
+               BT_PTA_PREDICTION_EVENT_ID;
 
        ret = wl1251_event_unmask(wl);
        if (ret < 0) {
@@ -314,8 +318,8 @@ int wl1251_boot_run_firmware(struct wl1251 *wl)
 static int wl1251_boot_upload_firmware(struct wl1251 *wl)
 {
        int addr, chunk_num, partition_limit;
-       size_t fw_data_len;
-       u8 *p;
+       size_t fw_data_len, len;
+       u8 *p, *buf;
 
        /* whal_FwCtrl_LoadFwImageSm() */
 
@@ -334,6 +338,12 @@ static int wl1251_boot_upload_firmware(struct wl1251 *wl)
                return -EIO;
        }
 
+       buf = kmalloc(CHUNK_SIZE, GFP_KERNEL);
+       if (!buf) {
+               wl1251_error("allocation for firmware upload chunk failed");
+               return -ENOMEM;
+       }
+
        wl1251_set_partition(wl, WL1251_PART_DOWN_MEM_START,
                             WL1251_PART_DOWN_MEM_SIZE,
                             WL1251_PART_DOWN_REG_START,
@@ -364,7 +374,11 @@ static int wl1251_boot_upload_firmware(struct wl1251 *wl)
                p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE;
                wl1251_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x",
                             p, addr);
-               wl1251_mem_write(wl, addr, p, CHUNK_SIZE);
+
+               /* need to copy the chunk for dma */
+               len = CHUNK_SIZE;
+               memcpy(buf, p, len);
+               wl1251_mem_write(wl, addr, buf, len);
 
                chunk_num++;
        }
@@ -372,9 +386,16 @@ static int wl1251_boot_upload_firmware(struct wl1251 *wl)
        /* 10.4 upload the last chunk */
        addr = WL1251_PART_DOWN_MEM_START + chunk_num * CHUNK_SIZE;
        p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE;
+
+       /* need to copy the chunk for dma */
+       len = fw_data_len % CHUNK_SIZE;
+       memcpy(buf, p, len);
+
        wl1251_debug(DEBUG_BOOT, "uploading fw last chunk (%zu B) 0x%p to 0x%x",
-                    fw_data_len % CHUNK_SIZE, p, addr);
-       wl1251_mem_write(wl, addr, p, fw_data_len % CHUNK_SIZE);
+                    len, p, addr);
+       wl1251_mem_write(wl, addr, buf, len);
+
+       kfree(buf);
 
        return 0;
 }
@@ -473,13 +494,19 @@ int wl1251_boot(struct wl1251 *wl)
                goto out;
 
        /* 2. start processing NVS file */
-       ret = wl1251_boot_upload_nvs(wl);
-       if (ret < 0)
-               goto out;
-
-       /* write firmware's last address (ie. it's length) to
-        * ACX_EEPROMLESS_IND_REG */
-       wl1251_reg_write32(wl, ACX_EEPROMLESS_IND_REG, wl->fw_len);
+       if (wl->use_eeprom) {
+               wl1251_reg_write32(wl, ACX_REG_EE_START, START_EEPROM_MGR);
+               msleep(4000);
+               wl1251_reg_write32(wl, ACX_EEPROMLESS_IND_REG, USE_EEPROM);
+       } else {
+               ret = wl1251_boot_upload_nvs(wl);
+               if (ret < 0)
+                       goto out;
+
+               /* write firmware's last address (ie. it's length) to
+                * ACX_EEPROMLESS_IND_REG */
+               wl1251_reg_write32(wl, ACX_EEPROMLESS_IND_REG, wl->fw_len);
+       }
 
        /* 6. read the EEPROM parameters */
        tmp = wl1251_reg_read32(wl, SCR_PAD2);
index 00076c4..020d764 100644 (file)
@@ -79,6 +79,21 @@ static int wl1251_event_process(struct wl1251 *wl, struct event_mailbox *mbox)
                }
        }
 
+       if (vector & SYNCHRONIZATION_TIMEOUT_EVENT_ID && wl->psm) {
+               wl1251_debug(DEBUG_EVENT, "SYNCHRONIZATION_TIMEOUT_EVENT");
+
+               /* indicate to the stack, that beacons have been lost */
+               ieee80211_beacon_loss(wl->vif);
+       }
+
+       if (vector & REGAINED_BSS_EVENT_ID) {
+               if (wl->psm_requested) {
+                       ret = wl1251_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
+                       if (ret < 0)
+                               return ret;
+               }
+       }
+
        return 0;
 }
 
index b2ee4f4..5cb5733 100644 (file)
@@ -147,7 +147,8 @@ int wl1251_hw_init_beacon_filter(struct wl1251 *wl)
 {
        int ret;
 
-       ret = wl1251_acx_beacon_filter_opt(wl);
+       /* disable beacon filtering at this stage */
+       ret = wl1251_acx_beacon_filter_opt(wl, false);
        if (ret < 0)
                return ret;
 
@@ -364,6 +365,11 @@ int wl1251_hw_init(struct wl1251 *wl)
        if (ret < 0)
                goto out_free_data_path;
 
+       /* Initialize connection monitoring thresholds */
+       ret = wl1251_acx_conn_monit_params(wl);
+       if (ret < 0)
+               goto out_free_data_path;
+
        /* Beacon filtering */
        ret = wl1251_hw_init_beacon_filter(wl);
        if (ret < 0)
index d03a07e..ff4be7b 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/irq.h>
 #include <linux/crc32.h>
 #include <linux/etherdevice.h>
+#include <linux/vmalloc.h>
 
 #include "wl1251.h"
 #include "wl12xx_80211.h"
@@ -83,7 +84,7 @@ static int wl1251_fetch_firmware(struct wl1251 *wl)
        }
 
        wl->fw_len = fw->size;
-       wl->fw = kmalloc(wl->fw_len, GFP_KERNEL);
+       wl->fw = vmalloc(wl->fw_len);
 
        if (!wl->fw) {
                wl1251_error("could not allocate memory for the firmware");
@@ -211,9 +212,10 @@ out:
        return ret;
 }
 
+#define WL1251_IRQ_LOOP_COUNT 10
 static void wl1251_irq_work(struct work_struct *work)
 {
-       u32 intr;
+       u32 intr, ctr = WL1251_IRQ_LOOP_COUNT;
        struct wl1251 *wl =
                container_of(work, struct wl1251, irq_work);
        int ret;
@@ -234,78 +236,86 @@ static void wl1251_irq_work(struct work_struct *work)
        intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR);
        wl1251_debug(DEBUG_IRQ, "intr: 0x%x", intr);
 
-       if (wl->data_path) {
-               wl->rx_counter =
-                       wl1251_mem_read32(wl, wl->data_path->rx_control_addr);
-
-               /* We handle a frmware bug here */
-               switch ((wl->rx_counter - wl->rx_handled) & 0xf) {
-               case 0:
-                       wl1251_debug(DEBUG_IRQ, "RX: FW and host in sync");
-                       intr &= ~WL1251_ACX_INTR_RX0_DATA;
-                       intr &= ~WL1251_ACX_INTR_RX1_DATA;
-                       break;
-               case 1:
-                       wl1251_debug(DEBUG_IRQ, "RX: FW +1");
-                       intr |= WL1251_ACX_INTR_RX0_DATA;
-                       intr &= ~WL1251_ACX_INTR_RX1_DATA;
-                       break;
-               case 2:
-                       wl1251_debug(DEBUG_IRQ, "RX: FW +2");
-                       intr |= WL1251_ACX_INTR_RX0_DATA;
-                       intr |= WL1251_ACX_INTR_RX1_DATA;
-                       break;
-               default:
-                       wl1251_warning("RX: FW and host out of sync: %d",
-                                      wl->rx_counter - wl->rx_handled);
-                       break;
-               }
-
-               wl->rx_handled = wl->rx_counter;
+       do {
+               if (wl->data_path) {
+                       wl->rx_counter = wl1251_mem_read32(
+                               wl, wl->data_path->rx_control_addr);
+
+                       /* We handle a frmware bug here */
+                       switch ((wl->rx_counter - wl->rx_handled) & 0xf) {
+                       case 0:
+                               wl1251_debug(DEBUG_IRQ,
+                                            "RX: FW and host in sync");
+                               intr &= ~WL1251_ACX_INTR_RX0_DATA;
+                               intr &= ~WL1251_ACX_INTR_RX1_DATA;
+                               break;
+                       case 1:
+                               wl1251_debug(DEBUG_IRQ, "RX: FW +1");
+                               intr |= WL1251_ACX_INTR_RX0_DATA;
+                               intr &= ~WL1251_ACX_INTR_RX1_DATA;
+                               break;
+                       case 2:
+                               wl1251_debug(DEBUG_IRQ, "RX: FW +2");
+                               intr |= WL1251_ACX_INTR_RX0_DATA;
+                               intr |= WL1251_ACX_INTR_RX1_DATA;
+                               break;
+                       default:
+                               wl1251_warning(
+                                       "RX: FW and host out of sync: %d",
+                                       wl->rx_counter - wl->rx_handled);
+                               break;
+                       }
 
+                       wl->rx_handled = wl->rx_counter;
 
-               wl1251_debug(DEBUG_IRQ, "RX counter: %d", wl->rx_counter);
-       }
+                       wl1251_debug(DEBUG_IRQ, "RX counter: %d",
+                                    wl->rx_counter);
+               }
 
-       intr &= wl->intr_mask;
+               intr &= wl->intr_mask;
 
-       if (intr == 0) {
-               wl1251_debug(DEBUG_IRQ, "INTR is 0");
-               wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK,
-                                  ~(wl->intr_mask));
+               if (intr == 0) {
+                       wl1251_debug(DEBUG_IRQ, "INTR is 0");
+                       goto out_sleep;
+               }
 
-               goto out_sleep;
-       }
+               if (intr & WL1251_ACX_INTR_RX0_DATA) {
+                       wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX0_DATA");
+                       wl1251_rx(wl);
+               }
 
-       if (intr & WL1251_ACX_INTR_RX0_DATA) {
-               wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX0_DATA");
-               wl1251_rx(wl);
-       }
+               if (intr & WL1251_ACX_INTR_RX1_DATA) {
+                       wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX1_DATA");
+                       wl1251_rx(wl);
+               }
 
-       if (intr & WL1251_ACX_INTR_RX1_DATA) {
-               wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX1_DATA");
-               wl1251_rx(wl);
-       }
+               if (intr & WL1251_ACX_INTR_TX_RESULT) {
+                       wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_TX_RESULT");
+                       wl1251_tx_complete(wl);
+               }
 
-       if (intr & WL1251_ACX_INTR_TX_RESULT) {
-               wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_TX_RESULT");
-               wl1251_tx_complete(wl);
-       }
+               if (intr & (WL1251_ACX_INTR_EVENT_A |
+                           WL1251_ACX_INTR_EVENT_B)) {
+                       wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT (0x%x)",
+                                    intr);
+                       if (intr & WL1251_ACX_INTR_EVENT_A)
+                               wl1251_event_handle(wl, 0);
+                       else
+                               wl1251_event_handle(wl, 1);
+               }
 
-       if (intr & (WL1251_ACX_INTR_EVENT_A | WL1251_ACX_INTR_EVENT_B)) {
-               wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT (0x%x)", intr);
-               if (intr & WL1251_ACX_INTR_EVENT_A)
-                       wl1251_event_handle(wl, 0);
-               else
-                       wl1251_event_handle(wl, 1);
-       }
+               if (intr & WL1251_ACX_INTR_INIT_COMPLETE)
+                       wl1251_debug(DEBUG_IRQ,
+                                    "WL1251_ACX_INTR_INIT_COMPLETE");
 
-       if (intr & WL1251_ACX_INTR_INIT_COMPLETE)
-               wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_INIT_COMPLETE");
+               if (--ctr == 0)
+                       break;
 
-       wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask));
+               intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR);
+       } while (intr);
 
 out_sleep:
+       wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask));
        wl1251_ps_elp_sleep(wl);
 
 out:
@@ -509,6 +519,12 @@ static int wl1251_op_add_interface(struct ieee80211_hw *hw,
                     conf->type, conf->mac_addr);
 
        mutex_lock(&wl->mutex);
+       if (wl->vif) {
+               ret = -EBUSY;
+               goto out;
+       }
+
+       wl->vif = conf->vif;
 
        switch (conf->type) {
        case NL80211_IFTYPE_STATION:
@@ -538,7 +554,12 @@ out:
 static void wl1251_op_remove_interface(struct ieee80211_hw *hw,
                                         struct ieee80211_if_init_conf *conf)
 {
+       struct wl1251 *wl = hw->priv;
+
+       mutex_lock(&wl->mutex);
        wl1251_debug(DEBUG_MAC80211, "mac80211 remove interface");
+       wl->vif = NULL;
+       mutex_unlock(&wl->mutex);
 }
 
 static int wl1251_build_null_data(struct wl1251 *wl)
@@ -555,7 +576,8 @@ static int wl1251_build_null_data(struct wl1251 *wl)
 
        memcpy(template.header.sa, wl->mac_addr, ETH_ALEN);
        template.header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA |
-                                               IEEE80211_STYPE_NULLFUNC);
+                                               IEEE80211_STYPE_NULLFUNC |
+                                               IEEE80211_FCTL_TODS);
 
        return wl1251_cmd_template_set(wl, CMD_NULL_DATA, &template,
                                       sizeof(template));
@@ -568,7 +590,10 @@ static int wl1251_build_ps_poll(struct wl1251 *wl, u16 aid)
 
        memcpy(template.bssid, wl->bssid, ETH_ALEN);
        memcpy(template.ta, wl->mac_addr, ETH_ALEN);
-       template.aid = aid;
+
+       /* aid in PS-Poll has its two MSBs each set to 1 */
+       template.aid = cpu_to_le16(1 << 15 | 1 << 14 | aid);
+
        template.fc = cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL);
 
        return wl1251_cmd_template_set(wl, CMD_PS_POLL, &template,
@@ -1090,8 +1115,8 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw,
                        wl->beacon_int = bss_conf->beacon_int;
                        wl->dtim_period = bss_conf->dtim_period;
 
-                       /* FIXME: call join */
-
+                       ret = wl1251_acx_wr_tbtt_and_dtim(wl, wl->beacon_int,
+                                                         wl->dtim_period);
                        wl->aid = bss_conf->aid;
 
                        ret = wl1251_build_ps_poll(wl, wl->aid);
@@ -1312,7 +1337,8 @@ int wl1251_init_ieee80211(struct wl1251 *wl)
 
        wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
                IEEE80211_HW_NOISE_DBM |
-               IEEE80211_HW_SUPPORTS_PS;
+               IEEE80211_HW_SUPPORTS_PS |
+               IEEE80211_HW_BEACON_FILTER;
 
        wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
        wl->hw->wiphy->max_scan_ssids = 1;
@@ -1355,6 +1381,7 @@ struct ieee80211_hw *wl1251_alloc_hw(void)
        skb_queue_head_init(&wl->tx_queue);
 
        INIT_WORK(&wl->filter_work, wl1251_filter_work);
+       INIT_DELAYED_WORK(&wl->elp_work, wl1251_elp_work);
        wl->channel = WL1251_DEFAULT_CHANNEL;
        wl->scanning = false;
        wl->default_key = 0;
@@ -1372,6 +1399,7 @@ struct ieee80211_hw *wl1251_alloc_hw(void)
        wl->power_level = WL1251_DEFAULT_POWER_LEVEL;
        wl->beacon_int = WL1251_DEFAULT_BEACON_INT;
        wl->dtim_period = WL1251_DEFAULT_DTIM_PERIOD;
+       wl->vif = NULL;
 
        for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++)
                wl->tx_frames[i] = NULL;
@@ -1413,7 +1441,7 @@ int wl1251_free_hw(struct wl1251 *wl)
 
        kfree(wl->target_mem_map);
        kfree(wl->data_path);
-       kfree(wl->fw);
+       vfree(wl->fw);
        wl->fw = NULL;
        kfree(wl->nvs);
        wl->nvs = NULL;
index c53e287..9931b19 100644 (file)
 
 #define WL1251_WAKEUP_TIMEOUT 2000
 
-/* Routines to toggle sleep mode while in ELP */
-void wl1251_ps_elp_sleep(struct wl1251 *wl)
+void wl1251_elp_work(struct work_struct *work)
 {
+       struct delayed_work *dwork;
+       struct wl1251 *wl;
+
+       dwork = container_of(work, struct delayed_work, work);
+       wl = container_of(dwork, struct wl1251, elp_work);
+
+       wl1251_debug(DEBUG_PSM, "elp work");
+
+       mutex_lock(&wl->mutex);
+
        if (wl->elp || !wl->psm)
-               return;
+               goto out;
 
        wl1251_debug(DEBUG_PSM, "chip to elp");
-
        wl1251_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP);
-
        wl->elp = true;
+
+out:
+       mutex_unlock(&wl->mutex);
+}
+
+#define ELP_ENTRY_DELAY  5
+
+/* Routines to toggle sleep mode while in ELP */
+void wl1251_ps_elp_sleep(struct wl1251 *wl)
+{
+       unsigned long delay;
+
+       if (wl->psm) {
+               cancel_delayed_work(&wl->elp_work);
+               delay = msecs_to_jiffies(ELP_ENTRY_DELAY);
+               ieee80211_queue_delayed_work(wl->hw, &wl->elp_work, delay);
+       }
 }
 
 int wl1251_ps_elp_wakeup(struct wl1251 *wl)
@@ -119,6 +143,11 @@ int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode)
        case STATION_POWER_SAVE_MODE:
                wl1251_debug(DEBUG_PSM, "entering psm");
 
+               /* enable beacon filtering */
+               ret = wl1251_acx_beacon_filter_opt(wl, true);
+               if (ret < 0)
+                       return ret;
+
                ret = wl1251_acx_wake_up_conditions(wl,
                                                    WAKE_UP_EVENT_DTIM_BITMAP,
                                                    wl->listen_int);
@@ -142,6 +171,11 @@ int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode)
                if (ret < 0)
                        return ret;
 
+               /* disable beacon filtering */
+               ret = wl1251_acx_beacon_filter_opt(wl, false);
+               if (ret < 0)
+                       return ret;
+
                ret = wl1251_acx_wake_up_conditions(wl,
                                                    WAKE_UP_EVENT_DTIM_BITMAP,
                                                    wl->listen_int);
index db036fe..c688ac5 100644 (file)
@@ -31,6 +31,7 @@
 int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode);
 void wl1251_ps_elp_sleep(struct wl1251 *wl);
 int wl1251_ps_elp_wakeup(struct wl1251 *wl);
+void wl1251_elp_work(struct work_struct *work);
 
 
 #endif /* __WL1251_PS_H__ */
index 06e1bd9..0ca3b43 100644 (file)
@@ -370,6 +370,7 @@ enum wl12xx_acx_int_reg {
  EEPROM location specified in the EE_ADDR register.
  The Wlan hardware hardware clears this bit automatically.
 *===============================================*/
+#define EE_CTL                              (REGISTERS_BASE + 0x2000)
 #define ACX_EE_CTL_REG                      EE_CTL
 #define EE_WRITE                            0x00000001ul
 #define EE_READ                             0x00000002ul
@@ -380,6 +381,7 @@ enum wl12xx_acx_int_reg {
   This register specifies the address
   within the EEPROM from/to which to read/write data.
   ===============================================*/
+#define EE_ADDR                             (REGISTERS_BASE + 0x2008)
 #define ACX_EE_ADDR_REG                     EE_ADDR
 
 /*===============================================
@@ -389,8 +391,12 @@ enum wl12xx_acx_int_reg {
   data from the EEPROM or the write data
   to be written to the EEPROM.
   ===============================================*/
+#define EE_DATA                             (REGISTERS_BASE + 0x2004)
 #define ACX_EE_DATA_REG                     EE_DATA
 
+#define EEPROM_ACCESS_TO                    10000   /* timeout counter */
+#define START_EEPROM_MGR                    0x00000001
+
 /*===============================================
   EEPROM Base Address  - 32bit RW
   ------------------------------------------
index 601fe0d..f84cc89 100644 (file)
@@ -72,10 +72,6 @@ static void wl1251_rx_status(struct wl1251 *wl,
        }
 
        status->signal = desc->rssi;
-       status->qual = (desc->rssi - WL1251_RX_MIN_RSSI) * 100 /
-               (WL1251_RX_MAX_RSSI - WL1251_RX_MIN_RSSI);
-       status->qual = min(status->qual, 100);
-       status->qual = max(status->qual, 0);
 
        /*
         * FIXME: guessing that snr needs to be divided by two, otherwise
index 2cf8a21..9cc8c32 100644 (file)
@@ -270,6 +270,8 @@ static int __devinit wl1251_spi_probe(struct spi_device *spi)
                return -ENODEV;
        }
 
+       wl->use_eeprom = pdata->use_eeprom;
+
        ret = request_irq(wl->irq, wl1251_irq, 0, DRIVER_NAME, wl);
        if (ret < 0) {
                wl1251_error("request_irq() failed: %d", ret);
index 4f1e0cf..891bdab 100644 (file)
@@ -381,7 +381,7 @@ static void wl3501_free_tx_buffer(struct wl3501_card *this, u16 ptr)
 
 static int wl3501_esbq_req_test(struct wl3501_card *this)
 {
-       u8 tmp;
+       u8 tmp = 0;
 
        wl3501_get_from_wla(this, this->esbq_req_head + 3, &tmp, sizeof(tmp));
        return tmp & 0x80;
index 579b114..5681ebe 100644 (file)
@@ -140,6 +140,19 @@ static void ssb_device_put(struct ssb_device *dev)
                put_device(dev->dev);
 }
 
+static inline struct ssb_driver *ssb_driver_get(struct ssb_driver *drv)
+{
+       if (drv)
+               get_driver(&drv->drv);
+       return drv;
+}
+
+static inline void ssb_driver_put(struct ssb_driver *drv)
+{
+       if (drv)
+               put_driver(&drv->drv);
+}
+
 static int ssb_device_resume(struct device *dev)
 {
        struct ssb_device *ssb_dev = dev_to_ssb_dev(dev);
@@ -210,90 +223,81 @@ int ssb_bus_suspend(struct ssb_bus *bus)
 EXPORT_SYMBOL(ssb_bus_suspend);
 
 #ifdef CONFIG_SSB_SPROM
-int ssb_devices_freeze(struct ssb_bus *bus)
+/** ssb_devices_freeze - Freeze all devices on the bus.
+ *
+ * After freezing no device driver will be handling a device
+ * on this bus anymore. ssb_devices_thaw() must be called after
+ * a successful freeze to reactivate the devices.
+ *
+ * @bus: The bus.
+ * @ctx: Context structure. Pass this to ssb_devices_thaw().
+ */
+int ssb_devices_freeze(struct ssb_bus *bus, struct ssb_freeze_context *ctx)
 {
-       struct ssb_device *dev;
-       struct ssb_driver *drv;
-       int err = 0;
-       int i;
-       pm_message_t state = PMSG_FREEZE;
+       struct ssb_device *sdev;
+       struct ssb_driver *sdrv;
+       unsigned int i;
+
+       memset(ctx, 0, sizeof(*ctx));
+       ctx->bus = bus;
+       SSB_WARN_ON(bus->nr_devices > ARRAY_SIZE(ctx->device_frozen));
 
-       /* First check that we are capable to freeze all devices. */
        for (i = 0; i < bus->nr_devices; i++) {
-               dev = &(bus->devices[i]);
-               if (!dev->dev ||
-                   !dev->dev->driver ||
-                   !device_is_registered(dev->dev))
-                       continue;
-               drv = drv_to_ssb_drv(dev->dev->driver);
-               if (!drv)
+               sdev = ssb_device_get(&bus->devices[i]);
+
+               if (!sdev->dev || !sdev->dev->driver ||
+                   !device_is_registered(sdev->dev)) {
+                       ssb_device_put(sdev);
                        continue;
-               if (!drv->suspend) {
-                       /* Nope, can't suspend this one. */
-                       return -EOPNOTSUPP;
                }
-       }
-       /* Now suspend all devices */
-       for (i = 0; i < bus->nr_devices; i++) {
-               dev = &(bus->devices[i]);
-               if (!dev->dev ||
-                   !dev->dev->driver ||
-                   !device_is_registered(dev->dev))
-                       continue;
-               drv = drv_to_ssb_drv(dev->dev->driver);
-               if (!drv)
+               sdrv = ssb_driver_get(drv_to_ssb_drv(sdev->dev->driver));
+               if (!sdrv || SSB_WARN_ON(!sdrv->remove)) {
+                       ssb_device_put(sdev);
                        continue;
-               err = drv->suspend(dev, state);
-               if (err) {
-                       ssb_printk(KERN_ERR PFX "Failed to freeze device %s\n",
-                                  dev_name(dev->dev));
-                       goto err_unwind;
                }
+               sdrv->remove(sdev);
+               ctx->device_frozen[i] = 1;
        }
 
        return 0;
-err_unwind:
-       for (i--; i >= 0; i--) {
-               dev = &(bus->devices[i]);
-               if (!dev->dev ||
-                   !dev->dev->driver ||
-                   !device_is_registered(dev->dev))
-                       continue;
-               drv = drv_to_ssb_drv(dev->dev->driver);
-               if (!drv)
-                       continue;
-               if (drv->resume)
-                       drv->resume(dev);
-       }
-       return err;
 }
 
-int ssb_devices_thaw(struct ssb_bus *bus)
+/** ssb_devices_thaw - Unfreeze all devices on the bus.
+ *
+ * This will re-attach the device drivers and re-init the devices.
+ *
+ * @ctx: The context structure from ssb_devices_freeze()
+ */
+int ssb_devices_thaw(struct ssb_freeze_context *ctx)
 {
-       struct ssb_device *dev;
-       struct ssb_driver *drv;
-       int err;
-       int i;
+       struct ssb_bus *bus = ctx->bus;
+       struct ssb_device *sdev;
+       struct ssb_driver *sdrv;
+       unsigned int i;
+       int err, result = 0;
 
        for (i = 0; i < bus->nr_devices; i++) {
-               dev = &(bus->devices[i]);
-               if (!dev->dev ||
-                   !dev->dev->driver ||
-                   !device_is_registered(dev->dev))
+               if (!ctx->device_frozen[i])
                        continue;
-               drv = drv_to_ssb_drv(dev->dev->driver);
-               if (!drv)
+               sdev = &bus->devices[i];
+
+               if (SSB_WARN_ON(!sdev->dev || !sdev->dev->driver))
                        continue;
-               if (SSB_WARN_ON(!drv->resume))
+               sdrv = drv_to_ssb_drv(sdev->dev->driver);
+               if (SSB_WARN_ON(!sdrv || !sdrv->probe))
                        continue;
-               err = drv->resume(dev);
+
+               err = sdrv->probe(sdev, &sdev->id);
                if (err) {
                        ssb_printk(KERN_ERR PFX "Failed to thaw device %s\n",
-                                  dev_name(dev->dev));
+                                  dev_name(sdev->dev));
+                       result = err;
                }
+               ssb_driver_put(sdrv);
+               ssb_device_put(sdev);
        }
 
-       return 0;
+       return result;
 }
 #endif /* CONFIG_SSB_SPROM */
 
index e8b89e8..0d6c028 100644 (file)
@@ -354,7 +354,7 @@ int ssb_bus_scan(struct ssb_bus *bus,
                dev->bus = bus;
                dev->ops = bus->ops;
 
-               ssb_dprintk(KERN_INFO PFX
+               printk(KERN_DEBUG PFX
                            "Core %d found: %s "
                            "(cc 0x%03X, rev 0x%02X, vendor 0x%04X)\n",
                            i, ssb_core_name(dev->id.coreid),
index 8943015..d0e6762 100644 (file)
@@ -13,6 +13,8 @@
 
 #include "ssb_private.h"
 
+#include <linux/ctype.h>
+
 
 static const struct ssb_sprom *fallback_sprom;
 
@@ -33,17 +35,27 @@ static int sprom2hex(const u16 *sprom, char *buf, size_t buf_len,
 static int hex2sprom(u16 *sprom, const char *dump, size_t len,
                     size_t sprom_size_words)
 {
-       char tmp[5] = { 0 };
-       int cnt = 0;
+       char c, tmp[5] = { 0 };
+       int err, cnt = 0;
        unsigned long parsed;
 
-       if (len < sprom_size_words * 2)
+       /* Strip whitespace at the end. */
+       while (len) {
+               c = dump[len - 1];
+               if (!isspace(c) && c != '\0')
+                       break;
+               len--;
+       }
+       /* Length must match exactly. */
+       if (len != sprom_size_words * 4)
                return -EINVAL;
 
        while (cnt < sprom_size_words) {
                memcpy(tmp, dump, 4);
                dump += 4;
-               parsed = simple_strtoul(tmp, NULL, 16);
+               err = strict_strtoul(tmp, 16, &parsed);
+               if (err)
+                       return err;
                sprom[cnt++] = swab16((u16)parsed);
        }
 
@@ -90,6 +102,7 @@ ssize_t ssb_attr_sprom_store(struct ssb_bus *bus,
        u16 *sprom;
        int res = 0, err = -ENOMEM;
        size_t sprom_size_words = bus->sprom_size;
+       struct ssb_freeze_context freeze;
 
        sprom = kcalloc(bus->sprom_size, sizeof(u16), GFP_KERNEL);
        if (!sprom)
@@ -111,18 +124,13 @@ ssize_t ssb_attr_sprom_store(struct ssb_bus *bus,
        err = -ERESTARTSYS;
        if (mutex_lock_interruptible(&bus->sprom_mutex))
                goto out_kfree;
-       err = ssb_devices_freeze(bus);
-       if (err == -EOPNOTSUPP) {
-               ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze devices. "
-                          "No suspend support. Is CONFIG_PM enabled?\n");
-               goto out_unlock;
-       }
+       err = ssb_devices_freeze(bus, &freeze);
        if (err) {
                ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze all devices\n");
                goto out_unlock;
        }
        res = sprom_write(bus, sprom);
-       err = ssb_devices_thaw(bus);
+       err = ssb_devices_thaw(&freeze);
        if (err)
                ssb_printk(KERN_ERR PFX "SPROM write: Could not thaw all devices\n");
 out_unlock:
index 2543356..56054be 100644 (file)
@@ -176,13 +176,21 @@ extern const struct ssb_sprom *ssb_get_fallback_sprom(void);
 
 /* core.c */
 extern u32 ssb_calc_clock_rate(u32 plltype, u32 n, u32 m);
-extern int ssb_devices_freeze(struct ssb_bus *bus);
-extern int ssb_devices_thaw(struct ssb_bus *bus);
 extern struct ssb_bus *ssb_pci_dev_to_bus(struct pci_dev *pdev);
 int ssb_for_each_bus_call(unsigned long data,
                          int (*func)(struct ssb_bus *bus, unsigned long data));
 extern struct ssb_bus *ssb_pcmcia_dev_to_bus(struct pcmcia_device *pdev);
 
+struct ssb_freeze_context {
+       /* Pointer to the bus */
+       struct ssb_bus *bus;
+       /* Boolean list to indicate whether a device is frozen on this bus. */
+       bool device_frozen[SSB_MAX_NR_CORES];
+};
+extern int ssb_devices_freeze(struct ssb_bus *bus, struct ssb_freeze_context *ctx);
+extern int ssb_devices_thaw(struct ssb_freeze_context *ctx);
+
+
 
 /* b43_pci_bridge.c */
 #ifdef CONFIG_SSB_B43_PCI_BRIDGE
index 49b1abd..afa8e0a 100644 (file)
 #define IEEE80211_MAX_SSID_LEN         32
 
 #define IEEE80211_MAX_MESH_ID_LEN      32
-#define IEEE80211_MESH_CONFIG_LEN      7
 
 #define IEEE80211_QOS_CTL_LEN          2
 #define IEEE80211_QOS_CTL_TID_MASK     0x000F
@@ -555,6 +554,21 @@ struct ieee80211_tim_ie {
 } __attribute__ ((packed));
 
 /**
+ * struct ieee80211_meshconf_ie
+ *
+ * This structure refers to "Mesh Configuration information element"
+ */
+struct ieee80211_meshconf_ie {
+       u8 meshconf_psel;
+       u8 meshconf_pmetric;
+       u8 meshconf_congest;
+       u8 meshconf_synch;
+       u8 meshconf_auth;
+       u8 meshconf_form;
+       u8 meshconf_cap;
+} __attribute__ ((packed));
+
+/**
  * struct ieee80211_rann_ie
  *
  * This structure refers to "Root Announcement information element"
index 3b2a46b..3a9f410 100644 (file)
@@ -70,6 +70,7 @@
 #define IFF_XMIT_DST_RELEASE 0x400     /* dev_hard_start_xmit() is allowed to
                                         * release skb->dst
                                         */
+#define IFF_DONT_BRIDGE 0x800          /* disallow bridging this ether dev */
 
 #define IF_GET_IFACE   0x0001          /* for querying only */
 #define IF_GET_PROTO   0x0002
index 3392c59..97059d0 100644 (file)
@@ -35,6 +35,8 @@
  * @RFKILL_TYPE_UWB: switch is on a ultra wideband device.
  * @RFKILL_TYPE_WIMAX: switch is on a WiMAX device.
  * @RFKILL_TYPE_WWAN: switch is on a wireless WAN device.
+ * @RFKILL_TYPE_GPS: switch is on a GPS device.
+ * @RFKILL_TYPE_FM: switch is on a FM radio device.
  * @NUM_RFKILL_TYPES: number of defined rfkill types
  */
 enum rfkill_type {
@@ -45,6 +47,7 @@ enum rfkill_type {
        RFKILL_TYPE_WIMAX,
        RFKILL_TYPE_WWAN,
        RFKILL_TYPE_GPS,
+       RFKILL_TYPE_FM,
        NUM_RFKILL_TYPES,
 };
 
index 11430ca..aed64ed 100644 (file)
@@ -26,6 +26,7 @@
 
 struct wl12xx_platform_data {
        void (*set_power)(bool enable);
+       bool use_eeprom;
 };
 
 #endif
index 21710fc..a6492e9 100644 (file)
@@ -1108,27 +1108,50 @@ struct cfg80211_ops {
  */
 
 /**
- * struct wiphy - wireless hardware description
- * @idx: the wiphy index assigned to this item
- * @class_dev: the class device representing /sys/class/ieee80211/<wiphy-name>
- * @custom_regulatory: tells us the driver for this device
+ * enum wiphy_flags - wiphy capability flags
+ *
+ * @WIPHY_FLAG_CUSTOM_REGULATORY:  tells us the driver for this device
  *     has its own custom regulatory domain and cannot identify the
  *     ISO / IEC 3166 alpha2 it belongs to. When this is enabled
  *     we will disregard the first regulatory hint (when the
  *     initiator is %REGDOM_SET_BY_CORE).
- * @strict_regulatory: tells us the driver for this device will ignore
- *     regulatory domain settings until it gets its own regulatory domain
- *     via its regulatory_hint(). After its gets its own regulatory domain
- *     it will only allow further regulatory domain settings to further
- *     enhance compliance. For example if channel 13 and 14 are disabled
- *     by this regulatory domain no user regulatory domain can enable these
- *     channels at a later time. This can be used for devices which do not
- *     have calibration information gauranteed for frequencies or settings
- *     outside of its regulatory domain.
- * @disable_beacon_hints: enable this if your driver needs to ensure that
- *     passive scan flags and beaconing flags may not be lifted by cfg80211
- *     due to regulatory beacon hints. For more information on beacon
+ * @WIPHY_FLAG_STRICT_REGULATORY: tells us the driver for this device will
+ *     ignore regulatory domain settings until it gets its own regulatory
+ *     domain via its regulatory_hint(). After its gets its own regulatory
+ *     domain it will only allow further regulatory domain settings to
+ *     further enhance compliance. For example if channel 13 and 14 are
+ *     disabled by this regulatory domain no user regulatory domain can
+ *     enable these channels at a later time. This can be used for devices
+ *     which do not have calibration information gauranteed for frequencies
+ *     or settings outside of its regulatory domain.
+ * @WIPHY_FLAG_DISABLE_BEACON_HINTS: enable this if your driver needs to ensure
+ *     that passive scan flags and beaconing flags may not be lifted by
+ *     cfg80211 due to regulatory beacon hints. For more information on beacon
  *     hints read the documenation for regulatory_hint_found_beacon()
+ * @WIPHY_FLAG_NETNS_OK: if not set, do not allow changing the netns of this
+ *     wiphy at all
+ * @WIPHY_FLAG_PS_ON_BY_DEFAULT: if set to true, powersave will be enabled
+ *     by default -- this flag will be set depending on the kernel's default
+ *     on wiphy_new(), but can be changed by the driver if it has a good
+ *     reason to override the default
+ * @WIPHY_FLAG_4ADDR_AP: supports 4addr mode even on AP (with a single station
+ *     on a VLAN interface)
+ * @WIPHY_FLAG_4ADDR_STATION: supports 4addr mode even as a station
+ */
+enum wiphy_flags {
+       WIPHY_FLAG_CUSTOM_REGULATORY    = BIT(0),
+       WIPHY_FLAG_STRICT_REGULATORY    = BIT(1),
+       WIPHY_FLAG_DISABLE_BEACON_HINTS = BIT(2),
+       WIPHY_FLAG_NETNS_OK             = BIT(3),
+       WIPHY_FLAG_PS_ON_BY_DEFAULT     = BIT(4),
+       WIPHY_FLAG_4ADDR_AP             = BIT(5),
+       WIPHY_FLAG_4ADDR_STATION        = BIT(6),
+};
+
+/**
+ * struct wiphy - wireless hardware description
+ * @idx: the wiphy index assigned to this item
+ * @class_dev: the class device representing /sys/class/ieee80211/<wiphy-name>
  * @reg_notifier: the driver's regulatory notification callback
  * @regd: the driver's regulatory domain, if one was requested via
  *     the regulatory_hint() API. This can be used by the driver
@@ -1143,11 +1166,6 @@ struct cfg80211_ops {
  *     -1 = fragmentation disabled, only odd values >= 256 used
  * @rts_threshold: RTS threshold (dot11RTSThreshold); -1 = RTS/CTS disabled
  * @net: the network namespace this wiphy currently lives in
- * @netnsok: if set to false, do not allow changing the netns of this
- *     wiphy at all
- * @ps_default: default for powersave, will be set depending on the
- *     kernel's default on wiphy_new(), but can be changed by the
- *     driver if it has a good reason to override the default
  */
 struct wiphy {
        /* assign these fields before you register the wiphy */
@@ -1158,12 +1176,7 @@ struct wiphy {
        /* Supported interface modes, OR together BIT(NL80211_IFTYPE_...) */
        u16 interface_modes;
 
-       bool custom_regulatory;
-       bool strict_regulatory;
-       bool disable_beacon_hints;
-
-       bool netnsok;
-       bool ps_default;
+       u32 flags;
 
        enum cfg80211_signal_type signal_type;
 
@@ -1358,6 +1371,10 @@ struct cfg80211_cached_keys;
  * @ssid_len: (private) Used by the internal configuration code
  * @wext: (private) Used by the internal wireless extensions compat code
  * @wext_bssid: (private) Used by the internal wireless extensions compat code
+ * @use_4addr: indicates 4addr mode is used on this interface, must be
+ *     set by driver (if supported) on add_interface BEFORE registering the
+ *     netdev and may otherwise be used by driver read-only, will be update
+ *     by cfg80211 on change_interface
  */
 struct wireless_dev {
        struct wiphy *wiphy;
@@ -1371,6 +1388,8 @@ struct wireless_dev {
 
        struct work_struct cleanup_work;
 
+       bool use_4addr;
+
        /* currently used for IBSS and SME - might be rearranged later */
        u8 ssid[IEEE80211_MAX_SSID_LEN];
        u8 ssid_len;
@@ -1820,6 +1839,18 @@ void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len);
 void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr);
 
 /**
+ * __cfg80211_auth_canceled - notify cfg80211 that authentication was canceled
+ * @dev: network device
+ * @addr: The MAC address of the device with which the authentication timed out
+ *
+ * When a pending authentication had no action yet, the driver may decide
+ * to not send a deauth frame, but in that case must calls this function
+ * to tell cfg80211 about this decision. It is only valid to call this
+ * function within the deauth() callback.
+ */
+void __cfg80211_auth_canceled(struct net_device *dev, const u8 *addr);
+
+/**
  * cfg80211_send_rx_assoc - notification of processed association
  * @dev: network device
  * @buf: (re)association response frame (header + body)
index 2c10eac..3754ea4 100644 (file)
@@ -219,7 +219,7 @@ struct ieee80211_bss_conf {
  *
  * These flags are used with the @flags member of &ieee80211_tx_info.
  *
- * @IEEE80211_TX_CTL_REQ_TX_STATUS: request TX status callback for this frame.
+ * @IEEE80211_TX_CTL_REQ_TX_STATUS: require TX status callback for this frame.
  * @IEEE80211_TX_CTL_ASSIGN_SEQ: The driver has to assign a sequence
  *     number to this frame, taking care of not overwriting the fragment
  *     number and increasing the sequence number only when the
@@ -390,10 +390,12 @@ struct ieee80211_tx_rate {
  * @control: union for control data
  * @status: union for status data
  * @driver_data: array of driver_data pointers
- * @ampdu_ack_len: number of aggregated frames.
+ * @ampdu_ack_len: number of acked aggregated frames.
  *     relevant only if IEEE80211_TX_STATUS_AMPDU was set.
  * @ampdu_ack_map: block ack bit map for the aggregation.
  *     relevant only if IEEE80211_TX_STATUS_AMPDU was set.
+ * @ampdu_len: number of aggregated frames.
+ *     relevant only if IEEE80211_TX_STATUS_AMPDU was set.
  * @ack_signal: signal strength of the ACK frame
  */
 struct ieee80211_tx_info {
@@ -428,7 +430,8 @@ struct ieee80211_tx_info {
                        u8 ampdu_ack_len;
                        u64 ampdu_ack_map;
                        int ack_signal;
-                       /* 8 bytes free */
+                       u8 ampdu_len;
+                       /* 7 bytes free */
                } status;
                struct {
                        struct ieee80211_tx_rate driver_rates[
@@ -852,6 +855,19 @@ enum ieee80211_tkip_key_type {
  * any particular flags. There are some exceptions to this rule,
  * however, so you are advised to review these flags carefully.
  *
+ * @IEEE80211_HW_HAS_RATE_CONTROL:
+ *     The hardware or firmware includes rate control, and cannot be
+ *     controlled by the stack. As such, no rate control algorithm
+ *     should be instantiated, and the TX rate reported to userspace
+ *     will be taken from the TX status instead of the rate control
+ *     algorithm.
+ *     Note that this requires that the driver implement a number of
+ *     callbacks so it has the correct information, it needs to have
+ *     the @set_rts_threshold callback and must look at the BSS config
+ *     @use_cts_prot for G/N protection, @use_short_slot for slot
+ *     timing in 2.4 GHz and @use_short_preamble for preambles for
+ *     CCK frames.
+ *
  * @IEEE80211_HW_RX_INCLUDES_FCS:
  *     Indicates that received frames passed to the stack include
  *     the FCS at the end.
@@ -910,6 +926,7 @@ enum ieee80211_tkip_key_type {
  *     avoid waking up cpu.
  */
 enum ieee80211_hw_flags {
+       IEEE80211_HW_HAS_RATE_CONTROL                   = 1<<0,
        IEEE80211_HW_RX_INCLUDES_FCS                    = 1<<1,
        IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING        = 1<<2,
        IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE          = 1<<3,
@@ -1505,6 +1522,7 @@ struct ieee80211_ops {
        void (*reset_tsf)(struct ieee80211_hw *hw);
        int (*tx_last_beacon)(struct ieee80211_hw *hw);
        int (*ampdu_action)(struct ieee80211_hw *hw,
+                           struct ieee80211_vif *vif,
                            enum ieee80211_ampdu_mlme_action action,
                            struct ieee80211_sta *sta, u16 tid, u16 *ssn);
 
@@ -2026,8 +2044,7 @@ void ieee80211_queue_delayed_work(struct ieee80211_hw *hw,
 
 /**
  * ieee80211_start_tx_ba_session - Start a tx Block Ack session.
- * @hw: pointer as obtained from ieee80211_alloc_hw().
- * @ra: receiver address of the BA session recipient
+ * @sta: the station for which to start a BA session
  * @tid: the TID to BA on.
  *
  * Return: success if addBA request was sent, failure otherwise
@@ -2036,22 +2053,22 @@ void ieee80211_queue_delayed_work(struct ieee80211_hw *hw,
  * the need to start aggregation on a certain RA/TID, the session level
  * will be managed by the mac80211.
  */
-int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid);
+int ieee80211_start_tx_ba_session(struct ieee80211_sta *sta, u16 tid);
 
 /**
  * ieee80211_start_tx_ba_cb - low level driver ready to aggregate.
- * @hw: pointer as obtained from ieee80211_alloc_hw().
+ * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf
  * @ra: receiver address of the BA session recipient.
  * @tid: the TID to BA on.
  *
  * This function must be called by low level driver once it has
  * finished with preparations for the BA session.
  */
-void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid);
+void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid);
 
 /**
  * ieee80211_start_tx_ba_cb_irqsafe - low level driver ready to aggregate.
- * @hw: pointer as obtained from ieee80211_alloc_hw().
+ * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf
  * @ra: receiver address of the BA session recipient.
  * @tid: the TID to BA on.
  *
@@ -2059,13 +2076,12 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid);
  * finished with preparations for the BA session.
  * This version of the function is IRQ-safe.
  */
-void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, const u8 *ra,
+void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_vif *vif, const u8 *ra,
                                      u16 tid);
 
 /**
  * ieee80211_stop_tx_ba_session - Stop a Block Ack session.
- * @hw: pointer as obtained from ieee80211_alloc_hw().
- * @ra: receiver address of the BA session recipient
+ * @sta: the station whose BA session to stop
  * @tid: the TID to stop BA.
  * @initiator: if indicates initiator DELBA frame will be sent.
  *
@@ -2075,24 +2091,23 @@ void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, const u8 *ra,
  * the need to stop aggregation on a certain RA/TID, the session level
  * will be managed by the mac80211.
  */
-int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw,
-                                u8 *ra, u16 tid,
+int ieee80211_stop_tx_ba_session(struct ieee80211_sta *sta, u16 tid,
                                 enum ieee80211_back_parties initiator);
 
 /**
  * ieee80211_stop_tx_ba_cb - low level driver ready to stop aggregate.
- * @hw: pointer as obtained from ieee80211_alloc_hw().
+ * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf
  * @ra: receiver address of the BA session recipient.
  * @tid: the desired TID to BA on.
  *
  * This function must be called by low level driver once it has
  * finished with preparations for the BA session tear down.
  */
-void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid);
+void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid);
 
 /**
  * ieee80211_stop_tx_ba_cb_irqsafe - low level driver ready to stop aggregate.
- * @hw: pointer as obtained from ieee80211_alloc_hw().
+ * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf
  * @ra: receiver address of the BA session recipient.
  * @tid: the desired TID to BA on.
  *
@@ -2100,7 +2115,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid);
  * finished with preparations for the BA session tear down.
  * This version of the function is IRQ-safe.
  */
-void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, const u8 *ra,
+void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_vif *vif, const u8 *ra,
                                     u16 tid);
 
 /**
index a6f74b2..a2cbe61 100644 (file)
@@ -390,6 +390,10 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
        if (dev->br_port != NULL)
                return -EBUSY;
 
+       /* No bridging devices that dislike that (e.g. wireless) */
+       if (dev->priv_flags & IFF_DONT_BRIDGE)
+               return -EOPNOTSUPP;
+
        p = new_nbp(br, dev);
        if (IS_ERR(p))
                return PTR_ERR(p);
index 9f3cf71..298cfcc 100644 (file)
@@ -2,7 +2,7 @@ obj-$(CONFIG_MAC80211) += mac80211.o
 
 # mac80211 objects
 mac80211-y := \
-       main.o \
+       main.o status.o \
        sta_info.o \
        wep.o \
        wpa.o \
index bc064d7..7ed5fe6 100644 (file)
@@ -41,7 +41,8 @@ void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
               sta->sta.addr, tid);
 #endif /* CONFIG_MAC80211_HT_DEBUG */
 
-       if (drv_ampdu_action(local, IEEE80211_AMPDU_RX_STOP,
+       if (drv_ampdu_action(local, &sta->sdata->vif,
+                            IEEE80211_AMPDU_RX_STOP,
                             &sta->sta, tid, NULL))
                printk(KERN_DEBUG "HW problem - can not stop rx "
                                "aggregation for tid %d\n", tid);
@@ -170,7 +171,7 @@ static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *d
        mgmt->u.action.u.addba_resp.timeout = cpu_to_le16(timeout);
        mgmt->u.action.u.addba_resp.status = cpu_to_le16(status);
 
-       ieee80211_tx_skb(sdata, skb, 1);
+       ieee80211_tx_skb(sdata, skb);
 }
 
 void ieee80211_process_addba_request(struct ieee80211_local *local,
@@ -284,7 +285,8 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
                goto end;
        }
 
-       ret = drv_ampdu_action(local, IEEE80211_AMPDU_RX_START,
+       ret = drv_ampdu_action(local, &sta->sdata->vif,
+                              IEEE80211_AMPDU_RX_START,
                               &sta->sta, tid, &start_seq_num);
 #ifdef CONFIG_MAC80211_HT_DEBUG
        printk(KERN_DEBUG "Rx A-MPDU request on tid %d result %d\n", tid, ret);
index b09948c..b50b2bc 100644 (file)
@@ -91,7 +91,7 @@ static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata,
        mgmt->u.action.u.addba_req.start_seq_num =
                                        cpu_to_le16(start_seq_num << 4);
 
-       ieee80211_tx_skb(sdata, skb, 1);
+       ieee80211_tx_skb(sdata, skb);
 }
 
 void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u16 ssn)
@@ -120,7 +120,8 @@ void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u1
        bar->control = cpu_to_le16(bar_control);
        bar->start_seq_num = cpu_to_le16(ssn);
 
-       ieee80211_tx_skb(sdata, skb, 0);
+       IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
+       ieee80211_tx_skb(sdata, skb);
 }
 
 static int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
@@ -138,7 +139,8 @@ static int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
        *state = HT_AGG_STATE_REQ_STOP_BA_MSK |
                (initiator << HT_AGG_STATE_INITIATOR_SHIFT);
 
-       ret = drv_ampdu_action(local, IEEE80211_AMPDU_TX_STOP,
+       ret = drv_ampdu_action(local, &sta->sdata->vif,
+                              IEEE80211_AMPDU_TX_STOP,
                               &sta->sta, tid, NULL);
 
        /* HW shall not deny going back to legacy */
@@ -196,11 +198,11 @@ static inline int ieee80211_ac_from_tid(int tid)
        return ieee802_1d_to_ac[tid & 7];
 }
 
-int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
+int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid)
 {
-       struct ieee80211_local *local = hw_to_local(hw);
-       struct sta_info *sta;
-       struct ieee80211_sub_if_data *sdata;
+       struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
+       struct ieee80211_sub_if_data *sdata = sta->sdata;
+       struct ieee80211_local *local = sdata->local;
        u8 *state;
        int ret = 0;
        u16 start_seq_num;
@@ -208,52 +210,37 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
        if (WARN_ON(!local->ops->ampdu_action))
                return -EINVAL;
 
-       if ((tid >= STA_TID_NUM) || !(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION))
+       if ((tid >= STA_TID_NUM) ||
+           !(local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION))
                return -EINVAL;
 
 #ifdef CONFIG_MAC80211_HT_DEBUG
        printk(KERN_DEBUG "Open BA session requested for %pM tid %u\n",
-              ra, tid);
+              pubsta->addr, tid);
 #endif /* CONFIG_MAC80211_HT_DEBUG */
 
-       rcu_read_lock();
-
-       sta = sta_info_get(local, ra);
-       if (!sta) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-               printk(KERN_DEBUG "Could not find the station\n");
-#endif
-               ret = -ENOENT;
-               goto unlock;
-       }
-
        /*
         * The aggregation code is not prepared to handle
         * anything but STA/AP due to the BSSID handling.
         * IBSS could work in the code but isn't supported
         * by drivers or the standard.
         */
-       if (sta->sdata->vif.type != NL80211_IFTYPE_STATION &&
-           sta->sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
-           sta->sdata->vif.type != NL80211_IFTYPE_AP) {
-               ret = -EINVAL;
-               goto unlock;
-       }
+       if (sdata->vif.type != NL80211_IFTYPE_STATION &&
+           sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
+           sdata->vif.type != NL80211_IFTYPE_AP)
+               return -EINVAL;
 
        if (test_sta_flags(sta, WLAN_STA_SUSPEND)) {
 #ifdef CONFIG_MAC80211_HT_DEBUG
                printk(KERN_DEBUG "Suspend in progress. "
                       "Denying BA session request\n");
 #endif
-               ret = -EINVAL;
-               goto unlock;
+               return -EINVAL;
        }
 
        spin_lock_bh(&sta->lock);
        spin_lock(&local->ampdu_lock);
 
-       sdata = sta->sdata;
-
        /* we have tried too many times, receiver does not want A-MPDU */
        if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) {
                ret = -EBUSY;
@@ -310,8 +297,9 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
 
        start_seq_num = sta->tid_seq[tid];
 
-       ret = drv_ampdu_action(local, IEEE80211_AMPDU_TX_START,
-                              &sta->sta, tid, &start_seq_num);
+       ret = drv_ampdu_action(local, &sdata->vif,
+                              IEEE80211_AMPDU_TX_START,
+                              pubsta, tid, &start_seq_num);
 
        if (ret) {
 #ifdef CONFIG_MAC80211_HT_DEBUG
@@ -336,7 +324,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
                        sta->ampdu_mlme.dialog_token_allocator;
        sta->ampdu_mlme.tid_tx[tid]->ssn = start_seq_num;
 
-       ieee80211_send_addba_request(sta->sdata, ra, tid,
+       ieee80211_send_addba_request(sdata, pubsta->addr, tid,
                         sta->ampdu_mlme.tid_tx[tid]->dialog_token,
                         sta->ampdu_mlme.tid_tx[tid]->ssn,
                         0x40, 5000);
@@ -348,7 +336,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
 #ifdef CONFIG_MAC80211_HT_DEBUG
        printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid);
 #endif
-       goto unlock;
+       return 0;
 
  err_free:
        kfree(sta->ampdu_mlme.tid_tx[tid]);
@@ -360,8 +348,6 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
  err_unlock_sta:
        spin_unlock(&local->ampdu_lock);
        spin_unlock_bh(&sta->lock);
- unlock:
-       rcu_read_unlock();
        return ret;
 }
 EXPORT_SYMBOL(ieee80211_start_tx_ba_session);
@@ -428,13 +414,15 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local,
        ieee80211_agg_splice_finish(local, sta, tid);
        spin_unlock(&local->ampdu_lock);
 
-       drv_ampdu_action(local, IEEE80211_AMPDU_TX_OPERATIONAL,
+       drv_ampdu_action(local, &sta->sdata->vif,
+                        IEEE80211_AMPDU_TX_OPERATIONAL,
                         &sta->sta, tid, NULL);
 }
 
-void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid)
+void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid)
 {
-       struct ieee80211_local *local = hw_to_local(hw);
+       struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+       struct ieee80211_local *local = sdata->local;
        struct sta_info *sta;
        u8 *state;
 
@@ -483,10 +471,11 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid)
 }
 EXPORT_SYMBOL(ieee80211_start_tx_ba_cb);
 
-void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw,
+void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_vif *vif,
                                      const u8 *ra, u16 tid)
 {
-       struct ieee80211_local *local = hw_to_local(hw);
+       struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+       struct ieee80211_local *local = sdata->local;
        struct ieee80211_ra_tid *ra_tid;
        struct sk_buff *skb = dev_alloc_skb(0);
 
@@ -501,6 +490,7 @@ void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw,
        ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
        memcpy(&ra_tid->ra, ra, ETH_ALEN);
        ra_tid->tid = tid;
+       ra_tid->vif = vif;
 
        skb->pkt_type = IEEE80211_ADDBA_MSG;
        skb_queue_tail(&local->skb_queue, skb);
@@ -535,13 +525,12 @@ int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
        return ret;
 }
 
-int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw,
-                                u8 *ra, u16 tid,
+int ieee80211_stop_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
                                 enum ieee80211_back_parties initiator)
 {
-       struct ieee80211_local *local = hw_to_local(hw);
-       struct sta_info *sta;
-       int ret = 0;
+       struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
+       struct ieee80211_sub_if_data *sdata = sta->sdata;
+       struct ieee80211_local *local = sdata->local;
 
        if (WARN_ON(!local->ops->ampdu_action))
                return -EINVAL;
@@ -549,22 +538,14 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw,
        if (tid >= STA_TID_NUM)
                return -EINVAL;
 
-       rcu_read_lock();
-       sta = sta_info_get(local, ra);
-       if (!sta) {
-               rcu_read_unlock();
-               return -ENOENT;
-       }
-
-       ret = __ieee80211_stop_tx_ba_session(sta, tid, initiator);
-       rcu_read_unlock();
-       return ret;
+       return __ieee80211_stop_tx_ba_session(sta, tid, initiator);
 }
 EXPORT_SYMBOL(ieee80211_stop_tx_ba_session);
 
-void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid)
+void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid)
 {
-       struct ieee80211_local *local = hw_to_local(hw);
+       struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+       struct ieee80211_local *local = sdata->local;
        struct sta_info *sta;
        u8 *state;
 
@@ -627,10 +608,11 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid)
 }
 EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb);
 
-void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw,
+void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_vif *vif,
                                     const u8 *ra, u16 tid)
 {
-       struct ieee80211_local *local = hw_to_local(hw);
+       struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+       struct ieee80211_local *local = sdata->local;
        struct ieee80211_ra_tid *ra_tid;
        struct sk_buff *skb = dev_alloc_skb(0);
 
@@ -645,6 +627,7 @@ void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw,
        ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
        memcpy(&ra_tid->ra, ra, ETH_ALEN);
        ra_tid->tid = tid;
+       ra_tid->vif = vif;
 
        skb->pkt_type = IEEE80211_DELBA_MSG;
        skb_queue_tail(&local->skb_queue, skb);
index 7f18c8f..93ee1fd 100644 (file)
@@ -42,15 +42,6 @@ static bool nl80211_params_check(enum nl80211_iftype type,
        if (!nl80211_type_check(type))
                return false;
 
-       if (params->use_4addr > 0) {
-               switch(type) {
-               case NL80211_IFTYPE_AP_VLAN:
-               case NL80211_IFTYPE_STATION:
-                       break;
-               default:
-                       return false;
-               }
-       }
        return true;
 }
 
@@ -107,12 +98,16 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
                                            params->mesh_id_len,
                                            params->mesh_id);
 
-       if (params->use_4addr >= 0)
-               sdata->use_4addr = !!params->use_4addr;
-
        if (sdata->vif.type != NL80211_IFTYPE_MONITOR || !flags)
                return 0;
 
+       if (type == NL80211_IFTYPE_AP_VLAN &&
+           params && params->use_4addr == 0)
+               rcu_assign_pointer(sdata->u.vlan.sta, NULL);
+       else if (type == NL80211_IFTYPE_STATION &&
+                params && params->use_4addr >= 0)
+               sdata->u.mgd.use_4addr = params->use_4addr;
+
        sdata->u.mntr_flags = *flags;
        return 0;
 }
@@ -398,13 +393,13 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
 static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev,
                                 int idx, u8 *mac, struct station_info *sinfo)
 {
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct sta_info *sta;
        int ret = -ENOENT;
 
        rcu_read_lock();
 
-       sta = sta_info_get_by_idx(local, idx, dev);
+       sta = sta_info_get_by_idx(sdata, idx);
        if (sta) {
                ret = 0;
                memcpy(mac, sta->sta.addr, ETH_ALEN);
@@ -827,9 +822,11 @@ static int ieee80211_change_station(struct wiphy *wiphy,
                        return -EINVAL;
                }
 
-               if (vlansdata->use_4addr) {
-                       if (vlansdata->u.vlan.sta)
+               if (params->vlan->ieee80211_ptr->use_4addr) {
+                       if (vlansdata->u.vlan.sta) {
+                               rcu_read_unlock();
                                return -EBUSY;
+                       }
 
                        rcu_assign_pointer(vlansdata->u.vlan.sta, sta);
                }
index 82c8077..e4b5409 100644 (file)
@@ -52,7 +52,7 @@ DEBUGFS_READONLY_FILE(total_ps_buffered, 20, "%d",
 DEBUGFS_READONLY_FILE(wep_iv, 20, "%#08x",
                      local->wep_iv & 0xffffff);
 DEBUGFS_READONLY_FILE(rate_ctrl_alg, 100, "%s",
-                     local->rate_ctrl ? local->rate_ctrl->ops->name : "<unset>");
+       local->rate_ctrl ? local->rate_ctrl->ops->name : "hw/driver");
 
 static ssize_t tsf_read(struct file *file, char __user *user_buf,
                             size_t count, loff_t *ppos)
index f043c29..3f41608 100644 (file)
@@ -157,6 +157,34 @@ static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf,
 }
 STA_OPS(agg_status);
 
+static ssize_t sta_ht_capa_read(struct file *file, char __user *userbuf,
+                               size_t count, loff_t *ppos)
+{
+       char buf[200], *p = buf;
+       int i;
+       struct sta_info *sta = file->private_data;
+       struct ieee80211_sta_ht_cap *htc = &sta->sta.ht_cap;
+
+       p += scnprintf(p, sizeof(buf) + buf - p, "ht %ssupported\n",
+                       htc->ht_supported ? "" : "not ");
+       if (htc->ht_supported) {
+               p += scnprintf(p, sizeof(buf)+buf-p, "cap: %#.2x\n", htc->cap);
+               p += scnprintf(p, sizeof(buf)+buf-p, "ampdu factor/density: %d/%d\n",
+                               htc->ampdu_factor, htc->ampdu_density);
+               p += scnprintf(p, sizeof(buf)+buf-p, "MCS mask:");
+               for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
+                       p += scnprintf(p, sizeof(buf)+buf-p, " %.2x",
+                                       htc->mcs.rx_mask[i]);
+               p += scnprintf(p, sizeof(buf)+buf-p, "\nMCS rx highest: %d\n",
+                               le16_to_cpu(htc->mcs.rx_highest));
+               p += scnprintf(p, sizeof(buf)+buf-p, "MCS tx params: %x\n",
+                               htc->mcs.tx_params);
+       }
+
+       return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
+}
+STA_OPS(ht_capa);
+
 #define DEBUGFS_ADD(name) \
        debugfs_create_file(#name, 0400, \
                sta->debugfs.dir, sta, &sta_ ##name## _ops);
@@ -207,6 +235,7 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta)
        DEBUGFS_ADD(last_signal);
        DEBUGFS_ADD(last_noise);
        DEBUGFS_ADD(wep_weak_iv_count);
+       DEBUGFS_ADD(ht_capa);
 }
 
 void ieee80211_sta_debugfs_remove(struct sta_info *sta)
index 020a94a..921dd9c 100644 (file)
@@ -239,15 +239,16 @@ static inline int drv_tx_last_beacon(struct ieee80211_local *local)
 }
 
 static inline int drv_ampdu_action(struct ieee80211_local *local,
+                                  struct ieee80211_vif *vif,
                                   enum ieee80211_ampdu_mlme_action action,
                                   struct ieee80211_sta *sta, u16 tid,
                                   u16 *ssn)
 {
        int ret = -EOPNOTSUPP;
        if (local->ops->ampdu_action)
-               ret = local->ops->ampdu_action(&local->hw, action,
+               ret = local->ops->ampdu_action(&local->hw, vif, action,
                                               sta, tid, ssn);
-       trace_drv_ampdu_action(local, action, sta, tid, ssn, ret);
+       trace_drv_ampdu_action(local, vif, action, sta, tid, ssn, ret);
        return ret;
 }
 
index 37b9051..b8fef1d 100644 (file)
@@ -634,11 +634,12 @@ TRACE_EVENT(drv_tx_last_beacon,
 
 TRACE_EVENT(drv_ampdu_action,
        TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_vif *vif,
                 enum ieee80211_ampdu_mlme_action action,
                 struct ieee80211_sta *sta, u16 tid,
                 u16 *ssn, int ret),
 
-       TP_ARGS(local, action, sta, tid, ssn, ret),
+       TP_ARGS(local, vif, action, sta, tid, ssn, ret),
 
        TP_STRUCT__entry(
                LOCAL_ENTRY
@@ -647,10 +648,12 @@ TRACE_EVENT(drv_ampdu_action,
                __field(u16, tid)
                __field(u16, ssn)
                __field(int, ret)
+               VIF_ENTRY
        ),
 
        TP_fast_assign(
                LOCAL_ASSIGN;
+               VIF_ASSIGN;
                STA_ASSIGN;
                __entry->ret = ret;
                __entry->action = action;
@@ -659,8 +662,8 @@ TRACE_EVENT(drv_ampdu_action,
        ),
 
        TP_printk(
-               LOCAL_PR_FMT  STA_PR_FMT " action:%d tid:%d ret:%d",
-               LOCAL_PR_ARG, STA_PR_ARG, __entry->action, __entry->tid, __entry->ret
+               LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " action:%d tid:%d ret:%d",
+               LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->action, __entry->tid, __entry->ret
        )
 );
 #endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */
index 48ef1a2..15c9d4f 100644 (file)
@@ -134,14 +134,13 @@ void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
        mgmt->u.action.u.delba.params = cpu_to_le16(params);
        mgmt->u.action.u.delba.reason_code = cpu_to_le16(reason_code);
 
-       ieee80211_tx_skb(sdata, skb, 1);
+       ieee80211_tx_skb(sdata, skb);
 }
 
 void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,
                             struct sta_info *sta,
                             struct ieee80211_mgmt *mgmt, size_t len)
 {
-       struct ieee80211_local *local = sdata->local;
        u16 tid, params;
        u16 initiator;
 
@@ -164,7 +163,7 @@ void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,
                sta->ampdu_mlme.tid_state_tx[tid] =
                                HT_AGG_STATE_OPERATIONAL;
                spin_unlock_bh(&sta->lock);
-               ieee80211_stop_tx_ba_session(&local->hw, sta->sta.addr, tid,
+               ieee80211_stop_tx_ba_session(&sta->sta, tid,
                                             WLAN_BACK_RECIPIENT);
        }
 }
index fbffce9..10d1385 100644 (file)
@@ -659,7 +659,8 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata,
        printk(KERN_DEBUG "%s: Sending ProbeResp to %pM\n",
               sdata->dev->name, resp->da);
 #endif /* CONFIG_MAC80211_IBSS_DEBUG */
-       ieee80211_tx_skb(sdata, skb, 0);
+       IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
+       ieee80211_tx_skb(sdata, skb);
 }
 
 static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
index b63b99f..04093e8 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/types.h>
 #include <linux/spinlock.h>
 #include <linux/etherdevice.h>
+#include <net/ieee80211_radiotap.h>
 #include <net/cfg80211.h>
 #include <net/mac80211.h>
 #include "key.h"
@@ -167,13 +168,10 @@ typedef unsigned __bitwise__ ieee80211_rx_result;
 
 struct ieee80211_rx_data {
        struct sk_buff *skb;
-       struct net_device *dev;
        struct ieee80211_local *local;
        struct ieee80211_sub_if_data *sdata;
        struct sta_info *sta;
        struct ieee80211_key *key;
-       struct ieee80211_rx_status *status;
-       struct ieee80211_rate *rate;
 
        unsigned int flags;
        int queue;
@@ -314,6 +312,8 @@ struct ieee80211_if_managed {
        } mfp; /* management frame protection */
 
        int wmm_last_param_set;
+
+       u8 use_4addr;
 };
 
 enum ieee80211_ibss_request {
@@ -461,8 +461,6 @@ struct ieee80211_sub_if_data {
        int force_unicast_rateidx; /* forced TX rateidx for unicast frames */
        int max_ratectrl_rateidx; /* max TX rateidx for rate control */
 
-       bool use_4addr; /* use 4-address frames */
-
        union {
                struct ieee80211_if_ap ap;
                struct ieee80211_if_wds wds;
@@ -581,7 +579,6 @@ struct ieee80211_local {
        /* number of interfaces with corresponding FIF_ flags */
        int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss, fif_pspoll;
        unsigned int filter_flags; /* FIF_* */
-       struct iw_statistics wstats;
 
        /* protects the aggregated multicast list and filter calls */
        spinlock_t filter_lock;
@@ -771,8 +768,9 @@ IEEE80211_DEV_TO_SUB_IF(struct net_device *dev)
        return netdev_priv(dev);
 }
 
-/* this struct represents 802.11n's RA/TID combination */
+/* this struct represents 802.11n's RA/TID combination along with our vif */
 struct ieee80211_ra_tid {
+       struct ieee80211_vif *vif;
        u8 ra[ETH_ALEN];
        u16 tid;
 };
@@ -799,7 +797,7 @@ struct ieee802_11_elems {
        u8 *wmm_param;
        struct ieee80211_ht_cap *ht_cap_elem;
        struct ieee80211_ht_info *ht_info_elem;
-       u8 *mesh_config;
+       struct ieee80211_meshconf_ie *mesh_config;
        u8 *mesh_id;
        u8 *peer_link;
        u8 *preq;
@@ -827,7 +825,6 @@ struct ieee802_11_elems {
        u8 ext_supp_rates_len;
        u8 wmm_info_len;
        u8 wmm_param_len;
-       u8 mesh_config_len;
        u8 mesh_id_len;
        u8 peer_link_len;
        u8 preq_len;
@@ -950,6 +947,18 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
 netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
                                       struct net_device *dev);
 
+/*
+ * radiotap header for status frames
+ */
+struct ieee80211_tx_status_rtap_hdr {
+       struct ieee80211_radiotap_header hdr;
+       u8 rate;
+       u8 padding_for_rate;
+       __le16 tx_flags;
+       u8 data_retries;
+} __attribute__ ((packed));
+
+
 /* HT */
 void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband,
                                       struct ieee80211_ht_cap *ht_cap_ie,
@@ -1017,8 +1026,7 @@ void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int ke
                                     struct ieee80211_hdr *hdr, const u8 *tsc,
                                     gfp_t gfp);
 void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata);
-void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
-                     int encrypt);
+void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb);
 void ieee802_11_parse_elems(u8 *start, size_t len,
                            struct ieee802_11_elems *elems);
 u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
index 1f02b06..1bf12a2 100644 (file)
@@ -752,7 +752,8 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
                ieee80211_mandatory_rates(sdata->local,
                        sdata->local->hw.conf.channel->band);
        sdata->drop_unencrypted = 0;
-       sdata->use_4addr = 0;
+       if (type == NL80211_IFTYPE_STATION)
+               sdata->u.mgd.use_4addr = false;
 
        return 0;
 }
@@ -810,6 +811,12 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
        /* setup type-dependent data */
        ieee80211_setup_sdata(sdata, type);
 
+       if (params) {
+               ndev->ieee80211_ptr->use_4addr = params->use_4addr;
+               if (type == NL80211_IFTYPE_STATION)
+                       sdata->u.mgd.use_4addr = params->use_4addr;
+       }
+
        ret = register_netdevice(ndev);
        if (ret)
                goto fail;
@@ -820,9 +827,6 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
                                            params->mesh_id_len,
                                            params->mesh_id);
 
-       if (params && params->use_4addr >= 0)
-               sdata->use_4addr = !!params->use_4addr;
-
        mutex_lock(&local->iflist_mtx);
        list_add_tail_rcu(&sdata->list, &local->interfaces);
        mutex_unlock(&local->iflist_mtx);
index beb8718..dd8ec8d 100644 (file)
@@ -9,7 +9,6 @@
  */
 
 #include <net/mac80211.h>
-#include <net/ieee80211_radiotap.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/netdevice.h>
 #include "rate.h"
 #include "mesh.h"
 #include "wep.h"
-#include "wme.h"
-#include "aes_ccm.h"
 #include "led.h"
 #include "cfg.h"
 #include "debugfs.h"
 #include "debugfs_netdev.h"
 
-/*
- * For seeing transmitted packets on monitor interfaces
- * we have a radiotap header too.
- */
-struct ieee80211_tx_status_rtap_hdr {
-       struct ieee80211_radiotap_header hdr;
-       u8 rate;
-       u8 padding_for_rate;
-       __le16 tx_flags;
-       u8 data_retries;
-} __attribute__ ((packed));
-
-
 void ieee80211_configure_filter(struct ieee80211_local *local)
 {
        u64 mc;
@@ -253,28 +237,6 @@ u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata)
               BSS_CHANGED_ERP_SLOT;
 }
 
-void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,
-                                struct sk_buff *skb)
-{
-       struct ieee80211_local *local = hw_to_local(hw);
-       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-       int tmp;
-
-       skb->pkt_type = IEEE80211_TX_STATUS_MSG;
-       skb_queue_tail(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS ?
-                      &local->skb_queue : &local->skb_queue_unreliable, skb);
-       tmp = skb_queue_len(&local->skb_queue) +
-               skb_queue_len(&local->skb_queue_unreliable);
-       while (tmp > IEEE80211_IRQSAFE_QUEUE_LIMIT &&
-              (skb = skb_dequeue(&local->skb_queue_unreliable))) {
-               dev_kfree_skb_irq(skb);
-               tmp--;
-               I802_DEBUG_INC(local->tx_status_drop);
-       }
-       tasklet_schedule(&local->tasklet);
-}
-EXPORT_SYMBOL(ieee80211_tx_status_irqsafe);
-
 static void ieee80211_tasklet_handler(unsigned long data)
 {
        struct ieee80211_local *local = (struct ieee80211_local *) data;
@@ -296,14 +258,14 @@ static void ieee80211_tasklet_handler(unsigned long data)
                        break;
                case IEEE80211_DELBA_MSG:
                        ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
-                       ieee80211_stop_tx_ba_cb(local_to_hw(local),
-                                               ra_tid->ra, ra_tid->tid);
+                       ieee80211_stop_tx_ba_cb(ra_tid->vif, ra_tid->ra,
+                                               ra_tid->tid);
                        dev_kfree_skb(skb);
                        break;
                case IEEE80211_ADDBA_MSG:
                        ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
-                       ieee80211_start_tx_ba_cb(local_to_hw(local),
-                                                ra_tid->ra, ra_tid->tid);
+                       ieee80211_start_tx_ba_cb(ra_tid->vif, ra_tid->ra,
+                                                ra_tid->tid);
                        dev_kfree_skb(skb);
                        break ;
                default:
@@ -315,299 +277,6 @@ static void ieee80211_tasklet_handler(unsigned long data)
        }
 }
 
-static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
-                                           struct sta_info *sta,
-                                           struct sk_buff *skb)
-{
-       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-
-       /*
-        * XXX: This is temporary!
-        *
-        *      The problem here is that when we get here, the driver will
-        *      quite likely have pretty much overwritten info->control by
-        *      using info->driver_data or info->rate_driver_data. Thus,
-        *      when passing out the frame to the driver again, we would be
-        *      passing completely bogus data since the driver would then
-        *      expect a properly filled info->control. In mac80211 itself
-        *      the same problem occurs, since we need info->control.vif
-        *      internally.
-        *
-        *      To fix this, we should send the frame through TX processing
-        *      again. However, it's not that simple, since the frame will
-        *      have been software-encrypted (if applicable) already, and
-        *      encrypting it again doesn't do much good. So to properly do
-        *      that, we not only have to skip the actual 'raw' encryption
-        *      (key selection etc. still has to be done!) but also the
-        *      sequence number assignment since that impacts the crypto
-        *      encapsulation, of course.
-        *
-        *      Hence, for now, fix the bug by just dropping the frame.
-        */
-       goto drop;
-
-       sta->tx_filtered_count++;
-
-       /*
-        * Clear the TX filter mask for this STA when sending the next
-        * packet. If the STA went to power save mode, this will happen
-        * when it wakes up for the next time.
-        */
-       set_sta_flags(sta, WLAN_STA_CLEAR_PS_FILT);
-
-       /*
-        * This code races in the following way:
-        *
-        *  (1) STA sends frame indicating it will go to sleep and does so
-        *  (2) hardware/firmware adds STA to filter list, passes frame up
-        *  (3) hardware/firmware processes TX fifo and suppresses a frame
-        *  (4) we get TX status before having processed the frame and
-        *      knowing that the STA has gone to sleep.
-        *
-        * This is actually quite unlikely even when both those events are
-        * processed from interrupts coming in quickly after one another or
-        * even at the same time because we queue both TX status events and
-        * RX frames to be processed by a tasklet and process them in the
-        * same order that they were received or TX status last. Hence, there
-        * is no race as long as the frame RX is processed before the next TX
-        * status, which drivers can ensure, see below.
-        *
-        * Note that this can only happen if the hardware or firmware can
-        * actually add STAs to the filter list, if this is done by the
-        * driver in response to set_tim() (which will only reduce the race
-        * this whole filtering tries to solve, not completely solve it)
-        * this situation cannot happen.
-        *
-        * To completely solve this race drivers need to make sure that they
-        *  (a) don't mix the irq-safe/not irq-safe TX status/RX processing
-        *      functions and
-        *  (b) always process RX events before TX status events if ordering
-        *      can be unknown, for example with different interrupt status
-        *      bits.
-        */
-       if (test_sta_flags(sta, WLAN_STA_PS_STA) &&
-           skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) {
-               skb_queue_tail(&sta->tx_filtered, skb);
-               return;
-       }
-
-       if (!test_sta_flags(sta, WLAN_STA_PS_STA) &&
-           !(info->flags & IEEE80211_TX_INTFL_RETRIED)) {
-               /* Software retry the packet once */
-               info->flags |= IEEE80211_TX_INTFL_RETRIED;
-               ieee80211_add_pending_skb(local, skb);
-               return;
-       }
-
- drop:
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-       if (net_ratelimit())
-               printk(KERN_DEBUG "%s: dropped TX filtered frame, "
-                      "queue_len=%d PS=%d @%lu\n",
-                      wiphy_name(local->hw.wiphy),
-                      skb_queue_len(&sta->tx_filtered),
-                      !!test_sta_flags(sta, WLAN_STA_PS_STA), jiffies);
-#endif
-       dev_kfree_skb(skb);
-}
-
-void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
-{
-       struct sk_buff *skb2;
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
-       struct ieee80211_local *local = hw_to_local(hw);
-       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-       u16 frag, type;
-       __le16 fc;
-       struct ieee80211_supported_band *sband;
-       struct ieee80211_tx_status_rtap_hdr *rthdr;
-       struct ieee80211_sub_if_data *sdata;
-       struct net_device *prev_dev = NULL;
-       struct sta_info *sta;
-       int retry_count = -1, i;
-
-       for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
-               /* the HW cannot have attempted that rate */
-               if (i >= hw->max_rates) {
-                       info->status.rates[i].idx = -1;
-                       info->status.rates[i].count = 0;
-               }
-
-               retry_count += info->status.rates[i].count;
-       }
-       if (retry_count < 0)
-               retry_count = 0;
-
-       rcu_read_lock();
-
-       sband = local->hw.wiphy->bands[info->band];
-
-       sta = sta_info_get(local, hdr->addr1);
-
-       if (sta) {
-               if (!(info->flags & IEEE80211_TX_STAT_ACK) &&
-                   test_sta_flags(sta, WLAN_STA_PS_STA)) {
-                       /*
-                        * The STA is in power save mode, so assume
-                        * that this TX packet failed because of that.
-                        */
-                       ieee80211_handle_filtered_frame(local, sta, skb);
-                       rcu_read_unlock();
-                       return;
-               }
-
-               fc = hdr->frame_control;
-
-               if ((info->flags & IEEE80211_TX_STAT_AMPDU_NO_BACK) &&
-                   (ieee80211_is_data_qos(fc))) {
-                       u16 tid, ssn;
-                       u8 *qc;
-
-                       qc = ieee80211_get_qos_ctl(hdr);
-                       tid = qc[0] & 0xf;
-                       ssn = ((le16_to_cpu(hdr->seq_ctrl) + 0x10)
-                                               & IEEE80211_SCTL_SEQ);
-                       ieee80211_send_bar(sta->sdata, hdr->addr1,
-                                          tid, ssn);
-               }
-
-               if (info->flags & IEEE80211_TX_STAT_TX_FILTERED) {
-                       ieee80211_handle_filtered_frame(local, sta, skb);
-                       rcu_read_unlock();
-                       return;
-               } else {
-                       if (!(info->flags & IEEE80211_TX_STAT_ACK))
-                               sta->tx_retry_failed++;
-                       sta->tx_retry_count += retry_count;
-               }
-
-               rate_control_tx_status(local, sband, sta, skb);
-               if (ieee80211_vif_is_mesh(&sta->sdata->vif))
-                       ieee80211s_update_metric(local, sta, skb);
-       }
-
-       rcu_read_unlock();
-
-       ieee80211_led_tx(local, 0);
-
-       /* SNMP counters
-        * Fragments are passed to low-level drivers as separate skbs, so these
-        * are actually fragments, not frames. Update frame counters only for
-        * the first fragment of the frame. */
-
-       frag = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG;
-       type = le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_FTYPE;
-
-       if (info->flags & IEEE80211_TX_STAT_ACK) {
-               if (frag == 0) {
-                       local->dot11TransmittedFrameCount++;
-                       if (is_multicast_ether_addr(hdr->addr1))
-                               local->dot11MulticastTransmittedFrameCount++;
-                       if (retry_count > 0)
-                               local->dot11RetryCount++;
-                       if (retry_count > 1)
-                               local->dot11MultipleRetryCount++;
-               }
-
-               /* This counter shall be incremented for an acknowledged MPDU
-                * with an individual address in the address 1 field or an MPDU
-                * with a multicast address in the address 1 field of type Data
-                * or Management. */
-               if (!is_multicast_ether_addr(hdr->addr1) ||
-                   type == IEEE80211_FTYPE_DATA ||
-                   type == IEEE80211_FTYPE_MGMT)
-                       local->dot11TransmittedFragmentCount++;
-       } else {
-               if (frag == 0)
-                       local->dot11FailedCount++;
-       }
-
-       /* this was a transmitted frame, but now we want to reuse it */
-       skb_orphan(skb);
-
-       /*
-        * This is a bit racy but we can avoid a lot of work
-        * with this test...
-        */
-       if (!local->monitors && !local->cooked_mntrs) {
-               dev_kfree_skb(skb);
-               return;
-       }
-
-       /* send frame to monitor interfaces now */
-
-       if (skb_headroom(skb) < sizeof(*rthdr)) {
-               printk(KERN_ERR "ieee80211_tx_status: headroom too small\n");
-               dev_kfree_skb(skb);
-               return;
-       }
-
-       rthdr = (struct ieee80211_tx_status_rtap_hdr *)
-                               skb_push(skb, sizeof(*rthdr));
-
-       memset(rthdr, 0, sizeof(*rthdr));
-       rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr));
-       rthdr->hdr.it_present =
-               cpu_to_le32((1 << IEEE80211_RADIOTAP_TX_FLAGS) |
-                           (1 << IEEE80211_RADIOTAP_DATA_RETRIES) |
-                           (1 << IEEE80211_RADIOTAP_RATE));
-
-       if (!(info->flags & IEEE80211_TX_STAT_ACK) &&
-           !is_multicast_ether_addr(hdr->addr1))
-               rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_FAIL);
-
-       /*
-        * XXX: Once radiotap gets the bitmap reset thing the vendor
-        *      extensions proposal contains, we can actually report
-        *      the whole set of tries we did.
-        */
-       if ((info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||
-           (info->status.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT))
-               rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_CTS);
-       else if (info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)
-               rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_RTS);
-       if (info->status.rates[0].idx >= 0 &&
-           !(info->status.rates[0].flags & IEEE80211_TX_RC_MCS))
-               rthdr->rate = sband->bitrates[
-                               info->status.rates[0].idx].bitrate / 5;
-
-       /* for now report the total retry_count */
-       rthdr->data_retries = retry_count;
-
-       /* XXX: is this sufficient for BPF? */
-       skb_set_mac_header(skb, 0);
-       skb->ip_summed = CHECKSUM_UNNECESSARY;
-       skb->pkt_type = PACKET_OTHERHOST;
-       skb->protocol = htons(ETH_P_802_2);
-       memset(skb->cb, 0, sizeof(skb->cb));
-
-       rcu_read_lock();
-       list_for_each_entry_rcu(sdata, &local->interfaces, list) {
-               if (sdata->vif.type == NL80211_IFTYPE_MONITOR) {
-                       if (!netif_running(sdata->dev))
-                               continue;
-
-                       if (prev_dev) {
-                               skb2 = skb_clone(skb, GFP_ATOMIC);
-                               if (skb2) {
-                                       skb2->dev = prev_dev;
-                                       netif_rx(skb2);
-                               }
-                       }
-
-                       prev_dev = sdata->dev;
-               }
-       }
-       if (prev_dev) {
-               skb->dev = prev_dev;
-               netif_rx(skb);
-               skb = NULL;
-       }
-       rcu_read_unlock();
-       dev_kfree_skb(skb);
-}
-EXPORT_SYMBOL(ieee80211_tx_status);
-
 static void ieee80211_restart_work(struct work_struct *work)
 {
        struct ieee80211_local *local =
@@ -659,7 +328,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
        if (!wiphy)
                return NULL;
 
-       wiphy->netnsok = true;
+       wiphy->flags |= WIPHY_FLAG_NETNS_OK |
+                       WIPHY_FLAG_4ADDR_AP |
+                       WIPHY_FLAG_4ADDR_STATION;
        wiphy->privid = mac80211_wiphy_privid;
 
        /* Yes, putting cfg80211_bss into ieee80211_bss is a hack */
index bbd56b0..51adb11 100644 (file)
 #define IEEE80211_MESH_HOUSEKEEPING_INTERVAL (60 * HZ)
 #define IEEE80211_MESH_RANN_INTERVAL        (1 * HZ)
 
-#define MESHCONF_PP_OFFSET     0               /* Path Selection Protocol */
-#define MESHCONF_PM_OFFSET     1               /* Path Selection Metric   */
-#define MESHCONF_CC_OFFSET     2               /* Congestion Control Mode */
-#define MESHCONF_SP_OFFSET     3               /* Synchronization Protocol */
-#define MESHCONF_AUTH_OFFSET   4               /* Authentication Protocol */
-#define MESHCONF_CAPAB_OFFSET  6
 #define MESHCONF_CAPAB_ACCEPT_PLINKS 0x01
 #define MESHCONF_CAPAB_FORWARDING    0x08
 
@@ -87,12 +81,11 @@ bool mesh_matches_local(struct ieee802_11_elems *ie, struct ieee80211_sub_if_dat
         */
        if (ifmsh->mesh_id_len == ie->mesh_id_len &&
                memcmp(ifmsh->mesh_id, ie->mesh_id, ie->mesh_id_len) == 0 &&
-               (ifmsh->mesh_pp_id == *(ie->mesh_config + MESHCONF_PP_OFFSET))&&
-               (ifmsh->mesh_pm_id == *(ie->mesh_config + MESHCONF_PM_OFFSET))&&
-               (ifmsh->mesh_cc_id == *(ie->mesh_config + MESHCONF_CC_OFFSET))&&
-               (ifmsh->mesh_sp_id == *(ie->mesh_config + MESHCONF_SP_OFFSET))&&
-               (ifmsh->mesh_auth_id == *(ie->mesh_config +
-                   MESHCONF_AUTH_OFFSET)))
+               (ifmsh->mesh_pp_id == ie->mesh_config->meshconf_psel) &&
+               (ifmsh->mesh_pm_id == ie->mesh_config->meshconf_pmetric) &&
+               (ifmsh->mesh_cc_id == ie->mesh_config->meshconf_congest) &&
+               (ifmsh->mesh_sp_id == ie->mesh_config->meshconf_synch) &&
+               (ifmsh->mesh_auth_id == ie->mesh_config->meshconf_auth))
                return true;
 
        return false;
@@ -105,7 +98,7 @@ bool mesh_matches_local(struct ieee802_11_elems *ie, struct ieee80211_sub_if_dat
  */
 bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie)
 {
-       return (*(ie->mesh_config + MESHCONF_CAPAB_OFFSET) &
+       return (ie->mesh_config->meshconf_cap &
            MESHCONF_CAPAB_ACCEPT_PLINKS) != 0;
 }
 
@@ -262,9 +255,9 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
        if (sdata->u.mesh.mesh_id_len)
                memcpy(pos, sdata->u.mesh.mesh_id, sdata->u.mesh.mesh_id_len);
 
-       pos = skb_put(skb, 2 + IEEE80211_MESH_CONFIG_LEN);
+       pos = skb_put(skb, 2 + sizeof(struct ieee80211_meshconf_ie));
        *pos++ = WLAN_EID_MESH_CONFIG;
-       *pos++ = IEEE80211_MESH_CONFIG_LEN;
+       *pos++ = sizeof(struct ieee80211_meshconf_ie);
 
        /* Active path selection protocol ID */
        *pos++ = sdata->u.mesh.mesh_pp_id;
@@ -394,8 +387,9 @@ void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh)
  *
  * Return the length of the 802.11 (does not include a mesh control header)
  */
-int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc, char
-               *meshda, char *meshsa) {
+int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc,
+                                 const u8 *meshda, const u8 *meshsa)
+{
        if (is_multicast_ether_addr(meshda)) {
                *fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
                /* DA TA SA */
index bd0e1cb..31e1025 100644 (file)
@@ -220,7 +220,7 @@ struct mesh_rmc {
 /* Public interfaces */
 /* Various */
 int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc,
-               char *da, char *sa);
+                                 const u8 *da, const u8 *sa);
 int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr,
                struct ieee80211_sub_if_data *sdata, char *addr4,
                char *addr5, char *addr6);
@@ -284,7 +284,7 @@ u32 mesh_table_hash(u8 *addr, struct ieee80211_sub_if_data *sdata,
                struct mesh_table *tbl);
 /* Mesh paths */
 int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn, __le16 target_rcode,
-               u8 *ra, struct ieee80211_sub_if_data *sdata);
+                      const u8 *ra, struct ieee80211_sub_if_data *sdata);
 void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta);
 void mesh_path_flush_pending(struct mesh_path *mpath);
 void mesh_path_tx_pending(struct mesh_path *mpath);
index 5c67e7b..9aecf02 100644 (file)
@@ -101,10 +101,12 @@ enum mpath_frame_type {
        MPATH_RANN
 };
 
+static const u8 broadcast_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
 static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags,
                u8 *orig_addr, __le32 orig_sn, u8 target_flags, u8 *target,
-               __le32 target_sn, u8 *da, u8 hop_count, u8 ttl,__le32 lifetime,
-               __le32 metric, __le32 preq_id,
+               __le32 target_sn, const u8 *da, u8 hop_count, u8 ttl,
+               __le32 lifetime, __le32 metric, __le32 preq_id,
                struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_local *local = sdata->local;
@@ -185,7 +187,7 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags,
                memcpy(pos, &target_sn, 4);
        }
 
-       ieee80211_tx_skb(sdata, skb, 1);
+       ieee80211_tx_skb(sdata, skb);
        return 0;
 }
 
@@ -198,8 +200,8 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags,
  * @ra: node this frame is addressed to
  */
 int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn,
-               __le16 target_rcode, u8 *ra,
-               struct ieee80211_sub_if_data *sdata)
+                      __le16 target_rcode, const u8 *ra,
+                      struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_local *local = sdata->local;
        struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400);
@@ -248,7 +250,7 @@ int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn,
        pos += 4;
        memcpy(pos, &target_rcode, 2);
 
-       ieee80211_tx_skb(sdata, skb, 1);
+       ieee80211_tx_skb(sdata, skb);
        return 0;
 }
 
@@ -548,7 +550,7 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
                hopcount = PREQ_IE_HOPCOUNT(preq_elem) + 1;
                mesh_path_sel_frame_tx(MPATH_PREQ, flags, orig_addr,
                                cpu_to_le32(orig_sn), target_flags, target_addr,
-                               cpu_to_le32(target_sn), sdata->dev->broadcast,
+                               cpu_to_le32(target_sn), broadcast_addr,
                                hopcount, ttl, cpu_to_le32(lifetime),
                                cpu_to_le32(metric), cpu_to_le32(preq_id),
                                sdata);
@@ -660,7 +662,7 @@ static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata,
                        spin_unlock_bh(&mpath->state_lock);
                        mesh_path_error_tx(ttl, target_addr, cpu_to_le32(target_sn),
                                           cpu_to_le16(target_rcode),
-                                          sdata->dev->broadcast, sdata);
+                                          broadcast_addr, sdata);
                } else
                        spin_unlock_bh(&mpath->state_lock);
        }
@@ -709,7 +711,7 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
        if (mpath->sn < orig_sn) {
                mesh_path_sel_frame_tx(MPATH_RANN, flags, orig_addr,
                                       cpu_to_le32(orig_sn),
-                                      0, NULL, 0, sdata->dev->broadcast,
+                                      0, NULL, 0, broadcast_addr,
                                       hopcount, ttl, 0,
                                       cpu_to_le32(metric + mpath->metric),
                                       0, sdata);
@@ -890,7 +892,7 @@ void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata)
        spin_unlock_bh(&mpath->state_lock);
        mesh_path_sel_frame_tx(MPATH_PREQ, 0, sdata->dev->dev_addr,
                        cpu_to_le32(ifmsh->sn), target_flags, mpath->dst,
-                       cpu_to_le32(mpath->sn), sdata->dev->broadcast, 0,
+                       cpu_to_le32(mpath->sn), broadcast_addr, 0,
                        ttl, cpu_to_le32(lifetime), 0,
                        cpu_to_le32(ifmsh->preq_id++), sdata);
        mod_timer(&mpath->timer, jiffies + mpath->discovery_timeout);
@@ -1011,6 +1013,6 @@ mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata)
 
        mesh_path_sel_frame_tx(MPATH_RANN, 0, sdata->dev->dev_addr,
                               cpu_to_le32(++ifmsh->sn),
-                              0, NULL, 0, sdata->dev->broadcast,
+                              0, NULL, 0, broadcast_addr,
                               0, MESH_TTL, 0, 0, 0, sdata);
 }
index 5399e7a..a8da239 100644 (file)
@@ -449,6 +449,7 @@ err_path_alloc:
  */
 void mesh_plink_broken(struct sta_info *sta)
 {
+       static const u8 bcast[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
        struct mesh_path *mpath;
        struct mpath_node *node;
        struct hlist_node *p;
@@ -467,8 +468,8 @@ void mesh_plink_broken(struct sta_info *sta)
                        spin_unlock_bh(&mpath->state_lock);
                        mesh_path_error_tx(MESH_TTL, mpath->dst,
                                        cpu_to_le32(mpath->sn),
-                                       PERR_RCODE_DEST_UNREACH,
-                                       sdata->dev->broadcast, sdata);
+                                       cpu_to_le16(PERR_RCODE_DEST_UNREACH),
+                                       bcast, sdata);
                } else
                spin_unlock_bh(&mpath->state_lock);
        }
@@ -613,7 +614,7 @@ void mesh_path_discard_frame(struct sk_buff *skb,
                if (mpath)
                        sn = ++mpath->sn;
                mesh_path_error_tx(MESH_TTL, skb->data, cpu_to_le32(sn),
-                                  PERR_RCODE_NO_ROUTE, ra, sdata);
+                                  cpu_to_le16(PERR_RCODE_NO_ROUTE), ra, sdata);
        }
 
        kfree_skb(skb);
index f21329a..0f7c6e6 100644 (file)
@@ -222,7 +222,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
                memcpy(pos, &reason, 2);
        }
 
-       ieee80211_tx_skb(sdata, skb, 1);
+       ieee80211_tx_skb(sdata, skb);
        return 0;
 }
 
index 2af306f..6dc7b5a 100644 (file)
@@ -426,7 +426,8 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
                memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs));
        }
 
-       ieee80211_tx_skb(sdata, skb, 0);
+       IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
+       ieee80211_tx_skb(sdata, skb);
 }
 
 
@@ -467,7 +468,9 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
                        __cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len);
                else
                        cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len);
-       ieee80211_tx_skb(sdata, skb, ifmgd->flags & IEEE80211_STA_MFP_ENABLED);
+       if (!(ifmgd->flags & IEEE80211_STA_MFP_ENABLED))
+               IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
+       ieee80211_tx_skb(sdata, skb);
 }
 
 void ieee80211_send_pspoll(struct ieee80211_local *local,
@@ -498,7 +501,8 @@ void ieee80211_send_pspoll(struct ieee80211_local *local,
        memcpy(pspoll->bssid, ifmgd->bssid, ETH_ALEN);
        memcpy(pspoll->ta, sdata->dev->dev_addr, ETH_ALEN);
 
-       ieee80211_tx_skb(sdata, skb, 0);
+       IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
+       ieee80211_tx_skb(sdata, skb);
 }
 
 void ieee80211_send_nullfunc(struct ieee80211_local *local,
@@ -531,7 +535,8 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local,
        memcpy(nullfunc->addr2, sdata->dev->dev_addr, ETH_ALEN);
        memcpy(nullfunc->addr3, sdata->u.mgd.bssid, ETH_ALEN);
 
-       ieee80211_tx_skb(sdata, skb, 0);
+       IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
+       ieee80211_tx_skb(sdata, skb);
 }
 
 /* spectrum management related things */
@@ -2503,6 +2508,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        struct ieee80211_mgd_work *wk;
        const u8 *bssid = NULL;
+       bool not_auth_yet = false;
 
        mutex_lock(&ifmgd->mtx);
 
@@ -2512,6 +2518,8 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
        } else list_for_each_entry(wk, &ifmgd->work_list, list) {
                if (&wk->bss->cbss == req->bss) {
                        bssid = req->bss->bssid;
+                       if (wk->state == IEEE80211_MGD_STATE_PROBE)
+                               not_auth_yet = true;
                        list_del(&wk->list);
                        kfree(wk);
                        break;
@@ -2519,6 +2527,20 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
        }
 
        /*
+        * If somebody requests authentication and we haven't
+        * sent out an auth frame yet there's no need to send
+        * out a deauth frame either. If the state was PROBE,
+        * then this is the case. If it's AUTH we have sent a
+        * frame, and if it's IDLE we have completed the auth
+        * process already.
+        */
+       if (not_auth_yet) {
+               mutex_unlock(&ifmgd->mtx);
+               __cfg80211_auth_canceled(sdata->dev, bssid);
+               return 0;
+       }
+
+       /*
         * cfg80211 should catch this ... but it's racy since
         * we can receive a deauth frame, process it, hand it
         * to cfg80211 while that's in a locked section already
index ccda745..b9007f8 100644 (file)
@@ -284,9 +284,16 @@ int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local,
        struct rate_control_ref *ref, *old;
 
        ASSERT_RTNL();
+
        if (local->open_count)
                return -EBUSY;
 
+       if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) {
+               if (WARN_ON(!local->ops->set_rts_threshold))
+                       return -EINVAL;
+               return 0;
+       }
+
        ref = rate_control_alloc(name, local);
        if (!ref) {
                printk(KERN_WARNING "%s: Failed to select rate control "
@@ -305,7 +312,6 @@ int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local,
               "algorithm '%s'\n", wiphy_name(local->hw.wiphy),
               ref->ops->name);
 
-
        return 0;
 }
 
@@ -314,6 +320,10 @@ void rate_control_deinitialize(struct ieee80211_local *local)
        struct rate_control_ref *ref;
 
        ref = local->rate_ctrl;
+
+       if (!ref)
+               return;
+
        local->rate_ctrl = NULL;
        rate_control_put(ref);
 }
index 2ab5ad9..cb9bd1f 100644 (file)
@@ -59,6 +59,9 @@ static inline void rate_control_rate_init(struct sta_info *sta)
        void *priv_sta = sta->rate_ctrl_priv;
        struct ieee80211_supported_band *sband;
 
+       if (!ref)
+               return;
+
        sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
 
        ref->ops->rate_init(ref->priv, sband, ista, priv_sta);
@@ -72,7 +75,7 @@ static inline void rate_control_rate_update(struct ieee80211_local *local,
        struct ieee80211_sta *ista = &sta->sta;
        void *priv_sta = sta->rate_ctrl_priv;
 
-       if (ref->ops->rate_update)
+       if (ref && ref->ops->rate_update)
                ref->ops->rate_update(ref->priv, sband, ista,
                                      priv_sta, changed);
 }
@@ -97,7 +100,7 @@ static inline void rate_control_add_sta_debugfs(struct sta_info *sta)
 {
 #ifdef CONFIG_MAC80211_DEBUGFS
        struct rate_control_ref *ref = sta->rate_ctrl;
-       if (sta->debugfs.dir && ref->ops->add_sta_debugfs)
+       if (ref && sta->debugfs.dir && ref->ops->add_sta_debugfs)
                ref->ops->add_sta_debugfs(ref->priv, sta->rate_ctrl_priv,
                                          sta->debugfs.dir);
 #endif
@@ -107,7 +110,7 @@ static inline void rate_control_remove_sta_debugfs(struct sta_info *sta)
 {
 #ifdef CONFIG_MAC80211_DEBUGFS
        struct rate_control_ref *ref = sta->rate_ctrl;
-       if (ref->ops->remove_sta_debugfs)
+       if (ref && ref->ops->remove_sta_debugfs)
                ref->ops->remove_sta_debugfs(ref->priv, sta->rate_ctrl_priv);
 #endif
 }
index 6bce97e..96f13ad 100644 (file)
 #include "tkip.h"
 #include "wme.h"
 
-static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
-                                          struct tid_ampdu_rx *tid_agg_rx,
-                                          struct sk_buff *skb,
-                                          u16 mpdu_seq_num,
-                                          int bar_req);
+static void ieee80211_release_reorder_frames(struct ieee80211_hw *hw,
+                                            struct tid_ampdu_rx *tid_agg_rx,
+                                            u16 head_seq_num);
+
 /*
  * monitor mode reception
  *
@@ -164,6 +163,9 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
        if (status->band == IEEE80211_BAND_5GHZ)
                put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ,
                                   pos);
+       else if (status->flag & RX_FLAG_HT)
+               put_unaligned_le16(IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ,
+                                  pos);
        else if (rate->flags & IEEE80211_RATE_ERP_G)
                put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ,
                                   pos);
@@ -478,7 +480,7 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
        unsigned int hdrlen = ieee80211_hdrlen(hdr->frame_control);
-       char *dev_addr = rx->dev->dev_addr;
+       char *dev_addr = rx->sdata->dev->dev_addr;
 
        if (ieee80211_is_data(hdr->frame_control)) {
                if (is_multicast_ether_addr(hdr->addr1)) {
@@ -592,7 +594,9 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
 static ieee80211_rx_result debug_noinline
 ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
 {
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
+       struct sk_buff *skb = rx->skb;
+       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
        int keyidx;
        int hdrlen;
        ieee80211_rx_result result = RX_DROP_UNUSABLE;
@@ -646,8 +650,8 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
                        return RX_CONTINUE;
        } else if (mmie_keyidx >= 0) {
                /* Broadcast/multicast robust management frame / BIP */
-               if ((rx->status->flag & RX_FLAG_DECRYPTED) &&
-                   (rx->status->flag & RX_FLAG_IV_STRIPPED))
+               if ((status->flag & RX_FLAG_DECRYPTED) &&
+                   (status->flag & RX_FLAG_IV_STRIPPED))
                        return RX_CONTINUE;
 
                if (mmie_keyidx < NUM_DEFAULT_KEYS ||
@@ -679,8 +683,8 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
                 * we somehow allow the driver to tell us which key
                 * the hardware used if this flag is set?
                 */
-               if ((rx->status->flag & RX_FLAG_DECRYPTED) &&
-                   (rx->status->flag & RX_FLAG_IV_STRIPPED))
+               if ((status->flag & RX_FLAG_DECRYPTED) &&
+                   (status->flag & RX_FLAG_IV_STRIPPED))
                        return RX_CONTINUE;
 
                hdrlen = ieee80211_hdrlen(hdr->frame_control);
@@ -716,8 +720,8 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
        /* Check for weak IVs if possible */
        if (rx->sta && rx->key->conf.alg == ALG_WEP &&
            ieee80211_is_data(hdr->frame_control) &&
-           (!(rx->status->flag & RX_FLAG_IV_STRIPPED) ||
-            !(rx->status->flag & RX_FLAG_DECRYPTED)) &&
+           (!(status->flag & RX_FLAG_IV_STRIPPED) ||
+            !(status->flag & RX_FLAG_DECRYPTED)) &&
            ieee80211_wep_is_weak_iv(rx->skb, rx->key))
                rx->sta->wep_weak_iv_count++;
 
@@ -737,7 +741,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
        }
 
        /* either the frame has been decrypted or will be dropped */
-       rx->status->flag |= RX_FLAG_DECRYPTED;
+       status->flag |= RX_FLAG_DECRYPTED;
 
        return result;
 }
@@ -817,7 +821,9 @@ static ieee80211_rx_result debug_noinline
 ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
 {
        struct sta_info *sta = rx->sta;
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
+       struct sk_buff *skb = rx->skb;
+       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 
        if (!sta)
                return RX_CONTINUE;
@@ -848,8 +854,8 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
 
        sta->rx_fragments++;
        sta->rx_bytes += rx->skb->len;
-       sta->last_signal = rx->status->signal;
-       sta->last_noise = rx->status->noise;
+       sta->last_signal = status->signal;
+       sta->last_noise = status->noise;
 
        /*
         * Change STA power saving mode only at the end of a frame
@@ -1141,11 +1147,14 @@ ieee80211_802_1x_port_control(struct ieee80211_rx_data *rx)
 static int
 ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc)
 {
+       struct sk_buff *skb = rx->skb;
+       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
+
        /*
         * Pass through unencrypted frames if the hardware has
         * decrypted them already.
         */
-       if (rx->status->flag & RX_FLAG_DECRYPTED)
+       if (status->flag & RX_FLAG_DECRYPTED)
                return 0;
 
        /* Drop unencrypted frames if key is set. */
@@ -1179,14 +1188,17 @@ ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc)
 static int
 __ieee80211_data_to_8023(struct ieee80211_rx_data *rx)
 {
-       struct net_device *dev = rx->dev;
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_sub_if_data *sdata = rx->sdata;
+       struct net_device *dev = sdata->dev;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
 
-       if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN && !sdata->use_4addr &&
-           ieee80211_has_a4(hdr->frame_control))
+       if (ieee80211_has_a4(hdr->frame_control) &&
+           sdata->vif.type == NL80211_IFTYPE_AP_VLAN && !sdata->u.vlan.sta)
                return -1;
-       if (sdata->use_4addr && is_multicast_ether_addr(hdr->addr1))
+
+       if (is_multicast_ether_addr(hdr->addr1) &&
+           ((sdata->vif.type == NL80211_IFTYPE_AP_VLAN && sdata->u.vlan.sta) ||
+            (sdata->vif.type == NL80211_IFTYPE_STATION && sdata->u.mgd.use_4addr)))
                return -1;
 
        return ieee80211_data_to_8023(rx->skb, dev->dev_addr, sdata->vif.type);
@@ -1206,7 +1218,7 @@ static bool ieee80211_frame_allowed(struct ieee80211_rx_data *rx, __le16 fc)
         * of whether the frame was encrypted or not.
         */
        if (ehdr->h_proto == htons(ETH_P_PAE) &&
-           (compare_ether_addr(ehdr->h_dest, rx->dev->dev_addr) == 0 ||
+           (compare_ether_addr(ehdr->h_dest, rx->sdata->dev->dev_addr) == 0 ||
             compare_ether_addr(ehdr->h_dest, pae_group_addr) == 0))
                return true;
 
@@ -1223,10 +1235,10 @@ static bool ieee80211_frame_allowed(struct ieee80211_rx_data *rx, __le16 fc)
 static void
 ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
 {
-       struct net_device *dev = rx->dev;
+       struct ieee80211_sub_if_data *sdata = rx->sdata;
+       struct net_device *dev = sdata->dev;
        struct ieee80211_local *local = rx->local;
        struct sk_buff *skb, *xmit_skb;
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ethhdr *ehdr = (struct ethhdr *) rx->skb->data;
        struct sta_info *dsta;
 
@@ -1236,7 +1248,8 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
        if ((sdata->vif.type == NL80211_IFTYPE_AP ||
             sdata->vif.type == NL80211_IFTYPE_AP_VLAN) &&
            !(sdata->flags & IEEE80211_SDATA_DONT_BRIDGE_PACKETS) &&
-           (rx->flags & IEEE80211_RX_RA_MATCH) && !rx->sdata->use_4addr) {
+           (rx->flags & IEEE80211_RX_RA_MATCH) &&
+           (sdata->vif.type != NL80211_IFTYPE_AP_VLAN || !sdata->u.vlan.sta)) {
                if (is_multicast_ether_addr(ehdr->h_dest)) {
                        /*
                         * send multicast frames both to higher layers in
@@ -1307,7 +1320,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
 static ieee80211_rx_result debug_noinline
 ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
 {
-       struct net_device *dev = rx->dev;
+       struct net_device *dev = rx->sdata->dev;
        struct ieee80211_local *local = rx->local;
        u16 ethertype;
        u8 *payload;
@@ -1432,12 +1445,11 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
        unsigned int hdrlen;
        struct sk_buff *skb = rx->skb, *fwd_skb;
        struct ieee80211_local *local = rx->local;
-       struct ieee80211_sub_if_data *sdata;
+       struct ieee80211_sub_if_data *sdata = rx->sdata;
 
        hdr = (struct ieee80211_hdr *) skb->data;
        hdrlen = ieee80211_hdrlen(hdr->frame_control);
        mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen);
-       sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
 
        if (!ieee80211_is_data(hdr->frame_control))
                return RX_CONTINUE;
@@ -1475,7 +1487,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
 
        /* Frame has reached destination.  Don't forward */
        if (!is_multicast_ether_addr(hdr->addr1) &&
-                       compare_ether_addr(rx->dev->dev_addr, hdr->addr3) == 0)
+           compare_ether_addr(sdata->dev->dev_addr, hdr->addr3) == 0)
                return RX_CONTINUE;
 
        mesh_hdr->ttl--;
@@ -1492,10 +1504,10 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
 
                        if (!fwd_skb && net_ratelimit())
                                printk(KERN_DEBUG "%s: failed to clone mesh frame\n",
-                                                  rx->dev->name);
+                                                  sdata->dev->name);
 
                        fwd_hdr =  (struct ieee80211_hdr *) fwd_skb->data;
-                       memcpy(fwd_hdr->addr2, rx->dev->dev_addr, ETH_ALEN);
+                       memcpy(fwd_hdr->addr2, sdata->dev->dev_addr, ETH_ALEN);
                        info = IEEE80211_SKB_CB(fwd_skb);
                        memset(info, 0, sizeof(*info));
                        info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
@@ -1529,7 +1541,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
        }
 
        if (is_multicast_ether_addr(hdr->addr1) ||
-           rx->dev->flags & IFF_PROMISC)
+           sdata->dev->flags & IFF_PROMISC)
                return RX_CONTINUE;
        else
                return RX_DROP_MONITOR;
@@ -1539,9 +1551,9 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
 static ieee80211_rx_result debug_noinline
 ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
 {
-       struct net_device *dev = rx->dev;
+       struct ieee80211_sub_if_data *sdata = rx->sdata;
+       struct net_device *dev = sdata->dev;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        __le16 fc = hdr->frame_control;
        int err;
 
@@ -1592,11 +1604,11 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx)
 
        if (ieee80211_is_back_req(bar->frame_control)) {
                if (!rx->sta)
-                       return RX_CONTINUE;
+                       return RX_DROP_MONITOR;
                tid = le16_to_cpu(bar->control) >> 12;
                if (rx->sta->ampdu_mlme.tid_state_rx[tid]
                                        != HT_AGG_STATE_OPERATIONAL)
-                       return RX_CONTINUE;
+                       return RX_DROP_MONITOR;
                tid_agg_rx = rx->sta->ampdu_mlme.tid_rx[tid];
 
                start_seq_num = le16_to_cpu(bar->start_seq_num) >> 4;
@@ -1606,13 +1618,10 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx)
                        mod_timer(&tid_agg_rx->session_timer,
                                  TU_TO_EXP_TIME(tid_agg_rx->timeout));
 
-               /* manage reordering buffer according to requested */
-               /* sequence number */
-               rcu_read_lock();
-               ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, NULL,
-                                                start_seq_num, 1);
-               rcu_read_unlock();
-               return RX_DROP_UNUSABLE;
+               /* release stored frames up to start of BAR */
+               ieee80211_release_reorder_frames(hw, tid_agg_rx, start_seq_num);
+               kfree_skb(skb);
+               return RX_QUEUED;
        }
 
        return RX_CONTINUE;
@@ -1661,14 +1670,14 @@ static void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata,
               mgmt->u.action.u.sa_query.trans_id,
               WLAN_SA_QUERY_TR_ID_LEN);
 
-       ieee80211_tx_skb(sdata, skb, 1);
+       ieee80211_tx_skb(sdata, skb);
 }
 
 static ieee80211_rx_result debug_noinline
 ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
 {
        struct ieee80211_local *local = rx->local;
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
+       struct ieee80211_sub_if_data *sdata = rx->sdata;
        struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
        int len = rx->skb->len;
 
@@ -1780,7 +1789,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
 static ieee80211_rx_result debug_noinline
 ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
 {
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
+       struct ieee80211_sub_if_data *sdata = rx->sdata;
        struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
 
        if (!(rx->flags & IEEE80211_RX_RA_MATCH))
@@ -1818,11 +1827,11 @@ static void ieee80211_rx_michael_mic_report(struct ieee80211_hdr *hdr,
                 * Some hardware seem to generate incorrect Michael MIC
                 * reports; ignore them to avoid triggering countermeasures.
                 */
-               goto ignore;
+               return;
        }
 
        if (!ieee80211_has_protected(hdr->frame_control))
-               goto ignore;
+               return;
 
        if (rx->sdata->vif.type == NL80211_IFTYPE_AP && keyidx) {
                /*
@@ -1831,35 +1840,33 @@ static void ieee80211_rx_michael_mic_report(struct ieee80211_hdr *hdr,
                 * group keys and only the AP is sending real multicast
                 * frames in the BSS.
                 */
-               goto ignore;
+               return;
        }
 
        if (!ieee80211_is_data(hdr->frame_control) &&
            !ieee80211_is_auth(hdr->frame_control))
-               goto ignore;
+               return;
 
        mac80211_ev_michael_mic_failure(rx->sdata, keyidx, hdr, NULL,
                                        GFP_ATOMIC);
- ignore:
-       dev_kfree_skb(rx->skb);
-       rx->skb = NULL;
 }
 
 /* TODO: use IEEE80211_RX_FRAGMENTED */
-static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx)
+static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,
+                                       struct ieee80211_rate *rate)
 {
        struct ieee80211_sub_if_data *sdata;
        struct ieee80211_local *local = rx->local;
        struct ieee80211_rtap_hdr {
                struct ieee80211_radiotap_header hdr;
                u8 flags;
-               u8 rate;
+               u8 rate_or_pad;
                __le16 chan_freq;
                __le16 chan_flags;
        } __attribute__ ((packed)) *rthdr;
        struct sk_buff *skb = rx->skb, *skb2;
        struct net_device *prev_dev = NULL;
-       struct ieee80211_rx_status *status = rx->status;
+       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
 
        if (rx->flags & IEEE80211_RX_CMNTR_REPORTED)
                goto out_free_skb;
@@ -1873,10 +1880,13 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx)
        rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr));
        rthdr->hdr.it_present =
                cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) |
-                           (1 << IEEE80211_RADIOTAP_RATE) |
                            (1 << IEEE80211_RADIOTAP_CHANNEL));
 
-       rthdr->rate = rx->rate->bitrate / 5;
+       if (rate) {
+               rthdr->rate_or_pad = rate->bitrate / 5;
+               rthdr->hdr.it_present |=
+                       cpu_to_le32(1 << IEEE80211_RADIOTAP_RATE);
+       }
        rthdr->chan_freq = cpu_to_le16(status->freq);
 
        if (status->band == IEEE80211_BAND_5GHZ)
@@ -1929,13 +1939,13 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx)
 
 static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata,
                                         struct ieee80211_rx_data *rx,
-                                        struct sk_buff *skb)
+                                        struct sk_buff *skb,
+                                        struct ieee80211_rate *rate)
 {
        ieee80211_rx_result res = RX_DROP_MONITOR;
 
        rx->skb = skb;
        rx->sdata = sdata;
-       rx->dev = sdata->dev;
 
 #define CALL_RXH(rxh)                  \
        do {                            \
@@ -1974,7 +1984,7 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata,
                        rx->sta->rx_dropped++;
                /* fall through */
        case RX_CONTINUE:
-               ieee80211_rx_cooked_monitor(rx);
+               ieee80211_rx_cooked_monitor(rx, rate);
                break;
        case RX_DROP_UNUSABLE:
                I802_DEBUG_INC(sdata->local->rx_handlers_drop);
@@ -1994,12 +2004,14 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
                                struct ieee80211_rx_data *rx,
                                struct ieee80211_hdr *hdr)
 {
-       u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len, sdata->vif.type);
+       struct sk_buff *skb = rx->skb;
+       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
+       u8 *bssid = ieee80211_get_bssid(hdr, skb->len, sdata->vif.type);
        int multicast = is_multicast_ether_addr(hdr->addr1);
 
        switch (sdata->vif.type) {
        case NL80211_IFTYPE_STATION:
-               if (!bssid && !sdata->use_4addr)
+               if (!bssid && !sdata->u.mgd.use_4addr)
                        return 0;
                if (!multicast &&
                    compare_ether_addr(sdata->dev->dev_addr, hdr->addr1) != 0) {
@@ -2026,10 +2038,10 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
                        rx->flags &= ~IEEE80211_RX_RA_MATCH;
                } else if (!rx->sta) {
                        int rate_idx;
-                       if (rx->status->flag & RX_FLAG_HT)
+                       if (status->flag & RX_FLAG_HT)
                                rate_idx = 0; /* TODO: HT rates */
                        else
-                               rate_idx = rx->status->rate_idx;
+                               rate_idx = status->rate_idx;
                        rx->sta = ieee80211_ibss_add_sta(sdata, bssid, hdr->addr2,
                                BIT(rate_idx));
                }
@@ -2064,8 +2076,6 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
                        return 0;
                break;
        case NL80211_IFTYPE_MONITOR:
-               /* take everything */
-               break;
        case NL80211_IFTYPE_UNSPECIFIED:
        case __NL80211_IFTYPE_AFTER_LAST:
                /* should never get here */
@@ -2098,23 +2108,9 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
        rx.skb = skb;
        rx.local = local;
 
-       rx.status = status;
-       rx.rate = rate;
-
        if (ieee80211_is_data(hdr->frame_control) || ieee80211_is_mgmt(hdr->frame_control))
                local->dot11ReceivedFragmentCount++;
 
-       rx.sta = sta_info_get(local, hdr->addr2);
-       if (rx.sta) {
-               rx.sdata = rx.sta->sdata;
-               rx.dev = rx.sta->sdata->dev;
-       }
-
-       if ((status->flag & RX_FLAG_MMIC_ERROR)) {
-               ieee80211_rx_michael_mic_report(hdr, &rx);
-               return;
-       }
-
        if (unlikely(test_bit(SCAN_HW_SCANNING, &local->scanning) ||
                     test_bit(SCAN_OFF_CHANNEL, &local->scanning)))
                rx.flags |= IEEE80211_RX_IN_SCAN;
@@ -2122,13 +2118,20 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
        ieee80211_parse_qos(&rx);
        ieee80211_verify_alignment(&rx);
 
-       skb = rx.skb;
+       rx.sta = sta_info_get(local, hdr->addr2);
+       if (rx.sta)
+               rx.sdata = rx.sta->sdata;
 
        if (rx.sdata && ieee80211_is_data(hdr->frame_control)) {
                rx.flags |= IEEE80211_RX_RA_MATCH;
                prepares = prepare_for_handlers(rx.sdata, &rx, hdr);
-               if (prepares)
-                       prev = rx.sdata;
+               if (prepares) {
+                       if (status->flag & RX_FLAG_MMIC_ERROR) {
+                               if (rx.flags & IEEE80211_RX_RA_MATCH)
+                                       ieee80211_rx_michael_mic_report(hdr, &rx);
+                       } else
+                               prev = rx.sdata;
+               }
        } else list_for_each_entry_rcu(sdata, &local->interfaces, list) {
                if (!netif_running(sdata->dev))
                        continue;
@@ -2143,6 +2146,13 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
                if (!prepares)
                        continue;
 
+               if (status->flag & RX_FLAG_MMIC_ERROR) {
+                       rx.sdata = sdata;
+                       if (rx.flags & IEEE80211_RX_RA_MATCH)
+                               ieee80211_rx_michael_mic_report(hdr, &rx);
+                       continue;
+               }
+
                /*
                 * frame is destined for this interface, but if it's not
                 * also for the previous one we handle that after the
@@ -2168,11 +2178,11 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
                                       prev->dev->name);
                        continue;
                }
-               ieee80211_invoke_rx_handlers(prev, &rx, skb_new);
+               ieee80211_invoke_rx_handlers(prev, &rx, skb_new, rate);
                prev = sdata;
        }
        if (prev)
-               ieee80211_invoke_rx_handlers(prev, &rx, skb);
+               ieee80211_invoke_rx_handlers(prev, &rx, skb, rate);
        else
                dev_kfree_skb(skb);
 }
@@ -2201,7 +2211,7 @@ static void ieee80211_release_reorder_frame(struct ieee80211_hw *hw,
                                            int index)
 {
        struct ieee80211_supported_band *sband;
-       struct ieee80211_rate *rate;
+       struct ieee80211_rate *rate = NULL;
        struct sk_buff *skb = tid_agg_rx->reorder_buf[index];
        struct ieee80211_rx_status *status;
 
@@ -2212,9 +2222,7 @@ static void ieee80211_release_reorder_frame(struct ieee80211_hw *hw,
 
        /* release the reordered frames to stack */
        sband = hw->wiphy->bands[status->band];
-       if (status->flag & RX_FLAG_HT)
-               rate = sband->bitrates; /* TODO: HT rates */
-       else
+       if (!(status->flag & RX_FLAG_HT))
                rate = &sband->bitrates[status->rate_idx];
        __ieee80211_rx_handle_packet(hw, skb, rate);
        tid_agg_rx->stored_mpdu_num--;
@@ -2224,6 +2232,18 @@ no_frame:
        tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num);
 }
 
+static void ieee80211_release_reorder_frames(struct ieee80211_hw *hw,
+                                            struct tid_ampdu_rx *tid_agg_rx,
+                                            u16 head_seq_num)
+{
+       int index;
+
+       while (seq_less(tid_agg_rx->head_seq_num, head_seq_num)) {
+               index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
+                                                       tid_agg_rx->buf_size;
+               ieee80211_release_reorder_frame(hw, tid_agg_rx, index);
+       }
+}
 
 /*
  * Timeout (in jiffies) for skb's that are waiting in the RX reorder buffer. If
@@ -2235,15 +2255,17 @@ no_frame:
 #define HT_RX_REORDER_BUF_TIMEOUT (HZ / 10)
 
 /*
- * As it function blongs to Rx path it must be called with
- * the proper rcu_read_lock protection for its flow.
+ * As this function belongs to the RX path it must be under
+ * rcu_read_lock protection. It returns false if the frame
+ * can be processed immediately, true if it was consumed.
  */
-static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
-                                          struct tid_ampdu_rx *tid_agg_rx,
-                                          struct sk_buff *skb,
-                                          u16 mpdu_seq_num,
-                                          int bar_req)
+static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
+                                            struct tid_ampdu_rx *tid_agg_rx,
+                                            struct sk_buff *skb)
 {
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       u16 sc = le16_to_cpu(hdr->seq_ctrl);
+       u16 mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4;
        u16 head_seq_num, buf_size;
        int index;
 
@@ -2253,47 +2275,37 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
        /* frame with out of date sequence number */
        if (seq_less(mpdu_seq_num, head_seq_num)) {
                dev_kfree_skb(skb);
-               return 1;
+               return true;
        }
 
-       /* if frame sequence number exceeds our buffering window size or
-        * block Ack Request arrived - release stored frames */
-       if ((!seq_less(mpdu_seq_num, head_seq_num + buf_size)) || (bar_req)) {
-               /* new head to the ordering buffer */
-               if (bar_req)
-                       head_seq_num = mpdu_seq_num;
-               else
-                       head_seq_num =
-                               seq_inc(seq_sub(mpdu_seq_num, buf_size));
+       /*
+        * If frame the sequence number exceeds our buffering window
+        * size release some previous frames to make room for this one.
+        */
+       if (!seq_less(mpdu_seq_num, head_seq_num + buf_size)) {
+               head_seq_num = seq_inc(seq_sub(mpdu_seq_num, buf_size));
                /* release stored frames up to new head to stack */
-               while (seq_less(tid_agg_rx->head_seq_num, head_seq_num)) {
-                       index = seq_sub(tid_agg_rx->head_seq_num,
-                               tid_agg_rx->ssn)
-                               % tid_agg_rx->buf_size;
-                       ieee80211_release_reorder_frame(hw, tid_agg_rx,
-                                                       index);
-               }
-               if (bar_req)
-                       return 1;
+               ieee80211_release_reorder_frames(hw, tid_agg_rx, head_seq_num);
        }
 
-       /* now the new frame is always in the range of the reordering */
-       /* buffer window */
-       index = seq_sub(mpdu_seq_num, tid_agg_rx->ssn)
-                               % tid_agg_rx->buf_size;
+       /* Now the new frame is always in the range of the reordering buffer */
+
+       index = seq_sub(mpdu_seq_num, tid_agg_rx->ssn) % tid_agg_rx->buf_size;
+
        /* check if we already stored this frame */
        if (tid_agg_rx->reorder_buf[index]) {
                dev_kfree_skb(skb);
-               return 1;
+               return true;
        }
 
-       /* if arrived mpdu is in the right order and nothing else stored */
-       /* release it immediately */
+       /*
+        * If the current MPDU is in the right order and nothing else
+        * is stored we can process it directly, no need to buffer it.
+        */
        if (mpdu_seq_num == tid_agg_rx->head_seq_num &&
-                       tid_agg_rx->stored_mpdu_num == 0) {
-               tid_agg_rx->head_seq_num =
-                       seq_inc(tid_agg_rx->head_seq_num);
-               return 0;
+           tid_agg_rx->stored_mpdu_num == 0) {
+               tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num);
+               return false;
        }
 
        /* put the frame in the reordering buffer */
@@ -2301,8 +2313,8 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
        tid_agg_rx->reorder_time[index] = jiffies;
        tid_agg_rx->stored_mpdu_num++;
        /* release the buffer until next missing frame */
-       index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn)
-                                               tid_agg_rx->buf_size;
+       index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
+                                               tid_agg_rx->buf_size;
        if (!tid_agg_rx->reorder_buf[index] &&
            tid_agg_rx->stored_mpdu_num > 1) {
                /*
@@ -2313,12 +2325,12 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
                int skipped = 1;
                for (j = (index + 1) % tid_agg_rx->buf_size; j != index;
                     j = (j + 1) % tid_agg_rx->buf_size) {
-                       if (tid_agg_rx->reorder_buf[j] == NULL) {
+                       if (!tid_agg_rx->reorder_buf[j]) {
                                skipped++;
                                continue;
                        }
                        if (!time_after(jiffies, tid_agg_rx->reorder_time[j] +
-                                       HZ / 10))
+                                       HT_RX_REORDER_BUF_TIMEOUT))
                                break;
 
 #ifdef CONFIG_MAC80211_HT_DEBUG
@@ -2334,51 +2346,56 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
                         * Increment the head seq# also for the skipped slots.
                         */
                        tid_agg_rx->head_seq_num =
-                               (tid_agg_rx->head_seq_num + skipped) &
-                               SEQ_MASK;
+                               (tid_agg_rx->head_seq_num + skipped) & SEQ_MASK;
                        skipped = 0;
                }
        } else while (tid_agg_rx->reorder_buf[index]) {
                ieee80211_release_reorder_frame(hw, tid_agg_rx, index);
-               index = seq_sub(tid_agg_rx->head_seq_num,
-                       tid_agg_rx->ssn) % tid_agg_rx->buf_size;
+               index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
+                                                       tid_agg_rx->buf_size;
        }
-       return 1;
+
+       return true;
 }
 
-static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local,
-                                    struct sk_buff *skb)
+/*
+ * Reorder MPDUs from A-MPDUs, keeping them on a buffer. Returns
+ * true if the MPDU was buffered, false if it should be processed.
+ */
+static bool ieee80211_rx_reorder_ampdu(struct ieee80211_local *local,
+                                      struct sk_buff *skb)
 {
        struct ieee80211_hw *hw = &local->hw;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
        struct sta_info *sta;
        struct tid_ampdu_rx *tid_agg_rx;
        u16 sc;
-       u16 mpdu_seq_num;
-       u8 ret = 0;
        int tid;
 
+       if (!ieee80211_is_data_qos(hdr->frame_control))
+               return false;
+
+       /*
+        * filter the QoS data rx stream according to
+        * STA/TID and check if this STA/TID is on aggregation
+        */
+
        sta = sta_info_get(local, hdr->addr2);
        if (!sta)
-               return ret;
-
-       /* filter the QoS data rx stream according to
-        * STA/TID and check if this STA/TID is on aggregation */
-       if (!ieee80211_is_data_qos(hdr->frame_control))
-               goto end_reorder;
+               return false;
 
        tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
 
        if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_OPERATIONAL)
-               goto end_reorder;
+               return false;
 
        tid_agg_rx = sta->ampdu_mlme.tid_rx[tid];
 
        /* qos null data frames are excluded */
        if (unlikely(hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_NULLFUNC)))
-               goto end_reorder;
+               return false;
 
-       /* new un-ordered ampdu frame - process it */
+       /* new, potentially un-ordered, ampdu frame - process it */
 
        /* reset session timer */
        if (tid_agg_rx->timeout)
@@ -2390,16 +2407,11 @@ static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local,
        if (sc & IEEE80211_SCTL_FRAG) {
                ieee80211_sta_stop_rx_ba_session(sta->sdata, sta->sta.addr,
                        tid, 0, WLAN_REASON_QSTA_REQUIRE_SETUP);
-               ret = 1;
-               goto end_reorder;
+               dev_kfree_skb(skb);
+               return true;
        }
 
-       /* according to mpdu sequence number deal with reordering buffer */
-       mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4;
-       ret = ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb,
-                                               mpdu_seq_num, 0);
- end_reorder:
-       return ret;
+       return ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb);
 }
 
 /*
@@ -2457,10 +2469,6 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
                         status->rate_idx,
                         status->rate_idx))
                        goto drop;
-               /* HT rates are not in the table - use the highest legacy rate
-                * for now since other parts of mac80211 may not yet be fully
-                * MCS aware. */
-               rate = &sband->bitrates[sband->n_bitrates - 1];
        } else {
                if (WARN_ON(status->rate_idx < 0 ||
                            status->rate_idx >= sband->n_bitrates))
index 6895303..aa743a8 100644 (file)
@@ -65,7 +65,7 @@ static void ieee80211_send_refuse_measurement_request(struct ieee80211_sub_if_da
                        IEEE80211_SPCT_MSR_RPRT_MODE_REFUSED;
        msr_report->u.action.u.measurement.msr_elem.type = request_ie->type;
 
-       ieee80211_tx_skb(sdata, skb, 1);
+       ieee80211_tx_skb(sdata, skb);
 }
 
 void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
index 396a948..71f370d 100644 (file)
@@ -116,14 +116,15 @@ struct sta_info *sta_info_get(struct ieee80211_local *local, const u8 *addr)
        return sta;
 }
 
-struct sta_info *sta_info_get_by_idx(struct ieee80211_local *local, int idx,
-                                    struct net_device *dev)
+struct sta_info *sta_info_get_by_idx(struct ieee80211_sub_if_data *sdata,
+                                    int idx)
 {
+       struct ieee80211_local *local = sdata->local;
        struct sta_info *sta;
        int i = 0;
 
        list_for_each_entry_rcu(sta, &local->sta_list, list) {
-               if (dev && dev != sta->sdata->dev)
+               if (sdata != sta->sdata)
                        continue;
                if (i < idx) {
                        ++i;
@@ -147,8 +148,10 @@ struct sta_info *sta_info_get_by_idx(struct ieee80211_local *local, int idx,
 static void __sta_info_free(struct ieee80211_local *local,
                            struct sta_info *sta)
 {
-       rate_control_free_sta(sta);
-       rate_control_put(sta->rate_ctrl);
+       if (sta->rate_ctrl) {
+               rate_control_free_sta(sta);
+               rate_control_put(sta->rate_ctrl);
+       }
 
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
        printk(KERN_DEBUG "%s: Destroyed STA %pM\n",
@@ -276,6 +279,23 @@ static void sta_unblock(struct work_struct *wk)
                ieee80211_sta_ps_deliver_poll_response(sta);
 }
 
+static int sta_prepare_rate_control(struct ieee80211_local *local,
+                                   struct sta_info *sta, gfp_t gfp)
+{
+       if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL)
+               return 0;
+
+       sta->rate_ctrl = rate_control_get(local->rate_ctrl);
+       sta->rate_ctrl_priv = rate_control_alloc_sta(sta->rate_ctrl,
+                                                    &sta->sta, gfp);
+       if (!sta->rate_ctrl_priv) {
+               rate_control_put(sta->rate_ctrl);
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
 struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
                                u8 *addr, gfp_t gfp)
 {
@@ -295,11 +315,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
        sta->local = local;
        sta->sdata = sdata;
 
-       sta->rate_ctrl = rate_control_get(local->rate_ctrl);
-       sta->rate_ctrl_priv = rate_control_alloc_sta(sta->rate_ctrl,
-                                                    &sta->sta, gfp);
-       if (!sta->rate_ctrl_priv) {
-               rate_control_put(sta->rate_ctrl);
+       if (sta_prepare_rate_control(local, sta, gfp)) {
                kfree(sta);
                return NULL;
        }
index 4673454..b4810f6 100644 (file)
@@ -185,6 +185,7 @@ struct sta_ampdu_mlme {
  * @lock: used for locking all fields that require locking, see comments
  *     in the header file.
  * @flaglock: spinlock for flags accesses
+ * @drv_unblock_wk: used for driver PS unblocking
  * @listen_interval: listen interval of this station, when we're acting as AP
  * @pin_status: used internally for pinning a STA struct into memory
  * @flags: STA flags, see &enum ieee80211_sta_info_flags
@@ -225,7 +226,6 @@ struct sta_ampdu_mlme {
  * @debugfs: debug filesystem info
  * @sta: station information we share with the driver
  * @dead: set to true when sta is unlinked
- * @drv_unblock_wk used for driver PS unblocking
  */
 struct sta_info {
        /* General information, mostly static */
@@ -409,8 +409,8 @@ struct sta_info *sta_info_get(struct ieee80211_local *local, const u8 *addr);
 /*
  * Get STA info by index, BROKEN!
  */
-struct sta_info *sta_info_get_by_idx(struct ieee80211_local *local, int idx,
-                                     struct net_device *dev);
+struct sta_info *sta_info_get_by_idx(struct ieee80211_sub_if_data *sdata,
+                                    int idx);
 /*
  * Create a new STA info, caller owns returned structure
  * until sta_info_insert().
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
new file mode 100644 (file)
index 0000000..9f91fd8
--- /dev/null
@@ -0,0 +1,337 @@
+/*
+ * Copyright 2002-2005, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
+ * Copyright 2008-2009 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <net/mac80211.h>
+#include "ieee80211_i.h"
+#include "rate.h"
+#include "mesh.h"
+#include "led.h"
+
+
+void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,
+                                struct sk_buff *skb)
+{
+       struct ieee80211_local *local = hw_to_local(hw);
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       int tmp;
+
+       skb->pkt_type = IEEE80211_TX_STATUS_MSG;
+       skb_queue_tail(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS ?
+                      &local->skb_queue : &local->skb_queue_unreliable, skb);
+       tmp = skb_queue_len(&local->skb_queue) +
+               skb_queue_len(&local->skb_queue_unreliable);
+       while (tmp > IEEE80211_IRQSAFE_QUEUE_LIMIT &&
+              (skb = skb_dequeue(&local->skb_queue_unreliable))) {
+               dev_kfree_skb_irq(skb);
+               tmp--;
+               I802_DEBUG_INC(local->tx_status_drop);
+       }
+       tasklet_schedule(&local->tasklet);
+}
+EXPORT_SYMBOL(ieee80211_tx_status_irqsafe);
+
+static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
+                                           struct sta_info *sta,
+                                           struct sk_buff *skb)
+{
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+
+       /*
+        * XXX: This is temporary!
+        *
+        *      The problem here is that when we get here, the driver will
+        *      quite likely have pretty much overwritten info->control by
+        *      using info->driver_data or info->rate_driver_data. Thus,
+        *      when passing out the frame to the driver again, we would be
+        *      passing completely bogus data since the driver would then
+        *      expect a properly filled info->control. In mac80211 itself
+        *      the same problem occurs, since we need info->control.vif
+        *      internally.
+        *
+        *      To fix this, we should send the frame through TX processing
+        *      again. However, it's not that simple, since the frame will
+        *      have been software-encrypted (if applicable) already, and
+        *      encrypting it again doesn't do much good. So to properly do
+        *      that, we not only have to skip the actual 'raw' encryption
+        *      (key selection etc. still has to be done!) but also the
+        *      sequence number assignment since that impacts the crypto
+        *      encapsulation, of course.
+        *
+        *      Hence, for now, fix the bug by just dropping the frame.
+        */
+       goto drop;
+
+       sta->tx_filtered_count++;
+
+       /*
+        * Clear the TX filter mask for this STA when sending the next
+        * packet. If the STA went to power save mode, this will happen
+        * when it wakes up for the next time.
+        */
+       set_sta_flags(sta, WLAN_STA_CLEAR_PS_FILT);
+
+       /*
+        * This code races in the following way:
+        *
+        *  (1) STA sends frame indicating it will go to sleep and does so
+        *  (2) hardware/firmware adds STA to filter list, passes frame up
+        *  (3) hardware/firmware processes TX fifo and suppresses a frame
+        *  (4) we get TX status before having processed the frame and
+        *      knowing that the STA has gone to sleep.
+        *
+        * This is actually quite unlikely even when both those events are
+        * processed from interrupts coming in quickly after one another or
+        * even at the same time because we queue both TX status events and
+        * RX frames to be processed by a tasklet and process them in the
+        * same order that they were received or TX status last. Hence, there
+        * is no race as long as the frame RX is processed before the next TX
+        * status, which drivers can ensure, see below.
+        *
+        * Note that this can only happen if the hardware or firmware can
+        * actually add STAs to the filter list, if this is done by the
+        * driver in response to set_tim() (which will only reduce the race
+        * this whole filtering tries to solve, not completely solve it)
+        * this situation cannot happen.
+        *
+        * To completely solve this race drivers need to make sure that they
+        *  (a) don't mix the irq-safe/not irq-safe TX status/RX processing
+        *      functions and
+        *  (b) always process RX events before TX status events if ordering
+        *      can be unknown, for example with different interrupt status
+        *      bits.
+        */
+       if (test_sta_flags(sta, WLAN_STA_PS_STA) &&
+           skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) {
+               skb_queue_tail(&sta->tx_filtered, skb);
+               return;
+       }
+
+       if (!test_sta_flags(sta, WLAN_STA_PS_STA) &&
+           !(info->flags & IEEE80211_TX_INTFL_RETRIED)) {
+               /* Software retry the packet once */
+               info->flags |= IEEE80211_TX_INTFL_RETRIED;
+               ieee80211_add_pending_skb(local, skb);
+               return;
+       }
+
+ drop:
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+       if (net_ratelimit())
+               printk(KERN_DEBUG "%s: dropped TX filtered frame, "
+                      "queue_len=%d PS=%d @%lu\n",
+                      wiphy_name(local->hw.wiphy),
+                      skb_queue_len(&sta->tx_filtered),
+                      !!test_sta_flags(sta, WLAN_STA_PS_STA), jiffies);
+#endif
+       dev_kfree_skb(skb);
+}
+
+void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
+{
+       struct sk_buff *skb2;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       struct ieee80211_local *local = hw_to_local(hw);
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       u16 frag, type;
+       __le16 fc;
+       struct ieee80211_supported_band *sband;
+       struct ieee80211_tx_status_rtap_hdr *rthdr;
+       struct ieee80211_sub_if_data *sdata;
+       struct net_device *prev_dev = NULL;
+       struct sta_info *sta;
+       int retry_count = -1, i;
+
+       for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
+               /* the HW cannot have attempted that rate */
+               if (i >= hw->max_rates) {
+                       info->status.rates[i].idx = -1;
+                       info->status.rates[i].count = 0;
+               }
+
+               retry_count += info->status.rates[i].count;
+       }
+       if (retry_count < 0)
+               retry_count = 0;
+
+       rcu_read_lock();
+
+       sband = local->hw.wiphy->bands[info->band];
+
+       sta = sta_info_get(local, hdr->addr1);
+
+       if (sta) {
+               if (!(info->flags & IEEE80211_TX_STAT_ACK) &&
+                   test_sta_flags(sta, WLAN_STA_PS_STA)) {
+                       /*
+                        * The STA is in power save mode, so assume
+                        * that this TX packet failed because of that.
+                        */
+                       ieee80211_handle_filtered_frame(local, sta, skb);
+                       rcu_read_unlock();
+                       return;
+               }
+
+               fc = hdr->frame_control;
+
+               if ((info->flags & IEEE80211_TX_STAT_AMPDU_NO_BACK) &&
+                   (ieee80211_is_data_qos(fc))) {
+                       u16 tid, ssn;
+                       u8 *qc;
+
+                       qc = ieee80211_get_qos_ctl(hdr);
+                       tid = qc[0] & 0xf;
+                       ssn = ((le16_to_cpu(hdr->seq_ctrl) + 0x10)
+                                               & IEEE80211_SCTL_SEQ);
+                       ieee80211_send_bar(sta->sdata, hdr->addr1,
+                                          tid, ssn);
+               }
+
+               if (info->flags & IEEE80211_TX_STAT_TX_FILTERED) {
+                       ieee80211_handle_filtered_frame(local, sta, skb);
+                       rcu_read_unlock();
+                       return;
+               } else {
+                       if (!(info->flags & IEEE80211_TX_STAT_ACK))
+                               sta->tx_retry_failed++;
+                       sta->tx_retry_count += retry_count;
+               }
+
+               rate_control_tx_status(local, sband, sta, skb);
+               if (ieee80211_vif_is_mesh(&sta->sdata->vif))
+                       ieee80211s_update_metric(local, sta, skb);
+       }
+
+       rcu_read_unlock();
+
+       ieee80211_led_tx(local, 0);
+
+       /* SNMP counters
+        * Fragments are passed to low-level drivers as separate skbs, so these
+        * are actually fragments, not frames. Update frame counters only for
+        * the first fragment of the frame. */
+
+       frag = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG;
+       type = le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_FTYPE;
+
+       if (info->flags & IEEE80211_TX_STAT_ACK) {
+               if (frag == 0) {
+                       local->dot11TransmittedFrameCount++;
+                       if (is_multicast_ether_addr(hdr->addr1))
+                               local->dot11MulticastTransmittedFrameCount++;
+                       if (retry_count > 0)
+                               local->dot11RetryCount++;
+                       if (retry_count > 1)
+                               local->dot11MultipleRetryCount++;
+               }
+
+               /* This counter shall be incremented for an acknowledged MPDU
+                * with an individual address in the address 1 field or an MPDU
+                * with a multicast address in the address 1 field of type Data
+                * or Management. */
+               if (!is_multicast_ether_addr(hdr->addr1) ||
+                   type == IEEE80211_FTYPE_DATA ||
+                   type == IEEE80211_FTYPE_MGMT)
+                       local->dot11TransmittedFragmentCount++;
+       } else {
+               if (frag == 0)
+                       local->dot11FailedCount++;
+       }
+
+       /* this was a transmitted frame, but now we want to reuse it */
+       skb_orphan(skb);
+
+       /*
+        * This is a bit racy but we can avoid a lot of work
+        * with this test...
+        */
+       if (!local->monitors && !local->cooked_mntrs) {
+               dev_kfree_skb(skb);
+               return;
+       }
+
+       /* send frame to monitor interfaces now */
+
+       if (skb_headroom(skb) < sizeof(*rthdr)) {
+               printk(KERN_ERR "ieee80211_tx_status: headroom too small\n");
+               dev_kfree_skb(skb);
+               return;
+       }
+
+       rthdr = (struct ieee80211_tx_status_rtap_hdr *)
+                               skb_push(skb, sizeof(*rthdr));
+
+       memset(rthdr, 0, sizeof(*rthdr));
+       rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr));
+       rthdr->hdr.it_present =
+               cpu_to_le32((1 << IEEE80211_RADIOTAP_TX_FLAGS) |
+                           (1 << IEEE80211_RADIOTAP_DATA_RETRIES) |
+                           (1 << IEEE80211_RADIOTAP_RATE));
+
+       if (!(info->flags & IEEE80211_TX_STAT_ACK) &&
+           !is_multicast_ether_addr(hdr->addr1))
+               rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_FAIL);
+
+       /*
+        * XXX: Once radiotap gets the bitmap reset thing the vendor
+        *      extensions proposal contains, we can actually report
+        *      the whole set of tries we did.
+        */
+       if ((info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||
+           (info->status.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT))
+               rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_CTS);
+       else if (info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)
+               rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_RTS);
+       if (info->status.rates[0].idx >= 0 &&
+           !(info->status.rates[0].flags & IEEE80211_TX_RC_MCS))
+               rthdr->rate = sband->bitrates[
+                               info->status.rates[0].idx].bitrate / 5;
+
+       /* for now report the total retry_count */
+       rthdr->data_retries = retry_count;
+
+       /* XXX: is this sufficient for BPF? */
+       skb_set_mac_header(skb, 0);
+       skb->ip_summed = CHECKSUM_UNNECESSARY;
+       skb->pkt_type = PACKET_OTHERHOST;
+       skb->protocol = htons(ETH_P_802_2);
+       memset(skb->cb, 0, sizeof(skb->cb));
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+               if (sdata->vif.type == NL80211_IFTYPE_MONITOR) {
+                       if (!netif_running(sdata->dev))
+                               continue;
+
+                       if ((sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) &&
+                           !(info->flags & IEEE80211_TX_CTL_INJECTED) &&
+                           (type == IEEE80211_FTYPE_DATA))
+                               continue;
+
+                       if (prev_dev) {
+                               skb2 = skb_clone(skb, GFP_ATOMIC);
+                               if (skb2) {
+                                       skb2->dev = prev_dev;
+                                       netif_rx(skb2);
+                               }
+                       }
+
+                       prev_dev = sdata->dev;
+               }
+       }
+       if (prev_dev) {
+               skb->dev = prev_dev;
+               netif_rx(skb);
+               skb = NULL;
+       }
+       rcu_read_unlock();
+       dev_kfree_skb(skb);
+}
+EXPORT_SYMBOL(ieee80211_tx_status);
index 964b7fa..4921d72 100644 (file)
@@ -301,9 +301,9 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
 #endif
                if (key->local->ops->update_tkip_key &&
                        key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) {
-                       u8 bcast[ETH_ALEN] =
+                       static const u8 bcast[ETH_ALEN] =
                                {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
-                       u8 *sta_addr = key->sta->sta.addr;
+                       const u8 *sta_addr = key->sta->sta.addr;
 
                        if (is_multicast_ether_addr(ra))
                                sta_addr = bcast;
index 3ad053f..943def2 100644 (file)
@@ -1051,7 +1051,7 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
 
        hdr = (struct ieee80211_hdr *) skb->data;
 
-       if ((sdata->vif.type == NL80211_IFTYPE_AP_VLAN) && sdata->use_4addr)
+       if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
                tx->sta = rcu_dereference(sdata->u.vlan.sta);
        if (!tx->sta)
                tx->sta = sta_info_get(local, hdr->addr1);
@@ -1219,7 +1219,8 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx)
        CALL_TXH(ieee80211_tx_h_ps_buf);
        CALL_TXH(ieee80211_tx_h_select_key);
        CALL_TXH(ieee80211_tx_h_michael_mic_add);
-       CALL_TXH(ieee80211_tx_h_rate_ctrl);
+       if (!(tx->local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL))
+               CALL_TXH(ieee80211_tx_h_rate_ctrl);
        CALL_TXH(ieee80211_tx_h_misc);
        CALL_TXH(ieee80211_tx_h_sequence);
        CALL_TXH(ieee80211_tx_h_fragment);
@@ -1430,8 +1431,6 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
        int headroom;
        bool may_encrypt;
 
-       dev_hold(sdata->dev);
-
        if (need_dynamic_ps(local)) {
                if (local->hw.conf.flags & IEEE80211_CONF_PS) {
                        ieee80211_stop_queues_by_reason(&local->hw,
@@ -1444,7 +1443,7 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
                        msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout));
        }
 
-       info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
+       rcu_read_lock();
 
        if (unlikely(sdata->vif.type == NL80211_IFTYPE_MONITOR)) {
                int hdrlen;
@@ -1468,7 +1467,6 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
                         * support we will need a different mechanism.
                         */
 
-                       rcu_read_lock();
                        list_for_each_entry_rcu(tmp_sdata, &local->interfaces,
                                                list) {
                                if (!netif_running(tmp_sdata->dev))
@@ -1477,13 +1475,10 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
                                        continue;
                                if (compare_ether_addr(tmp_sdata->dev->dev_addr,
                                                       hdr->addr2) == 0) {
-                                       dev_hold(tmp_sdata->dev);
-                                       dev_put(sdata->dev);
                                        sdata = tmp_sdata;
                                        break;
                                }
                        }
-                       rcu_read_unlock();
                }
        }
 
@@ -1497,7 +1492,7 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
 
        if (ieee80211_skb_resize(local, skb, headroom, may_encrypt)) {
                dev_kfree_skb(skb);
-               dev_put(sdata->dev);
+               rcu_read_unlock();
                return;
        }
 
@@ -1508,13 +1503,13 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
                !is_multicast_ether_addr(hdr->addr1))
                        if (mesh_nexthop_lookup(skb, sdata)) {
                                /* skb queued: don't free */
-                               dev_put(sdata->dev);
+                               rcu_read_unlock();
                                return;
                        }
 
        ieee80211_select_queue(local, skb);
        ieee80211_tx(sdata, skb, false);
-       dev_put(sdata->dev);
+       rcu_read_unlock();
 }
 
 netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
@@ -1578,6 +1573,8 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
 
        memset(info, 0, sizeof(*info));
 
+       info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
+
        /* pass the radiotap header up to xmit */
        ieee80211_xmit(IEEE80211_DEV_TO_SUB_IF(dev), skb);
        return NETDEV_TX_OK;
@@ -1635,8 +1632,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
        switch (sdata->vif.type) {
        case NL80211_IFTYPE_AP_VLAN:
                rcu_read_lock();
-               if (sdata->use_4addr)
-                       sta = rcu_dereference(sdata->u.vlan.sta);
+               sta = rcu_dereference(sdata->u.vlan.sta);
                if (sta) {
                        fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
                        /* RA TA DA SA */
@@ -1687,21 +1683,25 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
                        /* packet from other interface */
                        struct mesh_path *mppath;
                        int is_mesh_mcast = 1;
-                       char *mesh_da;
+                       const u8 *mesh_da;
 
                        rcu_read_lock();
                        if (is_multicast_ether_addr(skb->data))
                                /* DA TA mSA AE:SA */
                                mesh_da = skb->data;
                        else {
+                               static const u8 bcast[ETH_ALEN] =
+                                       { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
                                mppath = mpp_path_lookup(skb->data, sdata);
                                if (mppath) {
                                        /* RA TA mDA mSA AE:DA SA */
                                        mesh_da = mppath->mpp;
                                        is_mesh_mcast = 0;
-                               } else
+                               } else {
                                        /* DA TA mSA AE:SA */
-                                       mesh_da = dev->broadcast;
+                                       mesh_da = bcast;
+                               }
                        }
                        hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc,
                                        mesh_da, dev->dev_addr);
@@ -1726,7 +1726,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
 #endif
        case NL80211_IFTYPE_STATION:
                memcpy(hdr.addr1, sdata->u.mgd.bssid, ETH_ALEN);
-               if (sdata->use_4addr && ethertype != ETH_P_PAE) {
+               if (sdata->u.mgd.use_4addr && ethertype != ETH_P_PAE) {
                        fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
                        /* RA TA DA SA */
                        memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN);
@@ -1964,12 +1964,10 @@ void ieee80211_tx_pending(unsigned long data)
                        }
 
                        sdata = vif_to_sdata(info->control.vif);
-                       dev_hold(sdata->dev);
                        spin_unlock_irqrestore(&local->queue_stop_reason_lock,
                                                flags);
 
                        txok = ieee80211_tx_pending_skb(local, skb);
-                       dev_put(sdata->dev);
                        if (!txok)
                                __skb_queue_head(&local->pending[i], skb);
                        spin_lock_irqsave(&local->queue_stop_reason_lock,
@@ -2282,17 +2280,12 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
 }
 EXPORT_SYMBOL(ieee80211_get_buffered_bc);
 
-void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
-                     int encrypt)
+void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
 {
-       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        skb_set_mac_header(skb, 0);
        skb_set_network_header(skb, 0);
        skb_set_transport_header(skb, 0);
 
-       if (!encrypt)
-               info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
-
        /*
         * The other path calling ieee80211_xmit is from the tasklet,
         * and while we can handle concurrent transmissions locking
index da86e15..2fb0432 100644 (file)
@@ -666,8 +666,8 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
                        elems->mesh_id_len = elen;
                        break;
                case WLAN_EID_MESH_CONFIG:
-                       elems->mesh_config = pos;
-                       elems->mesh_config_len = elen;
+                       if (elen >= sizeof(struct ieee80211_meshconf_ie))
+                               elems->mesh_config = (void *)pos;
                        break;
                case WLAN_EID_PEER_LINK:
                        elems->peer_link = pos;
@@ -872,7 +872,8 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
                WARN_ON(err);
        }
 
-       ieee80211_tx_skb(sdata, skb, 0);
+       IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
+       ieee80211_tx_skb(sdata, skb);
 }
 
 int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
@@ -974,7 +975,8 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
        skb_put(skb, ieee80211_build_preq_ies(local, pos, ie, ie_len,
                                              local->hw.conf.channel->band));
 
-       ieee80211_tx_skb(sdata, skb, 0);
+       IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
+       ieee80211_tx_skb(sdata, skb);
 }
 
 u32 ieee80211_sta_get_rates(struct ieee80211_local *local,
index 8a980f1..247123f 100644 (file)
@@ -281,16 +281,18 @@ bool ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key)
 ieee80211_rx_result
 ieee80211_crypto_wep_decrypt(struct ieee80211_rx_data *rx)
 {
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
+       struct sk_buff *skb = rx->skb;
+       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 
        if (!ieee80211_is_data(hdr->frame_control) &&
            !ieee80211_is_auth(hdr->frame_control))
                return RX_CONTINUE;
 
-       if (!(rx->status->flag & RX_FLAG_DECRYPTED)) {
+       if (!(status->flag & RX_FLAG_DECRYPTED)) {
                if (ieee80211_wep_decrypt(rx->local, rx->skb, rx->key))
                        return RX_DROP_UNUSABLE;
-       } else if (!(rx->status->flag & RX_FLAG_IV_STRIPPED)) {
+       } else if (!(status->flag & RX_FLAG_IV_STRIPPED)) {
                ieee80211_wep_remove_iv(rx->local, rx->skb, rx->key);
                /* remove ICV */
                skb_trim(rx->skb, rx->skb->len - WEP_ICV_LEN);
index 7077869..5332014 100644 (file)
@@ -85,16 +85,16 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx)
        u8 *data, *key = NULL, key_offset;
        size_t data_len;
        unsigned int hdrlen;
-       struct ieee80211_hdr *hdr;
        u8 mic[MICHAEL_MIC_LEN];
        struct sk_buff *skb = rx->skb;
+       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
        int authenticator = 1, wpa_test = 0;
 
        /* No way to verify the MIC if the hardware stripped it */
-       if (rx->status->flag & RX_FLAG_MMIC_STRIPPED)
+       if (status->flag & RX_FLAG_MMIC_STRIPPED)
                return RX_CONTINUE;
 
-       hdr = (struct ieee80211_hdr *)skb->data;
        if (!rx->key || rx->key->conf.alg != ALG_TKIP ||
            !ieee80211_has_protected(hdr->frame_control) ||
            !ieee80211_is_data_present(hdr->frame_control))
@@ -216,6 +216,7 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx)
        int hdrlen, res, hwaccel = 0, wpa_test = 0;
        struct ieee80211_key *key = rx->key;
        struct sk_buff *skb = rx->skb;
+       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
 
        hdrlen = ieee80211_hdrlen(hdr->frame_control);
 
@@ -225,8 +226,8 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx)
        if (!rx->sta || skb->len - hdrlen < 12)
                return RX_DROP_UNUSABLE;
 
-       if (rx->status->flag & RX_FLAG_DECRYPTED) {
-               if (rx->status->flag & RX_FLAG_IV_STRIPPED) {
+       if (status->flag & RX_FLAG_DECRYPTED) {
+               if (status->flag & RX_FLAG_IV_STRIPPED) {
                        /*
                         * Hardware took care of all processing, including
                         * replay protection, and stripped the ICV/IV so
@@ -442,6 +443,7 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx)
        int hdrlen;
        struct ieee80211_key *key = rx->key;
        struct sk_buff *skb = rx->skb;
+       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
        u8 pn[CCMP_PN_LEN];
        int data_len;
 
@@ -455,8 +457,8 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx)
        if (!rx->sta || data_len < 0)
                return RX_DROP_UNUSABLE;
 
-       if ((rx->status->flag & RX_FLAG_DECRYPTED) &&
-           (rx->status->flag & RX_FLAG_IV_STRIPPED))
+       if ((status->flag & RX_FLAG_DECRYPTED) &&
+           (status->flag & RX_FLAG_IV_STRIPPED))
                return RX_CONTINUE;
 
        ccmp_hdr2pn(pn, skb->data + hdrlen);
@@ -466,7 +468,7 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx)
                return RX_DROP_UNUSABLE;
        }
 
-       if (!(rx->status->flag & RX_FLAG_DECRYPTED)) {
+       if (!(status->flag & RX_FLAG_DECRYPTED)) {
                /* hardware didn't decrypt/verify MIC */
                ccmp_special_blocks(skb, pn, key->u.ccmp.rx_crypto_buf, 1);
 
@@ -563,6 +565,7 @@ ieee80211_rx_result
 ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx)
 {
        struct sk_buff *skb = rx->skb;
+       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
        struct ieee80211_key *key = rx->key;
        struct ieee80211_mmie *mmie;
        u8 aad[20], mic[8], ipn[6];
@@ -571,8 +574,8 @@ ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx)
        if (!ieee80211_is_mgmt(hdr->frame_control))
                return RX_CONTINUE;
 
-       if ((rx->status->flag & RX_FLAG_DECRYPTED) &&
-           (rx->status->flag & RX_FLAG_IV_STRIPPED))
+       if ((status->flag & RX_FLAG_DECRYPTED) &&
+           (status->flag & RX_FLAG_IV_STRIPPED))
                return RX_CONTINUE;
 
        if (skb->len < 24 + sizeof(*mmie))
@@ -591,7 +594,7 @@ ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx)
                return RX_DROP_UNUSABLE;
        }
 
-       if (!(rx->status->flag & RX_FLAG_DECRYPTED)) {
+       if (!(status->flag & RX_FLAG_DECRYPTED)) {
                /* hardware didn't decrypt/verify MIC */
                bip_aad(skb, aad);
                ieee80211_aes_cmac(key->u.aes_cmac.tfm,
index ba2efb9..09f4e16 100644 (file)
@@ -592,11 +592,13 @@ static const char *rfkill_get_type_str(enum rfkill_type type)
                return "wwan";
        case RFKILL_TYPE_GPS:
                return "gps";
+       case RFKILL_TYPE_FM:
+               return "fm";
        default:
                BUG();
        }
 
-       BUILD_BUG_ON(NUM_RFKILL_TYPES != RFKILL_TYPE_GPS + 1);
+       BUILD_BUG_ON(NUM_RFKILL_TYPES != RFKILL_TYPE_FM + 1);
 }
 
 static ssize_t rfkill_type_show(struct device *dev,
index 614bdce..90e93a5 100644 (file)
@@ -74,12 +74,6 @@ config CFG80211_REG_DEBUG
 
          If unsure, say N.
 
-config CFG80211_DEFAULT_PS_VALUE
-       int
-       default 1 if CFG80211_DEFAULT_PS
-       default 0
-       depends on CFG80211
-
 config CFG80211_DEFAULT_PS
        bool "enable powersave by default"
        depends on CFG80211
index 45bd63a..fe6f402 100644 (file)
@@ -231,7 +231,7 @@ int cfg80211_switch_netns(struct cfg80211_registered_device *rdev,
        struct wireless_dev *wdev;
        int err = 0;
 
-       if (!rdev->wiphy.netnsok)
+       if (!(rdev->wiphy.flags & WIPHY_FLAG_NETNS_OK))
                return -EOPNOTSUPP;
 
        list_for_each_entry(wdev, &rdev->netdev_list, list) {
@@ -368,7 +368,9 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
        rdev->wiphy.dev.class = &ieee80211_class;
        rdev->wiphy.dev.platform_data = rdev;
 
-       rdev->wiphy.ps_default = CONFIG_CFG80211_DEFAULT_PS_VALUE;
+#ifdef CONFIG_CFG80211_DEFAULT_PS
+       rdev->wiphy.flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
+#endif
 
        wiphy_net_set(&rdev->wiphy, &init_net);
 
@@ -483,7 +485,7 @@ int wiphy_register(struct wiphy *wiphy)
        if (IS_ERR(rdev->wiphy.debugfsdir))
                rdev->wiphy.debugfsdir = NULL;
 
-       if (wiphy->custom_regulatory) {
+       if (wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY) {
                struct regulatory_request request;
 
                request.wiphy_idx = get_wiphy_idx(wiphy);
@@ -681,7 +683,10 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
                wdev->wext.default_key = -1;
                wdev->wext.default_mgmt_key = -1;
                wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
-               wdev->wext.ps = wdev->wiphy->ps_default;
+               if (wdev->wiphy->flags & WIPHY_FLAG_PS_ON_BY_DEFAULT)
+                       wdev->wext.ps = true;
+               else
+                       wdev->wext.ps = false;
                wdev->wext.ps_timeout = 100;
                if (rdev->ops->set_power_mgmt)
                        if (rdev->ops->set_power_mgmt(wdev->wiphy, dev,
@@ -693,6 +698,10 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
 #endif
                if (!dev->ethtool_ops)
                        dev->ethtool_ops = &cfg80211_ethtool_ops;
+
+               if ((wdev->iftype == NL80211_IFTYPE_STATION ||
+                    wdev->iftype == NL80211_IFTYPE_ADHOC) && !wdev->use_4addr)
+                       dev->priv_flags |= IFF_DONT_BRIDGE;
                break;
        case NETDEV_GOING_DOWN:
                switch (wdev->iftype) {
index 5aeebb9..a9db9e6 100644 (file)
@@ -273,6 +273,8 @@ int cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
                       struct cfg80211_ibss_params *params,
                       struct cfg80211_cached_keys *connkeys);
 void cfg80211_clear_ibss(struct net_device *dev, bool nowext);
+int __cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
+                         struct net_device *dev, bool nowext);
 int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
                        struct net_device *dev, bool nowext);
 void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid);
index 39b6d92..34dfc93 100644 (file)
@@ -169,8 +169,8 @@ void cfg80211_clear_ibss(struct net_device *dev, bool nowext)
        wdev_unlock(wdev);
 }
 
-static int __cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
-                                struct net_device *dev, bool nowext)
+int __cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
+                         struct net_device *dev, bool nowext)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        int err;
index 2610b74..1001db4 100644 (file)
@@ -243,21 +243,12 @@ void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len)
 }
 EXPORT_SYMBOL(cfg80211_send_disassoc);
 
-void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr)
+static void __cfg80211_auth_remove(struct wireless_dev *wdev, const u8 *addr)
 {
-       struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct wiphy *wiphy = wdev->wiphy;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
        int i;
        bool done = false;
 
-       wdev_lock(wdev);
-
-       nl80211_send_auth_timeout(rdev, dev, addr, GFP_KERNEL);
-       if (wdev->sme_state == CFG80211_SME_CONNECTING)
-               __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0,
-                                         WLAN_STATUS_UNSPECIFIED_FAILURE,
-                                         false, NULL);
+       ASSERT_WDEV_LOCK(wdev);
 
        for (i = 0; addr && i < MAX_AUTH_BSSES; i++) {
                if (wdev->authtry_bsses[i] &&
@@ -272,6 +263,29 @@ void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr)
        }
 
        WARN_ON(!done);
+}
+
+void __cfg80211_auth_canceled(struct net_device *dev, const u8 *addr)
+{
+       __cfg80211_auth_remove(dev->ieee80211_ptr, addr);
+}
+EXPORT_SYMBOL(__cfg80211_auth_canceled);
+
+void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct wiphy *wiphy = wdev->wiphy;
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+
+       wdev_lock(wdev);
+
+       nl80211_send_auth_timeout(rdev, dev, addr, GFP_KERNEL);
+       if (wdev->sme_state == CFG80211_SME_CONNECTING)
+               __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0,
+                                         WLAN_STATUS_UNSPECIFIED_FAILURE,
+                                         false, NULL);
+
+       __cfg80211_auth_remove(wdev, addr);
 
        wdev_unlock(wdev);
 }
@@ -446,12 +460,23 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
        struct cfg80211_assoc_request req;
        struct cfg80211_internal_bss *bss;
        int i, err, slot = -1;
+       bool was_connected = false;
 
        ASSERT_WDEV_LOCK(wdev);
 
        memset(&req, 0, sizeof(req));
 
-       if (wdev->current_bss)
+       if (wdev->current_bss && prev_bssid &&
+           memcmp(wdev->current_bss->pub.bssid, prev_bssid, ETH_ALEN) == 0) {
+               /*
+                * Trying to reassociate: Allow this to proceed and let the old
+                * association to be dropped when the new one is completed.
+                */
+               if (wdev->sme_state == CFG80211_SME_CONNECTED) {
+                       was_connected = true;
+                       wdev->sme_state = CFG80211_SME_CONNECTING;
+               }
+       } else if (wdev->current_bss)
                return -EALREADY;
 
        req.ie = ie;
@@ -461,8 +486,11 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
        req.prev_bssid = prev_bssid;
        req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
                                   WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
-       if (!req.bss)
+       if (!req.bss) {
+               if (was_connected)
+                       wdev->sme_state = CFG80211_SME_CONNECTED;
                return -ENOENT;
+       }
 
        bss = bss_from_pub(req.bss);
 
@@ -480,6 +508,8 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
 
        err = rdev->ops->assoc(&rdev->wiphy, dev, &req);
  out:
+       if (err && was_connected)
+               wdev->sme_state = CFG80211_SME_CONNECTED;
        /* still a reference in wdev->auth_bsses[slot] */
        cfg80211_put_bss(req.bss);
        return err;
index 37264d5..149539a 100644 (file)
@@ -561,7 +561,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
        CMD(deauth, DEAUTHENTICATE);
        CMD(disassoc, DISASSOCIATE);
        CMD(join_ibss, JOIN_IBSS);
-       if (dev->wiphy.netnsok) {
+       if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) {
                i++;
                NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS);
        }
@@ -968,6 +968,32 @@ static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags)
        return 0;
 }
 
+static int nl80211_valid_4addr(struct cfg80211_registered_device *rdev,
+                              struct net_device *netdev, u8 use_4addr,
+                              enum nl80211_iftype iftype)
+{
+       if (!use_4addr) {
+               if (netdev && netdev->br_port)
+                       return -EBUSY;
+               return 0;
+       }
+
+       switch (iftype) {
+       case NL80211_IFTYPE_AP_VLAN:
+               if (rdev->wiphy.flags & WIPHY_FLAG_4ADDR_AP)
+                       return 0;
+               break;
+       case NL80211_IFTYPE_STATION:
+               if (rdev->wiphy.flags & WIPHY_FLAG_4ADDR_STATION)
+                       return 0;
+               break;
+       default:
+               break;
+       }
+
+       return -EOPNOTSUPP;
+}
+
 static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
 {
        struct cfg80211_registered_device *rdev;
@@ -1011,6 +1037,9 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
        if (info->attrs[NL80211_ATTR_4ADDR]) {
                params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]);
                change = true;
+               err = nl80211_valid_4addr(rdev, dev, params.use_4addr, ntype);
+               if (err)
+                       goto unlock;
        } else {
                params.use_4addr = -1;
        }
@@ -1034,6 +1063,9 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
        else
                err = 0;
 
+       if (!err && params.use_4addr != -1)
+               dev->ieee80211_ptr->use_4addr = params.use_4addr;
+
  unlock:
        dev_put(dev);
        cfg80211_unlock_rdev(rdev);
@@ -1081,8 +1113,12 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
                params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
        }
 
-       if (info->attrs[NL80211_ATTR_4ADDR])
+       if (info->attrs[NL80211_ATTR_4ADDR]) {
                params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]);
+               err = nl80211_valid_4addr(rdev, NULL, params.use_4addr, type);
+               if (err)
+                       goto unlock;
+       }
 
        err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
                                  info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
index f256dff..1f33017 100644 (file)
@@ -1008,7 +1008,7 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band,
 
        if (last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
            request_wiphy && request_wiphy == wiphy &&
-           request_wiphy->strict_regulatory) {
+           request_wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) {
                /*
                 * This gaurantees the driver's requested regulatory domain
                 * will always be used as a base for further regulatory
@@ -1051,13 +1051,13 @@ static bool ignore_reg_update(struct wiphy *wiphy,
        if (!last_request)
                return true;
        if (initiator == NL80211_REGDOM_SET_BY_CORE &&
-                 wiphy->custom_regulatory)
+           wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY)
                return true;
        /*
         * wiphy->regd will be set once the device has its own
         * desired regulatory domain set
         */
-       if (wiphy->strict_regulatory && !wiphy->regd &&
+       if (wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY && !wiphy->regd &&
            !is_world_regdom(last_request->alpha2))
                return true;
        return false;
@@ -1093,7 +1093,7 @@ static void handle_reg_beacon(struct wiphy *wiphy,
 
        chan->beacon_found = true;
 
-       if (wiphy->disable_beacon_hints)
+       if (wiphy->flags & WIPHY_FLAG_DISABLE_BEACON_HINTS)
                return;
 
        chan_before.center_freq = chan->center_freq;
@@ -1164,7 +1164,7 @@ static bool reg_is_world_roaming(struct wiphy *wiphy)
                return true;
        if (last_request &&
            last_request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE &&
-           wiphy->custom_regulatory)
+           wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY)
                return true;
        return false;
 }
@@ -1591,7 +1591,8 @@ static void reg_process_hint(struct regulatory_request *reg_request)
 
        r = __regulatory_hint(wiphy, reg_request);
        /* This is required so that the orig_* parameters are saved */
-       if (r == -EALREADY && wiphy && wiphy->strict_regulatory)
+       if (r == -EALREADY && wiphy &&
+           wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY)
                wiphy_update_regulatory(wiphy, reg_request->initiator);
 out:
        mutex_unlock(&reg_mutex);
index e2d344f..227d57b 100644 (file)
@@ -217,7 +217,7 @@ static bool is_mesh(struct cfg80211_bss *a,
                     a->len_information_elements);
        if (!ie)
                return false;
-       if (ie[1] != IEEE80211_MESH_CONFIG_LEN)
+       if (ie[1] != sizeof(struct ieee80211_meshconf_ie))
                return false;
 
        /*
@@ -225,7 +225,8 @@ static bool is_mesh(struct cfg80211_bss *a,
         * comparing since that may differ between stations taking
         * part in the same mesh.
         */
-       return memcmp(ie + 2, meshcfg, IEEE80211_MESH_CONFIG_LEN - 2) == 0;
+       return memcmp(ie + 2, meshcfg,
+           sizeof(struct ieee80211_meshconf_ie) - 2) == 0;
 }
 
 static int cmp_bss(struct cfg80211_bss *a,
@@ -399,7 +400,7 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
                                  res->pub.information_elements,
                                  res->pub.len_information_elements);
                if (!meshid || !meshcfg ||
-                   meshcfg[1] != IEEE80211_MESH_CONFIG_LEN) {
+                   meshcfg[1] != sizeof(struct ieee80211_meshconf_ie)) {
                        /* bogus mesh */
                        kref_put(&res->ref, bss_release);
                        return NULL;
@@ -865,7 +866,7 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
                        break;
                case WLAN_EID_MESH_CONFIG:
                        ismesh = true;
-                       if (ie[1] != IEEE80211_MESH_CONFIG_LEN)
+                       if (ie[1] != sizeof(struct ieee80211_meshconf_ie))
                                break;
                        buf = kmalloc(50, GFP_ATOMIC);
                        if (!buf)
@@ -873,35 +874,40 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
                        cfg = ie + 2;
                        memset(&iwe, 0, sizeof(iwe));
                        iwe.cmd = IWEVCUSTOM;
-                       sprintf(buf, "Mesh network (version %d)", cfg[0]);
+                       sprintf(buf, "Mesh Network Path Selection Protocol ID: "
+                               "0x%02X", cfg[0]);
                        iwe.u.data.length = strlen(buf);
                        current_ev = iwe_stream_add_point(info, current_ev,
                                                          end_buf,
                                                          &iwe, buf);
-                       sprintf(buf, "Path Selection Protocol ID: "
-                               "0x%02X%02X%02X%02X", cfg[1], cfg[2], cfg[3],
-                                                       cfg[4]);
+                       sprintf(buf, "Path Selection Metric ID: 0x%02X",
+                               cfg[1]);
                        iwe.u.data.length = strlen(buf);
                        current_ev = iwe_stream_add_point(info, current_ev,
                                                          end_buf,
                                                          &iwe, buf);
-                       sprintf(buf, "Path Selection Metric ID: "
-                               "0x%02X%02X%02X%02X", cfg[5], cfg[6], cfg[7],
-                                                       cfg[8]);
+                       sprintf(buf, "Congestion Control Mode ID: 0x%02X",
+                               cfg[2]);
                        iwe.u.data.length = strlen(buf);
                        current_ev = iwe_stream_add_point(info, current_ev,
                                                          end_buf,
                                                          &iwe, buf);
-                       sprintf(buf, "Congestion Control Mode ID: "
-                               "0x%02X%02X%02X%02X", cfg[9], cfg[10],
-                                                       cfg[11], cfg[12]);
+                       sprintf(buf, "Synchronization ID: 0x%02X", cfg[3]);
                        iwe.u.data.length = strlen(buf);
                        current_ev = iwe_stream_add_point(info, current_ev,
                                                          end_buf,
                                                          &iwe, buf);
-                       sprintf(buf, "Channel Precedence: "
-                               "0x%02X%02X%02X%02X", cfg[13], cfg[14],
-                                                       cfg[15], cfg[16]);
+                       sprintf(buf, "Authentication ID: 0x%02X", cfg[4]);
+                       iwe.u.data.length = strlen(buf);
+                       current_ev = iwe_stream_add_point(info, current_ev,
+                                                         end_buf,
+                                                         &iwe, buf);
+                       sprintf(buf, "Formation Info: 0x%02X", cfg[5]);
+                       iwe.u.data.length = strlen(buf);
+                       current_ev = iwe_stream_add_point(info, current_ev,
+                                                         end_buf,
+                                                         &iwe, buf);
+                       sprintf(buf, "Capabilities: 0x%02X", cfg[6]);
                        iwe.u.data.length = strlen(buf);
                        current_ev = iwe_stream_add_point(info, current_ev,
                                                          end_buf,
index 5aa39f7..59361fd 100644 (file)
@@ -658,7 +658,14 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
            !(rdev->wiphy.interface_modes & (1 << ntype)))
                return -EOPNOTSUPP;
 
+       /* if it's part of a bridge, reject changing type to station/ibss */
+       if (dev->br_port && (ntype == NL80211_IFTYPE_ADHOC ||
+                            ntype == NL80211_IFTYPE_STATION))
+               return -EBUSY;
+
        if (ntype != otype) {
+               dev->ieee80211_ptr->use_4addr = false;
+
                switch (otype) {
                case NL80211_IFTYPE_ADHOC:
                        cfg80211_leave_ibss(rdev, dev, false);
@@ -682,5 +689,34 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
 
        WARN_ON(!err && dev->ieee80211_ptr->iftype != ntype);
 
+       if (!err && params && params->use_4addr != -1)
+               dev->ieee80211_ptr->use_4addr = params->use_4addr;
+
+       if (!err) {
+               dev->priv_flags &= ~IFF_DONT_BRIDGE;
+               switch (ntype) {
+               case NL80211_IFTYPE_STATION:
+                       if (dev->ieee80211_ptr->use_4addr)
+                               break;
+                       /* fall through */
+               case NL80211_IFTYPE_ADHOC:
+                       dev->priv_flags |= IFF_DONT_BRIDGE;
+                       break;
+               case NL80211_IFTYPE_AP:
+               case NL80211_IFTYPE_AP_VLAN:
+               case NL80211_IFTYPE_WDS:
+               case NL80211_IFTYPE_MESH_POINT:
+                       /* bridging OK */
+                       break;
+               case NL80211_IFTYPE_MONITOR:
+                       /* monitor can't bridge anyway */
+                       break;
+               case NL80211_IFTYPE_UNSPECIFIED:
+               case __NL80211_IFTYPE_AFTER_LAST:
+                       /* not happening */
+                       break;
+               }
+       }
+
        return err;
 }
index 41abcbd..29091ac 100644 (file)
@@ -437,6 +437,7 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        int err, i;
+       bool rejoin = false;
 
        if (!wdev->wext.keys) {
                wdev->wext.keys = kzalloc(sizeof(*wdev->wext.keys),
@@ -466,8 +467,24 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
 
        if (remove) {
                err = 0;
-               if (wdev->current_bss)
+               if (wdev->current_bss) {
+                       /*
+                        * If removing the current TX key, we will need to
+                        * join a new IBSS without the privacy bit clear.
+                        */
+                       if (idx == wdev->wext.default_key &&
+                           wdev->iftype == NL80211_IFTYPE_ADHOC) {
+                               __cfg80211_leave_ibss(rdev, wdev->netdev, true);
+                               rejoin = true;
+                       }
                        err = rdev->ops->del_key(&rdev->wiphy, dev, idx, addr);
+               }
+               /*
+                * Applications using wireless extensions expect to be
+                * able to delete keys that don't exist, so allow that.
+                */
+               if (err == -ENOENT)
+                       err = 0;
                if (!err) {
                        if (!addr) {
                                wdev->wext.keys->params[idx].key_len = 0;
@@ -478,12 +495,9 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
                        else if (idx == wdev->wext.default_mgmt_key)
                                wdev->wext.default_mgmt_key = -1;
                }
-               /*
-                * Applications using wireless extensions expect to be
-                * able to delete keys that don't exist, so allow that.
-                */
-               if (err == -ENOENT)
-                       return 0;
+
+               if (!err && rejoin)
+                       err = cfg80211_ibss_wext_join(rdev, wdev);
 
                return err;
        }
@@ -511,11 +525,25 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
        if ((params->cipher == WLAN_CIPHER_SUITE_WEP40 ||
             params->cipher == WLAN_CIPHER_SUITE_WEP104) &&
            (tx_key || (!addr && wdev->wext.default_key == -1))) {
-               if (wdev->current_bss)
+               if (wdev->current_bss) {
+                       /*
+                        * If we are getting a new TX key from not having
+                        * had one before we need to join a new IBSS with
+                        * the privacy bit set.
+                        */
+                       if (wdev->iftype == NL80211_IFTYPE_ADHOC &&
+                           wdev->wext.default_key == -1) {
+                               __cfg80211_leave_ibss(rdev, wdev->netdev, true);
+                               rejoin = true;
+                       }
                        err = rdev->ops->set_default_key(&rdev->wiphy,
                                                         dev, idx);
-               if (!err)
+               }
+               if (!err) {
                        wdev->wext.default_key = idx;
+                       if (rejoin)
+                               err = cfg80211_ibss_wext_join(rdev, wdev);
+               }
                return err;
        }
 
@@ -539,10 +567,13 @@ static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
 {
        int err;
 
+       /* devlist mutex needed for possible IBSS re-join */
+       mutex_lock(&rdev->devlist_mtx);
        wdev_lock(dev->ieee80211_ptr);
        err = __cfg80211_set_encryption(rdev, dev, addr, remove,
                                        tx_key, idx, params);
        wdev_unlock(dev->ieee80211_ptr);
+       mutex_unlock(&rdev->devlist_mtx);
 
        return err;
 }