Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 213997
b: refs/heads/master
c: 7e613e1
h: refs/heads/master
i:
  213995: 4296ab3
v: v3
  • Loading branch information
Ivo van Doorn authored and John W. Linville committed Aug 16, 2010
1 parent 56fbd43 commit bed5d6a
Show file tree
Hide file tree
Showing 6 changed files with 129 additions and 63 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: c17512d846a4b063c8d3e708d82c0664d9c7182e
refs/heads/master: 7e613e1666d59b5364f7918b3427bf328ac5f9ca
9 changes: 8 additions & 1 deletion trunk/drivers/net/wireless/rt2x00/rt2x00.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
Copyright (C) 2010 Willow Garage <http://www.willowgarage.com>
Copyright (C) 2004 - 2010 Ivo van Doorn <IvDoorn@gmail.com>
Copyright (C) 2004 - 2009 Gertjan van Wingerde <gwingerde@gmail.com>
<http://rt2x00.serialmonkey.com>
Expand Down Expand Up @@ -862,6 +863,12 @@ struct rt2x00_dev {
*/
struct work_struct intf_work;

/**
* Scheduled work for TX/RX done handling (USB devices)
*/
struct work_struct rxdone_work;
struct work_struct txdone_work;

/*
* Data queue arrays for RX, TX and Beacon.
* The Beacon array also contains the Atim queue
Expand Down
35 changes: 12 additions & 23 deletions trunk/drivers/net/wireless/rt2x00/rt2x00dev.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
Copyright (C) 2010 Willow Garage <http://www.willowgarage.com>
Copyright (C) 2004 - 2010 Ivo van Doorn <IvDoorn@gmail.com>
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
Expand Down Expand Up @@ -383,15 +384,7 @@ void rt2x00lib_txdone(struct queue_entry *entry,
* send the status report back.
*/
if (!(skbdesc_flags & SKBDESC_NOT_MAC80211))
/*
* Only PCI and SOC devices process the tx status in process
* context. Hence use ieee80211_tx_status for PCI and SOC
* devices and stick to ieee80211_tx_status_irqsafe for USB.
*/
if (rt2x00_is_usb(rt2x00dev))
ieee80211_tx_status_irqsafe(rt2x00dev->hw, entry->skb);
else
ieee80211_tx_status(rt2x00dev->hw, entry->skb);
ieee80211_tx_status(rt2x00dev->hw, entry->skb);
else
dev_kfree_skb_any(entry->skb);

Expand All @@ -403,7 +396,6 @@ void rt2x00lib_txdone(struct queue_entry *entry,

rt2x00dev->ops->lib->clear_entry(entry);

clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE);

/*
Expand Down Expand Up @@ -463,6 +455,10 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
struct ieee80211_rx_status *rx_status = &rt2x00dev->rx_status;
unsigned int header_length;
int rate_idx;

if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags))
goto submit_entry;

/*
* Allocate a new sk_buffer. If no new buffer available, drop the
* received frame and reuse the existing buffer.
Expand Down Expand Up @@ -540,26 +536,17 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
*/
rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_RXDONE, entry->skb);
memcpy(IEEE80211_SKB_RXCB(entry->skb), rx_status, sizeof(*rx_status));

/*
* Currently only PCI and SOC devices handle rx interrupts in process
* context. Hence, use ieee80211_rx_irqsafe for USB and ieee80211_rx_ni
* for PCI and SOC devices.
*/
if (rt2x00_is_usb(rt2x00dev))
ieee80211_rx_irqsafe(rt2x00dev->hw, entry->skb);
else
ieee80211_rx_ni(rt2x00dev->hw, entry->skb);
ieee80211_rx_ni(rt2x00dev->hw, entry->skb);

/*
* Replace the skb with the freshly allocated one.
*/
entry->skb = skb;
entry->flags = 0;

submit_entry:
rt2x00dev->ops->lib->clear_entry(entry);

rt2x00queue_index_inc(entry->queue, Q_INDEX);
rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE);
}
EXPORT_SYMBOL_GPL(rt2x00lib_rxdone);

Expand Down Expand Up @@ -1017,6 +1004,8 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev)
* Stop all work.
*/
cancel_work_sync(&rt2x00dev->intf_work);
cancel_work_sync(&rt2x00dev->rxdone_work);
cancel_work_sync(&rt2x00dev->txdone_work);

