aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl-4965.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2010-10-23 12:15:41 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-11-15 13:24:53 -0500
commit2295c66b68ae160dde2e6e2dc4f3061105153bfc (patch)
tree9bfbaf309944d5f72bd36b291680ddf370733c1a /drivers/net/wireless/iwlwifi/iwl-4965.c
parent2d4e43c3c6783f956163c11568303b0390725e28 (diff)
iwlagn: new RXON processing for modern devices
In order to simplify the flow, and make new enhancements easier, separate out the RXON processing for modern AGN (5000 and newer) from RXON processing for the older 3945 and 4965 devices. Avoid changing these old ones to avoid regressions and move their code to a new file (iwl-legacy.c). 4965 gets the commit_rxon that used to be common for all AGN devices, but with removed PAN support. The new RXON processing is more central and does more work in committing, so that it is easier to follow. To make it more evident what is split out for legacy, split the necessary operations for that into a new struct iwl_legacy_ops. Those parts that still exist in the new AGN code don't need to be parametrized. 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-4965.c')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965.c318
1 files changed, 312 insertions, 6 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index 7921a910b34a..8f07964e4305 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -48,6 +48,7 @@
48#include "iwl-agn-led.h" 48#include "iwl-agn-led.h"
49#include "iwl-agn.h" 49#include "iwl-agn.h"
50#include "iwl-agn-debugfs.h" 50#include "iwl-agn-debugfs.h"
51#include "iwl-legacy.h"
51 52
52static int iwl4965_send_tx_power(struct iwl_priv *priv); 53static int iwl4965_send_tx_power(struct iwl_priv *priv);
53static int iwl4965_hw_get_temperature(struct iwl_priv *priv); 54static int iwl4965_hw_get_temperature(struct iwl_priv *priv);
@@ -1443,6 +1444,142 @@ static int iwl4965_send_rxon_assoc(struct iwl_priv *priv,
1443 return ret; 1444 return ret;
1444} 1445}
1445 1446
1447static int iwl4965_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
1448{
1449 /* cast away the const for active_rxon in this function */
1450 struct iwl_rxon_cmd *active_rxon = (void *)&ctx->active;
1451 int ret;
1452 bool new_assoc =
1453 !!(ctx->staging.filter_flags & RXON_FILTER_ASSOC_MSK);
1454
1455 if (!iwl_is_alive(priv))
1456 return -EBUSY;
1457
1458 if (!ctx->is_active)
1459 return 0;
1460
1461 /* always get timestamp with Rx frame */
1462 ctx->staging.flags |= RXON_FLG_TSF2HOST_MSK;
1463
1464 ret = iwl_check_rxon_cmd(priv, ctx);
1465 if (ret) {
1466 IWL_ERR(priv, "Invalid RXON configuration. Not committing.\n");
1467 return -EINVAL;
1468 }
1469
1470 /*
1471 * receive commit_rxon request
1472 * abort any previous channel switch if still in process
1473 */
1474 if (priv->switch_rxon.switch_in_progress &&
1475 (priv->switch_rxon.channel != ctx->staging.channel)) {
1476 IWL_DEBUG_11H(priv, "abort channel switch on %d\n",
1477 le16_to_cpu(priv->switch_rxon.channel));
1478 iwl_chswitch_done(priv, false);
1479 }
1480
1481 /* If we don't need to send a full RXON, we can use
1482 * iwl_rxon_assoc_cmd which is used to reconfigure filter
1483 * and other flags for the current radio configuration. */
1484 if (!iwl_full_rxon_required(priv, ctx)) {
1485 ret = iwl_send_rxon_assoc(priv, ctx);
1486 if (ret) {
1487 IWL_ERR(priv, "Error setting RXON_ASSOC (%d)\n", ret);
1488 return ret;
1489 }
1490
1491 memcpy(active_rxon, &ctx->staging, sizeof(*active_rxon));
1492 iwl_print_rx_config_cmd(priv, ctx);
1493 return 0;
1494 }
1495
1496 /* If we are currently associated and the new config requires
1497 * an RXON_ASSOC and the new config wants the associated mask enabled,
1498 * we must clear the associated from the active configuration
1499 * before we apply the new config */
1500 if (iwl_is_associated_ctx(ctx) && new_assoc) {
1501 IWL_DEBUG_INFO(priv, "Toggling associated bit on current RXON\n");
1502 active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
1503
1504 ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd,
1505 sizeof(struct iwl_rxon_cmd),
1506 active_rxon);
1507
1508 /* If the mask clearing failed then we set
1509 * active_rxon back to what it was previously */
1510 if (ret) {
1511 active_rxon->filter_flags |= RXON_FILTER_ASSOC_MSK;
1512 IWL_ERR(priv, "Error clearing ASSOC_MSK (%d)\n", ret);
1513 return ret;
1514 }
1515 iwl_clear_ucode_stations(priv, ctx);
1516 iwl_restore_stations(priv, ctx);
1517 ret = iwl_restore_default_wep_keys(priv, ctx);
1518 if (ret) {
1519 IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret);
1520 return ret;
1521 }
1522 }
1523
1524 IWL_DEBUG_INFO(priv, "Sending RXON\n"
1525 "* with%s RXON_FILTER_ASSOC_MSK\n"
1526 "* channel = %d\n"
1527 "* bssid = %pM\n",
1528 (new_assoc ? "" : "out"),
1529 le16_to_cpu(ctx->staging.channel),
1530 ctx->staging.bssid_addr);
1531
1532 iwl_set_rxon_hwcrypto(priv, ctx, !priv->cfg->mod_params->sw_crypto);
1533
1534 /* Apply the new configuration
1535 * RXON unassoc clears the station table in uCode so restoration of
1536 * stations is needed after it (the RXON command) completes
1537 */
1538 if (!new_assoc) {
1539 ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd,
1540 sizeof(struct iwl_rxon_cmd), &ctx->staging);
1541 if (ret) {
1542 IWL_ERR(priv, "Error setting new RXON (%d)\n", ret);
1543 return ret;
1544 }
1545 IWL_DEBUG_INFO(priv, "Return from !new_assoc RXON.\n");
1546 memcpy(active_rxon, &ctx->staging, sizeof(*active_rxon));
1547 iwl_clear_ucode_stations(priv, ctx);
1548 iwl_restore_stations(priv, ctx);
1549 ret = iwl_restore_default_wep_keys(priv, ctx);
1550 if (ret) {
1551 IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret);
1552 return ret;
1553 }
1554 }
1555 if (new_assoc) {
1556 priv->start_calib = 0;
1557 /* Apply the new configuration
1558 * RXON assoc doesn't clear the station table in uCode,
1559 */
1560 ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd,
1561 sizeof(struct iwl_rxon_cmd), &ctx->staging);
1562 if (ret) {
1563 IWL_ERR(priv, "Error setting new RXON (%d)\n", ret);
1564 return ret;
1565 }
1566 memcpy(active_rxon, &ctx->staging, sizeof(*active_rxon));
1567 }
1568 iwl_print_rx_config_cmd(priv, ctx);
1569
1570 iwl_init_sensitivity(priv);
1571
1572 /* If we issue a new RXON command which required a tune then we must
1573 * send a new TXPOWER command or we won't be able to Tx any frames */
1574 ret = iwl_set_tx_power(priv, priv->tx_power_user_lmt, true);
1575 if (ret) {
1576 IWL_ERR(priv, "Error sending TX power (%d)\n", ret);
1577 return ret;
1578 }
1579
1580 return 0;
1581}
1582
1446static int iwl4965_hw_channel_switch(struct iwl_priv *priv, 1583static int iwl4965_hw_channel_switch(struct iwl_priv *priv,
1447 struct ieee80211_channel_switch *ch_switch) 1584 struct ieee80211_channel_switch *ch_switch)
1448{ 1585{
@@ -2212,7 +2349,7 @@ static void iwl4965_cancel_deferred_work(struct iwl_priv *priv)
2212 2349
2213static struct iwl_hcmd_ops iwl4965_hcmd = { 2350static struct iwl_hcmd_ops iwl4965_hcmd = {
2214 .rxon_assoc = iwl4965_send_rxon_assoc, 2351 .rxon_assoc = iwl4965_send_rxon_assoc,
2215 .commit_rxon = iwlagn_commit_rxon, 2352 .commit_rxon = iwl4965_commit_rxon,
2216 .set_rxon_chain = iwlagn_set_rxon_chain, 2353 .set_rxon_chain = iwlagn_set_rxon_chain,
2217 .send_bt_config = iwl_send_bt_config, 2354 .send_bt_config = iwl_send_bt_config,
2218}; 2355};
@@ -2229,6 +2366,149 @@ static void iwl4965_post_scan(struct iwl_priv *priv)
2229 iwlcore_commit_rxon(priv, ctx); 2366 iwlcore_commit_rxon(priv, ctx);
2230} 2367}
2231 2368
2369static void iwl4965_post_associate(struct iwl_priv *priv)
2370{
2371 struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
2372 struct ieee80211_vif *vif = ctx->vif;
2373 struct ieee80211_conf *conf = NULL;
2374 int ret = 0;
2375
2376 if (!vif || !priv->is_open)
2377 return;
2378
2379 if (vif->type == NL80211_IFTYPE_AP) {
2380 IWL_ERR(priv, "%s Should not be called in AP mode\n", __func__);
2381 return;
2382 }
2383
2384 if (test_bit(STATUS_EXIT_PENDING, &priv->status))
2385 return;
2386
2387 iwl_scan_cancel_timeout(priv, 200);
2388
2389 conf = ieee80211_get_hw_conf(priv->hw);
2390
2391 ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
2392 iwlcore_commit_rxon(priv, ctx);
2393
2394 ret = iwl_send_rxon_timing(priv, ctx);
2395 if (ret)
2396 IWL_WARN(priv, "RXON timing - "
2397 "Attempting to continue.\n");
2398
2399 ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
2400
2401 iwl_set_rxon_ht(priv, &priv->current_ht_config);
2402
2403 if (priv->cfg->ops->hcmd->set_rxon_chain)
2404 priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
2405
2406 ctx->staging.assoc_id = cpu_to_le16(vif->bss_conf.aid);
2407
2408 IWL_DEBUG_ASSOC(priv, "assoc id %d beacon interval %d\n",
2409 vif->bss_conf.aid, vif->bss_conf.beacon_int);
2410
2411 if (vif->bss_conf.use_short_preamble)
2412 ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
2413 else
2414 ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
2415
2416 if (ctx->staging.flags & RXON_FLG_BAND_24G_MSK) {
2417 if (vif->bss_conf.use_short_slot)
2418 ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK;
2419 else
2420 ctx->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
2421 }
2422
2423 iwlcore_commit_rxon(priv, ctx);
2424
2425 IWL_DEBUG_ASSOC(priv, "Associated as %d to: %pM\n",
2426 vif->bss_conf.aid, ctx->active.bssid_addr);
2427
2428 switch (vif->type) {
2429 case NL80211_IFTYPE_STATION:
2430 break;
2431 case NL80211_IFTYPE_ADHOC:
2432 iwlagn_send_beacon_cmd(priv);
2433 break;
2434 default:
2435 IWL_ERR(priv, "%s Should not be called in %d mode\n",
2436 __func__, vif->type);
2437 break;
2438 }
2439
2440 /* the chain noise calibration will enabled PM upon completion
2441 * If chain noise has already been run, then we need to enable
2442 * power management here */
2443 if (priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE)
2444 iwl_power_update_mode(priv, false);
2445
2446 /* Enable Rx differential gain and sensitivity calibrations */
2447 iwl_chain_noise_reset(priv);
2448 priv->start_calib = 1;
2449}
2450
2451static void iwl4965_config_ap(struct iwl_priv *priv)
2452{
2453 struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
2454 struct ieee80211_vif *vif = ctx->vif;
2455 int ret = 0;
2456
2457 lockdep_assert_held(&priv->mutex);
2458
2459 if (test_bit(STATUS_EXIT_PENDING, &priv->status))
2460 return;
2461
2462 /* The following should be done only at AP bring up */
2463 if (!iwl_is_associated_ctx(ctx)) {
2464
2465 /* RXON - unassoc (to set timing command) */
2466 ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
2467 iwlcore_commit_rxon(priv, ctx);
2468
2469 /* RXON Timing */
2470 ret = iwl_send_rxon_timing(priv, ctx);
2471 if (ret)
2472 IWL_WARN(priv, "RXON timing failed - "
2473 "Attempting to continue.\n");
2474
2475 /* AP has all antennas */
2476 priv->chain_noise_data.active_chains =
2477 priv->hw_params.valid_rx_ant;
2478 iwl_set_rxon_ht(priv, &priv->current_ht_config);
2479 if (priv->cfg->ops->hcmd->set_rxon_chain)
2480 priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
2481
2482 ctx->staging.assoc_id = 0;
2483
2484 if (vif->bss_conf.use_short_preamble)
2485 ctx->staging.flags |=
2486 RXON_FLG_SHORT_PREAMBLE_MSK;
2487 else
2488 ctx->staging.flags &=
2489 ~RXON_FLG_SHORT_PREAMBLE_MSK;
2490
2491 if (ctx->staging.flags & RXON_FLG_BAND_24G_MSK) {
2492 if (vif->bss_conf.use_short_slot)
2493 ctx->staging.flags |=
2494 RXON_FLG_SHORT_SLOT_MSK;
2495 else
2496 ctx->staging.flags &=
2497 ~RXON_FLG_SHORT_SLOT_MSK;
2498 }
2499 /* need to send beacon cmd before committing assoc RXON! */
2500 iwlagn_send_beacon_cmd(priv);
2501 /* restore RXON assoc */
2502 ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
2503 iwlcore_commit_rxon(priv, ctx);
2504 }
2505 iwlagn_send_beacon_cmd(priv);
2506
2507 /* FIXME - we need to add code here to detect a totally new
2508 * configuration, reset the AP, unassoc, rxon timing, assoc,
2509 * clear sta table, add BCAST sta... */
2510}
2511
2232static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = { 2512static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = {
2233 .get_hcmd_size = iwl4965_get_hcmd_size, 2513 .get_hcmd_size = iwl4965_get_hcmd_size,
2234 .build_addsta_hcmd = iwl4965_build_addsta_hcmd, 2514 .build_addsta_hcmd = iwl4965_build_addsta_hcmd,
@@ -2281,14 +2561,10 @@ static struct iwl_lib_ops iwl4965_lib = {
2281 }, 2561 },
2282 .send_tx_power = iwl4965_send_tx_power, 2562 .send_tx_power = iwl4965_send_tx_power,
2283 .update_chain_flags = iwl_update_chain_flags, 2563 .update_chain_flags = iwl_update_chain_flags,
2284 .post_associate = iwl_post_associate,
2285 .config_ap = iwl_config_ap,
2286 .isr = iwl_isr_legacy, 2564 .isr = iwl_isr_legacy,
2287 .temp_ops = { 2565 .temp_ops = {
2288 .temperature = iwl4965_temperature_calib, 2566 .temperature = iwl4965_temperature_calib,
2289 }, 2567 },
2290 .manage_ibss_station = iwlagn_manage_ibss_station,
2291 .update_bcast_stations = iwl_update_bcast_stations,
2292 .debugfs_ops = { 2568 .debugfs_ops = {
2293 .rx_stats_read = iwl_ucode_rx_stats_read, 2569 .rx_stats_read = iwl_ucode_rx_stats_read,
2294 .tx_stats_read = iwl_ucode_tx_stats_read, 2570 .tx_stats_read = iwl_ucode_tx_stats_read,
@@ -2300,12 +2576,42 @@ static struct iwl_lib_ops iwl4965_lib = {
2300 .check_plcp_health = iwl_good_plcp_health, 2576 .check_plcp_health = iwl_good_plcp_health,
2301}; 2577};
2302 2578
2579static const struct iwl_legacy_ops iwl4965_legacy_ops = {
2580 .post_associate = iwl4965_post_associate,
2581 .config_ap = iwl4965_config_ap,
2582 .manage_ibss_station = iwlagn_manage_ibss_station,
2583 .update_bcast_stations = iwl_update_bcast_stations,
2584};
2585
2586struct ieee80211_ops iwl4965_hw_ops = {
2587 .tx = iwlagn_mac_tx,
2588 .start = iwlagn_mac_start,
2589 .stop = iwlagn_mac_stop,
2590 .add_interface = iwl_mac_add_interface,
2591 .remove_interface = iwl_mac_remove_interface,
2592 .config = iwl_legacy_mac_config,
2593 .configure_filter = iwlagn_configure_filter,
2594 .set_key = iwlagn_mac_set_key,
2595 .update_tkip_key = iwlagn_mac_update_tkip_key,
2596 .conf_tx = iwl_mac_conf_tx,
2597 .reset_tsf = iwl_legacy_mac_reset_tsf,
2598 .bss_info_changed = iwl_legacy_mac_bss_info_changed,
2599 .ampdu_action = iwlagn_mac_ampdu_action,
2600 .hw_scan = iwl_mac_hw_scan,
2601 .sta_add = iwlagn_mac_sta_add,
2602 .sta_remove = iwl_mac_sta_remove,
2603 .channel_switch = iwlagn_mac_channel_switch,
2604 .flush = iwlagn_mac_flush,
2605 .tx_last_beacon = iwl_mac_tx_last_beacon,
2606};
2607
2303static const struct iwl_ops iwl4965_ops = { 2608static const struct iwl_ops iwl4965_ops = {
2304 .lib = &iwl4965_lib, 2609 .lib = &iwl4965_lib,
2305 .hcmd = &iwl4965_hcmd, 2610 .hcmd = &iwl4965_hcmd,
2306 .utils = &iwl4965_hcmd_utils, 2611 .utils = &iwl4965_hcmd_utils,
2307 .led = &iwlagn_led_ops, 2612 .led = &iwlagn_led_ops,
2308 .ieee80211_ops = &iwlagn_hw_ops, 2613 .legacy = &iwl4965_legacy_ops,
2614 .ieee80211_ops = &iwl4965_hw_ops,
2309}; 2615};
2310 2616
2311static struct iwl_base_params iwl4965_base_params = { 2617static struct iwl_base_params iwl4965_base_params = {