rt2x00pci.c 12.3 KB
Newer Older
1
/*
I
Ivo van Doorn 已提交
2
	Copyright (C) 2004 - 2008 rt2x00 SourceForge Project
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
	<http://rt2x00.serialmonkey.com>

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	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.,
	59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

/*
	Module: rt2x00pci
	Abstract: rt2x00 generic pci device routines.
 */

#include <linux/dma-mapping.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>

#include "rt2x00.h"
#include "rt2x00pci.h"

/*
 * TX data handlers.
 */
int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev,
I
Ivo van Doorn 已提交
38
			    struct data_queue *queue, struct sk_buff *skb,
39 40
			    struct ieee80211_tx_control *control)
{
I
Ivo van Doorn 已提交
41 42 43
	struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX);
	struct queue_entry_priv_pci_tx *priv_tx = entry->priv_data;
	struct skb_frame_desc *skbdesc;
44 45
	u32 word;

I
Ivo van Doorn 已提交
46
	if (rt2x00queue_full(queue))
47 48
		return -EINVAL;

I
Ivo van Doorn 已提交
49
	rt2x00_desc_read(priv_tx->desc, 0, &word);
50 51 52 53 54 55 56 57 58 59

	if (rt2x00_get_field32(word, TXD_ENTRY_OWNER_NIC) ||
	    rt2x00_get_field32(word, TXD_ENTRY_VALID)) {
		ERROR(rt2x00dev,
		      "Arrived at non-free entry in the non-full queue %d.\n"
		      "Please file bug report to %s.\n",
		      control->queue, DRV_PROJECT);
		return -EINVAL;
	}

I
Ivo van Doorn 已提交
60 61 62
	/*
	 * Fill in skb descriptor
	 */
I
Ivo van Doorn 已提交
63 64
	skbdesc = get_skb_frame_desc(skb);
	skbdesc->data = skb->data;
65
	skbdesc->data_len = skb->len;
I
Ivo van Doorn 已提交
66 67 68 69
	skbdesc->desc = priv_tx->desc;
	skbdesc->desc_len = queue->desc_size;
	skbdesc->entry = entry;

70
	memcpy(&priv_tx->control, control, sizeof(priv_tx->control));
I
Ivo van Doorn 已提交
71
	memcpy(priv_tx->data, skb->data, skb->len);
I
Ivo van Doorn 已提交
72
	rt2x00lib_write_tx_desc(rt2x00dev, skb, control);
73

I
Ivo van Doorn 已提交
74
	rt2x00queue_index_inc(queue, Q_INDEX);
75 76 77 78 79 80

	return 0;
}
EXPORT_SYMBOL_GPL(rt2x00pci_write_tx_data);

/*
81
 * TX/RX data handlers.
82 83 84
 */
void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
{
I
Ivo van Doorn 已提交
85 86 87
	struct data_queue *queue = rt2x00dev->rx;
	struct queue_entry *entry;
	struct queue_entry_priv_pci_rx *priv_rx;
88
	struct ieee80211_hdr *hdr;
I
Ivo van Doorn 已提交
89 90
	struct skb_frame_desc *skbdesc;
	struct rxdone_entry_desc rxdesc;
91 92
	int header_size;
	int align;
93
	u32 word;
94 95

	while (1) {
I
Ivo van Doorn 已提交
96 97 98
		entry = rt2x00queue_get_entry(queue, Q_INDEX);
		priv_rx = entry->priv_data;
		rt2x00_desc_read(priv_rx->desc, 0, &word);
99

100
		if (rt2x00_get_field32(word, RXD_ENTRY_OWNER_NIC))
101 102
			break;

I
Ivo van Doorn 已提交
103 104
		memset(&rxdesc, 0, sizeof(rxdesc));
		rt2x00dev->ops->lib->fill_rxdone(entry, &rxdesc);
105

I
Ivo van Doorn 已提交
106
		hdr = (struct ieee80211_hdr *)priv_rx->data;
107 108 109 110 111 112 113
		header_size =
		    ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control));

		/*
		 * The data behind the ieee80211 header must be
		 * aligned on a 4 byte boundary.
		 */
