aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl-4965.c
diff options
context:
space:
mode:
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 = {