X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fnet%2Fwireless%2Frt2x00%2Frt2x00queue.c;h=5b6b789cad3d6a4f0bd88ad0747e53aabcaf4774;hb=318ae2edc3b29216abd8a2510f3f80b764f06858;hp=65435c9fe4bcee7a39fa3d1ad7576a5c49c8f848;hpb=267e898755d7fc6249e26208e7ce97f415fd8c31;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 65435c9..5b6b789 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -1,5 +1,6 @@ /* - Copyright (C) 2004 - 2009 rt2x00 SourceForge Project + Copyright (C) 2004 - 2009 Ivo van Doorn + Copyright (C) 2004 - 2009 Gertjan van Wingerde This program is free software; you can redistribute it and/or modify @@ -103,7 +104,7 @@ void rt2x00queue_map_txskb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb) * is also mapped to the DMA so it can be used for transfering * additional descriptor information to the hardware. */ - skb_push(skb, rt2x00dev->hw->extra_tx_headroom); + skb_push(skb, rt2x00dev->ops->extra_tx_headroom); skbdesc->skb_dma = dma_map_single(rt2x00dev->dev, skb->data, skb->len, DMA_TO_DEVICE); @@ -111,7 +112,7 @@ void rt2x00queue_map_txskb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb) /* * Restore data pointer to original location again. */ - skb_pull(skb, rt2x00dev->hw->extra_tx_headroom); + skb_pull(skb, rt2x00dev->ops->extra_tx_headroom); skbdesc->flags |= SKBDESC_DMA_MAPPED_TX; } @@ -133,7 +134,7 @@ void rt2x00queue_unmap_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb) * by the driver, but it was actually mapped to DMA. */ dma_unmap_single(rt2x00dev->dev, skbdesc->skb_dma, - skb->len + rt2x00dev->hw->extra_tx_headroom, + skb->len + rt2x00dev->ops->extra_tx_headroom, DMA_TO_DEVICE); skbdesc->flags &= ~SKBDESC_DMA_MAPPED_TX; } @@ -148,33 +149,77 @@ void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb) dev_kfree_skb_any(skb); } -void rt2x00queue_payload_align(struct sk_buff *skb, - bool l2pad, unsigned int header_length) +void rt2x00queue_align_frame(struct sk_buff *skb) +{ + unsigned int frame_length = skb->len; + unsigned int align = ALIGN_SIZE(skb, 0); + + if (!align) + return; + + skb_push(skb, align); + memmove(skb->data, skb->data + align, frame_length); + skb_trim(skb, frame_length); +} + +void rt2x00queue_align_payload(struct sk_buff *skb, unsigned int header_length) { - struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); unsigned int frame_length = skb->len; unsigned int align = ALIGN_SIZE(skb, header_length); if (!align) return; - if (l2pad) { - if (skbdesc->flags & SKBDESC_L2_PADDED) { - /* Remove L2 padding */ - memmove(skb->data + align, skb->data, header_length); - skb_pull(skb, align); - skbdesc->flags &= ~SKBDESC_L2_PADDED; - } else { - /* Add L2 padding */ - skb_push(skb, align); - memmove(skb->data, skb->data + align, header_length); - skbdesc->flags |= SKBDESC_L2_PADDED; - } - } else { - /* Generic payload alignment to 4-byte boundary */ - skb_push(skb, align); - memmove(skb->data, skb->data + align, frame_length); - } + skb_push(skb, align); + memmove(skb->data, skb->data + align, frame_length); + skb_trim(skb, frame_length); +} + +void rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int header_length) +{ + unsigned int payload_length = skb->len - header_length; + unsigned int header_align = ALIGN_SIZE(skb, 0); + unsigned int payload_align = ALIGN_SIZE(skb, header_length); + unsigned int l2pad = payload_length ? L2PAD_SIZE(header_length) : 0; + + /* + * Adjust the header alignment if the payload needs to be moved more + * than the header. + */ + if (payload_align > header_align) + header_align += 4; + + /* There is nothing to do if no alignment is needed */ + if (!header_align) + return; + + /* Reserve the amount of space needed in front of the frame */ + skb_push(skb, header_align); + + /* + * Move the header. + */ + memmove(skb->data, skb->data + header_align, header_length); + + /* Move the payload, if present and if required */ + if (payload_length && payload_align) + memmove(skb->data + header_length + l2pad, + skb->data + header_length + l2pad + payload_align, + payload_length); + + /* Trim the skb to the correct size */ + skb_trim(skb, header_length + l2pad + payload_length); +} + +void rt2x00queue_remove_l2pad(struct sk_buff *skb, unsigned int header_length) +{ + unsigned int l2pad = L2PAD_SIZE(header_length); + + if (!l2pad) + return; + + memmove(skb->data + l2pad, skb->data, header_length); + skb_pull(skb, l2pad); } static void rt2x00queue_create_tx_descriptor_seq(struct queue_entry *entry, @@ -291,7 +336,9 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, * Header and alignment information. */ txdesc->header_length = ieee80211_get_hdrlen_from_skb(entry->skb); - txdesc->l2pad = ALIGN_SIZE(entry->skb, txdesc->header_length); + if (test_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags) && + (entry->skb->len > txdesc->header_length)) + txdesc->l2pad = L2PAD_SIZE(txdesc->header_length); /* * Check whether this frame is to be acked. @@ -332,10 +379,13 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, /* * Beacons and probe responses require the tsf timestamp - * to be inserted into the frame. + * to be inserted into the frame, except for a frame that has been injected + * through a monitor interface. This latter is needed for testing a + * monitor interface. */ - if (ieee80211_is_beacon(hdr->frame_control) || - ieee80211_is_probe_resp(hdr->frame_control)) + if ((ieee80211_is_beacon(hdr->frame_control) || + ieee80211_is_probe_resp(hdr->frame_control)) && + (!(tx_info->flags & IEEE80211_TX_CTL_INJECTED))) __set_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags); /* @@ -399,7 +449,8 @@ static void rt2x00queue_write_tx_descriptor(struct queue_entry *entry, rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, queue->qid); } -int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb) +int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb, + bool local) { struct ieee80211_tx_info *tx_info; struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX); @@ -440,10 +491,13 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb) skbdesc->tx_rate_idx = rate_idx; skbdesc->tx_rate_flags = rate_flags; + if (local) + skbdesc->flags |= SKBDESC_NOT_MAC80211; + /* * When hardware encryption is supported, and this frame * is to be encrypted, we should strip the IV/EIV data from - * the frame so we can provide it to the driver seperately. + * the frame so we can provide it to the driver separately. */ if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc.flags) && !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc.flags)) { @@ -453,9 +507,18 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb) rt2x00crypto_tx_remove_iv(skb, &txdesc); } + /* + * When DMA allocation is required we should guarentee to the + * driver that the DMA is aligned to a 4-byte boundary. + * However some drivers require L2 padding to pad the payload + * rather then the header. This could be a requirement for + * PCI and USB devices, while header alignment only is valid + * for PCI devices. + */ if (test_bit(DRIVER_REQUIRE_L2PAD, &queue->rt2x00dev->flags)) - rt2x00queue_payload_align(entry->skb, true, - txdesc.header_length); + rt2x00queue_insert_l2pad(entry->skb, txdesc.header_length); + else if (test_bit(DRIVER_REQUIRE_DMA, &queue->rt2x00dev->flags)) + rt2x00queue_align_frame(entry->skb); /* * It could be possible that the queue was corrupted and this @@ -491,14 +554,25 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev, if (unlikely(!intf->beacon)) return -ENOBUFS; + mutex_lock(&intf->beacon_skb_mutex); + + /* + * Clean up the beacon skb. + */ + rt2x00queue_free_skb(rt2x00dev, intf->beacon->skb); + intf->beacon->skb = NULL; + if (!enable_beacon) { rt2x00dev->ops->lib->kill_tx_queue(rt2x00dev, QID_BEACON); + mutex_unlock(&intf->beacon_skb_mutex); return 0; } intf->beacon->skb = ieee80211_beacon_get(rt2x00dev->hw, vif); - if (!intf->beacon->skb) + if (!intf->beacon->skb) { + mutex_unlock(&intf->beacon_skb_mutex); return -ENOMEM; + } /* * Copy all TX descriptor information into txdesc, @@ -536,6 +610,8 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev, rt2x00dev->ops->lib->write_beacon(intf->beacon); rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON); + mutex_unlock(&intf->beacon_skb_mutex); + return 0; }