114
		align = header_size % 4;
115

116 117 118 119
		/*
		 * Allocate the sk_buffer, initialize it and copy
		 * all data into it.
		 */
I
Ivo van Doorn 已提交
120 121
		entry->skb = dev_alloc_skb(rxdesc.size + align);
		if (!entry->skb)
122 123
			return;

I
Ivo van Doorn 已提交
124 125 126
		skb_reserve(entry->skb, align);
		memcpy(skb_put(entry->skb, rxdesc.size),
		       priv_rx->data, rxdesc.size);
127

I
Ivo van Doorn 已提交
128 129 130
		/*
		 * Fill in skb descriptor
		 */
I
Ivo van Doorn 已提交
131 132 133
		skbdesc = get_skb_frame_desc(entry->skb);
		memset(skbdesc, 0, sizeof(*skbdesc));
		skbdesc->data = entry->skb->data;
134
		skbdesc->data_len = entry->skb->len;
I
Ivo van Doorn 已提交
135 136
		skbdesc->desc = priv_rx->desc;
		skbdesc->desc_len = queue->desc_size;
I
Ivo van Doorn 已提交
137 138
		skbdesc->entry = entry;

139 140 141
		/*
		 * Send the frame to rt2x00lib for further processing.
		 */
I
Ivo van Doorn 已提交
142
		rt2x00lib_rxdone(entry, &rxdesc);
143

I
Ivo van Doorn 已提交
144
		if (test_bit(DEVICE_ENABLED_RADIO, &queue->rt2x00dev->flags)) {
145
			rt2x00_set_field32(&word, RXD_ENTRY_OWNER_NIC, 1);
I
Ivo van Doorn 已提交
146
			rt2x00_desc_write(priv_rx->desc, 0, word);
147 148
		}

I
Ivo van Doorn 已提交
149
		rt2x00queue_index_inc(queue, Q_INDEX);
150 151 152 153
	}
}
EXPORT_SYMBOL_GPL(rt2x00pci_rxdone);

I
Ivo van Doorn 已提交
154 155
void rt2x00pci_txdone(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry,
		      struct txdone_entry_desc *txdesc)
156
{
I
Ivo van Doorn 已提交
157
	struct queue_entry_priv_pci_tx *priv_tx = entry->priv_data;
158 159
	u32 word;

I
Ivo van Doorn 已提交
160 161
	txdesc->control = &priv_tx->control;
	rt2x00lib_txdone(entry, txdesc);
162 163 164 165 166 167

	/*
	 * Make this entry available for reuse.
	 */
	entry->flags = 0;

I
Ivo van Doorn 已提交
168
	rt2x00_desc_read(priv_tx->desc, 0, &word);
169 170
	rt2x00_set_field32(&word, TXD_ENTRY_OWNER_NIC, 0);
	rt2x00_set_field32(&word, TXD_ENTRY_VALID, 0);
I
Ivo van Doorn 已提交
171
	rt2x00_desc_write(priv_tx->desc, 0, word);
172

I
Ivo van Doorn 已提交
173
	rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE);
174 175

	/*
I
Ivo van Doorn 已提交
176
	 * If the data queue was full before the txdone handler
177 178 179
	 * we must make sure the packet queue in the mac80211 stack
	 * is reenabled when the txdone handler has finished.
	 */
I
Ivo van Doorn 已提交
180 181
	if (!rt2x00queue_full(entry->queue))
		ieee80211_wake_queue(rt2x00dev->hw, priv_tx->control.queue);
182 183 184 185

}
EXPORT_SYMBOL_GPL(rt2x00pci_txdone);

186 187 188
/*
 * Device initialization handlers.
 */
I
Ivo van Doorn 已提交
189 190 191
#define desc_size(__queue)			\
({						\
	 ((__queue)->limit * (__queue)->desc_size);\
192 193
})

I
Ivo van Doorn 已提交
194 195 196
#define data_size(__queue)			\
({						\
	 ((__queue)->limit * (__queue)->data_size);\
197 198
})

I
Ivo van Doorn 已提交
199 200 201
#define dma_size(__queue)			\
({						\
	data_size(__queue) + desc_size(__queue);\
202 203
})

I
Ivo van Doorn 已提交
204 205 206 207 208 209 210 211 212 213
#define desc_offset(__queue, __base, __i)	\
({						\
	(__base) + data_size(__queue) + 	\
	    ((__i) * (__queue)->desc_size);	\
})

#define data_offset(__queue, __base, __i)	\
({						\
	(__base) +				\
	    ((__i) * (__queue)->data_size);	\
I
Ivo van Doorn 已提交
214 215 216 217
})

static int rt2x00pci_alloc_queue_dma(struct rt2x00_dev *rt2x00dev,
				     struct data_queue *queue)
218
{
I
Ivo van Doorn 已提交
219
	struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev);
I
Ivo van Doorn 已提交
220
	struct queue_entry_priv_pci_rx *priv_rx;
I
Ivo van Doorn 已提交
221
	struct queue_entry_priv_pci_tx *priv_tx;
222 223 224 225
	void *addr;
	dma_addr_t dma;
	void *desc_addr;
	dma_addr_t desc_dma;
I
Ivo van Doorn 已提交
226 227
	void *data_addr;
	dma_addr_t data_dma;
228 229 230 231 232
	unsigned int i;

	/*
	 * Allocate DMA memory for descriptor and buffer.
	 */
233 234
	addr = pci_alloc_consistent(pci_dev, dma_size(queue), &dma);
	if (!addr)
235 236
		return -ENOMEM;

237
	memset(addr, 0, dma_size(queue));
I
Ivo van Doorn 已提交
238

239
	/*
I
Ivo van Doorn 已提交
240
	 * Initialize all queue entries to contain valid addresses.
241
	 */
I
Ivo van Doorn 已提交
242
	for (i = 0; i < queue->limit; i++) {
243 244 245 246
		desc_addr = desc_offset(queue, addr, i);
		desc_dma = desc_offset(queue, dma, i);
		data_addr = data_offset(queue, addr, i);
		data_dma = data_offset(queue, dma, i);
I
Ivo van Doorn 已提交
247 248 249

		if (queue->qid == QID_RX) {
			priv_rx = queue->entries[i].priv_data;
250 251 252 253
			priv_rx->desc = desc_addr;
			priv_rx->desc_dma = desc_dma;
			priv_rx->data = data_addr;
			priv_rx->data_dma = data_dma;
I
Ivo van Doorn 已提交
254 255
		} else {
			priv_tx = queue->entries[i].priv_data;
256 257 258 259
			priv_tx->desc = desc_addr;
			priv_tx->desc_dma = desc_dma;
			priv_tx->data = data_addr;
			priv_tx->data_dma = data_dma;
I
Ivo van Doorn 已提交
260
		}
261 262 263 264 265
	}

	return 0;
}

I
Ivo van Doorn 已提交
266 267
static void rt2x00pci_free_queue_dma(struct rt2x00_dev *rt2x00dev,
				     struct data_queue *queue)
268
{
I
Ivo van Doorn 已提交
269
	struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev);
I
Ivo van Doorn 已提交
270 271 272 273 274 275 276 277
	struct queue_entry_priv_pci_rx *priv_rx;
	struct queue_entry_priv_pci_tx *priv_tx;
	void *data_addr;
	dma_addr_t data_dma;

	if (queue->qid == QID_RX) {
		priv_rx = queue->entries[0].priv_data;
		data_addr = priv_rx->data;
278
		data_dma = priv_rx->data_dma;
I
Ivo van Doorn 已提交
279 280 281 282 283

		priv_rx->data = NULL;
	} else {
		priv_tx = queue->entries[0].priv_data;
		data_addr = priv_tx->data;
284
		data_dma = priv_tx->data_dma;
I
Ivo van Doorn 已提交
285 286 287

		priv_tx->data = NULL;
	}
I
Ivo van Doorn 已提交
288

I
Ivo van Doorn 已提交
289
	if (data_addr)
