1a55360e458551b0add4ec147ef786d71e163bf50Tomas Winkler/****************************************************************************** 2a55360e458551b0add4ec147ef786d71e163bf50Tomas Winkler * 351368bf792c79eb917694a4155d62f04359e3734Emmanuel Grumbach * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. 4a55360e458551b0add4ec147ef786d71e163bf50Tomas Winkler * 5a55360e458551b0add4ec147ef786d71e163bf50Tomas Winkler * Portions of this file are derived from the ipw3945 project, as well 66a686c600268b71619f93d35f9373e2b6ab5947bEmmanuel Grumbach * as portionhelp of the ieee80211 subsystem header files. 7a55360e458551b0add4ec147ef786d71e163bf50Tomas Winkler * 8a55360e458551b0add4ec147ef786d71e163bf50Tomas Winkler * This program is free software; you can redistribute it and/or modify it 9a55360e458551b0add4ec147ef786d71e163bf50Tomas Winkler * under the terms of version 2 of the GNU General Public License as 10a55360e458551b0add4ec147ef786d71e163bf50Tomas Winkler * published by the Free Software Foundation. 11a55360e458551b0add4ec147ef786d71e163bf50Tomas Winkler * 12a55360e458551b0add4ec147ef786d71e163bf50Tomas Winkler * This program is distributed in the hope that it will be useful, but WITHOUT 13a55360e458551b0add4ec147ef786d71e163bf50Tomas Winkler * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14a55360e458551b0add4ec147ef786d71e163bf50Tomas Winkler * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 15a55360e458551b0add4ec147ef786d71e163bf50Tomas Winkler * more details. 16a55360e458551b0add4ec147ef786d71e163bf50Tomas Winkler * 17a55360e458551b0add4ec147ef786d71e163bf50Tomas Winkler * You should have received a copy of the GNU General Public License along with 18a55360e458551b0add4ec147ef786d71e163bf50Tomas Winkler * this program; if not, write to the Free Software Foundation, Inc., 19a55360e458551b0add4ec147ef786d71e163bf50Tomas Winkler * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA 20a55360e458551b0add4ec147ef786d71e163bf50Tomas Winkler * 21a55360e458551b0add4ec147ef786d71e163bf50Tomas Winkler * The full GNU General Public License is included in this distribution in the 22a55360e458551b0add4ec147ef786d71e163bf50Tomas Winkler * file called LICENSE. 23a55360e458551b0add4ec147ef786d71e163bf50Tomas Winkler * 24a55360e458551b0add4ec147ef786d71e163bf50Tomas Winkler * Contact Information: 25759ef89fb096c4a6ef078d3cfd5682ac037bd789Winkler, Tomas * Intel Linux Wireless <ilw@linux.intel.com> 26a55360e458551b0add4ec147ef786d71e163bf50Tomas Winkler * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 27a55360e458551b0add4ec147ef786d71e163bf50Tomas Winkler * 28a55360e458551b0add4ec147ef786d71e163bf50Tomas Winkler *****************************************************************************/ 29a55360e458551b0add4ec147ef786d71e163bf50Tomas Winkler 301781a07fbe9cce3dc1697288a5edd260ea7edc02Emmanuel Grumbach#include <linux/etherdevice.h> 315a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 32118253ca46262342b87909927fec6214fa4a06a4Stanislaw Gruszka#include <linux/sched.h> 33a55360e458551b0add4ec147ef786d71e163bf50Tomas Winkler#include <net/mac80211.h> 34a05ffd395e1f1293d05a814ef697c12efa411ad8Tomas Winkler#include <asm/unaligned.h> 35a55360e458551b0add4ec147ef786d71e163bf50Tomas Winkler#include "iwl-io.h" 361023fdc4858b6b8cb88ff28cafd425b77555be9fJohannes Berg#include "dev.h" 371023fdc4858b6b8cb88ff28cafd425b77555be9fJohannes Berg#include "calib.h" 381023fdc4858b6b8cb88ff28cafd425b77555be9fJohannes Berg#include "agn.h" 39466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 40d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg#define IWL_CMD_ENTRY(x) [x] = #x 41d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg 42e5209263df94a41090199c95b21939139760fd85Johannes Bergconst char *const iwl_dvm_cmd_strings[REPLY_MAX] = { 43d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(REPLY_ALIVE), 44d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(REPLY_ERROR), 45d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(REPLY_ECHO), 46d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(REPLY_RXON), 47d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(REPLY_RXON_ASSOC), 48d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(REPLY_QOS_PARAM), 49d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(REPLY_RXON_TIMING), 50d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(REPLY_ADD_STA), 51d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(REPLY_REMOVE_STA), 52d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(REPLY_REMOVE_ALL_STA), 53d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(REPLY_TXFIFO_FLUSH), 54d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(REPLY_WEPKEY), 55d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(REPLY_TX), 56d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(REPLY_LEDS_CMD), 57d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(REPLY_TX_LINK_QUALITY_CMD), 58d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(COEX_PRIORITY_TABLE_CMD), 59d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(COEX_MEDIUM_NOTIFICATION), 60d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(COEX_EVENT_CMD), 61d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(REPLY_QUIET_CMD), 62d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(REPLY_CHANNEL_SWITCH), 63d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(CHANNEL_SWITCH_NOTIFICATION), 64d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(REPLY_SPECTRUM_MEASUREMENT_CMD), 65d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(SPECTRUM_MEASURE_NOTIFICATION), 66d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(POWER_TABLE_CMD), 67d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(PM_SLEEP_NOTIFICATION), 68d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(PM_DEBUG_STATISTIC_NOTIFIC), 69d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(REPLY_SCAN_CMD), 70d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(REPLY_SCAN_ABORT_CMD), 71d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(SCAN_START_NOTIFICATION), 72d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(SCAN_RESULTS_NOTIFICATION), 73d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(SCAN_COMPLETE_NOTIFICATION), 74d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(BEACON_NOTIFICATION), 75d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(REPLY_TX_BEACON), 76d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(WHO_IS_AWAKE_NOTIFICATION), 77d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(QUIET_NOTIFICATION), 78d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(REPLY_TX_PWR_TABLE_CMD), 79d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(MEASURE_ABORT_NOTIFICATION), 80d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(REPLY_BT_CONFIG), 81d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(REPLY_STATISTICS_CMD), 82d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(STATISTICS_NOTIFICATION), 83d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(REPLY_CARD_STATE_CMD), 84d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(CARD_STATE_NOTIFICATION), 85d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(MISSED_BEACONS_NOTIFICATION), 86d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(REPLY_CT_KILL_CONFIG_CMD), 87d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(SENSITIVITY_CMD), 88d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(REPLY_PHY_CALIBRATION_CMD), 89d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(REPLY_RX_PHY_CMD), 90d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(REPLY_RX_MPDU_CMD), 91d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(REPLY_COMPRESSED_BA), 92d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(CALIBRATION_CFG_CMD), 93d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(CALIBRATION_RES_NOTIFICATION), 94d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(CALIBRATION_COMPLETE_NOTIFICATION), 95d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(REPLY_TX_POWER_DBM_CMD), 96d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(TEMPERATURE_NOTIFICATION), 97d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(TX_ANT_CONFIGURATION_CMD), 98d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(REPLY_BT_COEX_PROFILE_NOTIF), 99d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(REPLY_BT_COEX_PRIO_TABLE), 100d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(REPLY_BT_COEX_PROT_ENV), 101d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(REPLY_WIPAN_PARAMS), 102d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(REPLY_WIPAN_RXON), 103d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(REPLY_WIPAN_RXON_TIMING), 104d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(REPLY_WIPAN_RXON_ASSOC), 105d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(REPLY_WIPAN_QOS_PARAM), 106d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(REPLY_WIPAN_WEPKEY), 107d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(REPLY_WIPAN_P2P_CHANNEL_SWITCH), 108d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(REPLY_WIPAN_NOA_NOTIFICATION), 109d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(REPLY_WIPAN_DEACTIVATION_COMPLETE), 110d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(REPLY_WOWLAN_PATTERNS), 111d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(REPLY_WOWLAN_WAKEUP_FILTER), 112d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(REPLY_WOWLAN_TSC_RSC_PARAMS), 113d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(REPLY_WOWLAN_TKIP_PARAMS), 114d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(REPLY_WOWLAN_KEK_KCK_MATERIAL), 115d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(REPLY_WOWLAN_GET_STATUS), 116d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_CMD_ENTRY(REPLY_D3_CONFIG), 117d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg}; 118d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg#undef IWL_CMD_ENTRY 119a55360e458551b0add4ec147ef786d71e163bf50Tomas Winkler 120466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka/****************************************************************************** 121466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka * 122466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka * Generic RX handler implementations 123466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka * 124466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka ******************************************************************************/ 125466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 1263246c4e6addfbf69b23095b69c5484cd76ddb37bWey-Yi Guystatic int iwlagn_rx_reply_error(struct iwl_priv *priv, 12748a2d66f58d2bf1818acf5ff7ed9897a9977a96eJohannes Berg struct iwl_rx_cmd_buffer *rxb, 128247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach struct iwl_device_cmd *cmd) 129466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka{ 130466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka struct iwl_rx_packet *pkt = rxb_addr(rxb); 131f8d7c1a18d5e77b17b5cc1ebefa21eaea7f2d0faJohannes Berg struct iwl_error_resp *err_resp = (void *)pkt->data; 132466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 133d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg IWL_ERR(priv, "Error Reply type 0x%08X cmd REPLY_ERROR (0x%02X) " 134466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka "seq 0x%04X ser 0x%08X\n", 135f8d7c1a18d5e77b17b5cc1ebefa21eaea7f2d0faJohannes Berg le32_to_cpu(err_resp->error_type), 136f8d7c1a18d5e77b17b5cc1ebefa21eaea7f2d0faJohannes Berg err_resp->cmd_id, 137f8d7c1a18d5e77b17b5cc1ebefa21eaea7f2d0faJohannes Berg le16_to_cpu(err_resp->bad_cmd_seq_num), 138f8d7c1a18d5e77b17b5cc1ebefa21eaea7f2d0faJohannes Berg le32_to_cpu(err_resp->error_info)); 139247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach return 0; 140466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka} 141466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 14248a2d66f58d2bf1818acf5ff7ed9897a9977a96eJohannes Bergstatic int iwlagn_rx_csa(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, 143247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach struct iwl_device_cmd *cmd) 144466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka{ 145466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka struct iwl_rx_packet *pkt = rxb_addr(rxb); 146f8d7c1a18d5e77b17b5cc1ebefa21eaea7f2d0faJohannes Berg struct iwl_csa_notification *csa = (void *)pkt->data; 147466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka /* 148466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka * MULTI-FIXME 149ade4c649a0e9e862751fe1c98f43fbee86554c8aWey-Yi Guy * See iwlagn_mac_channel_switch. 150466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka */ 151466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; 152466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka struct iwl_rxon_cmd *rxon = (void *)&ctx->active; 153466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 15483626404a70da74c67f32f119e53c0ba032ba2d8Don Fry if (!test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status)) 155247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach return 0; 1566f213ff1919fab6f8244ceae55631b5d6ef750a7Stanislaw Gruszka 1576f213ff1919fab6f8244ceae55631b5d6ef750a7Stanislaw Gruszka if (!le32_to_cpu(csa->status) && csa->channel == priv->switch_channel) { 1586f213ff1919fab6f8244ceae55631b5d6ef750a7Stanislaw Gruszka rxon->channel = csa->channel; 1596f213ff1919fab6f8244ceae55631b5d6ef750a7Stanislaw Gruszka ctx->staging.channel = csa->channel; 1606f213ff1919fab6f8244ceae55631b5d6ef750a7Stanislaw Gruszka IWL_DEBUG_11H(priv, "CSA notif: channel %d\n", 161466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka le16_to_cpu(csa->channel)); 1626f213ff1919fab6f8244ceae55631b5d6ef750a7Stanislaw Gruszka iwl_chswitch_done(priv, true); 1636f213ff1919fab6f8244ceae55631b5d6ef750a7Stanislaw Gruszka } else { 1646f213ff1919fab6f8244ceae55631b5d6ef750a7Stanislaw Gruszka IWL_ERR(priv, "CSA notif (fail) : channel %d\n", 1656f213ff1919fab6f8244ceae55631b5d6ef750a7Stanislaw Gruszka le16_to_cpu(csa->channel)); 1666f213ff1919fab6f8244ceae55631b5d6ef750a7Stanislaw Gruszka iwl_chswitch_done(priv, false); 167466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka } 168247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach return 0; 169466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka} 170466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 171466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 1723246c4e6addfbf69b23095b69c5484cd76ddb37bWey-Yi Guystatic int iwlagn_rx_spectrum_measure_notif(struct iwl_priv *priv, 17348a2d66f58d2bf1818acf5ff7ed9897a9977a96eJohannes Berg struct iwl_rx_cmd_buffer *rxb, 174247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach struct iwl_device_cmd *cmd) 17581963d68575d497d626ce13e42c84518a931cc12Reinette Chatre{ 17681963d68575d497d626ce13e42c84518a931cc12Reinette Chatre struct iwl_rx_packet *pkt = rxb_addr(rxb); 177f8d7c1a18d5e77b17b5cc1ebefa21eaea7f2d0faJohannes Berg struct iwl_spectrum_notification *report = (void *)pkt->data; 17881963d68575d497d626ce13e42c84518a931cc12Reinette Chatre 17981963d68575d497d626ce13e42c84518a931cc12Reinette Chatre if (!report->state) { 18081963d68575d497d626ce13e42c84518a931cc12Reinette Chatre IWL_DEBUG_11H(priv, 18181963d68575d497d626ce13e42c84518a931cc12Reinette Chatre "Spectrum Measure Notification: Start\n"); 182247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach return 0; 18381963d68575d497d626ce13e42c84518a931cc12Reinette Chatre } 18481963d68575d497d626ce13e42c84518a931cc12Reinette Chatre 18581963d68575d497d626ce13e42c84518a931cc12Reinette Chatre memcpy(&priv->measure_report, report, sizeof(*report)); 18681963d68575d497d626ce13e42c84518a931cc12Reinette Chatre priv->measurement_status |= MEASUREMENT_READY; 187247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach return 0; 18881963d68575d497d626ce13e42c84518a931cc12Reinette Chatre} 18981963d68575d497d626ce13e42c84518a931cc12Reinette Chatre 1903246c4e6addfbf69b23095b69c5484cd76ddb37bWey-Yi Guystatic int iwlagn_rx_pm_sleep_notif(struct iwl_priv *priv, 19148a2d66f58d2bf1818acf5ff7ed9897a9977a96eJohannes Berg struct iwl_rx_cmd_buffer *rxb, 192247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach struct iwl_device_cmd *cmd) 193466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka{ 194466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka#ifdef CONFIG_IWLWIFI_DEBUG 195466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka struct iwl_rx_packet *pkt = rxb_addr(rxb); 196f8d7c1a18d5e77b17b5cc1ebefa21eaea7f2d0faJohannes Berg struct iwl_sleep_notification *sleep = (void *)pkt->data; 197466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka IWL_DEBUG_RX(priv, "sleep mode: %d, src: %d\n", 198466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka sleep->pm_sleep_mode, sleep->pm_wakeup_src); 199466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka#endif 200247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach return 0; 201466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka} 202466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 2033246c4e6addfbf69b23095b69c5484cd76ddb37bWey-Yi Guystatic int iwlagn_rx_pm_debug_statistics_notif(struct iwl_priv *priv, 20448a2d66f58d2bf1818acf5ff7ed9897a9977a96eJohannes Berg struct iwl_rx_cmd_buffer *rxb, 205247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach struct iwl_device_cmd *cmd) 206466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka{ 207466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka struct iwl_rx_packet *pkt = rxb_addr(rxb); 20865b30348dbf9b529901b5c2b62dca6cad9017a2aJohannes Berg u32 __maybe_unused len = iwl_rx_packet_len(pkt); 209466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka IWL_DEBUG_RADIO(priv, "Dumping %d bytes of unhandled " 210d9fb6465802c2279ea14cc26eb66d17c133478b1Johannes Berg "notification for PM_DEBUG_STATISTIC_NOTIFIC:\n", len); 211f8d7c1a18d5e77b17b5cc1ebefa21eaea7f2d0faJohannes Berg iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->data, len); 212247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach return 0; 213466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka} 214466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 2153246c4e6addfbf69b23095b69c5484cd76ddb37bWey-Yi Guystatic int iwlagn_rx_beacon_notif(struct iwl_priv *priv, 21648a2d66f58d2bf1818acf5ff7ed9897a9977a96eJohannes Berg struct iwl_rx_cmd_buffer *rxb, 217247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach struct iwl_device_cmd *cmd) 218466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka{ 219466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka struct iwl_rx_packet *pkt = rxb_addr(rxb); 220f8d7c1a18d5e77b17b5cc1ebefa21eaea7f2d0faJohannes Berg struct iwlagn_beacon_notif *beacon = (void *)pkt->data; 221466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka#ifdef CONFIG_IWLWIFI_DEBUG 222466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka u16 status = le16_to_cpu(beacon->beacon_notify_hdr.status.status); 223466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka u8 rate = iwl_hw_get_rate(beacon->beacon_notify_hdr.rate_n_flags); 224466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 225466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka IWL_DEBUG_RX(priv, "beacon status %#x, retries:%d ibssmgr:%d " 226466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka "tsf:0x%.8x%.8x rate:%d\n", 227466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka status & TX_STATUS_MSK, 228466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka beacon->beacon_notify_hdr.failure_frame, 229466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka le32_to_cpu(beacon->ibss_mgr_status), 230466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka le32_to_cpu(beacon->high_tsf), 231466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka le32_to_cpu(beacon->low_tsf), rate); 232466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka#endif 233466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 234466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka priv->ibss_manager = le32_to_cpu(beacon->ibss_mgr_status); 235466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 236247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach return 0; 237466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka} 238466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 239ad6e82a5348e494c0023d77fa55933f23b55711cStanislaw Gruszka/** 240ad6e82a5348e494c0023d77fa55933f23b55711cStanislaw Gruszka * iwl_good_plcp_health - checks for plcp error. 241ad6e82a5348e494c0023d77fa55933f23b55711cStanislaw Gruszka * 242ad6e82a5348e494c0023d77fa55933f23b55711cStanislaw Gruszka * When the plcp error is exceeding the thresholds, reset the radio 243ad6e82a5348e494c0023d77fa55933f23b55711cStanislaw Gruszka * to improve the throughput. 244ad6e82a5348e494c0023d77fa55933f23b55711cStanislaw Gruszka */ 2453246c4e6addfbf69b23095b69c5484cd76ddb37bWey-Yi Guystatic bool iwlagn_good_plcp_health(struct iwl_priv *priv, 2460da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg struct statistics_rx_phy *cur_ofdm, 2470da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg struct statistics_rx_ht_phy *cur_ofdm_ht, 2480da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg unsigned int msecs) 249ad6e82a5348e494c0023d77fa55933f23b55711cStanislaw Gruszka{ 2506198c387b25b528fd89a48bf67f0402d828ffa18Stanislaw Gruszka int delta; 251ab5c0f1f2d525ed17f1abf727d213cf220ed26a8Johannes Berg int threshold = priv->plcp_delta_threshold; 252ad6e82a5348e494c0023d77fa55933f23b55711cStanislaw Gruszka 2536198c387b25b528fd89a48bf67f0402d828ffa18Stanislaw Gruszka if (threshold == IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE) { 254ad6e82a5348e494c0023d77fa55933f23b55711cStanislaw Gruszka IWL_DEBUG_RADIO(priv, "plcp_err check disabled\n"); 2556198c387b25b528fd89a48bf67f0402d828ffa18Stanislaw Gruszka return true; 256ad6e82a5348e494c0023d77fa55933f23b55711cStanislaw Gruszka } 257ad6e82a5348e494c0023d77fa55933f23b55711cStanislaw Gruszka 2580da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg delta = le32_to_cpu(cur_ofdm->plcp_err) - 2590da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg le32_to_cpu(priv->statistics.rx_ofdm.plcp_err) + 2600da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg le32_to_cpu(cur_ofdm_ht->plcp_err) - 2610da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg le32_to_cpu(priv->statistics.rx_ofdm_ht.plcp_err); 2626198c387b25b528fd89a48bf67f0402d828ffa18Stanislaw Gruszka 2630da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg /* Can be negative if firmware reset statistics */ 2646198c387b25b528fd89a48bf67f0402d828ffa18Stanislaw Gruszka if (delta <= 0) 2656198c387b25b528fd89a48bf67f0402d828ffa18Stanislaw Gruszka return true; 2666198c387b25b528fd89a48bf67f0402d828ffa18Stanislaw Gruszka 2676198c387b25b528fd89a48bf67f0402d828ffa18Stanislaw Gruszka if ((delta * 100 / msecs) > threshold) { 2686198c387b25b528fd89a48bf67f0402d828ffa18Stanislaw Gruszka IWL_DEBUG_RADIO(priv, 2696198c387b25b528fd89a48bf67f0402d828ffa18Stanislaw Gruszka "plcp health threshold %u delta %d msecs %u\n", 2706198c387b25b528fd89a48bf67f0402d828ffa18Stanislaw Gruszka threshold, delta, msecs); 2716198c387b25b528fd89a48bf67f0402d828ffa18Stanislaw Gruszka return false; 2726198c387b25b528fd89a48bf67f0402d828ffa18Stanislaw Gruszka } 2736198c387b25b528fd89a48bf67f0402d828ffa18Stanislaw Gruszka 2746198c387b25b528fd89a48bf67f0402d828ffa18Stanislaw Gruszka return true; 275ad6e82a5348e494c0023d77fa55933f23b55711cStanislaw Gruszka} 276ad6e82a5348e494c0023d77fa55933f23b55711cStanislaw Gruszka 27766cd9e39c6c0a870f12828b5f5b9e1d2e7c70313Meenakshi Venkataramanint iwl_force_rf_reset(struct iwl_priv *priv, bool external) 27866cd9e39c6c0a870f12828b5f5b9e1d2e7c70313Meenakshi Venkataraman{ 27966cd9e39c6c0a870f12828b5f5b9e1d2e7c70313Meenakshi Venkataraman struct iwl_rf_reset *rf_reset; 28066cd9e39c6c0a870f12828b5f5b9e1d2e7c70313Meenakshi Venkataraman 28166cd9e39c6c0a870f12828b5f5b9e1d2e7c70313Meenakshi Venkataraman if (test_bit(STATUS_EXIT_PENDING, &priv->status)) 28266cd9e39c6c0a870f12828b5f5b9e1d2e7c70313Meenakshi Venkataraman return -EAGAIN; 28366cd9e39c6c0a870f12828b5f5b9e1d2e7c70313Meenakshi Venkataraman 28466cd9e39c6c0a870f12828b5f5b9e1d2e7c70313Meenakshi Venkataraman if (!iwl_is_any_associated(priv)) { 28566cd9e39c6c0a870f12828b5f5b9e1d2e7c70313Meenakshi Venkataraman IWL_DEBUG_SCAN(priv, "force reset rejected: not associated\n"); 28666cd9e39c6c0a870f12828b5f5b9e1d2e7c70313Meenakshi Venkataraman return -ENOLINK; 28766cd9e39c6c0a870f12828b5f5b9e1d2e7c70313Meenakshi Venkataraman } 28866cd9e39c6c0a870f12828b5f5b9e1d2e7c70313Meenakshi Venkataraman 28966cd9e39c6c0a870f12828b5f5b9e1d2e7c70313Meenakshi Venkataraman rf_reset = &priv->rf_reset; 29066cd9e39c6c0a870f12828b5f5b9e1d2e7c70313Meenakshi Venkataraman rf_reset->reset_request_count++; 29166cd9e39c6c0a870f12828b5f5b9e1d2e7c70313Meenakshi Venkataraman if (!external && rf_reset->last_reset_jiffies && 29266cd9e39c6c0a870f12828b5f5b9e1d2e7c70313Meenakshi Venkataraman time_after(rf_reset->last_reset_jiffies + 29366cd9e39c6c0a870f12828b5f5b9e1d2e7c70313Meenakshi Venkataraman IWL_DELAY_NEXT_FORCE_RF_RESET, jiffies)) { 29466cd9e39c6c0a870f12828b5f5b9e1d2e7c70313Meenakshi Venkataraman IWL_DEBUG_INFO(priv, "RF reset rejected\n"); 29566cd9e39c6c0a870f12828b5f5b9e1d2e7c70313Meenakshi Venkataraman rf_reset->reset_reject_count++; 29666cd9e39c6c0a870f12828b5f5b9e1d2e7c70313Meenakshi Venkataraman return -EAGAIN; 29766cd9e39c6c0a870f12828b5f5b9e1d2e7c70313Meenakshi Venkataraman } 29866cd9e39c6c0a870f12828b5f5b9e1d2e7c70313Meenakshi Venkataraman rf_reset->reset_success_count++; 29966cd9e39c6c0a870f12828b5f5b9e1d2e7c70313Meenakshi Venkataraman rf_reset->last_reset_jiffies = jiffies; 30066cd9e39c6c0a870f12828b5f5b9e1d2e7c70313Meenakshi Venkataraman 30166cd9e39c6c0a870f12828b5f5b9e1d2e7c70313Meenakshi Venkataraman /* 30266cd9e39c6c0a870f12828b5f5b9e1d2e7c70313Meenakshi Venkataraman * There is no easy and better way to force reset the radio, 30366cd9e39c6c0a870f12828b5f5b9e1d2e7c70313Meenakshi Venkataraman * the only known method is switching channel which will force to 30466cd9e39c6c0a870f12828b5f5b9e1d2e7c70313Meenakshi Venkataraman * reset and tune the radio. 30566cd9e39c6c0a870f12828b5f5b9e1d2e7c70313Meenakshi Venkataraman * Use internal short scan (single channel) operation to should 30666cd9e39c6c0a870f12828b5f5b9e1d2e7c70313Meenakshi Venkataraman * achieve this objective. 30766cd9e39c6c0a870f12828b5f5b9e1d2e7c70313Meenakshi Venkataraman * Driver should reset the radio when number of consecutive missed 30866cd9e39c6c0a870f12828b5f5b9e1d2e7c70313Meenakshi Venkataraman * beacon, or any other uCode error condition detected. 30966cd9e39c6c0a870f12828b5f5b9e1d2e7c70313Meenakshi Venkataraman */ 31066cd9e39c6c0a870f12828b5f5b9e1d2e7c70313Meenakshi Venkataraman IWL_DEBUG_INFO(priv, "perform radio reset.\n"); 31166cd9e39c6c0a870f12828b5f5b9e1d2e7c70313Meenakshi Venkataraman iwl_internal_short_hw_scan(priv); 31266cd9e39c6c0a870f12828b5f5b9e1d2e7c70313Meenakshi Venkataraman return 0; 31366cd9e39c6c0a870f12828b5f5b9e1d2e7c70313Meenakshi Venkataraman} 31466cd9e39c6c0a870f12828b5f5b9e1d2e7c70313Meenakshi Venkataraman 31566cd9e39c6c0a870f12828b5f5b9e1d2e7c70313Meenakshi Venkataraman 3163246c4e6addfbf69b23095b69c5484cd76ddb37bWey-Yi Guystatic void iwlagn_recover_from_statistics(struct iwl_priv *priv, 3173246c4e6addfbf69b23095b69c5484cd76ddb37bWey-Yi Guy struct statistics_rx_phy *cur_ofdm, 3183246c4e6addfbf69b23095b69c5484cd76ddb37bWey-Yi Guy struct statistics_rx_ht_phy *cur_ofdm_ht, 3193246c4e6addfbf69b23095b69c5484cd76ddb37bWey-Yi Guy struct statistics_tx *tx, 3203246c4e6addfbf69b23095b69c5484cd76ddb37bWey-Yi Guy unsigned long stamp) 321fa8f130c504223d25c116b3d23787f465dfb1317Wey-Yi Guy{ 322410f2bb30d27252cc55a5f41668de60de62e5dc8Stanislaw Gruszka unsigned int msecs; 323b7977ffaab5187ad75edaf04ac854615cea93828Stanislaw Gruszka 32483626404a70da74c67f32f119e53c0ba032ba2d8Don Fry if (test_bit(STATUS_EXIT_PENDING, &priv->status)) 325410f2bb30d27252cc55a5f41668de60de62e5dc8Stanislaw Gruszka return; 326410f2bb30d27252cc55a5f41668de60de62e5dc8Stanislaw Gruszka 327410f2bb30d27252cc55a5f41668de60de62e5dc8Stanislaw Gruszka msecs = jiffies_to_msecs(stamp - priv->rx_statistics_jiffies); 328410f2bb30d27252cc55a5f41668de60de62e5dc8Stanislaw Gruszka 329410f2bb30d27252cc55a5f41668de60de62e5dc8Stanislaw Gruszka /* Only gather statistics and update time stamp when not associated */ 330410f2bb30d27252cc55a5f41668de60de62e5dc8Stanislaw Gruszka if (!iwl_is_any_associated(priv)) 3310da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg return; 332410f2bb30d27252cc55a5f41668de60de62e5dc8Stanislaw Gruszka 333410f2bb30d27252cc55a5f41668de60de62e5dc8Stanislaw Gruszka /* Do not check/recover when do not have enough statistics data */ 334410f2bb30d27252cc55a5f41668de60de62e5dc8Stanislaw Gruszka if (msecs < 99) 335fa8f130c504223d25c116b3d23787f465dfb1317Wey-Yi Guy return; 336ca3d9389642946072ed448b2b7386f9e5d3f296bStanislaw Gruszka 3378b5bf33575e112328af1e3cb233c7b162fe2cacdEmmanuel Grumbach if (!iwlagn_good_plcp_health(priv, cur_ofdm, cur_ofdm_ht, msecs)) 33848dffd397ec13e7fb4a52b77e8b07ed8ea12a938Johannes Berg iwl_force_rf_reset(priv, false); 339beac5498b792ed8420885ee23e8d4f2885ee2d13Wey-Yi Guy} 340beac5498b792ed8420885ee23e8d4f2885ee2d13Wey-Yi Guy 34167289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka/* Calculate noise level, based on measurements during network silence just 34267289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka * before arriving beacon. This measurement can be done only if we know 34367289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka * exactly when to expect beacons, therefore only when we're associated. */ 3443246c4e6addfbf69b23095b69c5484cd76ddb37bWey-Yi Guystatic void iwlagn_rx_calc_noise(struct iwl_priv *priv) 34567289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka{ 34667289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka struct statistics_rx_non_phy *rx_info; 34767289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka int num_active_rx = 0; 34867289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka int total_silence = 0; 34967289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka int bcn_silence_a, bcn_silence_b, bcn_silence_c; 35067289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka int last_rx_noise; 35167289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka 3520da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg rx_info = &priv->statistics.rx_non_phy; 3530da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg 35467289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka bcn_silence_a = 35567289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka le32_to_cpu(rx_info->beacon_silence_rssi_a) & IN_BAND_FILTER; 35667289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka bcn_silence_b = 35767289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka le32_to_cpu(rx_info->beacon_silence_rssi_b) & IN_BAND_FILTER; 35867289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka bcn_silence_c = 35967289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka le32_to_cpu(rx_info->beacon_silence_rssi_c) & IN_BAND_FILTER; 36067289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka 36167289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka if (bcn_silence_a) { 36267289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka total_silence += bcn_silence_a; 36367289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka num_active_rx++; 36467289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka } 36567289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka if (bcn_silence_b) { 36667289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka total_silence += bcn_silence_b; 36767289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka num_active_rx++; 36867289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka } 36967289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka if (bcn_silence_c) { 37067289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka total_silence += bcn_silence_c; 37167289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka num_active_rx++; 37267289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka } 37367289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka 37467289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka /* Average among active antennas */ 37567289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka if (num_active_rx) 37667289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka last_rx_noise = (total_silence / num_active_rx) - 107; 37767289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka else 37867289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE; 37967289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka 38067289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka IWL_DEBUG_CALIB(priv, "inband silence a %u, b %u, c %u, dBm %d\n", 38167289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka bcn_silence_a, bcn_silence_b, bcn_silence_c, 38267289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka last_rx_noise); 38367289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka} 38467289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka 3850da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg#ifdef CONFIG_IWLWIFI_DEBUGFS 38667289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka/* 38767289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka * based on the assumption of all statistics counter are in DWORD 38867289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka * FIXME: This function is for debugging, do not deal with 38967289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka * the case of counters roll-over. 39067289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka */ 3910da0e5bf1522d75d446f5124e17016628d0a149eJohannes Bergstatic void accum_stats(__le32 *prev, __le32 *cur, __le32 *delta, 3920da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg __le32 *max_delta, __le32 *accum, int size) 39367289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka{ 3940da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg int i; 3950da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg 3960da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg for (i = 0; 3970da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg i < size / sizeof(__le32); 3980da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg i++, prev++, cur++, delta++, max_delta++, accum++) { 3990da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg if (le32_to_cpu(*cur) > le32_to_cpu(*prev)) { 4000da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg *delta = cpu_to_le32( 4010da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg le32_to_cpu(*cur) - le32_to_cpu(*prev)); 4020da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg le32_add_cpu(accum, le32_to_cpu(*delta)); 4030da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg if (le32_to_cpu(*delta) > le32_to_cpu(*max_delta)) 40467289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka *max_delta = *delta; 40567289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka } 40667289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka } 4070da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg} 40867289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka 4090da0e5bf1522d75d446f5124e17016628d0a149eJohannes Bergstatic void 4103246c4e6addfbf69b23095b69c5484cd76ddb37bWey-Yi Guyiwlagn_accumulative_statistics(struct iwl_priv *priv, 4110da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg struct statistics_general_common *common, 4120da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg struct statistics_rx_non_phy *rx_non_phy, 4130da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg struct statistics_rx_phy *rx_ofdm, 4140da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg struct statistics_rx_ht_phy *rx_ofdm_ht, 4150da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg struct statistics_rx_phy *rx_cck, 4160da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg struct statistics_tx *tx, 4170da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg struct statistics_bt_activity *bt_activity) 4180da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg{ 4190da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg#define ACCUM(_name) \ 4200da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg accum_stats((__le32 *)&priv->statistics._name, \ 4210da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg (__le32 *)_name, \ 4220da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg (__le32 *)&priv->delta_stats._name, \ 4230da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg (__le32 *)&priv->max_delta_stats._name, \ 4240da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg (__le32 *)&priv->accum_stats._name, \ 4250da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg sizeof(*_name)); 4260da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg 4270da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg ACCUM(common); 4280da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg ACCUM(rx_non_phy); 4290da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg ACCUM(rx_ofdm); 4300da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg ACCUM(rx_ofdm_ht); 4310da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg ACCUM(rx_cck); 4320da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg ACCUM(tx); 4330da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg if (bt_activity) 4340da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg ACCUM(bt_activity); 4350da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg#undef ACCUM 436466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka} 4370da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg#else 4380da0e5bf1522d75d446f5124e17016628d0a149eJohannes Bergstatic inline void 4393246c4e6addfbf69b23095b69c5484cd76ddb37bWey-Yi Guyiwlagn_accumulative_statistics(struct iwl_priv *priv, 4400da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg struct statistics_general_common *common, 4410da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg struct statistics_rx_non_phy *rx_non_phy, 4420da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg struct statistics_rx_phy *rx_ofdm, 4430da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg struct statistics_rx_ht_phy *rx_ofdm_ht, 4440da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg struct statistics_rx_phy *rx_cck, 4450da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg struct statistics_tx *tx, 4460da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg struct statistics_bt_activity *bt_activity) 4470da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg{ 4480da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg} 4490da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg#endif 45067289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka 4513246c4e6addfbf69b23095b69c5484cd76ddb37bWey-Yi Guystatic int iwlagn_rx_statistics(struct iwl_priv *priv, 45248a2d66f58d2bf1818acf5ff7ed9897a9977a96eJohannes Berg struct iwl_rx_cmd_buffer *rxb, 453247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach struct iwl_device_cmd *cmd) 45467289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka{ 4550da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg unsigned long stamp = jiffies; 456466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka const int reg_recalib_period = 60; 45767289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka int change; 45867289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka struct iwl_rx_packet *pkt = rxb_addr(rxb); 45965b30348dbf9b529901b5c2b62dca6cad9017a2aJohannes Berg u32 len = iwl_rx_packet_payload_len(pkt); 4600da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg __le32 *flag; 4610da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg struct statistics_general_common *common; 4620da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg struct statistics_rx_non_phy *rx_non_phy; 4630da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg struct statistics_rx_phy *rx_ofdm; 4640da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg struct statistics_rx_ht_phy *rx_ofdm_ht; 4650da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg struct statistics_rx_phy *rx_cck; 4660da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg struct statistics_tx *tx; 4670da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg struct statistics_bt_activity *bt_activity; 4680da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg 4690da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg IWL_DEBUG_RX(priv, "Statistics notification received (%d bytes).\n", 4700da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg len); 4710da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg 4724ff70fcdf3c424c3fdca253e7b7556f77eaf39beJohannes Berg spin_lock(&priv->statistics.lock); 4734ff70fcdf3c424c3fdca253e7b7556f77eaf39beJohannes Berg 4740da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg if (len == sizeof(struct iwl_bt_notif_statistics)) { 4750da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg struct iwl_bt_notif_statistics *stats; 476f8d7c1a18d5e77b17b5cc1ebefa21eaea7f2d0faJohannes Berg stats = (void *)&pkt->data; 4770da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg flag = &stats->flag; 4780da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg common = &stats->general.common; 4790da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg rx_non_phy = &stats->rx.general.common; 4800da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg rx_ofdm = &stats->rx.ofdm; 4810da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg rx_ofdm_ht = &stats->rx.ofdm_ht; 4820da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg rx_cck = &stats->rx.cck; 4830da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg tx = &stats->tx; 4840da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg bt_activity = &stats->general.activity; 48567289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka 4860da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg#ifdef CONFIG_IWLWIFI_DEBUGFS 4870da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg /* handle this exception directly */ 4880da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg priv->statistics.num_bt_kills = stats->rx.general.num_bt_kills; 4890da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg le32_add_cpu(&priv->statistics.accum_num_bt_kills, 4900da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg le32_to_cpu(stats->rx.general.num_bt_kills)); 4910da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg#endif 4920da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg } else if (len == sizeof(struct iwl_notif_statistics)) { 4930da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg struct iwl_notif_statistics *stats; 494f8d7c1a18d5e77b17b5cc1ebefa21eaea7f2d0faJohannes Berg stats = (void *)&pkt->data; 4950da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg flag = &stats->flag; 4960da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg common = &stats->general.common; 4970da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg rx_non_phy = &stats->rx.general; 4980da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg rx_ofdm = &stats->rx.ofdm; 4990da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg rx_ofdm_ht = &stats->rx.ofdm_ht; 5000da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg rx_cck = &stats->rx.cck; 5010da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg tx = &stats->tx; 5020da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg bt_activity = NULL; 50367289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka } else { 5040da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg WARN_ONCE(1, "len %d doesn't match BT (%zu) or normal (%zu)\n", 5050da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg len, sizeof(struct iwl_bt_notif_statistics), 5060da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg sizeof(struct iwl_notif_statistics)); 5074ff70fcdf3c424c3fdca253e7b7556f77eaf39beJohannes Berg spin_unlock(&priv->statistics.lock); 508247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach return 0; 50967289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka } 51067289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka 5110da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg change = common->temperature != priv->statistics.common.temperature || 5120da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg (*flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK) != 5130da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg (priv->statistics.flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK); 5140da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg 5153246c4e6addfbf69b23095b69c5484cd76ddb37bWey-Yi Guy iwlagn_accumulative_statistics(priv, common, rx_non_phy, rx_ofdm, 5160da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg rx_ofdm_ht, rx_cck, tx, bt_activity); 5170da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg 5183246c4e6addfbf69b23095b69c5484cd76ddb37bWey-Yi Guy iwlagn_recover_from_statistics(priv, rx_ofdm, rx_ofdm_ht, tx, stamp); 5190da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg 5200da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg priv->statistics.flag = *flag; 5210da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg memcpy(&priv->statistics.common, common, sizeof(*common)); 5220da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg memcpy(&priv->statistics.rx_non_phy, rx_non_phy, sizeof(*rx_non_phy)); 5230da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg memcpy(&priv->statistics.rx_ofdm, rx_ofdm, sizeof(*rx_ofdm)); 5240da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg memcpy(&priv->statistics.rx_ofdm_ht, rx_ofdm_ht, sizeof(*rx_ofdm_ht)); 5250da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg memcpy(&priv->statistics.rx_cck, rx_cck, sizeof(*rx_cck)); 5260da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg memcpy(&priv->statistics.tx, tx, sizeof(*tx)); 5270da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg#ifdef CONFIG_IWLWIFI_DEBUGFS 5280da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg if (bt_activity) 5290da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg memcpy(&priv->statistics.bt_activity, bt_activity, 5300da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg sizeof(*bt_activity)); 5310da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg#endif 5320da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg 5330da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg priv->rx_statistics_jiffies = stamp; 53467289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka 53583626404a70da74c67f32f119e53c0ba032ba2d8Don Fry set_bit(STATUS_STATISTICS, &priv->status); 53667289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka 53767289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka /* Reschedule the statistics timer to occur in 538466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka * reg_recalib_period seconds to ensure we get a 53967289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka * thermal update even if the uCode doesn't give 54067289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka * us one */ 54167289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka mod_timer(&priv->statistics_periodic, jiffies + 542466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka msecs_to_jiffies(reg_recalib_period * 1000)); 54367289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka 54483626404a70da74c67f32f119e53c0ba032ba2d8Don Fry if (unlikely(!test_bit(STATUS_SCANNING, &priv->status)) && 54567289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka (pkt->hdr.cmd == STATISTICS_NOTIFICATION)) { 5463246c4e6addfbf69b23095b69c5484cd76ddb37bWey-Yi Guy iwlagn_rx_calc_noise(priv); 5471ee158d83853a9f5c1465be56d56ff56e6698e92Johannes Berg queue_work(priv->workqueue, &priv->run_time_calib_work); 54867289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka } 549e96766958c914f1240317c967bb322cd3731fb17Johannes Berg if (priv->lib->temperature && change) 550e96766958c914f1240317c967bb322cd3731fb17Johannes Berg priv->lib->temperature(priv); 5514ff70fcdf3c424c3fdca253e7b7556f77eaf39beJohannes Berg 5524ff70fcdf3c424c3fdca253e7b7556f77eaf39beJohannes Berg spin_unlock(&priv->statistics.lock); 5534ff70fcdf3c424c3fdca253e7b7556f77eaf39beJohannes Berg 554247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach return 0; 55567289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka} 55667289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka 5573246c4e6addfbf69b23095b69c5484cd76ddb37bWey-Yi Guystatic int iwlagn_rx_reply_statistics(struct iwl_priv *priv, 55848a2d66f58d2bf1818acf5ff7ed9897a9977a96eJohannes Berg struct iwl_rx_cmd_buffer *rxb, 559247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach struct iwl_device_cmd *cmd) 56067289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka{ 56167289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka struct iwl_rx_packet *pkt = rxb_addr(rxb); 562f8d7c1a18d5e77b17b5cc1ebefa21eaea7f2d0faJohannes Berg struct iwl_notif_statistics *stats = (void *)pkt->data; 56367289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka 564f8d7c1a18d5e77b17b5cc1ebefa21eaea7f2d0faJohannes Berg if (le32_to_cpu(stats->flag) & UCODE_STATISTICS_CLEAR_MSK) { 56567289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka#ifdef CONFIG_IWLWIFI_DEBUGFS 5660da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg memset(&priv->accum_stats, 0, 5670da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg sizeof(priv->accum_stats)); 5680da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg memset(&priv->delta_stats, 0, 5690da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg sizeof(priv->delta_stats)); 5700da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg memset(&priv->max_delta_stats, 0, 5710da0e5bf1522d75d446f5124e17016628d0a149eJohannes Berg sizeof(priv->max_delta_stats)); 57267289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka#endif 57367289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka IWL_DEBUG_RX(priv, "Statistics have been cleared\n"); 57467289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka } 5753246c4e6addfbf69b23095b69c5484cd76ddb37bWey-Yi Guy iwlagn_rx_statistics(priv, rxb, cmd); 576247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach return 0; 57767289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka} 57867289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka 579466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka/* Handle notification from uCode that card's power state is changing 580466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka * due to software, hardware, or critical temperature RFKILL */ 5813246c4e6addfbf69b23095b69c5484cd76ddb37bWey-Yi Guystatic int iwlagn_rx_card_state_notif(struct iwl_priv *priv, 58248a2d66f58d2bf1818acf5ff7ed9897a9977a96eJohannes Berg struct iwl_rx_cmd_buffer *rxb, 583247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach struct iwl_device_cmd *cmd) 584466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka{ 585466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka struct iwl_rx_packet *pkt = rxb_addr(rxb); 586f8d7c1a18d5e77b17b5cc1ebefa21eaea7f2d0faJohannes Berg struct iwl_card_state_notif *card_state_notif = (void *)pkt->data; 587f8d7c1a18d5e77b17b5cc1ebefa21eaea7f2d0faJohannes Berg u32 flags = le32_to_cpu(card_state_notif->flags); 5881353a7ba7ebe62dedc60a5ba75c434cfad960edeDon Fry unsigned long status = priv->status; 589466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 590466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka IWL_DEBUG_RF_KILL(priv, "Card state received: HW:%s SW:%s CT:%s\n", 591466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka (flags & HW_CARD_DISABLED) ? "Kill" : "On", 592466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka (flags & SW_CARD_DISABLED) ? "Kill" : "On", 593466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka (flags & CT_CARD_DISABLED) ? 594466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka "Reached" : "Not reached"); 595466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 596466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka if (flags & (SW_CARD_DISABLED | HW_CARD_DISABLED | 597466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka CT_CARD_DISABLED)) { 598466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 59968e8dfdadb424fd76ca81eeb399c3228adc5cea2Emmanuel Grumbach iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_SET, 600466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); 601466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 60268e8dfdadb424fd76ca81eeb399c3228adc5cea2Emmanuel Grumbach iwl_write_direct32(priv->trans, HBUS_TARG_MBX_C, 603466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED); 604466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 605466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka if (!(flags & RXON_CARD_DISABLED)) { 60668e8dfdadb424fd76ca81eeb399c3228adc5cea2Emmanuel Grumbach iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_CLR, 607466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); 60868e8dfdadb424fd76ca81eeb399c3228adc5cea2Emmanuel Grumbach iwl_write_direct32(priv->trans, HBUS_TARG_MBX_C, 609466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED); 610466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka } 611466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka if (flags & CT_CARD_DISABLED) 612466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka iwl_tt_enter_ct_kill(priv); 613466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka } 614466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka if (!(flags & CT_CARD_DISABLED)) 615466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka iwl_tt_exit_ct_kill(priv); 616466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 617466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka if (flags & HW_CARD_DISABLED) 61883626404a70da74c67f32f119e53c0ba032ba2d8Don Fry set_bit(STATUS_RF_KILL_HW, &priv->status); 619466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka else 62083626404a70da74c67f32f119e53c0ba032ba2d8Don Fry clear_bit(STATUS_RF_KILL_HW, &priv->status); 621466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 622466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 623466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka if (!(flags & RXON_CARD_DISABLED)) 624466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka iwl_scan_cancel(priv); 625466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 626466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka if ((test_bit(STATUS_RF_KILL_HW, &status) != 62783626404a70da74c67f32f119e53c0ba032ba2d8Don Fry test_bit(STATUS_RF_KILL_HW, &priv->status))) 628466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka wiphy_rfkill_set_hw_state(priv->hw->wiphy, 62983626404a70da74c67f32f119e53c0ba032ba2d8Don Fry test_bit(STATUS_RF_KILL_HW, &priv->status)); 630247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach return 0; 631466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka} 632466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 6333246c4e6addfbf69b23095b69c5484cd76ddb37bWey-Yi Guystatic int iwlagn_rx_missed_beacon_notif(struct iwl_priv *priv, 63448a2d66f58d2bf1818acf5ff7ed9897a9977a96eJohannes Berg struct iwl_rx_cmd_buffer *rxb, 635247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach struct iwl_device_cmd *cmd) 63667289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka 63767289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka{ 63867289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka struct iwl_rx_packet *pkt = rxb_addr(rxb); 639f8d7c1a18d5e77b17b5cc1ebefa21eaea7f2d0faJohannes Berg struct iwl_missed_beacon_notif *missed_beacon = (void *)pkt->data; 64067289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka 64167289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka if (le32_to_cpu(missed_beacon->consecutive_missed_beacons) > 64267289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka priv->missed_beacon_threshold) { 64367289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka IWL_DEBUG_CALIB(priv, 64467289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka "missed bcn cnsq %d totl %d rcd %d expctd %d\n", 64567289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka le32_to_cpu(missed_beacon->consecutive_missed_beacons), 64667289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka le32_to_cpu(missed_beacon->total_missed_becons), 64767289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka le32_to_cpu(missed_beacon->num_recvd_beacons), 64867289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka le32_to_cpu(missed_beacon->num_expected_beacons)); 64983626404a70da74c67f32f119e53c0ba032ba2d8Don Fry if (!test_bit(STATUS_SCANNING, &priv->status)) 65067289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka iwl_init_sensitivity(priv); 65167289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka } 652247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach return 0; 65367289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka} 65467289941d80f18fd8239e350e015a4b84878412bStanislaw Gruszka 655466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka/* Cache phy data (Rx signal strength, etc) for HT frame (REPLY_RX_PHY_CMD). 656466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka * This will be used later in iwl_rx_reply_rx() for REPLY_RX_MPDU_CMD. */ 6573246c4e6addfbf69b23095b69c5484cd76ddb37bWey-Yi Guystatic int iwlagn_rx_reply_rx_phy(struct iwl_priv *priv, 65848a2d66f58d2bf1818acf5ff7ed9897a9977a96eJohannes Berg struct iwl_rx_cmd_buffer *rxb, 659247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach struct iwl_device_cmd *cmd) 660466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka{ 661466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka struct iwl_rx_packet *pkt = rxb_addr(rxb); 662466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 663898ed67be047d0762cc7592f67bf1313dff53ca9Wey-Yi Guy priv->last_phy_res_valid = true; 66412bf6f45d17038589e0eaa8adeb7ee8169c0e4deJohannes Berg priv->ampdu_ref++; 665f8d7c1a18d5e77b17b5cc1ebefa21eaea7f2d0faJohannes Berg memcpy(&priv->last_phy_res, pkt->data, 666466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka sizeof(struct iwl_rx_phy_res)); 667247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach return 0; 668466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka} 669466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 6701781a07fbe9cce3dc1697288a5edd260ea7edc02Emmanuel Grumbach/* 6711781a07fbe9cce3dc1697288a5edd260ea7edc02Emmanuel Grumbach * returns non-zero if packet should be dropped 6721781a07fbe9cce3dc1697288a5edd260ea7edc02Emmanuel Grumbach */ 6733246c4e6addfbf69b23095b69c5484cd76ddb37bWey-Yi Guystatic int iwlagn_set_decrypted_flag(struct iwl_priv *priv, 674466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka struct ieee80211_hdr *hdr, 675466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka u32 decrypt_res, 676466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka struct ieee80211_rx_status *stats) 6771781a07fbe9cce3dc1697288a5edd260ea7edc02Emmanuel Grumbach{ 6781781a07fbe9cce3dc1697288a5edd260ea7edc02Emmanuel Grumbach u16 fc = le16_to_cpu(hdr->frame_control); 6791781a07fbe9cce3dc1697288a5edd260ea7edc02Emmanuel Grumbach 680246ed355221076884d225f9d8a4c30a048be8162Johannes Berg /* 681246ed355221076884d225f9d8a4c30a048be8162Johannes Berg * All contexts have the same setting here due to it being 682246ed355221076884d225f9d8a4c30a048be8162Johannes Berg * a module parameter, so OK to check any context. 683246ed355221076884d225f9d8a4c30a048be8162Johannes Berg */ 684246ed355221076884d225f9d8a4c30a048be8162Johannes Berg if (priv->contexts[IWL_RXON_CTX_BSS].active.filter_flags & 685246ed355221076884d225f9d8a4c30a048be8162Johannes Berg RXON_FILTER_DIS_DECRYPT_MSK) 6861781a07fbe9cce3dc1697288a5edd260ea7edc02Emmanuel Grumbach return 0; 6871781a07fbe9cce3dc1697288a5edd260ea7edc02Emmanuel Grumbach 6881781a07fbe9cce3dc1697288a5edd260ea7edc02Emmanuel Grumbach if (!(fc & IEEE80211_FCTL_PROTECTED)) 6891781a07fbe9cce3dc1697288a5edd260ea7edc02Emmanuel Grumbach return 0; 6901781a07fbe9cce3dc1697288a5edd260ea7edc02Emmanuel Grumbach 691e1623446bb1de1834ff1c57b3e8ed341d5d4a927Tomas Winkler IWL_DEBUG_RX(priv, "decrypt_res:0x%x\n", decrypt_res); 6921781a07fbe9cce3dc1697288a5edd260ea7edc02Emmanuel Grumbach switch (decrypt_res & RX_RES_STATUS_SEC_TYPE_MSK) { 6931781a07fbe9cce3dc1697288a5edd260ea7edc02Emmanuel Grumbach case RX_RES_STATUS_SEC_TYPE_TKIP: 6941781a07fbe9cce3dc1697288a5edd260ea7edc02Emmanuel Grumbach /* The uCode has got a bad phase 1 Key, pushes the packet. 6951781a07fbe9cce3dc1697288a5edd260ea7edc02Emmanuel Grumbach * Decryption will be done in SW. */ 6961781a07fbe9cce3dc1697288a5edd260ea7edc02Emmanuel Grumbach if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == 6971781a07fbe9cce3dc1697288a5edd260ea7edc02Emmanuel Grumbach RX_RES_STATUS_BAD_KEY_TTAK) 6981781a07fbe9cce3dc1697288a5edd260ea7edc02Emmanuel Grumbach break; 6991781a07fbe9cce3dc1697288a5edd260ea7edc02Emmanuel Grumbach 7001781a07fbe9cce3dc1697288a5edd260ea7edc02Emmanuel Grumbach case RX_RES_STATUS_SEC_TYPE_WEP: 7011781a07fbe9cce3dc1697288a5edd260ea7edc02Emmanuel Grumbach if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == 7021781a07fbe9cce3dc1697288a5edd260ea7edc02Emmanuel Grumbach RX_RES_STATUS_BAD_ICV_MIC) { 7031781a07fbe9cce3dc1697288a5edd260ea7edc02Emmanuel Grumbach /* bad ICV, the packet is destroyed since the 7041781a07fbe9cce3dc1697288a5edd260ea7edc02Emmanuel Grumbach * decryption is inplace, drop it */ 705e1623446bb1de1834ff1c57b3e8ed341d5d4a927Tomas Winkler IWL_DEBUG_RX(priv, "Packet destroyed\n"); 7061781a07fbe9cce3dc1697288a5edd260ea7edc02Emmanuel Grumbach return -1; 7071781a07fbe9cce3dc1697288a5edd260ea7edc02Emmanuel Grumbach } 7081781a07fbe9cce3dc1697288a5edd260ea7edc02Emmanuel Grumbach case RX_RES_STATUS_SEC_TYPE_CCMP: 7091781a07fbe9cce3dc1697288a5edd260ea7edc02Emmanuel Grumbach if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == 7101781a07fbe9cce3dc1697288a5edd260ea7edc02Emmanuel Grumbach RX_RES_STATUS_DECRYPT_OK) { 711e1623446bb1de1834ff1c57b3e8ed341d5d4a927Tomas Winkler IWL_DEBUG_RX(priv, "hw decrypt successfully!!!\n"); 7121781a07fbe9cce3dc1697288a5edd260ea7edc02Emmanuel Grumbach stats->flag |= RX_FLAG_DECRYPTED; 7131781a07fbe9cce3dc1697288a5edd260ea7edc02Emmanuel Grumbach } 7141781a07fbe9cce3dc1697288a5edd260ea7edc02Emmanuel Grumbach break; 7151781a07fbe9cce3dc1697288a5edd260ea7edc02Emmanuel Grumbach 7161781a07fbe9cce3dc1697288a5edd260ea7edc02Emmanuel Grumbach default: 7171781a07fbe9cce3dc1697288a5edd260ea7edc02Emmanuel Grumbach break; 7181781a07fbe9cce3dc1697288a5edd260ea7edc02Emmanuel Grumbach } 7191781a07fbe9cce3dc1697288a5edd260ea7edc02Emmanuel Grumbach return 0; 7201781a07fbe9cce3dc1697288a5edd260ea7edc02Emmanuel Grumbach} 721466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 7223246c4e6addfbf69b23095b69c5484cd76ddb37bWey-Yi Guystatic void iwlagn_pass_packet_to_mac80211(struct iwl_priv *priv, 723466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka struct ieee80211_hdr *hdr, 724466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka u16 len, 725466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka u32 ampdu_status, 72648a2d66f58d2bf1818acf5ff7ed9897a9977a96eJohannes Berg struct iwl_rx_cmd_buffer *rxb, 727466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka struct ieee80211_rx_status *stats) 728466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka{ 729466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka struct sk_buff *skb; 730466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka __le16 fc = hdr->frame_control; 73168b993118f715cc631b62b6a50574e4701fe9aceGaren Tamrazian struct iwl_rxon_context *ctx; 732ed90542b0ce5415050c6fbfca324bccaafa69f2fEric Dumazet unsigned int hdrlen, fraglen; 733466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 734466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka /* We only process data packets if the interface is open */ 735466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka if (unlikely(!priv->is_open)) { 736466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka IWL_DEBUG_DROP_LIMIT(priv, 737466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka "Dropping packet while interface is not open.\n"); 738466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka return; 739466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka } 740466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 741466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka /* In case of HW accelerated crypto and bad decryption, drop */ 74265de7e84fdc71a409f1d97aba8e44ece26628f51Johannes Berg if (!iwlwifi_mod_params.sw_crypto && 7433246c4e6addfbf69b23095b69c5484cd76ddb37bWey-Yi Guy iwlagn_set_decrypted_flag(priv, hdr, ampdu_status, stats)) 744466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka return; 745466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 746ed90542b0ce5415050c6fbfca324bccaafa69f2fEric Dumazet /* Dont use dev_alloc_skb(), we'll have enough headroom once 747ed90542b0ce5415050c6fbfca324bccaafa69f2fEric Dumazet * ieee80211_hdr pulled. 748ed90542b0ce5415050c6fbfca324bccaafa69f2fEric Dumazet */ 749ed90542b0ce5415050c6fbfca324bccaafa69f2fEric Dumazet skb = alloc_skb(128, GFP_ATOMIC); 750466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka if (!skb) { 751ed90542b0ce5415050c6fbfca324bccaafa69f2fEric Dumazet IWL_ERR(priv, "alloc_skb failed\n"); 752466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka return; 753466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka } 75456138f50d1900b0c3d8647376e37b488b23ba53dEric Dumazet /* If frame is small enough to fit in skb->head, pull it completely. 75556138f50d1900b0c3d8647376e37b488b23ba53dEric Dumazet * If not, only pull ieee80211_hdr so that splice() or TCP coalesce 75656138f50d1900b0c3d8647376e37b488b23ba53dEric Dumazet * are more efficient. 75756138f50d1900b0c3d8647376e37b488b23ba53dEric Dumazet */ 75856138f50d1900b0c3d8647376e37b488b23ba53dEric Dumazet hdrlen = (len <= skb_tailroom(skb)) ? len : sizeof(*hdr); 75956138f50d1900b0c3d8647376e37b488b23ba53dEric Dumazet 760ed90542b0ce5415050c6fbfca324bccaafa69f2fEric Dumazet memcpy(skb_put(skb, hdrlen), hdr, hdrlen); 761ed90542b0ce5415050c6fbfca324bccaafa69f2fEric Dumazet fraglen = len - hdrlen; 762466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 763ed90542b0ce5415050c6fbfca324bccaafa69f2fEric Dumazet if (fraglen) { 764341352d13dae752610342923c53ebe461624ee2cJohn W. Linville int offset = (void *)hdr + hdrlen - 765341352d13dae752610342923c53ebe461624ee2cJohn W. Linville rxb_addr(rxb) + rxb_offset(rxb); 766466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 767ed90542b0ce5415050c6fbfca324bccaafa69f2fEric Dumazet skb_add_rx_frag(skb, 0, rxb_steal_page(rxb), offset, 768ed90542b0ce5415050c6fbfca324bccaafa69f2fEric Dumazet fraglen, rxb->truesize); 769ed90542b0ce5415050c6fbfca324bccaafa69f2fEric Dumazet } 770466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 77168b993118f715cc631b62b6a50574e4701fe9aceGaren Tamrazian /* 77268b993118f715cc631b62b6a50574e4701fe9aceGaren Tamrazian * Wake any queues that were stopped due to a passive channel tx 77368b993118f715cc631b62b6a50574e4701fe9aceGaren Tamrazian * failure. This can happen because the regulatory enforcement in 77468b993118f715cc631b62b6a50574e4701fe9aceGaren Tamrazian * the device waits for a beacon before allowing transmission, 77568b993118f715cc631b62b6a50574e4701fe9aceGaren Tamrazian * sometimes even after already having transmitted frames for the 77668b993118f715cc631b62b6a50574e4701fe9aceGaren Tamrazian * association because the new RXON may reset the information. 77768b993118f715cc631b62b6a50574e4701fe9aceGaren Tamrazian */ 778e755f882b7e72c48da820acc24196532977cfd07Johannes Berg if (unlikely(ieee80211_is_beacon(fc) && priv->passive_no_rx)) { 77968b993118f715cc631b62b6a50574e4701fe9aceGaren Tamrazian for_each_context(priv, ctx) { 7802e42e4747ea72943c21551d8a206b51a9893b1e0Joe Perches if (!ether_addr_equal(hdr->addr3, 7812e42e4747ea72943c21551d8a206b51a9893b1e0Joe Perches ctx->active.bssid_addr)) 78268b993118f715cc631b62b6a50574e4701fe9aceGaren Tamrazian continue; 783e755f882b7e72c48da820acc24196532977cfd07Johannes Berg iwlagn_lift_passive_no_rx(priv); 78468b993118f715cc631b62b6a50574e4701fe9aceGaren Tamrazian } 78568b993118f715cc631b62b6a50574e4701fe9aceGaren Tamrazian } 78668b993118f715cc631b62b6a50574e4701fe9aceGaren Tamrazian 787466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); 788466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 789aeb0cf3cd08ad3ddcb554ca546c560a31ca44265Emmanuel Grumbach ieee80211_rx(priv->hw, skb); 790466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka} 791466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 7923246c4e6addfbf69b23095b69c5484cd76ddb37bWey-Yi Guystatic u32 iwlagn_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in) 793466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka{ 794466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka u32 decrypt_out = 0; 795466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 796466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka if ((decrypt_in & RX_RES_STATUS_STATION_FOUND) == 797466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka RX_RES_STATUS_STATION_FOUND) 798466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka decrypt_out |= (RX_RES_STATUS_STATION_FOUND | 799466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka RX_RES_STATUS_NO_STATION_INFO_MISMATCH); 800466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 801466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka decrypt_out |= (decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK); 802466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 803466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka /* packet was not encrypted */ 804466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka if ((decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) == 805466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka RX_RES_STATUS_SEC_TYPE_NONE) 806466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka return decrypt_out; 807466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 808466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka /* packet was encrypted with unknown alg */ 809466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka if ((decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) == 810466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka RX_RES_STATUS_SEC_TYPE_ERR) 811466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka return decrypt_out; 812466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 813466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka /* decryption was not done in HW */ 814466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka if ((decrypt_in & RX_MPDU_RES_STATUS_DEC_DONE_MSK) != 815466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka RX_MPDU_RES_STATUS_DEC_DONE_MSK) 816466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka return decrypt_out; 817466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 818466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka switch (decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) { 819466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 820466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka case RX_RES_STATUS_SEC_TYPE_CCMP: 821466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka /* alg is CCM: check MIC only */ 822466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka if (!(decrypt_in & RX_MPDU_RES_STATUS_MIC_OK)) 823466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka /* Bad MIC */ 824466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC; 825466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka else 826466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka decrypt_out |= RX_RES_STATUS_DECRYPT_OK; 827466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 828466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka break; 829466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 830466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka case RX_RES_STATUS_SEC_TYPE_TKIP: 831466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka if (!(decrypt_in & RX_MPDU_RES_STATUS_TTAK_OK)) { 832466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka /* Bad TTAK */ 833466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka decrypt_out |= RX_RES_STATUS_BAD_KEY_TTAK; 834466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka break; 835466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka } 836466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka /* fall through if TTAK OK */ 837466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka default: 838466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka if (!(decrypt_in & RX_MPDU_RES_STATUS_ICV_OK)) 839466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC; 840466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka else 841466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka decrypt_out |= RX_RES_STATUS_DECRYPT_OK; 842466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka break; 843466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka } 844466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 845466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka IWL_DEBUG_RX(priv, "decrypt_in:0x%x decrypt_out = 0x%x\n", 846466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka decrypt_in, decrypt_out); 847466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 848466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka return decrypt_out; 849466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka} 850466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 8515c3d29fc0d083e674c09407f1bc78e9dbf4ae8a5Don Fry/* Calc max signal level (dBm) among 3 possible receivers */ 8525c3d29fc0d083e674c09407f1bc78e9dbf4ae8a5Don Frystatic int iwlagn_calc_rssi(struct iwl_priv *priv, 8535c3d29fc0d083e674c09407f1bc78e9dbf4ae8a5Don Fry struct iwl_rx_phy_res *rx_resp) 8545c3d29fc0d083e674c09407f1bc78e9dbf4ae8a5Don Fry{ 8555c3d29fc0d083e674c09407f1bc78e9dbf4ae8a5Don Fry /* data from PHY/DSP regarding signal strength, etc., 8565c3d29fc0d083e674c09407f1bc78e9dbf4ae8a5Don Fry * contents are always there, not configurable by host 8575c3d29fc0d083e674c09407f1bc78e9dbf4ae8a5Don Fry */ 8585c3d29fc0d083e674c09407f1bc78e9dbf4ae8a5Don Fry struct iwlagn_non_cfg_phy *ncphy = 8595c3d29fc0d083e674c09407f1bc78e9dbf4ae8a5Don Fry (struct iwlagn_non_cfg_phy *)rx_resp->non_cfg_phy_buf; 8605c3d29fc0d083e674c09407f1bc78e9dbf4ae8a5Don Fry u32 val, rssi_a, rssi_b, rssi_c, max_rssi; 8615c3d29fc0d083e674c09407f1bc78e9dbf4ae8a5Don Fry u8 agc; 8625c3d29fc0d083e674c09407f1bc78e9dbf4ae8a5Don Fry 8635c3d29fc0d083e674c09407f1bc78e9dbf4ae8a5Don Fry val = le32_to_cpu(ncphy->non_cfg_phy[IWLAGN_RX_RES_AGC_IDX]); 8645c3d29fc0d083e674c09407f1bc78e9dbf4ae8a5Don Fry agc = (val & IWLAGN_OFDM_AGC_MSK) >> IWLAGN_OFDM_AGC_BIT_POS; 8655c3d29fc0d083e674c09407f1bc78e9dbf4ae8a5Don Fry 8665c3d29fc0d083e674c09407f1bc78e9dbf4ae8a5Don Fry /* Find max rssi among 3 possible receivers. 8675c3d29fc0d083e674c09407f1bc78e9dbf4ae8a5Don Fry * These values are measured by the digital signal processor (DSP). 8685c3d29fc0d083e674c09407f1bc78e9dbf4ae8a5Don Fry * They should stay fairly constant even as the signal strength varies, 8695c3d29fc0d083e674c09407f1bc78e9dbf4ae8a5Don Fry * if the radio's automatic gain control (AGC) is working right. 8705c3d29fc0d083e674c09407f1bc78e9dbf4ae8a5Don Fry * AGC value (see below) will provide the "interesting" info. 8715c3d29fc0d083e674c09407f1bc78e9dbf4ae8a5Don Fry */ 8725c3d29fc0d083e674c09407f1bc78e9dbf4ae8a5Don Fry val = le32_to_cpu(ncphy->non_cfg_phy[IWLAGN_RX_RES_RSSI_AB_IDX]); 8735c3d29fc0d083e674c09407f1bc78e9dbf4ae8a5Don Fry rssi_a = (val & IWLAGN_OFDM_RSSI_INBAND_A_BITMSK) >> 8745c3d29fc0d083e674c09407f1bc78e9dbf4ae8a5Don Fry IWLAGN_OFDM_RSSI_A_BIT_POS; 8755c3d29fc0d083e674c09407f1bc78e9dbf4ae8a5Don Fry rssi_b = (val & IWLAGN_OFDM_RSSI_INBAND_B_BITMSK) >> 8765c3d29fc0d083e674c09407f1bc78e9dbf4ae8a5Don Fry IWLAGN_OFDM_RSSI_B_BIT_POS; 8775c3d29fc0d083e674c09407f1bc78e9dbf4ae8a5Don Fry val = le32_to_cpu(ncphy->non_cfg_phy[IWLAGN_RX_RES_RSSI_C_IDX]); 8785c3d29fc0d083e674c09407f1bc78e9dbf4ae8a5Don Fry rssi_c = (val & IWLAGN_OFDM_RSSI_INBAND_C_BITMSK) >> 8795c3d29fc0d083e674c09407f1bc78e9dbf4ae8a5Don Fry IWLAGN_OFDM_RSSI_C_BIT_POS; 8805c3d29fc0d083e674c09407f1bc78e9dbf4ae8a5Don Fry 8815c3d29fc0d083e674c09407f1bc78e9dbf4ae8a5Don Fry max_rssi = max_t(u32, rssi_a, rssi_b); 8825c3d29fc0d083e674c09407f1bc78e9dbf4ae8a5Don Fry max_rssi = max_t(u32, max_rssi, rssi_c); 8835c3d29fc0d083e674c09407f1bc78e9dbf4ae8a5Don Fry 8845c3d29fc0d083e674c09407f1bc78e9dbf4ae8a5Don Fry IWL_DEBUG_STATS(priv, "Rssi In A %d B %d C %d Max %d AGC dB %d\n", 8855c3d29fc0d083e674c09407f1bc78e9dbf4ae8a5Don Fry rssi_a, rssi_b, rssi_c, max_rssi, agc); 8865c3d29fc0d083e674c09407f1bc78e9dbf4ae8a5Don Fry 8875c3d29fc0d083e674c09407f1bc78e9dbf4ae8a5Don Fry /* dBm = max_rssi dB - agc dB - constant. 8885c3d29fc0d083e674c09407f1bc78e9dbf4ae8a5Don Fry * Higher AGC (higher radio gain) means lower signal. */ 8895c3d29fc0d083e674c09407f1bc78e9dbf4ae8a5Don Fry return max_rssi - agc - IWLAGN_RSSI_OFFSET; 8905c3d29fc0d083e674c09407f1bc78e9dbf4ae8a5Don Fry} 8915c3d29fc0d083e674c09407f1bc78e9dbf4ae8a5Don Fry 8926d044b90022a6a5cffc35395c4b559b6c36deb06Emmanuel Grumbach/* Called for REPLY_RX_MPDU_CMD */ 8933246c4e6addfbf69b23095b69c5484cd76ddb37bWey-Yi Guystatic int iwlagn_rx_reply_rx(struct iwl_priv *priv, 89448a2d66f58d2bf1818acf5ff7ed9897a9977a96eJohannes Berg struct iwl_rx_cmd_buffer *rxb, 895247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach struct iwl_device_cmd *cmd) 896466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka{ 897466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka struct ieee80211_hdr *header; 8981d815ef4b8b8ebd6ef2cffcad663ae91d15646a2Johannes Berg struct ieee80211_rx_status rx_status = {}; 899466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka struct iwl_rx_packet *pkt = rxb_addr(rxb); 900466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka struct iwl_rx_phy_res *phy_res; 901466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka __le32 rx_pkt_status; 902466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka struct iwl_rx_mpdu_res_start *amsdu; 903466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka u32 len; 904466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka u32 ampdu_status; 905466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka u32 rate_n_flags; 906466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 9076d044b90022a6a5cffc35395c4b559b6c36deb06Emmanuel Grumbach if (!priv->last_phy_res_valid) { 9086d044b90022a6a5cffc35395c4b559b6c36deb06Emmanuel Grumbach IWL_ERR(priv, "MPDU frame without cached PHY data\n"); 9096d044b90022a6a5cffc35395c4b559b6c36deb06Emmanuel Grumbach return 0; 910466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka } 9116d044b90022a6a5cffc35395c4b559b6c36deb06Emmanuel Grumbach phy_res = &priv->last_phy_res; 9126d044b90022a6a5cffc35395c4b559b6c36deb06Emmanuel Grumbach amsdu = (struct iwl_rx_mpdu_res_start *)pkt->data; 9136d044b90022a6a5cffc35395c4b559b6c36deb06Emmanuel Grumbach header = (struct ieee80211_hdr *)(pkt->data + sizeof(*amsdu)); 9146d044b90022a6a5cffc35395c4b559b6c36deb06Emmanuel Grumbach len = le16_to_cpu(amsdu->byte_count); 9156d044b90022a6a5cffc35395c4b559b6c36deb06Emmanuel Grumbach rx_pkt_status = *(__le32 *)(pkt->data + sizeof(*amsdu) + len); 9166d044b90022a6a5cffc35395c4b559b6c36deb06Emmanuel Grumbach ampdu_status = iwlagn_translate_rx_status(priv, 9176d044b90022a6a5cffc35395c4b559b6c36deb06Emmanuel Grumbach le32_to_cpu(rx_pkt_status)); 918466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 919466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka if ((unlikely(phy_res->cfg_phy_cnt > 20))) { 9200ca24daff5b8d584f91172f08f34ce0856ebe4a1Johannes Berg IWL_DEBUG_DROP(priv, "dsp size out of range [0,20]: %d\n", 921466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka phy_res->cfg_phy_cnt); 922247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach return 0; 923466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka } 924466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 925466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka if (!(rx_pkt_status & RX_RES_STATUS_NO_CRC32_ERROR) || 926466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka !(rx_pkt_status & RX_RES_STATUS_NO_RXE_OVERFLOW)) { 927466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka IWL_DEBUG_RX(priv, "Bad CRC or FIFO: 0x%08X.\n", 928466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka le32_to_cpu(rx_pkt_status)); 929247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach return 0; 930466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka } 931466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 932466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka /* This will be used in several places later */ 933466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka rate_n_flags = le32_to_cpu(phy_res->rate_n_flags); 934466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 935466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka /* rx_status carries information about the packet to mac80211 */ 936466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka rx_status.mactime = le64_to_cpu(phy_res->timestamp); 937466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka rx_status.band = (phy_res->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ? 938466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; 939466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka rx_status.freq = 940466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka ieee80211_channel_to_frequency(le16_to_cpu(phy_res->channel), 941466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka rx_status.band); 942466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka rx_status.rate_idx = 943466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka iwlagn_hwrate_to_mac80211_idx(rate_n_flags, rx_status.band); 944466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka rx_status.flag = 0; 945466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 946466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka /* TSF isn't reliable. In order to allow smooth user experience, 947466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka * this W/A doesn't propagate it to the mac80211 */ 948f4bda337bbb6e245e2a07f344990adeb6a70ff35Thomas Pedersen /*rx_status.flag |= RX_FLAG_MACTIME_START;*/ 949466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 950466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka priv->ucode_beacon_time = le32_to_cpu(phy_res->beacon_time_stamp); 951466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 952466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka /* Find max signal strength (dBm) among 3 antenna/receiver chains */ 9535c3d29fc0d083e674c09407f1bc78e9dbf4ae8a5Don Fry rx_status.signal = iwlagn_calc_rssi(priv, phy_res); 954466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 955466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka IWL_DEBUG_STATS_LIMIT(priv, "Rssi %d, TSF %llu\n", 956466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka rx_status.signal, (unsigned long long)rx_status.mactime); 957466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 958466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka /* 959466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka * "antenna number" 960466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka * 961466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka * It seems that the antenna field in the phy flags value 962466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka * is actually a bit field. This is undefined by radiotap, 963466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka * it wants an actual antenna number but I always get "7" 964466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka * for most legacy frames I receive indicating that the 965466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka * same frame was received on all three RX chains. 966466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka * 967466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka * I think this field should be removed in favor of a 968466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka * new 802.11n radiotap field "RX chains" that is defined 969466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka * as a bitmask. 970466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka */ 971466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka rx_status.antenna = 972466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka (le16_to_cpu(phy_res->phy_flags) & RX_RES_PHY_FLAGS_ANTENNA_MSK) 973466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka >> RX_RES_PHY_FLAGS_ANTENNA_POS; 974466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 975466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka /* set the preamble flag if appropriate */ 976466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka if (phy_res->phy_flags & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK) 977466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka rx_status.flag |= RX_FLAG_SHORTPRE; 978466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 97912bf6f45d17038589e0eaa8adeb7ee8169c0e4deJohannes Berg if (phy_res->phy_flags & RX_RES_PHY_FLAGS_AGG_MSK) { 98012bf6f45d17038589e0eaa8adeb7ee8169c0e4deJohannes Berg /* 98112bf6f45d17038589e0eaa8adeb7ee8169c0e4deJohannes Berg * We know which subframes of an A-MPDU belong 98212bf6f45d17038589e0eaa8adeb7ee8169c0e4deJohannes Berg * together since we get a single PHY response 98312bf6f45d17038589e0eaa8adeb7ee8169c0e4deJohannes Berg * from the firmware for all of them 98412bf6f45d17038589e0eaa8adeb7ee8169c0e4deJohannes Berg */ 98512bf6f45d17038589e0eaa8adeb7ee8169c0e4deJohannes Berg rx_status.flag |= RX_FLAG_AMPDU_DETAILS; 98612bf6f45d17038589e0eaa8adeb7ee8169c0e4deJohannes Berg rx_status.ampdu_reference = priv->ampdu_ref; 98712bf6f45d17038589e0eaa8adeb7ee8169c0e4deJohannes Berg } 98812bf6f45d17038589e0eaa8adeb7ee8169c0e4deJohannes Berg 989466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka /* Set up the HT phy flags */ 990466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka if (rate_n_flags & RATE_MCS_HT_MSK) 991466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka rx_status.flag |= RX_FLAG_HT; 992466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka if (rate_n_flags & RATE_MCS_HT40_MSK) 993466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka rx_status.flag |= RX_FLAG_40MHZ; 994466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka if (rate_n_flags & RATE_MCS_SGI_MSK) 995466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka rx_status.flag |= RX_FLAG_SHORT_GI; 99653e1116ebd3c0bab4d6daf0da4492f813b778cf8Johannes Berg if (rate_n_flags & RATE_MCS_GF_MSK) 99753e1116ebd3c0bab4d6daf0da4492f813b778cf8Johannes Berg rx_status.flag |= RX_FLAG_HT_GF; 998466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 9993246c4e6addfbf69b23095b69c5484cd76ddb37bWey-Yi Guy iwlagn_pass_packet_to_mac80211(priv, header, len, ampdu_status, 1000466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka rxb, &rx_status); 1001247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach return 0; 1002466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka} 1003466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 100479d3eef89190ee0a7ee585e3949873241bc382e3Johannes Bergstatic int iwlagn_rx_noa_notification(struct iwl_priv *priv, 100548a2d66f58d2bf1818acf5ff7ed9897a9977a96eJohannes Berg struct iwl_rx_cmd_buffer *rxb, 100679d3eef89190ee0a7ee585e3949873241bc382e3Johannes Berg struct iwl_device_cmd *cmd) 100779d3eef89190ee0a7ee585e3949873241bc382e3Johannes Berg{ 100879d3eef89190ee0a7ee585e3949873241bc382e3Johannes Berg struct iwl_wipan_noa_data *new_data, *old_data; 100979d3eef89190ee0a7ee585e3949873241bc382e3Johannes Berg struct iwl_rx_packet *pkt = rxb_addr(rxb); 1010f8d7c1a18d5e77b17b5cc1ebefa21eaea7f2d0faJohannes Berg struct iwl_wipan_noa_notification *noa_notif = (void *)pkt->data; 101179d3eef89190ee0a7ee585e3949873241bc382e3Johannes Berg 101279d3eef89190ee0a7ee585e3949873241bc382e3Johannes Berg /* no condition -- we're in softirq */ 101379d3eef89190ee0a7ee585e3949873241bc382e3Johannes Berg old_data = rcu_dereference_protected(priv->noa_data, true); 101479d3eef89190ee0a7ee585e3949873241bc382e3Johannes Berg 101579d3eef89190ee0a7ee585e3949873241bc382e3Johannes Berg if (noa_notif->noa_active) { 101679d3eef89190ee0a7ee585e3949873241bc382e3Johannes Berg u32 len = le16_to_cpu(noa_notif->noa_attribute.length); 101779d3eef89190ee0a7ee585e3949873241bc382e3Johannes Berg u32 copylen = len; 101879d3eef89190ee0a7ee585e3949873241bc382e3Johannes Berg 101979d3eef89190ee0a7ee585e3949873241bc382e3Johannes Berg /* EID, len, OUI, subtype */ 102079d3eef89190ee0a7ee585e3949873241bc382e3Johannes Berg len += 1 + 1 + 3 + 1; 102179d3eef89190ee0a7ee585e3949873241bc382e3Johannes Berg /* P2P id, P2P length */ 102279d3eef89190ee0a7ee585e3949873241bc382e3Johannes Berg len += 1 + 2; 102379d3eef89190ee0a7ee585e3949873241bc382e3Johannes Berg copylen += 1 + 2; 102479d3eef89190ee0a7ee585e3949873241bc382e3Johannes Berg 102579d3eef89190ee0a7ee585e3949873241bc382e3Johannes Berg new_data = kmalloc(sizeof(*new_data) + len, GFP_ATOMIC); 102679d3eef89190ee0a7ee585e3949873241bc382e3Johannes Berg if (new_data) { 102779d3eef89190ee0a7ee585e3949873241bc382e3Johannes Berg new_data->length = len; 102879d3eef89190ee0a7ee585e3949873241bc382e3Johannes Berg new_data->data[0] = WLAN_EID_VENDOR_SPECIFIC; 102979d3eef89190ee0a7ee585e3949873241bc382e3Johannes Berg new_data->data[1] = len - 2; /* not counting EID, len */ 103079d3eef89190ee0a7ee585e3949873241bc382e3Johannes Berg new_data->data[2] = (WLAN_OUI_WFA >> 16) & 0xff; 103179d3eef89190ee0a7ee585e3949873241bc382e3Johannes Berg new_data->data[3] = (WLAN_OUI_WFA >> 8) & 0xff; 103279d3eef89190ee0a7ee585e3949873241bc382e3Johannes Berg new_data->data[4] = (WLAN_OUI_WFA >> 0) & 0xff; 103379d3eef89190ee0a7ee585e3949873241bc382e3Johannes Berg new_data->data[5] = WLAN_OUI_TYPE_WFA_P2P; 103479d3eef89190ee0a7ee585e3949873241bc382e3Johannes Berg memcpy(&new_data->data[6], &noa_notif->noa_attribute, 103579d3eef89190ee0a7ee585e3949873241bc382e3Johannes Berg copylen); 103679d3eef89190ee0a7ee585e3949873241bc382e3Johannes Berg } 103779d3eef89190ee0a7ee585e3949873241bc382e3Johannes Berg } else 103879d3eef89190ee0a7ee585e3949873241bc382e3Johannes Berg new_data = NULL; 103979d3eef89190ee0a7ee585e3949873241bc382e3Johannes Berg 104079d3eef89190ee0a7ee585e3949873241bc382e3Johannes Berg rcu_assign_pointer(priv->noa_data, new_data); 104179d3eef89190ee0a7ee585e3949873241bc382e3Johannes Berg 104279d3eef89190ee0a7ee585e3949873241bc382e3Johannes Berg if (old_data) 104379d3eef89190ee0a7ee585e3949873241bc382e3Johannes Berg kfree_rcu(old_data, rcu_head); 104479d3eef89190ee0a7ee585e3949873241bc382e3Johannes Berg 104579d3eef89190ee0a7ee585e3949873241bc382e3Johannes Berg return 0; 104679d3eef89190ee0a7ee585e3949873241bc382e3Johannes Berg} 104779d3eef89190ee0a7ee585e3949873241bc382e3Johannes Berg 1048466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka/** 1049466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka * iwl_setup_rx_handlers - Initialize Rx handler callbacks 1050466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka * 1051466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka * Setup the RX handlers for each of the reply types sent from the uCode 1052466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka * to the host. 1053466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka */ 1054466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszkavoid iwl_setup_rx_handlers(struct iwl_priv *priv) 1055466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka{ 105648a2d66f58d2bf1818acf5ff7ed9897a9977a96eJohannes Berg int (**handlers)(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, 1057247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach struct iwl_device_cmd *cmd); 1058466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 1059466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka handlers = priv->rx_handlers; 1060466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 10613246c4e6addfbf69b23095b69c5484cd76ddb37bWey-Yi Guy handlers[REPLY_ERROR] = iwlagn_rx_reply_error; 10623246c4e6addfbf69b23095b69c5484cd76ddb37bWey-Yi Guy handlers[CHANNEL_SWITCH_NOTIFICATION] = iwlagn_rx_csa; 10633246c4e6addfbf69b23095b69c5484cd76ddb37bWey-Yi Guy handlers[SPECTRUM_MEASURE_NOTIFICATION] = 10643246c4e6addfbf69b23095b69c5484cd76ddb37bWey-Yi Guy iwlagn_rx_spectrum_measure_notif; 10653246c4e6addfbf69b23095b69c5484cd76ddb37bWey-Yi Guy handlers[PM_SLEEP_NOTIFICATION] = iwlagn_rx_pm_sleep_notif; 10663246c4e6addfbf69b23095b69c5484cd76ddb37bWey-Yi Guy handlers[PM_DEBUG_STATISTIC_NOTIFIC] = 10673246c4e6addfbf69b23095b69c5484cd76ddb37bWey-Yi Guy iwlagn_rx_pm_debug_statistics_notif; 10683246c4e6addfbf69b23095b69c5484cd76ddb37bWey-Yi Guy handlers[BEACON_NOTIFICATION] = iwlagn_rx_beacon_notif; 1069247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach handlers[REPLY_ADD_STA] = iwl_add_sta_callback; 1070466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 107179d3eef89190ee0a7ee585e3949873241bc382e3Johannes Berg handlers[REPLY_WIPAN_NOA_NOTIFICATION] = iwlagn_rx_noa_notification; 107279d3eef89190ee0a7ee585e3949873241bc382e3Johannes Berg 1073466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka /* 1074466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka * The same handler is used for both the REPLY to a discrete 1075466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka * statistics request from the host as well as for the periodic 1076466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka * statistics notifications (after received beacons) from the uCode. 1077466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka */ 10783246c4e6addfbf69b23095b69c5484cd76ddb37bWey-Yi Guy handlers[REPLY_STATISTICS_CMD] = iwlagn_rx_reply_statistics; 10793246c4e6addfbf69b23095b69c5484cd76ddb37bWey-Yi Guy handlers[STATISTICS_NOTIFICATION] = iwlagn_rx_statistics; 1080466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 1081466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka iwl_setup_rx_scan_handlers(priv); 1082466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 10833246c4e6addfbf69b23095b69c5484cd76ddb37bWey-Yi Guy handlers[CARD_STATE_NOTIFICATION] = iwlagn_rx_card_state_notif; 10843246c4e6addfbf69b23095b69c5484cd76ddb37bWey-Yi Guy handlers[MISSED_BEACONS_NOTIFICATION] = 10853246c4e6addfbf69b23095b69c5484cd76ddb37bWey-Yi Guy iwlagn_rx_missed_beacon_notif; 1086466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 1087466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka /* Rx handlers */ 10883246c4e6addfbf69b23095b69c5484cd76ddb37bWey-Yi Guy handlers[REPLY_RX_PHY_CMD] = iwlagn_rx_reply_rx_phy; 10893246c4e6addfbf69b23095b69c5484cd76ddb37bWey-Yi Guy handlers[REPLY_RX_MPDU_CMD] = iwlagn_rx_reply_rx; 1090466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 1091466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka /* block ack */ 10923246c4e6addfbf69b23095b69c5484cd76ddb37bWey-Yi Guy handlers[REPLY_COMPRESSED_BA] = 10933246c4e6addfbf69b23095b69c5484cd76ddb37bWey-Yi Guy iwlagn_rx_reply_compressed_ba; 1094466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka 10958d30119346d52516f289016e1c57f853a835cb4aEmmanuel Grumbach priv->rx_handlers[REPLY_TX] = iwlagn_rx_reply_tx; 10968d30119346d52516f289016e1c57f853a835cb4aEmmanuel Grumbach 10978d30119346d52516f289016e1c57f853a835cb4aEmmanuel Grumbach /* set up notification wait support */ 10984bd14dd5f77bbe3c51f50f4e86d3b8960e6a518cJohannes Berg iwl_notification_wait_init(&priv->notif_wait); 10998d30119346d52516f289016e1c57f853a835cb4aEmmanuel Grumbach 11008d30119346d52516f289016e1c57f853a835cb4aEmmanuel Grumbach /* Set up BT Rx handlers */ 11010d8877a10d65f3c9bb84ad150e524d95ebd377fbJohannes Berg if (priv->lib->bt_params) 1102562f08eb8020cf3672c3743752f82d962ecb7788Johannes Berg iwlagn_bt_rx_handler_setup(priv); 1103466a19a003f3b45a755bc85f967c21da947f9a00Stanislaw Gruszka} 11041ab9f6c11b003d086ae4890ea202cc3c66f5a17aEmmanuel Grumbach 110548a2d66f58d2bf1818acf5ff7ed9897a9977a96eJohannes Bergint iwl_rx_dispatch(struct iwl_op_mode *op_mode, struct iwl_rx_cmd_buffer *rxb, 110648a2d66f58d2bf1818acf5ff7ed9897a9977a96eJohannes Berg struct iwl_device_cmd *cmd) 11071ab9f6c11b003d086ae4890ea202cc3c66f5a17aEmmanuel Grumbach{ 11081ab9f6c11b003d086ae4890ea202cc3c66f5a17aEmmanuel Grumbach struct iwl_rx_packet *pkt = rxb_addr(rxb); 1109db70f290e1a88f11815e50acd8ac1c36f89b0da2Emmanuel Grumbach struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode); 1110247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach int err = 0; 11111ab9f6c11b003d086ae4890ea202cc3c66f5a17aEmmanuel Grumbach 11121ab9f6c11b003d086ae4890ea202cc3c66f5a17aEmmanuel Grumbach /* 11131ab9f6c11b003d086ae4890ea202cc3c66f5a17aEmmanuel Grumbach * Do the notification wait before RX handlers so 11141ab9f6c11b003d086ae4890ea202cc3c66f5a17aEmmanuel Grumbach * even if the RX handler consumes the RXB we have 11151ab9f6c11b003d086ae4890ea202cc3c66f5a17aEmmanuel Grumbach * access to it in the notification wait entry. 11161ab9f6c11b003d086ae4890ea202cc3c66f5a17aEmmanuel Grumbach */ 11174bd14dd5f77bbe3c51f50f4e86d3b8960e6a518cJohannes Berg iwl_notification_wait_notify(&priv->notif_wait, pkt); 11181ab9f6c11b003d086ae4890ea202cc3c66f5a17aEmmanuel Grumbach 111949464ae502680e362be519ac024a0f5998faaa7eJohannes Berg /* Based on type of command response or notification, 112049464ae502680e362be519ac024a0f5998faaa7eJohannes Berg * handle those that need handling via function in 112149464ae502680e362be519ac024a0f5998faaa7eJohannes Berg * rx_handlers table. See iwl_setup_rx_handlers() */ 112249464ae502680e362be519ac024a0f5998faaa7eJohannes Berg if (priv->rx_handlers[pkt->hdr.cmd]) { 112349464ae502680e362be519ac024a0f5998faaa7eJohannes Berg priv->rx_handlers_stats[pkt->hdr.cmd]++; 112449464ae502680e362be519ac024a0f5998faaa7eJohannes Berg err = priv->rx_handlers[pkt->hdr.cmd] (priv, rxb, cmd); 112549464ae502680e362be519ac024a0f5998faaa7eJohannes Berg } else { 112649464ae502680e362be519ac024a0f5998faaa7eJohannes Berg /* No handling needed */ 112749464ae502680e362be519ac024a0f5998faaa7eJohannes Berg IWL_DEBUG_RX(priv, "No handler needed for %s, 0x%02x\n", 112849464ae502680e362be519ac024a0f5998faaa7eJohannes Berg iwl_dvm_get_cmd_string(pkt->hdr.cmd), 112949464ae502680e362be519ac024a0f5998faaa7eJohannes Berg pkt->hdr.cmd); 11301ab9f6c11b003d086ae4890ea202cc3c66f5a17aEmmanuel Grumbach } 1131247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach return err; 11321ab9f6c11b003d086ae4890ea202cc3c66f5a17aEmmanuel Grumbach} 1133