Commit 181d6902 authored by Ivo van Doorn's avatar Ivo van Doorn Committed by John W. Linville

rt2x00: Queue handling overhaul

This introduces a big queue handling overhaul, this also
renames "ring" to "queues".

Move queue handling into rt2x00queue.c and the matching header,
use Kerneldoc to improve rt2x00 library documentation.

Access to the queues is now protected under a spinlock, this
to prevent race conditions which could corrupt the indexing
system of the queue.

Each queue entry allocates x bytes for driver/device specific data,
this cleans up the queue structure significantly and improves
code readability.

rt2500usb no longer needs 2 entries in the beacon queue to correctly
send out the guardian byte. This is now handled in the entry specific
structure.

rt61 and rt73 now use the correct descriptor size for beacon frames,
since this data is written into the registers not the entire TXD
descriptor was used but instead of a subset of it named TXINFO.

Finally this also fixes numerous other bugs related to incorrect
beacon handling or beacon related code.
Signed-off-by: default avatarIvo van Doorn <IvDoorn@gmail.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 811aa9ca
rt2x00lib-objs := rt2x00dev.o rt2x00mac.o rt2x00config.o
rt2x00lib-objs := rt2x00dev.o rt2x00mac.o rt2x00config.o rt2x00queue.o
ifeq ($(CONFIG_RT2X00_LIB_DEBUGFS),y)
rt2x00lib-objs += rt2x00debug.o
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -27,7 +27,6 @@
#define RT2X00_H
#include <linux/bitops.h>
#include <linux/prefetch.h>
#include <linux/skbuff.h>
#include <linux/workqueue.h>
#include <linux/firmware.h>
......@@ -38,7 +37,7 @@
#include "rt2x00debug.h"
#include "rt2x00reg.h"
#include "rt2x00ring.h"
#include "rt2x00queue.h"
/*
* Module information.
......@@ -90,26 +89,6 @@
#define EEPROM(__dev, __msg, __args...) \
DEBUG_PRINTK(__dev, KERN_DEBUG, "EEPROM recovery", __msg, ##__args)
/*
* Ring sizes.
* Ralink PCI devices demand the Frame size to be a multiple of 128 bytes.
* DATA_FRAME_SIZE is used for TX, RX, ATIM and PRIO rings.
* MGMT_FRAME_SIZE is used for the BEACON ring.
*/
#define DATA_FRAME_SIZE 2432
#define MGMT_FRAME_SIZE 256
/*
* Number of entries in a packet ring.
* PCI devices only need 1 Beacon entry,
* but USB devices require a second because they
* have to send a Guardian byte first.
*/
#define RX_ENTRIES 12
#define TX_ENTRIES 12
#define ATIM_ENTRIES 1
#define BEACON_ENTRIES 2
/*
* Standard timing and size defines.
* These values should follow the ieee80211 specifications.
......@@ -474,12 +453,12 @@ struct rt2x00lib_ops {
void (*uninitialize) (struct rt2x00_dev *rt2x00dev);
/*
* Ring initialization handlers
* queue initialization handlers
*/
void (*init_rxentry) (struct rt2x00_dev *rt2x00dev,
struct data_entry *entry);
struct queue_entry *entry);
void (*init_txentry) (struct rt2x00_dev *rt2x00dev,
struct data_entry *entry);
struct queue_entry *entry);
/*
* Radio control handlers.
......@@ -497,10 +476,10 @@ struct rt2x00lib_ops {
*/
void (*write_tx_desc) (struct rt2x00_dev *rt2x00dev,
struct sk_buff *skb,
struct txdata_entry_desc *desc,
struct txentry_desc *txdesc,
struct ieee80211_tx_control *control);
int (*write_tx_data) (struct rt2x00_dev *rt2x00dev,
struct data_ring *ring, struct sk_buff *skb,
struct data_queue *queue, struct sk_buff *skb,
struct ieee80211_tx_control *control);
int (*get_tx_data_len) (struct rt2x00_dev *rt2x00dev,
struct sk_buff *skb);
......@@ -510,8 +489,8 @@ struct rt2x00lib_ops {
/*
* RX control handlers
*/
void (*fill_rxdone) (struct data_entry *entry,
struct rxdata_entry_desc *desc);
void (*fill_rxdone) (struct queue_entry *entry,
struct rxdone_entry_desc *rxdesc);
/*
* Configuration handlers.
......@@ -540,10 +519,12 @@ struct rt2x00lib_ops {
*/
struct rt2x00_ops {
const char *name;
const unsigned int rxd_size;
const unsigned int txd_size;
const unsigned int eeprom_size;
const unsigned int rf_size;
const struct data_queue_desc *rx;
const struct data_queue_desc *tx;
const struct data_queue_desc *bcn;
const struct data_queue_desc *atim;
const struct rt2x00lib_ops *lib;
const struct ieee80211_ops *hw;
#ifdef CONFIG_RT2X00_LIB_DEBUGFS
......@@ -570,7 +551,8 @@ enum rt2x00_flags {
* Driver features
*/
DRIVER_REQUIRE_FIRMWARE,
DRIVER_REQUIRE_BEACON_RING,
DRIVER_REQUIRE_BEACON_GUARD,
DRIVER_REQUIRE_ATIM_QUEUE,
/*
* Driver configuration
......@@ -597,8 +579,10 @@ struct rt2x00_dev {
* macro's should be used for correct typecasting.
*/
void *dev;
#define rt2x00dev_pci(__dev) ( (struct pci_dev*)(__dev)->dev )
#define rt2x00dev_usb(__dev) ( (struct usb_interface*)(__dev)->dev )
#define rt2x00dev_pci(__dev) ( (struct pci_dev *)(__dev)->dev )
#define rt2x00dev_usb(__dev) ( (struct usb_interface *)(__dev)->dev )
#define rt2x00dev_usb_dev(__dev)\
( (struct usb_device *)interface_to_usbdev(rt2x00dev_usb(__dev)) )
/*
* Callback functions.
......@@ -757,14 +741,14 @@ struct rt2x00_dev {
struct work_struct config_work;
/*
* Data ring arrays for RX, TX and Beacon.
* The Beacon array also contains the Atim ring
* Data queue arrays for RX, TX and Beacon.
* The Beacon array also contains the Atim queue
* if that is supported by the device.
*/
int data_rings;
struct data_ring *rx;
struct data_ring *tx;
struct data_ring *bcn;
int data_queues;
struct data_queue *rx;
struct data_queue *tx;
struct data_queue *bcn;
/*
* Firmware image.
......@@ -772,37 +756,6 @@ struct rt2x00_dev {
const struct firmware *fw;
};
/*
* For-each loop for the ring array.
* All rings have been allocated as a single array,
* this means we can create a very simply loop macro
* that is capable of looping through all rings.
* ring_end(), txring_end() and ring_loop() are helper macro's which
* should not be used directly. Instead the following should be used:
* ring_for_each() - Loops through all rings (RX, TX, Beacon & Atim)
* txring_for_each() - Loops through TX data rings (TX only)
* txringall_for_each() - Loops through all TX rings (TX, Beacon & Atim)
*/
#define ring_end(__dev) \
&(__dev)->rx[(__dev)->data_rings]
#define txring_end(__dev) \
&(__dev)->tx[(__dev)->hw->queues]
#define ring_loop(__entry, __start, __end) \
for ((__entry) = (__start); \
prefetch(&(__entry)[1]), (__entry) != (__end); \
(__entry) = &(__entry)[1])
#define ring_for_each(__dev, __entry) \
ring_loop(__entry, (__dev)->rx, ring_end(__dev))
#define txring_for_each(__dev, __entry) \
ring_loop(__entry, (__dev)->tx, txring_end(__dev))
#define txringall_for_each(__dev, __entry) \
ring_loop(__entry, (__dev)->tx, ring_end(__dev))
/*
* Generic RF access.
* The RF is being accessed by word index.
......@@ -895,20 +848,42 @@ static inline u16 get_duration_res(const unsigned int size, const u8 rate)
return ((size * 8 * 10) % rate);
}
/*
* Library functions.
/**
* rt2x00queue_get_queue - Convert mac80211 queue index to rt2x00 queue
* @rt2x00dev: Pointer to &struct rt2x00_dev.
* @queue: mac80211 queue index (see &enum ieee80211_tx_queue).
*/
struct data_ring *rt2x00lib_get_ring(struct rt2x00_dev *rt2x00dev,
const unsigned int queue);
struct data_queue *rt2x00queue_get_queue(struct rt2x00_dev *rt2x00dev,
const enum ieee80211_tx_queue queue);
/**
* rt2x00queue_get_entry - Get queue entry where the given index points to.
* @rt2x00dev: Pointer to &struct rt2x00_dev.
* @index: Index identifier for obtaining the correct index.
*/
struct queue_entry *rt2x00queue_get_entry(struct data_queue *queue,
enum queue_index index);
/**
* rt2x00queue_index_inc - Index incrementation function
* @queue: Queue (&struct data_queue) to perform the action on.
* @action: Index type (&enum queue_index) to perform the action on.
*
* This function will increase the requested index on the queue,
* it will grab the appropriate locks and handle queue overflow events by
* resetting the index to the start of the queue.
*/
void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index);
/*
* Interrupt context handlers.
*/
void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev);
void rt2x00lib_txdone(struct data_entry *entry,
const int status, const int retry);
void rt2x00lib_rxdone(struct data_entry *entry, struct sk_buff *skb,
struct rxdata_entry_desc *desc);
void rt2x00lib_txdone(struct queue_entry *entry,
struct txdone_entry_desc *txdesc);
void rt2x00lib_rxdone(struct queue_entry *entry,
struct rxdone_entry_desc *rxdesc);
/*
* TX descriptor initializer
......
......@@ -116,7 +116,7 @@ void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
struct sk_buff *skb)
{
struct rt2x00debug_intf *intf = rt2x00dev->debugfs_intf;
struct skb_desc *desc = get_skb_desc(skb);
struct skb_frame_desc *desc = get_skb_frame_desc(skb);
struct sk_buff *skbcopy;
struct rt2x00dump_hdr *dump_hdr;
struct timeval timestamp;
......@@ -147,7 +147,7 @@ void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
dump_hdr->chip_rf = cpu_to_le16(rt2x00dev->chip.rf);
dump_hdr->chip_rev = cpu_to_le32(rt2x00dev->chip.rev);
dump_hdr->type = cpu_to_le16(desc->frame_type);
dump_hdr->ring_index = desc->ring->queue_idx;
dump_hdr->queue_index = desc->entry->queue->qid;
dump_hdr->entry_index = desc->entry->entry_idx;
dump_hdr->timestamp_sec = cpu_to_le32(timestamp.tv_sec);
dump_hdr->timestamp_usec = cpu_to_le32(timestamp.tv_usec);
......@@ -186,7 +186,7 @@ static int rt2x00debug_file_release(struct inode *inode, struct file *file)
return 0;
}
static int rt2x00debug_open_ring_dump(struct inode *inode, struct file *file)
static int rt2x00debug_open_queue_dump(struct inode *inode, struct file *file)
{
struct rt2x00debug_intf *intf = inode->i_private;
int retval;
......@@ -203,7 +203,7 @@ static int rt2x00debug_open_ring_dump(struct inode *inode, struct file *file)
return 0;
}
static int rt2x00debug_release_ring_dump(struct inode *inode, struct file *file)
static int rt2x00debug_release_queue_dump(struct inode *inode, struct file *file)
{
struct rt2x00debug_intf *intf = inode->i_private;
......@@ -214,10 +214,10 @@ static int rt2x00debug_release_ring_dump(struct inode *inode, struct file *file)
return rt2x00debug_file_release(inode, file);
}
static ssize_t rt2x00debug_read_ring_dump(struct file *file,
char __user *buf,
size_t length,
loff_t *offset)
static ssize_t rt2x00debug_read_queue_dump(struct file *file,
char __user *buf,
size_t length,
loff_t *offset)
{
struct rt2x00debug_intf *intf = file->private_data;
struct sk_buff *skb;
......@@ -248,8 +248,8 @@ exit:
return status;
}
static unsigned int rt2x00debug_poll_ring_dump(struct file *file,
poll_table *wait)
static unsigned int rt2x00debug_poll_queue_dump(struct file *file,
poll_table *wait)
{
struct rt2x00debug_intf *intf = file->private_data;
......@@ -261,12 +261,12 @@ static unsigned int rt2x00debug_poll_ring_dump(struct file *file,
return 0;
}
static const struct file_operations rt2x00debug_fop_ring_dump = {
static const struct file_operations rt2x00debug_fop_queue_dump = {
.owner = THIS_MODULE,
.read = rt2x00debug_read_ring_dump,
.poll = rt2x00debug_poll_ring_dump,
.open = rt2x00debug_open_ring_dump,
.release = rt2x00debug_release_ring_dump,
.read = rt2x00debug_read_queue_dump,
.poll = rt2x00debug_poll_queue_dump,
.open = rt2x00debug_open_queue_dump,
.release = rt2x00debug_release_queue_dump,
};
#define RT2X00DEBUGFS_OPS_READ(__name, __format, __type) \
......@@ -503,7 +503,7 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
intf->frame_dump_entry =
debugfs_create_file("dump", S_IRUGO, intf->frame_folder,
intf, &rt2x00debug_fop_ring_dump);
intf, &rt2x00debug_fop_queue_dump);
if (IS_ERR(intf->frame_dump_entry))
goto exit;
......
This diff is collapsed.
......@@ -93,8 +93,8 @@ enum rt2x00_dump_type {
* @chip_rf: RF chipset
* @chip_rev: Chipset revision
* @type: The frame type (&rt2x00_dump_type)
* @ring_index: The index number of the data ring.
* @entry_index: The index number of the entry inside the data ring.
* @queue_index: The index number of the data queue.
* @entry_index: The index number of the entry inside the data queue.
* @timestamp_sec: Timestamp - seconds
* @timestamp_usec: Timestamp - microseconds
*/
......@@ -111,7 +111,7 @@ struct rt2x00dump_hdr {
__le32 chip_rev;
__le16 type;
__u8 ring_index;
__u8 queue_index;
__u8 entry_index;
__le32 timestamp_sec;
......
......@@ -58,6 +58,16 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
struct ieee80211_conf *conf, const int force_config);
/*
* Queue handlers.
*/
void rt2x00queue_init_rx(struct rt2x00_dev *rt2x00dev);
void rt2x00queue_init_tx(struct rt2x00_dev *rt2x00dev);
int rt2x00queue_initialize(struct rt2x00_dev *rt2x00dev);
void rt2x00queue_uninitialize(struct rt2x00_dev *rt2x00dev);
int rt2x00queue_allocate(struct rt2x00_dev *rt2x00dev);
void rt2x00queue_free(struct rt2x00_dev *rt2x00dev);
/*
* Firmware handlers.
*/
......
......@@ -30,7 +30,7 @@
#include "rt2x00lib.h"
static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev,
struct data_ring *ring,
struct data_queue *queue,
struct sk_buff *frag_skb,
struct ieee80211_tx_control *control)
{
......@@ -60,7 +60,7 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev,
frag_skb->data, frag_skb->len, control,
(struct ieee80211_rts *)(skb->data));
if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, ring, skb, control)) {
if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, queue, skb, control)) {
WARNING(rt2x00dev, "Failed to send RTS/CTS frame.\n");
return NETDEV_TX_BUSY;
}
......@@ -73,7 +73,7 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data;
struct data_ring *ring;
struct data_queue *queue;
u16 frame_control;
/*
......@@ -88,10 +88,10 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
}
/*
* Determine which ring to put packet on.
* Determine which queue to put packet on.
*/
ring = rt2x00lib_get_ring(rt2x00dev, control->queue);
if (unlikely(!ring)) {
queue = rt2x00queue_get_queue(rt2x00dev, control->queue);
if (unlikely(!queue)) {
ERROR(rt2x00dev,
"Attempt to send packet over invalid queue %d.\n"
"Please file bug report to %s.\n",
......@@ -110,23 +110,23 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
if (!is_rts_frame(frame_control) && !is_cts_frame(frame_control) &&
(control->flags & (IEEE80211_TXCTL_USE_RTS_CTS |
IEEE80211_TXCTL_USE_CTS_PROTECT))) {
if (rt2x00_ring_free(ring) <= 1) {
if (rt2x00queue_available(queue) <= 1) {
ieee80211_stop_queue(rt2x00dev->hw, control->queue);
return NETDEV_TX_BUSY;
}
if (rt2x00mac_tx_rts_cts(rt2x00dev, ring, skb, control)) {
if (rt2x00mac_tx_rts_cts(rt2x00dev, queue, skb, control)) {
ieee80211_stop_queue(rt2x00dev->hw, control->queue);
return NETDEV_TX_BUSY;
}
}
if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, ring, skb, control)) {
if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, queue, skb, control)) {
ieee80211_stop_queue(rt2x00dev->hw, control->queue);
return NETDEV_TX_BUSY;
}
if (rt2x00_ring_full(ring))
if (rt2x00queue_full(queue))
ieee80211_stop_queue(rt2x00dev->hw, control->queue);
if (rt2x00dev->ops->lib->kick_tx_queue)
......@@ -214,7 +214,7 @@ void rt2x00mac_remove_interface(struct ieee80211_hw *hw,
!is_interface_present(intf))
return;
intf->id = 0;
intf->id = NULL;
intf->type = IEEE80211_IF_TYPE_INVALID;
memset(&intf->bssid, 0x00, ETH_ALEN);
memset(&intf->mac, 0x00, ETH_ALEN);
......@@ -334,9 +334,11 @@ int rt2x00mac_get_tx_stats(struct ieee80211_hw *hw,
struct rt2x00_dev *rt2x00dev = hw->priv;
unsigned int i;
for (i = 0; i < hw->queues; i++)
memcpy(&stats->data[i], &rt2x00dev->tx[i].stats,
sizeof(rt2x00dev->tx[i].stats));
for (i = 0; i < hw->queues; i++) {
stats->data[i].len = rt2x00dev->tx[i].length;
stats->data[i].limit = rt2x00dev->tx[i].limit;
stats->data[i].count = rt2x00dev->tx[i].count;
}
return 0;
}
......@@ -380,14 +382,14 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
}
EXPORT_SYMBOL_GPL(rt2x00mac_bss_info_changed);
int rt2x00mac_conf_tx(struct ieee80211_hw *hw, int queue,
int rt2x00mac_conf_tx(struct ieee80211_hw *hw, int queue_idx,
const struct ieee80211_tx_queue_params *params)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct data_ring *ring;
struct data_queue *queue;
ring = rt2x00lib_get_ring(rt2x00dev, queue);
if (unlikely(!ring))
queue = rt2x00queue_get_queue(rt2x00dev, queue_idx);
if (unlikely(!queue))
return -EINVAL;
/*
......@@ -395,24 +397,23 @@ int rt2x00mac_conf_tx(struct ieee80211_hw *hw, int queue,
* Ralink registers require to know the bit number 'n'.
*/
if (params->cw_min)
ring->tx_params.cw_min = fls(params->cw_min);
queue->cw_min = fls(params->cw_min);
else
ring->tx_params.cw_min = 5; /* cw_min: 2^5 = 32. */
queue->cw_min = 5; /* cw_min: 2^5 = 32. */
if (params->cw_max)
ring->tx_params.cw_max = fls(params->cw_max);
queue->cw_max = fls(params->cw_max);
else
ring->tx_params.cw_max = 10; /* cw_min: 2^10 = 1024. */
queue->cw_max = 10; /* cw_min: 2^10 = 1024. */
if (params->aifs)
ring->tx_params.aifs = params->aifs;
queue->aifs = params->aifs;
else
ring->tx_params.aifs = 2;
queue->aifs = 2;
INFO(rt2x00dev,
"Configured TX ring %d - CWmin: %d, CWmax: %d, Aifs: %d.\n",
queue, ring->tx_params.cw_min, ring->tx_params.cw_max,
ring->tx_params.aifs);
"Configured TX queue %d - CWmin: %d, CWmax: %d, Aifs: %d.\n",
queue_idx, queue->cw_min, queue->cw_max, queue->aifs);
return 0;
}
......
This diff is collapsed.
......@@ -97,15 +97,54 @@ int rt2x00pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
* TX data handlers.
*/
int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev,
struct data_ring *ring, struct sk_buff *skb,
struct data_queue *queue, struct sk_buff *skb,
struct ieee80211_tx_control *control);
/*
* RX/TX data handlers.
/**
* struct queue_entry_priv_pci_rx: Per RX entry PCI specific information
*
* @desc: Pointer to device descriptor.
* @data: Pointer to device's entry memory.
* @dma: DMA pointer to &data.
*/
struct queue_entry_priv_pci_rx {
__le32 *desc;
void *data;
dma_addr_t dma;
};
/**
* struct queue_entry_priv_pci_tx: Per TX entry PCI specific information
*
* @desc: Pointer to device descriptor
* @data: Pointer to device's entry memory.
* @dma: DMA pointer to &data.
* @control: mac80211 control structure used to transmit data.
*/
struct queue_entry_priv_pci_tx {
__le32 *desc;
void *data;
dma_addr_t dma;
struct ieee80211_tx_control control;
};
/**
* rt2x00pci_rxdone - Handle RX done events
* @rt2x00dev: Device pointer, see &struct rt2x00_dev.
*/
void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev);
void rt2x00pci_txdone(struct rt2x00_dev *rt2x00dev, struct data_entry *entry,
const int tx_status, const int retry);
/**
* rt2x00pci_txdone - Handle TX done events
* @rt2x00dev: Device pointer, see &struct rt2x00_dev.
* @entry: Entry which has completed the transmission of a frame.
* @desc: TX done descriptor
*/
void rt2x00pci_txdone(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry,
struct txdone_entry_desc *desc);
/*
* Device initialization handlers.
......
/*
Copyright (C) 2004 - 2008 rt2x00 SourceForge Project
<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: rt2x00lib
Abstract: rt2x00 queue specific routines.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include "rt2x00.h"
#include "rt2x00lib.h"
struct data_queue *rt2x00queue_get_queue(struct rt2x00_dev *rt2x00dev,
const enum ieee80211_tx_queue queue)
{
int atim = test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags);
if (queue < rt2x00dev->hw->queues && rt2x00dev->tx)
return &rt2x00dev->tx[queue];
if (!rt2x00dev->bcn)
return NULL;
if (queue == IEEE80211_TX_QUEUE_BEACON)
return &rt2x00dev->bcn[0];
else if (queue == IEEE80211_TX_QUEUE_AFTER_BEACON && atim)
return &rt2x00dev->bcn[1];
return NULL;
}
EXPORT_SYMBOL_GPL(rt2x00queue_get_queue);
struct queue_entry *rt2x00queue_get_entry(struct data_queue *queue,
enum queue_index index)
{
struct queue_entry *entry;
if (unlikely(index >= Q_INDEX_MAX)) {
ERROR(queue->rt2x00dev,
"Entry requested from invalid index type (%d)\n", index);
return NULL;
}
spin_lock(&queue->lock);
entry = &queue->entries[queue->index[index]];
spin_unlock(&queue->lock);
return entry;
}
EXPORT_SYMBOL_GPL(rt2x00queue_get_entry);
void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index)
{
if (unlikely(index >= Q_INDEX_MAX)) {
ERROR(queue->rt2x00dev,
"Index change on invalid index type (%d)\n", index);
return;
}
spin_lock(&queue->lock);
queue->index[index]++;
if (queue->index[index] >= queue->limit)
queue->index[index] = 0;
queue->length--;
queue->count += (index == Q_INDEX_DONE);
spin_unlock(&queue->lock);
}
EXPORT_SYMBOL_GPL(rt2x00queue_index_inc);
static void rt2x00queue_reset(struct data_queue *queue)
{
spin_lock(&queue->lock);
queue->count = 0;
queue->length = 0;
memset(queue->index, 0, sizeof(queue->index));
spin_unlock(&queue->lock);
}
void rt2x00queue_init_rx(struct rt2x00_dev *rt2x00dev)
{
struct data_queue *queue = rt2x00dev->rx;
unsigned int i;
rt2x00queue_reset(queue);
if (!rt2x00dev->ops->lib->init_rxentry)
return;
for (i = 0; i < queue->limit; i++)
rt2x00dev->ops->lib->init_rxentry(rt2x00dev,
&queue->entries[i]);
}
void rt2x00queue_init_tx(struct rt2x00_dev *rt2x00dev)
{
struct data_queue *queue;
unsigned int i;
txall_queue_for_each(rt2x00dev, queue) {
rt2x00queue_reset(queue);
if (!rt2x00dev->ops->lib->init_txentry)
continue;
for (i = 0; i < queue->limit; i++)
rt2x00dev->ops->lib->init_txentry(rt2x00dev,
&queue->entries[i]);
}
}
static int rt2x00queue_alloc_entries(struct data_queue *queue,
const struct data_queue_desc *qdesc)
{
struct queue_entry *entries;
unsigned int entry_size;
unsigned int i;
rt2x00queue_reset(queue);
queue->limit = qdesc->entry_num;
queue->data_size = qdesc->data_size;
queue->desc_size = qdesc->desc_size;
/*
* Allocate all queue entries.
*/
entry_size = sizeof(*entries) + qdesc->priv_size;
entries = kzalloc(queue->limit * entry_size, GFP_KERNEL);
if (!entries)
return -ENOMEM;
#define QUEUE_ENTRY_PRIV_OFFSET(__base, __index, __limit, __esize, __psize) \
( (__base) + ((__limit) * (__esize)) + ((__index) * (__psize)) )
for (i = 0; i < queue->limit; i++) {
entries[i].flags = 0;
entries[i].queue = queue;
entries[i].skb = NULL;
entries[i].entry_idx = i;
entries[i].priv_data =
QUEUE_ENTRY_PRIV_OFFSET(entries, i, queue->limit,
sizeof(*entries), qdesc->priv_size);
}
#undef QUEUE_ENTRY_PRIV_OFFSET
queue->entries = entries;
return 0;
}
int rt2x00queue_initialize(struct rt2x00_dev *rt2x00dev)
{
struct data_queue *queue;
int status;
status = rt2x00queue_alloc_entries(rt2x00dev->rx, rt2x00dev->ops->rx);
if (status)
goto exit;
tx_queue_for_each(rt2x00dev, queue) {
status = rt2x00queue_alloc_entries(queue, rt2x00dev->ops->tx);
if (status)
goto exit;
}
status = rt2x00queue_alloc_entries(rt2x00dev->bcn, rt2x00dev->ops->bcn);
if (status)
goto exit;
if (!test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags))
return 0;
status = rt2x00queue_alloc_entries(&rt2x00dev->bcn[1],
rt2x00dev->ops->atim);
if (status)
goto exit;
return 0;
exit:
ERROR(rt2x00dev, "Queue entries allocation failed.\n");
rt2x00queue_uninitialize(rt2x00dev);
return status;
}
void rt2x00queue_uninitialize(struct rt2x00_dev *rt2x00dev)
{
struct data_queue *queue;
queue_for_each(rt2x00dev, queue) {
kfree(queue->entries);
queue->entries = NULL;
}
}
int rt2x00queue_allocate(struct rt2x00_dev *rt2x00dev)
{
struct data_queue *queue;
enum data_queue_qid qid;
unsigned int req_atim =
!!test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags);
/*
* We need the following queues:
* RX: 1
* TX: hw->queues
* Beacon: 1
* Atim: 1 (if required)
*/
rt2x00dev->data_queues = 2 + rt2x00dev->hw->queues + req_atim;
queue = kzalloc(rt2x00dev->data_queues * sizeof(*queue), GFP_KERNEL);
if (!queue) {
ERROR(rt2x00dev, "Queue allocation failed.\n");
return -ENOMEM;
}
/*
* Initialize pointers
*/
rt2x00dev->rx = queue;
rt2x00dev->tx = &queue[1];
rt2x00dev->bcn = &queue[1 + rt2x00dev->hw->queues];
/*
* Initialize queue parameters.
* RX: qid = QID_RX
* TX: qid = QID_AC_BE + index
* TX: cw_min: 2^5 = 32.
* TX: cw_max: 2^10 = 1024.
* BCN & Atim: qid = QID_MGMT
*/
qid = QID_AC_BE;
queue_for_each(rt2x00dev, queue) {
spin_lock_init(&queue->lock);
queue->rt2x00dev = rt2x00dev;
queue->qid = qid++;
queue->aifs = 2;
queue->cw_min = 5;
queue->cw_max = 10;
}
/*
* Fix non-TX data qid's
*/
rt2x00dev->rx->qid = QID_RX;
rt2x00dev->bcn[0].qid = QID_MGMT;
if (req_atim)
rt2x00dev->bcn[1].qid = QID_MGMT;
return 0;
}
void rt2x00queue_free(struct rt2x00_dev *rt2x00dev)
{
kfree(rt2x00dev->rx);
rt2x00dev->rx = NULL;
rt2x00dev->tx = NULL;
rt2x00dev->bcn = NULL;
}
This diff is collapsed.
......@@ -29,7 +29,7 @@
/*
* TX result flags.
*/
enum TX_STATUS {
enum tx_status {
TX_SUCCESS = 0,
TX_SUCCESS_RETRY = 1,
TX_FAIL_RETRY = 2,
......
/*
Copyright (C) 2004 - 2008 rt2x00 SourceForge Project
<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: rt2x00
Abstract: rt2x00 ring datastructures and routines
*/
#ifndef RT2X00RING_H
#define RT2X00RING_H
/*
* skb_desc
* Descriptor information for the skb buffer
*/
struct skb_desc {
unsigned int frame_type;
unsigned int desc_len;
unsigned int data_len;
void *desc;
void *data;
struct data_ring *ring;
struct data_entry *entry;
};
static inline struct skb_desc* get_skb_desc(struct sk_buff *skb)
{
return (struct skb_desc*)&skb->cb[0];
}
/*
* rxdata_entry_desc
* Summary of information that has been read from the
* RX frame descriptor.
*/
struct rxdata_entry_desc {
int signal;
int rssi;
int ofdm;
int size;
int flags;
int my_bss;
};
/*
* txdata_entry_desc
* Summary of information that should be written into the
* descriptor for sending a TX frame.
*/
struct txdata_entry_desc {
unsigned long flags;
#define ENTRY_TXDONE 1
#define ENTRY_TXD_RTS_FRAME 2
#define ENTRY_TXD_OFDM_RATE 3
#define ENTRY_TXD_MORE_FRAG 4
#define ENTRY_TXD_REQ_TIMESTAMP 5
#define ENTRY_TXD_BURST 6
#define ENTRY_TXD_ACK 7
/*
* Queue ID. ID's 0-4 are data TX rings
*/
int queue;
#define QUEUE_MGMT 13
#define QUEUE_RX 14
#define QUEUE_OTHER 15
/*
* PLCP values.
*/
u16 length_high;
u16 length_low;
u16 signal;
u16 service;
/*
* Timing information
*/
int aifs;
int ifs;
int cw_min;
int cw_max;
};
/*
* data_entry
* The data ring is a list of data entries.
* Each entry holds a reference to the descriptor
* and the data buffer. For TX rings the reference to the
* sk_buff of the packet being transmitted is also stored here.
*/
struct data_entry {
/*
* Status flags
*/
unsigned long flags;
#define ENTRY_OWNER_NIC 1
/*
* Ring we belong to.
*/
struct data_ring *ring;
/*
* sk_buff for the packet which is being transmitted
* in this entry (Only used with TX related rings).
*/
struct sk_buff *skb;
/*
* Store a ieee80211_tx_status structure in each
* ring entry, this will optimize the txdone
* handler.
*/
struct ieee80211_tx_status tx_status;
/*
* private pointer specific to driver.
*/
void *priv;
/*
* Data address for this entry.
*/
void *data_addr;
dma_addr_t data_dma;
/*
* Entry identification number (index).
*/
unsigned int entry_idx;
};
/*
* data_ring
* Data rings are used by the device to send and receive packets.
* The data_addr is the base address of the data memory.
* To determine at which point in the ring we are,
* have to use the rt2x00_ring_index_*() functions.
*/
struct data_ring {
/*
* Pointer to main rt2x00dev structure where this
* ring belongs to.
*/
struct rt2x00_dev *rt2x00dev;
/*
* Base address for the device specific data entries.
*/
struct data_entry *entry;
/*
* TX queue statistic info.
*/
struct ieee80211_tx_queue_stats_data stats;
/*
* TX Queue parameters.
*/
struct ieee80211_tx_queue_params tx_params;
/*
* Base address for data ring.
*/
dma_addr_t data_dma;
void *data_addr;
/*
* Queue identification number:
* RX: 0
* TX: IEEE80211_TX_*
*/
unsigned int queue_idx;
/*
* Index variables.
*/
u16 index;
u16 index_done;
/*
* Size of packet and descriptor in bytes.
*/
u16 data_size;
u16 desc_size;
};
/*
* Handlers to determine the address of the current device specific
* data entry, where either index or index_done points to.
*/
static inline struct data_entry *rt2x00_get_data_entry(struct data_ring *ring)
{
return &ring->entry[ring->index];
}
static inline struct data_entry *rt2x00_get_data_entry_done(struct data_ring
*ring)
{
return &ring->entry[ring->index_done];
}
/*
* Total ring memory
*/
static inline int rt2x00_get_ring_size(struct data_ring *ring)
{
return ring->stats.limit * (ring->desc_size + ring->data_size);
}
/*
* Ring index manipulation functions.
*/
static inline void rt2x00_ring_index_inc(struct data_ring *ring)
{
ring->index++;
if (ring->index >= ring->stats.limit)
ring->index = 0;
ring->stats.len++;
}
static inline void rt2x00_ring_index_done_inc(struct data_ring *ring)
{
ring->index_done++;
if (ring->index_done >= ring->stats.limit)
ring->index_done = 0;
ring->stats.len--;
ring->stats.count++;
}
static inline void rt2x00_ring_index_clear(struct data_ring *ring)
{
ring->index = 0;
ring->index_done = 0;
ring->stats.len = 0;
ring->stats.count = 0;
}
static inline int rt2x00_ring_empty(struct data_ring *ring)
{
return ring->stats.len == 0;
}
static inline int rt2x00_ring_full(struct data_ring *ring)
{
return ring->stats.len == ring->stats.limit;
}
static inline int rt2x00_ring_free(struct data_ring *ring)
{
return ring->stats.limit - ring->stats.len;
}
/*
* TX/RX Descriptor access functions.
*/
static inline void rt2x00_desc_read(__le32 *desc,
const u8 word, u32 *value)
{
*value = le32_to_cpu(desc[word]);
}
static inline void rt2x00_desc_write(__le32 *desc,
const u8 word, const u32 value)
{
desc[word] = cpu_to_le32(value);
}
#endif /* RT2X00RING_H */
This diff is collapsed.
......@@ -160,16 +160,58 @@ void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev);
* TX data handlers.
*/
int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev,
struct data_ring *ring, struct sk_buff *skb,
struct data_queue *queue, struct sk_buff *skb,
struct ieee80211_tx_control *control);
/**
* struct queue_entry_priv_usb_rx: Per RX entry USB specific information
*
* @urb: Urb structure used for device communication.
*/
struct queue_entry_priv_usb_rx {
struct urb *urb;
};
/**
* struct queue_entry_priv_usb_tx: Per TX entry USB specific information
*
* @urb: Urb structure used for device communication.
* @control: mac80211 control structure used to transmit data.
*/
struct queue_entry_priv_usb_tx {
struct urb *urb;
struct ieee80211_tx_control control;
};
/**
* struct queue_entry_priv_usb_tx: Per TX entry USB specific information
*
* The first section should match &struct queue_entry_priv_usb_tx exactly.
* rt2500usb can use this structure to send a guardian byte when working
* with beacons.
*
* @urb: Urb structure used for device communication.
* @control: mac80211 control structure used to transmit data.
* @guardian_data: Set to 0, used for sending the guardian data.
* @guardian_urb: Urb structure used to send the guardian data.
*/
struct queue_entry_priv_usb_bcn {
struct urb *urb;
struct ieee80211_tx_control control;
unsigned int guardian_data;
struct urb *guardian_urb;
};
/*
* Device initialization handlers.
*/
void rt2x00usb_init_rxentry(struct rt2x00_dev *rt2x00dev,
struct data_entry *entry);
struct queue_entry *entry);
void rt2x00usb_init_txentry(struct rt2x00_dev *rt2x00dev,
struct data_entry *entry);
struct queue_entry *entry);
int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev);
void rt2x00usb_uninitialize(struct rt2x00_dev *rt2x00dev);
......
This diff is collapsed.
......@@ -1247,6 +1247,7 @@ struct hw_pairwise_ta_entry {
* DMA descriptor defines.
*/
#define TXD_DESC_SIZE ( 16 * sizeof(__le32) )
#define TXINFO_SIZE ( 6 * sizeof(__le32) )
#define RXD_DESC_SIZE ( 16 * sizeof(__le32) )
/*
......
......@@ -1234,10 +1234,10 @@ static int rt73usb_set_device_state(struct rt2x00_dev *rt2x00dev,
*/
static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
struct sk_buff *skb,
struct txdata_entry_desc *desc,
struct txentry_desc *txdesc,
struct ieee80211_tx_control *control)
{
struct skb_desc *skbdesc = get_skb_desc(skb);
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
__le32 *txd = skbdesc->desc;
u32 word;
......@@ -1245,19 +1245,19 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
* Start writing the descriptor words.
*/
rt2x00_desc_read(txd, 1, &word);
rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, desc->queue);
rt2x00_set_field32(&word, TXD_W1_AIFSN, desc->aifs);
rt2x00_set_field32(&word, TXD_W1_CWMIN, desc->cw_min);
rt2x00_set_field32(&word, TXD_W1_CWMAX, desc->cw_max);
rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, txdesc->queue);
rt2x00_set_field32(&word, TXD_W1_AIFSN, txdesc->aifs);
rt2x00_set_field32(&word, TXD_W1_CWMIN, txdesc->cw_min);
rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max);
rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, IEEE80211_HEADER);
rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE, 1);
rt2x00_desc_write(txd, 1, word);
rt2x00_desc_read(txd, 2, &word);
rt2x00_set_field32(&word, TXD_W2_PLCP_SIGNAL, desc->signal);
rt2x00_set_field32(&word, TXD_W2_PLCP_SERVICE, desc->service);
rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_LOW, desc->length_low);
rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_HIGH, desc->length_high);
rt2x00_set_field32(&word, TXD_W2_PLCP_SIGNAL, txdesc->signal);
rt2x00_set_field32(&word, TXD_W2_PLCP_SERVICE, txdesc->service);
rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_LOW, txdesc->length_low);
rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_HIGH, txdesc->length_high);
rt2x00_desc_write(txd, 2, word);
rt2x00_desc_read(txd, 5, &word);
......@@ -1268,24 +1268,24 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
rt2x00_desc_read(txd, 0, &word);
rt2x00_set_field32(&word, TXD_W0_BURST,
test_bit(ENTRY_TXD_BURST, &desc->flags));
test_bit(ENTRY_TXD_BURST, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W0_VALID, 1);
rt2x00_set_field32(&word, TXD_W0_MORE_FRAG,
test_bit(ENTRY_TXD_MORE_FRAG, &desc->flags));
test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W0_ACK,
test_bit(ENTRY_TXD_ACK, &desc->flags));
test_bit(ENTRY_TXD_ACK, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W0_TIMESTAMP,
test_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc->flags));
test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W0_OFDM,
test_bit(ENTRY_TXD_OFDM_RATE, &desc->flags));
rt2x00_set_field32(&word, TXD_W0_IFS, desc->ifs);
test_bit(ENTRY_TXD_OFDM_RATE, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs);
rt2x00_set_field32(&word, TXD_W0_RETRY_MODE,
!!(control->flags &
IEEE80211_TXCTL_LONG_RETRY_LIMIT));
rt2x00_set_field32(&word, TXD_W0_TKIP_MIC, 0);
rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skbdesc->data_len);
rt2x00_set_field32(&word, TXD_W0_BURST2,
test_bit(ENTRY_TXD_BURST, &desc->flags));
test_bit(ENTRY_TXD_BURST, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, CIPHER_NONE);
rt2x00_desc_write(txd, 0, word);
}
......@@ -1377,37 +1377,57 @@ static int rt73usb_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1)
return rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_AGC) * 2 - offset;
}
static void rt73usb_fill_rxdone(struct data_entry *entry,
struct rxdata_entry_desc *desc)
static void rt73usb_fill_rxdone(struct queue_entry *entry,
struct rxdone_entry_desc *rxdesc)
{
struct skb_desc *skbdesc = get_skb_desc(entry->skb);
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
__le32 *rxd = (__le32 *)entry->skb->data;
struct ieee80211_hdr *hdr =
(struct ieee80211_hdr *)entry->skb->data + entry->queue->desc_size;
int header_size = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control));
u32 word0;
u32 word1;
rt2x00_desc_read(rxd, 0, &word0);
rt2x00_desc_read(rxd, 1, &word1);
desc->flags = 0;
rxdesc->flags = 0;
if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR))
desc->flags |= RX_FLAG_FAILED_FCS_CRC;
rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC;
/*
* Obtain the status about this packet.
*/
desc->signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL);
desc->rssi = rt73usb_agc_to_rssi(entry->ring->rt2x00dev, word1);
desc->ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM);
desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
desc->my_bss = !!rt2x00_get_field32(word0, RXD_W0_MY_BSS);
rxdesc->signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL);
rxdesc->rssi = rt73usb_agc_to_rssi(entry->queue->rt2x00dev, word1);
rxdesc->ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM);
rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
rxdesc->my_bss = !!rt2x00_get_field32(word0, RXD_W0_MY_BSS);
/*
* The data behind the ieee80211 header must be
* aligned on a 4 byte boundary.
*/
if (header_size % 4 == 0) {
skb_push(entry->skb, 2);
memmove(entry->skb->data, entry->skb->data + 2,
entry->skb->len - 2);
}
/*
* Set descriptor and data pointer.
*/
skbdesc->data = entry->skb->data + entry->queue->desc_size;
skbdesc->data_len = entry->queue->data_size;
skbdesc->desc = entry->skb->data;
skbdesc->desc_len = entry->ring->desc_size;
skbdesc->data = entry->skb->data + entry->ring->desc_size;
skbdesc->data_len = desc->size;
skbdesc->desc_len = entry->queue->desc_size;
/*
* Remove descriptor from skb buffer and trim the whole thing
* down to only contain data.
*/
skb_pull(entry->skb, skbdesc->desc_len);
skb_trim(entry->skb, rxdesc->size);
}
/*
......@@ -1967,9 +1987,9 @@ static int rt73usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
struct ieee80211_tx_control *control)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct skb_desc *desc;
struct data_ring *ring;
struct data_entry *entry;
struct skb_frame_desc *skbdesc;
struct data_queue *queue;
struct queue_entry *entry;
int timeout;
/*
......@@ -1978,25 +1998,25 @@ static int rt73usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
* initialization.
*/
control->queue = IEEE80211_TX_QUEUE_BEACON;
ring = rt2x00lib_get_ring(rt2x00dev, control->queue);
entry = rt2x00_get_data_entry(ring);
queue = rt2x00queue_get_queue(rt2x00dev, control->queue);
entry = rt2x00queue_get_entry(queue, Q_INDEX);
/*
* Add the descriptor in front of the skb.
*/
skb_push(skb, ring->desc_size);
memset(skb->data, 0, ring->desc_size);
skb_push(skb, queue->desc_size);
memset(skb->data, 0, queue->desc_size);
/*
* Fill in skb descriptor
*/
desc = get_skb_desc(skb);
desc->desc_len = ring->desc_size;
desc->data_len = skb->len - ring->desc_size;
desc->desc = skb->data;
desc->data = skb->data + ring->desc_size;
desc->ring = ring;
desc->entry = entry;
skbdesc = get_skb_frame_desc(skb);
memset(skbdesc, 0, sizeof(*skbdesc));
skbdesc->data = skb->data + queue->desc_size;
skbdesc->data_len = queue->data_size;
skbdesc->desc = skb->data;
skbdesc->desc_len = queue->desc_size;
skbdesc->entry = entry;
rt2x00lib_write_tx_desc(rt2x00dev, skb, control);
......@@ -2057,12 +2077,34 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = {
.config = rt73usb_config,
};
static const struct data_queue_desc rt73usb_queue_rx = {
.entry_num = RX_ENTRIES,
.data_size = DATA_FRAME_SIZE,
.desc_size = RXD_DESC_SIZE,
.priv_size = sizeof(struct queue_entry_priv_usb_rx),
};
static const struct data_queue_desc rt73usb_queue_tx = {
.entry_num = TX_ENTRIES,
.data_size = DATA_FRAME_SIZE,
.desc_size = TXD_DESC_SIZE,
.priv_size = sizeof(struct queue_entry_priv_usb_tx),
};
static const struct data_queue_desc rt73usb_queue_bcn = {
.entry_num = BEACON_ENTRIES,
.data_size = MGMT_FRAME_SIZE,
.desc_size = TXINFO_SIZE,
.priv_size = sizeof(struct queue_entry_priv_usb_tx),
};
static const struct rt2x00_ops rt73usb_ops = {
.name = KBUILD_MODNAME,
.rxd_size = RXD_DESC_SIZE,
.txd_size = TXD_DESC_SIZE,
.eeprom_size = EEPROM_SIZE,
.rf_size = RF_SIZE,
.rx = &rt73usb_queue_rx,
.tx = &rt73usb_queue_tx,
.bcn = &rt73usb_queue_bcn,
.lib = &rt73usb_rt2x00_ops,
.hw = &rt73usb_mac80211_ops,
#ifdef CONFIG_RT2X00_LIB_DEBUGFS
......
......@@ -867,6 +867,7 @@ struct hw_pairwise_ta_entry {
* DMA descriptor defines.
*/
#define TXD_DESC_SIZE ( 6 * sizeof(__le32) )
#define TXINFO_SIZE ( 6 * sizeof(__le32) )
#define RXD_DESC_SIZE ( 6 * sizeof(__le32) )
/*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment