]> git.karo-electronics.de Git - linux-beck.git/commitdiff
Merge branch 'wl12xx-next' into for-linville
authorLuciano Coelho <coelho@ti.com>
Tue, 4 Dec 2012 14:39:47 +0000 (16:39 +0200)
committerLuciano Coelho <coelho@ti.com>
Tue, 4 Dec 2012 14:39:47 +0000 (16:39 +0200)
Conflicts:
drivers/net/wireless/ti/wlcore/main.c

1  2 
drivers/net/wireless/ti/wlcore/main.c

index 4f1a05b92d2d9022ac82bd97cd3e0b0da53f2724,4dfd533a81c1895819289615944ab00a64933fb5..a163b0900b778f1d1cf28194874e92a7ccb45973
@@@ -2489,18 -2575,111 +2575,111 @@@ static int wlcore_join(struct wl1271 *w
        /* clear encryption type */
        wlvif->encryption_type = KEY_NONE;
  
-       if (set_assoc)
-               set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags);
        if (is_ibss)
                ret = wl12xx_cmd_role_start_ibss(wl, wlvif);
-       else
+       else {
+               if (wl->quirks & WLCORE_QUIRK_START_STA_FAILS) {
+                       /*
+                        * TODO: this is an ugly workaround for wl12xx fw
+                        * bug - we are not able to tx/rx after the first
+                        * start_sta, so make dummy start+stop calls,
+                        * and then call start_sta again.
+                        * this should be fixed in the fw.
+                        */
+                       wl12xx_cmd_role_start_sta(wl, wlvif);
+                       wl12xx_cmd_role_stop_sta(wl, wlvif);
+               }
                ret = wl12xx_cmd_role_start_sta(wl, wlvif);
 -      wlvif->channel_type = bss_conf->channel_type;
+       }
+       return ret;
+ }
+ static int wl1271_ssid_set(struct wl12xx_vif *wlvif, struct sk_buff *skb,
+                           int offset)
+ {
+       u8 ssid_len;
+       const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
+                                        skb->len - offset);
+       if (!ptr) {
+               wl1271_error("No SSID in IEs!");
+               return -ENOENT;
+       }
+       ssid_len = ptr[1];
+       if (ssid_len > IEEE80211_MAX_SSID_LEN) {
+               wl1271_error("SSID is too long!");
+               return -EINVAL;
+       }
+       wlvif->ssid_len = ssid_len;
+       memcpy(wlvif->ssid, ptr+2, ssid_len);
+       return 0;
+ }
+ static int wlcore_set_ssid(struct wl1271 *wl, struct wl12xx_vif *wlvif)
+ {
+       struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
+       struct sk_buff *skb;
+       int ieoffset;
+       /* we currently only support setting the ssid from the ap probe req */
+       if (wlvif->bss_type != BSS_TYPE_STA_BSS)
+               return -EINVAL;
+       skb = ieee80211_ap_probereq_get(wl->hw, vif);
+       if (!skb)
+               return -EINVAL;
+       ieoffset = offsetof(struct ieee80211_mgmt,
+                           u.probe_req.variable);
+       wl1271_ssid_set(wlvif, skb, ieoffset);
+       dev_kfree_skb(skb);
+       return 0;
+ }
+ static int wlcore_set_assoc(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+                           struct ieee80211_bss_conf *bss_conf,
+                           u32 sta_rate_set)
+ {
+       int ieoffset;
+       int ret;
+       wlvif->aid = bss_conf->aid;
++      wlvif->channel_type = cfg80211_get_chandef_type(&bss_conf->chandef);
+       wlvif->beacon_int = bss_conf->beacon_int;
+       wlvif->wmm_enabled = bss_conf->qos;
+       set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags);
+       /*
+        * with wl1271, we don't need to update the
+        * beacon_int and dtim_period, because the firmware
+        * updates it by itself when the first beacon is
+        * received after a join.
+        */
+       ret = wl1271_cmd_build_ps_poll(wl, wlvif, wlvif->aid);
        if (ret < 0)
-               goto out;
+               return ret;
  
-       if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
-               goto out;
+       /*
+        * Get a template for hardware connection maintenance
+        */
+       dev_kfree_skb(wlvif->probereq);
+       wlvif->probereq = wl1271_cmd_build_ap_probe_req(wl,
+                                                       wlvif,
+                                                       NULL);
+       ieoffset = offsetof(struct ieee80211_mgmt,
+                           u.probe_req.variable);
+       wl1271_ssid_set(wlvif, wlvif->probereq, ieoffset);
+       /* enable the connection monitoring feature */
+       ret = wl1271_acx_conn_monit_params(wl, wlvif, true);
+       if (ret < 0)
+               return ret;
  
        /*
         * The join command disable the keep-alive mode, shut down its process,
@@@ -4070,27 -4118,26 +4118,26 @@@ static void wl1271_bss_info_changed_sta
        }
  
        /* Handle new association with HT. Do this after join. */
