aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorClaudiu Manoil <claudiu.manoil@freescale.com>2013-03-19 03:40:02 -0400
committerDavid S. Miller <davem@davemloft.net>2013-03-20 13:21:52 -0400
commitc233cf4074e50933edd5e82c3c5826923f0c1b10 (patch)
treef7541eb12a7041ebda10230aa4d5a84586833e41
parent3e5289d5e3f98b7b5b8cac32e9e5a7004c067436 (diff)
gianfar: Fix tx napi polling
There are 2 issues with the current napi poll routine, with regards to tx ring cleanup: 1) for multi-queue devices (MQ_MG_MODE), should tx_bit_map != rx_bit_map, which is possible (and supported in h/w) if the DT property "fsl,tx-bit-map" holds a different value than rx_bit_map, the current polling routine will service the wrong Tx queues in this case (i.e. the interrupt group will receive interrupts from tx queues that it will not service) 2) Tx cleanup completion consumes napi budget, whereas the napi budget should be reserved for Rx work only. The patch fixes these issues and provides a clean napi polling routine. Napi poll completion is reached when all the Rx queues have been serviced and there is no Tx work to do. Signed-off-by: Claudiu Manoil <claudiu.manoil@freescale.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/freescale/gianfar.c82
1 files changed, 45 insertions, 37 deletions
diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c
index 1b468a82a68f..1e555a70b821 100644
--- 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 *napi, int budget);
132static void gfar_netpoll(struct net_device *dev); 132static void gfar_netpoll(struct net_device *dev);
133#endif 133#endif
134int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit); 134int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit);
135static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue); 135static void gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue);
136static void gfar_process_frame(struct net_device *dev, struct sk_buff *skb, 136static void gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
137 int amount_pull, struct napi_struct *napi); 137 int amount_pull, struct napi_struct *napi);
138void gfar_halt(struct net_device *dev); 138void gfar_halt(struct net_device *dev);
@@ -2468,7 +2468,7 @@ static void gfar_align_skb(struct sk_buff *skb)
2468} 2468}
2469 2469
2470/* Interrupt Handler for Transmit complete */ 2470/* Interrupt Handler for Transmit complete */
2471static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue) 2471static void gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
2472{ 2472{
2473 struct net_device *dev = tx_queue->dev; 2473 struct net_device *dev = tx_queue->dev;
2474 struct netdev_queue *txq; 2474 struct netdev_queue *txq;
@@ -2570,8 +2570,6 @@ static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
2570 tx_queue->dirty_tx = bdp; 2570 tx_queue->dirty_tx = bdp;
2571 2571
2572 netdev_tx_completed_queue(txq, howmany, bytes_sent); 2572 netdev_tx_completed_queue(txq, howmany, bytes_sent);
2573
2574 return howmany;
2575} 2573}
2576 2574
2577static void gfar_schedule_cleanup(struct gfar_priv_grp *gfargrp) 2575static void gfar_schedule_cleanup(struct gfar_priv_grp *gfargrp)
@@ -2834,62 +2832,72 @@ static int gfar_poll(struct napi_struct *napi, int budget)
2834 struct gfar __iomem *regs = gfargrp->regs; 2832 struct gfar __iomem *regs = gfargrp->regs;
2835 struct gfar_priv_tx_q *tx_queue = NULL; 2833 struct gfar_priv_tx_q *tx_queue = NULL;
2836 struct gfar_priv_rx_q *rx_queue = NULL; 2834 struct gfar_priv_rx_q *rx_queue = NULL;
2837 int rx_cleaned = 0, budget_per_queue = 0, rx_cleaned_per_queue = 0; 2835 int work_done = 0, work_done_per_q = 0;
2838 int tx_cleaned = 0, i, left_over_budget = budget; 2836 int i, budget_per_q;
2837 int has_tx_work;
2839 unsigned long serviced_queues = 0; 2838 unsigned long serviced_queues = 0;
2840 int num_queues = 0; 2839 int num_queues = gfargrp->num_rx_queues;
2841
2842 num_queues = gfargrp->num_rx_queues;
2843 budget_per_queue = budget/num_queues;
2844 2840
2841 budget_per_q = budget/num_queues;
2845 /* Clear IEVENT, so interrupts aren't called again 2842 /* Clear IEVENT, so interrupts aren't called again
2846 * because of the packets that have already arrived 2843 * because of the packets that have already arrived
2847 */ 2844 */
2848 gfar_write(&regs->ievent, IEVENT_RTX_MASK); 2845 gfar_write(&regs->ievent, IEVENT_RTX_MASK);
2849 2846
2850 while (num_queues && left_over_budget) { 2847 while (1) {
2851 budget_per_queue = left_over_budget/num_queues; 2848 has_tx_work = 0;
2852 left_over_budget = 0; 2849 for_each_set_bit(i, &gfargrp->tx_bit_map, priv->num_tx_queues) {
2850 tx_queue = priv->tx_queue[i];
2851 /* run Tx cleanup to completion */
2852 if (tx_queue->tx_skbuff[tx_queue->skb_dirtytx]) {
2853 gfar_clean_tx_ring(tx_queue);
2854 has_tx_work = 1;
2855 }
2856 }
2853 2857
2854 for_each_set_bit(i, &gfargrp->rx_bit_map, priv->num_rx_queues) { 2858 for_each_set_bit(i, &gfargrp->rx_bit_map, priv->num_rx_queues) {
2855 if (test_bit(i, &serviced_queues)) 2859 if (test_bit(i, &serviced_queues))
2856 continue; 2860 continue;
2861
2857 rx_queue = priv->rx_queue[i]; 2862 rx_queue = priv->rx_queue[i];
2858 tx_queue = priv->tx_queue[rx_queue->qindex]; 2863 work_done_per_q =
2859 2864 gfar_clean_rx_ring(rx_queue, budget_per_q);
2860 tx_cleaned += gfar_clean_tx_ring(tx_queue); 2865 work_done += work_done_per_q;
2861 rx_cleaned_per_queue = 2866
2862 gfar_clean_rx_ring(rx_queue, budget_per_queue); 2867 /* finished processing this queue */
2863 rx_cleaned += rx_cleaned_per_queue; 2868 if (work_done_per_q < budget_per_q) {
2864 if (rx_cleaned_per_queue < budget_per_queue) {
2865 left_over_budget = left_over_budget +
2866 (budget_per_queue -
2867 rx_cleaned_per_queue);
2868 set_bit(i, &serviced_queues); 2869 set_bit(i, &serviced_queues);
2869 num_queues--; 2870 num_queues--;
2871 if (!num_queues)
2872 break;
2873 /* recompute budget per Rx queue */
2874 budget_per_q =
2875 (budget - work_done) / num_queues;
2870 } 2876 }
2871 } 2877 }
2872 }
2873 2878
2874 if (tx_cleaned) 2879 if (work_done >= budget)
2875 return budget; 2880 break;
2876 2881
2877 if (rx_cleaned < budget) { 2882 if (!num_queues && !has_tx_work) {
2878 napi_complete(napi);
2879 2883
2880 /* Clear the halt bit in RSTAT */ 2884 napi_complete(napi);
2881 gfar_write(&regs->rstat, gfargrp->rstat);
2882 2885
2883 gfar_write(&regs->imask, IMASK_DEFAULT); 2886 /* Clear the halt bit in RSTAT */
2887 gfar_write(&regs->rstat, gfargrp->rstat);
2884 2888
2885 /* If we are coalescing interrupts, update the timer 2889 gfar_write(&regs->imask, IMASK_DEFAULT);
2886 * Otherwise, clear it 2890
2887 */ 2891 /* If we are coalescing interrupts, update the timer
2888 gfar_configure_coalescing(priv, gfargrp->rx_bit_map, 2892 * Otherwise, clear it
2889 gfargrp->tx_bit_map); 2893 */
2894 gfar_configure_coalescing(priv, gfargrp->rx_bit_map,
2895 gfargrp->tx_bit_map);
2896 break;
2897 }
2890 } 2898 }
2891 2899
2892 return rx_cleaned; 2900 return work_done;
2893} 2901}
2894 2902
2895#ifdef CONFIG_NET_POLL_CONTROLLER 2903#ifdef CONFIG_NET_POLL_CONTROLLER