27
27
#include <linux/of_address.h>
28
28
#include <linux/phy.h>
29
29
#include <linux/clk.h>
30
+ #include <linux/hrtimer.h>
31
+ #include <linux/ktime.h>
30
32
#include <uapi/linux/ppp_defs.h>
31
33
#include <net/ip.h>
32
34
#include <net/ipv6.h>
299
301
300
302
/* Coalescing */
301
303
#define MVPP2_TXDONE_COAL_PKTS_THRESH 15
304
+ #define MVPP2_TXDONE_HRTIMER_PERIOD_NS 1000000UL
302
305
#define MVPP2_RX_COAL_PKTS 32
303
306
#define MVPP2_RX_COAL_USEC 100
304
307
@@ -660,6 +663,14 @@ struct mvpp2_pcpu_stats {
660
663
u64 tx_bytes ;
661
664
};
662
665
666
+ /* Per-CPU port control */
667
+ struct mvpp2_port_pcpu {
668
+ struct hrtimer tx_done_timer ;
669
+ bool timer_scheduled ;
670
+ /* Tasklet for egress finalization */
671
+ struct tasklet_struct tx_done_tasklet ;
672
+ };
673
+
663
674
struct mvpp2_port {
664
675
u8 id ;
665
676
@@ -679,6 +690,9 @@ struct mvpp2_port {
679
690
u32 pending_cause_rx ;
680
691
struct napi_struct napi ;
681
692
693
+ /* Per-CPU port control */
694
+ struct mvpp2_port_pcpu __percpu * pcpu ;
695
+
682
696
/* Flags */
683
697
unsigned long flags ;
684
698
@@ -3798,7 +3812,6 @@ static void mvpp2_interrupts_unmask(void *arg)
3798
3812
3799
3813
mvpp2_write (port -> priv , MVPP2_ISR_RX_TX_MASK_REG (port -> id ),
3800
3814
(MVPP2_CAUSE_MISC_SUM_MASK |
3801
- MVPP2_CAUSE_TXQ_OCCUP_DESC_ALL_MASK |
3802
3815
MVPP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK ));
3803
3816
}
3804
3817
@@ -4374,23 +4387,6 @@ static void mvpp2_rx_time_coal_set(struct mvpp2_port *port,
4374
4387
rxq -> time_coal = usec ;
4375
4388
}
4376
4389
4377
- /* Set threshold for TX_DONE pkts coalescing */
4378
- static void mvpp2_tx_done_pkts_coal_set (void * arg )
4379
- {
4380
- struct mvpp2_port * port = arg ;
4381
- int queue ;
4382
- u32 val ;
4383
-
4384
- for (queue = 0 ; queue < txq_number ; queue ++ ) {
4385
- struct mvpp2_tx_queue * txq = port -> txqs [queue ];
4386
-
4387
- val = (txq -> done_pkts_coal << MVPP2_TRANSMITTED_THRESH_OFFSET ) &
4388
- MVPP2_TRANSMITTED_THRESH_MASK ;
4389
- mvpp2_write (port -> priv , MVPP2_TXQ_NUM_REG , txq -> id );
4390
- mvpp2_write (port -> priv , MVPP2_TXQ_THRESH_REG , val );
4391
- }
4392
- }
4393
-
4394
4390
/* Free Tx queue skbuffs */
4395
4391
static void mvpp2_txq_bufs_free (struct mvpp2_port * port ,
4396
4392
struct mvpp2_tx_queue * txq ,
@@ -4425,7 +4421,7 @@ static inline struct mvpp2_rx_queue *mvpp2_get_rx_queue(struct mvpp2_port *port,
4425
4421
static inline struct mvpp2_tx_queue * mvpp2_get_tx_queue (struct mvpp2_port * port ,
4426
4422
u32 cause )
4427
4423
{
4428
- int queue = fls (cause >> 16 ) - 1 ;
4424
+ int queue = fls (cause ) - 1 ;
4429
4425
4430
4426
return port -> txqs [queue ];
4431
4427
}
@@ -4452,6 +4448,29 @@ static void mvpp2_txq_done(struct mvpp2_port *port, struct mvpp2_tx_queue *txq,
4452
4448
netif_tx_wake_queue (nq );
4453
4449
}
4454
4450
4451
+ static unsigned int mvpp2_tx_done (struct mvpp2_port * port , u32 cause )
4452
+ {
4453
+ struct mvpp2_tx_queue * txq ;
4454
+ struct mvpp2_txq_pcpu * txq_pcpu ;
4455
+ unsigned int tx_todo = 0 ;
4456
+
4457
+ while (cause ) {
4458
+ txq = mvpp2_get_tx_queue (port , cause );
4459
+ if (!txq )
4460
+ break ;
4461
+
4462
+ txq_pcpu = this_cpu_ptr (txq -> pcpu );
4463
+
4464
+ if (txq_pcpu -> count ) {
4465
+ mvpp2_txq_done (port , txq , txq_pcpu );
4466
+ tx_todo += txq_pcpu -> count ;
4467
+ }
4468
+
4469
+ cause &= ~(1 << txq -> log_id );
4470
+ }
4471
+ return tx_todo ;
4472
+ }
4473
+
4455
4474
/* Rx/Tx queue initialization/cleanup methods */
4456
4475
4457
4476
/* Allocate and initialize descriptors for aggr TXQ */
@@ -4812,7 +4831,6 @@ static int mvpp2_setup_txqs(struct mvpp2_port *port)
4812
4831
goto err_cleanup ;
4813
4832
}
4814
4833
4815
- on_each_cpu (mvpp2_tx_done_pkts_coal_set , port , 1 );
4816
4834
on_each_cpu (mvpp2_txq_sent_counter_clear , port , 1 );
4817
4835
return 0 ;
4818
4836
@@ -4894,6 +4912,49 @@ static void mvpp2_link_event(struct net_device *dev)
4894
4912
}
4895
4913
}
4896
4914
4915
+ static void mvpp2_timer_set (struct mvpp2_port_pcpu * port_pcpu )
4916
+ {
4917
+ ktime_t interval ;
4918
+
4919
+ if (!port_pcpu -> timer_scheduled ) {
4920
+ port_pcpu -> timer_scheduled = true;
4921
+ interval = ktime_set (0 , MVPP2_TXDONE_HRTIMER_PERIOD_NS );
4922
+ hrtimer_start (& port_pcpu -> tx_done_timer , interval ,
4923
+ HRTIMER_MODE_REL_PINNED );
4924
+ }
4925
+ }
4926
+
4927
+ static void mvpp2_tx_proc_cb (unsigned long data )
4928
+ {
4929
+ struct net_device * dev = (struct net_device * )data ;
4930
+ struct mvpp2_port * port = netdev_priv (dev );
4931
+ struct mvpp2_port_pcpu * port_pcpu = this_cpu_ptr (port -> pcpu );
4932
+ unsigned int tx_todo , cause ;
4933
+
4934
+ if (!netif_running (dev ))
4935
+ return ;
4936
+ port_pcpu -> timer_scheduled = false;
4937
+
4938
+ /* Process all the Tx queues */
4939
+ cause = (1 << txq_number ) - 1 ;
4940
+ tx_todo = mvpp2_tx_done (port , cause );
4941
+
4942
+ /* Set the timer in case not all the packets were processed */
4943
+ if (tx_todo )
4944
+ mvpp2_timer_set (port_pcpu );
4945
+ }
4946
+
4947
+ static enum hrtimer_restart mvpp2_hr_timer_cb (struct hrtimer * timer )
4948
+ {
4949
+ struct mvpp2_port_pcpu * port_pcpu = container_of (timer ,
4950
+ struct mvpp2_port_pcpu ,
4951
+ tx_done_timer );
4952
+
4953
+ tasklet_schedule (& port_pcpu -> tx_done_tasklet );
4954
+
4955
+ return HRTIMER_NORESTART ;
4956
+ }
4957
+
4897
4958
/* Main RX/TX processing routines */
4898
4959
4899
4960
/* Display more error info */
@@ -5262,6 +5323,17 @@ static int mvpp2_tx(struct sk_buff *skb, struct net_device *dev)
5262
5323
dev_kfree_skb_any (skb );
5263
5324
}
5264
5325
5326
+ /* Finalize TX processing */
5327
+ if (txq_pcpu -> count >= txq -> done_pkts_coal )
5328
+ mvpp2_txq_done (port , txq , txq_pcpu );
5329
+
5330
+ /* Set the timer in case not all frags were processed */
5331
+ if (txq_pcpu -> count <= frags && txq_pcpu -> count > 0 ) {
5332
+ struct mvpp2_port_pcpu * port_pcpu = this_cpu_ptr (port -> pcpu );
5333
+
5334
+ mvpp2_timer_set (port_pcpu );
5335
+ }
5336
+
5265
5337
return NETDEV_TX_OK ;
5266
5338
}
5267
5339
@@ -5275,10 +5347,11 @@ static inline void mvpp2_cause_error(struct net_device *dev, int cause)
5275
5347
netdev_err (dev , "tx fifo underrun error\n" );
5276
5348
}
5277
5349
5278
- static void mvpp2_txq_done_percpu ( void * arg )
5350
+ static int mvpp2_poll ( struct napi_struct * napi , int budget )
5279
5351
{
5280
- struct mvpp2_port * port = arg ;
5281
- u32 cause_rx_tx , cause_tx , cause_misc ;
5352
+ u32 cause_rx_tx , cause_rx , cause_misc ;
5353
+ int rx_done = 0 ;
5354
+ struct mvpp2_port * port = netdev_priv (napi -> dev );
5282
5355
5283
5356
/* Rx/Tx cause register
5284
5357
*
@@ -5292,7 +5365,7 @@ static void mvpp2_txq_done_percpu(void *arg)
5292
5365
*/
5293
5366
cause_rx_tx = mvpp2_read (port -> priv ,
5294
5367
MVPP2_ISR_RX_TX_CAUSE_REG (port -> id ));
5295
- cause_tx = cause_rx_tx & MVPP2_CAUSE_TXQ_OCCUP_DESC_ALL_MASK ;
5368
+ cause_rx_tx &= ~ MVPP2_CAUSE_TXQ_OCCUP_DESC_ALL_MASK ;
5296
5369
cause_misc = cause_rx_tx & MVPP2_CAUSE_MISC_SUM_MASK ;
5297
5370
5298
5371
if (cause_misc ) {
@@ -5304,26 +5377,6 @@ static void mvpp2_txq_done_percpu(void *arg)
5304
5377
cause_rx_tx & ~MVPP2_CAUSE_MISC_SUM_MASK );
5305
5378
}
5306
5379
5307
- /* Release TX descriptors */
5308
- if (cause_tx ) {
5309
- struct mvpp2_tx_queue * txq = mvpp2_get_tx_queue (port , cause_tx );
5310
- struct mvpp2_txq_pcpu * txq_pcpu = this_cpu_ptr (txq -> pcpu );
5311
-
5312
- if (txq_pcpu -> count )
5313
- mvpp2_txq_done (port , txq , txq_pcpu );
5314
- }
5315
- }
5316
-
5317
- static int mvpp2_poll (struct napi_struct * napi , int budget )
5318
- {
5319
- u32 cause_rx_tx , cause_rx ;
5320
- int rx_done = 0 ;
5321
- struct mvpp2_port * port = netdev_priv (napi -> dev );
5322
-
5323
- on_each_cpu (mvpp2_txq_done_percpu , port , 1 );
5324
-
5325
- cause_rx_tx = mvpp2_read (port -> priv ,
5326
- MVPP2_ISR_RX_TX_CAUSE_REG (port -> id ));
5327
5380
cause_rx = cause_rx_tx & MVPP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK ;
5328
5381
5329
5382
/* Process RX packets */
@@ -5568,6 +5621,8 @@ static int mvpp2_open(struct net_device *dev)
5568
5621
static int mvpp2_stop (struct net_device * dev )
5569
5622
{
5570
5623
struct mvpp2_port * port = netdev_priv (dev );
5624
+ struct mvpp2_port_pcpu * port_pcpu ;
5625
+ int cpu ;
5571
5626
5572
5627
mvpp2_stop_dev (port );
5573
5628
mvpp2_phy_disconnect (port );
@@ -5576,6 +5631,13 @@ static int mvpp2_stop(struct net_device *dev)
5576
5631
on_each_cpu (mvpp2_interrupts_mask , port , 1 );
5577
5632
5578
5633
free_irq (port -> irq , port );
5634
+ for_each_present_cpu (cpu ) {
5635
+ port_pcpu = per_cpu_ptr (port -> pcpu , cpu );
5636
+
5637
+ hrtimer_cancel (& port_pcpu -> tx_done_timer );
5638
+ port_pcpu -> timer_scheduled = false;
5639
+ tasklet_kill (& port_pcpu -> tx_done_tasklet );
5640
+ }
5579
5641
mvpp2_cleanup_rxqs (port );
5580
5642
mvpp2_cleanup_txqs (port );
5581
5643
@@ -5791,7 +5853,6 @@ static int mvpp2_ethtool_set_coalesce(struct net_device *dev,
5791
5853
txq -> done_pkts_coal = c -> tx_max_coalesced_frames ;
5792
5854
}
5793
5855
5794
- on_each_cpu (mvpp2_tx_done_pkts_coal_set , port , 1 );
5795
5856
return 0 ;
5796
5857
}
5797
5858
@@ -6042,6 +6103,7 @@ static int mvpp2_port_probe(struct platform_device *pdev,
6042
6103
{
6043
6104
struct device_node * phy_node ;
6044
6105
struct mvpp2_port * port ;
6106
+ struct mvpp2_port_pcpu * port_pcpu ;
6045
6107
struct net_device * dev ;
6046
6108
struct resource * res ;
6047
6109
const char * dt_mac_addr ;
@@ -6051,7 +6113,7 @@ static int mvpp2_port_probe(struct platform_device *pdev,
6051
6113
int features ;
6052
6114
int phy_mode ;
6053
6115
int priv_common_regs_num = 2 ;
6054
- int err , i ;
6116
+ int err , i , cpu ;
6055
6117
6056
6118
dev = alloc_etherdev_mqs (sizeof (struct mvpp2_port ), txq_number ,
6057
6119
rxq_number );
@@ -6142,6 +6204,24 @@ static int mvpp2_port_probe(struct platform_device *pdev,
6142
6204
}
6143
6205
mvpp2_port_power_up (port );
6144
6206
6207
+ port -> pcpu = alloc_percpu (struct mvpp2_port_pcpu );
6208
+ if (!port -> pcpu ) {
6209
+ err = - ENOMEM ;
6210
+ goto err_free_txq_pcpu ;
6211
+ }
6212
+
6213
+ for_each_present_cpu (cpu ) {
6214
+ port_pcpu = per_cpu_ptr (port -> pcpu , cpu );
6215
+
6216
+ hrtimer_init (& port_pcpu -> tx_done_timer , CLOCK_MONOTONIC ,
6217
+ HRTIMER_MODE_REL_PINNED );
6218
+ port_pcpu -> tx_done_timer .function = mvpp2_hr_timer_cb ;
6219
+ port_pcpu -> timer_scheduled = false;
6220
+
6221
+ tasklet_init (& port_pcpu -> tx_done_tasklet , mvpp2_tx_proc_cb ,
6222
+ (unsigned long )dev );
6223
+ }
6224
+
6145
6225
netif_napi_add (dev , & port -> napi , mvpp2_poll , NAPI_POLL_WEIGHT );
6146
6226
features = NETIF_F_SG | NETIF_F_IP_CSUM ;
6147
6227
dev -> features = features | NETIF_F_RXCSUM ;
@@ -6151,7 +6231,7 @@ static int mvpp2_port_probe(struct platform_device *pdev,
6151
6231
err = register_netdev (dev );
6152
6232
if (err < 0 ) {
6153
6233
dev_err (& pdev -> dev , "failed to register netdev\n" );
6154
- goto err_free_txq_pcpu ;
6234
+ goto err_free_port_pcpu ;
6155
6235
}
6156
6236
netdev_info (dev , "Using %s mac address %pM\n" , mac_from , dev -> dev_addr );
6157
6237
@@ -6160,6 +6240,8 @@ static int mvpp2_port_probe(struct platform_device *pdev,
6160
6240
priv -> port_list [id ] = port ;
6161
6241
return 0 ;
6162
6242
6243
+ err_free_port_pcpu :
6244
+ free_percpu (port -> pcpu );
6163
6245
err_free_txq_pcpu :
6164
6246
for (i = 0 ; i < txq_number ; i ++ )
6165
6247
free_percpu (port -> txqs [i ]-> pcpu );
@@ -6178,6 +6260,7 @@ static void mvpp2_port_remove(struct mvpp2_port *port)
6178
6260
int i ;
6179
6261
6180
6262
unregister_netdev (port -> dev );
6263
+ free_percpu (port -> pcpu );
6181
6264
free_percpu (port -> stats );
6182
6265
for (i = 0 ; i < txq_number ; i ++ )
6183
6266
free_percpu (port -> txqs [i ]-> pcpu );
0 commit comments