aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/mpc85xx/patches-3.10/200-fix_gianfar_napi_poll.patch
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@openwrt.org>2013-11-19 13:00:37 +0000
committerFelix Fietkau <nbd@openwrt.org>2013-11-19 13:00:37 +0000
commitf0ffb644dddee00c7e609f4f24584f7d566a94ad (patch)
tree4e4bdce514d1f7c8fcfca2ab990769901575d7e6 /target/linux/mpc85xx/patches-3.10/200-fix_gianfar_napi_poll.patch
parenta91d911f7d6c10dc1baeef1e6d9f422abebb3269 (diff)
downloadmaster-187ad058-f0ffb644dddee00c7e609f4f24584f7d566a94ad.tar.gz
master-187ad058-f0ffb644dddee00c7e609f4f24584f7d566a94ad.tar.bz2
master-187ad058-f0ffb644dddee00c7e609f4f24584f7d566a94ad.zip
mpc85xx: Fix NAPI poll mechanism in GIANFAR ethernet driver
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 <thomas@net.t-labs.tu-berlin.de> Signed-off-by: Felix Fietkau <nbd@openwrt.org> git-svn-id: svn://svn.openwrt.org/openwrt/trunk@38865 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'target/linux/mpc85xx/patches-3.10/200-fix_gianfar_napi_poll.patch')
-rw-r--r--target/linux/mpc85xx/patches-3.10/200-fix_gianfar_napi_poll.patch109
1 files changed, 109 insertions, 0 deletions
diff --git a/target/linux/mpc85xx/patches-3.10/200-fix_gianfar_napi_poll.patch b/target/linux/mpc85xx/patches-3.10/200-fix_gianfar_napi_poll.patch
new file mode 100644
index 0000000000..a1877be921
--- /dev/null
+++ b/target/linux/mpc85xx/patches-3.10/200-fix_gianfar_napi_poll.patch
@@ -0,0 +1,109 @@
+--- a/drivers/net/ethernet/freescale/gianfar.c
++++ b/drivers/net/ethernet/freescale/gianfar.c
+@@ -2835,7 +2835,7 @@ static int gfar_poll(struct napi_struct
+ 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 @@ static int gfar_poll(struct napi_struct
+ 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;