aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2010-10-23 12:15:43 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-11-15 13:24:55 -0500
commitd4daaea656e0b5543c2e37c31934cea8f044b31e (patch)
tree9c90e1966b64056ab83dc348c75d9bd6771415c5
parentbd50a8ab9f48787109f6ff761c8f0e185e3d0690 (diff)
iwlwifi: implement switching iftype while up
Implement switching the interface while an interface is up in iwlwifi. Interfaces have to stay on the context they were created on. 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>
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965.c1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c168
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl3945-base.c1
5 files changed, 130 insertions, 44 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index 8f07964e4305..6d313c817040 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -2589,6 +2589,7 @@ struct ieee80211_ops iwl4965_hw_ops = {
2589 .stop = iwlagn_mac_stop, 2589 .stop = iwlagn_mac_stop,
2590 .add_interface = iwl_mac_add_interface, 2590 .add_interface = iwl_mac_add_interface,
2591 .remove_interface = iwl_mac_remove_interface, 2591 .remove_interface = iwl_mac_remove_interface,
2592 .change_interface = iwl_mac_change_interface,
2592 .config = iwl_legacy_mac_config, 2593 .config = iwl_legacy_mac_config,
2593 .configure_filter = iwlagn_configure_filter, 2594 .configure_filter = iwlagn_configure_filter,
2594 .set_key = iwlagn_mac_set_key, 2595 .set_key = iwlagn_mac_set_key,
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 1050f31d90a4..481c993c2491 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -3909,6 +3909,7 @@ struct ieee80211_ops iwlagn_hw_ops = {
3909 .stop = iwlagn_mac_stop, 3909 .stop = iwlagn_mac_stop,
3910 .add_interface = iwl_mac_add_interface, 3910 .add_interface = iwl_mac_add_interface,
3911 .remove_interface = iwl_mac_remove_interface, 3911 .remove_interface = iwl_mac_remove_interface,
3912 .change_interface = iwl_mac_change_interface,
3912 .config = iwlagn_mac_config, 3913 .config = iwlagn_mac_config,
3913 .configure_filter = iwlagn_configure_filter, 3914 .configure_filter = iwlagn_configure_filter,
3914 .set_key = iwlagn_mac_set_key, 3915 .set_key = iwlagn_mac_set_key,
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index 776713c6a7ff..180d09ec3136 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -1427,10 +1427,8 @@ int iwl_mac_tx_last_beacon(struct ieee80211_hw *hw)
1427} 1427}
1428EXPORT_SYMBOL_GPL(iwl_mac_tx_last_beacon); 1428EXPORT_SYMBOL_GPL(iwl_mac_tx_last_beacon);
1429 1429
1430static int iwl_set_mode(struct iwl_priv *priv, struct ieee80211_vif *vif) 1430static int iwl_set_mode(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
1431{ 1431{
1432 struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
1433
1434 iwl_connection_init_rx_config(priv, ctx); 1432 iwl_connection_init_rx_config(priv, ctx);
1435 1433
1436 if (priv->cfg->ops->hcmd->set_rxon_chain) 1434 if (priv->cfg->ops->hcmd->set_rxon_chain)
@@ -1439,12 +1437,49 @@ static int iwl_set_mode(struct iwl_priv *priv, struct ieee80211_vif *vif)
1439 return iwlcore_commit_rxon(priv, ctx); 1437 return iwlcore_commit_rxon(priv, ctx);
1440} 1438}
1441 1439
1440static int iwl_setup_interface(struct iwl_priv *priv,
1441 struct iwl_rxon_context *ctx)
1442{
1443 struct ieee80211_vif *vif = ctx->vif;
1444 int err;
1445
1446 lockdep_assert_held(&priv->mutex);
1447
1448 /*
1449 * This variable will be correct only when there's just
1450 * a single context, but all code using it is for hardware
1451 * that supports only one context.
1452 */
1453 priv->iw_mode = vif->type;
1454
1455 ctx->is_active = true;
1456
1457 err = iwl_set_mode(priv, ctx);
1458 if (err) {
1459 if (!ctx->always_active)
1460 ctx->is_active = false;
1461 return err;
1462 }
1463
1464 if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist &&
1465 vif->type == NL80211_IFTYPE_ADHOC) {
1466 /*
1467 * pretend to have high BT traffic as long as we
1468 * are operating in IBSS mode, as this will cause
1469 * the rate scaling etc. to behave as intended.
1470 */
1471 priv->bt_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_HIGH;
1472 }
1473
1474 return 0;
1475}
1476
1442int iwl_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) 1477int iwl_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
1443{ 1478{
1444 struct iwl_priv *priv = hw->priv; 1479 struct iwl_priv *priv = hw->priv;
1445 struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; 1480 struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
1446 struct iwl_rxon_context *tmp, *ctx = NULL; 1481 struct iwl_rxon_context *tmp, *ctx = NULL;
1447 int err = 0; 1482 int err;
1448 1483
1449 IWL_DEBUG_MAC80211(priv, "enter: type %d, addr %pM\n", 1484 IWL_DEBUG_MAC80211(priv, "enter: type %d, addr %pM\n",
1450 vif->type, vif->addr); 1485 vif->type, vif->addr);
@@ -1486,36 +1521,11 @@ int iwl_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
1486 1521
1487 vif_priv->ctx = ctx; 1522 vif_priv->ctx = ctx;
1488 ctx->vif = vif; 1523 ctx->vif = vif;
1489 /*
1490 * This variable will be correct only when there's just
1491 * a single context, but all code using it is for hardware
1492 * that supports only one context.
1493 */
1494 priv->iw_mode = vif->type;
1495
1496 ctx->is_active = true;
1497
1498 err = iwl_set_mode(priv, vif);
1499 if (err) {
1500 if (!ctx->always_active)
1501 ctx->is_active = false;
1502 goto out_err;
1503 }
1504
1505 if (priv->cfg->bt_params &&
1506 priv->cfg->bt_params->advanced_bt_coexist &&
1507 vif->type == NL80211_IFTYPE_ADHOC) {
1508 /*
1509 * pretend to have high BT traffic as long as we
1510 * are operating in IBSS mode, as this will cause
1511 * the rate scaling etc. to behave as intended.
1512 */
1513 priv->bt_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_HIGH;
1514 }
1515 1524
1516 goto out; 1525 err = iwl_setup_interface(priv, ctx);
1526 if (!err)
1527 goto out;
1517 1528
1518 out_err:
1519 ctx->vif = NULL; 1529 ctx->vif = NULL;
1520 priv->iw_mode = NL80211_IFTYPE_STATION; 1530 priv->iw_mode = NL80211_IFTYPE_STATION;
1521 out: 1531 out:
@@ -1526,27 +1536,24 @@ int iwl_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
1526} 1536}
1527EXPORT_SYMBOL(iwl_mac_add_interface); 1537EXPORT_SYMBOL(iwl_mac_add_interface);
1528 1538
1529void iwl_mac_remove_interface(struct ieee80211_hw *hw, 1539static void iwl_teardown_interface(struct iwl_priv *priv,
1530 struct ieee80211_vif *vif) 1540 struct ieee80211_vif *vif,
1541 bool mode_change)
1531{ 1542{
1532 struct iwl_priv *priv = hw->priv;
1533 struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); 1543 struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
1534 1544
1535 IWL_DEBUG_MAC80211(priv, "enter\n"); 1545 lockdep_assert_held(&priv->mutex);
1536
1537 mutex_lock(&priv->mutex);
1538
1539 WARN_ON(ctx->vif != vif);
1540 ctx->vif = NULL;
1541 1546
1542 if (priv->scan_vif == vif) { 1547 if (priv->scan_vif == vif) {
1543 iwl_scan_cancel_timeout(priv, 200); 1548 iwl_scan_cancel_timeout(priv, 200);
1544 iwl_force_scan_end(priv); 1549 iwl_force_scan_end(priv);
1545 } 1550 }
1546 iwl_set_mode(priv, vif);
1547 1551
1548 if (!ctx->always_active) 1552 if (!mode_change) {
1549 ctx->is_active = false; 1553 iwl_set_mode(priv, ctx);
1554 if (!ctx->always_active)
1555 ctx->is_active = false;
1556 }
1550 1557
1551 /* 1558 /*
1552 * When removing the IBSS interface, overwrite the 1559 * When removing the IBSS interface, overwrite the
@@ -1557,6 +1564,22 @@ void iwl_mac_remove_interface(struct ieee80211_hw *hw,
1557 */ 1564 */
1558 if (vif->type == NL80211_IFTYPE_ADHOC) 1565 if (vif->type == NL80211_IFTYPE_ADHOC)
1559 priv->bt_traffic_load = priv->notif_bt_traffic_load; 1566 priv->bt_traffic_load = priv->notif_bt_traffic_load;
1567}
1568
1569void iwl_mac_remove_interface(struct ieee80211_hw *hw,
1570 struct ieee80211_vif *vif)
1571{
1572 struct iwl_priv *priv = hw->priv;
1573 struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
1574
1575 IWL_DEBUG_MAC80211(priv, "enter\n");
1576
1577 mutex_lock(&priv->mutex);
1578
1579 WARN_ON(ctx->vif != vif);
1580 ctx->vif = NULL;
1581
1582 iwl_teardown_interface(priv, vif, false);
1560 1583
1561 memset(priv->bssid, 0, ETH_ALEN); 1584 memset(priv->bssid, 0, ETH_ALEN);
1562 mutex_unlock(&priv->mutex); 1585 mutex_unlock(&priv->mutex);
@@ -1908,6 +1931,63 @@ int iwl_force_reset(struct iwl_priv *priv, int mode, bool external)
1908 return 0; 1931 return 0;
1909} 1932}
1910 1933
1934int iwl_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
1935 enum nl80211_iftype newtype, bool newp2p)
1936{
1937 struct iwl_priv *priv = hw->priv;
1938 struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
1939 struct iwl_rxon_context *tmp;
1940 u32 interface_modes;
1941 int err;
1942
1943 newtype = ieee80211_iftype_p2p(newtype, newp2p);
1944
1945 mutex_lock(&priv->mutex);
1946
1947 interface_modes = ctx->interface_modes | ctx->exclusive_interface_modes;
1948
1949 if (!(interface_modes & BIT(newtype))) {
1950 err = -EBUSY;
1951 goto out;
1952 }
1953
1954 if (ctx->exclusive_interface_modes & BIT(newtype)) {
1955 for_each_context(priv, tmp) {
1956 if (ctx == tmp)
1957 continue;
1958
1959 if (!tmp->vif)
1960 continue;
1961
1962 /*
1963 * The current mode switch would be exclusive, but
1964 * another context is active ... refuse the switch.
1965 */
1966 err = -EBUSY;
1967 goto out;
1968 }
1969 }
1970
1971 /* success */
1972 iwl_teardown_interface(priv, vif, true);
1973 vif->type = newtype;
1974 err = iwl_setup_interface(priv, ctx);
1975 WARN_ON(err);
1976 /*
1977 * We've switched internally, but submitting to the
1978 * device may have failed for some reason. Mask this
1979 * error, because otherwise mac80211 will not switch
1980 * (and set the interface type back) and we'll be
1981 * out of sync with it.
1982 */
1983 err = 0;
1984
1985 out:
1986 mutex_unlock(&priv->mutex);
1987 return err;
1988}
1989EXPORT_SYMBOL(iwl_mac_change_interface);
1990
1911/** 1991/**
1912 * iwl_bg_monitor_recover - Timer callback to check for stuck queue and recover 1992 * iwl_bg_monitor_recover - Timer callback to check for stuck queue and recover
1913 * 1993 *
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index 854613e4f2be..8fb063affac4 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -432,6 +432,9 @@ int iwl_mac_add_interface(struct ieee80211_hw *hw,
432 struct ieee80211_vif *vif); 432 struct ieee80211_vif *vif);
433void iwl_mac_remove_interface(struct ieee80211_hw *hw, 433void iwl_mac_remove_interface(struct ieee80211_hw *hw,
434 struct ieee80211_vif *vif); 434 struct ieee80211_vif *vif);
435int iwl_mac_change_interface(struct ieee80211_hw *hw,
436 struct ieee80211_vif *vif,
437 enum nl80211_iftype newtype, bool newp2p);
435int iwl_alloc_txq_mem(struct iwl_priv *priv); 438int iwl_alloc_txq_mem(struct iwl_priv *priv);
436void iwl_free_txq_mem(struct iwl_priv *priv); 439void iwl_free_txq_mem(struct iwl_priv *priv);
437void iwlcore_tx_cmd_protection(struct iwl_priv *priv, 440void iwlcore_tx_cmd_protection(struct iwl_priv *priv,
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index 73f2f3fcb49c..6152a86c19b5 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -3832,6 +3832,7 @@ struct ieee80211_ops iwl3945_hw_ops = {
3832 .stop = iwl3945_mac_stop, 3832 .stop = iwl3945_mac_stop,
3833 .add_interface = iwl_mac_add_interface, 3833 .add_interface = iwl_mac_add_interface,
3834 .remove_interface = iwl_mac_remove_interface, 3834 .remove_interface = iwl_mac_remove_interface,
3835 .change_interface = iwl_mac_change_interface,
3835 .config = iwl_legacy_mac_config, 3836 .config = iwl_legacy_mac_config,
3836 .configure_filter = iwl3945_configure_filter, 3837 .configure_filter = iwl3945_configure_filter,
3837 .set_key = iwl3945_mac_set_key, 3838 .set_key = iwl3945_mac_set_key,