From 4818d14de36228a749f714b450a85c1b35542e6f Mon Sep 17 00:00:00 2001 From: "Prasanna S.Panchamukhi" Date: Mon, 18 Jan 2010 14:28:23 -0800 Subject: wimax/i2400m: fix incorrect return -ESHUTDOWN when there is no Tx buffer available i2400m_tx() routine was returning -ESHUTDOWN even when there was no Tx buffer available. This patch fixes the i2400m_tx() to return -ESHUTDOWN only when the device is down(i2400m->tx_buf is NULL) and also to return -ENOSPC when there is no Tx buffer. Error seen in the kernel log. kernel: i2400m_sdio mmc0:0001:1: can't send message 0x5606: -108 kernel: i2400m_sdio mmc0:0001:1: Failed to issue 'Enter power save'command: -108 Signed-off-by: Prasanna S.Panchamukhi --- drivers/net/wimax/i2400m/tx.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/net/wimax/i2400m/tx.c') diff --git a/drivers/net/wimax/i2400m/tx.c b/drivers/net/wimax/i2400m/tx.c index 6db909ecf1c9..fab27e4a4cb3 100644 --- a/drivers/net/wimax/i2400m/tx.c +++ b/drivers/net/wimax/i2400m/tx.c @@ -643,9 +643,11 @@ int i2400m_tx(struct i2400m *i2400m, const void *buf, size_t buf_len, * current one is out of payload slots or we have a singleton, * close it and start a new one */ spin_lock_irqsave(&i2400m->tx_lock, flags); - result = -ESHUTDOWN; - if (i2400m->tx_buf == NULL) + /* If tx_buf is NULL, device is shutdown */ + if (i2400m->tx_buf == NULL) { + result = -ESHUTDOWN; goto error_tx_new; + } try_new: if (unlikely(i2400m->tx_msg == NULL)) i2400m_tx_new(i2400m); -- cgit v1.2.3 From 570eb0ea65db625e0b11ca97f4ae857bc1193250 Mon Sep 17 00:00:00 2001 From: "Prasanna S. Panchamukhi" Date: Tue, 26 Jan 2010 19:44:45 -0700 Subject: wimax/i2400m: fix insufficient size of Tx buffer for 12 payload of 1400 MTU. This patch increases the Tx buffer size so as to accommodate 12 payloads of 1408 (1400 MTU 16 bytes aligned). Currently Tx buffer is 32 KiB which is insufficient to accommodate 12 payloads of 1408 size. This patch - increases I2400M_TX_BUF_SIZE from 32KiB to 64KiB - Adds a BUILD_BUG_ON if the calculated buffer size based on the given MTU exceeds the I2400M_TX_BUF_SIZE. Below is how we calculate the size of the Tx buffer. Payload + 4 bytes prefix for each payload (1400 MTU 16 bytes boundary aligned) = (1408 + sizeof(struct i2400m_pl_data_hdr)) * I2400M_TX_PLD_MAX Adding 16 byte message header = + sizeof(struct i2400m_msg_hdr) Aligning to 256 byte boundary Total Tx buffer = (((((1408 + sizeof(struct i2400m_pl_data_hdr)) * I2400M_TX_PLD_MAX )+ sizeof(struct i2400m_msg_hdr)) / 256) + 1) * 256 * 2 Signed-off-by: Prasanna S. Panchamukhi Signed-off-by: Inaky Perez-Gonzalez --- drivers/net/wimax/i2400m/tx.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'drivers/net/wimax/i2400m/tx.c') diff --git a/drivers/net/wimax/i2400m/tx.c b/drivers/net/wimax/i2400m/tx.c index fab27e4a4cb3..8561c0766535 100644 --- a/drivers/net/wimax/i2400m/tx.c +++ b/drivers/net/wimax/i2400m/tx.c @@ -258,8 +258,10 @@ enum { * Doc says maximum transaction is 16KiB. If we had 16KiB en * route and 16KiB being queued, it boils down to needing * 32KiB. + * 32KiB is insufficient for 1400 MTU, hence increasing + * tx buffer size to 64KiB. */ - I2400M_TX_BUF_SIZE = 32768, + I2400M_TX_BUF_SIZE = 65536, /** * Message header and payload descriptors have to be 16 * aligned (16 + 4 * N = 16 * M). If we take that average sent @@ -274,6 +276,19 @@ enum { I2400M_TX_PLD_SIZE = sizeof(struct i2400m_msg_hdr) + I2400M_TX_PLD_MAX * sizeof(struct i2400m_pld), I2400M_TX_SKIP = 0x80000000, + /* + * 16 byte aligned MAX_MTU + 4 byte payload prefix. + */ + I2400M_MAX_MTU_ALIGN = 16, + I2400M_TX_PDU_SIZE = I2400M_MAX_MTU % I2400M_MAX_MTU_ALIGN + + I2400M_MAX_MTU + sizeof(struct i2400m_pl_data_hdr), + /* + * 256 byte aligned toal size of 12 PDUs including msg header, + */ + I2400M_TX_PDU_ALIGN = 256, + I2400M_TX_PDU_TOTAL_SIZE = ((I2400M_TX_PDU_SIZE * I2400M_TX_PLD_MAX + + sizeof(struct i2400m_msg_hdr))/I2400M_TX_PDU_ALIGN + 1) + * I2400M_TX_PDU_ALIGN * 2, }; #define TAIL_FULL ((void *)~(unsigned long)NULL) @@ -874,6 +889,8 @@ int i2400m_tx_setup(struct i2400m *i2400m) INIT_WORK(&i2400m->wake_tx_ws, i2400m_wake_tx_work); i2400m->tx_sequence = 0; + /* Warn if the calculated buffer size exceeds I2400M_TX_BUF_SIZE. */ + BUILD_BUG_ON(I2400M_TX_PDU_TOTAL_SIZE > I2400M_TX_BUF_SIZE); i2400m->tx_buf = kmalloc(I2400M_TX_BUF_SIZE, GFP_KERNEL); if (i2400m->tx_buf == NULL) result = -ENOMEM; -- cgit v1.2.3 From d94401742dc662747db5bb9e444d353a4feba018 Mon Sep 17 00:00:00 2001 From: Cindy H Kao Date: Fri, 23 Apr 2010 17:19:06 -0700 Subject: wimax/i2400m: Reset the TX FIFO indices when allocating the TX FIFO in tx_setup() This patch makes sure whenever tx_setup() is invoked during driver initialization or device reset where TX FIFO is released and re-allocated, the indices tx_in, tx_out, tx_msg_size, tx_sequence, tx_msg are properly initialized. When a device reset happens and the TX FIFO is released/re-allocated, a new block of memory may be allocated for the TX FIFO, therefore tx_msg should be cleared so that no any TX threads (tx_worker, tx) would access to the out-of-date addresses. Also, the TX threads use tx_in and tx_out to decide where to put the new host-to-device messages and from where to copy them to the device HW FIFO, these indices have to be cleared so after the TX FIFO is re-allocated during the reset, the indices both refer to the head of the FIFO, ie. a new start. The same rational applies to tx_msg_size and tx_sequence. To protect the indices from being accessed by multiple threads simultaneously, the lock tx_lock has to be obtained before the initializations and released afterwards. Signed-off-by: Cindy H Kao --- drivers/net/wimax/i2400m/tx.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) (limited to 'drivers/net/wimax/i2400m/tx.c') diff --git a/drivers/net/wimax/i2400m/tx.c b/drivers/net/wimax/i2400m/tx.c index 8561c0766535..21909e5d2010 100644 --- a/drivers/net/wimax/i2400m/tx.c +++ b/drivers/net/wimax/i2400m/tx.c @@ -877,27 +877,40 @@ EXPORT_SYMBOL_GPL(i2400m_tx_msg_sent); * i2400m_tx_setup - Initialize the TX queue and infrastructure * * Make sure we reset the TX sequence to zero, as when this function - * is called, the firmware has been just restarted. + * is called, the firmware has been just restarted. Same rational + * for tx_in, tx_out, tx_msg_size and tx_msg. We reset them since + * the memory for TX queue is reallocated. */ int i2400m_tx_setup(struct i2400m *i2400m) { - int result; + int result = 0; + void *tx_buf; + unsigned long flags; /* Do this here only once -- can't do on * i2400m_hard_start_xmit() as we'll cause race conditions if * the WS was scheduled on another CPU */ INIT_WORK(&i2400m->wake_tx_ws, i2400m_wake_tx_work); - i2400m->tx_sequence = 0; + tx_buf = kmalloc(I2400M_TX_BUF_SIZE, GFP_ATOMIC); + if (tx_buf == NULL) { + result = -ENOMEM; + goto error_kmalloc; + } + /* Warn if the calculated buffer size exceeds I2400M_TX_BUF_SIZE. */ BUILD_BUG_ON(I2400M_TX_PDU_TOTAL_SIZE > I2400M_TX_BUF_SIZE); - i2400m->tx_buf = kmalloc(I2400M_TX_BUF_SIZE, GFP_KERNEL); - if (i2400m->tx_buf == NULL) - result = -ENOMEM; - else - result = 0; + spin_lock_irqsave(&i2400m->tx_lock, flags); + i2400m->tx_sequence = 0; + i2400m->tx_in = 0; + i2400m->tx_out = 0; + i2400m->tx_msg_size = 0; + i2400m->tx_msg = NULL; + i2400m->tx_buf = tx_buf; + spin_unlock_irqrestore(&i2400m->tx_lock, flags); /* Huh? the bus layer has to define this... */ BUG_ON(i2400m->bus_tx_block_size == 0); +error_kmalloc: return result; } -- cgit v1.2.3 From e6dd789af1823908ed3ccda26bf07faf5970bce1 Mon Sep 17 00:00:00 2001 From: "Prasanna S. Panchamukhi" Date: Thu, 8 Apr 2010 16:24:27 -0700 Subject: wimax/i2400m: increase the maximum number of payloads per message to 60 [v1] According to Intel Wimax i3200, i5x50 and i6x50 device specification documents, the maximum number of payloads per message can be up to 60. Increasing the number of payloads to 60 per message helps to accommodate smaller payloads in a single transaction. This patch increases the maximum number of payloads from 12 to 60 per message. Signed-off-by: Prasanna S. Panchamukhi --- drivers/net/wimax/i2400m/tx.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/net/wimax/i2400m/tx.c') diff --git a/drivers/net/wimax/i2400m/tx.c b/drivers/net/wimax/i2400m/tx.c index 21909e5d2010..b10c3b77c27e 100644 --- a/drivers/net/wimax/i2400m/tx.c +++ b/drivers/net/wimax/i2400m/tx.c @@ -272,7 +272,13 @@ enum { * at the end there are less, we pad up to the nearest * multiple of 16. */ - I2400M_TX_PLD_MAX = 12, + /* + * According to Intel Wimax i3200, i5x50 and i6x50 specification + * documents, the maximum number of payloads per message can be + * up to 60. Increasing the number of payloads to 60 per message + * helps to accommodate smaller payloads in a single transaction. + */ + I2400M_TX_PLD_MAX = 60, I2400M_TX_PLD_SIZE = sizeof(struct i2400m_msg_hdr) + I2400M_TX_PLD_MAX * sizeof(struct i2400m_pld), I2400M_TX_SKIP = 0x80000000, -- cgit v1.2.3 From a40242f2cde38ccb04d4c35cad66aab3c047fa6a Mon Sep 17 00:00:00 2001 From: "Prasanna S. Panchamukhi" Date: Thu, 8 Apr 2010 16:24:28 -0700 Subject: wimax/i2400m: limit the message size upto 16KiB [v1] According to Intel Wimax i3200, i5x50 and i6x50 specification documents, the maximum size of each TX message can be upto 16KiB. This patch modifies the i2400m_tx() routine to check that the message size does not exceed the 16KiB limit. Please refer the documentation in the code for details. Signed-off-by: Prasanna S. Panchamukhi --- drivers/net/wimax/i2400m/tx.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'drivers/net/wimax/i2400m/tx.c') diff --git a/drivers/net/wimax/i2400m/tx.c b/drivers/net/wimax/i2400m/tx.c index b10c3b77c27e..a5002c8467c2 100644 --- a/drivers/net/wimax/i2400m/tx.c +++ b/drivers/net/wimax/i2400m/tx.c @@ -282,6 +282,11 @@ enum { I2400M_TX_PLD_SIZE = sizeof(struct i2400m_msg_hdr) + I2400M_TX_PLD_MAX * sizeof(struct i2400m_pld), I2400M_TX_SKIP = 0x80000000, + /* + * According to Intel Wimax i3200, i5x50 and i6x50 specification + * documents, the maximum size of each message can be up to 16KiB. + */ + I2400M_TX_MSG_SIZE = 16384, /* * 16 byte aligned MAX_MTU + 4 byte payload prefix. */ @@ -682,7 +687,13 @@ try_new: } if (i2400m->tx_msg == NULL) goto error_tx_new; - if (i2400m->tx_msg->size + padded_len > I2400M_TX_BUF_SIZE / 2) { + /* + * Check if this skb will fit in the TX queue's current active + * TX message. The total message size must not exceed the maximum + * size of each message I2400M_TX_MSG_SIZE. If it exceeds, + * close the current message and push this skb into the new message. + */ + if (i2400m->tx_msg->size + padded_len > I2400M_TX_MSG_SIZE) { d_printf(2, dev, "TX: message too big, going new\n"); i2400m_tx_close(i2400m); i2400m_tx_new(i2400m); -- cgit v1.2.3 From 718e94907d79e74bbc7cfdb3cda2266079c5e993 Mon Sep 17 00:00:00 2001 From: "Prasanna S. Panchamukhi" Date: Thu, 8 Apr 2010 16:24:29 -0700 Subject: wimax/i2400m: fix BUILD_BUG_ON() to use the maximum message size constant [v1] The older method of computing the maximum PDU size relied on a method that doesn't work when we prop the maximum number of payloads up to the physical limit, and thus we kill the whole computation and just verify that the constants are congruent. Signed-off-by: Prasanna S. Panchamukhi --- drivers/net/wimax/i2400m/tx.c | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) (limited to 'drivers/net/wimax/i2400m/tx.c') diff --git a/drivers/net/wimax/i2400m/tx.c b/drivers/net/wimax/i2400m/tx.c index a5002c8467c2..1725f2b022a2 100644 --- a/drivers/net/wimax/i2400m/tx.c +++ b/drivers/net/wimax/i2400m/tx.c @@ -287,19 +287,6 @@ enum { * documents, the maximum size of each message can be up to 16KiB. */ I2400M_TX_MSG_SIZE = 16384, - /* - * 16 byte aligned MAX_MTU + 4 byte payload prefix. - */ - I2400M_MAX_MTU_ALIGN = 16, - I2400M_TX_PDU_SIZE = I2400M_MAX_MTU % I2400M_MAX_MTU_ALIGN - + I2400M_MAX_MTU + sizeof(struct i2400m_pl_data_hdr), - /* - * 256 byte aligned toal size of 12 PDUs including msg header, - */ - I2400M_TX_PDU_ALIGN = 256, - I2400M_TX_PDU_TOTAL_SIZE = ((I2400M_TX_PDU_SIZE * I2400M_TX_PLD_MAX - + sizeof(struct i2400m_msg_hdr))/I2400M_TX_PDU_ALIGN + 1) - * I2400M_TX_PDU_ALIGN * 2, }; #define TAIL_FULL ((void *)~(unsigned long)NULL) @@ -915,8 +902,11 @@ int i2400m_tx_setup(struct i2400m *i2400m) goto error_kmalloc; } - /* Warn if the calculated buffer size exceeds I2400M_TX_BUF_SIZE. */ - BUILD_BUG_ON(I2400M_TX_PDU_TOTAL_SIZE > I2400M_TX_BUF_SIZE); + /* + * Fail the build if we can't fit at least two maximum size messages + * on the TX FIFO [one being delivered while one is constructed]. + */ + BUILD_BUG_ON(2 * I2400M_TX_MSG_SIZE > I2400M_TX_BUF_SIZE); spin_lock_irqsave(&i2400m->tx_lock, flags); i2400m->tx_sequence = 0; i2400m->tx_in = 0; -- cgit v1.2.3 From 9e6e3bd52b0f77ca5cc385892c14ff8ba5ecfa67 Mon Sep 17 00:00:00 2001 From: "Prasanna S. Panchamukhi" Date: Thu, 8 Apr 2010 16:24:30 -0700 Subject: wimax/i2400m: modify i2400m_tx_fifo_push() to check for head room space in the TX FIFO [v1] This fixes i2400m_tx_fifo_push(); the check for having enough space in the TX FIFO's tail was obscure and broken in certain corner cases. The new check works in all cases and is way clearer. Please refer the documentation in the code for details. Signed-off-by: Prasanna S. Panchamukhi --- drivers/net/wimax/i2400m/tx.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'drivers/net/wimax/i2400m/tx.c') diff --git a/drivers/net/wimax/i2400m/tx.c b/drivers/net/wimax/i2400m/tx.c index 1725f2b022a2..101550a2f5a2 100644 --- a/drivers/net/wimax/i2400m/tx.c +++ b/drivers/net/wimax/i2400m/tx.c @@ -396,8 +396,20 @@ void *i2400m_tx_fifo_push(struct i2400m *i2400m, size_t size, size_t padding) /* Is there space at the tail? */ tail_room = __i2400m_tx_tail_room(i2400m); if (tail_room < needed_size) { - if (i2400m->tx_out % I2400M_TX_BUF_SIZE - < i2400m->tx_in % I2400M_TX_BUF_SIZE) { + /* + * If the tail room space is not enough to push the message + * in the TX FIFO, then there are two possibilities: + * 1. There is enough head room space to accommodate + * this message in the TX FIFO. + * 2. There is not enough space in the head room and + * in tail room of the TX FIFO to accommodate the message. + * In the case (1), return TAIL_FULL so that the caller + * can figure out, if the caller wants to push the message + * into the head room space. + * In the case (2), return NULL, indicating that the TX FIFO + * cannot accommodate the message. + */ + if (room - tail_room >= needed_size) { d_printf(2, dev, "fifo push %zu/%zu: tail full\n", size, padding); return TAIL_FULL; /* There might be head space */ -- cgit v1.2.3 From 85a19e07e30f67c517266cafe92b7bcd9b98966d Mon Sep 17 00:00:00 2001 From: "Prasanna S. Panchamukhi" Date: Thu, 8 Apr 2010 16:24:31 -0700 Subject: wimax/i2400m: fix system freeze caused by an infinite loop [v1] This patch fixes an infinite loop caused by i2400m_tx_fifo_push() due to a corner case where there is no tail space in the TX FIFO. Please refer the documentation in the code for details. Signed-off-by: Prasanna S. Panchamukhi --- drivers/net/wimax/i2400m/tx.c | 65 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 60 insertions(+), 5 deletions(-) (limited to 'drivers/net/wimax/i2400m/tx.c') diff --git a/drivers/net/wimax/i2400m/tx.c b/drivers/net/wimax/i2400m/tx.c index 101550a2f5a2..609f1ca6e9fc 100644 --- a/drivers/net/wimax/i2400m/tx.c +++ b/drivers/net/wimax/i2400m/tx.c @@ -341,6 +341,14 @@ size_t __i2400m_tx_tail_room(struct i2400m *i2400m) * @padding: ensure that there is at least this many bytes of free * contiguous space in the fifo. This is needed because later on * we might need to add padding. + * @try_head: specify either to allocate head room or tail room space + * in the TX FIFO. This boolean is required to avoids a system hang + * due to an infinite loop caused by i2400m_tx_fifo_push(). + * The caller must always try to allocate tail room space first by + * calling this routine with try_head = 0. In case if there + * is not enough tail room space but there is enough head room space, + * (i2400m_tx_fifo_push() returns TAIL_FULL) try to allocate head + * room space, by calling this routine again with try_head = 1. * * Returns: * @@ -372,6 +380,48 @@ size_t __i2400m_tx_tail_room(struct i2400m *i2400m) * fail and return TAIL_FULL and let the caller figure out if we wants to * skip the tail room and try to allocate from the head. * + * There is a corner case, wherein i2400m_tx_new() can get into + * an infinite loop calling i2400m_tx_fifo_push(). + * In certain situations, tx_in would have reached on the top of TX FIFO + * and i2400m_tx_tail_room() returns 0, as described below: + * + * N ___________ tail room is zero + * |<- IN ->| + * | | + * | | + * | | + * | data | + * |<- OUT ->| + * | | + * | | + * | head room | + * 0 ----------- + * During such a time, where tail room is zero in the TX FIFO and if there + * is a request to add a payload to TX FIFO, which calls: + * i2400m_tx() + * ->calls i2400m_tx_close() + * ->calls i2400m_tx_skip_tail() + * goto try_new; + * ->calls i2400m_tx_new() + * |----> [try_head:] + * infinite loop | ->calls i2400m_tx_fifo_push() + * | if (tail_room < needed) + * | if (head_room => needed) + * | return TAIL_FULL; + * |<---- goto try_head; + * + * i2400m_tx() calls i2400m_tx_close() to close the message, since there + * is no tail room to accommodate the payload and calls + * i2400m_tx_skip_tail() to skip the tail space. Now i2400m_tx() calls + * i2400m_tx_new() to allocate space for new message header calling + * i2400m_tx_fifo_push() that returns TAIL_FULL, since there is no tail space + * to accommodate the message header, but there is enough head space. + * The i2400m_tx_new() keeps re-retrying by calling i2400m_tx_fifo_push() + * ending up in a loop causing system freeze. + * + * This corner case is avoided by using a try_head boolean, + * as an argument to i2400m_tx_fifo_push(). + * * Note: * * Assumes i2400m->tx_lock is taken, and we use that as a barrier @@ -380,7 +430,8 @@ size_t __i2400m_tx_tail_room(struct i2400m *i2400m) * pop data off the queue */ static -void *i2400m_tx_fifo_push(struct i2400m *i2400m, size_t size, size_t padding) +void *i2400m_tx_fifo_push(struct i2400m *i2400m, size_t size, + size_t padding, bool try_head) { struct device *dev = i2400m_dev(i2400m); size_t room, tail_room, needed_size; @@ -395,7 +446,7 @@ void *i2400m_tx_fifo_push(struct i2400m *i2400m, size_t size, size_t padding) } /* Is there space at the tail? */ tail_room = __i2400m_tx_tail_room(i2400m); - if (tail_room < needed_size) { + if (!try_head && tail_room < needed_size) { /* * If the tail room space is not enough to push the message * in the TX FIFO, then there are two possibilities: @@ -510,14 +561,16 @@ void i2400m_tx_new(struct i2400m *i2400m) { struct device *dev = i2400m_dev(i2400m); struct i2400m_msg_hdr *tx_msg; + bool try_head = 0; BUG_ON(i2400m->tx_msg != NULL); try_head: - tx_msg = i2400m_tx_fifo_push(i2400m, I2400M_TX_PLD_SIZE, 0); + tx_msg = i2400m_tx_fifo_push(i2400m, I2400M_TX_PLD_SIZE, 0, try_head); if (tx_msg == NULL) goto out; else if (tx_msg == TAIL_FULL) { i2400m_tx_skip_tail(i2400m); d_printf(2, dev, "new TX message: tail full, trying head\n"); + try_head = 1; goto try_head; } memset(tx_msg, 0, I2400M_TX_PLD_SIZE); @@ -591,7 +644,7 @@ void i2400m_tx_close(struct i2400m *i2400m) aligned_size = ALIGN(tx_msg_moved->size, i2400m->bus_tx_block_size); padding = aligned_size - tx_msg_moved->size; if (padding > 0) { - pad_buf = i2400m_tx_fifo_push(i2400m, padding, 0); + pad_buf = i2400m_tx_fifo_push(i2400m, padding, 0, 0); if (unlikely(WARN_ON(pad_buf == NULL || pad_buf == TAIL_FULL))) { /* This should not happen -- append should verify @@ -657,6 +710,7 @@ int i2400m_tx(struct i2400m *i2400m, const void *buf, size_t buf_len, unsigned long flags; size_t padded_len; void *ptr; + bool try_head = 0; unsigned is_singleton = pl_type == I2400M_PT_RESET_WARM || pl_type == I2400M_PT_RESET_COLD; @@ -702,11 +756,12 @@ try_new: /* So we have a current message header; now append space for * the message -- if there is not enough, try the head */ ptr = i2400m_tx_fifo_push(i2400m, padded_len, - i2400m->bus_tx_block_size); + i2400m->bus_tx_block_size, try_head); if (ptr == TAIL_FULL) { /* Tail is full, try head */ d_printf(2, dev, "pl append: tail full\n"); i2400m_tx_close(i2400m); i2400m_tx_skip_tail(i2400m); + try_head = 1; goto try_new; } else if (ptr == NULL) { /* All full */ result = -ENOSPC; -- cgit v1.2.3 From 27502908866ba37d03594e7f7ee7b649cb007330 Mon Sep 17 00:00:00 2001 From: "Prasanna S. Panchamukhi" Date: Tue, 13 Apr 2010 16:36:19 -0700 Subject: wimax/i2400m: reserve additional space in the TX queue's buffer while allocating space for a new message header Increase the possibilities of including at least one payload by reserving some additional space in the TX queue while allocating TX queue's space for new message header. Please refer the documentation in the code for details. Signed-off-by: Prasanna S. Panchamukhi --- drivers/net/wimax/i2400m/i2400m.h | 6 ++++++ drivers/net/wimax/i2400m/tx.c | 11 ++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) (limited to 'drivers/net/wimax/i2400m/tx.c') diff --git a/drivers/net/wimax/i2400m/i2400m.h b/drivers/net/wimax/i2400m/i2400m.h index b8c7dbfead49..1babc55b1312 100644 --- a/drivers/net/wimax/i2400m/i2400m.h +++ b/drivers/net/wimax/i2400m/i2400m.h @@ -242,6 +242,11 @@ struct i2400m_barker_db; * so we have a tx_blk_size variable that the bus layer sets to * tell the engine how much of that we need. * + * @bus_tx_room_min: [fill] Minimum room required while allocating + * TX queue's buffer space for message header. SDIO requires + * 224 bytes and USB 16 bytes. Refer bus specific driver code + * for details. + * * @bus_pl_size_max: [fill] Maximum payload size. * * @bus_setup: [optional fill] Function called by the bus-generic code @@ -573,6 +578,7 @@ struct i2400m { wait_queue_head_t state_wq; /* Woken up when on state updates */ size_t bus_tx_block_size; + size_t bus_tx_room_min; size_t bus_pl_size_max; unsigned bus_bm_retries; diff --git a/drivers/net/wimax/i2400m/tx.c b/drivers/net/wimax/i2400m/tx.c index 609f1ca6e9fc..3f819efc06b5 100644 --- a/drivers/net/wimax/i2400m/tx.c +++ b/drivers/net/wimax/i2400m/tx.c @@ -563,8 +563,17 @@ void i2400m_tx_new(struct i2400m *i2400m) struct i2400m_msg_hdr *tx_msg; bool try_head = 0; BUG_ON(i2400m->tx_msg != NULL); + /* + * In certain situations, TX queue might have enough space to + * accommodate the new message header I2400M_TX_PLD_SIZE, but + * might not have enough space to accommodate the payloads. + * Adding bus_tx_room_min padding while allocating a new TX message + * increases the possibilities of including at least one payload of the + * size <= bus_tx_room_min. + */ try_head: - tx_msg = i2400m_tx_fifo_push(i2400m, I2400M_TX_PLD_SIZE, 0, try_head); + tx_msg = i2400m_tx_fifo_push(i2400m, I2400M_TX_PLD_SIZE, + i2400m->bus_tx_room_min, try_head); if (tx_msg == NULL) goto out; else if (tx_msg == TAIL_FULL) { -- cgit v1.2.3