diff options
author | Ivo van Doorn <ivdoorn@gmail.com> | 2008-05-10 07:46:13 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-05-21 21:47:34 -0400 |
commit | 7050ec821c52826b63835dde54ee3d71c7db4262 (patch) | |
tree | f8154413b4ed1e8ff01b6dbb1c79240dcce83dc8 /drivers/net/wireless/rt2x00/rt2x00queue.c | |
parent | 4de36fe5abe077a4c65bf0b6a309865aa043e055 (diff) |
rt2x00: Split rt2x00lib_write_tx_desc()
Split rt2x00lib_write_tx_desc() up into a TX descriptor initializor
and TX descriptor writer.
This split is required to properly allow mac80211 to move its
tx_control structure into the skb->cb array.
The rt2x00queue_create_tx_descriptor() function will read all tx control
information and convert it into a rt2x00 TX descriptor information structure.
After that function is complete, we have all information we needed from the
tx control structure and are free to start writing into the skb->cb array
for our own purposes.
rt2x00queue_write_tx_descriptor() will be in charge of really sending
the TX descriptor to the hardware and kicking the TX queue.
Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/rt2x00/rt2x00queue.c')
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00queue.c | 157 |
1 files changed, 157 insertions, 0 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 95f8dd3462f6..19c10629c767 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c | |||
@@ -29,6 +29,163 @@ | |||
29 | #include "rt2x00.h" | 29 | #include "rt2x00.h" |
30 | #include "rt2x00lib.h" | 30 | #include "rt2x00lib.h" |
31 | 31 | ||
32 | void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, | ||
33 | struct txentry_desc *txdesc, | ||
34 | struct ieee80211_tx_control *control) | ||
35 | { | ||
36 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)entry->skb->data; | ||
37 | struct ieee80211_rate *rate = control->tx_rate; | ||
38 | const struct rt2x00_rate *hwrate; | ||
39 | unsigned int data_length; | ||
40 | unsigned int duration; | ||
41 | unsigned int residual; | ||
42 | u16 frame_control; | ||
43 | |||
44 | memset(txdesc, 0, sizeof(*txdesc)); | ||
45 | |||
46 | /* | ||
47 | * Initialize information from queue | ||
48 | */ | ||
49 | txdesc->queue = entry->queue->qid; | ||
50 | txdesc->cw_min = entry->queue->cw_min; | ||
51 | txdesc->cw_max = entry->queue->cw_max; | ||
52 | txdesc->aifs = entry->queue->aifs; | ||
53 | |||
54 | /* Data length should be extended with 4 bytes for CRC */ | ||
55 | data_length = entry->skb->len + 4; | ||
56 | |||
57 | /* | ||
58 | * Read required fields from ieee80211 header. | ||
59 | */ | ||
60 | frame_control = le16_to_cpu(hdr->frame_control); | ||
61 | |||
62 | /* | ||
63 | * Check whether this frame is to be acked. | ||
64 | */ | ||
65 | if (!(control->flags & IEEE80211_TXCTL_NO_ACK)) | ||
66 | __set_bit(ENTRY_TXD_ACK, &txdesc->flags); | ||
67 | |||
68 | /* | ||
69 | * Check if this is a RTS/CTS frame | ||
70 | */ | ||
71 | if (is_rts_frame(frame_control) || is_cts_frame(frame_control)) { | ||
72 | __set_bit(ENTRY_TXD_BURST, &txdesc->flags); | ||
73 | if (is_rts_frame(frame_control)) { | ||
74 | __set_bit(ENTRY_TXD_RTS_FRAME, &txdesc->flags); | ||
75 | __set_bit(ENTRY_TXD_ACK, &txdesc->flags); | ||
76 | } else { | ||
77 | __set_bit(ENTRY_TXD_CTS_FRAME, &txdesc->flags); | ||
78 | __clear_bit(ENTRY_TXD_ACK, &txdesc->flags); | ||
79 | } | ||
80 | if (control->rts_cts_rate) | ||
81 | rate = control->rts_cts_rate; | ||
82 | } | ||
83 | |||
84 | /* | ||
85 | * Determine retry information. | ||
86 | */ | ||
87 | txdesc->retry_limit = control->retry_limit; | ||
88 | if (control->flags & IEEE80211_TXCTL_LONG_RETRY_LIMIT) | ||
89 | __set_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags); | ||
90 | |||
91 | /* | ||
92 | * Check if more fragments are pending | ||
93 | */ | ||
94 | if (ieee80211_get_morefrag(hdr)) { | ||
95 | __set_bit(ENTRY_TXD_BURST, &txdesc->flags); | ||
96 | __set_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags); | ||
97 | } | ||
98 | |||
99 | /* | ||
100 | * Beacons and probe responses require the tsf timestamp | ||
101 | * to be inserted into the frame. | ||
102 | */ | ||
103 | if (txdesc->queue == QID_BEACON || is_probe_resp(frame_control)) | ||
104 | __set_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags); | ||
105 | |||
106 | /* | ||
107 | * Determine with what IFS priority this frame should be send. | ||
108 | * Set ifs to IFS_SIFS when the this is not the first fragment, | ||
109 | * or this fragment came after RTS/CTS. | ||
110 | */ | ||
111 | if (test_bit(ENTRY_TXD_RTS_FRAME, &txdesc->flags)) { | ||
112 | txdesc->ifs = IFS_SIFS; | ||
113 | } else if (control->flags & IEEE80211_TXCTL_FIRST_FRAGMENT) { | ||
114 | __set_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags); | ||
115 | txdesc->ifs = IFS_BACKOFF; | ||
116 | } else { | ||
117 | txdesc->ifs = IFS_SIFS; | ||
118 | } | ||
119 | |||
120 | /* | ||
121 | * PLCP setup | ||
122 | * Length calculation depends on OFDM/CCK rate. | ||
123 | */ | ||
124 | hwrate = rt2x00_get_rate(rate->hw_value); | ||
125 | txdesc->signal = hwrate->plcp; | ||
126 | txdesc->service = 0x04; | ||
127 | |||
128 | if (hwrate->flags & DEV_RATE_OFDM) { | ||
129 | __set_bit(ENTRY_TXD_OFDM_RATE, &txdesc->flags); | ||
130 | |||
131 | txdesc->length_high = (data_length >> 6) & 0x3f; | ||
132 | txdesc->length_low = data_length & 0x3f; | ||
133 | } else { | ||
134 | /* | ||
135 | * Convert length to microseconds. | ||
136 | */ | ||
137 | residual = get_duration_res(data_length, hwrate->bitrate); | ||
138 | duration = get_duration(data_length, hwrate->bitrate); | ||
139 | |||
140 | if (residual != 0) { | ||
141 | duration++; | ||
142 | |||
143 | /* | ||
144 | * Check if we need to set the Length Extension | ||
145 | */ | ||
146 | if (hwrate->bitrate == 110 && residual <= 30) | ||
147 | txdesc->service |= 0x80; | ||
148 | } | ||
149 | |||
150 | txdesc->length_high = (duration >> 8) & 0xff; | ||
151 | txdesc->length_low = duration & 0xff; | ||
152 | |||
153 | /* | ||
154 | * When preamble is enabled we should set the | ||
155 | * preamble bit for the signal. | ||
156 | */ | ||
157 | if (rt2x00_get_rate_preamble(rate->hw_value)) | ||
158 | txdesc->signal |= 0x08; | ||
159 | } | ||
160 | } | ||
161 | EXPORT_SYMBOL_GPL(rt2x00queue_create_tx_descriptor); | ||
162 | |||
163 | void rt2x00queue_write_tx_descriptor(struct queue_entry *entry, | ||
164 | struct txentry_desc *txdesc) | ||
165 | { | ||
166 | struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; | ||
167 | struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); | ||
168 | |||
169 | rt2x00dev->ops->lib->write_tx_desc(rt2x00dev, entry->skb, txdesc); | ||
170 | |||
171 | /* | ||
172 | * All processing on the frame has been completed, this means | ||
173 | * it is now ready to be dumped to userspace through debugfs. | ||
174 | */ | ||
175 | rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_TX, entry->skb); | ||
176 | |||
177 | /* | ||
178 | * We are done writing the frame to the queue entry, | ||
179 | * if this entry is a RTS of CTS-to-self frame we are done, | ||
180 | * otherwise we need to kick the queue. | ||
181 | */ | ||
182 | if (rt2x00dev->ops->lib->kick_tx_queue && | ||
183 | !(skbdesc->flags & FRAME_DESC_DRIVER_GENERATED)) | ||
184 | rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, | ||
185 | entry->queue->qid); | ||
186 | } | ||
187 | EXPORT_SYMBOL_GPL(rt2x00queue_write_tx_descriptor); | ||
188 | |||
32 | struct data_queue *rt2x00queue_get_queue(struct rt2x00_dev *rt2x00dev, | 189 | struct data_queue *rt2x00queue_get_queue(struct rt2x00_dev *rt2x00dev, |
33 | const enum data_queue_qid queue) | 190 | const enum data_queue_qid queue) |
34 | { | 191 | { |