Skip to content

Commit

Permalink
rt2x00: Replace statically allocated DMA buffers with mapped skb's.
Browse files Browse the repository at this point in the history
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: Gertjan van Wingerde <gwingerde@kpnplanet.nl>
Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
  • Loading branch information
Gertjan van Wingerde authored and John W. Linville committed Jun 26, 2008
1 parent 30caa6e commit c4da004
Show file tree
Hide file tree
Showing 10 changed files with 204 additions and 176 deletions.
13 changes: 7 additions & 6 deletions drivers/net/wireless/rt2x00/rt2400pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -632,15 +632,15 @@ static void rt2400pci_init_rxentry(struct rt2x00_dev *rt2x00dev,
struct queue_entry *entry)
{
struct queue_entry_priv_pci *entry_priv = entry->priv_data;
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
u32 word;

rt2x00_desc_read(entry_priv->desc, 2, &word);
rt2x00_set_field32(&word, RXD_W2_BUFFER_LENGTH,
entry->queue->data_size);
rt2x00_set_field32(&word, RXD_W2_BUFFER_LENGTH, entry->skb->len);
rt2x00_desc_write(entry_priv->desc, 2, 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_read(entry_priv->desc, 0, &word);
Expand Down Expand Up @@ -1012,7 +1012,7 @@ static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
* Start writing the descriptor words.
*/
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_read(txd, 2, &word);
Expand Down Expand Up @@ -1412,9 +1412,10 @@ static int rt2400pci_probe_hw(struct rt2x00_dev *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_DMA, &rt2x00dev->flags);

/*
* Set the rssi offset.
Expand Down Expand Up @@ -1526,7 +1527,7 @@ static int rt2400pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
* Write entire beacon with descriptor to register,
* 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);
rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON);

Expand Down
10 changes: 6 additions & 4 deletions drivers/net/wireless/rt2x00/rt2500pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -727,10 +727,11 @@ static void rt2500pci_init_rxentry(struct rt2x00_dev *rt2x00dev,
struct queue_entry *entry)
{
struct queue_entry_priv_pci *entry_priv = entry->priv_data;
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
u32 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_read(entry_priv->desc, 0, &word);
Expand Down Expand Up @@ -1171,7 +1172,7 @@ static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
* Start writing the descriptor words.
*/
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_read(txd, 2, &word);
Expand Down Expand Up @@ -1752,9 +1753,10 @@ static int rt2500pci_probe_hw(struct rt2x00_dev *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_DMA, &rt2x00dev->flags);

/*
* Set the rssi offset.
Expand Down Expand Up @@ -1842,7 +1844,7 @@ static int rt2500pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
* Write entire beacon with descriptor to register,
* 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);
rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON);

Expand Down
28 changes: 23 additions & 5 deletions drivers/net/wireless/rt2x00/rt2x00.h
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,7 @@ enum rt2x00_flags {
DRIVER_REQUIRE_BEACON_GUARD,
DRIVER_REQUIRE_ATIM_QUEUE,
DRIVER_REQUIRE_SCHEDULED,
DRIVER_REQUIRE_DMA,

/*
* Driver configuration
Expand Down Expand Up @@ -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.
*/
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
* @rt2x00dev: Pointer to &struct rt2x00_dev.
* @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
Expand Down Expand Up @@ -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_txdone(struct queue_entry *entry,
struct txdone_entry_desc *txdesc);
void rt2x00lib_rxdone(struct queue_entry *entry,
struct rxdone_entry_desc *rxdesc);
void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
struct queue_entry *entry);

/*
* mac80211 handlers.
Expand Down
64 changes: 45 additions & 19 deletions drivers/net/wireless/rt2x00/rt2x00dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,7 @@ static void rt2x00lib_intf_scheduled(struct work_struct *work)
static void rt2x00lib_beacondone_iter(void *data, u8 *mac,
struct ieee80211_vif *vif)
{
struct rt2x00_dev *rt2x00dev = data;
struct rt2x00_intf *intf = vif_to_intf(vif);

if (vif->type != IEEE80211_IF_TYPE_AP &&
Expand All @@ -477,7 +478,7 @@ static void rt2x00lib_beacondone_iter(void *data, u8 *mac,
/*
* Clean up the beacon skb.
*/
dev_kfree_skb_irq(intf->beacon->skb);
rt2x00queue_free_skb(rt2x00dev, intf->beacon->skb);
intf->beacon->skb = NULL;

spin_lock(&intf->lock);
Expand Down Expand Up @@ -555,34 +556,55 @@ void rt2x00lib_txdone(struct queue_entry *entry,
}
EXPORT_SYMBOL_GPL(rt2x00lib_txdone);

void rt2x00lib_rxdone(struct queue_entry *entry,
struct rxdone_entry_desc *rxdesc)
void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
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;
unsigned int header_size = ieee80211_get_hdrlen_from_skb(entry->skb);
struct ieee80211_supported_band *sband;
struct ieee80211_hdr *hdr;
const struct rt2x00_rate *rate;
unsigned int header_size;
unsigned int align;
unsigned int i;
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
* aligned on a 4 byte boundary.
*/
header_size = ieee80211_get_hdrlen_from_skb(entry->skb);
align = ((unsigned long)(entry->skb->data + header_size)) & 3;

if (align) {
skb_push(entry->skb, align);
/* Move entire frame in 1 command */
memmove(entry->skb->data, entry->skb->data + align,
rxdesc->size);
rxdesc.size);
}