I
Ivo van Doorn 已提交
290
		pci_free_consistent(pci_dev, dma_size(queue),
I
Ivo van Doorn 已提交
291
				    data_addr, data_dma);
292 293 294 295 296
}

int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev)
{
	struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev);
I
Ivo van Doorn 已提交
297
	struct data_queue *queue;
298 299 300 301 302
	int status;

	/*
	 * Allocate DMA
	 */
I
Ivo van Doorn 已提交
303 304
	queue_for_each(rt2x00dev, queue) {
		status = rt2x00pci_alloc_queue_dma(rt2x00dev, queue);
305 306 307 308 309 310 311 312 313 314 315 316
		if (status)
			goto exit;
	}

	/*
	 * Register interrupt handler.
	 */
	status = request_irq(pci_dev->irq, rt2x00dev->ops->lib->irq_handler,
			     IRQF_SHARED, pci_name(pci_dev), rt2x00dev);
	if (status) {
		ERROR(rt2x00dev, "IRQ %d allocation failed (error %d).\n",
		      pci_dev->irq, status);
317
		goto exit;
318 319 320 321 322
	}

	return 0;

exit:
323 324
	queue_for_each(rt2x00dev, queue)
		rt2x00pci_free_queue_dma(rt2x00dev, queue);
325 326 327 328 329 330 331

	return status;
}
EXPORT_SYMBOL_GPL(rt2x00pci_initialize);

void rt2x00pci_uninitialize(struct rt2x00_dev *rt2x00dev)
{
I
Ivo van Doorn 已提交
332
	struct data_queue *queue;
333 334 335 336 337 338 339 340 341

	/*
	 * Free irq line.
	 */
	free_irq(rt2x00dev_pci(rt2x00dev)->irq, rt2x00dev);

	/*
	 * Free DMA
	 */
I
Ivo van Doorn 已提交
342 343
	queue_for_each(rt2x00dev, queue)
		rt2x00pci_free_queue_dma(rt2x00dev, queue);
344 345 346 347 348 349 350 351 352 353 354 355 356 357
}
EXPORT_SYMBOL_GPL(rt2x00pci_uninitialize);

/*
 * PCI driver handlers.
 */
static void rt2x00pci_free_reg(struct rt2x00_dev *rt2x00dev)
{
	kfree(rt2x00dev->rf);
	rt2x00dev->rf = NULL;

	kfree(rt2x00dev->eeprom);
	rt2x00dev->eeprom = NULL;

358 359 360
	if (rt2x00dev->csr.base) {
		iounmap(rt2x00dev->csr.base);
		rt2x00dev->csr.base = NULL;
361 362 363 364 365 366 367
	}
}

static int rt2x00pci_alloc_reg(struct rt2x00_dev *rt2x00dev)
{
	struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev);

368
	rt2x00dev->csr.base = ioremap(pci_resource_start(pci_dev, 0),
369
				      pci_resource_len(pci_dev, 0));
370
	if (!rt2x00dev->csr.base)
371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414
		goto exit;

	rt2x00dev->eeprom = kzalloc(rt2x00dev->ops->eeprom_size, GFP_KERNEL);
	if (!rt2x00dev->eeprom)
		goto exit;

	rt2x00dev->rf = kzalloc(rt2x00dev->ops->rf_size, GFP_KERNEL);
	if (!rt2x00dev->rf)
		goto exit;

	return 0;

exit:
	ERROR_PROBE("Failed to allocate registers.\n");

	rt2x00pci_free_reg(rt2x00dev);

	return -ENOMEM;
}

