iwl-3945.c 76.9 KB
Newer Older
1 2
/******************************************************************************
 *
3
 * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved.
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
 *
 * 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.
 *
 * Contact Information:
 * James P. Ketrenos <ipw2100-admin@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/version.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/dma-mapping.h>
#include <linux/delay.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/wireless.h>
#include <linux/firmware.h>
#include <linux/etherdevice.h>
Zhu Yi's avatar
Zhu Yi committed
39 40
#include <asm/unaligned.h>
#include <net/mac80211.h>
41

Tomas Winkler's avatar
Tomas Winkler committed
42
#include "iwl-3945-core.h"
43
#include "iwl-3945.h"
44
#include "iwl-helpers.h"
45 46 47 48 49 50 51 52 53 54
#include "iwl-3945-rs.h"

#define IWL_DECLARE_RATE_INFO(r, ip, in, rp, rn, pp, np)    \
	[IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP,   \
				    IWL_RATE_##r##M_IEEE,   \
				    IWL_RATE_##ip##M_INDEX, \
				    IWL_RATE_##in##M_INDEX, \
				    IWL_RATE_##rp##M_INDEX, \
				    IWL_RATE_##rn##M_INDEX, \
				    IWL_RATE_##pp##M_INDEX, \
55 56 57
				    IWL_RATE_##np##M_INDEX, \
				    IWL_RATE_##r##M_INDEX_TABLE, \
				    IWL_RATE_##ip##M_INDEX_TABLE }
58 59 60 61 62 63 64 65 66

/*
 * Parameter order:
 *   rate, prev rate, next rate, prev tgg rate, next tgg rate
 *
 * If there isn't a valid next or previous rate then INV is used which
 * maps to IWL_RATE_INVALID
 *
 */
Christoph Hellwig's avatar
Christoph Hellwig committed
67
const struct iwl3945_rate_info iwl3945_rates[IWL_RATE_COUNT] = {
68 69 70 71
	IWL_DECLARE_RATE_INFO(1, INV, 2, INV, 2, INV, 2),    /*  1mbps */
	IWL_DECLARE_RATE_INFO(2, 1, 5, 1, 5, 1, 5),          /*  2mbps */
	IWL_DECLARE_RATE_INFO(5, 2, 6, 2, 11, 2, 11),        /*5.5mbps */
	IWL_DECLARE_RATE_INFO(11, 9, 12, 5, 12, 5, 18),      /* 11mbps */
72 73 74 75 76 77 78 79 80 81
	IWL_DECLARE_RATE_INFO(6, 5, 9, 5, 11, 5, 11),        /*  6mbps */
	IWL_DECLARE_RATE_INFO(9, 6, 11, 5, 11, 5, 11),       /*  9mbps */
	IWL_DECLARE_RATE_INFO(12, 11, 18, 11, 18, 11, 18),   /* 12mbps */
	IWL_DECLARE_RATE_INFO(18, 12, 24, 12, 24, 11, 24),   /* 18mbps */
	IWL_DECLARE_RATE_INFO(24, 18, 36, 18, 36, 18, 36),   /* 24mbps */
	IWL_DECLARE_RATE_INFO(36, 24, 48, 24, 48, 24, 48),   /* 36mbps */
	IWL_DECLARE_RATE_INFO(48, 36, 54, 36, 54, 36, 54),   /* 48mbps */
	IWL_DECLARE_RATE_INFO(54, 48, INV, 48, INV, 48, INV),/* 54mbps */
};

Christoph Hellwig's avatar
Christoph Hellwig committed
82
/* 1 = enable the iwl3945_disable_events() function */
83 84 85 86
#define IWL_EVT_DISABLE (0)
#define IWL_EVT_DISABLE_SIZE (1532/32)

/**
Christoph Hellwig's avatar
Christoph Hellwig committed
87
 * iwl3945_disable_events - Disable selected events in uCode event log
88 89 90 91 92 93 94
 *
 * Disable an event by writing "1"s into "disable"
 *   bitmap in SRAM.  Bit position corresponds to Event # (id/type).
 *   Default values of 0 enable uCode events to be logged.
 * Use for only special debugging.  This function is just a placeholder as-is,
 *   you'll need to provide the special bits! ...
 *   ... and set IWL_EVT_DISABLE to 1. */
Christoph Hellwig's avatar
Christoph Hellwig committed
95
void iwl3945_disable_events(struct iwl3945_priv *priv)
96
{
97
	int ret;
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
	int i;
	u32 base;		/* SRAM address of event log header */
	u32 disable_ptr;	/* SRAM address of event-disable bitmap array */
	u32 array_size;		/* # of u32 entries in array */
	u32 evt_disable[IWL_EVT_DISABLE_SIZE] = {
		0x00000000,	/*   31 -    0  Event id numbers */
		0x00000000,	/*   63 -   32 */
		0x00000000,	/*   95 -   64 */
		0x00000000,	/*  127 -   96 */
		0x00000000,	/*  159 -  128 */
		0x00000000,	/*  191 -  160 */
		0x00000000,	/*  223 -  192 */
		0x00000000,	/*  255 -  224 */
		0x00000000,	/*  287 -  256 */
		0x00000000,	/*  319 -  288 */
		0x00000000,	/*  351 -  320 */
		0x00000000,	/*  383 -  352 */
		0x00000000,	/*  415 -  384 */
		0x00000000,	/*  447 -  416 */
		0x00000000,	/*  479 -  448 */
		0x00000000,	/*  511 -  480 */
		0x00000000,	/*  543 -  512 */
		0x00000000,	/*  575 -  544 */
		0x00000000,	/*  607 -  576 */
		0x00000000,	/*  639 -  608 */
		0x00000000,	/*  671 -  640 */
		0x00000000,	/*  703 -  672 */
		0x00000000,	/*  735 -  704 */
		0x00000000,	/*  767 -  736 */
		0x00000000,	/*  799 -  768 */
		0x00000000,	/*  831 -  800 */
		0x00000000,	/*  863 -  832 */
		0x00000000,	/*  895 -  864 */
		0x00000000,	/*  927 -  896 */
		0x00000000,	/*  959 -  928 */
		0x00000000,	/*  991 -  960 */
		0x00000000,	/* 1023 -  992 */
		0x00000000,	/* 1055 - 1024 */
		0x00000000,	/* 1087 - 1056 */
		0x00000000,	/* 1119 - 1088 */
		0x00000000,	/* 1151 - 1120 */
		0x00000000,	/* 1183 - 1152 */
		0x00000000,	/* 1215 - 1184 */
		0x00000000,	/* 1247 - 1216 */
		0x00000000,	/* 1279 - 1248 */
		0x00000000,	/* 1311 - 1280 */
		0x00000000,	/* 1343 - 1312 */
		0x00000000,	/* 1375 - 1344 */
		0x00000000,	/* 1407 - 1376 */
		0x00000000,	/* 1439 - 1408 */
		0x00000000,	/* 1471 - 1440 */
		0x00000000,	/* 1503 - 1472 */
	};

	base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
Christoph Hellwig's avatar
Christoph Hellwig committed
153
	if (!iwl3945_hw_valid_rtc_data_addr(base)) {
154 155 156 157
		IWL_ERROR("Invalid event log pointer 0x%08X\n", base);
		return;
	}

Christoph Hellwig's avatar
Christoph Hellwig committed
158
	ret = iwl3945_grab_nic_access(priv);
159
	if (ret) {
160 161 162 163
		IWL_WARNING("Can not read from adapter at this time.\n");
		return;
	}

Christoph Hellwig's avatar
Christoph Hellwig committed
164 165 166
	disable_ptr = iwl3945_read_targ_mem(priv, base + (4 * sizeof(u32)));
	array_size = iwl3945_read_targ_mem(priv, base + (5 * sizeof(u32)));
	iwl3945_release_nic_access(priv);
167 168 169 170

	if (IWL_EVT_DISABLE && (array_size == IWL_EVT_DISABLE_SIZE)) {
		IWL_DEBUG_INFO("Disabling selected uCode log events at 0x%x\n",
			       disable_ptr);
Christoph Hellwig's avatar
Christoph Hellwig committed
171
		ret = iwl3945_grab_nic_access(priv);
172
		for (i = 0; i < IWL_EVT_DISABLE_SIZE; i++)
Christoph Hellwig's avatar
Christoph Hellwig committed
173
			iwl3945_write_targ_mem(priv,
174 175
					   disable_ptr + (i * sizeof(u32)),
					   evt_disable[i]);
176

Christoph Hellwig's avatar
Christoph Hellwig committed
177
		iwl3945_release_nic_access(priv);
178 179 180 181 182 183 184 185 186
	} else {
		IWL_DEBUG_INFO("Selected uCode log events may be disabled\n");
		IWL_DEBUG_INFO("  by writing \"1\"s into disable bitmap\n");
		IWL_DEBUG_INFO("  in SRAM at 0x%x, size %d u32s\n",
			       disable_ptr, array_size);
	}

}

187 188 189 190 191 192 193 194 195 196
static int iwl3945_hwrate_to_plcp_idx(u8 plcp)
{
	int idx;

	for (idx = 0; idx < IWL_RATE_COUNT; idx++)
		if (iwl3945_rates[idx].plcp == plcp)
			return idx;
	return -1;
}

197 198 199 200 201 202 203 204 205 206 207
/**
 * iwl3945_get_antenna_flags - Get antenna flags for RXON command
 * @priv: eeprom and antenna fields are used to determine antenna flags
 *
 * priv->eeprom  is used to determine if antenna AUX/MAIN are reversed
 * priv->antenna specifies the antenna diversity mode:
 *
 * IWL_ANTENNA_DIVERISTY - NIC selects best antenna by itself
 * IWL_ANTENNA_MAIN      - Force MAIN antenna
 * IWL_ANTENNA_AUX       - Force AUX antenna
 */
Christoph Hellwig's avatar
Christoph Hellwig committed
208
__le32 iwl3945_get_antenna_flags(const struct iwl3945_priv *priv)
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
{
	switch (priv->antenna) {
	case IWL_ANTENNA_DIVERSITY:
		return 0;

	case IWL_ANTENNA_MAIN:
		if (priv->eeprom.antenna_switch_type)
			return RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_B_MSK;
		return RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_A_MSK;

	case IWL_ANTENNA_AUX:
		if (priv->eeprom.antenna_switch_type)
			return RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_A_MSK;
		return RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_B_MSK;
	}

	/* bad antenna selector value */
	IWL_ERROR("Bad antenna selector value (0x%x)\n", priv->antenna);
	return 0;		/* "diversity" is default if error */
}

230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285
#ifdef CONFIG_IWL3945_DEBUG
#define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x

static const char *iwl3945_get_tx_fail_reason(u32 status)
{
	switch (status & TX_STATUS_MSK) {
	case TX_STATUS_SUCCESS:
		return "SUCCESS";
		TX_STATUS_ENTRY(SHORT_LIMIT);
		TX_STATUS_ENTRY(LONG_LIMIT);
		TX_STATUS_ENTRY(FIFO_UNDERRUN);
		TX_STATUS_ENTRY(MGMNT_ABORT);
		TX_STATUS_ENTRY(NEXT_FRAG);
		TX_STATUS_ENTRY(LIFE_EXPIRE);
		TX_STATUS_ENTRY(DEST_PS);
		TX_STATUS_ENTRY(ABORTED);
		TX_STATUS_ENTRY(BT_RETRY);
		TX_STATUS_ENTRY(STA_INVALID);
		TX_STATUS_ENTRY(FRAG_DROPPED);
		TX_STATUS_ENTRY(TID_DISABLE);
		TX_STATUS_ENTRY(FRAME_FLUSHED);
		TX_STATUS_ENTRY(INSUFFICIENT_CF_POLL);
		TX_STATUS_ENTRY(TX_LOCKED);
		TX_STATUS_ENTRY(NO_BEACON_ON_RADAR);
	}

	return "UNKNOWN";
}
#else
static inline const char *iwl3945_get_tx_fail_reason(u32 status)
{
	return "";
}
#endif


/**
 * iwl3945_tx_queue_reclaim - Reclaim Tx queue entries already Tx'd
 *
 * When FW advances 'R' index, all entries between old and new 'R' index
 * need to be reclaimed. As result, some free space forms. If there is
 * enough free space (> low mark), wake the stack that feeds us.
 */
static void iwl3945_tx_queue_reclaim(struct iwl3945_priv *priv,
				     int txq_id, int index)
{
	struct iwl3945_tx_queue *txq = &priv->txq[txq_id];
	struct iwl3945_queue *q = &txq->q;
	struct iwl3945_tx_info *tx_info;

	BUG_ON(txq_id == IWL_CMD_QUEUE_NUM);

	for (index = iwl_queue_inc_wrap(index, q->n_bd); q->read_ptr != index;
		q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {

		tx_info = &txq->txb[txq->q.read_ptr];
286
		ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb[0]);
287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307
		tx_info->skb[0] = NULL;
		iwl3945_hw_txq_free_tfd(priv, txq);
	}

	if (iwl3945_queue_space(q) > q->low_mark && (txq_id >= 0) &&
			(txq_id != IWL_CMD_QUEUE_NUM) &&
			priv->mac80211_registered)
		ieee80211_wake_queue(priv->hw, txq_id);
}

/**
 * iwl3945_rx_reply_tx - Handle Tx response
 */
static void iwl3945_rx_reply_tx(struct iwl3945_priv *priv,
			    struct iwl3945_rx_mem_buffer *rxb)
{
	struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data;
	u16 sequence = le16_to_cpu(pkt->hdr.sequence);
	int txq_id = SEQ_TO_QUEUE(sequence);
	int index = SEQ_TO_INDEX(sequence);
	struct iwl3945_tx_queue *txq = &priv->txq[txq_id];
308
	struct ieee80211_tx_info *info;
309 310 311 312 313 314 315 316 317 318 319 320
	struct iwl3945_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
	u32  status = le32_to_cpu(tx_resp->status);
	int rate_idx;

	if ((index >= txq->q.n_bd) || (iwl3945_x2_queue_used(&txq->q, index) == 0)) {
		IWL_ERROR("Read index for DMA queue txq_id (%d) index %d "
			  "is out of range [0-%d] %d %d\n", txq_id,
			  index, txq->q.n_bd, txq->q.write_ptr,
			  txq->q.read_ptr);
		return;
	}

321 322
	info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]);
	memset(&info->status, 0, sizeof(info->status));
323

324
	info->status.retry_count = tx_resp->failure_frame;
325
	/* tx_status->rts_retry_count = tx_resp->failure_rts; */
