diff options
author | Giuseppe CAVALLARO <peppe.cavallaro@st.com> | 2012-11-25 18:10:42 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-11-26 17:22:10 -0500 |
commit | 9125cdd1be1199588f71c99e76e32bcda0b7d847 (patch) | |
tree | 52fe0ed58cc7522324399f9a3e23fb81bdff6d7e /drivers/net/ethernet/stmicro/stmmac | |
parent | 7284a3f1ad0d09dcf3cc5a1914ceaf01a3352314 (diff) |
stmmac: add the initial tx coalesce schema
This patch adds a new schema used for mitigating the
number of transmit interrupts.
It is based on a SW timer and a threshold value.
The timer is used to periodically call the stmmac_tx_clean
function; the threshold is used for setting the IC (Interrupt
on Completion bit). The ISR will then invoke the poll method.
Also the patch improves some ethtool stat fields.
V2: review the logic to manage the IC bit in the TDESC
that was bugged because it didn't take care about the
fragments. Also fix the tx_count_frames that has not to be
limited to TX DMA ring. Thanks to Ben Hutchings.
V3: removed the spin_lock irqsave/restore as D. Miller suggested.
Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/stmicro/stmmac')
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/common.h | 22 | ||||
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c | 7 | ||||
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/stmmac.h | 4 | ||||
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c | 8 | ||||
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 132 |
5 files changed, 111 insertions, 62 deletions
diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h index 719be3912aa9..723e9035f275 100644 --- a/drivers/net/ethernet/stmicro/stmmac/common.h +++ b/drivers/net/ethernet/stmicro/stmmac/common.h | |||
@@ -95,9 +95,12 @@ struct stmmac_extra_stats { | |||
95 | unsigned long threshold; | 95 | unsigned long threshold; |
96 | unsigned long tx_pkt_n; | 96 | unsigned long tx_pkt_n; |
97 | unsigned long rx_pkt_n; | 97 | unsigned long rx_pkt_n; |
98 | unsigned long poll_n; | ||
99 | unsigned long sched_timer_n; | ||
100 | unsigned long normal_irq_n; | 98 | unsigned long normal_irq_n; |
99 | unsigned long rx_normal_irq_n; | ||
100 | unsigned long napi_poll; | ||
101 | unsigned long tx_normal_irq_n; | ||
102 | unsigned long tx_clean; | ||
103 | unsigned long tx_reset_ic_bit; | ||
101 | unsigned long mmc_tx_irq_n; | 104 | unsigned long mmc_tx_irq_n; |
102 | unsigned long mmc_rx_irq_n; | 105 | unsigned long mmc_rx_irq_n; |
103 | unsigned long mmc_rx_csum_offload_irq_n; | 106 | unsigned long mmc_rx_csum_offload_irq_n; |
@@ -162,6 +165,12 @@ struct stmmac_extra_stats { | |||
162 | #define DMA_HW_FEAT_ACTPHYIF 0x70000000 /* Active/selected PHY interface */ | 165 | #define DMA_HW_FEAT_ACTPHYIF 0x70000000 /* Active/selected PHY interface */ |
163 | #define DEFAULT_DMA_PBL 8 | 166 | #define DEFAULT_DMA_PBL 8 |
164 | 167 | ||
168 | /* Tx coalesce parameters */ | ||
169 | #define STMMAC_COAL_TX_TIMER 40000 | ||
170 | #define STMMAC_MAX_COAL_TX_TICK 100000 | ||
171 | #define STMMAC_TX_MAX_FRAMES 256 | ||
172 | #define STMMAC_TX_FRAMES 64 | ||
173 | |||
165 | enum rx_frame_status { /* IPC status */ | 174 | enum rx_frame_status { /* IPC status */ |
166 | good_frame = 0, | 175 | good_frame = 0, |
167 | discard_frame = 1, | 176 | discard_frame = 1, |
@@ -169,10 +178,11 @@ enum rx_frame_status { /* IPC status */ | |||
169 | llc_snap = 4, | 178 | llc_snap = 4, |
170 | }; | 179 | }; |
171 | 180 | ||
172 | enum tx_dma_irq_status { | 181 | enum dma_irq_status { |
173 | tx_hard_error = 1, | 182 | tx_hard_error = 0x1, |
174 | tx_hard_error_bump_tc = 2, | 183 | tx_hard_error_bump_tc = 0x2, |
175 | handle_tx_rx = 3, | 184 | handle_rx = 0x4, |
185 | handle_tx = 0x8, | ||
176 | }; | 186 | }; |
177 | 187 | ||
178 | enum core_specific_irq_mask { | 188 | enum core_specific_irq_mask { |
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c index 4e0e18a44fcc..73766e655011 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c | |||
@@ -206,9 +206,10 @@ int dwmac_dma_interrupt(void __iomem *ioaddr, | |||
206 | /* TX/RX NORMAL interrupts */ | 206 | /* TX/RX NORMAL interrupts */ |
207 | if (intr_status & DMA_STATUS_NIS) { | 207 | if (intr_status & DMA_STATUS_NIS) { |
208 | x->normal_irq_n++; | 208 | x->normal_irq_n++; |
209 | if (likely((intr_status & DMA_STATUS_RI) || | 209 | if (likely(intr_status & DMA_STATUS_RI)) |
210 | (intr_status & (DMA_STATUS_TI)))) | 210 | ret |= handle_rx; |
211 | ret = handle_tx_rx; | 211 | if (intr_status & (DMA_STATUS_TI)) |
212 | ret |= handle_tx; | ||
212 | } | 213 | } |
213 | /* Optional hardware blocks, interrupts should be disabled */ | 214 | /* Optional hardware blocks, interrupts should be disabled */ |
214 | if (unlikely(intr_status & | 215 | if (unlikely(intr_status & |
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h index 5f89415bdbc8..01b34517ca8e 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h | |||
@@ -87,6 +87,10 @@ struct stmmac_priv { | |||
87 | int eee_enabled; | 87 | int eee_enabled; |
88 | int eee_active; | 88 | int eee_active; |
89 | int tx_lpi_timer; | 89 | int tx_lpi_timer; |
90 | struct timer_list txtimer; | ||
91 | u32 tx_count_frames; | ||
92 | u32 tx_coal_frames; | ||
93 | u32 tx_coal_timer; | ||
90 | }; | 94 | }; |
91 | 95 | ||
92 | extern int phyaddr; | 96 | extern int phyaddr; |
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c index 76fd61aa005f..15cb6ee6ee41 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c | |||
@@ -90,10 +90,12 @@ static const struct stmmac_stats stmmac_gstrings_stats[] = { | |||
90 | STMMAC_STAT(threshold), | 90 | STMMAC_STAT(threshold), |
91 | STMMAC_STAT(tx_pkt_n), | 91 | STMMAC_STAT(tx_pkt_n), |
92 | STMMAC_STAT(rx_pkt_n), | 92 | STMMAC_STAT(rx_pkt_n), |
93 | STMMAC_STAT(poll_n), | ||
94 | STMMAC_STAT(sched_timer_n), | ||
95 | STMMAC_STAT(normal_irq_n), | ||
96 | STMMAC_STAT(normal_irq_n), | 93 | STMMAC_STAT(normal_irq_n), |
94 | STMMAC_STAT(rx_normal_irq_n), | ||
95 | STMMAC_STAT(napi_poll), | ||
96 | STMMAC_STAT(tx_normal_irq_n), | ||
97 | STMMAC_STAT(tx_clean), | ||
98 | STMMAC_STAT(tx_reset_ic_bit), | ||
97 | STMMAC_STAT(mmc_tx_irq_n), | 99 | STMMAC_STAT(mmc_tx_irq_n), |
98 | STMMAC_STAT(mmc_rx_irq_n), | 100 | STMMAC_STAT(mmc_rx_irq_n), |
99 | STMMAC_STAT(mmc_rx_csum_offload_irq_n), | 101 | STMMAC_STAT(mmc_rx_csum_offload_irq_n), |
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 777234cb30d6..d9d68649bdaa 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | |||
@@ -137,6 +137,8 @@ static int stmmac_init_fs(struct net_device *dev); | |||
137 | static void stmmac_exit_fs(void); | 137 | static void stmmac_exit_fs(void); |
138 | #endif | 138 | #endif |
139 | 139 | ||
140 | #define STMMAC_COAL_TIMER(x) (jiffies + usecs_to_jiffies(x)) | ||
141 | |||
140 | /** | 142 | /** |
141 | * stmmac_verify_args - verify the driver parameters. | 143 | * stmmac_verify_args - verify the driver parameters. |
142 | * Description: it verifies if some wrong parameter is passed to the driver. | 144 | * Description: it verifies if some wrong parameter is passed to the driver. |
@@ -688,16 +690,18 @@ static void stmmac_dma_operation_mode(struct stmmac_priv *priv) | |||
688 | } | 690 | } |
689 | 691 | ||
690 | /** | 692 | /** |
691 | * stmmac_tx: | 693 | * stmmac_tx_clean: |
692 | * @priv: private driver structure | 694 | * @priv: private data pointer |
693 | * Description: it reclaims resources after transmission completes. | 695 | * Description: it reclaims resources after transmission completes. |
694 | */ | 696 | */ |
695 | static void stmmac_tx(struct stmmac_priv *priv) | 697 | static void stmmac_tx_clean(struct stmmac_priv *priv) |
696 | { | 698 | { |
697 | unsigned int txsize = priv->dma_tx_size; | 699 | unsigned int txsize = priv->dma_tx_size; |
698 | 700 | ||
699 | spin_lock(&priv->tx_lock); | 701 | spin_lock(&priv->tx_lock); |
700 | 702 | ||
703 | priv->xstats.tx_clean++; | ||
704 | |||
701 | while (priv->dirty_tx != priv->cur_tx) { | 705 | while (priv->dirty_tx != priv->cur_tx) { |
702 | int last; | 706 | int last; |
703 | unsigned int entry = priv->dirty_tx % txsize; | 707 | unsigned int entry = priv->dirty_tx % txsize; |
@@ -757,40 +761,16 @@ static void stmmac_tx(struct stmmac_priv *priv) | |||
757 | spin_unlock(&priv->tx_lock); | 761 | spin_unlock(&priv->tx_lock); |
758 | } | 762 | } |
759 | 763 | ||
760 | static inline void stmmac_enable_irq(struct stmmac_priv *priv) | 764 | static inline void stmmac_enable_dma_irq(struct stmmac_priv *priv) |
761 | { | 765 | { |
762 | priv->hw->dma->enable_dma_irq(priv->ioaddr); | 766 | priv->hw->dma->enable_dma_irq(priv->ioaddr); |
763 | } | 767 | } |
764 | 768 | ||
765 | static inline void stmmac_disable_irq(struct stmmac_priv *priv) | 769 | static inline void stmmac_disable_dma_irq(struct stmmac_priv *priv) |
766 | { | 770 | { |
767 | priv->hw->dma->disable_dma_irq(priv->ioaddr); | 771 | priv->hw->dma->disable_dma_irq(priv->ioaddr); |
768 | } | 772 | } |
769 | 773 | ||
770 | static int stmmac_has_work(struct stmmac_priv *priv) | ||
771 | { | ||
772 | unsigned int has_work = 0; | ||
773 | int rxret, tx_work = 0; | ||
774 | |||
775 | rxret = priv->hw->desc->get_rx_owner(priv->dma_rx + | ||
776 | (priv->cur_rx % priv->dma_rx_size)); | ||
777 | |||
778 | if (priv->dirty_tx != priv->cur_tx) | ||
779 | tx_work = 1; | ||
780 | |||
781 | if (likely(!rxret || tx_work)) | ||
782 | has_work = 1; | ||
783 | |||
784 | return has_work; | ||
785 | } | ||
786 | |||
787 | static inline void _stmmac_schedule(struct stmmac_priv *priv) | ||
788 | { | ||
789 | if (likely(stmmac_has_work(priv))) { | ||
790 | stmmac_disable_irq(priv); | ||
791 | napi_schedule(&priv->napi); | ||
792 | } | ||
793 | } | ||
794 | 774 | ||
795 | /** | 775 | /** |
796 | * stmmac_tx_err: | 776 | * stmmac_tx_err: |
@@ -813,16 +793,18 @@ static void stmmac_tx_err(struct stmmac_priv *priv) | |||
813 | netif_wake_queue(priv->dev); | 793 | netif_wake_queue(priv->dev); |
814 | } | 794 | } |
815 | 795 | ||
816 | |||
817 | static void stmmac_dma_interrupt(struct stmmac_priv *priv) | 796 | static void stmmac_dma_interrupt(struct stmmac_priv *priv) |
818 | { | 797 | { |
819 | int status; | 798 | int status; |
820 | 799 | ||
821 | status = priv->hw->dma->dma_interrupt(priv->ioaddr, &priv->xstats); | 800 | status = priv->hw->dma->dma_interrupt(priv->ioaddr, &priv->xstats); |
822 | if (likely(status == handle_tx_rx)) | 801 | if (likely((status & handle_rx)) || (status & handle_tx)) { |
823 | _stmmac_schedule(priv); | 802 | if (likely(napi_schedule_prep(&priv->napi))) { |
824 | 803 | stmmac_disable_dma_irq(priv); | |
825 | else if (unlikely(status == tx_hard_error_bump_tc)) { | 804 | __napi_schedule(&priv->napi); |
805 | } | ||
806 | } | ||
807 | if (unlikely(status & tx_hard_error_bump_tc)) { | ||
826 | /* Try to bump up the dma threshold on this failure */ | 808 | /* Try to bump up the dma threshold on this failure */ |
827 | if (unlikely(tc != SF_DMA_MODE) && (tc <= 256)) { | 809 | if (unlikely(tc != SF_DMA_MODE) && (tc <= 256)) { |
828 | tc += 64; | 810 | tc += 64; |
@@ -938,7 +920,6 @@ static int stmmac_get_hw_features(struct stmmac_priv *priv) | |||
938 | /* Alternate (enhanced) DESC mode*/ | 920 | /* Alternate (enhanced) DESC mode*/ |
939 | priv->dma_cap.enh_desc = | 921 | priv->dma_cap.enh_desc = |
940 | (hw_cap & DMA_HW_FEAT_ENHDESSEL) >> 24; | 922 | (hw_cap & DMA_HW_FEAT_ENHDESSEL) >> 24; |
941 | |||
942 | } | 923 | } |
943 | 924 | ||
944 | return hw_cap; | 925 | return hw_cap; |
@@ -980,6 +961,38 @@ static int stmmac_init_dma_engine(struct stmmac_priv *priv) | |||
980 | } | 961 | } |
981 | 962 | ||
982 | /** | 963 | /** |
964 | * stmmac_tx_timer: | ||
965 | * @data: data pointer | ||
966 | * Description: | ||
967 | * This is the timer handler to directly invoke the stmmac_tx_clean. | ||
968 | */ | ||
969 | static void stmmac_tx_timer(unsigned long data) | ||
970 | { | ||
971 | struct stmmac_priv *priv = (struct stmmac_priv *)data; | ||
972 | |||
973 | stmmac_tx_clean(priv); | ||
974 | } | ||
975 | |||
976 | /** | ||
977 | * stmmac_tx_timer: | ||
978 | * @priv: private data structure | ||
979 | * Description: | ||
980 | * This inits the transmit coalesce parameters: i.e. timer rate, | ||
981 | * timer handler and default threshold used for enabling the | ||
982 | * interrupt on completion bit. | ||
983 | */ | ||
984 | static void stmmac_init_tx_coalesce(struct stmmac_priv *priv) | ||
985 | { | ||
986 | priv->tx_coal_frames = STMMAC_TX_FRAMES; | ||
987 | priv->tx_coal_timer = STMMAC_COAL_TX_TIMER; | ||
988 | init_timer(&priv->txtimer); | ||
989 | priv->txtimer.expires = STMMAC_COAL_TIMER(priv->tx_coal_timer); | ||
990 | priv->txtimer.data = (unsigned long)priv; | ||
991 | priv->txtimer.function = stmmac_tx_timer; | ||
992 | add_timer(&priv->txtimer); | ||
993 | } | ||
994 | |||
995 | /** | ||
983 | * stmmac_open - open entry point of the driver | 996 | * stmmac_open - open entry point of the driver |
984 | * @dev : pointer to the device structure. | 997 | * @dev : pointer to the device structure. |
985 | * Description: | 998 | * Description: |
@@ -1091,6 +1104,8 @@ static int stmmac_open(struct net_device *dev) | |||
1091 | priv->tx_lpi_timer = STMMAC_DEFAULT_TWT_LS_TIMER; | 1104 | priv->tx_lpi_timer = STMMAC_DEFAULT_TWT_LS_TIMER; |
1092 | priv->eee_enabled = stmmac_eee_init(priv); | 1105 | priv->eee_enabled = stmmac_eee_init(priv); |
1093 | 1106 | ||
1107 | stmmac_init_tx_coalesce(priv); | ||
1108 | |||
1094 | napi_enable(&priv->napi); | 1109 | napi_enable(&priv->napi); |
1095 | netif_start_queue(dev); | 1110 | netif_start_queue(dev); |
1096 | 1111 | ||
@@ -1136,6 +1151,8 @@ static int stmmac_release(struct net_device *dev) | |||
1136 | 1151 | ||
1137 | napi_disable(&priv->napi); | 1152 | napi_disable(&priv->napi); |
1138 | 1153 | ||
1154 | del_timer_sync(&priv->txtimer); | ||
1155 | |||
1139 | /* Free the IRQ lines */ | 1156 | /* Free the IRQ lines */ |
1140 | free_irq(dev->irq, dev); | 1157 | free_irq(dev->irq, dev); |
1141 | if (priv->wol_irq != dev->irq) | 1158 | if (priv->wol_irq != dev->irq) |
@@ -1198,11 +1215,13 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) | |||
1198 | 1215 | ||
1199 | #ifdef STMMAC_XMIT_DEBUG | 1216 | #ifdef STMMAC_XMIT_DEBUG |
1200 | if ((skb->len > ETH_FRAME_LEN) || nfrags) | 1217 | if ((skb->len > ETH_FRAME_LEN) || nfrags) |
1201 | pr_info("stmmac xmit:\n" | 1218 | pr_debug("stmmac xmit: [entry %d]\n" |
1202 | "\tskb addr %p - len: %d - nopaged_len: %d\n" | 1219 | "\tskb addr %p - len: %d - nopaged_len: %d\n" |
1203 | "\tn_frags: %d - ip_summed: %d - %s gso\n", | 1220 | "\tn_frags: %d - ip_summed: %d - %s gso\n" |
1204 | skb, skb->len, nopaged_len, nfrags, skb->ip_summed, | 1221 | "\ttx_count_frames %d\n", entry, |
1205 | !skb_is_gso(skb) ? "isn't" : "is"); | 1222 | skb, skb->len, nopaged_len, nfrags, skb->ip_summed, |
1223 | !skb_is_gso(skb) ? "isn't" : "is", | ||
1224 | priv->tx_count_frames); | ||
1206 | #endif | 1225 | #endif |
1207 | 1226 | ||
1208 | csum_insertion = (skb->ip_summed == CHECKSUM_PARTIAL); | 1227 | csum_insertion = (skb->ip_summed == CHECKSUM_PARTIAL); |
@@ -1212,9 +1231,9 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) | |||
1212 | 1231 | ||
1213 | #ifdef STMMAC_XMIT_DEBUG | 1232 | #ifdef STMMAC_XMIT_DEBUG |
1214 | if ((nfrags > 0) || (skb->len > ETH_FRAME_LEN)) | 1233 | if ((nfrags > 0) || (skb->len > ETH_FRAME_LEN)) |
1215 | pr_debug("stmmac xmit: skb len: %d, nopaged_len: %d,\n" | 1234 | pr_debug("\tskb len: %d, nopaged_len: %d,\n" |
1216 | "\t\tn_frags: %d, ip_summed: %d\n", | 1235 | "\t\tn_frags: %d, ip_summed: %d\n", |
1217 | skb->len, nopaged_len, nfrags, skb->ip_summed); | 1236 | skb->len, nopaged_len, nfrags, skb->ip_summed); |
1218 | #endif | 1237 | #endif |
1219 | priv->tx_skbuff[entry] = skb; | 1238 | priv->tx_skbuff[entry] = skb; |
1220 | 1239 | ||
@@ -1245,10 +1264,24 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) | |||
1245 | wmb(); | 1264 | wmb(); |
1246 | } | 1265 | } |
1247 | 1266 | ||
1248 | /* Interrupt on completition only for the latest segment */ | 1267 | /* Finalize the latest segment. */ |
1249 | priv->hw->desc->close_tx_desc(desc); | 1268 | priv->hw->desc->close_tx_desc(desc); |
1250 | 1269 | ||
1251 | wmb(); | 1270 | wmb(); |
1271 | /* According to the coalesce parameter the IC bit for the latest | ||
1272 | * segment could be reset and the timer re-started to invoke the | ||
1273 | * stmmac_tx function. This approach takes care about the fragments. | ||
1274 | */ | ||
1275 | priv->tx_count_frames += nfrags + 1; | ||
1276 | if (priv->tx_coal_frames > priv->tx_count_frames) { | ||
1277 | priv->hw->desc->clear_tx_ic(desc); | ||
1278 | priv->xstats.tx_reset_ic_bit++; | ||
1279 | TX_DBG("\t[entry %d]: tx_count_frames %d\n", entry, | ||
1280 | priv->tx_count_frames); | ||
1281 | mod_timer(&priv->txtimer, | ||
1282 | STMMAC_COAL_TIMER(priv->tx_coal_timer)); | ||
1283 | } else | ||
1284 | priv->tx_count_frames = 0; | ||
1252 | 1285 | ||
1253 | /* To avoid raise condition */ | 1286 | /* To avoid raise condition */ |
1254 | priv->hw->desc->set_tx_owner(first); | 1287 | priv->hw->desc->set_tx_owner(first); |
@@ -1419,21 +1452,20 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit) | |||
1419 | * @budget : maximum number of packets that the current CPU can receive from | 1452 | * @budget : maximum number of packets that the current CPU can receive from |
1420 | * all interfaces. | 1453 | * all interfaces. |
1421 | * Description : | 1454 | * Description : |
1422 | * This function implements the the reception process. | 1455 | * To look at the incoming frames and clear the tx resources. |
1423 | * Also it runs the TX completion thread | ||
1424 | */ | 1456 | */ |
1425 | static int stmmac_poll(struct napi_struct *napi, int budget) | 1457 | static int stmmac_poll(struct napi_struct *napi, int budget) |
1426 | { | 1458 | { |
1427 | struct stmmac_priv *priv = container_of(napi, struct stmmac_priv, napi); | 1459 | struct stmmac_priv *priv = container_of(napi, struct stmmac_priv, napi); |
1428 | int work_done = 0; | 1460 | int work_done = 0; |
1429 | 1461 | ||
1430 | priv->xstats.poll_n++; | 1462 | priv->xstats.napi_poll++; |
1431 | stmmac_tx(priv); | 1463 | stmmac_tx_clean(priv); |
1432 | work_done = stmmac_rx(priv, budget); | ||
1433 | 1464 | ||
1465 | work_done = stmmac_rx(priv, budget); | ||
1434 | if (work_done < budget) { | 1466 | if (work_done < budget) { |
1435 | napi_complete(napi); | 1467 | napi_complete(napi); |
1436 | stmmac_enable_irq(priv); | 1468 | stmmac_enable_dma_irq(priv); |
1437 | } | 1469 | } |
1438 | return work_done; | 1470 | return work_done; |
1439 | } | 1471 | } |