aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/stmicro/stmmac
diff options
context:
space:
mode:
authorGiuseppe CAVALLARO <peppe.cavallaro@st.com>2012-11-25 18:10:42 -0500
committerDavid S. Miller <davem@davemloft.net>2012-11-26 17:22:10 -0500
commit9125cdd1be1199588f71c99e76e32bcda0b7d847 (patch)
tree52fe0ed58cc7522324399f9a3e23fb81bdff6d7e /drivers/net/ethernet/stmicro/stmmac
parent7284a3f1ad0d09dcf3cc5a1914ceaf01a3352314 (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.h22
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c7
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac.h4
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c8
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_main.c132
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
165enum rx_frame_status { /* IPC status */ 174enum 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
172enum tx_dma_irq_status { 181enum 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
178enum core_specific_irq_mask { 188enum 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
92extern int phyaddr; 96extern 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);
137static void stmmac_exit_fs(void); 137static 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 */
695static void stmmac_tx(struct stmmac_priv *priv) 697static 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
760static inline void stmmac_enable_irq(struct stmmac_priv *priv) 764static 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
765static inline void stmmac_disable_irq(struct stmmac_priv *priv) 769static 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
770static 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
787static 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
817static void stmmac_dma_interrupt(struct stmmac_priv *priv) 796static 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 */
969static 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 */
984static 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 */
1425static int stmmac_poll(struct napi_struct *napi, int budget) 1457static 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}