diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-4965.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-4965.c | 318 |
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 | ||
52 | static int iwl4965_send_tx_power(struct iwl_priv *priv); | 53 | static int iwl4965_send_tx_power(struct iwl_priv *priv); |
53 | static int iwl4965_hw_get_temperature(struct iwl_priv *priv); | 54 | static 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 | ||
1447 | static 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 | |||
1446 | static int iwl4965_hw_channel_switch(struct iwl_priv *priv, | 1583 | static 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 | ||
2213 | static struct iwl_hcmd_ops iwl4965_hcmd = { | 2350 | static 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 | ||
2369 | static 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 | |||
2451 | static 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 | |||
2232 | static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = { | 2512 | static 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 | ||
2579 | static 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 | |||
2586 | struct 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 | |||
2303 | static const struct iwl_ops iwl4965_ops = { | 2608 | static 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 | ||
2311 | static struct iwl_base_params iwl4965_base_params = { | 2617 | static struct iwl_base_params iwl4965_base_params = { |