-       if (sta_exists) {
-               if ((changed & BSS_CHANGED_HT) &&
-                   (bss_conf->chandef.width != NL80211_CHAN_WIDTH_20_NOHT)) {
-                       ret = wl1271_acx_set_ht_capabilities(wl,
-                                                            &sta_ht_cap,
-                                                            true,
-                                                            wlvif->sta.hlid);
-                       if (ret < 0) {
-                               wl1271_warning("Set ht cap true failed %d",
-                                              ret);
-                               goto out;
-                       }
+       if (sta_exists &&
+           (changed & BSS_CHANGED_HT)) {
+               bool enabled =
 -                      bss_conf->channel_type != NL80211_CHAN_NO_HT;
++                      bss_conf->chandef.width != NL80211_CHAN_WIDTH_20_NOHT;
+               ret = wl1271_acx_set_ht_capabilities(wl,
+                                                    &sta_ht_cap,
+                                                    enabled,
+                                                    wlvif->sta.hlid);
+               if (ret < 0) {
+                       wl1271_warning("Set ht cap failed %d", ret);
+                       goto out;
                }
-               /* handle new association without HT and disassociation */
-               else if (changed & BSS_CHANGED_ASSOC) {
-                       ret = wl1271_acx_set_ht_capabilities(wl,
-                                                            &sta_ht_cap,
-                                                            false,
-                                                            wlvif->sta.hlid);
+               if (enabled) {
+                       ret = wl1271_acx_set_ht_information(wl, wlvif,
+                                               bss_conf->ht_operation_mode);
                        if (ret < 0) {
-                               wl1271_warning("Set ht cap false failed %d",
+                               wl1271_warning("Set ht information failed %d",
                                               ret);
                                goto out;
                        }
        mutex_unlock(&wl->mutex);
  }
  
 -                   ieee80211_frequency_to_channel(ctx->channel->center_freq),
 -                   ctx->channel_type);
+ static int wlcore_op_add_chanctx(struct ieee80211_hw *hw,
+                                struct ieee80211_chanctx_conf *ctx)
+ {
+       wl1271_debug(DEBUG_MAC80211, "mac80211 add chanctx %d (type %d)",
 -                   ieee80211_frequency_to_channel(ctx->channel->center_freq),
 -                   ctx->channel_type);
++                   ieee80211_frequency_to_channel(ctx->def.chan->center_freq),
++                   cfg80211_get_chandef_type(&ctx->def));
+       return 0;
+ }
+ static void wlcore_op_remove_chanctx(struct ieee80211_hw *hw,
+                                    struct ieee80211_chanctx_conf *ctx)
+ {
+       wl1271_debug(DEBUG_MAC80211, "mac80211 remove chanctx %d (type %d)",
 -                   ieee80211_frequency_to_channel(ctx->channel->center_freq),
 -                   ctx->channel_type, changed);
++                   ieee80211_frequency_to_channel(ctx->def.chan->center_freq),
++                   cfg80211_get_chandef_type(&ctx->def));
+ }
+ static void wlcore_op_change_chanctx(struct ieee80211_hw *hw,
+                                    struct ieee80211_chanctx_conf *ctx,
+                                    u32 changed)
+ {
+       wl1271_debug(DEBUG_MAC80211,
+                    "mac80211 change chanctx %d (type %d) changed 0x%x",
 -              ctx->channel->center_freq);
++                   ieee80211_frequency_to_channel(ctx->def.chan->center_freq),
++                   cfg80211_get_chandef_type(&ctx->def), changed);
+ }
+ static int wlcore_op_assign_vif_chanctx(struct ieee80211_hw *hw,
+                                       struct ieee80211_vif *vif,
+                                       struct ieee80211_chanctx_conf *ctx)
+ {
+       struct wl1271 *wl = hw->priv;
+       struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
+       int channel = ieee80211_frequency_to_channel(
 -                   wlvif->role_id, channel, ctx->channel_type);
++              ctx->def.chan->center_freq);
+       wl1271_debug(DEBUG_MAC80211,
+                    "mac80211 assign chanctx (role %d) %d (type %d)",
 -      wlvif->band = ctx->channel->band;
++                   wlvif->role_id, channel, cfg80211_get_chandef_type(&ctx->def));
+       mutex_lock(&wl->mutex);
 -      wlvif->channel_type = ctx->channel_type;
++      wlvif->band = ctx->def.chan->band;
+       wlvif->channel = channel;
 -                   ieee80211_frequency_to_channel(ctx->channel->center_freq),
 -                   ctx->channel_type);