/*
* Uninitialize device.
Expand Down
7 changes: 4 additions & 3 deletions trunk/drivers/net/wireless/rt2x00/rt2x00queue.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
Copyright (C) 2010 Willow Garage <http://www.willowgarage.com>
Copyright (C) 2004 - 2010 Ivo van Doorn <IvDoorn@gmail.com>
Copyright (C) 2004 - 2009 Gertjan van Wingerde <gwingerde@gmail.com>
<http://rt2x00.serialmonkey.com>
Expand Down Expand Up @@ -730,9 +731,9 @@ void rt2x00queue_init_queues(struct rt2x00_dev *rt2x00dev)
rt2x00queue_reset(queue);

for (i = 0; i < queue->limit; i++) {
queue->entries[i].flags = 0;

rt2x00dev->ops->lib->clear_entry(&queue->entries[i]);
if (queue->qid == QID_RX)
rt2x00queue_index_inc(queue, Q_INDEX);
}
}
}
Expand Down
6 changes: 5 additions & 1 deletion trunk/drivers/net/wireless/rt2x00/rt2x00queue.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
Copyright (C) 2004 - 2010 Ivo van Doorn <IvDoorn@gmail.com>
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
Expand Down Expand Up @@ -363,12 +363,16 @@ struct txentry_desc {
* the device has signaled it is done with it.
* @ENTRY_DATA_PENDING: This entry contains a valid frame and is waiting
* for the signal to start sending.
* @ENTRY_DATA_IO_FAILED: Hardware indicated that an IO error occured
* while transfering the data to the hardware. No TX status report will
* be expected from the hardware.
*/
enum queue_entry_flags {
ENTRY_BCN_ASSIGNED,
ENTRY_OWNER_DEVICE_DATA,
ENTRY_OWNER_DEVICE_CRYPTO,
ENTRY_DATA_PENDING,
ENTRY_DATA_IO_FAILED
};

/**
Expand Down
133 changes: 99 additions & 34 deletions trunk/drivers/net/wireless/rt2x00/rt2x00usb.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
Copyright (C) 2010 Willow Garage <http://www.willowgarage.com>
Copyright (C) 2004 - 2010 Ivo van Doorn <IvDoorn@gmail.com>
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
Expand Down Expand Up @@ -167,35 +168,69 @@ EXPORT_SYMBOL_GPL(rt2x00usb_regbusy_read);
/*
* TX data handlers.
*/
static void rt2x00usb_interrupt_txdone(struct urb *urb)
static void rt2x00usb_work_txdone_entry(struct queue_entry *entry)
{
struct queue_entry *entry = (struct queue_entry *)urb->context;
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct txdone_entry_desc txdesc;

if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) ||
!test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
return;

/*
* Obtain the status about this packet.
* Note that when the status is 0 it does not mean the
* If the transfer to hardware succeeded, it does not mean the
* frame was send out correctly. It only means the frame
* was succesfully pushed to the hardware, we have no
* way to determine the transmission status right now.
* (Only indirectly by looking at the failed TX counters
* in the register).
*/
txdesc.flags = 0;
if (!urb->status)
__set_bit(TXDONE_UNKNOWN, &txdesc.flags);
else
if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags))
__set_bit(TXDONE_FAILURE, &txdesc.flags);
else
__set_bit(TXDONE_UNKNOWN, &txdesc.flags);
txdesc.retry = 0;

rt2x00lib_txdone(entry, &txdesc);
}

static void rt2x00usb_work_txdone(struct work_struct *work)
{
struct rt2x00_dev *rt2x00dev =
container_of(work, struct rt2x00_dev, txdone_work);
struct data_queue *queue;
struct queue_entry *entry;

tx_queue_for_each(rt2x00dev, queue) {
while (!rt2x00queue_empty(queue)) {
entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);

if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
break;

rt2x00usb_work_txdone_entry(entry);
}
}
}

static void rt2x00usb_interrupt_txdone(struct urb *urb)
{
struct queue_entry *entry = (struct queue_entry *)urb->context;
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;

if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) ||
!__test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
return;

/*
* Check if the frame was correctly uploaded
*/
if (urb->status)
__set_bit(ENTRY_DATA_IO_FAILED, &entry->flags);

/*
* Schedule the delayed work for reading the TX status
* from the device.
*/
ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->txdone_work);
}

