aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl-agn.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2011-07-23 13:24:47 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-08-08 16:04:04 -0400
commitc6baf7fb40cb141c4b510372f7dac829621ccf3f (patch)
tree7ba06f858ef0e7f904f4fd20ca1f15d0687b0784 /drivers/net/wireless/iwlwifi/iwl-agn.c
parent4d2a5d0ecd3d5350957ed8afc4cee2dbc606c7e2 (diff)
iwlagn: support new P2P implementation
The previous P2P implementation turned out to not work well and new uCode capabilities were added to support P2P. Modify the driver to take advantage of those, and also discover P2P support automatically based on a uCode flag instead of having a Kconfig symbol for P2P. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-agn.c')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c190
1 files changed, 73 insertions, 117 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index d5242fba8756..33894dde1ae3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -680,10 +680,12 @@ static void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags)
680 priv->contexts[IWL_RXON_CTX_PAN].mcast_queue = IWL_IPAN_MCAST_QUEUE; 680 priv->contexts[IWL_RXON_CTX_PAN].mcast_queue = IWL_IPAN_MCAST_QUEUE;
681 priv->contexts[IWL_RXON_CTX_PAN].interface_modes = 681 priv->contexts[IWL_RXON_CTX_PAN].interface_modes =
682 BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP); 682 BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP);
683#ifdef CONFIG_IWL_P2P 683
684 priv->contexts[IWL_RXON_CTX_PAN].interface_modes |= 684 if (ucode_flags & IWL_UCODE_TLV_FLAGS_P2P)
685 BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO); 685 priv->contexts[IWL_RXON_CTX_PAN].interface_modes |=
686#endif 686 BIT(NL80211_IFTYPE_P2P_CLIENT) |
687 BIT(NL80211_IFTYPE_P2P_GO);
688
687 priv->contexts[IWL_RXON_CTX_PAN].ap_devtype = RXON_DEV_TYPE_CP; 689 priv->contexts[IWL_RXON_CTX_PAN].ap_devtype = RXON_DEV_TYPE_CP;
688 priv->contexts[IWL_RXON_CTX_PAN].station_devtype = RXON_DEV_TYPE_2STA; 690 priv->contexts[IWL_RXON_CTX_PAN].station_devtype = RXON_DEV_TYPE_2STA;
689 priv->contexts[IWL_RXON_CTX_PAN].unused_devtype = RXON_DEV_TYPE_P2P; 691 priv->contexts[IWL_RXON_CTX_PAN].unused_devtype = RXON_DEV_TYPE_P2P;
@@ -1234,6 +1236,13 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
1234 if (!(priv->cfg->sku & EEPROM_SKU_CAP_IPAN_ENABLE)) 1236 if (!(priv->cfg->sku & EEPROM_SKU_CAP_IPAN_ENABLE))
1235 ucode_capa.flags &= ~IWL_UCODE_TLV_FLAGS_PAN; 1237 ucode_capa.flags &= ~IWL_UCODE_TLV_FLAGS_PAN;
1236 1238
1239 /*
1240 * if not PAN, then don't support P2P -- might be a uCode
1241 * packaging bug or due to the eeprom check above
1242 */
1243 if (!(ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PAN))
1244 ucode_capa.flags &= ~IWL_UCODE_TLV_FLAGS_P2P;
1245
1237 if (ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PAN) { 1246 if (ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PAN) {
1238 priv->sta_key_max_num = STA_KEY_MAX_NUM_PAN; 1247 priv->sta_key_max_num = STA_KEY_MAX_NUM_PAN;
1239 priv->cmd_queue = IWL_IPAN_CMD_QUEUE_NUM; 1248 priv->cmd_queue = IWL_IPAN_CMD_QUEUE_NUM;
@@ -1855,6 +1864,13 @@ static void __iwl_down(struct iwl_priv *priv)
1855 1864
1856 iwl_scan_cancel_timeout(priv, 200); 1865 iwl_scan_cancel_timeout(priv, 200);
1857 1866
1867 /*
1868 * If active, scanning won't cancel it, so say it expired.
1869 * No race since we hold the mutex here and a new one
1870 * can't come in at this time.
1871 */
1872 ieee80211_remain_on_channel_expired(priv->hw);
1873
1858 exit_pending = test_and_set_bit(STATUS_EXIT_PENDING, &priv->status); 1874 exit_pending = test_and_set_bit(STATUS_EXIT_PENDING, &priv->status);
1859 1875
1860 /* Stop TX queues watchdog. We need to have STATUS_EXIT_PENDING bit set 1876 /* Stop TX queues watchdog. We need to have STATUS_EXIT_PENDING bit set
@@ -2045,94 +2061,6 @@ static void iwl_bg_restart(struct work_struct *data)
2045 } 2061 }
2046} 2062}
2047 2063
2048static int iwl_mac_offchannel_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
2049 struct ieee80211_channel *chan,
2050 enum nl80211_channel_type channel_type,
2051 unsigned int wait)
2052{
2053 struct iwl_priv *priv = hw->priv;
2054 int ret;
2055
2056 /* Not supported if we don't have PAN */
2057 if (!(priv->valid_contexts & BIT(IWL_RXON_CTX_PAN))) {
2058 ret = -EOPNOTSUPP;
2059 goto free;
2060 }
2061
2062 /* Not supported on pre-P2P firmware */
2063 if (!(priv->contexts[IWL_RXON_CTX_PAN].interface_modes &
2064 BIT(NL80211_IFTYPE_P2P_CLIENT))) {
2065 ret = -EOPNOTSUPP;
2066 goto free;
2067 }
2068
2069 mutex_lock(&priv->mutex);
2070
2071 if (!priv->contexts[IWL_RXON_CTX_PAN].is_active) {
2072 /*
2073 * If the PAN context is free, use the normal
2074 * way of doing remain-on-channel offload + TX.
2075 */
2076 ret = 1;
2077 goto out;
2078 }
2079
2080 /* TODO: queue up if scanning? */
2081 if (test_bit(STATUS_SCANNING, &priv->status) ||
2082 priv->offchan_tx_skb) {
2083 ret = -EBUSY;
2084 goto out;
2085 }
2086
2087 /*
2088 * max_scan_ie_len doesn't include the blank SSID or the header,
2089 * so need to add that again here.
2090 */
2091 if (skb->len > hw->wiphy->max_scan_ie_len + 24 + 2) {
2092 ret = -ENOBUFS;
2093 goto out;
2094 }
2095
2096 priv->offchan_tx_skb = skb;
2097 priv->offchan_tx_timeout = wait;
2098 priv->offchan_tx_chan = chan;
2099
2100 ret = iwl_scan_initiate(priv, priv->contexts[IWL_RXON_CTX_PAN].vif,
2101 IWL_SCAN_OFFCH_TX, chan->band);
2102 if (ret)
2103 priv->offchan_tx_skb = NULL;
2104 out:
2105 mutex_unlock(&priv->mutex);
2106 free:
2107 if (ret < 0)
2108 kfree_skb(skb);
2109
2110 return ret;
2111}
2112
2113static int iwl_mac_offchannel_tx_cancel_wait(struct ieee80211_hw *hw)
2114{
2115 struct iwl_priv *priv = hw->priv;
2116 int ret;
2117
2118 mutex_lock(&priv->mutex);
2119
2120 if (!priv->offchan_tx_skb) {
2121 ret = -EINVAL;
2122 goto unlock;
2123 }
2124
2125 priv->offchan_tx_skb = NULL;
2126
2127 ret = iwl_scan_cancel_timeout(priv, 200);
2128 if (ret)
2129 ret = -EIO;
2130unlock:
2131 mutex_unlock(&priv->mutex);
2132
2133 return ret;
2134}
2135
2136/***************************************************************************** 2064/*****************************************************************************
2137 * 2065 *
2138 * mac80211 entry point functions 2066 * mac80211 entry point functions
@@ -3288,35 +3216,34 @@ done:
3288 IWL_DEBUG_MAC80211(priv, "leave\n"); 3216 IWL_DEBUG_MAC80211(priv, "leave\n");
3289} 3217}
3290 3218
3291static void iwlagn_disable_roc(struct iwl_priv *priv) 3219void iwlagn_disable_roc(struct iwl_priv *priv)
3292{ 3220{
3293 struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_PAN]; 3221 struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_PAN];
3294 struct ieee80211_channel *chan = ACCESS_ONCE(priv->hw->conf.channel);
3295 3222
3296 lockdep_assert_held(&priv->mutex); 3223 lockdep_assert_held(&priv->mutex);
3297 3224
3298 if (!ctx->is_active) 3225 if (!priv->hw_roc_setup)
3299 return; 3226 return;
3300 3227
3301 ctx->staging.dev_type = RXON_DEV_TYPE_2STA; 3228 ctx->staging.dev_type = RXON_DEV_TYPE_P2P;
3302 ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK; 3229 ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
3303 iwl_set_rxon_channel(priv, chan, ctx);
3304 iwl_set_flags_for_band(priv, ctx, chan->band, NULL);
3305 3230
3306 priv->hw_roc_channel = NULL; 3231 priv->hw_roc_channel = NULL;
3307 3232
3233 memset(ctx->staging.node_addr, 0, ETH_ALEN);
3234
3308 iwlagn_commit_rxon(priv, ctx); 3235 iwlagn_commit_rxon(priv, ctx);
3309 3236
3310 ctx->is_active = false; 3237 ctx->is_active = false;
3238 priv->hw_roc_setup = false;
3311} 3239}
3312 3240
3313static void iwlagn_bg_roc_done(struct work_struct *work) 3241static void iwlagn_disable_roc_work(struct work_struct *work)
3314{ 3242{
3315 struct iwl_priv *priv = container_of(work, struct iwl_priv, 3243 struct iwl_priv *priv = container_of(work, struct iwl_priv,
3316 hw_roc_work.work); 3244 hw_roc_disable_work.work);
3317 3245
3318 mutex_lock(&priv->mutex); 3246 mutex_lock(&priv->mutex);
3319 ieee80211_remain_on_channel_expired(priv->hw);
3320 iwlagn_disable_roc(priv); 3247 iwlagn_disable_roc(priv);
3321 mutex_unlock(&priv->mutex); 3248 mutex_unlock(&priv->mutex);
3322} 3249}
@@ -3327,33 +3254,63 @@ static int iwl_mac_remain_on_channel(struct ieee80211_hw *hw,
3327 int duration) 3254 int duration)
3328{ 3255{
3329 struct iwl_priv *priv = hw->priv; 3256 struct iwl_priv *priv = hw->priv;
3257 struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_PAN];
3330 int err = 0; 3258 int err = 0;
3331 3259
3332 if (!(priv->valid_contexts & BIT(IWL_RXON_CTX_PAN))) 3260 if (!(priv->valid_contexts & BIT(IWL_RXON_CTX_PAN)))
3333 return -EOPNOTSUPP; 3261 return -EOPNOTSUPP;
3334 3262
3335 if (!(priv->contexts[IWL_RXON_CTX_PAN].interface_modes & 3263 if (!(ctx->interface_modes & BIT(NL80211_IFTYPE_P2P_CLIENT)))
3336 BIT(NL80211_IFTYPE_P2P_CLIENT)))
3337 return -EOPNOTSUPP; 3264 return -EOPNOTSUPP;
3338 3265
3339 mutex_lock(&priv->mutex); 3266 mutex_lock(&priv->mutex);
3340 3267
3341 if (priv->contexts[IWL_RXON_CTX_PAN].is_active || 3268 /*
3342 test_bit(STATUS_SCAN_HW, &priv->status)) { 3269 * TODO: Remove this hack! Firmware needs to be updated
3270 * to allow longer off-channel periods in scanning for
3271 * this use case, based on a flag (and we'll need an API
3272 * flag in the firmware when it has that).
3273 */
3274 if (iwl_is_associated(priv, IWL_RXON_CTX_BSS) && duration > 80)
3275 duration = 80;
3276
3277 if (test_bit(STATUS_SCAN_HW, &priv->status)) {
3343 err = -EBUSY; 3278 err = -EBUSY;
3344 goto out; 3279 goto out;
3345 } 3280 }
3346 3281
3347 priv->contexts[IWL_RXON_CTX_PAN].is_active = true;
3348 priv->hw_roc_channel = channel; 3282 priv->hw_roc_channel = channel;
3349 priv->hw_roc_chantype = channel_type; 3283 priv->hw_roc_chantype = channel_type;
3350 priv->hw_roc_duration = DIV_ROUND_UP(duration * 1000, 1024); 3284 priv->hw_roc_duration = duration;
3351 iwlagn_commit_rxon(priv, &priv->contexts[IWL_RXON_CTX_PAN]); 3285 cancel_delayed_work(&priv->hw_roc_disable_work);
3352 queue_delayed_work(priv->workqueue, &priv->hw_roc_work, 3286
3353 msecs_to_jiffies(duration + 20)); 3287 if (!ctx->is_active) {
3288 ctx->is_active = true;
3289 ctx->staging.dev_type = RXON_DEV_TYPE_P2P;
3290 memcpy(ctx->staging.node_addr,
3291 priv->contexts[IWL_RXON_CTX_BSS].staging.node_addr,
3292 ETH_ALEN);
3293 memcpy(ctx->staging.bssid_addr,
3294 priv->contexts[IWL_RXON_CTX_BSS].staging.node_addr,
3295 ETH_ALEN);
3296 err = iwlagn_commit_rxon(priv, ctx);
3297 if (err)
3298 goto out;
3299 ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK |
3300 RXON_FILTER_PROMISC_MSK |
3301 RXON_FILTER_CTL2HOST_MSK;
3302
3303 err = iwlagn_commit_rxon(priv, ctx);
3304 if (err) {
3305 iwlagn_disable_roc(priv);
3306 goto out;
3307 }
3308 priv->hw_roc_setup = true;
3309 }
3354 3310
3355 msleep(IWL_MIN_SLOT_TIME); /* TU is almost ms */ 3311 err = iwl_scan_initiate(priv, ctx->vif, IWL_SCAN_ROC, channel->band);
3356 ieee80211_ready_on_channel(priv->hw); 3312 if (err)
3313 iwlagn_disable_roc(priv);
3357 3314
3358 out: 3315 out:
3359 mutex_unlock(&priv->mutex); 3316 mutex_unlock(&priv->mutex);
@@ -3368,9 +3325,8 @@ static int iwl_mac_cancel_remain_on_channel(struct ieee80211_hw *hw)
3368 if (!(priv->valid_contexts & BIT(IWL_RXON_CTX_PAN))) 3325 if (!(priv->valid_contexts & BIT(IWL_RXON_CTX_PAN)))
3369 return -EOPNOTSUPP; 3326 return -EOPNOTSUPP;
3370 3327
3371 cancel_delayed_work_sync(&priv->hw_roc_work);
3372
3373 mutex_lock(&priv->mutex); 3328 mutex_lock(&priv->mutex);
3329 iwl_scan_cancel_timeout(priv, priv->hw_roc_duration);
3374 iwlagn_disable_roc(priv); 3330 iwlagn_disable_roc(priv);
3375 mutex_unlock(&priv->mutex); 3331 mutex_unlock(&priv->mutex);
3376 3332
@@ -3395,7 +3351,8 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
3395 INIT_WORK(&priv->tx_flush, iwl_bg_tx_flush); 3351 INIT_WORK(&priv->tx_flush, iwl_bg_tx_flush);
3396 INIT_WORK(&priv->bt_full_concurrency, iwl_bg_bt_full_concurrency); 3352 INIT_WORK(&priv->bt_full_concurrency, iwl_bg_bt_full_concurrency);
3397 INIT_WORK(&priv->bt_runtime_config, iwl_bg_bt_runtime_config); 3353 INIT_WORK(&priv->bt_runtime_config, iwl_bg_bt_runtime_config);
3398 INIT_DELAYED_WORK(&priv->hw_roc_work, iwlagn_bg_roc_done); 3354 INIT_DELAYED_WORK(&priv->hw_roc_disable_work,
3355 iwlagn_disable_roc_work);
3399 3356
3400 iwl_setup_scan_deferred_work(priv); 3357 iwl_setup_scan_deferred_work(priv);
3401 3358
@@ -3427,6 +3384,7 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv)
3427 3384
3428 cancel_work_sync(&priv->bt_full_concurrency); 3385 cancel_work_sync(&priv->bt_full_concurrency);
3429 cancel_work_sync(&priv->bt_runtime_config); 3386 cancel_work_sync(&priv->bt_runtime_config);
3387 cancel_delayed_work_sync(&priv->hw_roc_disable_work);
3430 3388
3431 del_timer_sync(&priv->statistics_periodic); 3389 del_timer_sync(&priv->statistics_periodic);
3432 del_timer_sync(&priv->ucode_trace); 3390 del_timer_sync(&priv->ucode_trace);
@@ -3579,8 +3537,6 @@ struct ieee80211_ops iwlagn_hw_ops = {
3579 .tx_last_beacon = iwl_mac_tx_last_beacon, 3537 .tx_last_beacon = iwl_mac_tx_last_beacon,
3580 .remain_on_channel = iwl_mac_remain_on_channel, 3538 .remain_on_channel = iwl_mac_remain_on_channel,
3581 .cancel_remain_on_channel = iwl_mac_cancel_remain_on_channel, 3539 .cancel_remain_on_channel = iwl_mac_cancel_remain_on_channel,
3582 .offchannel_tx = iwl_mac_offchannel_tx,
3583 .offchannel_tx_cancel_wait = iwl_mac_offchannel_tx_cancel_wait,
3584 .rssi_callback = iwl_mac_rssi_callback, 3540 .rssi_callback = iwl_mac_rssi_callback,
3585 CFG80211_TESTMODE_CMD(iwl_testmode_cmd) 3541 CFG80211_TESTMODE_CMD(iwl_testmode_cmd)
3586 CFG80211_TESTMODE_DUMP(iwl_testmode_dump) 3542 CFG80211_TESTMODE_DUMP(iwl_testmode_dump)