++      wlvif->channel_type = cfg80211_get_chandef_type(&ctx->def);
+       /* update default rates according to the band */
+       wl1271_set_band_rate(wl, wlvif);
+       mutex_unlock(&wl->mutex);
+       return 0;
+ }
+ static void wlcore_op_unassign_vif_chanctx(struct ieee80211_hw *hw,
+                                          struct ieee80211_vif *vif,
+                                          struct ieee80211_chanctx_conf *ctx)
+ {
+       struct wl1271 *wl = hw->priv;
+       struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
+       wl1271_debug(DEBUG_MAC80211,
+                    "mac80211 unassign chanctx (role %d) %d (type %d)",
+                    wlvif->role_id,
++                   ieee80211_frequency_to_channel(ctx->def.chan->center_freq),
++                   cfg80211_get_chandef_type(&ctx->def));
+       wl1271_tx_flush(wl);
+ }
  static int wl1271_op_conf_tx(struct ieee80211_hw *hw,
                             struct ieee80211_vif *vif, u16 queue,
                             const struct ieee80211_tx_queue_params *params)
@@@ -4684,6 -4869,145 +4869,144 @@@ static void wlcore_op_flush(struct ieee
        wl1271_tx_flush(wl);
  }
  
 -                                     enum nl80211_channel_type channel_type,
+ static int wlcore_op_remain_on_channel(struct ieee80211_hw *hw,
+                                      struct ieee80211_vif *vif,
+                                      struct ieee80211_channel *chan,
+                                      int duration)
+ {
+       struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
+       struct wl1271 *wl = hw->priv;
+       int channel, ret = 0;
+       channel = ieee80211_frequency_to_channel(chan->center_freq);
+       wl1271_debug(DEBUG_MAC80211, "mac80211 roc %d (%d)",
+                    channel, wlvif->role_id);
+       mutex_lock(&wl->mutex);
+       if (unlikely(wl->state != WLCORE_STATE_ON))
+               goto out;
+       /* return EBUSY if we can't ROC right now */
+       if (WARN_ON(wl->roc_vif ||
+                   find_first_bit(wl->roc_map,
+                                  WL12XX_MAX_ROLES) < WL12XX_MAX_ROLES)) {
+               ret = -EBUSY;
+               goto out;
+       }
+       ret = wl1271_ps_elp_wakeup(wl);
+       if (ret < 0)
+               goto out;
+       ret = wl12xx_start_dev(wl, wlvif, chan->band, channel);
+       if (ret < 0)
+               goto out_sleep;
+       wl->roc_vif = vif;
+       ieee80211_queue_delayed_work(hw, &wl->roc_complete_work,
+                                    msecs_to_jiffies(duration));
+ out_sleep:
+       wl1271_ps_elp_sleep(wl);
+ out:
+       mutex_unlock(&wl->mutex);
+       return ret;
+ }
+ static int __wlcore_roc_completed(struct wl1271 *wl)
+ {
+       struct wl12xx_vif *wlvif;
+       int ret;
+       /* already completed */
+       if (unlikely(!wl->roc_vif))
+               return 0;
+       wlvif = wl12xx_vif_to_data(wl->roc_vif);
+       if (!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
+               return -EBUSY;
+       ret = wl12xx_stop_dev(wl, wlvif);
+       if (ret < 0)
+               return ret;
+       wl->roc_vif = NULL;
+       return 0;
+ }
+ static int wlcore_roc_completed(struct wl1271 *wl)
+ {
+       int ret;
+       wl1271_debug(DEBUG_MAC80211, "roc complete");
+       mutex_lock(&wl->mutex);
+       if (unlikely(wl->state != WLCORE_STATE_ON)) {
+               ret = -EBUSY;
+               goto out;
+       }
+       ret = wl1271_ps_elp_wakeup(wl);
+       if (ret < 0)
+               goto out;
+       ret = __wlcore_roc_completed(wl);
+       wl1271_ps_elp_sleep(wl);
+ out:
+       mutex_unlock(&wl->mutex);
+       return ret;
+ }
+ static void wlcore_roc_complete_work(struct work_struct *work)
+ {
+       struct delayed_work *dwork;
+       struct wl1271 *wl;
+       int ret;
+       dwork = container_of(work, struct delayed_work, work);
+       wl = container_of(dwork, struct wl1271, roc_complete_work);
+       ret = wlcore_roc_completed(wl);
+       if (!ret)
+               ieee80211_remain_on_channel_expired(wl->hw);
+ }
+ static int wlcore_op_cancel_remain_on_channel(struct ieee80211_hw *hw)
+ {
+       struct wl1271 *wl = hw->priv;
+       wl1271_debug(DEBUG_MAC80211, "mac80211 croc");
+       /* TODO: per-vif */
+       wl1271_tx_flush(wl);
+       /*
+        * we can't just flush_work here, because it might deadlock
+        * (as we might get called from the same workqueue)
+        */
+       cancel_delayed_work_sync(&wl->roc_complete_work);
+       wlcore_roc_completed(wl);
+       return 0;
+ }
+ static void wlcore_op_sta_rc_update(struct ieee80211_hw *hw,
+                                   struct ieee80211_vif *vif,
+                                   struct ieee80211_sta *sta,
+                                   u32 changed)
+ {
+       struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
+       struct wl1271 *wl = hw->priv;
+       wlcore_hw_sta_rc_update(wl, wlvif, sta, changed);
+ }
  static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
  {
        struct wl1271 *wl = hw->priv;