static inline void rt2x00usb_kick_tx_entry(struct queue_entry *entry)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
Expand Down Expand Up @@ -294,6 +329,7 @@ EXPORT_SYMBOL_GPL(rt2x00usb_kill_tx_queue);

static void rt2x00usb_watchdog_reset_tx(struct data_queue *queue)
{
struct queue_entry *entry;
struct queue_entry_priv_usb *entry_priv;
unsigned short threshold = queue->threshold;

Expand All @@ -313,14 +349,22 @@ static void rt2x00usb_watchdog_reset_tx(struct data_queue *queue)
* Reset all currently uploaded TX frames.
*/
while (!rt2x00queue_empty(queue)) {
entry_priv = rt2x00queue_get_entry(queue, Q_INDEX_DONE)->priv_data;
entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
entry_priv = entry->priv_data;
usb_kill_urb(entry_priv->urb);

/*
* We need a short delay here to wait for
* the URB to be canceled and invoked the tx_done handler.
* the URB to be canceled
*/
udelay(200);
do {
udelay(100);
} while (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags));

/*
* Invoke the TX done handler
*/
rt2x00usb_work_txdone_entry(entry);
}

/*
Expand All @@ -345,38 +389,56 @@ EXPORT_SYMBOL_GPL(rt2x00usb_watchdog);
/*
* RX data handlers.
*/
static void rt2x00usb_work_rxdone(struct work_struct *work)
{
struct rt2x00_dev *rt2x00dev =
container_of(work, struct rt2x00_dev, rxdone_work);
struct queue_entry *entry;
struct skb_frame_desc *skbdesc;
u8 rxd[32];

while (!rt2x00queue_empty(rt2x00dev->rx)) {
entry = rt2x00queue_get_entry(rt2x00dev->rx, Q_INDEX_DONE);

if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
break;

/*
* Fill in desc fields of the skb descriptor
*/
skbdesc = get_skb_frame_desc(entry->skb);
skbdesc->desc = rxd;
skbdesc->desc_len = entry->queue->desc_size;

/*
* Send the frame to rt2x00lib for further processing.
*/
rt2x00lib_rxdone(rt2x00dev, entry);
}
}

static void rt2x00usb_interrupt_rxdone(struct urb *urb)
{
struct queue_entry *entry = (struct queue_entry *)urb->context;
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
u8 rxd[32];

if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) ||
!test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
!__test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
return;

/*
* Check if the received data is simply too small
* to be actually valid, or if the urb is signaling
* a problem.
*/
if (urb->actual_length < entry->queue->desc_size || urb->status) {
set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
usb_submit_urb(urb, GFP_ATOMIC);
return;
}

/*
* Fill in desc fields of the skb descriptor
*/
skbdesc->desc = rxd;
skbdesc->desc_len = entry->queue->desc_size;
if (urb->actual_length < entry->queue->desc_size || urb->status)
__set_bit(ENTRY_DATA_IO_FAILED, &entry->flags);

/*
* Send the frame to rt2x00lib for further processing.
* Schedule the delayed work for reading the RX status
* from the device.
*/
rt2x00lib_rxdone(rt2x00dev, entry);
ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->rxdone_work);
}

/*
Expand Down Expand Up @@ -405,6 +467,8 @@ void rt2x00usb_clear_entry(struct queue_entry *entry)
struct queue_entry_priv_usb *entry_priv = entry->priv_data;
int pipe;

entry->flags = 0;

if (entry->queue->qid == QID_RX) {
pipe = usb_rcvbulkpipe(usb_dev, entry->queue->usb_endpoint);
usb_fill_bulk_urb(entry_priv->urb, usb_dev, pipe,
Expand All @@ -413,8 +477,6 @@ void rt2x00usb_clear_entry(struct queue_entry *entry)

set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
usb_submit_urb(entry_priv->urb, GFP_ATOMIC);
} else {
entry->flags = 0;
}
}
EXPORT_SYMBOL_GPL(rt2x00usb_clear_entry);
Expand Down Expand Up @@ -659,6 +721,9 @@ int rt2x00usb_probe(struct usb_interface *usb_intf,

rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_USB);

INIT_WORK(&rt2x00dev->rxdone_work, rt2x00usb_work_rxdone);
INIT_WORK(&rt2x00dev->txdone_work, rt2x00usb_work_txdone);

retval = rt2x00usb_alloc_reg(rt2x00dev);
if (retval)
goto exit_free_device;
Expand Down

0 comments on commit bed5d6a

Please sign in to comment.