Commit c4da0048 authored by Gertjan van Wingerde's avatar Gertjan van Wingerde Committed by John W. Linville

rt2x00: Replace statically allocated DMA buffers with mapped skb's.

The current PCI drivers require a lot of pre-allocated DMA buffers. Reduce this
by using dynamically mapped skb's (using pci_map_single) instead of the pre-
allocated DMA buffers that are allocated at device start-up time.

At the same time move common RX path code into rt2x00lib from rt2x00pci and
rt2x00usb, as the RX paths now are now almost the same.
Signed-off-by: default avatarGertjan van Wingerde <gwingerde@kpnplanet.nl>
Signed-off-by: default avatarIvo van Doorn <IvDoorn@gmail.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 30caa6e3
...@@ -632,15 +632,15 @@ static void rt2400pci_init_rxentry(struct rt2x00_dev *rt2x00dev, ...@@ -632,15 +632,15 @@ static void rt2400pci_init_rxentry(struct rt2x00_dev *rt2x00dev,
struct queue_entry *entry) struct queue_entry *entry)
{ {
struct queue_entry_priv_pci *entry_priv = entry->priv_data; struct queue_entry_priv_pci *entry_priv = entry->priv_data;
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
u32 word; u32 word;
rt2x00_desc_read(entry_priv->desc, 2, &word); rt2x00_desc_read(entry_priv->desc, 2, &word);
rt2x00_set_field32(&word, RXD_W2_BUFFER_LENGTH, rt2x00_set_field32(&word, RXD_W2_BUFFER_LENGTH, entry->skb->len);
entry->queue->data_size);
rt2x00_desc_write(entry_priv->desc, 2, word); rt2x00_desc_write(entry_priv->desc, 2, word);
rt2x00_desc_read(entry_priv->desc, 1, &word); rt2x00_desc_read(entry_priv->desc, 1, &word);
rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, entry_priv->data_dma); rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma);
rt2x00_desc_write(entry_priv->desc, 1, word); rt2x00_desc_write(entry_priv->desc, 1, word);
rt2x00_desc_read(entry_priv->desc, 0, &word); rt2x00_desc_read(entry_priv->desc, 0, &word);
...@@ -1012,7 +1012,7 @@ static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, ...@@ -1012,7 +1012,7 @@ static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
* Start writing the descriptor words. * Start writing the descriptor words.
*/ */
rt2x00_desc_read(entry_priv->desc, 1, &word); rt2x00_desc_read(entry_priv->desc, 1, &word);
rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, entry_priv->data_dma); rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma);
rt2x00_desc_write(entry_priv->desc, 1, word); rt2x00_desc_write(entry_priv->desc, 1, word);
rt2x00_desc_read(txd, 2, &word); rt2x00_desc_read(txd, 2, &word);
...@@ -1412,9 +1412,10 @@ static int rt2400pci_probe_hw(struct rt2x00_dev *rt2x00dev) ...@@ -1412,9 +1412,10 @@ static int rt2400pci_probe_hw(struct rt2x00_dev *rt2x00dev)
rt2400pci_probe_hw_mode(rt2x00dev); rt2400pci_probe_hw_mode(rt2x00dev);
/* /*
* This device requires the atim queue * This device requires the atim queue and DMA-mapped skbs.
*/ */
__set_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags); __set_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags);
__set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags);
/* /*
* Set the rssi offset. * Set the rssi offset.
...@@ -1526,7 +1527,7 @@ static int rt2400pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) ...@@ -1526,7 +1527,7 @@ static int rt2400pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
* Write entire beacon with descriptor to register, * Write entire beacon with descriptor to register,
* and kick the beacon generator. * and kick the beacon generator.
*/ */
memcpy(entry_priv->data, skb->data, skb->len); rt2x00queue_map_txskb(rt2x00dev, intf->beacon->skb);
rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc); rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc);
rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON); rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON);
......
...@@ -727,10 +727,11 @@ static void rt2500pci_init_rxentry(struct rt2x00_dev *rt2x00dev, ...@@ -727,10 +727,11 @@ static void rt2500pci_init_rxentry(struct rt2x00_dev *rt2x00dev,
struct queue_entry *entry) struct queue_entry *entry)
{ {
struct queue_entry_priv_pci *entry_priv = entry->priv_data; struct queue_entry_priv_pci *entry_priv = entry->priv_data;
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
u32 word; u32 word;
rt2x00_desc_read(entry_priv->desc, 1, &word); rt2x00_desc_read(entry_priv->desc, 1, &word);
rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, entry_priv->data_dma); rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma);
rt2x00_desc_write(entry_priv->desc, 1, word); rt2x00_desc_write(entry_priv->desc, 1, word);
rt2x00_desc_read(entry_priv->desc, 0, &word); rt2x00_desc_read(entry_priv->desc, 0, &word);
...@@ -1171,7 +1172,7 @@ static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, ...@@ -1171,7 +1172,7 @@ static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
* Start writing the descriptor words. * Start writing the descriptor words.
*/ */
rt2x00_desc_read(entry_priv->desc, 1, &word); rt2x00_desc_read(entry_priv->desc, 1, &word);
rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, entry_priv->data_dma); rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma);
rt2x00_desc_write(entry_priv->desc, 1, word); rt2x00_desc_write(entry_priv->desc, 1, word);
rt2x00_desc_read(txd, 2, &word); rt2x00_desc_read(txd, 2, &word);
...@@ -1752,9 +1753,10 @@ static int rt2500pci_probe_hw(struct rt2x00_dev *rt2x00dev) ...@@ -1752,9 +1753,10 @@ static int rt2500pci_probe_hw(struct rt2x00_dev *rt2x00dev)
rt2500pci_probe_hw_mode(rt2x00dev); rt2500pci_probe_hw_mode(rt2x00dev);
/* /*
* This device requires the atim queue * This device requires the atim queue and DMA-mapped skbs.
*/ */
__set_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags); __set_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags);
__set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags);
/* /*
* Set the rssi offset. * Set the rssi offset.
...@@ -1842,7 +1844,7 @@ static int rt2500pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) ...@@ -1842,7 +1844,7 @@ static int rt2500pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
* Write entire beacon with descriptor to register, * Write entire beacon with descriptor to register,
* and kick the beacon generator. * and kick the beacon generator.
*/ */
memcpy(entry_priv->data, skb->data, skb->len); rt2x00queue_map_txskb(rt2x00dev, intf->beacon->skb);
rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc); rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc);
rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON); rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON);
......
...@@ -601,6 +601,7 @@ enum rt2x00_flags { ...@@ -601,6 +601,7 @@ enum rt2x00_flags {
DRIVER_REQUIRE_BEACON_GUARD, DRIVER_REQUIRE_BEACON_GUARD,
DRIVER_REQUIRE_ATIM_QUEUE, DRIVER_REQUIRE_ATIM_QUEUE,
DRIVER_REQUIRE_SCHEDULED, DRIVER_REQUIRE_SCHEDULED,
DRIVER_REQUIRE_DMA,
/* /*
* Driver configuration * Driver configuration
...@@ -899,16 +900,33 @@ static inline u16 get_duration_res(const unsigned int size, const u8 rate) ...@@ -899,16 +900,33 @@ static inline u16 get_duration_res(const unsigned int size, const u8 rate)
} }
/** /**
* rt2x00queue_alloc_skb - allocate a skb. * rt2x00queue_alloc_rxskb - allocate a skb for RX purposes.
* @rt2x00dev: Pointer to &struct rt2x00_dev.
* @queue: The queue for which the skb will be applicable. * @queue: The queue for which the skb will be applicable.
*/ */
struct sk_buff *rt2x00queue_alloc_skb(struct data_queue *queue); struct sk_buff *rt2x00queue_alloc_rxskb(struct rt2x00_dev *rt2x00dev,
struct queue_entry *entry);
/**
* rt2x00queue_map_txskb - Map a skb into DMA for TX purposes.
* @rt2x00dev: Pointer to &struct rt2x00_dev.
* @skb: The skb to map.
*/
void rt2x00queue_map_txskb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
/**
* rt2x00queue_unmap_skb - Unmap a skb from DMA.
* @rt2x00dev: Pointer to &struct rt2x00_dev.
* @skb: The skb to unmap.
*/
void rt2x00queue_unmap_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
/** /**
* rt2x00queue_free_skb - free a skb * rt2x00queue_free_skb - free a skb
* @rt2x00dev: Pointer to &struct rt2x00_dev.
* @skb: The skb to free. * @skb: The skb to free.
*/ */
void rt2x00queue_free_skb(struct sk_buff *skb); void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
/** /**
* rt2x00queue_create_tx_descriptor - Create TX descriptor from mac80211 input * rt2x00queue_create_tx_descriptor - Create TX descriptor from mac80211 input
...@@ -977,8 +995,8 @@ void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index); ...@@ -977,8 +995,8 @@ void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index);
void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev); void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev);
void rt2x00lib_txdone(struct queue_entry *entry, void rt2x00lib_txdone(struct queue_entry *entry,
struct txdone_entry_desc *txdesc); struct txdone_entry_desc *txdesc);
void rt2x00lib_rxdone(struct queue_entry *entry, void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
struct rxdone_entry_desc *rxdesc); struct queue_entry *entry);
/* /*
* mac80211 handlers. * mac80211 handlers.
......
...@@ -468,6 +468,7 @@ static void rt2x00lib_intf_scheduled(struct work_struct *work) ...@@ -468,6 +468,7 @@ static void rt2x00lib_intf_scheduled(struct work_struct *work)
static void rt2x00lib_beacondone_iter(void *data, u8 *mac, static void rt2x00lib_beacondone_iter(void *data, u8 *mac,
struct ieee80211_vif *vif) struct ieee80211_vif *vif)
{ {
struct rt2x00_dev *rt2x00dev = data;
struct rt2x00_intf *intf = vif_to_intf(vif); struct rt2x00_intf *intf = vif_to_intf(vif);
if (vif->type != IEEE80211_IF_TYPE_AP && if (vif->type != IEEE80211_IF_TYPE_AP &&
...@@ -477,7 +478,7 @@ static void rt2x00lib_beacondone_iter(void *data, u8 *mac, ...@@ -477,7 +478,7 @@ static void rt2x00lib_beacondone_iter(void *data, u8 *mac,
/* /*
* Clean up the beacon skb. * Clean up the beacon skb.
*/ */
dev_kfree_skb_irq(intf->beacon->skb); rt2x00queue_free_skb(rt2x00dev, intf->beacon->skb);
intf->beacon->skb = NULL; intf->beacon->skb = NULL;
spin_lock(&intf->lock); spin_lock(&intf->lock);
...@@ -555,34 +556,55 @@ void rt2x00lib_txdone(struct queue_entry *entry, ...@@ -555,34 +556,55 @@ void rt2x00lib_txdone(struct queue_entry *entry,
} }
EXPORT_SYMBOL_GPL(rt2x00lib_txdone); EXPORT_SYMBOL_GPL(rt2x00lib_txdone);
void rt2x00lib_rxdone(struct queue_entry *entry, void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
struct rxdone_entry_desc *rxdesc) struct queue_entry *entry)
{ {
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct rxdone_entry_desc rxdesc;
struct sk_buff *skb;
struct ieee80211_rx_status *rx_status = &rt2x00dev->rx_status; struct ieee80211_rx_status *rx_status = &rt2x00dev->rx_status;
unsigned int header_size = ieee80211_get_hdrlen_from_skb(entry->skb);
struct ieee80211_supported_band *sband; struct ieee80211_supported_band *sband;
struct ieee80211_hdr *hdr; struct ieee80211_hdr *hdr;
const struct rt2x00_rate *rate; const struct rt2x00_rate *rate;
unsigned int header_size;
unsigned int align; unsigned int align;
unsigned int i; unsigned int i;
int idx = -1; int idx = -1;
/*
* Allocate a new sk_buffer. If no new buffer available, drop the
* received frame and reuse the existing buffer.
*/
skb = rt2x00queue_alloc_rxskb(rt2x00dev, entry);
if (!skb)
return;
/*
* Unmap the skb.
*/
rt2x00queue_unmap_skb(rt2x00dev, entry->skb);
/*
* Extract the RXD details.
*/
memset(&rxdesc, 0, sizeof(rxdesc));
rt2x00dev->ops->lib->fill_rxdone(entry, &rxdesc);
/* /*
* The data behind the ieee80211 header must be * The data behind the ieee80211 header must be
* aligned on a 4 byte boundary. * aligned on a 4 byte boundary.
*/ */
header_size = ieee80211_get_hdrlen_from_skb(entry->skb);
align = ((unsigned long)(entry->skb->data + header_size)) & 3; align = ((unsigned long)(entry->skb->data + header_size)) & 3;
if (align) { if (align) {
skb_push(entry->skb, align); skb_push(entry->skb, align);
/* Move entire frame in 1 command */ /* Move entire frame in 1 command */
memmove(entry->skb->data, entry->skb->data + align, memmove(entry->skb->data, entry->skb->data + align,
rxdesc->size); rxdesc.size);
} }
/* Update data pointers, trim buffer to correct size */ /* Update data pointers, trim buffer to correct size */
skb_trim(entry->skb, rxdesc->size); skb_trim(entry->skb, rxdesc.size);
/* /*
* Update RX statistics. * Update RX statistics.
...@@ -591,10 +613,10 @@ void rt2x00lib_rxdone(struct queue_entry *entry, ...@@ -591,10 +613,10 @@ void rt2x00lib_rxdone(struct queue_entry *entry,
for (i = 0; i < sband->n_bitrates; i++) { for (i = 0; i < sband->n_bitrates; i++) {
rate = rt2x00_get_rate(sband->bitrates[i].hw_value); rate = rt2x00_get_rate(sband->bitrates[i].hw_value);
if (((rxdesc->dev_flags & RXDONE_SIGNAL_PLCP) && if (((rxdesc.dev_flags & RXDONE_SIGNAL_PLCP) &&
(rate->plcp == rxdesc->signal)) || (rate->plcp == rxdesc.signal)) ||
(!(rxdesc->dev_flags & RXDONE_SIGNAL_PLCP) && (!(rxdesc.dev_flags & RXDONE_SIGNAL_PLCP) &&
(rate->bitrate == rxdesc->signal))) { (rate->bitrate == rxdesc.signal))) {
idx = i; idx = i;
break; break;
} }
...@@ -602,8 +624,8 @@ void rt2x00lib_rxdone(struct queue_entry *entry, ...@@ -602,8 +624,8 @@ void rt2x00lib_rxdone(struct queue_entry *entry,
if (idx < 0) { if (idx < 0) {
WARNING(rt2x00dev, "Frame received with unrecognized signal," WARNING(rt2x00dev, "Frame received with unrecognized signal,"
"signal=0x%.2x, plcp=%d.\n", rxdesc->signal, "signal=0x%.2x, plcp=%d.\n", rxdesc.signal,
!!(rxdesc->dev_flags & RXDONE_SIGNAL_PLCP)); !!(rxdesc.dev_flags & RXDONE_SIGNAL_PLCP));
idx = 0; idx = 0;
} }
...@@ -612,16 +634,16 @@ void rt2x00lib_rxdone(struct queue_entry *entry, ...@@ -612,16 +634,16 @@ void rt2x00lib_rxdone(struct queue_entry *entry,
*/ */
hdr = (struct ieee80211_hdr *)entry->skb->data; hdr = (struct ieee80211_hdr *)entry->skb->data;
if (ieee80211_is_beacon(hdr->frame_control) && if (ieee80211_is_beacon(hdr->frame_control) &&
(rxdesc->dev_flags & RXDONE_MY_BSS)) (rxdesc.dev_flags & RXDONE_MY_BSS))
rt2x00lib_update_link_stats(&rt2x00dev->link, rxdesc->rssi); rt2x00lib_update_link_stats(&rt2x00dev->link, rxdesc.rssi);
rt2x00dev->link.qual.rx_success++; rt2x00dev->link.qual.rx_success++;
rx_status->rate_idx = idx; rx_status->rate_idx = idx;
rx_status->qual = rx_status->qual =
rt2x00lib_calculate_link_signal(rt2x00dev, rxdesc->rssi); rt2x00lib_calculate_link_signal(rt2x00dev, rxdesc.rssi);
rx_status->signal = rxdesc->rssi; rx_status->signal = rxdesc.rssi;
rx_status->flag = rxdesc->flags; rx_status->flag = rxdesc.flags;
rx_status->antenna = rt2x00dev->link.ant.active.rx; rx_status->antenna = rt2x00dev->link.ant.active.rx;
/* /*
...@@ -630,7 +652,11 @@ void rt2x00lib_rxdone(struct queue_entry *entry, ...@@ -630,7 +652,11 @@ void rt2x00lib_rxdone(struct queue_entry *entry,
*/ */
rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_RXDONE, entry->skb); rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_RXDONE, entry->skb);
ieee80211_rx_irqsafe(rt2x00dev->hw, entry->skb, rx_status); ieee80211_rx_irqsafe(rt2x00dev->hw, entry->skb, rx_status);
entry->skb = NULL;
/*
* Replace the skb with the freshly allocated one.
*/
entry->skb = skb;
} }
EXPORT_SYMBOL_GPL(rt2x00lib_rxdone); EXPORT_SYMBOL_GPL(rt2x00lib_rxdone);
......
...@@ -65,7 +65,7 @@ int rt2x00pci_write_tx_data(struct queue_entry *entry) ...@@ -65,7 +65,7 @@ int rt2x00pci_write_tx_data(struct queue_entry *entry)
skbdesc->desc_len = entry->queue->desc_size; skbdesc->desc_len = entry->queue->desc_size;
skbdesc->entry = entry; skbdesc->entry = entry;
memcpy(entry_priv->data, entry->skb->data, entry->skb->len); rt2x00queue_map_txskb(entry->queue->rt2x00dev, entry->skb);
return 0; return 0;
} }
...@@ -74,75 +74,38 @@ EXPORT_SYMBOL_GPL(rt2x00pci_write_tx_data); ...@@ -74,75 +74,38 @@ EXPORT_SYMBOL_GPL(rt2x00pci_write_tx_data);
/* /*
* TX/RX data handlers. * TX/RX data handlers.
*/ */
static void rt2x00pci_rxdone_entry(struct rt2x00_dev *rt2x00dev, void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
struct queue_entry *entry)
{ {
struct sk_buff *skb; struct data_queue *queue = rt2x00dev->rx;
struct queue_entry *entry;
struct queue_entry_priv_pci *entry_priv;
struct skb_frame_desc *skbdesc; struct skb_frame_desc *skbdesc;
struct rxdone_entry_desc rxdesc; u32 word;
struct queue_entry_priv_pci *entry_priv = entry->priv_data;
/*
* Allocate a new sk_buffer. If no new buffer available, drop the
* received frame and reuse the existing buffer.
*/
skb = rt2x00queue_alloc_skb(entry->queue);
if (!skb)
return;
/* while (1) {
* Extract the RXD details. entry = rt2x00queue_get_entry(queue, Q_INDEX);
*/ entry_priv = entry->priv_data;
memset(&rxdesc, 0, sizeof(rxdesc)); rt2x00_desc_read(entry_priv->desc, 0, &word);
rt2x00dev->ops->lib->fill_rxdone(entry, &rxdesc);
/* if (rt2x00_get_field32(word, RXD_ENTRY_OWNER_NIC))
* Copy the received data to the entries' skb. break;
*/
memcpy(entry->skb->data, entry_priv->data, rxdesc.size);
skb_trim(entry->skb, rxdesc.size);
/* /*
* Fill in skb descriptor * Fill in desc fields of the skb descriptor
*/ */
skbdesc = get_skb_frame_desc(entry->skb); skbdesc = get_skb_frame_desc(entry->skb);
memset(skbdesc, 0, sizeof(*skbdesc));
skbdesc->desc = entry_priv->desc; skbdesc->desc = entry_priv->desc;
skbdesc->desc_len = entry->queue->desc_size; skbdesc->desc_len = entry->queue->desc_size;
skbdesc->entry = entry;
/* /*
* Send the frame to rt2x00lib for further processing. * Send the frame to rt2x00lib for further processing.
*/ */
rt2x00lib_rxdone(entry, &rxdesc); rt2x00lib_rxdone(rt2x00dev, entry);
/* /*
* Replace the entries' skb with the newly allocated one. * Reset the RXD for this entry.
*/ */
entry->skb = skb; rt2x00dev->ops->lib->init_rxentry(rt2x00dev, entry);
}
void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
{
struct data_queue *queue = rt2x00dev->rx;
struct queue_entry *entry;
struct queue_entry_priv_pci *entry_priv;
u32 word;
while (1) {
entry = rt2x00queue_get_entry(queue, Q_INDEX);
entry_priv = entry->priv_data;
rt2x00_desc_read(entry_priv->desc, 0, &word);
if (rt2x00_get_field32(word, RXD_ENTRY_OWNER_NIC))
break;
rt2x00pci_rxdone_entry(rt2x00dev, entry);
if (test_bit(DEVICE_ENABLED_RADIO, &queue->rt2x00dev->flags)) {
rt2x00_set_field32(&word, RXD_ENTRY_OWNER_NIC, 1);
rt2x00_desc_write(entry_priv->desc, 0, word);
}
rt2x00queue_index_inc(queue, Q_INDEX); rt2x00queue_index_inc(queue, Q_INDEX);
} }
...@@ -156,6 +119,11 @@ void rt2x00pci_txdone(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry, ...@@ -156,6 +119,11 @@ void rt2x00pci_txdone(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry,
enum data_queue_qid qid = skb_get_queue_mapping(entry->skb); enum data_queue_qid qid = skb_get_queue_mapping(entry->skb);
u32 word; u32 word;
/*
* Unmap the skb.
*/
rt2x00queue_unmap_skb(rt2x00dev, entry->skb);
rt2x00lib_txdone(entry, txdesc); rt2x00lib_txdone(entry, txdesc);
/* /*
...@@ -185,33 +153,6 @@ EXPORT_SYMBOL_GPL(rt2x00pci_txdone); ...@@ -185,33 +153,6 @@ EXPORT_SYMBOL_GPL(rt2x00pci_txdone);
/* /*
* Device initialization handlers. * Device initialization handlers.
*/ */
#define desc_size(__queue) \
({ \
((__queue)->limit * (__queue)->desc_size);\
})
#define data_size(__queue) \
({ \
((__queue)->limit * (__queue)->data_size);\
})
#define dma_size(__queue) \
({ \
data_size(__queue) + desc_size(__queue);\
})
#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); \
})
static int rt2x00pci_alloc_queue_dma(struct rt2x00_dev *rt2x00dev, static int rt2x00pci_alloc_queue_dma(struct rt2x00_dev *rt2x00dev,
struct data_queue *queue) struct data_queue *queue)
{ {
...@@ -223,22 +164,21 @@ static int rt2x00pci_alloc_queue_dma(struct rt2x00_dev *rt2x00dev, ...@@ -223,22 +164,21 @@ static int rt2x00pci_alloc_queue_dma(struct rt2x00_dev *rt2x00dev,
/* /*
* Allocate DMA memory for descriptor and buffer. * Allocate DMA memory for descriptor and buffer.
*/ */
addr = dma_alloc_coherent(rt2x00dev->dev, dma_size(queue), &dma, addr = dma_alloc_coherent(rt2x00dev->dev,
GFP_KERNEL | GFP_DMA); queue->limit * queue->desc_size,
&dma, GFP_KERNEL | GFP_DMA);
if (!addr) if (!addr)
return -ENOMEM; return -ENOMEM;
memset(addr, 0, dma_size(queue)); memset(addr, 0, queue->limit * queue->desc_size);
/* /*
* Initialize all queue entries to contain valid addresses. * Initialize all queue entries to contain valid addresses.
*/ */
for (i = 0; i < queue->limit; i++) { for (i = 0; i < queue->limit; i++) {
entry_priv = queue->entries[i].priv_data; entry_priv = queue->entries[i].priv_data;
entry_priv->desc = desc_offset(queue, addr, i); entry_priv->desc = addr + i * queue->desc_size;
entry_priv->desc_dma = desc_offset(queue, dma, i); entry_priv->desc_dma = dma + i * queue->desc_size;
entry_priv->data = data_offset(queue, addr, i);
entry_priv->data_dma = data_offset(queue, dma, i);
} }
return 0; return 0;
...@@ -250,10 +190,11 @@ static void rt2x00pci_free_queue_dma(struct rt2x00_dev *rt2x00dev, ...@@ -250,10 +190,11 @@ static void rt2x00pci_free_queue_dma(struct rt2x00_dev *rt2x00dev,
struct queue_entry_priv_pci *entry_priv = struct queue_entry_priv_pci *entry_priv =
queue->entries[0].priv_data; queue->entries[0].priv_data;
if (entry_priv->data) if (entry_priv->desc)
dma_free_coherent(rt2x00dev->dev, dma_size(queue), dma_free_coherent(rt2x00dev->dev,
entry_priv->data, entry_priv->data_dma); queue->limit * queue->desc_size,
entry_priv->data = NULL; entry_priv->desc, entry_priv->desc_dma);
entry_priv->desc = NULL;
} }
int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev) int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev)
......
...@@ -107,9 +107,6 @@ int rt2x00pci_write_tx_data(struct queue_entry *entry); ...@@ -107,9 +107,6 @@ int rt2x00pci_write_tx_data(struct queue_entry *entry);
struct queue_entry_priv_pci { struct queue_entry_priv_pci {
__le32 *desc; __le32 *desc;
dma_addr_t desc_dma; dma_addr_t desc_dma;
void *data;
dma_addr_t data_dma;
}; };
/** /**
......
...@@ -25,21 +25,24 @@ ...@@ -25,21 +25,24 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/dma-mapping.h>
#include "rt2x00.h" #include "rt2x00.h"
#include "rt2x00lib.h" #include "rt2x00lib.h"
struct sk_buff *rt2x00queue_alloc_skb(struct data_queue *queue) struct sk_buff *rt2x00queue_alloc_rxskb(struct rt2x00_dev *rt2x00dev,
struct queue_entry *entry)
{ {
struct sk_buff *skb;
unsigned int frame_size; unsigned int frame_size;
unsigned int reserved_size; unsigned int reserved_size;
struct sk_buff *skb;
struct skb_frame_desc *skbdesc;
/* /*
* The frame size includes descriptor size, because the * The frame size includes descriptor size, because the
* hardware directly receive the frame into the skbuffer. * hardware directly receive the frame into the skbuffer.
*/ */
frame_size = queue->data_size + queue->desc_size; frame_size = entry->queue->data_size + entry->queue->desc_size;
/* /*
* Reserve a few bytes extra headroom to allow drivers some moving * Reserve a few bytes extra headroom to allow drivers some moving
...@@ -57,12 +60,67 @@ struct sk_buff *rt2x00queue_alloc_skb(struct data_queue *queue) ...@@ -57,12 +60,67 @@ struct sk_buff *rt2x00queue_alloc_skb(struct data_queue *queue)
skb_reserve(skb, reserved_size); skb_reserve(skb, reserved_size);
skb_put(skb, frame_size); skb_put(skb, frame_size);
/*
* Populate skbdesc.
*/
skbdesc = get_skb_frame_desc(skb);
memset(skbdesc, 0, sizeof(*skbdesc));
skbdesc->entry = entry;
if (test_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags)) {
skbdesc->skb_dma = dma_map_single(rt2x00dev->dev,
skb->data,
skb->len,
DMA_FROM_DEVICE);
skbdesc->flags |= SKBDESC_DMA_MAPPED_RX;
}
return skb; return skb;
} }
EXPORT_SYMBOL_GPL(rt2x00queue_alloc_skb); EXPORT_SYMBOL_GPL(rt2x00queue_alloc_rxskb);
void rt2x00queue_free_skb(struct sk_buff *skb) void rt2x00queue_map_txskb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb)
{ {
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
skbdesc->skb_dma = dma_map_single(rt2x00dev->dev, skb->data, skb->len,
DMA_TO_DEVICE);
skbdesc->flags |= SKBDESC_DMA_MAPPED_TX;
}
EXPORT_SYMBOL_GPL(rt2x00queue_map_txskb);
void rt2x00queue_unmap_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb)
{
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
if (skbdesc->flags & SKBDESC_DMA_MAPPED_RX) {
dma_unmap_single(rt2x00dev->dev, skbdesc->skb_dma, skb->len,
DMA_FROM_DEVICE);
skbdesc->flags &= ~SKBDESC_DMA_MAPPED_RX;
}
if (skbdesc->flags & SKBDESC_DMA_MAPPED_TX) {
dma_unmap_single(rt2x00dev->dev, skbdesc->skb_dma, skb->len,
DMA_TO_DEVICE);
skbdesc->flags &= ~SKBDESC_DMA_MAPPED_TX;
}
}
EXPORT_SYMBOL_GPL(rt2x00queue_unmap_skb);
void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb)
{
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
if (skbdesc->flags & SKBDESC_DMA_MAPPED_RX) {
dma_unmap_single(rt2x00dev->dev, skbdesc->skb_dma, skb->len,
DMA_FROM_DEVICE);
}
if (skbdesc->flags & SKBDESC_DMA_MAPPED_TX) {
dma_unmap_single(rt2x00dev->dev, skbdesc->skb_dma, skb->len,
DMA_TO_DEVICE);
}
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
} }
EXPORT_SYMBOL_GPL(rt2x00queue_free_skb); EXPORT_SYMBOL_GPL(rt2x00queue_free_skb);
...@@ -421,7 +479,8 @@ static int rt2x00queue_alloc_entries(struct data_queue *queue, ...@@ -421,7 +479,8 @@ static int rt2x00queue_alloc_entries(struct data_queue *queue,
return 0; return 0;
} }
static void rt2x00queue_free_skbs(struct data_queue *queue) static void rt2x00queue_free_skbs(struct rt2x00_dev *rt2x00dev,
struct data_queue *queue)
{ {
unsigned int i; unsigned int i;
...@@ -430,27 +489,27 @@ static void rt2x00queue_free_skbs(struct data_queue *queue) ...@@ -430,27 +489,27 @@ static void rt2x00queue_free_skbs(struct data_queue *queue)
for (i = 0; i < queue->limit; i++) { for (i = 0; i < queue->limit; i++) {
if (queue->entries[i].skb) if (queue->entries[i].skb)
rt2x00queue_free_skb(queue->entries[i].skb); rt2x00queue_free_skb(rt2x00dev, queue->entries[i].skb);
} }
} }
static int rt2x00queue_alloc_skbs(struct data_queue *queue) static int rt2x00queue_alloc_rxskbs(struct rt2x00_dev *rt2x00dev,
struct data_queue *queue)
{ {
unsigned int i; unsigned int i;
struct sk_buff *skb; struct sk_buff *skb;
for (i = 0; i < queue->limit; i++) { for (i = 0; i < queue->limit; i++) {
skb = rt2x00queue_alloc_skb(queue); skb = rt2x00queue_alloc_rxskb(rt2x00dev, &queue->entries[i]);
if (!skb) if (!skb)
goto exit; goto exit;
queue->entries[i].skb = skb; queue->entries[i].skb = skb;
} }
return 0; return 0;
exit: exit:
rt2x00queue_free_skbs(queue); rt2x00queue_free_skbs(rt2x00dev, queue);
return -ENOMEM; return -ENOMEM;
} }
...@@ -481,7 +540,7 @@ int rt2x00queue_initialize(struct rt2x00_dev *rt2x00dev) ...@@ -481,7 +540,7 @@ int rt2x00queue_initialize(struct rt2x00_dev *rt2x00dev)
goto exit; goto exit;
} }
status = rt2x00queue_alloc_skbs(rt2x00dev->rx); status = rt2x00queue_alloc_rxskbs(rt2x00dev, rt2x00dev->rx);
if (status) if (status)
goto exit; goto exit;
...@@ -499,7 +558,7 @@ void rt2x00queue_uninitialize(struct rt2x00_dev *rt2x00dev) ...@@ -499,7 +558,7 @@ void rt2x00queue_uninitialize(struct rt2x00_dev *rt2x00dev)
{ {
struct data_queue *queue; struct data_queue *queue;
rt2x00queue_free_skbs(rt2x00dev->rx); rt2x00queue_free_skbs(rt2x00dev, rt2x00dev->rx);
queue_for_each(rt2x00dev, queue) { queue_for_each(rt2x00dev, queue) {
kfree(queue->entries); kfree(queue->entries);
......
...@@ -83,9 +83,10 @@ enum data_queue_qid { ...@@ -83,9 +83,10 @@ enum data_queue_qid {
* enum skb_frame_desc_flags: Flags for &struct skb_frame_desc * enum skb_frame_desc_flags: Flags for &struct skb_frame_desc
* *
*/ */
//enum skb_frame_desc_flags { enum skb_frame_desc_flags {
// TEMPORARILY EMPTY SKBDESC_DMA_MAPPED_RX = (1 << 0),
//}; SKBDESC_DMA_MAPPED_TX = (1 << 1),
};
/** /**
* struct skb_frame_desc: Descriptor information for the skb buffer * struct skb_frame_desc: Descriptor information for the skb buffer
...@@ -94,19 +95,20 @@ enum data_queue_qid { ...@@ -94,19 +95,20 @@ enum data_queue_qid {
* this structure should not exceed the size of that array (40 bytes). * this structure should not exceed the size of that array (40 bytes).
* *
* @flags: Frame flags, see &enum skb_frame_desc_flags. * @flags: Frame flags, see &enum skb_frame_desc_flags.
* @data: Pointer to data part of frame (Start of ieee80211 header). * @desc_len: Length of the frame descriptor.
* @desc: Pointer to descriptor part of the frame. * @desc: Pointer to descriptor part of the frame.
* Note that this pointer could point to something outside * Note that this pointer could point to something outside
* of the scope of the skb->data pointer. * of the scope of the skb->data pointer.
* @data_len: Length of the frame data. * @skb_dma: (PCI-only) the DMA address associated with the sk buffer.
* @desc_len: Length of the frame descriptor.
* @entry: The entry to which this sk buffer belongs. * @entry: The entry to which this sk buffer belongs.
*/ */
struct skb_frame_desc { struct skb_frame_desc {
unsigned int flags; unsigned int flags;
void *desc;
unsigned int desc_len; unsigned int desc_len;
void *desc;
dma_addr_t skb_dma;
struct queue_entry *entry; struct queue_entry *entry;
}; };
......
...@@ -266,9 +266,7 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb) ...@@ -266,9 +266,7 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb)
{ {
struct queue_entry *entry = (struct queue_entry *)urb->context; struct queue_entry *entry = (struct queue_entry *)urb->context;
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct sk_buff *skb; struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
struct skb_frame_desc *skbdesc;
struct rxdone_entry_desc rxdesc;
u8 rxd[32]; u8 rxd[32];
if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) || if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) ||
...@@ -284,36 +282,19 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb) ...@@ -284,36 +282,19 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb)
goto skip_entry; goto skip_entry;
/* /*
* Fill in skb descriptor * Fill in desc fields of the skb descriptor
*/ */
skbdesc = get_skb_frame_desc(entry->skb);
memset(skbdesc, 0, sizeof(*skbdesc));
skbdesc->entry = entry;
skbdesc->desc = rxd; skbdesc->desc = rxd;
skbdesc->desc_len = entry->queue->desc_size; skbdesc->desc_len = entry->queue->desc_size;
memset(&rxdesc, 0, sizeof(rxdesc));
rt2x00dev->ops->lib->fill_rxdone(entry, &rxdesc);
/*
* Allocate a new sk buffer to replace the current one.
* If allocation fails, we should drop the current frame
* so we can recycle the existing sk buffer for the new frame.
*/
skb = rt2x00queue_alloc_skb(entry->queue);
if (!skb)
goto skip_entry;
/* /*
* Send the frame to rt2x00lib for further processing. * Send the frame to rt2x00lib for further processing.
*/ */
rt2x00lib_rxdone(entry, &rxdesc); rt2x00lib_rxdone(rt2x00dev, entry);
/* /*
* Replace current entry's skb with the newly allocated one, * Reinitialize the urb.
* and reinitialize the urb.
*/ */
entry->skb = skb;
urb->transfer_buffer = entry->skb->data; urb->transfer_buffer = entry->skb->data;
urb->transfer_buffer_length = entry->skb->len; urb->transfer_buffer_length = entry->skb->len;
......
...@@ -1030,11 +1030,12 @@ static void rt61pci_init_rxentry(struct rt2x00_dev *rt2x00dev, ...@@ -1030,11 +1030,12 @@ static void rt61pci_init_rxentry(struct rt2x00_dev *rt2x00dev,
struct queue_entry *entry) struct queue_entry *entry)
{ {
struct queue_entry_priv_pci *entry_priv = entry->priv_data; struct queue_entry_priv_pci *entry_priv = entry->priv_data;
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
u32 word; u32 word;
rt2x00_desc_read(entry_priv->desc, 5, &word); rt2x00_desc_read(entry_priv->desc, 5, &word);
rt2x00_set_field32(&word, RXD_W5_BUFFER_PHYSICAL_ADDRESS, rt2x00_set_field32(&word, RXD_W5_BUFFER_PHYSICAL_ADDRESS,
entry_priv->data_dma); skbdesc->skb_dma);
rt2x00_desc_write(entry_priv->desc, 5, word); rt2x00_desc_write(entry_priv->desc, 5, word);
rt2x00_desc_read(entry_priv->desc, 0, &word); rt2x00_desc_read(entry_priv->desc, 0, &word);
...@@ -1522,7 +1523,6 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, ...@@ -1522,7 +1523,6 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
struct txentry_desc *txdesc) struct txentry_desc *txdesc)
{ {
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
struct queue_entry_priv_pci *entry_priv = skbdesc->entry->priv_data;
__le32 *txd = skbdesc->desc; __le32 *txd = skbdesc->desc;
u32 word; u32 word;
...@@ -1557,7 +1557,7 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, ...@@ -1557,7 +1557,7 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
rt2x00_desc_read(txd, 6, &word); rt2x00_desc_read(txd, 6, &word);
rt2x00_set_field32(&word, TXD_W6_BUFFER_PHYSICAL_ADDRESS, rt2x00_set_field32(&word, TXD_W6_BUFFER_PHYSICAL_ADDRESS,
entry_priv->data_dma); skbdesc->skb_dma);
rt2x00_desc_write(txd, 6, word); rt2x00_desc_write(txd, 6, word);
if (skbdesc->desc_len > TXINFO_SIZE) { if (skbdesc->desc_len > TXINFO_SIZE) {
...@@ -2302,9 +2302,10 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev) ...@@ -2302,9 +2302,10 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev)
rt61pci_probe_hw_mode(rt2x00dev); rt61pci_probe_hw_mode(rt2x00dev);
/* /*
* This device requires firmware. * This device requires firmware and DMA mapped skbs.
*/ */
__set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags); __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags);
__set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags);
/* /*
* Set the rssi offset. * Set the rssi offset.
......
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