326 327
	info->flags |= ((status & TX_STATUS_MSK) == TX_STATUS_SUCCESS) ?
				IEEE80211_TX_STAT_ACK : 0;
328 329 330 331 332 333

	IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) plcp rate %d retries %d\n",
			txq_id, iwl3945_get_tx_fail_reason(status), status,
			tx_resp->rate, tx_resp->failure_frame);

	rate_idx = iwl3945_hwrate_to_plcp_idx(tx_resp->rate);
334
	if (info->band == IEEE80211_BAND_5GHZ)
335
		rate_idx -= IWL_FIRST_OFDM_RATE;
336
	info->tx_rate_idx = rate_idx;
337 338 339 340 341 342 343 344 345
	IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index);
	iwl3945_tx_queue_reclaim(priv, txq_id, index);

	if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK))
		IWL_ERROR("TODO:  Implement Tx ABORT REQUIRED!!!\n");
}



346 347 348 349 350 351 352 353
/*****************************************************************************
 *
 * Intel PRO/Wireless 3945ABG/BG Network Connection
 *
 *  RX handler implementations
 *
 *****************************************************************************/

Christoph Hellwig's avatar
Christoph Hellwig committed
354
void iwl3945_hw_rx_statistics(struct iwl3945_priv *priv, struct iwl3945_rx_mem_buffer *rxb)
355
{
Christoph Hellwig's avatar
Christoph Hellwig committed
356
	struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data;
357
	IWL_DEBUG_RX("Statistics notification received (%d vs %d).\n",
Christoph Hellwig's avatar
Christoph Hellwig committed
358
		     (int)sizeof(struct iwl3945_notif_statistics),
359 360 361 362
		     le32_to_cpu(pkt->len));

	memcpy(&priv->statistics, pkt->u.raw, sizeof(priv->statistics));

Mohamed Abbas's avatar
Mohamed Abbas committed
363 364
	iwl3945_led_background(priv);

365 366 367
	priv->last_statistics_time = jiffies;
}

368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390
/******************************************************************************
 *
 * Misc. internal state and helper functions
 *
 ******************************************************************************/
#ifdef CONFIG_IWL3945_DEBUG

/**
 * iwl3945_report_frame - dump frame to syslog during debug sessions
 *
 * You may hack this function to show different aspects of received frames,
 * including selective frame dumps.
 * group100 parameter selects whether to show 1 out of 100 good frames.
 */
static void iwl3945_dbg_report_frame(struct iwl3945_priv *priv,
		      struct iwl3945_rx_packet *pkt,
		      struct ieee80211_hdr *header, int group100)
{
	u32 to_us;
	u32 print_summary = 0;
	u32 print_dump = 0;	/* set to 1 to dump all frames' contents */
	u32 hundred = 0;
	u32 dataframe = 0;
391
	__le16 fc;
392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409
	u16 seq_ctl;
	u16 channel;
	u16 phy_flags;
	u16 length;
	u16 status;
	u16 bcn_tmr;
	u32 tsf_low;
	u64 tsf;
	u8 rssi;
	u8 agc;
	u16 sig_avg;
	u16 noise_diff;
	struct iwl3945_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt);
	struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
	struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt);
	u8 *data = IWL_RX_DATA(pkt);

	/* MAC header */
410
	fc = header->frame_control;
411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433
	seq_ctl = le16_to_cpu(header->seq_ctrl);

	/* metadata */
	channel = le16_to_cpu(rx_hdr->channel);
	phy_flags = le16_to_cpu(rx_hdr->phy_flags);
	length = le16_to_cpu(rx_hdr->len);

	/* end-of-frame status and timestamp */
	status = le32_to_cpu(rx_end->status);
	bcn_tmr = le32_to_cpu(rx_end->beacon_timestamp);
	tsf_low = le64_to_cpu(rx_end->timestamp) & 0x0ffffffff;
	tsf = le64_to_cpu(rx_end->timestamp);

	/* signal statistics */
	rssi = rx_stats->rssi;
	agc = rx_stats->agc;
	sig_avg = le16_to_cpu(rx_stats->sig_avg);
	noise_diff = le16_to_cpu(rx_stats->noise_diff);

	to_us = !compare_ether_addr(header->addr1, priv->mac_addr);

	/* if data frame is to us and all is good,
	 *   (optionally) print summary for only 1 out of every 100 */
434 435
	if (to_us && (fc & ~cpu_to_le16(IEEE80211_FCTL_PROTECTED)) ==
	    cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FTYPE_DATA)) {
436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453
		dataframe = 1;
		if (!group100)
			print_summary = 1;	/* print each frame */
		else if (priv->framecnt_to_us < 100) {
			priv->framecnt_to_us++;
			print_summary = 0;
		} else {
			priv->framecnt_to_us = 0;
			print_summary = 1;
			hundred = 1;
		}
	} else {
		/* print summary for all other frames */
		print_summary = 1;
	}

	if (print_summary) {
		char *title;
454
		int rate;
455 456 457

		if (hundred)
			title = "100Frames";
458
		else if (ieee80211_has_retry(fc))
459
			title = "Retry";
460
		else if (ieee80211_is_assoc_resp(fc))
461
			title = "AscRsp";
462
		else if (ieee80211_is_reassoc_resp(fc))
463
			title = "RasRsp";
464
		else if (ieee80211_is_probe_resp(fc)) {
465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491
			title = "PrbRsp";
			print_dump = 1;	/* dump frame contents */
		} else if (ieee80211_is_beacon(fc)) {
			title = "Beacon";
			print_dump = 1;	/* dump frame contents */
		} else if (ieee80211_is_atim(fc))
			title = "ATIM";
		else if (ieee80211_is_auth(fc))
			title = "Auth";
		else if (ieee80211_is_deauth(fc))
			title = "DeAuth";
		else if (ieee80211_is_disassoc(fc))
			title = "DisAssoc";
		else
			title = "Frame";

		rate = iwl3945_hwrate_to_plcp_idx(rx_hdr->rate);
		if (rate == -1)
			rate = 0;
		else
			rate = iwl3945_rates[rate].ieee / 2;

		/* print frame summary.
		 * MAC addresses show just the last byte (for brevity),
		 *    but you can hack it to show more, if you'd like to. */
		if (dataframe)
			IWL_DEBUG_RX("%s: mhd=0x%04x, dst=0x%02x, "
492
				     "len=%u, rssi=%d, chnl=%d, rate=%d, \n",
493
				     title, le16_to_cpu(fc), header->addr1[5],
494 495 496 497 498 499
				     length, rssi, channel, rate);
		else {
			/* src/dst addresses assume managed mode */
			IWL_DEBUG_RX("%s: 0x%04x, dst=0x%02x, "
				     "src=0x%02x, rssi=%u, tim=%lu usec, "
				     "phy=0x%02x, chnl=%d\n",
500
				     title, le16_to_cpu(fc), header->addr1[5],
501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517
				     header->addr3[5], rssi,
				     tsf_low - priv->scan_start_tsf,
				     phy_flags, channel);
		}
	}
	if (print_dump)
		iwl3945_print_hex_dump(IWL_DL_RX, data, length);
}
#else
static inline void iwl3945_dbg_report_frame(struct iwl3945_priv *priv,
		      struct iwl3945_rx_packet *pkt,
		      struct ieee80211_hdr *header, int group100)
{
}
#endif


518 519 520 521
static void iwl3945_add_radiotap(struct iwl3945_priv *priv,
				 struct sk_buff *skb,
				 struct iwl3945_rx_frame_hdr *rx_hdr,
				 struct ieee80211_rx_status *stats)
