Commit | Line | Data |
---|---|---|
aa5a7aca IPG |
1 | /* |
2 | * Intel Wireless WiMAX Connection 2400m | |
3 | * Generic (non-bus specific) TX handling | |
4 | * | |
5 | * | |
6 | * Copyright (C) 2007-2008 Intel Corporation. All rights reserved. | |
7 | * | |
8 | * Redistribution and use in source and binary forms, with or without | |
9 | * modification, are permitted provided that the following conditions | |
10 | * are met: | |
11 | * | |
12 | * * Redistributions of source code must retain the above copyright | |
13 | * notice, this list of conditions and the following disclaimer. | |
14 | * * Redistributions in binary form must reproduce the above copyright | |
15 | * notice, this list of conditions and the following disclaimer in | |
16 | * the documentation and/or other materials provided with the | |
17 | * distribution. | |
18 | * * Neither the name of Intel Corporation nor the names of its | |
19 | * contributors may be used to endorse or promote products derived | |
20 | * from this software without specific prior written permission. | |
21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
23 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
24 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
25 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
26 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
27 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
28 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
30 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
31 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
32 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
33 | * | |
34 | * | |
35 | * Intel Corporation <linux-wimax@intel.com> | |
36 | * Yanir Lubetkin <yanirx.lubetkin@intel.com> | |
37 | * - Initial implementation | |
38 | * | |
39 | * Intel Corporation <linux-wimax@intel.com> | |
40 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | |
41 | * - Rewritten to use a single FIFO to lower the memory allocation | |
42 | * pressure and optimize cache hits when copying to the queue, as | |
43 | * well as splitting out bus-specific code. | |
44 | * | |
45 | * | |
46 | * Implements data transmission to the device; this is done through a | |
47 | * software FIFO, as data/control frames can be coalesced (while the | |
48 | * device is reading the previous tx transaction, others accumulate). | |
49 | * | |
50 | * A FIFO is used because at the end it is resource-cheaper that trying | |
51 | * to implement scatter/gather over USB. As well, most traffic is going | |
52 | * to be download (vs upload). | |
53 | * | |
54 | * The format for sending/receiving data to/from the i2400m is | |
55 | * described in detail in rx.c:PROTOCOL FORMAT. In here we implement | |
56 | * the transmission of that. This is split between a bus-independent | |
57 | * part that just prepares everything and a bus-specific part that | |
58 | * does the actual transmission over the bus to the device (in the | |
59 | * bus-specific driver). | |
60 | * | |
61 | * | |
62 | * The general format of a device-host transaction is MSG-HDR, PLD1, | |
63 | * PLD2...PLDN, PL1, PL2,...PLN, PADDING. | |
64 | * | |
65 | * Because we need the send payload descriptors and then payloads and | |
66 | * because it is kind of expensive to do scatterlists in USB (one URB | |
67 | * per node), it becomes cheaper to append all the data to a FIFO | |
68 | * (copying to a FIFO potentially in cache is cheaper). | |
69 | * | |
70 | * Then the bus-specific code takes the parts of that FIFO that are | |
71 | * written and passes them to the device. | |
72 | * | |
73 | * So the concepts to keep in mind there are: | |
74 | * | |
75 | * We use a FIFO to queue the data in a linear buffer. We first append | |
76 | * a MSG-HDR, space for I2400M_TX_PLD_MAX payload descriptors and then | |
77 | * go appending payloads until we run out of space or of payload | |
78 | * descriptors. Then we append padding to make the whole transaction a | |
79 | * multiple of i2400m->bus_tx_block_size (as defined by the bus layer). | |
80 | * | |
81 | * - A TX message: a combination of a message header, payload | |
82 | * descriptors and payloads. | |
83 | * | |
84 | * Open: it is marked as active (i2400m->tx_msg is valid) and we | |
85 | * can keep adding payloads to it. | |
86 | * | |
87 | * Closed: we are not appending more payloads to this TX message | |
88 | * (exahusted space in the queue, too many payloads or | |
89 | * whichever). We have appended padding so the whole message | |
90 | * length is aligned to i2400m->bus_tx_block_size (as set by the | |
91 | * bus/transport layer). | |
92 | * | |
93 | * - Most of the time we keep a TX message open to which we append | |
94 | * payloads. | |
95 | * | |
96 | * - If we are going to append and there is no more space (we are at | |
97 | * the end of the FIFO), we close the message, mark the rest of the | |
98 | * FIFO space unusable (skip_tail), create a new message at the | |
99 | * beginning of the FIFO (if there is space) and append the message | |
100 | * there. | |
101 | * | |
102 | * This is because we need to give linear TX messages to the bus | |
103 | * engine. So we don't write a message to the remaining FIFO space | |
104 | * until the tail and continue at the head of it. | |
105 | * | |
106 | * - We overload one of the fields in the message header to use it as | |
107 | * 'size' of the TX message, so we can iterate over them. It also | |
108 | * contains a flag that indicates if we have to skip it or not. | |
109 | * When we send the buffer, we update that to its real on-the-wire | |
110 | * value. | |
111 | * | |
112 | * - The MSG-HDR PLD1...PLD2 stuff has to be a size multiple of 16. | |
113 | * | |
114 | * It follows that if MSG-HDR says we have N messages, the whole | |
115 | * header + descriptors is 16 + 4*N; for those to be a multiple of | |
116 | * 16, it follows that N can be 4, 8, 12, ... (32, 48, 64, 80... | |
117 | * bytes). | |
118 | * | |
119 | * So if we have only 1 payload, we have to submit a header that in | |
120 | * all truth has space for 4. | |
121 | * | |
122 | * The implication is that we reserve space for 12 (64 bytes); but | |
123 | * if we fill up only (eg) 2, our header becomes 32 bytes only. So | |
124 | * the TX engine has to shift those 32 bytes of msg header and 2 | |
125 | * payloads and padding so that right after it the payloads start | |
126 | * and the TX engine has to know about that. | |
127 | * | |
128 | * It is cheaper to move the header up than the whole payloads down. | |
129 | * | |
130 | * We do this in i2400m_tx_close(). See 'i2400m_msg_hdr->offset'. | |
131 | * | |
132 | * - Each payload has to be size-padded to 16 bytes; before appending | |
133 | * it, we just do it. | |
134 | * | |
135 | * - The whole message has to be padded to i2400m->bus_tx_block_size; | |
136 | * we do this at close time. Thus, when reserving space for the | |
137 | * payload, we always make sure there is also free space for this | |
138 | * padding that sooner or later will happen. | |
139 | * | |
140 | * When we append a message, we tell the bus specific code to kick in | |
141 | * TXs. It will TX (in parallel) until the buffer is exhausted--hence | |
142 | * the lockin we do. The TX code will only send a TX message at the | |
143 | * time (which remember, might contain more than one payload). Of | |
144 | * course, when the bus-specific driver attempts to TX a message that | |
145 | * is still open, it gets closed first. | |
146 | * | |
147 | * Gee, this is messy; well a picture. In the example below we have a | |
148 | * partially full FIFO, with a closed message ready to be delivered | |
149 | * (with a moved message header to make sure it is size-aligned to | |
150 | * 16), TAIL room that was unusable (and thus is marked with a message | |
151 | * header that says 'skip this') and at the head of the buffer, an | |
152 | * imcomplete message with a couple of payloads. | |
153 | * | |
154 | * N ___________________________________________________ | |
155 | * | | | |
156 | * | TAIL room | | |
157 | * | | | |
158 | * | msg_hdr to skip (size |= 0x80000) | | |
159 | * |---------------------------------------------------|------- | |
160 | * | | /|\ | |
161 | * | | | | |
162 | * | TX message padding | | | |
163 | * | | | | |
164 | * | | | | |
165 | * |- - - - - - - - - - - - - - - - - - - - - - - - - -| | | |
166 | * | | | | |
167 | * | payload 1 | | | |
168 | * | | N * tx_block_size | |
169 | * | | | | |
170 | * |- - - - - - - - - - - - - - - - - - - - - - - - - -| | | |
171 | * | | | | |
172 | * | payload 1 | | | |
173 | * | | | | |
174 | * | | | | |
175 | * |- - - - - - - - - - - - - - - - - - - - - - - - - -|- -|- - - - | |
176 | * | padding 3 /|\ | | /|\ | |
177 | * | padding 2 | | | | | |
178 | * | pld 1 32 bytes (2 * 16) | | | | |
179 | * | pld 0 | | | | | |
180 | * | moved msg_hdr \|/ | \|/ | | |
181 | * |- - - - - - - - - - - - - - - - - - - - - - - - - -|- - - | | |
182 | * | | _PLD_SIZE | |
183 | * | unused | | | |
184 | * | | | | |
185 | * |- - - - - - - - - - - - - - - - - - - - - - - - - -| | | |
186 | * | msg_hdr (size X) [this message is closed] | \|/ | |
187 | * |===================================================|========== <=== OUT | |
188 | * | | | |
189 | * | | | |
190 | * | | | |
191 | * | Free rooom | | |
192 | * | | | |
193 | * | | | |
194 | * | | | |
195 | * | | | |
196 | * | | | |
197 | * | | | |
198 | * | | | |
199 | * | | | |
200 | * | | | |
201 | * |===================================================|========== <=== IN | |
202 | * | | | |
203 | * | | | |
204 | * | | | |
205 | * | | | |
206 | * | payload 1 | | |
207 | * | | | |
208 | * | | | |
209 | * |- - - - - - - - - - - - - - - - - - - - - - - - - -| | |
210 | * | | | |
211 | * | payload 0 | | |
212 | * | | | |
213 | * | | | |
214 | * |- - - - - - - - - - - - - - - - - - - - - - - - - -| | |
215 | * | pld 11 /|\ | | |
216 | * | ... | | | |
217 | * | pld 1 64 bytes (2 * 16) | | |
218 | * | pld 0 | | | |
219 | * | msg_hdr (size X) \|/ [message is open] | | |
220 | * 0 --------------------------------------------------- | |
221 | * | |
222 | * | |
223 | * ROADMAP | |
224 | * | |
225 | * i2400m_tx_setup() Called by i2400m_setup | |
226 | * i2400m_tx_release() Called by i2400m_release() | |
227 | * | |
228 | * i2400m_tx() Called to send data or control frames | |
229 | * i2400m_tx_fifo_push() Allocates append-space in the FIFO | |
230 | * i2400m_tx_new() Opens a new message in the FIFO | |
231 | * i2400m_tx_fits() Checks if a new payload fits in the message | |
232 | * i2400m_tx_close() Closes an open message in the FIFO | |
233 | * i2400m_tx_skip_tail() Marks unusable FIFO tail space | |
234 | * i2400m->bus_tx_kick() | |
235 | * | |
236 | * Now i2400m->bus_tx_kick() is the the bus-specific driver backend | |
237 | * implementation; that would do: | |
238 | * | |
239 | * i2400m->bus_tx_kick() | |
240 | * i2400m_tx_msg_get() Gets first message ready to go | |
241 | * ...sends it... | |
242 | * i2400m_tx_msg_sent() Ack the message is sent; repeat from | |
243 | * _tx_msg_get() until it returns NULL | |
244 | * (FIFO empty). | |
245 | */ | |
246 | #include <linux/netdevice.h> | |
5a0e3ad6 | 247 | #include <linux/slab.h> |
aa5a7aca IPG |
248 | #include "i2400m.h" |
249 | ||
250 | ||
251 | #define D_SUBMODULE tx | |
252 | #include "debug-levels.h" | |
253 | ||
254 | enum { | |
255 | /** | |
256 | * TX Buffer size | |
257 | * | |
258 | * Doc says maximum transaction is 16KiB. If we had 16KiB en | |
259 | * route and 16KiB being queued, it boils down to needing | |
260 | * 32KiB. | |
261 | */ | |
262 | I2400M_TX_BUF_SIZE = 32768, | |
263 | /** | |
264 | * Message header and payload descriptors have to be 16 | |
265 | * aligned (16 + 4 * N = 16 * M). If we take that average sent | |
266 | * packets are MTU size (~1400-~1500) it follows that we could | |
267 | * fit at most 10-11 payloads in one transaction. To meet the | |
268 | * alignment requirement, that means we need to leave space | |
269 | * for 12 (64 bytes). To simplify, we leave space for that. If | |
270 | * at the end there are less, we pad up to the nearest | |
271 | * multiple of 16. | |
272 | */ | |
273 | I2400M_TX_PLD_MAX = 12, | |
274 | I2400M_TX_PLD_SIZE = sizeof(struct i2400m_msg_hdr) | |
275 | + I2400M_TX_PLD_MAX * sizeof(struct i2400m_pld), | |
276 | I2400M_TX_SKIP = 0x80000000, | |
277 | }; | |
278 | ||
279 | #define TAIL_FULL ((void *)~(unsigned long)NULL) | |
280 | ||
2971a5ba IPG |
281 | /* |
282 | * Calculate how much tail room is available | |
283 | * | |
284 | * Note the trick here. This path is ONLY caleed for Case A (see | |
285 | * i2400m_tx_fifo_push() below), where we have: | |
286 | * | |
287 | * Case A | |
288 | * N ___________ | |
289 | * | tail room | | |
290 | * | | | |
291 | * |<- IN ->| | |
292 | * | | | |
293 | * | data | | |
294 | * | | | |
295 | * |<- OUT ->| | |
296 | * | | | |
297 | * | head room | | |
298 | * 0 ----------- | |
299 | * | |
300 | * When calculating the tail_room, tx_in might get to be zero if | |
301 | * i2400m->tx_in is right at the end of the buffer (really full | |
302 | * buffer) if there is no head room. In this case, tail_room would be | |
303 | * I2400M_TX_BUF_SIZE, although it is actually zero. Hence the final | |
304 | * mod (%) operation. However, when doing this kind of optimization, | |
305 | * i2400m->tx_in being zero would fail, so we treat is an a special | |
306 | * case. | |
307 | */ | |
308 | static inline | |
309 | size_t __i2400m_tx_tail_room(struct i2400m *i2400m) | |
310 | { | |
311 | size_t tail_room; | |
312 | size_t tx_in; | |
313 | ||
2d44f204 | 314 | if (unlikely(i2400m->tx_in == 0)) |
2971a5ba IPG |
315 | return I2400M_TX_BUF_SIZE; |
316 | tx_in = i2400m->tx_in % I2400M_TX_BUF_SIZE; | |
317 | tail_room = I2400M_TX_BUF_SIZE - tx_in; | |
318 | tail_room %= I2400M_TX_BUF_SIZE; | |
319 | return tail_room; | |
320 | } | |
321 | ||
322 | ||
aa5a7aca IPG |
323 | /* |
324 | * Allocate @size bytes in the TX fifo, return a pointer to it | |
325 | * | |
326 | * @i2400m: device descriptor | |
327 | * @size: size of the buffer we need to allocate | |
328 | * @padding: ensure that there is at least this many bytes of free | |
329 | * contiguous space in the fifo. This is needed because later on | |
330 | * we might need to add padding. | |
331 | * | |
332 | * Returns: | |
333 | * | |
334 | * Pointer to the allocated space. NULL if there is no | |
335 | * space. TAIL_FULL if there is no space at the tail but there is at | |
336 | * the head (Case B below). | |
337 | * | |
338 | * These are the two basic cases we need to keep an eye for -- it is | |
339 | * much better explained in linux/kernel/kfifo.c, but this code | |
340 | * basically does the same. No rocket science here. | |
341 | * | |
342 | * Case A Case B | |
343 | * N ___________ ___________ | |
344 | * | tail room | | data | | |
345 | * | | | | | |
346 | * |<- IN ->| |<- OUT ->| | |
347 | * | | | | | |
348 | * | data | | room | | |
349 | * | | | | | |
350 | * |<- OUT ->| |<- IN ->| | |
351 | * | | | | | |
352 | * | head room | | data | | |
353 | * 0 ----------- ----------- | |
354 | * | |
355 | * We allocate only *contiguous* space. | |
356 | * | |
357 | * We can allocate only from 'room'. In Case B, it is simple; in case | |
358 | * A, we only try from the tail room; if it is not enough, we just | |
359 | * fail and return TAIL_FULL and let the caller figure out if we wants to | |
360 | * skip the tail room and try to allocate from the head. | |
361 | * | |
362 | * Note: | |
363 | * | |
364 | * Assumes i2400m->tx_lock is taken, and we use that as a barrier | |
365 | * | |
366 | * The indexes keep increasing and we reset them to zero when we | |
367 | * pop data off the queue | |
368 | */ | |
369 | static | |
370 | void *i2400m_tx_fifo_push(struct i2400m *i2400m, size_t size, size_t padding) | |
371 | { | |
372 | struct device *dev = i2400m_dev(i2400m); | |
373 | size_t room, tail_room, needed_size; | |
374 | void *ptr; | |
375 | ||
376 | needed_size = size + padding; | |
377 | room = I2400M_TX_BUF_SIZE - (i2400m->tx_in - i2400m->tx_out); | |
378 | if (room < needed_size) { /* this takes care of Case B */ | |
379 | d_printf(2, dev, "fifo push %zu/%zu: no space\n", | |
380 | size, padding); | |
381 | return NULL; | |
382 | } | |
383 | /* Is there space at the tail? */ | |
2971a5ba | 384 | tail_room = __i2400m_tx_tail_room(i2400m); |
aa5a7aca IPG |
385 | if (tail_room < needed_size) { |
386 | if (i2400m->tx_out % I2400M_TX_BUF_SIZE | |
387 | < i2400m->tx_in % I2400M_TX_BUF_SIZE) { | |
388 | d_printf(2, dev, "fifo push %zu/%zu: tail full\n", | |
389 | size, padding); | |
390 | return TAIL_FULL; /* There might be head space */ | |
391 | } else { | |
392 | d_printf(2, dev, "fifo push %zu/%zu: no head space\n", | |
393 | size, padding); | |
394 | return NULL; /* There is no space */ | |
395 | } | |
396 | } | |
397 | ptr = i2400m->tx_buf + i2400m->tx_in % I2400M_TX_BUF_SIZE; | |
398 | d_printf(2, dev, "fifo push %zu/%zu: at @%zu\n", size, padding, | |
399 | i2400m->tx_in % I2400M_TX_BUF_SIZE); | |
400 | i2400m->tx_in += size; | |
401 | return ptr; | |
402 | } | |
403 | ||
404 | ||
405 | /* | |
406 | * Mark the tail of the FIFO buffer as 'to-skip' | |
407 | * | |
408 | * We should never hit the BUG_ON() because all the sizes we push to | |
409 | * the FIFO are padded to be a multiple of 16 -- the size of *msg | |
410 | * (I2400M_PL_PAD for the payloads, I2400M_TX_PLD_SIZE for the | |
411 | * header). | |
412 | * | |
2971a5ba IPG |
413 | * Tail room can get to be zero if a message was opened when there was |
414 | * space only for a header. _tx_close() will mark it as to-skip (as it | |
415 | * will have no payloads) and there will be no more space to flush, so | |
416 | * nothing has to be done here. This is probably cheaper than ensuring | |
417 | * in _tx_new() that there is some space for payloads...as we could | |
418 | * always possibly hit the same problem if the payload wouldn't fit. | |
419 | * | |
aa5a7aca IPG |
420 | * Note: |
421 | * | |
422 | * Assumes i2400m->tx_lock is taken, and we use that as a barrier | |
2971a5ba IPG |
423 | * |
424 | * This path is only taken for Case A FIFO situations [see | |
425 | * i2400m_tx_fifo_push()] | |
aa5a7aca IPG |
426 | */ |
427 | static | |
428 | void i2400m_tx_skip_tail(struct i2400m *i2400m) | |
429 | { | |
430 | struct device *dev = i2400m_dev(i2400m); | |
431 | size_t tx_in = i2400m->tx_in % I2400M_TX_BUF_SIZE; | |
2971a5ba | 432 | size_t tail_room = __i2400m_tx_tail_room(i2400m); |
aa5a7aca | 433 | struct i2400m_msg_hdr *msg = i2400m->tx_buf + tx_in; |
2971a5ba IPG |
434 | if (unlikely(tail_room == 0)) |
435 | return; | |
aa5a7aca IPG |
436 | BUG_ON(tail_room < sizeof(*msg)); |
437 | msg->size = tail_room | I2400M_TX_SKIP; | |
438 | d_printf(2, dev, "skip tail: skipping %zu bytes @%zu\n", | |
439 | tail_room, tx_in); | |
440 | i2400m->tx_in += tail_room; | |
441 | } | |
442 | ||
443 | ||
444 | /* | |
445 | * Check if a skb will fit in the TX queue's current active TX | |
446 | * message (if there are still descriptors left unused). | |
447 | * | |
448 | * Returns: | |
449 | * 0 if the message won't fit, 1 if it will. | |
450 | * | |
451 | * Note: | |
452 | * | |
453 | * Assumes a TX message is active (i2400m->tx_msg). | |
454 | * | |
455 | * Assumes i2400m->tx_lock is taken, and we use that as a barrier | |
456 | */ | |
457 | static | |
458 | unsigned i2400m_tx_fits(struct i2400m *i2400m) | |
459 | { | |
460 | struct i2400m_msg_hdr *msg_hdr = i2400m->tx_msg; | |
461 | return le16_to_cpu(msg_hdr->num_pls) < I2400M_TX_PLD_MAX; | |
462 | ||
463 | } | |
464 | ||
465 | ||
466 | /* | |
467 | * Start a new TX message header in the queue. | |
468 | * | |
469 | * Reserve memory from the base FIFO engine and then just initialize | |
470 | * the message header. | |
471 | * | |
472 | * We allocate the biggest TX message header we might need (one that'd | |
473 | * fit I2400M_TX_PLD_MAX payloads) -- when it is closed it will be | |
474 | * 'ironed it out' and the unneeded parts removed. | |
475 | * | |
476 | * NOTE: | |
477 | * | |
478 | * Assumes that the previous message is CLOSED (eg: either | |
479 | * there was none or 'i2400m_tx_close()' was called on it). | |
480 | * | |
481 | * Assumes i2400m->tx_lock is taken, and we use that as a barrier | |
482 | */ | |
483 | static | |
484 | void i2400m_tx_new(struct i2400m *i2400m) | |
485 | { | |
486 | struct device *dev = i2400m_dev(i2400m); | |
487 | struct i2400m_msg_hdr *tx_msg; | |
488 | BUG_ON(i2400m->tx_msg != NULL); | |
489 | try_head: | |
490 | tx_msg = i2400m_tx_fifo_push(i2400m, I2400M_TX_PLD_SIZE, 0); | |
491 | if (tx_msg == NULL) | |
492 | goto out; | |
493 | else if (tx_msg == TAIL_FULL) { | |
494 | i2400m_tx_skip_tail(i2400m); | |
495 | d_printf(2, dev, "new TX message: tail full, trying head\n"); | |
496 | goto try_head; | |
497 | } | |
498 | memset(tx_msg, 0, I2400M_TX_PLD_SIZE); | |
499 | tx_msg->size = I2400M_TX_PLD_SIZE; | |
500 | out: | |
501 | i2400m->tx_msg = tx_msg; | |
502 | d_printf(2, dev, "new TX message: %p @%zu\n", | |
503 | tx_msg, (void *) tx_msg - i2400m->tx_buf); | |
504 | } | |
505 | ||
506 | ||
507 | /* | |
508 | * Finalize the current TX message header | |
509 | * | |
510 | * Sets the message header to be at the proper location depending on | |
511 | * how many descriptors we have (check documentation at the file's | |
512 | * header for more info on that). | |
513 | * | |
514 | * Appends padding bytes to make sure the whole TX message (counting | |
515 | * from the 'relocated' message header) is aligned to | |
516 | * tx_block_size. We assume the _append() code has left enough space | |
517 | * in the FIFO for that. If there are no payloads, just pass, as it | |
518 | * won't be transferred. | |
519 | * | |
520 | * The amount of padding bytes depends on how many payloads are in the | |
521 | * TX message, as the "msg header and payload descriptors" will be | |
522 | * shifted up in the buffer. | |
523 | */ | |
524 | static | |
525 | void i2400m_tx_close(struct i2400m *i2400m) | |
526 | { | |
527 | struct device *dev = i2400m_dev(i2400m); | |
528 | struct i2400m_msg_hdr *tx_msg = i2400m->tx_msg; | |
529 | struct i2400m_msg_hdr *tx_msg_moved; | |
530 | size_t aligned_size, padding, hdr_size; | |
531 | void *pad_buf; | |
c56affaf | 532 | unsigned num_pls; |
aa5a7aca IPG |
533 | |
534 | if (tx_msg->size & I2400M_TX_SKIP) /* a skipper? nothing to do */ | |
535 | goto out; | |
c56affaf IPG |
536 | num_pls = le16_to_cpu(tx_msg->num_pls); |
537 | /* We can get this situation when a new message was started | |
538 | * and there was no space to add payloads before hitting the | |
539 | tail (and taking padding into consideration). */ | |
540 | if (num_pls == 0) { | |
541 | tx_msg->size |= I2400M_TX_SKIP; | |
542 | goto out; | |
543 | } | |
aa5a7aca IPG |
544 | /* Relocate the message header |
545 | * | |
546 | * Find the current header size, align it to 16 and if we need | |
547 | * to move it so the tail is next to the payloads, move it and | |
548 | * set the offset. | |
549 | * | |
550 | * If it moved, this header is good only for transmission; the | |
551 | * original one (it is kept if we moved) is still used to | |
552 | * figure out where the next TX message starts (and where the | |
553 | * offset to the moved header is). | |
554 | */ | |
555 | hdr_size = sizeof(*tx_msg) | |
556 | + le16_to_cpu(tx_msg->num_pls) * sizeof(tx_msg->pld[0]); | |
8593a196 | 557 | hdr_size = ALIGN(hdr_size, I2400M_PL_ALIGN); |
aa5a7aca IPG |
558 | tx_msg->offset = I2400M_TX_PLD_SIZE - hdr_size; |
559 | tx_msg_moved = (void *) tx_msg + tx_msg->offset; | |
560 | memmove(tx_msg_moved, tx_msg, hdr_size); | |
561 | tx_msg_moved->size -= tx_msg->offset; | |
562 | /* | |
563 | * Now figure out how much we have to add to the (moved!) | |
564 | * message so the size is a multiple of i2400m->bus_tx_block_size. | |
565 | */ | |
566 | aligned_size = ALIGN(tx_msg_moved->size, i2400m->bus_tx_block_size); | |
567 | padding = aligned_size - tx_msg_moved->size; | |
568 | if (padding > 0) { | |
569 | pad_buf = i2400m_tx_fifo_push(i2400m, padding, 0); | |
570 | if (unlikely(WARN_ON(pad_buf == NULL | |
571 | || pad_buf == TAIL_FULL))) { | |
572 | /* This should not happen -- append should verify | |
573 | * there is always space left at least to append | |
574 | * tx_block_size */ | |
575 | dev_err(dev, | |
576 | "SW BUG! Possible data leakage from memory the " | |
577 | "device should not read for padding - " | |
578 | "size %lu aligned_size %zu tx_buf %p in " | |
579 | "%zu out %zu\n", | |
580 | (unsigned long) tx_msg_moved->size, | |
581 | aligned_size, i2400m->tx_buf, i2400m->tx_in, | |
582 | i2400m->tx_out); | |
583 | } else | |
584 | memset(pad_buf, 0xad, padding); | |
585 | } | |
586 | tx_msg_moved->padding = cpu_to_le16(padding); | |
587 | tx_msg_moved->size += padding; | |
588 | if (tx_msg != tx_msg_moved) | |
589 | tx_msg->size += padding; | |
590 | out: | |
591 | i2400m->tx_msg = NULL; | |
592 | } | |
593 | ||
594 | ||
595 | /** | |
596 | * i2400m_tx - send the data in a buffer to the device | |
597 | * | |
598 | * @buf: pointer to the buffer to transmit | |
599 | * | |
600 | * @buf_len: buffer size | |
601 | * | |
602 | * @pl_type: type of the payload we are sending. | |
603 | * | |
604 | * Returns: | |
605 | * 0 if ok, < 0 errno code on error (-ENOSPC, if there is no more | |
606 | * room for the message in the queue). | |
607 | * | |
608 | * Appends the buffer to the TX FIFO and notifies the bus-specific | |
609 | * part of the driver that there is new data ready to transmit. | |
610 | * Once this function returns, the buffer has been copied, so it can | |
611 | * be reused. | |
612 | * | |
613 | * The steps followed to append are explained in detail in the file | |
614 | * header. | |
615 | * | |
616 | * Whenever we write to a message, we increase msg->size, so it | |
617 | * reflects exactly how big the message is. This is needed so that if | |
618 | * we concatenate two messages before they can be sent, the code that | |
619 | * sends the messages can find the boundaries (and it will replace the | |
620 | * size with the real barker before sending). | |
621 | * | |
622 | * Note: | |
623 | * | |
624 | * Cold and warm reset payloads need to be sent as a single | |
625 | * payload, so we handle that. | |
626 | */ | |
627 | int i2400m_tx(struct i2400m *i2400m, const void *buf, size_t buf_len, | |
628 | enum i2400m_pt pl_type) | |
629 | { | |
630 | int result = -ENOSPC; | |
631 | struct device *dev = i2400m_dev(i2400m); | |
632 | unsigned long flags; | |
633 | size_t padded_len; | |
634 | void *ptr; | |
635 | unsigned is_singleton = pl_type == I2400M_PT_RESET_WARM | |
636 | || pl_type == I2400M_PT_RESET_COLD; | |
637 | ||
638 | d_fnstart(3, dev, "(i2400m %p skb %p [%zu bytes] pt %u)\n", | |
639 | i2400m, buf, buf_len, pl_type); | |
8593a196 | 640 | padded_len = ALIGN(buf_len, I2400M_PL_ALIGN); |
aa5a7aca IPG |
641 | d_printf(5, dev, "padded_len %zd buf_len %zd\n", padded_len, buf_len); |
642 | /* If there is no current TX message, create one; if the | |
643 | * current one is out of payload slots or we have a singleton, | |
644 | * close it and start a new one */ | |
645 | spin_lock_irqsave(&i2400m->tx_lock, flags); | |
46c50147 IPG |
646 | result = -ESHUTDOWN; |
647 | if (i2400m->tx_buf == NULL) | |
648 | goto error_tx_new; | |
aa5a7aca IPG |
649 | try_new: |
650 | if (unlikely(i2400m->tx_msg == NULL)) | |
651 | i2400m_tx_new(i2400m); | |
652 | else if (unlikely(!i2400m_tx_fits(i2400m) | |
653 | || (is_singleton && i2400m->tx_msg->num_pls != 0))) { | |
654 | d_printf(2, dev, "closing TX message (fits %u singleton " | |
655 | "%u num_pls %u)\n", i2400m_tx_fits(i2400m), | |
656 | is_singleton, i2400m->tx_msg->num_pls); | |
657 | i2400m_tx_close(i2400m); | |
658 | i2400m_tx_new(i2400m); | |
659 | } | |
59063afa IPG |
660 | if (i2400m->tx_msg == NULL) |
661 | goto error_tx_new; | |
aa5a7aca IPG |
662 | if (i2400m->tx_msg->size + padded_len > I2400M_TX_BUF_SIZE / 2) { |
663 | d_printf(2, dev, "TX: message too big, going new\n"); | |
664 | i2400m_tx_close(i2400m); | |
665 | i2400m_tx_new(i2400m); | |
666 | } | |
667 | if (i2400m->tx_msg == NULL) | |
668 | goto error_tx_new; | |
669 | /* So we have a current message header; now append space for | |
670 | * the message -- if there is not enough, try the head */ | |
671 | ptr = i2400m_tx_fifo_push(i2400m, padded_len, | |
672 | i2400m->bus_tx_block_size); | |
673 | if (ptr == TAIL_FULL) { /* Tail is full, try head */ | |
674 | d_printf(2, dev, "pl append: tail full\n"); | |
675 | i2400m_tx_close(i2400m); | |
676 | i2400m_tx_skip_tail(i2400m); | |
677 | goto try_new; | |
678 | } else if (ptr == NULL) { /* All full */ | |
679 | result = -ENOSPC; | |
680 | d_printf(2, dev, "pl append: all full\n"); | |
681 | } else { /* Got space, copy it, set padding */ | |
682 | struct i2400m_msg_hdr *tx_msg = i2400m->tx_msg; | |
683 | unsigned num_pls = le16_to_cpu(tx_msg->num_pls); | |
684 | memcpy(ptr, buf, buf_len); | |
685 | memset(ptr + buf_len, 0xad, padded_len - buf_len); | |
686 | i2400m_pld_set(&tx_msg->pld[num_pls], buf_len, pl_type); | |
687 | d_printf(3, dev, "pld 0x%08x (type 0x%1x len 0x%04zx\n", | |
688 | le32_to_cpu(tx_msg->pld[num_pls].val), | |
689 | pl_type, buf_len); | |
690 | tx_msg->num_pls = le16_to_cpu(num_pls+1); | |
691 | tx_msg->size += padded_len; | |
692 | d_printf(2, dev, "TX: appended %zu b (up to %u b) pl #%u \n", | |
693 | padded_len, tx_msg->size, num_pls+1); | |
694 | d_printf(2, dev, | |
695 | "TX: appended hdr @%zu %zu b pl #%u @%zu %zu/%zu b\n", | |
696 | (void *)tx_msg - i2400m->tx_buf, (size_t)tx_msg->size, | |
697 | num_pls+1, ptr - i2400m->tx_buf, buf_len, padded_len); | |
698 | result = 0; | |
699 | if (is_singleton) | |
700 | i2400m_tx_close(i2400m); | |
701 | } | |
702 | error_tx_new: | |
703 | spin_unlock_irqrestore(&i2400m->tx_lock, flags); | |
46c50147 IPG |
704 | /* kick in most cases, except when the TX subsys is down, as |
705 | * it might free space */ | |
706 | if (likely(result != -ESHUTDOWN)) | |
707 | i2400m->bus_tx_kick(i2400m); | |
aa5a7aca IPG |
708 | d_fnend(3, dev, "(i2400m %p skb %p [%zu bytes] pt %u) = %d\n", |
709 | i2400m, buf, buf_len, pl_type, result); | |
710 | return result; | |
711 | } | |
712 | EXPORT_SYMBOL_GPL(i2400m_tx); | |
713 | ||
714 | ||
715 | /** | |
716 | * i2400m_tx_msg_get - Get the first TX message in the FIFO to start sending it | |
717 | * | |
718 | * @i2400m: device descriptors | |
719 | * @bus_size: where to place the size of the TX message | |
720 | * | |
721 | * Called by the bus-specific driver to get the first TX message at | |
722 | * the FIF that is ready for transmission. | |
723 | * | |
724 | * It sets the state in @i2400m to indicate the bus-specific driver is | |
725 | * transfering that message (i2400m->tx_msg_size). | |
726 | * | |
727 | * Once the transfer is completed, call i2400m_tx_msg_sent(). | |
728 | * | |
729 | * Notes: | |
730 | * | |
731 | * The size of the TX message to be transmitted might be smaller than | |
732 | * that of the TX message in the FIFO (in case the header was | |
733 | * shorter). Hence, we copy it in @bus_size, for the bus layer to | |
734 | * use. We keep the message's size in i2400m->tx_msg_size so that | |
735 | * when the bus later is done transferring we know how much to | |
736 | * advance the fifo. | |
737 | * | |
738 | * We collect statistics here as all the data is available and we | |
739 | * assume it is going to work [see i2400m_tx_msg_sent()]. | |
740 | */ | |
741 | struct i2400m_msg_hdr *i2400m_tx_msg_get(struct i2400m *i2400m, | |
742 | size_t *bus_size) | |
743 | { | |
744 | struct device *dev = i2400m_dev(i2400m); | |
745 | struct i2400m_msg_hdr *tx_msg, *tx_msg_moved; | |
746 | unsigned long flags, pls; | |
747 | ||
748 | d_fnstart(3, dev, "(i2400m %p bus_size %p)\n", i2400m, bus_size); | |
749 | spin_lock_irqsave(&i2400m->tx_lock, flags); | |
46c50147 IPG |
750 | tx_msg_moved = NULL; |
751 | if (i2400m->tx_buf == NULL) | |
752 | goto out_unlock; | |
aa5a7aca IPG |
753 | skip: |
754 | tx_msg_moved = NULL; | |
755 | if (i2400m->tx_in == i2400m->tx_out) { /* Empty FIFO? */ | |
756 | i2400m->tx_in = 0; | |
757 | i2400m->tx_out = 0; | |
758 | d_printf(2, dev, "TX: FIFO empty: resetting\n"); | |
759 | goto out_unlock; | |
760 | } | |
761 | tx_msg = i2400m->tx_buf + i2400m->tx_out % I2400M_TX_BUF_SIZE; | |
762 | if (tx_msg->size & I2400M_TX_SKIP) { /* skip? */ | |
763 | d_printf(2, dev, "TX: skip: msg @%zu (%zu b)\n", | |
764 | i2400m->tx_out % I2400M_TX_BUF_SIZE, | |
765 | (size_t) tx_msg->size & ~I2400M_TX_SKIP); | |
766 | i2400m->tx_out += tx_msg->size & ~I2400M_TX_SKIP; | |
767 | goto skip; | |
768 | } | |
769 | ||
770 | if (tx_msg->num_pls == 0) { /* No payloads? */ | |
771 | if (tx_msg == i2400m->tx_msg) { /* open, we are done */ | |
772 | d_printf(2, dev, | |
773 | "TX: FIFO empty: open msg w/o payloads @%zu\n", | |
774 | (void *) tx_msg - i2400m->tx_buf); | |
775 | tx_msg = NULL; | |
776 | goto out_unlock; | |
777 | } else { /* closed, skip it */ | |
778 | d_printf(2, dev, | |
779 | "TX: skip msg w/o payloads @%zu (%zu b)\n", | |
780 | (void *) tx_msg - i2400m->tx_buf, | |
781 | (size_t) tx_msg->size); | |
782 | i2400m->tx_out += tx_msg->size & ~I2400M_TX_SKIP; | |
783 | goto skip; | |
784 | } | |
785 | } | |
786 | if (tx_msg == i2400m->tx_msg) /* open msg? */ | |
787 | i2400m_tx_close(i2400m); | |
788 | ||
789 | /* Now we have a valid TX message (with payloads) to TX */ | |
790 | tx_msg_moved = (void *) tx_msg + tx_msg->offset; | |
791 | i2400m->tx_msg_size = tx_msg->size; | |
792 | *bus_size = tx_msg_moved->size; | |
793 | d_printf(2, dev, "TX: pid %d msg hdr at @%zu offset +@%zu " | |
794 | "size %zu bus_size %zu\n", | |
795 | current->pid, (void *) tx_msg - i2400m->tx_buf, | |
796 | (size_t) tx_msg->offset, (size_t) tx_msg->size, | |
797 | (size_t) tx_msg_moved->size); | |
798 | tx_msg_moved->barker = le32_to_cpu(I2400M_H2D_PREVIEW_BARKER); | |
799 | tx_msg_moved->sequence = le32_to_cpu(i2400m->tx_sequence++); | |
800 | ||
801 | pls = le32_to_cpu(tx_msg_moved->num_pls); | |
802 | i2400m->tx_pl_num += pls; /* Update stats */ | |
803 | if (pls > i2400m->tx_pl_max) | |
804 | i2400m->tx_pl_max = pls; | |
805 | if (pls < i2400m->tx_pl_min) | |
806 | i2400m->tx_pl_min = pls; | |
807 | i2400m->tx_num++; | |
808 | i2400m->tx_size_acc += *bus_size; | |
809 | if (*bus_size < i2400m->tx_size_min) | |
810 | i2400m->tx_size_min = *bus_size; | |
811 | if (*bus_size > i2400m->tx_size_max) | |
812 | i2400m->tx_size_max = *bus_size; | |
813 | out_unlock: | |
814 | spin_unlock_irqrestore(&i2400m->tx_lock, flags); | |
815 | d_fnstart(3, dev, "(i2400m %p bus_size %p [%zu]) = %p\n", | |
816 | i2400m, bus_size, *bus_size, tx_msg_moved); | |
817 | return tx_msg_moved; | |
818 | } | |
819 | EXPORT_SYMBOL_GPL(i2400m_tx_msg_get); | |
820 | ||
821 | ||
822 | /** | |
823 | * i2400m_tx_msg_sent - indicate the transmission of a TX message | |
824 | * | |
825 | * @i2400m: device descriptor | |
826 | * | |
827 | * Called by the bus-specific driver when a message has been sent; | |
828 | * this pops it from the FIFO; and as there is space, start the queue | |
829 | * in case it was stopped. | |
830 | * | |
831 | * Should be called even if the message send failed and we are | |
832 | * dropping this TX message. | |
833 | */ | |
834 | void i2400m_tx_msg_sent(struct i2400m *i2400m) | |
835 | { | |
836 | unsigned n; | |
837 | unsigned long flags; | |
838 | struct device *dev = i2400m_dev(i2400m); | |
839 | ||
840 | d_fnstart(3, dev, "(i2400m %p)\n", i2400m); | |
841 | spin_lock_irqsave(&i2400m->tx_lock, flags); | |
46c50147 IPG |
842 | if (i2400m->tx_buf == NULL) |
843 | goto out_unlock; | |
aa5a7aca IPG |
844 | i2400m->tx_out += i2400m->tx_msg_size; |
845 | d_printf(2, dev, "TX: sent %zu b\n", (size_t) i2400m->tx_msg_size); | |
846 | i2400m->tx_msg_size = 0; | |
847 | BUG_ON(i2400m->tx_out > i2400m->tx_in); | |
848 | /* level them FIFO markers off */ | |
849 | n = i2400m->tx_out / I2400M_TX_BUF_SIZE; | |
850 | i2400m->tx_out %= I2400M_TX_BUF_SIZE; | |
851 | i2400m->tx_in -= n * I2400M_TX_BUF_SIZE; | |
46c50147 | 852 | out_unlock: |
aa5a7aca IPG |
853 | spin_unlock_irqrestore(&i2400m->tx_lock, flags); |
854 | d_fnend(3, dev, "(i2400m %p) = void\n", i2400m); | |
855 | } | |
856 | EXPORT_SYMBOL_GPL(i2400m_tx_msg_sent); | |
857 | ||
858 | ||
859 | /** | |
860 | * i2400m_tx_setup - Initialize the TX queue and infrastructure | |
861 | * | |
862 | * Make sure we reset the TX sequence to zero, as when this function | |
863 | * is called, the firmware has been just restarted. | |
864 | */ | |
865 | int i2400m_tx_setup(struct i2400m *i2400m) | |
866 | { | |
867 | int result; | |
868 | ||
869 | /* Do this here only once -- can't do on | |
870 | * i2400m_hard_start_xmit() as we'll cause race conditions if | |
871 | * the WS was scheduled on another CPU */ | |
872 | INIT_WORK(&i2400m->wake_tx_ws, i2400m_wake_tx_work); | |
873 | ||
874 | i2400m->tx_sequence = 0; | |
875 | i2400m->tx_buf = kmalloc(I2400M_TX_BUF_SIZE, GFP_KERNEL); | |
876 | if (i2400m->tx_buf == NULL) | |
877 | result = -ENOMEM; | |
878 | else | |
879 | result = 0; | |
880 | /* Huh? the bus layer has to define this... */ | |
881 | BUG_ON(i2400m->bus_tx_block_size == 0); | |
882 | return result; | |
883 | ||
884 | } | |
885 | ||
886 | ||
887 | /** | |
888 | * i2400m_tx_release - Tear down the TX queue and infrastructure | |
889 | */ | |
890 | void i2400m_tx_release(struct i2400m *i2400m) | |
891 | { | |
46c50147 IPG |
892 | unsigned long flags; |
893 | spin_lock_irqsave(&i2400m->tx_lock, flags); | |
aa5a7aca | 894 | kfree(i2400m->tx_buf); |
46c50147 IPG |
895 | i2400m->tx_buf = NULL; |
896 | spin_unlock_irqrestore(&i2400m->tx_lock, flags); | |
aa5a7aca | 897 | } |