X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fnet%2Fwireless%2Frt2x00%2Frt2x00queue.c;h=19c10629c767513ca510e66c82732ce5e91584da;hb=7050ec821c52826b63835dde54ee3d71c7db4262;hp=9188323f067b4133001547e1911f79ec24b31089;hpb=255333c1db3ec63921de29b134418a4e56e5921e;p=linux-2.6 diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 9188323f06..19c10629c7 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -29,20 +29,177 @@ #include "rt2x00.h" #include "rt2x00lib.h" +void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, + struct txentry_desc *txdesc, + struct ieee80211_tx_control *control) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)entry->skb->data; + struct ieee80211_rate *rate = control->tx_rate; + const struct rt2x00_rate *hwrate; + unsigned int data_length; + unsigned int duration; + unsigned int residual; + u16 frame_control; + + memset(txdesc, 0, sizeof(*txdesc)); + + /* + * Initialize information from queue + */ + txdesc->queue = entry->queue->qid; + txdesc->cw_min = entry->queue->cw_min; + txdesc->cw_max = entry->queue->cw_max; + txdesc->aifs = entry->queue->aifs; + + /* Data length should be extended with 4 bytes for CRC */ + data_length = entry->skb->len + 4; + + /* + * Read required fields from ieee80211 header. + */ + frame_control = le16_to_cpu(hdr->frame_control); + + /* + * Check whether this frame is to be acked. + */ + if (!(control->flags & IEEE80211_TXCTL_NO_ACK)) + __set_bit(ENTRY_TXD_ACK, &txdesc->flags); + + /* + * Check if this is a RTS/CTS frame + */ + if (is_rts_frame(frame_control) || is_cts_frame(frame_control)) { + __set_bit(ENTRY_TXD_BURST, &txdesc->flags); + if (is_rts_frame(frame_control)) { + __set_bit(ENTRY_TXD_RTS_FRAME, &txdesc->flags); + __set_bit(ENTRY_TXD_ACK, &txdesc->flags); + } else { + __set_bit(ENTRY_TXD_CTS_FRAME, &txdesc->flags); + __clear_bit(ENTRY_TXD_ACK, &txdesc->flags); + } + if (control->rts_cts_rate) + rate = control->rts_cts_rate; + } + + /* + * Determine retry information. + */ + txdesc->retry_limit = control->retry_limit; + if (control->flags & IEEE80211_TXCTL_LONG_RETRY_LIMIT) + __set_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags); + + /* + * Check if more fragments are pending + */ + if (ieee80211_get_morefrag(hdr)) { + __set_bit(ENTRY_TXD_BURST, &txdesc->flags); + __set_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags); + } + + /* + * Beacons and probe responses require the tsf timestamp + * to be inserted into the frame. + */ + if (txdesc->queue == QID_BEACON || is_probe_resp(frame_control)) + __set_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags); + + /* + * Determine with what IFS priority this frame should be send. + * Set ifs to IFS_SIFS when the this is not the first fragment, + * or this fragment came after RTS/CTS. + */ + if (test_bit(ENTRY_TXD_RTS_FRAME, &txdesc->flags)) { + txdesc->ifs = IFS_SIFS; + } else if (control->flags & IEEE80211_TXCTL_FIRST_FRAGMENT) { + __set_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags); + txdesc->ifs = IFS_BACKOFF; + } else { + txdesc->ifs = IFS_SIFS; + } + + /* + * PLCP setup + * Length calculation depends on OFDM/CCK rate. + */ + hwrate = rt2x00_get_rate(rate->hw_value); + txdesc->signal = hwrate->plcp; + txdesc->service = 0x04; + + if (hwrate->flags & DEV_RATE_OFDM) { + __set_bit(ENTRY_TXD_OFDM_RATE, &txdesc->flags); + + txdesc->length_high = (data_length >> 6) & 0x3f; + txdesc->length_low = data_length & 0x3f; + } else { + /* + * Convert length to microseconds. + */ + residual = get_duration_res(data_length, hwrate->bitrate); + duration = get_duration(data_length, hwrate->bitrate); + + if (residual != 0) { + duration++; + + /* + * Check if we need to set the Length Extension + */ + if (hwrate->bitrate == 110 && residual <= 30) + txdesc->service |= 0x80; + } + + txdesc->length_high = (duration >> 8) & 0xff; + txdesc->length_low = duration & 0xff; + + /* + * When preamble is enabled we should set the + * preamble bit for the signal. + */ + if (rt2x00_get_rate_preamble(rate->hw_value)) + txdesc->signal |= 0x08; + } +} +EXPORT_SYMBOL_GPL(rt2x00queue_create_tx_descriptor); + +void rt2x00queue_write_tx_descriptor(struct queue_entry *entry, + struct txentry_desc *txdesc) +{ + struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; + struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); + + rt2x00dev->ops->lib->write_tx_desc(rt2x00dev, entry->skb, txdesc); + + /* + * All processing on the frame has been completed, this means + * it is now ready to be dumped to userspace through debugfs. + */ + rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_TX, entry->skb); + + /* + * We are done writing the frame to the queue entry, + * if this entry is a RTS of CTS-to-self frame we are done, + * otherwise we need to kick the queue. + */ + if (rt2x00dev->ops->lib->kick_tx_queue && + !(skbdesc->flags & FRAME_DESC_DRIVER_GENERATED)) + rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, + entry->queue->qid); +} +EXPORT_SYMBOL_GPL(rt2x00queue_write_tx_descriptor); + struct data_queue *rt2x00queue_get_queue(struct rt2x00_dev *rt2x00dev, - const unsigned int queue) + const enum data_queue_qid queue) { int atim = test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags); - if (queue < rt2x00dev->hw->queues && rt2x00dev->tx) + if (queue < rt2x00dev->ops->tx_queues && rt2x00dev->tx) return &rt2x00dev->tx[queue]; if (!rt2x00dev->bcn) return NULL; - if (queue == RT2X00_BCN_QUEUE_BEACON) + if (queue == QID_BEACON) return &rt2x00dev->bcn[0]; - else if (queue == RT2X00_BCN_QUEUE_ATIM && atim) + else if (queue == QID_ATIM && atim) return &rt2x00dev->bcn[1]; return NULL; @@ -53,6 +210,7 @@ struct queue_entry *rt2x00queue_get_entry(struct data_queue *queue, enum queue_index index) { struct queue_entry *entry; + unsigned long irqflags; if (unlikely(index >= Q_INDEX_MAX)) { ERROR(queue->rt2x00dev, @@ -60,11 +218,11 @@ struct queue_entry *rt2x00queue_get_entry(struct data_queue *queue, return NULL; } - spin_lock(&queue->lock); + spin_lock_irqsave(&queue->lock, irqflags); entry = &queue->entries[queue->index[index]]; - spin_unlock(&queue->lock); + spin_unlock_irqrestore(&queue->lock, irqflags); return entry; } @@ -72,13 +230,15 @@ EXPORT_SYMBOL_GPL(rt2x00queue_get_entry); void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index) { + unsigned long irqflags; + if (unlikely(index >= Q_INDEX_MAX)) { ERROR(queue->rt2x00dev, "Index change on invalid index type (%d)\n", index); return; } - spin_lock(&queue->lock); + spin_lock_irqsave(&queue->lock, irqflags); queue->index[index]++; if (queue->index[index] >= queue->limit) @@ -91,19 +251,21 @@ void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index) queue->count ++; } - spin_unlock(&queue->lock); + spin_unlock_irqrestore(&queue->lock, irqflags); } EXPORT_SYMBOL_GPL(rt2x00queue_index_inc); static void rt2x00queue_reset(struct data_queue *queue) { - spin_lock(&queue->lock); + unsigned long irqflags; + + spin_lock_irqsave(&queue->lock, irqflags); queue->count = 0; queue->length = 0; memset(queue->index, 0, sizeof(queue->index)); - spin_unlock(&queue->lock); + spin_unlock_irqrestore(&queue->lock, irqflags); } void rt2x00queue_init_rx(struct rt2x00_dev *rt2x00dev) @@ -250,11 +412,11 @@ int rt2x00queue_allocate(struct rt2x00_dev *rt2x00dev) /* * We need the following queues: * RX: 1 - * TX: hw->queues + * TX: ops->tx_queues * Beacon: 1 * Atim: 1 (if required) */ - rt2x00dev->data_queues = 2 + rt2x00dev->hw->queues + req_atim; + rt2x00dev->data_queues = 2 + rt2x00dev->ops->tx_queues + req_atim; queue = kzalloc(rt2x00dev->data_queues * sizeof(*queue), GFP_KERNEL); if (!queue) { @@ -267,7 +429,7 @@ int rt2x00queue_allocate(struct rt2x00_dev *rt2x00dev) */ rt2x00dev->rx = queue; rt2x00dev->tx = &queue[1]; - rt2x00dev->bcn = &queue[1 + rt2x00dev->hw->queues]; + rt2x00dev->bcn = &queue[1 + rt2x00dev->ops->tx_queues]; /* * Initialize queue parameters.