rt2x00: rt2x00pci: fix build error on Ralink RT3x5x SoCs
The rt2800pci driver supports the built-in wireless MAC of the Ralink RT3x5x SoCs. However building the driver for these SoCs leads to the following error: LD init/built-in.o drivers/built-in.o: In function `rt2800pci_rxdone_tasklet': <...>/drivers/net/wireless/rt2x00/rt2800pci.c:1012: undefined reference to `rt2x00pci_rxdone' drivers/built-in.o:(.rodata+0x4780): undefined reference to `rt2x00pci_initialize' drivers/built-in.o:(.rodata+0x4784): undefined reference to `rt2x00pci_uninitialize' drivers/built-in.o:(.rodata+0x47bc): undefined reference to `rt2x00pci_flush_queue' drivers/built-in.o:(.rodata+0x4818): undefined reference to `rt2x00pci_regbusy_read' make[5]: *** [vmlinux] Error 1 The missing functions are provided by the rt2x00pci module. This module is only selected by the rt2800pci driver if PCI support is enabled in the kernel, because some parts of the rt2x00pci code depends on PCI support. PCI support is not available on the RT3x5x SoCs because those have no PCI host controller at all. Move the non PCI specific code from rt2x00pci into a separate module. This makes it possible to use that code even if PCI support is disabled. The affected functions are used by all of the rt2x00 PCI drivers so select the new module for those drivers. Signed-off-by: Gabor Juhos <juhosg@openwrt.org> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
Родитель
83589b30f1
Коммит
69a2bac898
|
@ -20,6 +20,7 @@ if RT2X00
|
||||||
config RT2400PCI
|
config RT2400PCI
|
||||||
tristate "Ralink rt2400 (PCI/PCMCIA) support"
|
tristate "Ralink rt2400 (PCI/PCMCIA) support"
|
||||||
depends on PCI
|
depends on PCI
|
||||||
|
select RT2X00_LIB_MMIO
|
||||||
select RT2X00_LIB_PCI
|
select RT2X00_LIB_PCI
|
||||||
select EEPROM_93CX6
|
select EEPROM_93CX6
|
||||||
---help---
|
---help---
|
||||||
|
@ -31,6 +32,7 @@ config RT2400PCI
|
||||||
config RT2500PCI
|
config RT2500PCI
|
||||||
tristate "Ralink rt2500 (PCI/PCMCIA) support"
|
tristate "Ralink rt2500 (PCI/PCMCIA) support"
|
||||||
depends on PCI
|
depends on PCI
|
||||||
|
select RT2X00_LIB_MMIO
|
||||||
select RT2X00_LIB_PCI
|
select RT2X00_LIB_PCI
|
||||||
select EEPROM_93CX6
|
select EEPROM_93CX6
|
||||||
---help---
|
---help---
|
||||||
|
@ -43,6 +45,7 @@ config RT61PCI
|
||||||
tristate "Ralink rt2501/rt61 (PCI/PCMCIA) support"
|
tristate "Ralink rt2501/rt61 (PCI/PCMCIA) support"
|
||||||
depends on PCI
|
depends on PCI
|
||||||
select RT2X00_LIB_PCI
|
select RT2X00_LIB_PCI
|
||||||
|
select RT2X00_LIB_MMIO
|
||||||
select RT2X00_LIB_FIRMWARE
|
select RT2X00_LIB_FIRMWARE
|
||||||
select RT2X00_LIB_CRYPTO
|
select RT2X00_LIB_CRYPTO
|
||||||
select CRC_ITU_T
|
select CRC_ITU_T
|
||||||
|
@ -57,6 +60,7 @@ config RT2800PCI
|
||||||
tristate "Ralink rt27xx/rt28xx/rt30xx (PCI/PCIe/PCMCIA) support"
|
tristate "Ralink rt27xx/rt28xx/rt30xx (PCI/PCIe/PCMCIA) support"
|
||||||
depends on PCI || SOC_RT288X || SOC_RT305X
|
depends on PCI || SOC_RT288X || SOC_RT305X
|
||||||
select RT2800_LIB
|
select RT2800_LIB
|
||||||
|
select RT2X00_LIB_MMIO
|
||||||
select RT2X00_LIB_PCI if PCI
|
select RT2X00_LIB_PCI if PCI
|
||||||
select RT2X00_LIB_SOC if SOC_RT288X || SOC_RT305X
|
select RT2X00_LIB_SOC if SOC_RT288X || SOC_RT305X
|
||||||
select RT2X00_LIB_FIRMWARE
|
select RT2X00_LIB_FIRMWARE
|
||||||
|
@ -185,6 +189,9 @@ endif
|
||||||
config RT2800_LIB
|
config RT2800_LIB
|
||||||
tristate
|
tristate
|
||||||
|
|
||||||
|
config RT2X00_LIB_MMIO
|
||||||
|
tristate
|
||||||
|
|
||||||
config RT2X00_LIB_PCI
|
config RT2X00_LIB_PCI
|
||||||
tristate
|
tristate
|
||||||
select RT2X00_LIB
|
select RT2X00_LIB
|
||||||
|
|
|
@ -9,6 +9,7 @@ rt2x00lib-$(CONFIG_RT2X00_LIB_FIRMWARE) += rt2x00firmware.o
|
||||||
rt2x00lib-$(CONFIG_RT2X00_LIB_LEDS) += rt2x00leds.o
|
rt2x00lib-$(CONFIG_RT2X00_LIB_LEDS) += rt2x00leds.o
|
||||||
|
|
||||||
obj-$(CONFIG_RT2X00_LIB) += rt2x00lib.o
|
obj-$(CONFIG_RT2X00_LIB) += rt2x00lib.o
|
||||||
|
obj-$(CONFIG_RT2X00_LIB_MMIO) += rt2x00mmio.o
|
||||||
obj-$(CONFIG_RT2X00_LIB_PCI) += rt2x00pci.o
|
obj-$(CONFIG_RT2X00_LIB_PCI) += rt2x00pci.o
|
||||||
obj-$(CONFIG_RT2X00_LIB_SOC) += rt2x00soc.o
|
obj-$(CONFIG_RT2X00_LIB_SOC) += rt2x00soc.o
|
||||||
obj-$(CONFIG_RT2X00_LIB_USB) += rt2x00usb.o
|
obj-$(CONFIG_RT2X00_LIB_USB) += rt2x00usb.o
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
|
||||||
#include "rt2x00.h"
|
#include "rt2x00.h"
|
||||||
|
#include "rt2x00mmio.h"
|
||||||
#include "rt2x00pci.h"
|
#include "rt2x00pci.h"
|
||||||
#include "rt2400pci.h"
|
#include "rt2400pci.h"
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
|
||||||
#include "rt2x00.h"
|
#include "rt2x00.h"
|
||||||
|
#include "rt2x00mmio.h"
|
||||||
#include "rt2x00pci.h"
|
#include "rt2x00pci.h"
|
||||||
#include "rt2500pci.h"
|
#include "rt2500pci.h"
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
#include <linux/eeprom_93cx6.h>
|
#include <linux/eeprom_93cx6.h>
|
||||||
|
|
||||||
#include "rt2x00.h"
|
#include "rt2x00.h"
|
||||||
|
#include "rt2x00mmio.h"
|
||||||
#include "rt2x00pci.h"
|
#include "rt2x00pci.h"
|
||||||
#include "rt2x00soc.h"
|
#include "rt2x00soc.h"
|
||||||
#include "rt2800lib.h"
|
#include "rt2800lib.h"
|
||||||
|
|
|
@ -0,0 +1,216 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
|
||||||
|
<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: rt2x00mmio
|
||||||
|
Abstract: rt2x00 generic mmio device routines.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/dma-mapping.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
|
||||||
|
#include "rt2x00.h"
|
||||||
|
#include "rt2x00mmio.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Register access.
|
||||||
|
*/
|
||||||
|
int rt2x00pci_regbusy_read(struct rt2x00_dev *rt2x00dev,
|
||||||
|
const unsigned int offset,
|
||||||
|
const struct rt2x00_field32 field,
|
||||||
|
u32 *reg)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
|
||||||
|
rt2x00pci_register_read(rt2x00dev, offset, reg);
|
||||||
|
if (!rt2x00_get_field32(*reg, field))
|
||||||
|
return 1;
|
||||||
|
udelay(REGISTER_BUSY_DELAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
printk_once(KERN_ERR "%s() Indirect register access failed: "
|
||||||
|
"offset=0x%.08x, value=0x%.08x\n", __func__, offset, *reg);
|
||||||
|
*reg = ~0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(rt2x00pci_regbusy_read);
|
||||||
|
|
||||||
|
bool rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
|
||||||
|
{
|
||||||
|
struct data_queue *queue = rt2x00dev->rx;
|
||||||
|
struct queue_entry *entry;
|
||||||
|
struct queue_entry_priv_pci *entry_priv;
|
||||||
|
struct skb_frame_desc *skbdesc;
|
||||||
|
int max_rx = 16;
|
||||||
|
|
||||||
|
while (--max_rx) {
|
||||||
|
entry = rt2x00queue_get_entry(queue, Q_INDEX);
|
||||||
|
entry_priv = entry->priv_data;
|
||||||
|
|
||||||
|
if (rt2x00dev->ops->lib->get_entry_state(entry))
|
||||||
|
break;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fill in desc fields of the skb descriptor
|
||||||
|
*/
|
||||||
|
skbdesc = get_skb_frame_desc(entry->skb);
|
||||||
|
skbdesc->desc = entry_priv->desc;
|
||||||
|
skbdesc->desc_len = entry->queue->desc_size;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* DMA is already done, notify rt2x00lib that
|
||||||
|
* it finished successfully.
|
||||||
|
*/
|
||||||
|
rt2x00lib_dmastart(entry);
|
||||||
|
rt2x00lib_dmadone(entry);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Send the frame to rt2x00lib for further processing.
|
||||||
|
*/
|
||||||
|
rt2x00lib_rxdone(entry, GFP_ATOMIC);
|
||||||
|
}
|
||||||
|
|
||||||
|
return !max_rx;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(rt2x00pci_rxdone);
|
||||||
|
|
||||||
|
void rt2x00pci_flush_queue(struct data_queue *queue, bool drop)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
for (i = 0; !rt2x00queue_empty(queue) && i < 10; i++)
|
||||||
|
msleep(10);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(rt2x00pci_flush_queue);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Device initialization handlers.
|
||||||
|
*/
|
||||||
|
static int rt2x00pci_alloc_queue_dma(struct rt2x00_dev *rt2x00dev,
|
||||||
|
struct data_queue *queue)
|
||||||
|
{
|
||||||
|
struct queue_entry_priv_pci *entry_priv;
|
||||||
|
void *addr;
|
||||||
|
dma_addr_t dma;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocate DMA memory for descriptor and buffer.
|
||||||
|
*/
|
||||||
|
addr = dma_alloc_coherent(rt2x00dev->dev,
|
||||||
|
queue->limit * queue->desc_size,
|
||||||
|
&dma, GFP_KERNEL);
|
||||||
|
if (!addr)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
memset(addr, 0, queue->limit * queue->desc_size);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize all queue entries to contain valid addresses.
|
||||||
|
*/
|
||||||
|
for (i = 0; i < queue->limit; i++) {
|
||||||
|
entry_priv = queue->entries[i].priv_data;
|
||||||
|
entry_priv->desc = addr + i * queue->desc_size;
|
||||||
|
entry_priv->desc_dma = dma + i * queue->desc_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rt2x00pci_free_queue_dma(struct rt2x00_dev *rt2x00dev,
|
||||||
|
struct data_queue *queue)
|
||||||
|
{
|
||||||
|
struct queue_entry_priv_pci *entry_priv =
|
||||||
|
queue->entries[0].priv_data;
|
||||||
|
|
||||||
|
if (entry_priv->desc)
|
||||||
|
dma_free_coherent(rt2x00dev->dev,
|
||||||
|
queue->limit * queue->desc_size,
|
||||||
|
entry_priv->desc, entry_priv->desc_dma);
|
||||||
|
entry_priv->desc = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev)
|
||||||
|
{
|
||||||
|
struct data_queue *queue;
|
||||||
|
int status;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocate DMA
|
||||||
|
*/
|
||||||
|
queue_for_each(rt2x00dev, queue) {
|
||||||
|
status = rt2x00pci_alloc_queue_dma(rt2x00dev, queue);
|
||||||
|
if (status)
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Register interrupt handler.
|
||||||
|
*/
|
||||||
|
status = request_irq(rt2x00dev->irq,
|
||||||
|
rt2x00dev->ops->lib->irq_handler,
|
||||||
|
IRQF_SHARED, rt2x00dev->name, rt2x00dev);
|
||||||
|
if (status) {
|
||||||
|
ERROR(rt2x00dev, "IRQ %d allocation failed (error %d).\n",
|
||||||
|
rt2x00dev->irq, status);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
exit:
|
||||||
|
queue_for_each(rt2x00dev, queue)
|
||||||
|
rt2x00pci_free_queue_dma(rt2x00dev, queue);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(rt2x00pci_initialize);
|
||||||
|
|
||||||
|
void rt2x00pci_uninitialize(struct rt2x00_dev *rt2x00dev)
|
||||||
|
{
|
||||||
|
struct data_queue *queue;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Free irq line.
|
||||||
|
*/
|
||||||
|
free_irq(rt2x00dev->irq, rt2x00dev);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Free DMA
|
||||||
|
*/
|
||||||
|
queue_for_each(rt2x00dev, queue)
|
||||||
|
rt2x00pci_free_queue_dma(rt2x00dev, queue);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(rt2x00pci_uninitialize);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* rt2x00mmio module information.
|
||||||
|
*/
|
||||||
|
MODULE_AUTHOR(DRV_PROJECT);
|
||||||
|
MODULE_VERSION(DRV_VERSION);
|
||||||
|
MODULE_DESCRIPTION("rt2x00 mmio library");
|
||||||
|
MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,119 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
|
||||||
|
<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: rt2x00mmio
|
||||||
|
Abstract: Data structures for the rt2x00mmio module.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RT2X00MMIO_H
|
||||||
|
#define RT2X00MMIO_H
|
||||||
|
|
||||||
|
#include <linux/io.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Register access.
|
||||||
|
*/
|
||||||
|
static inline void rt2x00pci_register_read(struct rt2x00_dev *rt2x00dev,
|
||||||
|
const unsigned int offset,
|
||||||
|
u32 *value)
|
||||||
|
{
|
||||||
|
*value = readl(rt2x00dev->csr.base + offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void rt2x00pci_register_multiread(struct rt2x00_dev *rt2x00dev,
|
||||||
|
const unsigned int offset,
|
||||||
|
void *value, const u32 length)
|
||||||
|
{
|
||||||
|
memcpy_fromio(value, rt2x00dev->csr.base + offset, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void rt2x00pci_register_write(struct rt2x00_dev *rt2x00dev,
|
||||||
|
const unsigned int offset,
|
||||||
|
u32 value)
|
||||||
|
{
|
||||||
|
writel(value, rt2x00dev->csr.base + offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void rt2x00pci_register_multiwrite(struct rt2x00_dev *rt2x00dev,
|
||||||
|
const unsigned int offset,
|
||||||
|
const void *value,
|
||||||
|
const u32 length)
|
||||||
|
{
|
||||||
|
__iowrite32_copy(rt2x00dev->csr.base + offset, value, length >> 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rt2x00pci_regbusy_read - Read from register with busy check
|
||||||
|
* @rt2x00dev: Device pointer, see &struct rt2x00_dev.
|
||||||
|
* @offset: Register offset
|
||||||
|
* @field: Field to check if register is busy
|
||||||
|
* @reg: Pointer to where register contents should be stored
|
||||||
|
*
|
||||||
|
* This function will read the given register, and checks if the
|
||||||
|
* register is busy. If it is, it will sleep for a couple of
|
||||||
|
* microseconds before reading the register again. If the register
|
||||||
|
* is not read after a certain timeout, this function will return
|
||||||
|
* FALSE.
|
||||||
|
*/
|
||||||
|
int rt2x00pci_regbusy_read(struct rt2x00_dev *rt2x00dev,
|
||||||
|
const unsigned int offset,
|
||||||
|
const struct rt2x00_field32 field,
|
||||||
|
u32 *reg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct queue_entry_priv_pci: Per entry PCI specific information
|
||||||
|
*
|
||||||
|
* @desc: Pointer to device descriptor
|
||||||
|
* @desc_dma: DMA pointer to &desc.
|
||||||
|
* @data: Pointer to device's entry memory.
|
||||||
|
* @data_dma: DMA pointer to &data.
|
||||||
|
*/
|
||||||
|
struct queue_entry_priv_pci {
|
||||||
|
__le32 *desc;
|
||||||
|
dma_addr_t desc_dma;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rt2x00pci_rxdone - Handle RX done events
|
||||||
|
* @rt2x00dev: Device pointer, see &struct rt2x00_dev.
|
||||||
|
*
|
||||||
|
* Returns true if there are still rx frames pending and false if all
|
||||||
|
* pending rx frames were processed.
|
||||||
|
*/
|
||||||
|
bool rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rt2x00pci_flush_queue - Flush data queue
|
||||||
|
* @queue: Data queue to stop
|
||||||
|
* @drop: True to drop all pending frames.
|
||||||
|
*
|
||||||
|
* This will wait for a maximum of 100ms, waiting for the queues
|
||||||
|
* to become empty.
|
||||||
|
*/
|
||||||
|
void rt2x00pci_flush_queue(struct data_queue *queue, bool drop);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Device initialization handlers.
|
||||||
|
*/
|
||||||
|
int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev);
|
||||||
|
void rt2x00pci_uninitialize(struct rt2x00_dev *rt2x00dev);
|
||||||
|
|
||||||
|
#endif /* RT2X00MMIO_H */
|
|
@ -32,182 +32,6 @@
|
||||||
#include "rt2x00.h"
|
#include "rt2x00.h"
|
||||||
#include "rt2x00pci.h"
|
#include "rt2x00pci.h"
|
||||||
|
|
||||||
/*
|
|
||||||
* Register access.
|
|
||||||
*/
|
|
||||||
int rt2x00pci_regbusy_read(struct rt2x00_dev *rt2x00dev,
|
|
||||||
const unsigned int offset,
|
|
||||||
const struct rt2x00_field32 field,
|
|
||||||
u32 *reg)
|
|
||||||
{
|
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
|
|
||||||
rt2x00pci_register_read(rt2x00dev, offset, reg);
|
|
||||||
if (!rt2x00_get_field32(*reg, field))
|
|
||||||
return 1;
|
|
||||||
udelay(REGISTER_BUSY_DELAY);
|
|
||||||
}
|
|
||||||
|
|
||||||
printk_once(KERN_ERR "%s() Indirect register access failed: "
|
|
||||||
"offset=0x%.08x, value=0x%.08x\n", __func__, offset, *reg);
|
|
||||||
*reg = ~0;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(rt2x00pci_regbusy_read);
|
|
||||||
|
|
||||||
bool rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
|
|
||||||
{
|
|
||||||
struct data_queue *queue = rt2x00dev->rx;
|
|
||||||
struct queue_entry *entry;
|
|
||||||
struct queue_entry_priv_pci *entry_priv;
|
|
||||||
struct skb_frame_desc *skbdesc;
|
|
||||||
int max_rx = 16;
|
|
||||||
|
|
||||||
while (--max_rx) {
|
|
||||||
entry = rt2x00queue_get_entry(queue, Q_INDEX);
|
|
||||||
entry_priv = entry->priv_data;
|
|
||||||
|
|
||||||
if (rt2x00dev->ops->lib->get_entry_state(entry))
|
|
||||||
break;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Fill in desc fields of the skb descriptor
|
|
||||||
*/
|
|
||||||
skbdesc = get_skb_frame_desc(entry->skb);
|
|
||||||
skbdesc->desc = entry_priv->desc;
|
|
||||||
skbdesc->desc_len = entry->queue->desc_size;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* DMA is already done, notify rt2x00lib that
|
|
||||||
* it finished successfully.
|
|
||||||
*/
|
|
||||||
rt2x00lib_dmastart(entry);
|
|
||||||
rt2x00lib_dmadone(entry);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Send the frame to rt2x00lib for further processing.
|
|
||||||
*/
|
|
||||||
rt2x00lib_rxdone(entry, GFP_ATOMIC);
|
|
||||||
}
|
|
||||||
|
|
||||||
return !max_rx;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(rt2x00pci_rxdone);
|
|
||||||
|
|
||||||
void rt2x00pci_flush_queue(struct data_queue *queue, bool drop)
|
|
||||||
{
|
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
for (i = 0; !rt2x00queue_empty(queue) && i < 10; i++)
|
|
||||||
msleep(10);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(rt2x00pci_flush_queue);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Device initialization handlers.
|
|
||||||
*/
|
|
||||||
static int rt2x00pci_alloc_queue_dma(struct rt2x00_dev *rt2x00dev,
|
|
||||||
struct data_queue *queue)
|
|
||||||
{
|
|
||||||
struct queue_entry_priv_pci *entry_priv;
|
|
||||||
void *addr;
|
|
||||||
dma_addr_t dma;
|
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Allocate DMA memory for descriptor and buffer.
|
|
||||||
*/
|
|
||||||
addr = dma_alloc_coherent(rt2x00dev->dev,
|
|
||||||
queue->limit * queue->desc_size,
|
|
||||||
&dma, GFP_KERNEL);
|
|
||||||
if (!addr)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
memset(addr, 0, queue->limit * queue->desc_size);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Initialize all queue entries to contain valid addresses.
|
|
||||||
*/
|
|
||||||
for (i = 0; i < queue->limit; i++) {
|
|
||||||
entry_priv = queue->entries[i].priv_data;
|
|
||||||
entry_priv->desc = addr + i * queue->desc_size;
|
|
||||||
entry_priv->desc_dma = dma + i * queue->desc_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rt2x00pci_free_queue_dma(struct rt2x00_dev *rt2x00dev,
|
|
||||||
struct data_queue *queue)
|
|
||||||
{
|
|
||||||
struct queue_entry_priv_pci *entry_priv =
|
|
||||||
queue->entries[0].priv_data;
|
|
||||||
|
|
||||||
if (entry_priv->desc)
|
|
||||||
dma_free_coherent(rt2x00dev->dev,
|
|
||||||
queue->limit * queue->desc_size,
|
|
||||||
entry_priv->desc, entry_priv->desc_dma);
|
|
||||||
entry_priv->desc = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev)
|
|
||||||
{
|
|
||||||
struct data_queue *queue;
|
|
||||||
int status;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Allocate DMA
|
|
||||||
*/
|
|
||||||
queue_for_each(rt2x00dev, queue) {
|
|
||||||
status = rt2x00pci_alloc_queue_dma(rt2x00dev, queue);
|
|
||||||
if (status)
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Register interrupt handler.
|
|
||||||
*/
|
|
||||||
status = request_irq(rt2x00dev->irq,
|
|
||||||
rt2x00dev->ops->lib->irq_handler,
|
|
||||||
IRQF_SHARED, rt2x00dev->name, rt2x00dev);
|
|
||||||
if (status) {
|
|
||||||
ERROR(rt2x00dev, "IRQ %d allocation failed (error %d).\n",
|
|
||||||
rt2x00dev->irq, status);
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
exit:
|
|
||||||
queue_for_each(rt2x00dev, queue)
|
|
||||||
rt2x00pci_free_queue_dma(rt2x00dev, queue);
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(rt2x00pci_initialize);
|
|
||||||
|
|
||||||
void rt2x00pci_uninitialize(struct rt2x00_dev *rt2x00dev)
|
|
||||||
{
|
|
||||||
struct data_queue *queue;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Free irq line.
|
|
||||||
*/
|
|
||||||
free_irq(rt2x00dev->irq, rt2x00dev);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Free DMA
|
|
||||||
*/
|
|
||||||
queue_for_each(rt2x00dev, queue)
|
|
||||||
rt2x00pci_free_queue_dma(rt2x00dev, queue);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(rt2x00pci_uninitialize);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* PCI driver handlers.
|
* PCI driver handlers.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -35,94 +35,6 @@
|
||||||
*/
|
*/
|
||||||
#define PCI_DEVICE_DATA(__ops) .driver_data = (kernel_ulong_t)(__ops)
|
#define PCI_DEVICE_DATA(__ops) .driver_data = (kernel_ulong_t)(__ops)
|
||||||
|
|
||||||
/*
|
|
||||||
* Register access.
|
|
||||||
*/
|
|
||||||
static inline void rt2x00pci_register_read(struct rt2x00_dev *rt2x00dev,
|
|
||||||
const unsigned int offset,
|
|
||||||
u32 *value)
|
|
||||||
{
|
|
||||||
*value = readl(rt2x00dev->csr.base + offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void rt2x00pci_register_multiread(struct rt2x00_dev *rt2x00dev,
|
|
||||||
const unsigned int offset,
|
|
||||||
void *value, const u32 length)
|
|
||||||
{
|
|
||||||
memcpy_fromio(value, rt2x00dev->csr.base + offset, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void rt2x00pci_register_write(struct rt2x00_dev *rt2x00dev,
|
|
||||||
const unsigned int offset,
|
|
||||||
u32 value)
|
|
||||||
{
|
|
||||||
writel(value, rt2x00dev->csr.base + offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void rt2x00pci_register_multiwrite(struct rt2x00_dev *rt2x00dev,
|
|
||||||
const unsigned int offset,
|
|
||||||
const void *value,
|
|
||||||
const u32 length)
|
|
||||||
{
|
|
||||||
__iowrite32_copy(rt2x00dev->csr.base + offset, value, length >> 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* rt2x00pci_regbusy_read - Read from register with busy check
|
|
||||||
* @rt2x00dev: Device pointer, see &struct rt2x00_dev.
|
|
||||||
* @offset: Register offset
|
|
||||||
* @field: Field to check if register is busy
|
|
||||||
* @reg: Pointer to where register contents should be stored
|
|
||||||
*
|
|
||||||
* This function will read the given register, and checks if the
|
|
||||||
* register is busy. If it is, it will sleep for a couple of
|
|
||||||
* microseconds before reading the register again. If the register
|
|
||||||
* is not read after a certain timeout, this function will return
|
|
||||||
* FALSE.
|
|
||||||
*/
|
|
||||||
int rt2x00pci_regbusy_read(struct rt2x00_dev *rt2x00dev,
|
|
||||||
const unsigned int offset,
|
|
||||||
const struct rt2x00_field32 field,
|
|
||||||
u32 *reg);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* struct queue_entry_priv_pci: Per entry PCI specific information
|
|
||||||
*
|
|
||||||
* @desc: Pointer to device descriptor
|
|
||||||
* @desc_dma: DMA pointer to &desc.
|
|
||||||
* @data: Pointer to device's entry memory.
|
|
||||||
* @data_dma: DMA pointer to &data.
|
|
||||||
*/
|
|
||||||
struct queue_entry_priv_pci {
|
|
||||||
__le32 *desc;
|
|
||||||
dma_addr_t desc_dma;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* rt2x00pci_rxdone - Handle RX done events
|
|
||||||
* @rt2x00dev: Device pointer, see &struct rt2x00_dev.
|
|
||||||
*
|
|
||||||
* Returns true if there are still rx frames pending and false if all
|
|
||||||
* pending rx frames were processed.
|
|
||||||
*/
|
|
||||||
bool rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* rt2x00pci_flush_queue - Flush data queue
|
|
||||||
* @queue: Data queue to stop
|
|
||||||
* @drop: True to drop all pending frames.
|
|
||||||
*
|
|
||||||
* This will wait for a maximum of 100ms, waiting for the queues
|
|
||||||
* to become empty.
|
|
||||||
*/
|
|
||||||
void rt2x00pci_flush_queue(struct data_queue *queue, bool drop);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Device initialization handlers.
|
|
||||||
*/
|
|
||||||
int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev);
|
|
||||||
void rt2x00pci_uninitialize(struct rt2x00_dev *rt2x00dev);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* PCI driver handlers.
|
* PCI driver handlers.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
#include <linux/eeprom_93cx6.h>
|
#include <linux/eeprom_93cx6.h>
|
||||||
|
|
||||||
#include "rt2x00.h"
|
#include "rt2x00.h"
|
||||||
|
#include "rt2x00mmio.h"
|
||||||
#include "rt2x00pci.h"
|
#include "rt2x00pci.h"
|
||||||
#include "rt61pci.h"
|
#include "rt61pci.h"
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче