iwl-4965-rx.c 6.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
/******************************************************************************
 *
 * GPL LICENSE SUMMARY
 *
 * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of version 2 of the GNU General Public License as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
 * USA
 *
 * The full GNU General Public License is included in this distribution
 * in the file called LICENSE.GPL.
 *
 * Contact Information:
 *  Intel Linux Wireless <ilw@linux.intel.com>
 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 *
 *****************************************************************************/

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched.h>

#include "iwl-dev.h"
#include "iwl-core.h"
#include "iwl-4965-calib.h"
#include "iwl-sta.h"
#include "iwl-io.h"
#include "iwl-helpers.h"
#include "iwl-4965-hw.h"
#include "iwl-4965.h"

S
Stanislaw Gruszka 已提交
44
void il4965_rx_missed_beacon_notif(struct il_priv *il,
S
Stanislaw Gruszka 已提交
45
				struct il_rx_mem_buffer *rxb)
46 47

{
48
	struct il_rx_pkt *pkt = rxb_addr(rxb);
S
Stanislaw Gruszka 已提交
49
	struct il_missed_beacon_notif *missed_beacon;
50 51 52

	missed_beacon = &pkt->u.missed_beacon;
	if (le32_to_cpu(missed_beacon->consecutive_missed_beacons) >
S
Stanislaw Gruszka 已提交
53
	    il->missed_beacon_threshold) {
54
		D_CALIB(
55 56 57 58 59
		    "missed bcn cnsq %d totl %d rcd %d expctd %d\n",
		    le32_to_cpu(missed_beacon->consecutive_missed_beacons),
		    le32_to_cpu(missed_beacon->total_missed_becons),
		    le32_to_cpu(missed_beacon->num_recvd_beacons),
		    le32_to_cpu(missed_beacon->num_expected_beacons));
S
Stanislaw Gruszka 已提交
60 61
		if (!test_bit(STATUS_SCANNING, &il->status))
			il4965_init_sensitivity(il);
62 63 64 65 66 67
	}
}

/* Calculate noise level, based on measurements during network silence just
 *   before arriving beacon.  This measurement can be done only if we know
 *   exactly when to expect beacons, therefore only when we're associated. */
S
Stanislaw Gruszka 已提交
68
static void il4965_rx_calc_noise(struct il_priv *il)
69 70 71 72 73 74 75
{
	struct statistics_rx_non_phy *rx_info;
	int num_active_rx = 0;
	int total_silence = 0;
	int bcn_silence_a, bcn_silence_b, bcn_silence_c;
	int last_rx_noise;

S
Stanislaw Gruszka 已提交
76
	rx_info = &(il->_4965.statistics.rx.general);
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
	bcn_silence_a =
		le32_to_cpu(rx_info->beacon_silence_rssi_a) & IN_BAND_FILTER;
	bcn_silence_b =
		le32_to_cpu(rx_info->beacon_silence_rssi_b) & IN_BAND_FILTER;
	bcn_silence_c =
		le32_to_cpu(rx_info->beacon_silence_rssi_c) & IN_BAND_FILTER;

	if (bcn_silence_a) {
		total_silence += bcn_silence_a;
		num_active_rx++;
	}
	if (bcn_silence_b) {
		total_silence += bcn_silence_b;
		num_active_rx++;
	}
	if (bcn_silence_c) {
		total_silence += bcn_silence_c;
		num_active_rx++;
	}

	/* Average among active antennas */
	if (num_active_rx)
		last_rx_noise = (total_silence / num_active_rx) - 107;
	else
S
Stanislaw Gruszka 已提交
101
		last_rx_noise = IL_NOISE_MEAS_NOT_AVAILABLE;
102

103
	D_CALIB("inband silence a %u, b %u, c %u, dBm %d\n",
104 105 106 107
			bcn_silence_a, bcn_silence_b, bcn_silence_c,
			last_rx_noise);
}

108
#ifdef CONFIG_IWLEGACY_DEBUGFS
109 110 111 112 113
/*
 *  based on the assumption of all statistics counter are in DWORD
 *  FIXME: This function is for debugging, do not deal with
 *  the case of counters roll-over.
 */
S
Stanislaw Gruszka 已提交
114
static void il4965_accumulative_statistics(struct il_priv *il,
115 116 117 118 119 120 121 122 123
					__le32 *stats)
{
	int i, size;
	__le32 *prev_stats;
	u32 *accum_stats;
	u32 *delta, *max_delta;
	struct statistics_general_common *general, *accum_general;
	struct statistics_tx *tx, *accum_tx;

S
Stanislaw Gruszka 已提交
124 125
	prev_stats = (__le32 *)&il->_4965.statistics;
	accum_stats = (u32 *)&il->_4965.accum_statistics;
S
Stanislaw Gruszka 已提交
126
	size = sizeof(struct il_notif_statistics);
S
Stanislaw Gruszka 已提交
127 128 129 130 131 132
	general = &il->_4965.statistics.general.common;
	accum_general = &il->_4965.accum_statistics.general.common;
	tx = &il->_4965.statistics.tx;
	accum_tx = &il->_4965.accum_statistics.tx;
	delta = (u32 *)&il->_4965.delta_statistics;
	max_delta = (u32 *)&il->_4965.max_delta;
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153

	for (i = sizeof(__le32); i < size;
	     i += sizeof(__le32), stats++, prev_stats++, delta++,
	     max_delta++, accum_stats++) {
		if (le32_to_cpu(*stats) > le32_to_cpu(*prev_stats)) {
			*delta = (le32_to_cpu(*stats) -
				le32_to_cpu(*prev_stats));
			*accum_stats += *delta;
			if (*delta > *max_delta)
				*max_delta = *delta;
		}
	}

	/* reset accumulative statistics for "no-counter" type statistics */
	accum_general->temperature = general->temperature;
	accum_general->ttl_timestamp = general->ttl_timestamp;
}
#endif

#define REG_RECALIB_PERIOD (60)

S
Stanislaw Gruszka 已提交
154
void il4965_rx_statistics(struct il_priv *il,
S
Stanislaw Gruszka 已提交
155
			      struct il_rx_mem_buffer *rxb)
156 157
{
	int change;
158
	struct il_rx_pkt *pkt = rxb_addr(rxb);
159

160
	D_RX(
161
		     "Statistics notification received (%d vs %d).\n",
S
Stanislaw Gruszka 已提交
162
		     (int)sizeof(struct il_notif_statistics),
163 164 165
		     le32_to_cpu(pkt->len_n_flags) &
		     FH_RSCSR_FRAME_SIZE_MSK);

S
Stanislaw Gruszka 已提交
166
	change = ((il->_4965.statistics.general.common.temperature !=
167
		   pkt->u.stats.general.common.temperature) ||
S
Stanislaw Gruszka 已提交
168
		   ((il->_4965.statistics.flag &
169 170 171
		   STATISTICS_REPLY_FLG_HT40_MODE_MSK) !=
		   (pkt->u.stats.flag &
		   STATISTICS_REPLY_FLG_HT40_MODE_MSK)));
172
#ifdef CONFIG_IWLEGACY_DEBUGFS
S
Stanislaw Gruszka 已提交
173
	il4965_accumulative_statistics(il, (__le32 *)&pkt->u.stats);
174 175
#endif

176
	/* TODO: reading some of statistics is unneeded */
S
Stanislaw Gruszka 已提交
177 178
	memcpy(&il->_4965.statistics, &pkt->u.stats,
		sizeof(il->_4965.statistics));
179

S
Stanislaw Gruszka 已提交
180
	set_bit(STATUS_STATISTICS, &il->status);
181 182 183 184 185

	/* Reschedule the statistics timer to occur in
	 * REG_RECALIB_PERIOD seconds to ensure we get a
	 * thermal update even if the uCode doesn't give
	 * us one */
S
Stanislaw Gruszka 已提交
186
	mod_timer(&il->statistics_periodic, jiffies +
187 188
		  msecs_to_jiffies(REG_RECALIB_PERIOD * 1000));

S
Stanislaw Gruszka 已提交
189
	if (unlikely(!test_bit(STATUS_SCANNING, &il->status)) &&
190
	    (pkt->hdr.cmd == STATISTICS_NOTIFICATION)) {
S
Stanislaw Gruszka 已提交
191 192
		il4965_rx_calc_noise(il);
		queue_work(il->workqueue, &il->run_time_calib_work);
193
	}
S
Stanislaw Gruszka 已提交
194 195
	if (il->cfg->ops->lib->temp_ops.temperature && change)
		il->cfg->ops->lib->temp_ops.temperature(il);
196 197
}

S
Stanislaw Gruszka 已提交
198
void il4965_reply_statistics(struct il_priv *il,
S
Stanislaw Gruszka 已提交
199
			      struct il_rx_mem_buffer *rxb)
200
{
201
	struct il_rx_pkt *pkt = rxb_addr(rxb);
202 203

	if (le32_to_cpu(pkt->u.stats.flag) & UCODE_STATISTICS_CLEAR_MSK) {
204
#ifdef CONFIG_IWLEGACY_DEBUGFS
S
Stanislaw Gruszka 已提交
205
		memset(&il->_4965.accum_statistics, 0,
S
Stanislaw Gruszka 已提交
206
			sizeof(struct il_notif_statistics));
S
Stanislaw Gruszka 已提交
207
		memset(&il->_4965.delta_statistics, 0,
S
Stanislaw Gruszka 已提交
208
			sizeof(struct il_notif_statistics));
S
Stanislaw Gruszka 已提交
209
		memset(&il->_4965.max_delta, 0,
S
Stanislaw Gruszka 已提交
210
			sizeof(struct il_notif_statistics));
211
#endif
212
		D_RX("Statistics have been cleared\n");
213
	}
S
Stanislaw Gruszka 已提交
214
	il4965_rx_statistics(il, rxb);
215
}