/*
* Obtain the status about this packet.
+ * Note that when the status is 0 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.status = !urb->status ? TX_SUCCESS : TX_FAIL_RETRY;
+ if (!urb->status)
+ __set_bit(TXDONE_UNKNOWN, &txdesc.flags);
+ else
+ __set_bit(TXDONE_FAILURE, &txdesc.flags);
txdesc.retry = 0;
txdesc.control = &priv_tx->control;
struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX);
struct queue_entry_priv_usb_tx *priv_tx = entry->priv_data;
struct skb_frame_desc *skbdesc;
+ struct txentry_desc txdesc;
u32 length;
if (rt2x00queue_full(queue))
ERROR(rt2x00dev,
"Arrived at non-free entry in the non-full queue %d.\n"
"Please file bug report to %s.\n",
- control->queue, DRV_PROJECT);
+ entry->queue->qid, DRV_PROJECT);
return -EINVAL;
}
+ /*
+ * Copy all TX descriptor information into txdesc,
+ * after that we are free to use the skb->cb array
+ * for our information.
+ */
+ entry->skb = skb;
+ rt2x00queue_create_tx_descriptor(entry, &txdesc, control);
+
/*
* Add the descriptor in front of the skb.
*/
skbdesc->entry = entry;
memcpy(&priv_tx->control, control, sizeof(priv_tx->control));
- rt2x00lib_write_tx_desc(rt2x00dev, skb, control);
+ rt2x00queue_write_tx_descriptor(entry, &txdesc);
/*
* USB devices cannot blindly pass the skb->len as the
{
struct sk_buff *skb;
unsigned int frame_size;
+ unsigned int reserved_size;
/*
- * As alignment we use 2 and not NET_IP_ALIGN because we need
- * to be sure we have 2 bytes room in the head. (NET_IP_ALIGN
- * can be 0 on some hardware). We use these 2 bytes for frame
- * alignment later, we assume that the chance that
- * header_size % 4 == 2 is bigger then header_size % 2 == 0
- * and thus optimize alignment by reserving the 2 bytes in
- * advance.
+ * The frame size includes descriptor size, because the
+ * hardware directly receive the frame into the skbuffer.
*/
frame_size = queue->data_size + queue->desc_size;
- skb = dev_alloc_skb(queue->desc_size + frame_size + 2);
+
+ /*
+ * For the allocation we should keep a few things in mind:
+ * 1) 4byte alignment of 802.11 payload
+ *
+ * For (1) we need at most 4 bytes to guarentee the correct
+ * alignment. We are going to optimize the fact that the chance
+ * that the 802.11 header_size % 4 == 2 is much bigger then
+ * anything else. However since we need to move the frame up
+ * to 3 bytes to the front, which means we need to preallocate
+ * 6 bytes.
+ */
+ reserved_size = 6;
+
+ /*
+ * Allocate skbuffer.
+ */
+ skb = dev_alloc_skb(frame_size + reserved_size);
if (!skb)
return NULL;
- skb_reserve(skb, queue->desc_size + 2);
+ skb_reserve(skb, reserved_size);
skb_put(skb, frame_size);
return skb;
struct sk_buff *skb;
struct skb_frame_desc *skbdesc;
struct rxdone_entry_desc rxdesc;
- int header_size;
+ unsigned int header_size;
+ unsigned int align;
if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) ||
!test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
memset(&rxdesc, 0, sizeof(rxdesc));
rt2x00dev->ops->lib->fill_rxdone(entry, &rxdesc);
+ header_size = ieee80211_get_hdrlen_from_skb(entry->skb);
+
/*
* The data behind the ieee80211 header must be
- * aligned on a 4 byte boundary.
+ * aligned on a 4 byte boundary. We already reserved
+ * 2 bytes for header_size % 4 == 2 optimization.
+ * To determine the number of bytes which the data
+ * should be moved to the left, we must add these
+ * 2 bytes to the header_size.
*/
- header_size = ieee80211_get_hdrlen_from_skb(entry->skb);
- if (header_size % 4 == 0) {
- skb_push(entry->skb, 2);
- memmove(entry->skb->data, entry->skb->data + 2,
- entry->skb->len - 2);
- skbdesc->data = entry->skb->data;
- skb_trim(entry->skb,entry->skb->len - 2);
+ align = (header_size + 2) % 4;
+
+ if (align) {
+ skb_push(entry->skb, align);
+ /* Move entire frame in 1 command */
+ memmove(entry->skb->data, entry->skb->data + align,
+ rxdesc.size);
}
+ /* Update data pointers, trim buffer to correct size */
+ skbdesc->data = entry->skb->data;
+ skb_trim(entry->skb, rxdesc.size);
+
/*
* Allocate a new sk buffer to replace the current one.
* If allocation fails, we should drop the current frame
struct data_queue *queue;
unsigned int i;
- rt2x00usb_vendor_request_sw(rt2x00dev, USB_RX_CONTROL, 0x0000, 0x0000,
+ rt2x00usb_vendor_request_sw(rt2x00dev, USB_RX_CONTROL, 0, 0,
REGISTER_TIMEOUT);
/*