Zhu Yi's avatar
Zhu Yi committed
522 523 524
{
	/* First cache any information we need before we overwrite
	 * the information provided in the skb from the hardware */
525
	s8 signal = stats->signal;
Zhu Yi's avatar
Zhu Yi committed
526
	s8 noise = 0;
527
	int rate = stats->rate_idx;
Zhu Yi's avatar
Zhu Yi committed
528
	u64 tsf = stats->mactime;
Johannes Berg's avatar
Johannes Berg committed
529
	__le16 phy_flags_hw = rx_hdr->phy_flags, antenna;
Zhu Yi's avatar
Zhu Yi committed
530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545

	struct iwl3945_rt_rx_hdr {
		struct ieee80211_radiotap_header rt_hdr;
		__le64 rt_tsf;		/* TSF */
		u8 rt_flags;		/* radiotap packet flags */
		u8 rt_rate;		/* rate in 500kb/s */
		__le16 rt_channelMHz;	/* channel in MHz */
		__le16 rt_chbitmask;	/* channel bitfield */
		s8 rt_dbmsignal;	/* signal in dBm, kluged to signed */
		s8 rt_dbmnoise;
		u8 rt_antenna;		/* antenna number */
	} __attribute__ ((packed)) *iwl3945_rt;

	if (skb_headroom(skb) < sizeof(*iwl3945_rt)) {
		if (net_ratelimit())
			printk(KERN_ERR "not enough headroom [%d] for "
546
			       "radiotap head [%zd]\n",
Zhu Yi's avatar
Zhu Yi committed
547 548 549 550 551 552 553 554 555 556 557 558
			       skb_headroom(skb), sizeof(*iwl3945_rt));
		return;
	}

	/* put radiotap header in front of 802.11 header and data */
	iwl3945_rt = (void *)skb_push(skb, sizeof(*iwl3945_rt));

	/* initialise radiotap header */
	iwl3945_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION;
	iwl3945_rt->rt_hdr.it_pad = 0;

	/* total header + data */
559
	put_unaligned_le16(sizeof(*iwl3945_rt), &iwl3945_rt->rt_hdr.it_len);
Zhu Yi's avatar
Zhu Yi committed
560 561

	/* Indicate all the fields we add to the radiotap header */
562 563 564 565 566 567 568 569
	put_unaligned_le32((1 << IEEE80211_RADIOTAP_TSFT) |
			   (1 << IEEE80211_RADIOTAP_FLAGS) |
			   (1 << IEEE80211_RADIOTAP_RATE) |
			   (1 << IEEE80211_RADIOTAP_CHANNEL) |
			   (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) |
			   (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) |
			   (1 << IEEE80211_RADIOTAP_ANTENNA),
			&iwl3945_rt->rt_hdr.it_present);
Zhu Yi's avatar
Zhu Yi committed
570 571 572 573

	/* Zero the flags, we'll add to them as we go */
	iwl3945_rt->rt_flags = 0;

574
	put_unaligned_le64(tsf, &iwl3945_rt->rt_tsf);
Zhu Yi's avatar
Zhu Yi committed
575 576 577 578 579

	iwl3945_rt->rt_dbmsignal = signal;
	iwl3945_rt->rt_dbmnoise = noise;

	/* Convert the channel frequency and set the flags */
580
	put_unaligned_le16(stats->freq, &iwl3945_rt->rt_channelMHz);
Zhu Yi's avatar
Zhu Yi committed
581
	if (!(phy_flags_hw & RX_RES_PHY_FLAGS_BAND_24_MSK))
582
		put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ,
Zhu Yi's avatar
Zhu Yi committed
583 584
			      &iwl3945_rt->rt_chbitmask);
	else if (phy_flags_hw & RX_RES_PHY_FLAGS_MOD_CCK_MSK)
585
		put_unaligned_le16(IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ,
Zhu Yi's avatar
Zhu Yi committed
586 587
			      &iwl3945_rt->rt_chbitmask);
	else	/* 802.11g */
588
		put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ,
Zhu Yi's avatar
Zhu Yi committed
589 590 591 592
			      &iwl3945_rt->rt_chbitmask);

	if (rate == -1)
		iwl3945_rt->rt_rate = 0;
593 594 595 596
	else {
		if (stats->band == IEEE80211_BAND_5GHZ)
			rate += IWL_FIRST_OFDM_RATE;

Zhu Yi's avatar
Zhu Yi committed
597
		iwl3945_rt->rt_rate = iwl3945_rates[rate].ieee;
598
	}
Zhu Yi's avatar
Zhu Yi committed
599 600

	/* antenna number */
Johannes Berg's avatar
Johannes Berg committed
601 602
	antenna = phy_flags_hw & RX_RES_PHY_FLAGS_ANTENNA_MSK;
	iwl3945_rt->rt_antenna = le16_to_cpu(antenna) >> 4;
Zhu Yi's avatar
Zhu Yi committed
603 604 605 606 607 608 609 610

	/* set the preamble flag if we have it */
	if (phy_flags_hw & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK)
		iwl3945_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;

	stats->flag |= RX_FLAG_RADIOTAP;
}

Christoph Hellwig's avatar
Christoph Hellwig committed
611 612
static void iwl3945_handle_data_packet(struct iwl3945_priv *priv, int is_data,
				   struct iwl3945_rx_mem_buffer *rxb,
Zhu Yi's avatar
Zhu Yi committed
613
				   struct ieee80211_rx_status *stats)
614 615
{
	struct ieee80211_hdr *hdr;
Christoph Hellwig's avatar
Christoph Hellwig committed
616 617 618
	struct iwl3945_rx_packet *pkt = (struct iwl3945_rx_packet *)rxb->skb->data;
	struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
	struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt);
619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639
	short len = le16_to_cpu(rx_hdr->len);

	/* We received data from the HW, so stop the watchdog */
	if (unlikely((len + IWL_RX_FRAME_SIZE) > skb_tailroom(rxb->skb))) {
		IWL_DEBUG_DROP("Corruption detected!\n");
		return;
	}

	/* We only process data packets if the interface is open */
	if (unlikely(!priv->is_open)) {
		IWL_DEBUG_DROP_LIMIT
		    ("Dropping packet while interface is not open.\n");
		return;
	}

	skb_reserve(rxb->skb, (void *)rx_hdr->payload - (void *)pkt);
	/* Set the size of the skb to the size of the frame */
	skb_put(rxb->skb, le16_to_cpu(rx_hdr->len));

	hdr = (void *)rxb->skb->data;

Christoph Hellwig's avatar
Christoph Hellwig committed
640 641
	if (iwl3945_param_hwcrypto)
		iwl3945_set_decrypted_flag(priv, rxb->skb,
642 643
				       le32_to_cpu(rx_end->status), stats);

Zhu Yi's avatar
Zhu Yi committed
644 645 646
	if (priv->add_radiotap)
		iwl3945_add_radiotap(priv, rxb->skb, rx_hdr, stats);

Mohamed Abbas's avatar
Mohamed Abbas committed
647 648 649 650
#ifdef CONFIG_IWL3945_LEDS
	if (is_data)
		priv->rxtxpackets += len;
#endif
651 652 653 654
	ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats);
	rxb->skb = NULL;
}

655 656
#define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6)

Christoph Hellwig's avatar
Christoph Hellwig committed
657 658
static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv,
				struct iwl3945_rx_mem_buffer *rxb)
659
{
660 661
	struct ieee80211_hdr *header;
	struct ieee80211_rx_status rx_status;
Christoph Hellwig's avatar
Christoph Hellwig committed
662 663 664 665
	struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data;
	struct iwl3945_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt);
	struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
	struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt);
666
	int snr;
667 668 669
	u16 rx_stats_sig_avg = le16_to_cpu(rx_stats->sig_avg);
	u16 rx_stats_noise_diff = le16_to_cpu(rx_stats->noise_diff);
	u8 network_packet;
670 671 672 673

	rx_status.antenna = 0;
	rx_status.flag = 0;
	rx_status.mactime = le64_to_cpu(rx_end->timestamp);
674
	rx_status.freq =
675
		ieee80211_channel_to_frequency(le16_to_cpu(rx_hdr->channel));
676 677 678 679 680 681
	rx_status.band = (rx_hdr->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ?
				IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;

	rx_status.rate_idx = iwl3945_hwrate_to_plcp_idx(rx_hdr->rate);
	if (rx_status.band == IEEE80211_BAND_5GHZ)
		rx_status.rate_idx -= IWL_FIRST_OFDM_RATE;
682 683 684 685 686 687 688 689 690 691 692 693 694 695 696

	if ((unlikely(rx_stats->phy_count > 20))) {
		IWL_DEBUG_DROP
		    ("dsp size out of range [0,20]: "
		     "%d/n", rx_stats->phy_count);
		return;
	}

	if (!(rx_end->status & RX_RES_STATUS_NO_CRC32_ERROR)
	    || !(rx_end->status & RX_RES_STATUS_NO_RXE_OVERFLOW)) {
		IWL_DEBUG_RX("Bad CRC or FIFO: 0x%08X.\n", rx_end->status);
		return;
	}

	if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) {
697
		iwl3945_handle_data_packet(priv, 1, rxb, &rx_status);
698 699 700 701
		return;
	}

	/* Convert 3945's rssi indicator to dBm */
702
	rx_status.signal = rx_stats->rssi - IWL_RSSI_OFFSET;
703 704 705 706 707 708 709 710 711 712 713 714 715 716 717

	/* Set default noise value to -127 */
	if (priv->last_rx_noise == 0)
		priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE;

	/* 3945 provides noise info for OFDM frames only.
	 * sig_avg and noise_diff are measured by the 3945's digital signal
	 *   processor (DSP), and indicate linear levels of signal level and
	 *   distortion/noise within the packet preamble after
	 *   automatic gain control (AGC).  sig_avg should stay fairly
	 *   constant if the radio's AGC is working well.
	 * Since these values are linear (not dB or dBm), linear
	 *   signal-to-noise ratio (SNR) is (sig_avg / noise_diff).
	 * Convert linear SNR to dB SNR, then subtract that from rssi dBm
	 *   to obtain noise level in dBm.
718
	 * Calculate rx_status.signal (quality indicator in %) based on SNR. */
719 720
	if (rx_stats_noise_diff) {
		snr = rx_stats_sig_avg / rx_stats_noise_diff;
721
		rx_status.noise = rx_status.signal -
722
					iwl3945_calc_db_from_ratio(snr);
723
		rx_status.qual = iwl3945_calc_sig_qual(rx_status.signal,
724
							 rx_status.noise);
725 726 727 728

	/* If noise info not available, calculate signal quality indicator (%)
	 *   using just the dBm signal level. */
	} else {
729
		rx_status.noise = priv->last_rx_noise;
730
		rx_status.qual = iwl3945_calc_sig_qual(rx_status.signal, 0);
731 732 733 734
	}


	IWL_DEBUG_STATS("Rssi %d noise %d qual %d sig_avg %d noise_diff %d\n",
735
			rx_status.signal, rx_status.noise, rx_status.qual,
736 737 738 739
			rx_stats_sig_avg, rx_stats_noise_diff);

	header = (struct ieee80211_hdr *)IWL_RX_DATA(pkt);

Christoph Hellwig's avatar
Christoph Hellwig committed
740
	network_packet = iwl3945_is_network_packet(priv, header);
741

742 743 744
	IWL_DEBUG_STATS_LIMIT("[%c] %d RSSI:%d Signal:%u, Noise:%u, Rate:%u\n",
			      network_packet ? '*' : ' ',
			      le16_to_cpu(rx_hdr->channel),
745 746
			      rx_status.signal, rx_status.signal,
			      rx_status.noise, rx_status.rate_idx);
747

748
#ifdef CONFIG_IWL3945_DEBUG
Christoph Hellwig's avatar
Christoph Hellwig committed
749
	if (iwl3945_debug_level & (IWL_DL_RX))
750
		/* Set "1" to report good data frames in groups of 100 */
751
		iwl3945_dbg_report_frame(priv, pkt, header, 1);
752 753 754 755 756
#endif

	if (network_packet) {
		priv->last_beacon_time = le32_to_cpu(rx_end->beacon_timestamp);
		priv->last_tsf = le64_to_cpu(rx_end->timestamp);
757
		priv->last_rx_rssi = rx_status.signal;
758
		priv->last_rx_noise = rx_status.noise;
759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802
	}

	switch (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FTYPE) {
	case IEEE80211_FTYPE_MGMT:
		switch (le16_to_cpu(header->frame_control) &
			IEEE80211_FCTL_STYPE) {
		case IEEE80211_STYPE_PROBE_RESP:
		case IEEE80211_STYPE_BEACON:{
				/* If this is a beacon or probe response for
				 * our network then cache the beacon
				 * timestamp */
				if ((((priv->iw_mode == IEEE80211_IF_TYPE_STA)
				      && !compare_ether_addr(header->addr2,
							     priv->bssid)) ||
				     ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
				      && !compare_ether_addr(header->addr3,
							     priv->bssid)))) {
					struct ieee80211_mgmt *mgmt =
					    (struct ieee80211_mgmt *)header;
					__le32 *pos;
					pos =
					    (__le32 *) & mgmt->u.beacon.
					    timestamp;
					priv->timestamp0 = le32_to_cpu(pos[0]);
					priv->timestamp1 = le32_to_cpu(pos[1]);
					priv->beacon_int = le16_to_cpu(
					    mgmt->u.beacon.beacon_int);
					if (priv->call_post_assoc_from_beacon &&
					    (priv->iw_mode ==
						IEEE80211_IF_TYPE_STA))
						queue_work(priv->workqueue,
						    &priv->post_associate.work);

					priv->call_post_assoc_from_beacon = 0;
				}

				break;
			}

		case IEEE80211_STYPE_ACTION:
			/* TODO: Parse 802.11h frames for CSA... */
			break;

			/*
803 804
			 * TODO: Use the new callback function from
			 * mac80211 instead of sniffing these packets.
805 806 807 808 809
			 */
		case IEEE80211_STYPE_ASSOC_RESP:
		case IEEE80211_STYPE_REASSOC_RESP:{
				struct ieee80211_mgmt *mgnt =
				    (struct ieee80211_mgmt *)header;
810 811 812 813 814 815 816

				/* We have just associated, give some
				 * time for the 4-way handshake if
				 * any. Don't start scan too early. */
				priv->next_scan_jiffies = jiffies +
					IWL_DELAY_NEXT_SCAN_AFTER_ASSOC;

817 818 819 820 821 822 823 824 825 826 827 828 829 830
				priv->assoc_id = (~((1 << 15) | (1 << 14)) &
						  le16_to_cpu(mgnt->u.
							      assoc_resp.aid));
				priv->assoc_capability =
				    le16_to_cpu(mgnt->u.assoc_resp.capab_info);
				if (priv->beacon_int)
					queue_work(priv->workqueue,
					    &priv->post_associate.work);
				else
					priv->call_post_assoc_from_beacon = 1;
				break;
			}

		case IEEE80211_STYPE_PROBE_REQ:{
831 832 833
				DECLARE_MAC_BUF(mac1);
				DECLARE_MAC_BUF(mac2);
				DECLARE_MAC_BUF(mac3);
834 835
				if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
					IWL_DEBUG_DROP
836 837 838 839 840
					    ("Dropping (non network): %s"
					     ", %s, %s\n",
					     print_mac(mac1, header->addr1),
					     print_mac(mac2, header->addr2),
					     print_mac(mac3, header->addr3));
841 842 843 844
				return;
			}
		}

