diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-4965.c | 1 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn.c | 1 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-core.c | 168 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-core.h | 3 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl3945-base.c | 1 |
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 | } |
1428 | EXPORT_SYMBOL_GPL(iwl_mac_tx_last_beacon); | 1428 | EXPORT_SYMBOL_GPL(iwl_mac_tx_last_beacon); |
1429 | 1429 | ||
1430 | static int iwl_set_mode(struct iwl_priv *priv, struct ieee80211_vif *vif) | 1430 | static 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 | ||
1440 | static 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 | |||
1442 | int iwl_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) | 1477 | int 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 | } |
1527 | EXPORT_SYMBOL(iwl_mac_add_interface); | 1537 | EXPORT_SYMBOL(iwl_mac_add_interface); |
1528 | 1538 | ||
1529 | void iwl_mac_remove_interface(struct ieee80211_hw *hw, | 1539 | static 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 | |||
1569 | void 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 | ||
1934 | int 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 | } | ||
1989 | EXPORT_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); |
433 | void iwl_mac_remove_interface(struct ieee80211_hw *hw, | 433 | void iwl_mac_remove_interface(struct ieee80211_hw *hw, |
434 | struct ieee80211_vif *vif); | 434 | struct ieee80211_vif *vif); |
435 | int iwl_mac_change_interface(struct ieee80211_hw *hw, | ||
436 | struct ieee80211_vif *vif, | ||
437 | enum nl80211_iftype newtype, bool newp2p); | ||
435 | int iwl_alloc_txq_mem(struct iwl_priv *priv); | 438 | int iwl_alloc_txq_mem(struct iwl_priv *priv); |
436 | void iwl_free_txq_mem(struct iwl_priv *priv); | 439 | void iwl_free_txq_mem(struct iwl_priv *priv); |
437 | void iwlcore_tx_cmd_protection(struct iwl_priv *priv, | 440 | void 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, |