aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wimax/i2400m/tx.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wimax/i2400m/tx.c')
-rw-r--r--drivers/net/wimax/i2400m/tx.c75
1 files changed, 69 insertions, 6 deletions
diff --git a/drivers/net/wimax/i2400m/tx.c b/drivers/net/wimax/i2400m/tx.c
index 613a88ffd651..fa16ccf8e26a 100644
--- a/drivers/net/wimax/i2400m/tx.c
+++ b/drivers/net/wimax/i2400m/tx.c
@@ -278,6 +278,48 @@ enum {
278#define TAIL_FULL ((void *)~(unsigned long)NULL) 278#define TAIL_FULL ((void *)~(unsigned long)NULL)
279 279
280/* 280/*
281 * Calculate how much tail room is available
282 *
283 * Note the trick here. This path is ONLY caleed for Case A (see
284 * i2400m_tx_fifo_push() below), where we have:
285 *
286 * Case A
287 * N ___________
288 * | tail room |
289 * | |
290 * |<- IN ->|
291 * | |
292 * | data |
293 * | |
294 * |<- OUT ->|
295 * | |
296 * | head room |
297 * 0 -----------
298 *
299 * When calculating the tail_room, tx_in might get to be zero if
300 * i2400m->tx_in is right at the end of the buffer (really full
301 * buffer) if there is no head room. In this case, tail_room would be
302 * I2400M_TX_BUF_SIZE, although it is actually zero. Hence the final
303 * mod (%) operation. However, when doing this kind of optimization,
304 * i2400m->tx_in being zero would fail, so we treat is an a special
305 * case.
306 */
307static inline
308size_t __i2400m_tx_tail_room(struct i2400m *i2400m)
309{
310 size_t tail_room;
311 size_t tx_in;
312
313 if (unlikely(i2400m->tx_in) == 0)
314 return I2400M_TX_BUF_SIZE;
315 tx_in = i2400m->tx_in % I2400M_TX_BUF_SIZE;
316 tail_room = I2400M_TX_BUF_SIZE - tx_in;
317 tail_room %= I2400M_TX_BUF_SIZE;
318 return tail_room;
319}
320
321
322/*
281 * Allocate @size bytes in the TX fifo, return a pointer to it 323 * Allocate @size bytes in the TX fifo, return a pointer to it
282 * 324 *
283 * @i2400m: device descriptor 325 * @i2400m: device descriptor
@@ -338,7 +380,7 @@ void *i2400m_tx_fifo_push(struct i2400m *i2400m, size_t size, size_t padding)
338 return NULL; 380 return NULL;
339 } 381 }
340 /* Is there space at the tail? */ 382 /* Is there space at the tail? */
341 tail_room = I2400M_TX_BUF_SIZE - i2400m->tx_in % I2400M_TX_BUF_SIZE; 383 tail_room = __i2400m_tx_tail_room(i2400m);
342 if (tail_room < needed_size) { 384 if (tail_room < needed_size) {
343 if (i2400m->tx_out % I2400M_TX_BUF_SIZE 385 if (i2400m->tx_out % I2400M_TX_BUF_SIZE
344 < i2400m->tx_in % I2400M_TX_BUF_SIZE) { 386 < i2400m->tx_in % I2400M_TX_BUF_SIZE) {
@@ -367,17 +409,29 @@ void *i2400m_tx_fifo_push(struct i2400m *i2400m, size_t size, size_t padding)
367 * (I2400M_PL_PAD for the payloads, I2400M_TX_PLD_SIZE for the 409 * (I2400M_PL_PAD for the payloads, I2400M_TX_PLD_SIZE for the
368 * header). 410 * header).
369 * 411 *
412 * Tail room can get to be zero if a message was opened when there was
413 * space only for a header. _tx_close() will mark it as to-skip (as it
414 * will have no payloads) and there will be no more space to flush, so
415 * nothing has to be done here. This is probably cheaper than ensuring
416 * in _tx_new() that there is some space for payloads...as we could
417 * always possibly hit the same problem if the payload wouldn't fit.
418 *
370 * Note: 419 * Note:
371 * 420 *
372 * Assumes i2400m->tx_lock is taken, and we use that as a barrier 421 * Assumes i2400m->tx_lock is taken, and we use that as a barrier
422 *
423 * This path is only taken for Case A FIFO situations [see
424 * i2400m_tx_fifo_push()]
373 */ 425 */
374static 426static
375void i2400m_tx_skip_tail(struct i2400m *i2400m) 427void i2400m_tx_skip_tail(struct i2400m *i2400m)
376{ 428{
377 struct device *dev = i2400m_dev(i2400m); 429 struct device *dev = i2400m_dev(i2400m);
378 size_t tx_in = i2400m->tx_in % I2400M_TX_BUF_SIZE; 430 size_t tx_in = i2400m->tx_in % I2400M_TX_BUF_SIZE;
379 size_t tail_room = I2400M_TX_BUF_SIZE - tx_in; 431 size_t tail_room = __i2400m_tx_tail_room(i2400m);
380 struct i2400m_msg_hdr *msg = i2400m->tx_buf + tx_in; 432 struct i2400m_msg_hdr *msg = i2400m->tx_buf + tx_in;
433 if (unlikely(tail_room == 0))
434 return;
381 BUG_ON(tail_room < sizeof(*msg)); 435 BUG_ON(tail_room < sizeof(*msg));
382 msg->size = tail_room | I2400M_TX_SKIP; 436 msg->size = tail_room | I2400M_TX_SKIP;
383 d_printf(2, dev, "skip tail: skipping %zu bytes @%zu\n", 437 d_printf(2, dev, "skip tail: skipping %zu bytes @%zu\n",
@@ -474,10 +528,18 @@ void i2400m_tx_close(struct i2400m *i2400m)
474 struct i2400m_msg_hdr *tx_msg_moved; 528 struct i2400m_msg_hdr *tx_msg_moved;
475 size_t aligned_size, padding, hdr_size; 529 size_t aligned_size, padding, hdr_size;
476 void *pad_buf; 530 void *pad_buf;
531 unsigned num_pls;
477 532
478 if (tx_msg->size & I2400M_TX_SKIP) /* a skipper? nothing to do */ 533 if (tx_msg->size & I2400M_TX_SKIP) /* a skipper? nothing to do */
479 goto out; 534 goto out;
480 535 num_pls = le16_to_cpu(tx_msg->num_pls);
536 /* We can get this situation when a new message was started
537 * and there was no space to add payloads before hitting the
538 tail (and taking padding into consideration). */
539 if (num_pls == 0) {
540 tx_msg->size |= I2400M_TX_SKIP;
541 goto out;
542 }
481 /* Relocate the message header 543 /* Relocate the message header
482 * 544 *
483 * Find the current header size, align it to 16 and if we need 545 * Find the current header size, align it to 16 and if we need
@@ -491,7 +553,7 @@ void i2400m_tx_close(struct i2400m *i2400m)
491 */ 553 */
492 hdr_size = sizeof(*tx_msg) 554 hdr_size = sizeof(*tx_msg)
493 + le16_to_cpu(tx_msg->num_pls) * sizeof(tx_msg->pld[0]); 555 + le16_to_cpu(tx_msg->num_pls) * sizeof(tx_msg->pld[0]);
494 hdr_size = ALIGN(hdr_size, I2400M_PL_PAD); 556 hdr_size = ALIGN(hdr_size, I2400M_PL_ALIGN);
495 tx_msg->offset = I2400M_TX_PLD_SIZE - hdr_size; 557 tx_msg->offset = I2400M_TX_PLD_SIZE - hdr_size;
496 tx_msg_moved = (void *) tx_msg + tx_msg->offset; 558 tx_msg_moved = (void *) tx_msg + tx_msg->offset;
497 memmove(tx_msg_moved, tx_msg, hdr_size); 559 memmove(tx_msg_moved, tx_msg, hdr_size);
@@ -574,7 +636,7 @@ int i2400m_tx(struct i2400m *i2400m, const void *buf, size_t buf_len,
574 636
575 d_fnstart(3, dev, "(i2400m %p skb %p [%zu bytes] pt %u)\n", 637 d_fnstart(3, dev, "(i2400m %p skb %p [%zu bytes] pt %u)\n",
576 i2400m, buf, buf_len, pl_type); 638 i2400m, buf, buf_len, pl_type);
577 padded_len = ALIGN(buf_len, I2400M_PL_PAD); 639 padded_len = ALIGN(buf_len, I2400M_PL_ALIGN);
578 d_printf(5, dev, "padded_len %zd buf_len %zd\n", padded_len, buf_len); 640 d_printf(5, dev, "padded_len %zd buf_len %zd\n", padded_len, buf_len);
579 /* If there is no current TX message, create one; if the 641 /* If there is no current TX message, create one; if the
580 * current one is out of payload slots or we have a singleton, 642 * current one is out of payload slots or we have a singleton,
@@ -591,6 +653,8 @@ try_new:
591 i2400m_tx_close(i2400m); 653 i2400m_tx_close(i2400m);
592 i2400m_tx_new(i2400m); 654 i2400m_tx_new(i2400m);
593 } 655 }
656 if (i2400m->tx_msg == NULL)
657 goto error_tx_new;
594 if (i2400m->tx_msg->size + padded_len > I2400M_TX_BUF_SIZE / 2) { 658 if (i2400m->tx_msg->size + padded_len > I2400M_TX_BUF_SIZE / 2) {
595 d_printf(2, dev, "TX: message too big, going new\n"); 659 d_printf(2, dev, "TX: message too big, going new\n");
596 i2400m_tx_close(i2400m); 660 i2400m_tx_close(i2400m);
@@ -773,7 +837,6 @@ void i2400m_tx_msg_sent(struct i2400m *i2400m)
773 n = i2400m->tx_out / I2400M_TX_BUF_SIZE; 837 n = i2400m->tx_out / I2400M_TX_BUF_SIZE;
774 i2400m->tx_out %= I2400M_TX_BUF_SIZE; 838 i2400m->tx_out %= I2400M_TX_BUF_SIZE;
775 i2400m->tx_in -= n * I2400M_TX_BUF_SIZE; 839 i2400m->tx_in -= n * I2400M_TX_BUF_SIZE;
776 netif_start_queue(i2400m->wimax_dev.net_dev);
777 spin_unlock_irqrestore(&i2400m->tx_lock, flags); 840 spin_unlock_irqrestore(&i2400m->tx_lock, flags);
778 d_fnend(3, dev, "(i2400m %p) = void\n", i2400m); 841 d_fnend(3, dev, "(i2400m %p) = void\n", i2400m);
779} 842}