845
		iwl3945_handle_data_packet(priv, 0, rxb, &rx_status);
846 847 848 849 850
		break;

	case IEEE80211_FTYPE_CTL:
		break;

851 852 853 854 855
	case IEEE80211_FTYPE_DATA: {
		DECLARE_MAC_BUF(mac1);
		DECLARE_MAC_BUF(mac2);
		DECLARE_MAC_BUF(mac3);

Christoph Hellwig's avatar
Christoph Hellwig committed
856
		if (unlikely(iwl3945_is_duplicate_packet(priv, header)))
857 858 859 860
			IWL_DEBUG_DROP("Dropping (dup): %s, %s, %s\n",
				       print_mac(mac1, header->addr1),
				       print_mac(mac2, header->addr2),
				       print_mac(mac3, header->addr3));
861
		else
862
			iwl3945_handle_data_packet(priv, 1, rxb, &rx_status);
863 864
		break;
	}
865
	}
866 867
}

Christoph Hellwig's avatar
Christoph Hellwig committed
868
int iwl3945_hw_txq_attach_buf_to_tfd(struct iwl3945_priv *priv, void *ptr,
869 870 871 872
				 dma_addr_t addr, u16 len)
{
	int count;
	u32 pad;
Christoph Hellwig's avatar
Christoph Hellwig committed
873
	struct iwl3945_tfd_frame *tfd = (struct iwl3945_tfd_frame *)ptr;
874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895

	count = TFD_CTL_COUNT_GET(le32_to_cpu(tfd->control_flags));
	pad = TFD_CTL_PAD_GET(le32_to_cpu(tfd->control_flags));

	if ((count >= NUM_TFD_CHUNKS) || (count < 0)) {
		IWL_ERROR("Error can not send more than %d chunks\n",
			  NUM_TFD_CHUNKS);
		return -EINVAL;
	}

	tfd->pa[count].addr = cpu_to_le32(addr);
	tfd->pa[count].len = cpu_to_le32(len);

	count++;

	tfd->control_flags = cpu_to_le32(TFD_CTL_COUNT_SET(count) |
					 TFD_CTL_PAD_SET(pad));

	return 0;
}

/**
Christoph Hellwig's avatar
Christoph Hellwig committed
896
 * iwl3945_hw_txq_free_tfd - Free one TFD, those at index [txq->q.read_ptr]
897 898 899
 *
 * Does NOT advance any indexes
 */
Christoph Hellwig's avatar
Christoph Hellwig committed
900
int iwl3945_hw_txq_free_tfd(struct iwl3945_priv *priv, struct iwl3945_tx_queue *txq)
901
{
Christoph Hellwig's avatar
Christoph Hellwig committed
902 903
	struct iwl3945_tfd_frame *bd_tmp = (struct iwl3945_tfd_frame *)&txq->bd[0];
	struct iwl3945_tfd_frame *bd = &bd_tmp[txq->q.read_ptr];
904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925
	struct pci_dev *dev = priv->pci_dev;
	int i;
	int counter;

	/* classify bd */
	if (txq->q.id == IWL_CMD_QUEUE_NUM)
		/* nothing to cleanup after for host commands */
		return 0;

	/* sanity check */
	counter = TFD_CTL_COUNT_GET(le32_to_cpu(bd->control_flags));
	if (counter > NUM_TFD_CHUNKS) {
		IWL_ERROR("Too many chunks: %i\n", counter);
		/* @todo issue fatal error, it is quite serious situation */
		return 0;
	}

	/* unmap chunks if any */

	for (i = 1; i < counter; i++) {
		pci_unmap_single(dev, le32_to_cpu(bd->pa[i].addr),
				 le32_to_cpu(bd->pa[i].len), PCI_DMA_TODEVICE);
926 927 928
		if (txq->txb[txq->q.read_ptr].skb[0]) {
			struct sk_buff *skb = txq->txb[txq->q.read_ptr].skb[0];
			if (txq->txb[txq->q.read_ptr].skb[0]) {
929 930
				/* Can be called from interrupt context */
				dev_kfree_skb_any(skb);
931
				txq->txb[txq->q.read_ptr].skb[0] = NULL;
932 933 934 935 936 937
			}
		}
	}
	return 0;
}

Christoph Hellwig's avatar
Christoph Hellwig committed
938
u8 iwl3945_hw_find_station(struct iwl3945_priv *priv, const u8 *addr)
939 940 941 942
{
	int i;
	int ret = IWL_INVALID_STATION;
	unsigned long flags;
943
	DECLARE_MAC_BUF(mac);
944 945 946 947 948 949 950 951 952 953

	spin_lock_irqsave(&priv->sta_lock, flags);
	for (i = IWL_STA_ID; i < priv->hw_setting.max_stations; i++)
		if ((priv->stations[i].used) &&
		    (!compare_ether_addr
		     (priv->stations[i].sta.sta.addr, addr))) {
			ret = i;
			goto out;
		}

954 955
	IWL_DEBUG_INFO("can not find STA %s (total %d)\n",
		       print_mac(mac, addr), priv->num_stations);
956 957 958 959 960 961
 out:
	spin_unlock_irqrestore(&priv->sta_lock, flags);
	return ret;
}

/**
Christoph Hellwig's avatar
Christoph Hellwig committed
962
 * iwl3945_hw_build_tx_cmd_rate - Add rate portion to TX_CMD:
963 964
 *
*/
Christoph Hellwig's avatar
Christoph Hellwig committed
965 966
void iwl3945_hw_build_tx_cmd_rate(struct iwl3945_priv *priv,
			      struct iwl3945_cmd *cmd,
967
			      struct ieee80211_tx_info *info,
968 969 970
			      struct ieee80211_hdr *hdr, int sta_id, int tx_id)
{
	unsigned long flags;
971
	u16 hw_value = ieee80211_get_tx_rate(priv->hw, info)->hw_value;
972
	u16 rate_index = min(hw_value & 0xffff, IWL_RATE_COUNT - 1);
973 974 975 976 977
	u16 rate_mask;
	int rate;
	u8 rts_retry_limit;
	u8 data_retry_limit;
	__le32 tx_flags;
978
	__le16 fc = hdr->frame_control;
979

Christoph Hellwig's avatar
Christoph Hellwig committed
980
	rate = iwl3945_rates[rate_index].plcp;
981 982 983
	tx_flags = cmd->cmd.tx.tx_flags;

