Commit | Line | Data |
---|---|---|
f5fc0f86 LC |
1 | /* |
2 | * This file is part of wl1271 | |
3 | * | |
4 | * Copyright (C) 2009 Nokia Corporation | |
5 | * | |
6 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU General Public License | |
10 | * version 2 as published by the Free Software Foundation. | |
11 | * | |
12 | * This program is distributed in the hope that it will be useful, but | |
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public License | |
18 | * along with this program; if not, write to the Free Software | |
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | |
20 | * 02110-1301 USA | |
21 | * | |
22 | */ | |
23 | ||
24 | #include <linux/kernel.h> | |
25 | #include <linux/module.h> | |
26 | ||
27 | #include "wl1271.h" | |
28 | #include "wl1271_spi.h" | |
29 | #include "wl1271_reg.h" | |
30 | #include "wl1271_ps.h" | |
31 | #include "wl1271_tx.h" | |
32 | ||
33 | static int wl1271_tx_id(struct wl1271 *wl, struct sk_buff *skb) | |
34 | { | |
35 | int i; | |
36 | ||
37 | for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) | |
38 | if (wl->tx_frames[i] == NULL) { | |
39 | wl->tx_frames[i] = skb; | |
40 | return i; | |
41 | } | |
42 | ||
43 | return -EBUSY; | |
44 | } | |
45 | ||
46 | static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra) | |
47 | { | |
48 | struct wl1271_tx_hw_descr *desc; | |
49 | u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra; | |
50 | u32 total_blocks, excluded; | |
51 | int id, ret = -EBUSY; | |
52 | ||
53 | /* allocate free identifier for the packet */ | |
54 | id = wl1271_tx_id(wl, skb); | |
55 | if (id < 0) | |
56 | return id; | |
57 | ||
58 | /* approximate the number of blocks required for this packet | |
59 | in the firmware */ | |
60 | /* FIXME: try to figure out what is done here and make it cleaner */ | |
3b4be9e0 | 61 | total_blocks = (total_len) >> TX_HW_BLOCK_SHIFT_DIV; |
f5fc0f86 LC |
62 | excluded = (total_blocks << 2) + (skb->len & 0xff) + 34; |
63 | total_blocks += (excluded > 252) ? 2 : 1; | |
64 | total_blocks += TX_HW_BLOCK_SPARE; | |
65 | ||
66 | if (total_blocks <= wl->tx_blocks_available) { | |
67 | desc = (struct wl1271_tx_hw_descr *)skb_push( | |
68 | skb, total_len - skb->len); | |
69 | ||
70 | desc->extra_mem_blocks = TX_HW_BLOCK_SPARE; | |
71 | desc->total_mem_blocks = total_blocks; | |
72 | desc->id = id; | |
73 | ||
74 | wl->tx_blocks_available -= total_blocks; | |
75 | ||
76 | ret = 0; | |
77 | ||
78 | wl1271_debug(DEBUG_TX, | |
79 | "tx_allocate: size: %d, blocks: %d, id: %d", | |
80 | total_len, total_blocks, id); | |
81 | } else | |
82 | wl->tx_frames[id] = NULL; | |
83 | ||
84 | return ret; | |
85 | } | |
86 | ||
87 | static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, | |
88 | u32 extra, struct ieee80211_tx_info *control) | |
89 | { | |
90 | struct wl1271_tx_hw_descr *desc; | |
91 | int pad; | |
92 | ||
93 | desc = (struct wl1271_tx_hw_descr *) skb->data; | |
94 | ||
95 | /* configure packet life time */ | |
96 | desc->start_time = jiffies_to_usecs(jiffies) - wl->time_offset; | |
97 | desc->life_time = TX_HW_MGMT_PKT_LIFETIME_TU; | |
98 | ||
99 | /* configure the tx attributes */ | |
100 | desc->tx_attr = wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER; | |
101 | /* FIXME: do we know the packet priority? can we identify mgmt | |
102 | packets, and use max prio for them at least? */ | |
103 | desc->tid = 0; | |
104 | desc->aid = TX_HW_DEFAULT_AID; | |
105 | desc->reserved = 0; | |
106 | ||
107 | /* align the length (and store in terms of words) */ | |
108 | pad = WL1271_TX_ALIGN(skb->len); | |
109 | desc->length = pad >> 2; | |
110 | ||
111 | /* calculate number of padding bytes */ | |
112 | pad = pad - skb->len; | |
113 | desc->tx_attr |= pad << TX_HW_ATTR_OFST_LAST_WORD_PAD; | |
114 | ||
115 | wl1271_debug(DEBUG_TX, "tx_fill_hdr: pad: %d", pad); | |
116 | return 0; | |
117 | } | |
118 | ||
119 | static int wl1271_tx_send_packet(struct wl1271 *wl, struct sk_buff *skb, | |
120 | struct ieee80211_tx_info *control) | |
121 | { | |
122 | ||
123 | struct wl1271_tx_hw_descr *desc; | |
124 | int len; | |
125 | ||
126 | /* FIXME: This is a workaround for getting non-aligned packets. | |
127 | This happens at least with EAPOL packets from the user space. | |
128 | Our DMA requires packets to be aligned on a 4-byte boundary. | |
129 | */ | |
130 | if (unlikely((long)skb->data & 0x03)) { | |
131 | int offset = (4 - (long)skb->data) & 0x03; | |
132 | wl1271_debug(DEBUG_TX, "skb offset %d", offset); | |
133 | ||
134 | /* check whether the current skb can be used */ | |
135 | if (!skb_cloned(skb) && (skb_tailroom(skb) >= offset)) { | |
136 | unsigned char *src = skb->data; | |
137 | ||
138 | /* align the buffer on a 4-byte boundary */ | |
139 | skb_reserve(skb, offset); | |
140 | memmove(skb->data, src, skb->len); | |
141 | } else { | |
142 | wl1271_info("No handler, fixme!"); | |
143 | return -EINVAL; | |
144 | } | |
145 | } | |
146 | ||
147 | len = WL1271_TX_ALIGN(skb->len); | |
148 | ||
149 | /* perform a fixed address block write with the packet */ | |
150 | wl1271_spi_reg_write(wl, WL1271_SLV_MEM_DATA, skb->data, len, true); | |
151 | ||
152 | /* write packet new counter into the write access register */ | |
153 | wl->tx_packets_count++; | |
154 | wl1271_reg_write32(wl, WL1271_HOST_WR_ACCESS, wl->tx_packets_count); | |
155 | ||
156 | desc = (struct wl1271_tx_hw_descr *) skb->data; | |
157 | wl1271_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u (%u words)", | |
158 | desc->id, skb, len, desc->length); | |
159 | ||
160 | return 0; | |
161 | } | |
162 | ||
163 | /* caller must hold wl->mutex */ | |
164 | static int wl1271_tx_frame(struct wl1271 *wl, struct sk_buff *skb) | |
165 | { | |
166 | struct ieee80211_tx_info *info; | |
167 | u32 extra = 0; | |
168 | int ret = 0; | |
169 | u8 idx; | |
170 | ||
171 | if (!skb) | |
172 | return -EINVAL; | |
173 | ||
174 | info = IEEE80211_SKB_CB(skb); | |
175 | ||
176 | if (info->control.hw_key && | |
177 | info->control.hw_key->alg == ALG_TKIP) | |
178 | extra = WL1271_TKIP_IV_SPACE; | |
179 | ||
180 | if (info->control.hw_key) { | |
181 | idx = info->control.hw_key->hw_key_idx; | |
182 | ||
183 | /* FIXME: do we have to do this if we're not using WEP? */ | |
184 | if (unlikely(wl->default_key != idx)) { | |
185 | ret = wl1271_cmd_set_default_wep_key(wl, idx); | |
186 | if (ret < 0) | |
187 | return ret; | |
188 | } | |
189 | } | |
190 | ||
191 | ret = wl1271_tx_allocate(wl, skb, extra); | |
192 | if (ret < 0) | |
193 | return ret; | |
194 | ||
195 | ret = wl1271_tx_fill_hdr(wl, skb, extra, info); | |
196 | if (ret < 0) | |
197 | return ret; | |
198 | ||
199 | ret = wl1271_tx_send_packet(wl, skb, info); | |
200 | if (ret < 0) | |
201 | return ret; | |
202 | ||
203 | return ret; | |
204 | } | |
205 | ||
206 | void wl1271_tx_work(struct work_struct *work) | |
207 | { | |
208 | struct wl1271 *wl = container_of(work, struct wl1271, tx_work); | |
209 | struct sk_buff *skb; | |
210 | bool woken_up = false; | |
211 | int ret; | |
212 | ||
213 | mutex_lock(&wl->mutex); | |
214 | ||
215 | if (unlikely(wl->state == WL1271_STATE_OFF)) | |
216 | goto out; | |
217 | ||
218 | while ((skb = skb_dequeue(&wl->tx_queue))) { | |
219 | if (!woken_up) { | |
220 | ret = wl1271_ps_elp_wakeup(wl, false); | |
221 | if (ret < 0) | |
222 | goto out; | |
223 | woken_up = true; | |
224 | } | |
225 | ||
226 | ret = wl1271_tx_frame(wl, skb); | |
227 | if (ret == -EBUSY) { | |
228 | /* firmware buffer is full, stop queues */ | |
229 | wl1271_debug(DEBUG_TX, "tx_work: fw buffer full, " | |
230 | "stop queues"); | |
231 | ieee80211_stop_queues(wl->hw); | |
232 | wl->tx_queue_stopped = true; | |
233 | skb_queue_head(&wl->tx_queue, skb); | |
234 | goto out; | |
235 | } else if (ret < 0) { | |
236 | dev_kfree_skb(skb); | |
237 | goto out; | |
238 | } else if (wl->tx_queue_stopped) { | |
239 | /* firmware buffer has space, restart queues */ | |
240 | wl1271_debug(DEBUG_TX, | |
241 | "complete_packet: waking queues"); | |
242 | ieee80211_wake_queues(wl->hw); | |
243 | wl->tx_queue_stopped = false; | |
244 | } | |
245 | } | |
246 | ||
247 | out: | |
248 | if (woken_up) | |
249 | wl1271_ps_elp_sleep(wl); | |
250 | ||
251 | mutex_unlock(&wl->mutex); | |
252 | } | |
253 | ||
254 | static void wl1271_tx_complete_packet(struct wl1271 *wl, | |
255 | struct wl1271_tx_hw_res_descr *result) | |
256 | { | |
257 | ||
258 | struct ieee80211_tx_info *info; | |
259 | struct sk_buff *skb; | |
260 | u32 header_len; | |
261 | int id = result->id; | |
262 | ||
263 | /* check for id legality */ | |
264 | if (id >= TX_HW_RESULT_QUEUE_LEN || wl->tx_frames[id] == NULL) { | |
265 | wl1271_warning("TX result illegal id: %d", id); | |
266 | return; | |
267 | } | |
268 | ||
269 | skb = wl->tx_frames[id]; | |
270 | info = IEEE80211_SKB_CB(skb); | |
271 | ||
272 | /* update packet status */ | |
273 | if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) { | |
274 | if (result->status == TX_SUCCESS) | |
275 | info->flags |= IEEE80211_TX_STAT_ACK; | |
276 | if (result->status & TX_RETRY_EXCEEDED) { | |
277 | /* FIXME */ | |
278 | /* info->status.excessive_retries = 1; */ | |
279 | wl->stats.excessive_retries++; | |
280 | } | |
281 | } | |
282 | ||
283 | /* FIXME */ | |
284 | /* info->status.retry_count = result->ack_failures; */ | |
285 | wl->stats.retry_count += result->ack_failures; | |
286 | ||
287 | /* get header len */ | |
288 | if (info->control.hw_key && | |
289 | info->control.hw_key->alg == ALG_TKIP) | |
290 | header_len = WL1271_TKIP_IV_SPACE + | |
291 | sizeof(struct wl1271_tx_hw_descr); | |
292 | else | |
293 | header_len = sizeof(struct wl1271_tx_hw_descr); | |
294 | ||
295 | wl1271_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x" | |
296 | " status 0x%x", | |
297 | result->id, skb, result->ack_failures, | |
298 | result->rate_class_index, result->status); | |
299 | ||
300 | /* remove private header from packet */ | |
301 | skb_pull(skb, header_len); | |
302 | ||
303 | /* return the packet to the stack */ | |
304 | ieee80211_tx_status(wl->hw, skb); | |
305 | wl->tx_frames[result->id] = NULL; | |
306 | } | |
307 | ||
308 | /* Called upon reception of a TX complete interrupt */ | |
309 | void wl1271_tx_complete(struct wl1271 *wl, u32 count) | |
310 | { | |
311 | struct wl1271_acx_mem_map *memmap = | |
312 | (struct wl1271_acx_mem_map *)wl->target_mem_map; | |
313 | u32 i; | |
314 | ||
315 | wl1271_debug(DEBUG_TX, "tx_complete received, packets: %d", count); | |
316 | ||
317 | /* read the tx results from the chipset */ | |
318 | wl1271_spi_mem_read(wl, memmap->tx_result, | |
319 | wl->tx_res_if, sizeof(*wl->tx_res_if)); | |
320 | ||
321 | /* verify that the result buffer is not getting overrun */ | |
322 | if (count > TX_HW_RESULT_QUEUE_LEN) { | |
323 | wl1271_warning("TX result overflow from chipset: %d", count); | |
324 | count = TX_HW_RESULT_QUEUE_LEN; | |
325 | } | |
326 | ||
327 | /* process the results */ | |
328 | for (i = 0; i < count; i++) { | |
329 | struct wl1271_tx_hw_res_descr *result; | |
330 | u8 offset = wl->tx_results_count & TX_HW_RESULT_QUEUE_LEN_MASK; | |
331 | ||
332 | /* process the packet */ | |
333 | result = &(wl->tx_res_if->tx_results_queue[offset]); | |
334 | wl1271_tx_complete_packet(wl, result); | |
335 | ||
336 | wl->tx_results_count++; | |
337 | } | |
338 | ||
339 | /* write host counter to chipset (to ack) */ | |
340 | wl1271_mem_write32(wl, memmap->tx_result + | |
341 | offsetof(struct wl1271_tx_hw_res_if, | |
342 | tx_result_host_counter), | |
343 | wl->tx_res_if->tx_result_fw_counter); | |
344 | } | |
345 | ||
346 | /* caller must hold wl->mutex */ | |
347 | void wl1271_tx_flush(struct wl1271 *wl) | |
348 | { | |
349 | int i; | |
350 | struct sk_buff *skb; | |
351 | struct ieee80211_tx_info *info; | |
352 | ||
353 | /* TX failure */ | |
354 | /* control->flags = 0; FIXME */ | |
355 | ||
356 | while ((skb = skb_dequeue(&wl->tx_queue))) { | |
357 | info = IEEE80211_SKB_CB(skb); | |
358 | ||
359 | wl1271_debug(DEBUG_TX, "flushing skb 0x%p", skb); | |
360 | ||
361 | if (!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)) | |
362 | continue; | |
363 | ||
364 | ieee80211_tx_status(wl->hw, skb); | |
365 | } | |
366 | ||
367 | for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) | |
368 | if (wl->tx_frames[i] != NULL) { | |
369 | skb = wl->tx_frames[i]; | |
370 | info = IEEE80211_SKB_CB(skb); | |
371 | ||
372 | if (!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)) | |
373 | continue; | |
374 | ||
375 | ieee80211_tx_status(wl->hw, skb); | |
376 | wl->tx_frames[i] = NULL; | |
377 | } | |
378 | } |