[go: nahoru, domu]

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