	/* We need to figure out how to get the sta->supp_rates while
984
	 * in this running context */
985 986 987 988 989 990 991
	rate_mask = IWL_RATES_MASK;

	spin_lock_irqsave(&priv->sta_lock, flags);

	priv->stations[sta_id].current_rate.rate_n_flags = rate;

	if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) &&
992
	    (sta_id != priv->hw_setting.bcast_sta_id) &&
993 994 995 996 997 998 999 1000 1001 1002
		(sta_id != IWL_MULTICAST_ID))
		priv->stations[IWL_STA_ID].current_rate.rate_n_flags = rate;

	spin_unlock_irqrestore(&priv->sta_lock, flags);

	if (tx_id >= IWL_CMD_QUEUE_NUM)
		rts_retry_limit = 3;
	else
		rts_retry_limit = 7;

1003
	if (ieee80211_is_probe_resp(fc)) {
1004 1005 1006 1007 1008 1009 1010 1011 1012
		data_retry_limit = 3;
		if (data_retry_limit < rts_retry_limit)
			rts_retry_limit = data_retry_limit;
	} else
		data_retry_limit = IWL_DEFAULT_TX_RETRY;

	if (priv->data_retry_limit != -1)
		data_retry_limit = priv->data_retry_limit;

1013 1014 1015 1016 1017 1018
	if (ieee80211_is_mgmt(fc)) {
		switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) {
		case cpu_to_le16(IEEE80211_STYPE_AUTH):
		case cpu_to_le16(IEEE80211_STYPE_DEAUTH):
		case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ):
		case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ):
1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034
			if (tx_flags & TX_CMD_FLG_RTS_MSK) {
				tx_flags &= ~TX_CMD_FLG_RTS_MSK;
				tx_flags |= TX_CMD_FLG_CTS_MSK;
			}
			break;
		default:
			break;
		}
	}

	cmd->cmd.tx.rts_retry_limit = rts_retry_limit;
	cmd->cmd.tx.data_retry_limit = data_retry_limit;
	cmd->cmd.tx.rate = rate;
	cmd->cmd.tx.tx_flags = tx_flags;

	/* OFDM */
1035 1036
	cmd->cmd.tx.supp_rates[0] =
	   ((rate_mask & IWL_OFDM_RATES_MASK) >> IWL_FIRST_OFDM_RATE) & 0xFF;
1037 1038

	/* CCK */
1039
	cmd->cmd.tx.supp_rates[1] = (rate_mask & 0xF);
1040 1041 1042 1043 1044 1045 1046

	IWL_DEBUG_RATE("Tx sta id: %d, rate: %d (plcp), flags: 0x%4X "
		       "cck/ofdm mask: 0x%x/0x%x\n", sta_id,
		       cmd->cmd.tx.rate, le32_to_cpu(cmd->cmd.tx.tx_flags),
		       cmd->cmd.tx.supp_rates[1], cmd->cmd.tx.supp_rates[0]);
}

Christoph Hellwig's avatar
Christoph Hellwig committed
1047
u8 iwl3945_sync_sta(struct iwl3945_priv *priv, int sta_id, u16 tx_rate, u8 flags)
1048 1049
{
	unsigned long flags_spin;
Christoph Hellwig's avatar
Christoph Hellwig committed
1050
	struct iwl3945_station_entry *station;
1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064

	if (sta_id == IWL_INVALID_STATION)
		return IWL_INVALID_STATION;

	spin_lock_irqsave(&priv->sta_lock, flags_spin);
	station = &priv->stations[sta_id];

	station->sta.sta.modify_mask = STA_MODIFY_TX_RATE_MSK;
	station->sta.rate_n_flags = cpu_to_le16(tx_rate);
	station->current_rate.rate_n_flags = tx_rate;
	station->sta.mode = STA_CONTROL_MODIFY_MSK;

	spin_unlock_irqrestore(&priv->sta_lock, flags_spin);

Christoph Hellwig's avatar
Christoph Hellwig committed
1065
	iwl3945_send_add_station(priv, &station->sta, flags);
1066 1067 1068 1069 1070
	IWL_DEBUG_RATE("SCALE sync station %d to rate %d\n",
			sta_id, tx_rate);
	return sta_id;
}

Christoph Hellwig's avatar
Christoph Hellwig committed
1071
static int iwl3945_nic_set_pwr_src(struct iwl3945_priv *priv, int pwr_max)
1072 1073 1074 1075 1076
{
	int rc;
	unsigned long flags;

	spin_lock_irqsave(&priv->lock, flags);
Christoph Hellwig's avatar
Christoph Hellwig committed
1077
	rc = iwl3945_grab_nic_access(priv);
1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088
	if (rc) {
		spin_unlock_irqrestore(&priv->lock, flags);
		return rc;
	}

	if (!pwr_max) {
		u32 val;

		rc = pci_read_config_dword(priv->pci_dev,
				PCI_POWER_SOURCE, &val);
		if (val & PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT) {
Christoph Hellwig's avatar
Christoph Hellwig committed
1089
			iwl3945_set_bits_mask_prph(priv, APMG_PS_CTRL_REG,
1090 1091
					APMG_PS_CTRL_VAL_PWR_SRC_VAUX,
					~APMG_PS_CTRL_MSK_PWR_SRC);
Christoph Hellwig's avatar
Christoph Hellwig committed
1092
			iwl3945_release_nic_access(priv);
1093

Christoph Hellwig's avatar
Christoph Hellwig committed
1094
			iwl3945_poll_bit(priv, CSR_GPIO_IN,
1095 1096 1097
				     CSR_GPIO_IN_VAL_VAUX_PWR_SRC,
				     CSR_GPIO_IN_BIT_AUX_POWER, 5000);
		} else
Christoph Hellwig's avatar
Christoph Hellwig committed
1098
			iwl3945_release_nic_access(priv);
1099
	} else {
Christoph Hellwig's avatar
Christoph Hellwig committed
1100
		iwl3945_set_bits_mask_prph(priv, APMG_PS_CTRL_REG,
1101 1102 1103
				APMG_PS_CTRL_VAL_PWR_SRC_VMAIN,
				~APMG_PS_CTRL_MSK_PWR_SRC);

Christoph Hellwig's avatar
Christoph Hellwig committed
1104 1105
		iwl3945_release_nic_access(priv);
		iwl3945_poll_bit(priv, CSR_GPIO_IN, CSR_GPIO_IN_VAL_VMAIN_PWR_SRC,
1106 1107 1108 1109 1110 1111 1112
			     CSR_GPIO_IN_BIT_AUX_POWER, 5000);	/* uS */
	}
	spin_unlock_irqrestore(&priv->lock, flags);

	return rc;
}