int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
{
	struct rt2x00_ops *ops = (struct rt2x00_ops *)id->driver_data;
	struct ieee80211_hw *hw;
	struct rt2x00_dev *rt2x00dev;
	int retval;

	retval = pci_request_regions(pci_dev, pci_name(pci_dev));
	if (retval) {
		ERROR_PROBE("PCI request regions failed.\n");
		return retval;
	}

	retval = pci_enable_device(pci_dev);
	if (retval) {
		ERROR_PROBE("Enable device failed.\n");
		goto exit_release_regions;
	}

	pci_set_master(pci_dev);

	if (pci_set_mwi(pci_dev))
		ERROR_PROBE("MWI not available.\n");

415
	if (pci_set_dma_mask(pci_dev, DMA_32BIT_MASK)) {
416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 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 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539
		ERROR_PROBE("PCI DMA not supported.\n");
		retval = -EIO;
		goto exit_disable_device;
	}

	hw = ieee80211_alloc_hw(sizeof(struct rt2x00_dev), ops->hw);
	if (!hw) {
		ERROR_PROBE("Failed to allocate hardware.\n");
		retval = -ENOMEM;
		goto exit_disable_device;
	}

	pci_set_drvdata(pci_dev, hw);

	rt2x00dev = hw->priv;
	rt2x00dev->dev = pci_dev;
	rt2x00dev->ops = ops;
	rt2x00dev->hw = hw;

	retval = rt2x00pci_alloc_reg(rt2x00dev);
	if (retval)
		goto exit_free_device;

	retval = rt2x00lib_probe_dev(rt2x00dev);
	if (retval)
		goto exit_free_reg;

	return 0;

exit_free_reg:
	rt2x00pci_free_reg(rt2x00dev);

exit_free_device:
	ieee80211_free_hw(hw);

exit_disable_device:
	if (retval != -EBUSY)
		pci_disable_device(pci_dev);

exit_release_regions:
	pci_release_regions(pci_dev);

	pci_set_drvdata(pci_dev, NULL);

	return retval;
}
EXPORT_SYMBOL_GPL(rt2x00pci_probe);

void rt2x00pci_remove(struct pci_dev *pci_dev)
{
	struct ieee80211_hw *hw = pci_get_drvdata(pci_dev);
	struct rt2x00_dev *rt2x00dev = hw->priv;

	/*
	 * Free all allocated data.
	 */
	rt2x00lib_remove_dev(rt2x00dev);
	rt2x00pci_free_reg(rt2x00dev);
	ieee80211_free_hw(hw);

	/*
	 * Free the PCI device data.
	 */
	pci_set_drvdata(pci_dev, NULL);
	pci_disable_device(pci_dev);
	pci_release_regions(pci_dev);
}
EXPORT_SYMBOL_GPL(rt2x00pci_remove);

#ifdef CONFIG_PM
int rt2x00pci_suspend(struct pci_dev *pci_dev, pm_message_t state)
{
	struct ieee80211_hw *hw = pci_get_drvdata(pci_dev);
	struct rt2x00_dev *rt2x00dev = hw->priv;
	int retval;

	retval = rt2x00lib_suspend(rt2x00dev, state);
	if (retval)
		return retval;

	rt2x00pci_free_reg(rt2x00dev);

	pci_save_state(pci_dev);
	pci_disable_device(pci_dev);
	return pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state));
}
EXPORT_SYMBOL_GPL(rt2x00pci_suspend);

int rt2x00pci_resume(struct pci_dev *pci_dev)
{
	struct ieee80211_hw *hw = pci_get_drvdata(pci_dev);
	struct rt2x00_dev *rt2x00dev = hw->priv;
	int retval;

	if (pci_set_power_state(pci_dev, PCI_D0) ||
	    pci_enable_device(pci_dev) ||
	    pci_restore_state(pci_dev)) {
		ERROR(rt2x00dev, "Failed to resume device.\n");
		return -EIO;
	}

	retval = rt2x00pci_alloc_reg(rt2x00dev);
	if (retval)
		return retval;

	retval = rt2x00lib_resume(rt2x00dev);
	if (retval)
		goto exit_free_reg;

	return 0;

exit_free_reg:
	rt2x00pci_free_reg(rt2x00dev);

	return retval;
}
EXPORT_SYMBOL_GPL(rt2x00pci_resume);
#endif /* CONFIG_PM */

/*
 * rt2x00pci module information.
 */
MODULE_AUTHOR(DRV_PROJECT);
MODULE_VERSION(DRV_VERSION);
I
Ivo van Doorn 已提交
540
MODULE_DESCRIPTION("rt2x00 pci library");
541
MODULE_LICENSE("GPL");