This patch would be a great addition, and works wonderfully :) I have it running for some time now from when I found it in the thread https://forum.openwrt.org/viewtopic.php?id=42062&p=15 Tested-by: Martijn Zilverschoon <thefriedzom...@gmail.com>
2013/11/19 Thomas Huehn <tho...@net.t-labs.tu-berlin.de>: > 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. > --- > v2: add the deletion of the former workaround > 200-gianfar_napi_poll_revert.patch > > Signed-off-by: Thomas Huehn <tho...@net.t-labs.tu-berlin.de> > --- > .../200-gianfar_napi_poll_revert.patch | 162 > -------------------- > .../patches-3.10/201-fix_gianfar_napi_poll.patch | 111 ++++++++++++++ > 2 files changed, 111 insertions(+), 162 deletions(-) > delete mode 100644 > target/linux/mpc85xx/patches-3.10/200-gianfar_napi_poll_revert.patch > create mode 100644 > target/linux/mpc85xx/patches-3.10/201-fix_gianfar_napi_poll.patch > > diff --git > a/target/linux/mpc85xx/patches-3.10/200-gianfar_napi_poll_revert.patch > b/target/linux/mpc85xx/patches-3.10/200-gianfar_napi_poll_revert.patch > deleted file mode 100644 > index 7b0e6c9..0000000 > --- a/target/linux/mpc85xx/patches-3.10/200-gianfar_napi_poll_revert.patch > +++ /dev/null > @@ -1,162 +0,0 @@ > ---- a/drivers/net/ethernet/freescale/gianfar.c > -+++ b/drivers/net/ethernet/freescale/gianfar.c > -@@ -132,7 +132,7 @@ static int gfar_poll(struct napi_struct > - static void gfar_netpoll(struct net_device *dev); > - #endif > - int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit); > --static void gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue); > -+static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue); > - static void gfar_process_frame(struct net_device *dev, struct sk_buff *skb, > - int amount_pull, struct napi_struct *napi); > - void gfar_halt(struct net_device *dev); > -@@ -2475,7 +2475,7 @@ static void gfar_align_skb(struct sk_buf > - } > - > - /* Interrupt Handler for Transmit complete */ > --static void gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue) > -+static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue) > - { > - struct net_device *dev = tx_queue->dev; > - struct netdev_queue *txq; > -@@ -2575,6 +2575,8 @@ static void gfar_clean_tx_ring(struct gf > - tx_queue->dirty_tx = bdp; > - > - netdev_tx_completed_queue(txq, howmany, bytes_sent); > -+ > -+ return howmany; > - } > - > - static void gfar_schedule_cleanup(struct gfar_priv_grp *gfargrp) > -@@ -2833,82 +2835,62 @@ static int gfar_poll(struct napi_struct > - struct gfar __iomem *regs = gfargrp->regs; > - struct gfar_priv_tx_q *tx_queue = NULL; > - 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; > -- unsigned long rstat_rxf; > -- int num_act_queues; > -+ int rx_cleaned = 0, budget_per_queue = 0, rx_cleaned_per_queue = 0; > -+ int tx_cleaned = 0, i, left_over_budget = budget; > -+ unsigned long serviced_queues = 0; > -+ int num_queues = 0; > -+ > -+ num_queues = gfargrp->num_rx_queues; > -+ budget_per_queue = budget/num_queues; > - > - /* Clear IEVENT, so interrupts aren't called again > - * because of the packets that have already arrived > - */ > - gfar_write(®s->ievent, IEVENT_RTX_MASK); > - > -- rstat_rxf = gfar_read(®s->rstat) & RSTAT_RXF_MASK; > -- > -- num_act_queues = bitmap_weight(&rstat_rxf, MAX_RX_QS); > -- 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; > -- } > -- } > -+ while (num_queues && left_over_budget) { > -+ budget_per_queue = left_over_budget/num_queues; > -+ left_over_budget = 0; > - > - 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))) > -+ if (test_bit(i, &serviced_queues)) > - 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(®s->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; > -+ tx_queue = priv->tx_queue[rx_queue->qindex]; > -+ > -+ tx_cleaned += gfar_clean_tx_ring(tx_queue); > -+ rx_cleaned_per_queue = > -+ gfar_clean_rx_ring(rx_queue, > budget_per_queue); > -+ rx_cleaned += rx_cleaned_per_queue; > -+ if (rx_cleaned_per_queue < budget_per_queue) { > -+ left_over_budget = left_over_budget + > -+ (budget_per_queue - > -+ rx_cleaned_per_queue); > -+ set_bit(i, &serviced_queues); > -+ num_queues--; > - } > - } > -+ } > - > -- if (work_done >= budget) > -- break; > -- > -- if (!num_act_queues && !has_tx_work) { > -+ if (tx_cleaned) > -+ return budget; > - > -- napi_complete(napi); > -+ if (rx_cleaned < budget) { > -+ napi_complete(napi); > - > -- /* Clear the halt bit in RSTAT */ > -- gfar_write(®s->rstat, gfargrp->rstat); > -+ /* Clear the halt bit in RSTAT */ > -+ gfar_write(®s->rstat, gfargrp->rstat); > - > -- gfar_write(®s->imask, IMASK_DEFAULT); > -+ gfar_write(®s->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; > -+ return rx_cleaned; > - } > - > - #ifdef CONFIG_NET_POLL_CONTROLLER > ---- a/drivers/net/ethernet/freescale/gianfar.h > -+++ b/drivers/net/ethernet/freescale/gianfar.h > -@@ -291,9 +291,7 @@ extern const char gfar_driver_version[]; > - #define RCTRL_PADDING(x) ((x << 16) & RCTRL_PAL_MASK) > - > - > --#define RSTAT_CLEAR_RHALT 0x00800000 > --#define RSTAT_CLEAR_RXF0 0x00000080 > --#define RSTAT_RXF_MASK 0x000000ff > -+#define RSTAT_CLEAR_RHALT 0x00800000 > - > - #define TCTRL_IPCSEN 0x00004000 > - #define TCTRL_TUCSEN 0x00002000 > diff --git > a/target/linux/mpc85xx/patches-3.10/201-fix_gianfar_napi_poll.patch > b/target/linux/mpc85xx/patches-3.10/201-fix_gianfar_napi_poll.patch > new file mode 100644 > index 0000000..8f40b91 > --- /dev/null > +++ b/target/linux/mpc85xx/patches-3.10/201-fix_gianfar_napi_poll.patch > @@ -0,0 +1,111 @@ > +Index: linux-3.10.18/drivers/net/ethernet/freescale/gianfar.c > +=================================================================== > +--- linux-3.10.18.orig/drivers/net/ethernet/freescale/gianfar.c > 2013-11-19 13:30:28.681253169 +0100 > ++++ linux-3.10.18/drivers/net/ethernet/freescale/gianfar.c 2013-11-19 > 13:36:23.685269549 +0100 > +@@ -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(®s->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(®s->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(®s->rstat, gfargrp->rstat); > ++ /* Clear the halt bit in RSTAT */ > ++ gfar_write(®s->rstat, gfargrp->rstat); > + > +- gfar_write(®s->imask, IMASK_DEFAULT); > ++ gfar_write(®s->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 _______________________________________________ openwrt-devel mailing list openwrt-devel@lists.openwrt.org https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel