diff options
author | Wey-Yi Guy <wey-yi.w.guy@intel.com> | 2011-11-10 09:55:14 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-11-11 12:32:54 -0500 |
commit | 0b7a4c788fd08ffd147b266b7d0992f6f13ccdae (patch) | |
tree | e33e8ec6606aec0956b4b1aa01a7191795648984 /drivers/net | |
parent | a69cd040d03711215c32f89683a025d28594d2b5 (diff) |
iwlwifi: move more mac80211 callback function
Move more mac80211 related functions to _mac80211 file
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')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-core.c | 304 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-core.h | 11 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-mac80211.c | 308 |
3 files changed, 308 insertions, 315 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 989f9f3fdaf8..f7b00481a9fe 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c | |||
@@ -1120,227 +1120,8 @@ int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags, bool clear) | |||
1120 | &statistics_cmd); | 1120 | &statistics_cmd); |
1121 | } | 1121 | } |
1122 | 1122 | ||
1123 | int iwlagn_mac_conf_tx(struct ieee80211_hw *hw, | ||
1124 | struct ieee80211_vif *vif, u16 queue, | ||
1125 | const struct ieee80211_tx_queue_params *params) | ||
1126 | { | ||
1127 | struct iwl_priv *priv = hw->priv; | ||
1128 | struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; | ||
1129 | struct iwl_rxon_context *ctx = vif_priv->ctx; | ||
1130 | unsigned long flags; | ||
1131 | int q; | ||
1132 | |||
1133 | if (WARN_ON(!ctx)) | ||
1134 | return -EINVAL; | ||
1135 | |||
1136 | IWL_DEBUG_MAC80211(priv, "enter\n"); | ||
1137 | |||
1138 | if (!iwl_is_ready_rf(priv->shrd)) { | ||
1139 | IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n"); | ||
1140 | return -EIO; | ||
1141 | } | ||
1142 | |||
1143 | if (queue >= AC_NUM) { | ||
1144 | IWL_DEBUG_MAC80211(priv, "leave - queue >= AC_NUM %d\n", queue); | ||
1145 | return 0; | ||
1146 | } | ||
1147 | |||
1148 | q = AC_NUM - 1 - queue; | ||
1149 | |||
1150 | spin_lock_irqsave(&priv->shrd->lock, flags); | ||
1151 | |||
1152 | ctx->qos_data.def_qos_parm.ac[q].cw_min = | ||
1153 | cpu_to_le16(params->cw_min); | ||
1154 | ctx->qos_data.def_qos_parm.ac[q].cw_max = | ||
1155 | cpu_to_le16(params->cw_max); | ||
1156 | ctx->qos_data.def_qos_parm.ac[q].aifsn = params->aifs; | ||
1157 | ctx->qos_data.def_qos_parm.ac[q].edca_txop = | ||
1158 | cpu_to_le16((params->txop * 32)); | ||
1159 | |||
1160 | ctx->qos_data.def_qos_parm.ac[q].reserved1 = 0; | ||
1161 | |||
1162 | spin_unlock_irqrestore(&priv->shrd->lock, flags); | ||
1163 | |||
1164 | IWL_DEBUG_MAC80211(priv, "leave\n"); | ||
1165 | return 0; | ||
1166 | } | ||
1167 | |||
1168 | int iwlagn_mac_tx_last_beacon(struct ieee80211_hw *hw) | ||
1169 | { | ||
1170 | struct iwl_priv *priv = hw->priv; | ||
1171 | |||
1172 | return priv->ibss_manager == IWL_IBSS_MANAGER; | ||
1173 | } | ||
1174 | |||
1175 | static int iwl_set_mode(struct iwl_priv *priv, struct iwl_rxon_context *ctx) | ||
1176 | { | ||
1177 | iwl_connection_init_rx_config(priv, ctx); | ||
1178 | |||
1179 | iwlagn_set_rxon_chain(priv, ctx); | ||
1180 | |||
1181 | return iwlagn_commit_rxon(priv, ctx); | ||
1182 | } | ||
1183 | |||
1184 | static int iwl_setup_interface(struct iwl_priv *priv, | ||
1185 | struct iwl_rxon_context *ctx) | ||
1186 | { | ||
1187 | struct ieee80211_vif *vif = ctx->vif; | ||
1188 | int err; | ||
1189 | 1123 | ||
1190 | lockdep_assert_held(&priv->shrd->mutex); | ||
1191 | |||
1192 | /* | ||
1193 | * This variable will be correct only when there's just | ||
1194 | * a single context, but all code using it is for hardware | ||
1195 | * that supports only one context. | ||
1196 | */ | ||
1197 | priv->iw_mode = vif->type; | ||
1198 | |||
1199 | ctx->is_active = true; | ||
1200 | |||
1201 | err = iwl_set_mode(priv, ctx); | ||
1202 | if (err) { | ||
1203 | if (!ctx->always_active) | ||
1204 | ctx->is_active = false; | ||
1205 | return err; | ||
1206 | } | ||
1207 | |||
1208 | if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist && | ||
1209 | vif->type == NL80211_IFTYPE_ADHOC) { | ||
1210 | /* | ||
1211 | * pretend to have high BT traffic as long as we | ||
1212 | * are operating in IBSS mode, as this will cause | ||
1213 | * the rate scaling etc. to behave as intended. | ||
1214 | */ | ||
1215 | priv->bt_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_HIGH; | ||
1216 | } | ||
1217 | |||
1218 | return 0; | ||
1219 | } | ||
1220 | |||
1221 | int iwlagn_mac_add_interface(struct ieee80211_hw *hw, | ||
1222 | struct ieee80211_vif *vif) | ||
1223 | { | ||
1224 | struct iwl_priv *priv = hw->priv; | ||
1225 | struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; | ||
1226 | struct iwl_rxon_context *tmp, *ctx = NULL; | ||
1227 | int err; | ||
1228 | enum nl80211_iftype viftype = ieee80211_vif_type_p2p(vif); | ||
1229 | 1124 | ||
1230 | IWL_DEBUG_MAC80211(priv, "enter: type %d, addr %pM\n", | ||
1231 | viftype, vif->addr); | ||
1232 | |||
1233 | cancel_delayed_work_sync(&priv->hw_roc_disable_work); | ||
1234 | |||
1235 | mutex_lock(&priv->shrd->mutex); | ||
1236 | |||
1237 | iwlagn_disable_roc(priv); | ||
1238 | |||
1239 | if (!iwl_is_ready_rf(priv->shrd)) { | ||
1240 | IWL_WARN(priv, "Try to add interface when device not ready\n"); | ||
1241 | err = -EINVAL; | ||
1242 | goto out; | ||
1243 | } | ||
1244 | |||
1245 | for_each_context(priv, tmp) { | ||
1246 | u32 possible_modes = | ||
1247 | tmp->interface_modes | tmp->exclusive_interface_modes; | ||
1248 | |||
1249 | if (tmp->vif) { | ||
1250 | /* check if this busy context is exclusive */ | ||
1251 | if (tmp->exclusive_interface_modes & | ||
1252 | BIT(tmp->vif->type)) { | ||
1253 | err = -EINVAL; | ||
1254 | goto out; | ||
1255 | } | ||
1256 | continue; | ||
1257 | } | ||
1258 | |||
1259 | if (!(possible_modes & BIT(viftype))) | ||
1260 | continue; | ||
1261 | |||
1262 | /* have maybe usable context w/o interface */ | ||
1263 | ctx = tmp; | ||
1264 | break; | ||
1265 | } | ||
1266 | |||
1267 | if (!ctx) { | ||
1268 | err = -EOPNOTSUPP; | ||
1269 | goto out; | ||
1270 | } | ||
1271 | |||
1272 | vif_priv->ctx = ctx; | ||
1273 | ctx->vif = vif; | ||
1274 | |||
1275 | err = iwl_setup_interface(priv, ctx); | ||
1276 | if (!err) | ||
1277 | goto out; | ||
1278 | |||
1279 | ctx->vif = NULL; | ||
1280 | priv->iw_mode = NL80211_IFTYPE_STATION; | ||
1281 | out: | ||
1282 | mutex_unlock(&priv->shrd->mutex); | ||
1283 | |||
1284 | IWL_DEBUG_MAC80211(priv, "leave\n"); | ||
1285 | return err; | ||
1286 | } | ||
1287 | |||
1288 | static void iwl_teardown_interface(struct iwl_priv *priv, | ||
1289 | struct ieee80211_vif *vif, | ||
1290 | bool mode_change) | ||
1291 | { | ||
1292 | struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); | ||
1293 | |||
1294 | lockdep_assert_held(&priv->shrd->mutex); | ||
1295 | |||
1296 | if (priv->scan_vif == vif) { | ||
1297 | iwl_scan_cancel_timeout(priv, 200); | ||
1298 | iwl_force_scan_end(priv); | ||
1299 | } | ||
1300 | |||
1301 | if (!mode_change) { | ||
1302 | iwl_set_mode(priv, ctx); | ||
1303 | if (!ctx->always_active) | ||
1304 | ctx->is_active = false; | ||
1305 | } | ||
1306 | |||
1307 | /* | ||
1308 | * When removing the IBSS interface, overwrite the | ||
1309 | * BT traffic load with the stored one from the last | ||
1310 | * notification, if any. If this is a device that | ||
1311 | * doesn't implement this, this has no effect since | ||
1312 | * both values are the same and zero. | ||
1313 | */ | ||
1314 | if (vif->type == NL80211_IFTYPE_ADHOC) | ||
1315 | priv->bt_traffic_load = priv->last_bt_traffic_load; | ||
1316 | } | ||
1317 | |||
1318 | void iwlagn_mac_remove_interface(struct ieee80211_hw *hw, | ||
1319 | struct ieee80211_vif *vif) | ||
1320 | { | ||
1321 | struct iwl_priv *priv = hw->priv; | ||
1322 | struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); | ||
1323 | |||
1324 | IWL_DEBUG_MAC80211(priv, "enter\n"); | ||
1325 | |||
1326 | mutex_lock(&priv->shrd->mutex); | ||
1327 | |||
1328 | if (WARN_ON(ctx->vif != vif)) { | ||
1329 | struct iwl_rxon_context *tmp; | ||
1330 | IWL_ERR(priv, "ctx->vif = %p, vif = %p\n", ctx->vif, vif); | ||
1331 | for_each_context(priv, tmp) | ||
1332 | IWL_ERR(priv, "\tID = %d:\tctx = %p\tctx->vif = %p\n", | ||
1333 | tmp->ctxid, tmp, tmp->vif); | ||
1334 | } | ||
1335 | ctx->vif = NULL; | ||
1336 | |||
1337 | iwl_teardown_interface(priv, vif, false); | ||
1338 | |||
1339 | mutex_unlock(&priv->shrd->mutex); | ||
1340 | |||
1341 | IWL_DEBUG_MAC80211(priv, "leave\n"); | ||
1342 | |||
1343 | } | ||
1344 | 1125 | ||
1345 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 1126 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
1346 | 1127 | ||
@@ -1647,91 +1428,6 @@ int iwl_force_reset(struct iwl_priv *priv, int mode, bool external) | |||
1647 | return 0; | 1428 | return 0; |
1648 | } | 1429 | } |
1649 | 1430 | ||
1650 | int iwlagn_mac_change_interface(struct ieee80211_hw *hw, | ||
1651 | struct ieee80211_vif *vif, | ||
1652 | enum nl80211_iftype newtype, bool newp2p) | ||
1653 | { | ||
1654 | struct iwl_priv *priv = hw->priv; | ||
1655 | struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); | ||
1656 | struct iwl_rxon_context *bss_ctx = &priv->contexts[IWL_RXON_CTX_BSS]; | ||
1657 | struct iwl_rxon_context *tmp; | ||
1658 | enum nl80211_iftype newviftype = newtype; | ||
1659 | u32 interface_modes; | ||
1660 | int err; | ||
1661 | |||
1662 | IWL_DEBUG_MAC80211(priv, "enter\n"); | ||
1663 | |||
1664 | newtype = ieee80211_iftype_p2p(newtype, newp2p); | ||
1665 | |||
1666 | mutex_lock(&priv->shrd->mutex); | ||
1667 | |||
1668 | if (!ctx->vif || !iwl_is_ready_rf(priv->shrd)) { | ||
1669 | /* | ||
1670 | * Huh? But wait ... this can maybe happen when | ||
1671 | * we're in the middle of a firmware restart! | ||
1672 | */ | ||
1673 | err = -EBUSY; | ||
1674 | goto out; | ||
1675 | } | ||
1676 | |||
1677 | interface_modes = ctx->interface_modes | ctx->exclusive_interface_modes; | ||
1678 | |||
1679 | if (!(interface_modes & BIT(newtype))) { | ||
1680 | err = -EBUSY; | ||
1681 | goto out; | ||
1682 | } | ||
1683 | |||
1684 | /* | ||
1685 | * Refuse a change that should be done by moving from the PAN | ||
1686 | * context to the BSS context instead, if the BSS context is | ||
1687 | * available and can support the new interface type. | ||
1688 | */ | ||
1689 | if (ctx->ctxid == IWL_RXON_CTX_PAN && !bss_ctx->vif && | ||
1690 | (bss_ctx->interface_modes & BIT(newtype) || | ||
1691 | bss_ctx->exclusive_interface_modes & BIT(newtype))) { | ||
1692 | BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2); | ||
1693 | err = -EBUSY; | ||
1694 | goto out; | ||
1695 | } | ||
1696 | |||
1697 | if (ctx->exclusive_interface_modes & BIT(newtype)) { | ||
1698 | for_each_context(priv, tmp) { | ||
1699 | if (ctx == tmp) | ||
1700 | continue; | ||
1701 | |||
1702 | if (!tmp->vif) | ||
1703 | continue; | ||
1704 | |||
1705 | /* | ||
1706 | * The current mode switch would be exclusive, but | ||
1707 | * another context is active ... refuse the switch. | ||
1708 | */ | ||
1709 | err = -EBUSY; | ||
1710 | goto out; | ||
1711 | } | ||
1712 | } | ||
1713 | |||
1714 | /* success */ | ||
1715 | iwl_teardown_interface(priv, vif, true); | ||
1716 | vif->type = newviftype; | ||
1717 | vif->p2p = newp2p; | ||
1718 | err = iwl_setup_interface(priv, ctx); | ||
1719 | WARN_ON(err); | ||
1720 | /* | ||
1721 | * We've switched internally, but submitting to the | ||
1722 | * device may have failed for some reason. Mask this | ||
1723 | * error, because otherwise mac80211 will not switch | ||
1724 | * (and set the interface type back) and we'll be | ||
1725 | * out of sync with it. | ||
1726 | */ | ||
1727 | err = 0; | ||
1728 | |||
1729 | out: | ||
1730 | mutex_unlock(&priv->shrd->mutex); | ||
1731 | IWL_DEBUG_MAC80211(priv, "leave\n"); | ||
1732 | |||
1733 | return err; | ||
1734 | } | ||
1735 | 1431 | ||
1736 | int iwl_cmd_echo_test(struct iwl_priv *priv) | 1432 | int iwl_cmd_echo_test(struct iwl_priv *priv) |
1737 | { | 1433 | { |
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 137da3380704..ee3692adbad2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h | |||
@@ -237,10 +237,6 @@ struct iwl_cfg { | |||
237 | * L i b * | 237 | * L i b * |
238 | ***************************/ | 238 | ***************************/ |
239 | 239 | ||
240 | int iwlagn_mac_conf_tx(struct ieee80211_hw *hw, | ||
241 | struct ieee80211_vif *vif, u16 queue, | ||
242 | const struct ieee80211_tx_queue_params *params); | ||
243 | int iwlagn_mac_tx_last_beacon(struct ieee80211_hw *hw); | ||
244 | void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, struct iwl_rxon_context *ctx, | 240 | void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, struct iwl_rxon_context *ctx, |
245 | int hw_decrypt); | 241 | int hw_decrypt); |
246 | int iwl_check_rxon_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx); | 242 | int iwl_check_rxon_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx); |
@@ -260,13 +256,6 @@ bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv, | |||
260 | void iwl_connection_init_rx_config(struct iwl_priv *priv, | 256 | void iwl_connection_init_rx_config(struct iwl_priv *priv, |
261 | struct iwl_rxon_context *ctx); | 257 | struct iwl_rxon_context *ctx); |
262 | void iwl_set_rate(struct iwl_priv *priv); | 258 | void iwl_set_rate(struct iwl_priv *priv); |
263 | int iwlagn_mac_add_interface(struct ieee80211_hw *hw, | ||
264 | struct ieee80211_vif *vif); | ||
265 | void iwlagn_mac_remove_interface(struct ieee80211_hw *hw, | ||
266 | struct ieee80211_vif *vif); | ||
267 | int iwlagn_mac_change_interface(struct ieee80211_hw *hw, | ||
268 | struct ieee80211_vif *vif, | ||
269 | enum nl80211_iftype newtype, bool newp2p); | ||
270 | int iwl_cmd_echo_test(struct iwl_priv *priv); | 259 | int iwl_cmd_echo_test(struct iwl_priv *priv); |
271 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 260 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
272 | int iwl_alloc_traffic_mem(struct iwl_priv *priv); | 261 | int iwl_alloc_traffic_mem(struct iwl_priv *priv); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-mac80211.c b/drivers/net/wireless/iwlwifi/iwl-mac80211.c index c06bfe40cf38..1b2dbb006adc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-mac80211.c +++ b/drivers/net/wireless/iwlwifi/iwl-mac80211.c | |||
@@ -1493,6 +1493,314 @@ static int iwlagn_mac_set_tim(struct ieee80211_hw *hw, | |||
1493 | return 0; | 1493 | return 0; |
1494 | } | 1494 | } |
1495 | 1495 | ||
1496 | static int iwlagn_mac_conf_tx(struct ieee80211_hw *hw, | ||
1497 | struct ieee80211_vif *vif, u16 queue, | ||
1498 | const struct ieee80211_tx_queue_params *params) | ||
1499 | { | ||
1500 | struct iwl_priv *priv = hw->priv; | ||
1501 | struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; | ||
1502 | struct iwl_rxon_context *ctx = vif_priv->ctx; | ||
1503 | unsigned long flags; | ||
1504 | int q; | ||
1505 | |||
1506 | if (WARN_ON(!ctx)) | ||
1507 | return -EINVAL; | ||
1508 | |||
1509 | IWL_DEBUG_MAC80211(priv, "enter\n"); | ||
1510 | |||
1511 | if (!iwl_is_ready_rf(priv->shrd)) { | ||
1512 | IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n"); | ||
1513 | return -EIO; | ||
1514 | } | ||
1515 | |||
1516 | if (queue >= AC_NUM) { | ||
1517 | IWL_DEBUG_MAC80211(priv, "leave - queue >= AC_NUM %d\n", queue); | ||
1518 | return 0; | ||
1519 | } | ||
1520 | |||
1521 | q = AC_NUM - 1 - queue; | ||
1522 | |||
1523 | spin_lock_irqsave(&priv->shrd->lock, flags); | ||
1524 | |||
1525 | ctx->qos_data.def_qos_parm.ac[q].cw_min = | ||
1526 | cpu_to_le16(params->cw_min); | ||
1527 | ctx->qos_data.def_qos_parm.ac[q].cw_max = | ||
1528 | cpu_to_le16(params->cw_max); | ||
1529 | ctx->qos_data.def_qos_parm.ac[q].aifsn = params->aifs; | ||
1530 | ctx->qos_data.def_qos_parm.ac[q].edca_txop = | ||
1531 | cpu_to_le16((params->txop * 32)); | ||
1532 | |||
1533 | ctx->qos_data.def_qos_parm.ac[q].reserved1 = 0; | ||
1534 | |||
1535 | spin_unlock_irqrestore(&priv->shrd->lock, flags); | ||
1536 | |||
1537 | IWL_DEBUG_MAC80211(priv, "leave\n"); | ||
1538 | return 0; | ||
1539 | } | ||
1540 | |||
1541 | static int iwlagn_mac_tx_last_beacon(struct ieee80211_hw *hw) | ||
1542 | { | ||
1543 | struct iwl_priv *priv = hw->priv; | ||
1544 | |||
1545 | return priv->ibss_manager == IWL_IBSS_MANAGER; | ||
1546 | } | ||
1547 | |||
1548 | static int iwl_set_mode(struct iwl_priv *priv, struct iwl_rxon_context *ctx) | ||
1549 | { | ||
1550 | iwl_connection_init_rx_config(priv, ctx); | ||
1551 | |||
1552 | iwlagn_set_rxon_chain(priv, ctx); | ||
1553 | |||
1554 | return iwlagn_commit_rxon(priv, ctx); | ||
1555 | } | ||
1556 | |||
1557 | static int iwl_setup_interface(struct iwl_priv *priv, | ||
1558 | struct iwl_rxon_context *ctx) | ||
1559 | { | ||
1560 | struct ieee80211_vif *vif = ctx->vif; | ||
1561 | int err; | ||
1562 | |||
1563 | lockdep_assert_held(&priv->shrd->mutex); | ||
1564 | |||
1565 | /* | ||
1566 | * This variable will be correct only when there's just | ||
1567 | * a single context, but all code using it is for hardware | ||
1568 | * that supports only one context. | ||
1569 | */ | ||
1570 | priv->iw_mode = vif->type; | ||
1571 | |||
1572 | ctx->is_active = true; | ||
1573 | |||
1574 | err = iwl_set_mode(priv, ctx); | ||
1575 | if (err) { | ||
1576 | if (!ctx->always_active) | ||
1577 | ctx->is_active = false; | ||
1578 | return err; | ||
1579 | } | ||
1580 | |||
1581 | if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist && | ||
1582 | vif->type == NL80211_IFTYPE_ADHOC) { | ||
1583 | /* | ||
1584 | * pretend to have high BT traffic as long as we | ||
1585 | * are operating in IBSS mode, as this will cause | ||
1586 | * the rate scaling etc. to behave as intended. | ||
1587 | */ | ||
1588 | priv->bt_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_HIGH; | ||
1589 | } | ||
1590 | |||
1591 | return 0; | ||
1592 | } | ||
1593 | |||
1594 | static int iwlagn_mac_add_interface(struct ieee80211_hw *hw, | ||
1595 | struct ieee80211_vif *vif) | ||
1596 | { | ||
1597 | struct iwl_priv *priv = hw->priv; | ||
1598 | struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; | ||
1599 | struct iwl_rxon_context *tmp, *ctx = NULL; | ||
1600 | int err; | ||
1601 | enum nl80211_iftype viftype = ieee80211_vif_type_p2p(vif); | ||
1602 | |||
1603 | IWL_DEBUG_MAC80211(priv, "enter: type %d, addr %pM\n", | ||
1604 | viftype, vif->addr); | ||
1605 | |||
1606 | cancel_delayed_work_sync(&priv->hw_roc_disable_work); | ||
1607 | |||
1608 | mutex_lock(&priv->shrd->mutex); | ||
1609 | |||
1610 | iwlagn_disable_roc(priv); | ||
1611 | |||
1612 | if (!iwl_is_ready_rf(priv->shrd)) { | ||
1613 | IWL_WARN(priv, "Try to add interface when device not ready\n"); | ||
1614 | err = -EINVAL; | ||
1615 | goto out; | ||
1616 | } | ||
1617 | |||
1618 | for_each_context(priv, tmp) { | ||
1619 | u32 possible_modes = | ||
1620 | tmp->interface_modes | tmp->exclusive_interface_modes; | ||
1621 | |||
1622 | if (tmp->vif) { | ||
1623 | /* check if this busy context is exclusive */ | ||
1624 | if (tmp->exclusive_interface_modes & | ||
1625 | BIT(tmp->vif->type)) { | ||
1626 | err = -EINVAL; | ||
1627 | goto out; | ||
1628 | } | ||
1629 | continue; | ||
1630 | } | ||
1631 | |||
1632 | if (!(possible_modes & BIT(viftype))) | ||
1633 | continue; | ||
1634 | |||
1635 | /* have maybe usable context w/o interface */ | ||
1636 | ctx = tmp; | ||
1637 | break; | ||
1638 | } | ||
1639 | |||
1640 | if (!ctx) { | ||
1641 | err = -EOPNOTSUPP; | ||
1642 | goto out; | ||
1643 | } | ||
1644 | |||
1645 | vif_priv->ctx = ctx; | ||
1646 | ctx->vif = vif; | ||
1647 | |||
1648 | err = iwl_setup_interface(priv, ctx); | ||
1649 | if (!err) | ||
1650 | goto out; | ||
1651 | |||
1652 | ctx->vif = NULL; | ||
1653 | priv->iw_mode = NL80211_IFTYPE_STATION; | ||
1654 | out: | ||
1655 | mutex_unlock(&priv->shrd->mutex); | ||
1656 | |||
1657 | IWL_DEBUG_MAC80211(priv, "leave\n"); | ||
1658 | return err; | ||
1659 | } | ||
1660 | |||
1661 | static void iwl_teardown_interface(struct iwl_priv *priv, | ||
1662 | struct ieee80211_vif *vif, | ||
1663 | bool mode_change) | ||
1664 | { | ||
1665 | struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); | ||
1666 | |||
1667 | lockdep_assert_held(&priv->shrd->mutex); | ||
1668 | |||
1669 | if (priv->scan_vif == vif) { | ||
1670 | iwl_scan_cancel_timeout(priv, 200); | ||
1671 | iwl_force_scan_end(priv); | ||
1672 | } | ||
1673 | |||
1674 | if (!mode_change) { | ||
1675 | iwl_set_mode(priv, ctx); | ||
1676 | if (!ctx->always_active) | ||
1677 | ctx->is_active = false; | ||
1678 | } | ||
1679 | |||
1680 | /* | ||
1681 | * When removing the IBSS interface, overwrite the | ||
1682 | * BT traffic load with the stored one from the last | ||
1683 | * notification, if any. If this is a device that | ||
1684 | * doesn't implement this, this has no effect since | ||
1685 | * both values are the same and zero. | ||
1686 | */ | ||
1687 | if (vif->type == NL80211_IFTYPE_ADHOC) | ||
1688 | priv->bt_traffic_load = priv->last_bt_traffic_load; | ||
1689 | } | ||
1690 | |||
1691 | static void iwlagn_mac_remove_interface(struct ieee80211_hw *hw, | ||
1692 | struct ieee80211_vif *vif) | ||
1693 | { | ||
1694 | struct iwl_priv *priv = hw->priv; | ||
1695 | struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); | ||
1696 | |||
1697 | IWL_DEBUG_MAC80211(priv, "enter\n"); | ||
1698 | |||
1699 | mutex_lock(&priv->shrd->mutex); | ||
1700 | |||
1701 | if (WARN_ON(ctx->vif != vif)) { | ||
1702 | struct iwl_rxon_context *tmp; | ||
1703 | IWL_ERR(priv, "ctx->vif = %p, vif = %p\n", ctx->vif, vif); | ||
1704 | for_each_context(priv, tmp) | ||
1705 | IWL_ERR(priv, "\tID = %d:\tctx = %p\tctx->vif = %p\n", | ||
1706 | tmp->ctxid, tmp, tmp->vif); | ||
1707 | } | ||
1708 | ctx->vif = NULL; | ||
1709 | |||
1710 | iwl_teardown_interface(priv, vif, false); | ||
1711 | |||
1712 | mutex_unlock(&priv->shrd->mutex); | ||
1713 | |||
1714 | IWL_DEBUG_MAC80211(priv, "leave\n"); | ||
1715 | |||
1716 | } | ||
1717 | |||
1718 | static int iwlagn_mac_change_interface(struct ieee80211_hw *hw, | ||
1719 | struct ieee80211_vif *vif, | ||
1720 | enum nl80211_iftype newtype, bool newp2p) | ||
1721 | { | ||
1722 | struct iwl_priv *priv = hw->priv; | ||
1723 | struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); | ||
1724 | struct iwl_rxon_context *bss_ctx = &priv->contexts[IWL_RXON_CTX_BSS]; | ||
1725 | struct iwl_rxon_context *tmp; | ||
1726 | enum nl80211_iftype newviftype = newtype; | ||
1727 | u32 interface_modes; | ||
1728 | int err; | ||
1729 | |||
1730 | IWL_DEBUG_MAC80211(priv, "enter\n"); | ||
1731 | |||
1732 | newtype = ieee80211_iftype_p2p(newtype, newp2p); | ||
1733 | |||
1734 | mutex_lock(&priv->shrd->mutex); | ||
1735 | |||
1736 | if (!ctx->vif || !iwl_is_ready_rf(priv->shrd)) { | ||
1737 | /* | ||
1738 | * Huh? But wait ... this can maybe happen when | ||
1739 | * we're in the middle of a firmware restart! | ||
1740 | */ | ||
1741 | err = -EBUSY; | ||
1742 | goto out; | ||
1743 | } | ||
1744 | |||
1745 | interface_modes = ctx->interface_modes | ctx->exclusive_interface_modes; | ||
1746 | |||
1747 | if (!(interface_modes & BIT(newtype))) { | ||
1748 | err = -EBUSY; | ||
1749 | goto out; | ||
1750 | } | ||
1751 | |||
1752 | /* | ||
1753 | * Refuse a change that should be done by moving from the PAN | ||
1754 | * context to the BSS context instead, if the BSS context is | ||
1755 | * available and can support the new interface type. | ||
1756 | */ | ||
1757 | if (ctx->ctxid == IWL_RXON_CTX_PAN && !bss_ctx->vif && | ||
1758 | (bss_ctx->interface_modes & BIT(newtype) || | ||
1759 | bss_ctx->exclusive_interface_modes & BIT(newtype))) { | ||
1760 | BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2); | ||
1761 | err = -EBUSY; | ||
1762 | goto out; | ||
1763 | } | ||
1764 | |||
1765 | if (ctx->exclusive_interface_modes & BIT(newtype)) { | ||
1766 | for_each_context(priv, tmp) { | ||
1767 | if (ctx == tmp) | ||
1768 | continue; | ||
1769 | |||
1770 | if (!tmp->vif) | ||
1771 | continue; | ||
1772 | |||
1773 | /* | ||
1774 | * The current mode switch would be exclusive, but | ||
1775 | * another context is active ... refuse the switch. | ||
1776 | */ | ||
1777 | err = -EBUSY; | ||
1778 | goto out; | ||
1779 | } | ||
1780 | } | ||
1781 | |||
1782 | /* success */ | ||
1783 | iwl_teardown_interface(priv, vif, true); | ||
1784 | vif->type = newviftype; | ||
1785 | vif->p2p = newp2p; | ||
1786 | err = iwl_setup_interface(priv, ctx); | ||
1787 | WARN_ON(err); | ||
1788 | /* | ||
1789 | * We've switched internally, but submitting to the | ||
1790 | * device may have failed for some reason. Mask this | ||
1791 | * error, because otherwise mac80211 will not switch | ||
1792 | * (and set the interface type back) and we'll be | ||
1793 | * out of sync with it. | ||
1794 | */ | ||
1795 | err = 0; | ||
1796 | |||
1797 | out: | ||
1798 | mutex_unlock(&priv->shrd->mutex); | ||
1799 | IWL_DEBUG_MAC80211(priv, "leave\n"); | ||
1800 | |||
1801 | return err; | ||
1802 | } | ||
1803 | |||
1496 | struct ieee80211_ops iwlagn_hw_ops = { | 1804 | struct ieee80211_ops iwlagn_hw_ops = { |
1497 | .tx = iwlagn_mac_tx, | 1805 | .tx = iwlagn_mac_tx, |
1498 | .start = iwlagn_mac_start, | 1806 | .start = iwlagn_mac_start, |