/* Update data pointers, trim buffer to correct size */
skb_trim(entry->skb, rxdesc->size);
skb_trim(entry->skb, rxdesc.size);

/*
* Update RX statistics.
Expand All @@ -591,19 +613,19 @@ void rt2x00lib_rxdone(struct queue_entry *entry,
for (i = 0; i < sband->n_bitrates; i++) {
rate = rt2x00_get_rate(sband->bitrates[i].hw_value);

if (((rxdesc->dev_flags & RXDONE_SIGNAL_PLCP) &&
(rate->plcp == rxdesc->signal)) ||
(!(rxdesc->dev_flags & RXDONE_SIGNAL_PLCP) &&
(rate->bitrate == rxdesc->signal))) {
if (((rxdesc.dev_flags & RXDONE_SIGNAL_PLCP) &&
(rate->plcp == rxdesc.signal)) ||
(!(rxdesc.dev_flags & RXDONE_SIGNAL_PLCP) &&
(rate->bitrate == rxdesc.signal))) {
idx = i;
break;
}
}

if (idx < 0) {
WARNING(rt2x00dev, "Frame received with unrecognized signal,"
"signal=0x%.2x, plcp=%d.\n", rxdesc->signal,
!!(rxdesc->dev_flags & RXDONE_SIGNAL_PLCP));
"signal=0x%.2x, plcp=%d.\n", rxdesc.signal,
!!(rxdesc.dev_flags & RXDONE_SIGNAL_PLCP));
idx = 0;
}

Expand All @@ -612,16 +634,16 @@ void rt2x00lib_rxdone(struct queue_entry *entry,
*/
hdr = (struct ieee80211_hdr *)entry->skb->data;
if (ieee80211_is_beacon(hdr->frame_control) &&
(rxdesc->dev_flags & RXDONE_MY_BSS))
rt2x00lib_update_link_stats(&rt2x00dev->link, rxdesc->rssi);
(rxdesc.dev_flags & RXDONE_MY_BSS))
rt2x00lib_update_link_stats(&rt2x00dev->link, rxdesc.rssi);

rt2x00dev->link.qual.rx_success++;

rx_status->rate_idx = idx;
rx_status->qual =
rt2x00lib_calculate_link_signal(rt2x00dev, rxdesc->rssi);
rx_status->signal = rxdesc->rssi;
rx_status->flag = rxdesc->flags;
rt2x00lib_calculate_link_signal(rt2x00dev, rxdesc.rssi);
rx_status->signal = rxdesc.rssi;
rx_status->flag = rxdesc.flags;
rx_status->antenna = rt2x00dev->link.ant.active.rx;

/*
Expand All @@ -630,7 +652,11 @@ void rt2x00lib_rxdone(struct queue_entry *entry,
*/
rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_RXDONE, entry->skb);
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);

Expand Down
Loading

0 comments on commit c4da004

Please sign in to comment.