Christoph Hellwig's avatar
Christoph Hellwig committed
1113
static int iwl3945_rx_init(struct iwl3945_priv *priv, struct iwl3945_rx_queue *rxq)
1114 1115 1116 1117 1118
{
	int rc;
	unsigned long flags;

	spin_lock_irqsave(&priv->lock, flags);
Christoph Hellwig's avatar
Christoph Hellwig committed
1119
	rc = iwl3945_grab_nic_access(priv);
1120 1121 1122 1123 1124
	if (rc) {
		spin_unlock_irqrestore(&priv->lock, flags);
		return rc;
	}

Christoph Hellwig's avatar
Christoph Hellwig committed
1125 1126
	iwl3945_write_direct32(priv, FH_RCSR_RBD_BASE(0), rxq->dma_addr);
	iwl3945_write_direct32(priv, FH_RCSR_RPTR_ADDR(0),
1127
			     priv->hw_setting.shared_phys +
Christoph Hellwig's avatar
Christoph Hellwig committed
1128 1129 1130
			     offsetof(struct iwl3945_shared, rx_read_ptr[0]));
	iwl3945_write_direct32(priv, FH_RCSR_WPTR(0), 0);
	iwl3945_write_direct32(priv, FH_RCSR_CONFIG(0),
1131 1132 1133 1134 1135 1136 1137 1138 1139 1140
		ALM_FH_RCSR_RX_CONFIG_REG_VAL_DMA_CHNL_EN_ENABLE |
		ALM_FH_RCSR_RX_CONFIG_REG_VAL_RDRBD_EN_ENABLE |
		ALM_FH_RCSR_RX_CONFIG_REG_BIT_WR_STTS_EN |
		ALM_FH_RCSR_RX_CONFIG_REG_VAL_MAX_FRAG_SIZE_128 |
		(RX_QUEUE_SIZE_LOG << ALM_FH_RCSR_RX_CONFIG_REG_POS_RBDC_SIZE) |
		ALM_FH_RCSR_RX_CONFIG_REG_VAL_IRQ_DEST_INT_HOST |
		(1 << ALM_FH_RCSR_RX_CONFIG_REG_POS_IRQ_RBTH) |
		ALM_FH_RCSR_RX_CONFIG_REG_VAL_MSG_MODE_FH);

	/* fake read to flush all prev I/O */
Christoph Hellwig's avatar
Christoph Hellwig committed
1141
	iwl3945_read_direct32(priv, FH_RSSR_CTRL);
1142

Christoph Hellwig's avatar
Christoph Hellwig committed
1143
	iwl3945_release_nic_access(priv);
1144 1145 1146 1147 1148
	spin_unlock_irqrestore(&priv->lock, flags);

	return 0;
}

Christoph Hellwig's avatar
Christoph Hellwig committed
1149
static int iwl3945_tx_reset(struct iwl3945_priv *priv)
1150 1151 1152 1153 1154
{
	int rc;
	unsigned long flags;

	spin_lock_irqsave(&priv->lock, flags);
Christoph Hellwig's avatar
Christoph Hellwig committed
1155
	rc = iwl3945_grab_nic_access(priv);
1156 1157 1158 1159 1160 1161
	if (rc) {
		spin_unlock_irqrestore(&priv->lock, flags);
		return rc;
	}

	/* bypass mode */
Christoph Hellwig's avatar
Christoph Hellwig committed
1162
	iwl3945_write_prph(priv, ALM_SCD_MODE_REG, 0x2);
1163 1164

	/* RA 0 is active */
Christoph Hellwig's avatar
Christoph Hellwig committed
1165
	iwl3945_write_prph(priv, ALM_SCD_ARASTAT_REG, 0x01);
1166 1167

	/* all 6 fifo are active */
Christoph Hellwig's avatar
Christoph Hellwig committed
1168
	iwl3945_write_prph(priv, ALM_SCD_TXFACT_REG, 0x3f);
1169

Christoph Hellwig's avatar
Christoph Hellwig committed
1170 1171 1172 1173
	iwl3945_write_prph(priv, ALM_SCD_SBYP_MODE_1_REG, 0x010000);
	iwl3945_write_prph(priv, ALM_SCD_SBYP_MODE_2_REG, 0x030002);
	iwl3945_write_prph(priv, ALM_SCD_TXF4MF_REG, 0x000004);
	iwl3945_write_prph(priv, ALM_SCD_TXF5MF_REG, 0x000005);
1174

Christoph Hellwig's avatar
Christoph Hellwig committed
1175
	iwl3945_write_direct32(priv, FH_TSSR_CBB_BASE,
1176 1177
			     priv->hw_setting.shared_phys);

Christoph Hellwig's avatar
Christoph Hellwig committed
1178
	iwl3945_write_direct32(priv, FH_TSSR_MSG_CONFIG,
1179 1180 1181 1182 1183 1184 1185 1186
		ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TXPD_ON |
		ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_TXPD_ON |
		ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_MAX_FRAG_SIZE_128B |
		ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TFD_ON |
		ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_CBB_ON |
		ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RSP_WAIT_TH |
		ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_RSP_WAIT_TH);

Christoph Hellwig's avatar
Christoph Hellwig committed
1187
	iwl3945_release_nic_access(priv);
1188 1189 1190 1191 1192 1193 1194 1195 1196 1197
	spin_unlock_irqrestore(&priv->lock, flags);

	return 0;
}

/**
 * iwl3945_txq_ctx_reset - Reset TX queue context
 *
 * Destroys all DMA structures and initialize them again
 */
Christoph Hellwig's avatar
Christoph Hellwig committed
1198
static int iwl3945_txq_ctx_reset(struct iwl3945_priv *priv)
1199 1200 1201 1202
{
	int rc;
	int txq_id, slots_num;

Christoph Hellwig's avatar
Christoph Hellwig committed
1203
	iwl3945_hw_txq_ctx_free(priv);
1204 1205 1206 1207 1208 1209 1210 1211 1212 1213

	/* Tx CMD queue */
	rc = iwl3945_tx_reset(priv);
	if (rc)
		goto error;

	/* Tx queue(s) */
	for (txq_id = 0; txq_id < TFD_QUEUE_MAX; txq_id++) {
		slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ?
				TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
Christoph Hellwig's avatar
Christoph Hellwig committed
1214
		rc = iwl3945_tx_queue_init(priv, &priv->txq[txq_id], slots_num,
1215 1216 1217 1218 1219 1220 1221 1222 1223 1224
				txq_id);
		if (rc) {
			IWL_ERROR("Tx %d queue init failed\n", txq_id);
			goto error;
		}
	}

	return rc;

 error:
Christoph Hellwig's avatar
Christoph Hellwig committed
1225
	iwl3945_hw_txq_ctx_free(priv);
1226 1227 1228
	return rc;
}

Christoph Hellwig's avatar
Christoph Hellwig committed
1229
int iwl3945_hw_nic_init(struct iwl3945_priv *priv)
1230 1231 1232 1233
{
	u8 rev_id;
	int rc;
	unsigned long flags;
Christoph Hellwig's avatar
Christoph Hellwig committed
1234
	struct iwl3945_rx_queue *rxq = &priv->rxq;
1235

Christoph Hellwig's avatar
Christoph Hellwig committed
1236
	iwl3945_power_init_handle(priv);
1237 1238

	spin_lock_irqsave(&priv->lock, flags);
1239
	iwl3945_set_bit(priv, CSR_ANA_PLL_CFG, CSR39_ANA_PLL_CFG_VAL);
Christoph Hellwig's avatar
Christoph Hellwig committed
1240
	iwl3945_set_bit(priv, CSR_GIO_CHICKEN_BITS,
1241 1242
		    CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX);

Christoph Hellwig's avatar
Christoph Hellwig committed
1243 1244
	iwl3945_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
	rc = iwl3945_poll_bit(priv, CSR_GP_CNTRL,
1245 1246 1247 1248 1249 1250 1251 1252
			  CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
			  CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
	if (rc < 0) {
		spin_unlock_irqrestore(&priv->lock, flags);
		IWL_DEBUG_INFO("Failed to init the card\n");
		return rc;
	}

Christoph Hellwig's avatar
Christoph Hellwig committed