This patch fixes the NAPI poll mechanism in the GIANFAR ethernet driver, which
was not properly working since Linus Kernel Version 3,8.
Therefore the workaround patch to downgrade the GIANFAR ethernet driver to
Kernelversion v3.8 is obsoete.
This patch was extensivly testes with different network loads and types of
traffic. There is quite a substantial user base that reports proper Ethernet
function with TPlink-4900. This patch is based on the fixes from GINAFAR
maintainer Claudiu Manoli.

Signed-off-by: Thomas Huehn <tho...@net.t-labs.tu-berlin.de>
---
 .../patches-3.10/900-fix_gianfar_napi_poll.patch   |  111 ++++++++++++++++++++
 1 file changed, 111 insertions(+)
 create mode 100644 
target/linux/mpc85xx/patches-3.10/900-fix_gianfar_napi_poll.patch

diff --git a/target/linux/mpc85xx/patches-3.10/900-fix_gianfar_napi_poll.patch 
b/target/linux/mpc85xx/patches-3.10/900-fix_gianfar_napi_poll.patch
new file mode 100644
index 0000000..cf570c9
--- /dev/null
+++ b/target/linux/mpc85xx/patches-3.10/900-fix_gianfar_napi_poll.patch
@@ -0,0 +1,111 @@
+Index: linux-3.10.15/drivers/net/ethernet/freescale/gianfar.c
+===================================================================
+--- linux-3.10.15.orig/drivers/net/ethernet/freescale/gianfar.c        
2013-10-05 16:13:21.000000000 +0200
++++ linux-3.10.15/drivers/net/ethernet/freescale/gianfar.c     2013-10-16 
13:44:36.469810517 +0200
+@@ -2835,7 +2835,7 @@
+       struct gfar_priv_rx_q *rx_queue = NULL;
+       int work_done = 0, work_done_per_q = 0;
+       int i, budget_per_q = 0;
+-      int has_tx_work;
++      int has_tx_work = 0;
+       unsigned long rstat_rxf;
+       int num_act_queues;
+ 
+@@ -2850,62 +2850,48 @@
+       if (num_act_queues)
+               budget_per_q = budget/num_act_queues;
+ 
+-      while (1) {
+-              has_tx_work = 0;
+-              for_each_set_bit(i, &gfargrp->tx_bit_map, priv->num_tx_queues) {
+-                      tx_queue = priv->tx_queue[i];
+-                      /* run Tx cleanup to completion */
+-                      if (tx_queue->tx_skbuff[tx_queue->skb_dirtytx]) {
+-                              gfar_clean_tx_ring(tx_queue);
+-                              has_tx_work = 1;
+-                      }
+-              }
+-
+-              for_each_set_bit(i, &gfargrp->rx_bit_map, priv->num_rx_queues) {
+-                      /* skip queue if not active */
+-                      if (!(rstat_rxf & (RSTAT_CLEAR_RXF0 >> i)))
+-                              continue;
+-
+-                      rx_queue = priv->rx_queue[i];
+-                      work_done_per_q =
+-                              gfar_clean_rx_ring(rx_queue, budget_per_q);
+-                      work_done += work_done_per_q;
+-
+-                      /* finished processing this queue */
+-                      if (work_done_per_q < budget_per_q) {
+-                              /* clear active queue hw indication */
+-                              gfar_write(&regs->rstat,
+-                                         RSTAT_CLEAR_RXF0 >> i);
+-                              rstat_rxf &= ~(RSTAT_CLEAR_RXF0 >> i);
+-                              num_act_queues--;
+-
+-                              if (!num_act_queues)
+-                                      break;
+-                              /* recompute budget per Rx queue */
+-                              budget_per_q =
+-                                      (budget - work_done) / num_act_queues;
+-                      }
++      for_each_set_bit(i, &gfargrp->tx_bit_map, priv->num_tx_queues) {
++              tx_queue = priv->tx_queue[i];
++              /* run Tx cleanup to completion */
++              if (tx_queue->tx_skbuff[tx_queue->skb_dirtytx]) {
++                      gfar_clean_tx_ring(tx_queue);
++                      has_tx_work = 1;
+               }
++      }
+ 
+-              if (work_done >= budget)
+-                      break;
++      for_each_set_bit(i, &gfargrp->rx_bit_map, priv->num_rx_queues) {
++              /* skip queue if not active */
++              if (!(rstat_rxf & (RSTAT_CLEAR_RXF0 >> i)))
++                      continue;
++
++              rx_queue = priv->rx_queue[i];
++              work_done_per_q = gfar_clean_rx_ring(rx_queue, budget_per_q);
++              work_done += work_done_per_q;
++
++              /* finished processing this queue */
++              if (work_done_per_q < budget_per_q) {
++                      /* clear active queue hw indication */
++                      gfar_write(&regs->rstat, RSTAT_CLEAR_RXF0 >> i);
++                      num_act_queues--;
+ 
+-              if (!num_act_queues && !has_tx_work) {
++                      if (!num_act_queues)
++                              break;
++              }
++      }
+ 
+-                      napi_complete(napi);
++      if (!num_act_queues && !has_tx_work) {
++              napi_complete(napi);
+ 
+-                      /* Clear the halt bit in RSTAT */
+-                      gfar_write(&regs->rstat, gfargrp->rstat);
++              /* Clear the halt bit in RSTAT */
++              gfar_write(&regs->rstat, gfargrp->rstat);
+ 
+-                      gfar_write(&regs->imask, IMASK_DEFAULT);
++              gfar_write(&regs->imask, IMASK_DEFAULT);
+ 
+-                      /* If we are coalescing interrupts, update the timer
+-                       * Otherwise, clear it
+-                       */
+-                      gfar_configure_coalescing(priv, gfargrp->rx_bit_map,
+-                                                gfargrp->tx_bit_map);
+-                      break;
+-              }
++              /* If we are coalescing interrupts, update the timer
++               * Otherwise, clear it
++               */
++              gfar_configure_coalescing(priv, gfargrp->rx_bit_map,
++                                        gfargrp->tx_bit_map);
+       }
+ 
+       return work_done;
-- 
1.7.9.5
_______________________________________________
openwrt-devel mailing list
openwrt-devel@lists.openwrt.org
https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel

Reply via email to