@@ -98,11 +98,20 @@ void prueth_xmit_free(struct prueth_tx_chn *tx_chn,
98
98
{
99
99
struct cppi5_host_desc_t * first_desc , * next_desc ;
100
100
dma_addr_t buf_dma , next_desc_dma ;
101
+ struct prueth_swdata * swdata ;
102
+ struct page * page ;
101
103
u32 buf_dma_len ;
102
104
103
105
first_desc = desc ;
104
106
next_desc = first_desc ;
105
107
108
+ swdata = cppi5_hdesc_get_swdata (desc );
109
+ if (swdata -> type == PRUETH_SWDATA_PAGE ) {
110
+ page = swdata -> data .page ;
111
+ page_pool_recycle_direct (page -> pp , swdata -> data .page );
112
+ goto free_desc ;
113
+ }
114
+
106
115
cppi5_hdesc_get_obuf (first_desc , & buf_dma , & buf_dma_len );
107
116
k3_udma_glue_tx_cppi5_to_dma_addr (tx_chn -> tx_chn , & buf_dma );
108
117
@@ -126,6 +135,7 @@ void prueth_xmit_free(struct prueth_tx_chn *tx_chn,
126
135
k3_cppi_desc_pool_free (tx_chn -> desc_pool , next_desc );
127
136
}
128
137
138
+ free_desc :
129
139
k3_cppi_desc_pool_free (tx_chn -> desc_pool , first_desc );
130
140
}
131
141
EXPORT_SYMBOL_GPL (prueth_xmit_free );
@@ -139,6 +149,7 @@ int emac_tx_complete_packets(struct prueth_emac *emac, int chn,
139
149
struct prueth_swdata * swdata ;
140
150
struct prueth_tx_chn * tx_chn ;
141
151
unsigned int total_bytes = 0 ;
152
+ struct xdp_frame * xdpf ;
142
153
struct sk_buff * skb ;
143
154
dma_addr_t desc_dma ;
144
155
int res , num_tx = 0 ;
@@ -161,16 +172,28 @@ int emac_tx_complete_packets(struct prueth_emac *emac, int chn,
161
172
desc_tx = k3_cppi_desc_pool_dma2virt (tx_chn -> desc_pool ,
162
173
desc_dma );
163
174
swdata = cppi5_hdesc_get_swdata (desc_tx );
164
- prueth_xmit_free (tx_chn , desc_tx );
165
- if (swdata -> type != PRUETH_SWDATA_SKB )
175
+
176
+ switch (swdata -> type ) {
177
+ case PRUETH_SWDATA_SKB :
178
+ skb = swdata -> data .skb ;
179
+ dev_sw_netstats_tx_add (skb -> dev , 1 , skb -> len );
180
+ total_bytes += skb -> len ;
181
+ napi_consume_skb (skb , budget );
182
+ break ;
183
+ case PRUETH_SWDATA_XDPF :
184
+ xdpf = swdata -> data .xdpf ;
185
+ dev_sw_netstats_tx_add (ndev , 1 , xdpf -> len );
186
+ total_bytes += xdpf -> len ;
187
+ xdp_return_frame (xdpf );
188
+ break ;
189
+ default :
190
+ netdev_err (ndev , "tx_complete: invalid swdata type %d\n" , swdata -> type );
191
+ prueth_xmit_free (tx_chn , desc_tx );
192
+ ndev -> stats .tx_dropped ++ ;
166
193
continue ;
194
+ }
167
195
168
- skb = swdata -> data .skb ;
169
- ndev = skb -> dev ;
170
- ndev -> stats .tx_packets ++ ;
171
- ndev -> stats .tx_bytes += skb -> len ;
172
- total_bytes += skb -> len ;
173
- napi_consume_skb (skb , budget );
196
+ prueth_xmit_free (tx_chn , desc_tx );
174
197
num_tx ++ ;
175
198
}
176
199
@@ -529,7 +552,153 @@ void emac_rx_timestamp(struct prueth_emac *emac,
529
552
ssh -> hwtstamp = ns_to_ktime (ns );
530
553
}
531
554
532
- static int emac_rx_packet (struct prueth_emac * emac , u32 flow_id )
555
+ /**
556
+ * emac_xmit_xdp_frame - transmits an XDP frame
557
+ * @emac: emac device
558
+ * @xdpf: data to transmit
559
+ * @page: page from page pool if already DMA mapped
560
+ * @q_idx: queue id
561
+ *
562
+ * Return: XDP state
563
+ */
564
+ u32 emac_xmit_xdp_frame (struct prueth_emac * emac ,
565
+ struct xdp_frame * xdpf ,
566
+ struct page * page ,
567
+ unsigned int q_idx )
568
+ {
569
+ struct cppi5_host_desc_t * first_desc ;
570
+ struct net_device * ndev = emac -> ndev ;
571
+ struct prueth_tx_chn * tx_chn ;
572
+ dma_addr_t desc_dma , buf_dma ;
573
+ struct prueth_swdata * swdata ;
574
+ u32 * epib ;
575
+ int ret ;
576
+
577
+ if (q_idx >= PRUETH_MAX_TX_QUEUES ) {
578
+ netdev_err (ndev , "xdp tx: invalid q_id %d\n" , q_idx );
579
+ return ICSSG_XDP_CONSUMED ; /* drop */
580
+ }
581
+
582
+ tx_chn = & emac -> tx_chns [q_idx ];
583
+
584
+ first_desc = k3_cppi_desc_pool_alloc (tx_chn -> desc_pool );
585
+ if (!first_desc ) {
586
+ netdev_dbg (ndev , "xdp tx: failed to allocate descriptor\n" );
587
+ goto drop_free_descs ; /* drop */
588
+ }
589
+
590
+ if (page ) { /* already DMA mapped by page_pool */
591
+ buf_dma = page_pool_get_dma_addr (page );
592
+ buf_dma += xdpf -> headroom + sizeof (struct xdp_frame );
593
+ } else { /* Map the linear buffer */
594
+ buf_dma = dma_map_single (tx_chn -> dma_dev , xdpf -> data , xdpf -> len , DMA_TO_DEVICE );
595
+ if (dma_mapping_error (tx_chn -> dma_dev , buf_dma )) {
596
+ netdev_err (ndev , "xdp tx: failed to map data buffer\n" );
597
+ goto drop_free_descs ; /* drop */
598
+ }
599
+ }
600
+
601
+ cppi5_hdesc_init (first_desc , CPPI5_INFO0_HDESC_EPIB_PRESENT ,
602
+ PRUETH_NAV_PS_DATA_SIZE );
603
+ cppi5_hdesc_set_pkttype (first_desc , 0 );
604
+ epib = first_desc -> epib ;
605
+ epib [0 ] = 0 ;
606
+ epib [1 ] = 0 ;
607
+
608
+ /* set dst tag to indicate internal qid at the firmware which is at
609
+ * bit8..bit15. bit0..bit7 indicates port num for directed
610
+ * packets in case of switch mode operation
611
+ */
612
+ cppi5_desc_set_tags_ids (& first_desc -> hdr , 0 , (emac -> port_id | (q_idx << 8 )));
613
+ k3_udma_glue_tx_dma_to_cppi5_addr (tx_chn -> tx_chn , & buf_dma );
614
+ cppi5_hdesc_attach_buf (first_desc , buf_dma , xdpf -> len , buf_dma , xdpf -> len );
615
+ swdata = cppi5_hdesc_get_swdata (first_desc );
616
+ if (page ) {
617
+ swdata -> type = PRUETH_SWDATA_PAGE ;
618
+ swdata -> data .page = page ;
619
+ } else {
620
+ swdata -> type = PRUETH_SWDATA_XDPF ;
621
+ swdata -> data .xdpf = xdpf ;
622
+ }
623
+
624
+ cppi5_hdesc_set_pktlen (first_desc , xdpf -> len );
625
+ desc_dma = k3_cppi_desc_pool_virt2dma (tx_chn -> desc_pool , first_desc );
626
+
627
+ ret = k3_udma_glue_push_tx_chn (tx_chn -> tx_chn , first_desc , desc_dma );
628
+ if (ret ) {
629
+ netdev_err (ndev , "xdp tx: push failed: %d\n" , ret );
630
+ goto drop_free_descs ;
631
+ }
632
+
633
+ return ICSSG_XDP_TX ;
634
+
635
+ drop_free_descs :
636
+ prueth_xmit_free (tx_chn , first_desc );
637
+ return ICSSG_XDP_CONSUMED ;
638
+ }
639
+ EXPORT_SYMBOL_GPL (emac_xmit_xdp_frame );
640
+
641
+ /**
642
+ * emac_run_xdp - run an XDP program
643
+ * @emac: emac device
644
+ * @xdp: XDP buffer containing the frame
645
+ * @page: page with RX data if already DMA mapped
646
+ * @len: Rx descriptor packet length
647
+ *
648
+ * Return: XDP state
649
+ */
650
+ static u32 emac_run_xdp (struct prueth_emac * emac , struct xdp_buff * xdp ,
651
+ struct page * page , u32 * len )
652
+ {
653
+ struct net_device * ndev = emac -> ndev ;
654
+ struct bpf_prog * xdp_prog ;
655
+ struct xdp_frame * xdpf ;
656
+ u32 pkt_len = * len ;
657
+ u32 act , result ;
658
+ int q_idx , err ;
659
+
660
+ xdp_prog = READ_ONCE (emac -> xdp_prog );
661
+ act = bpf_prog_run_xdp (xdp_prog , xdp );
662
+ switch (act ) {
663
+ case XDP_PASS :
664
+ return ICSSG_XDP_PASS ;
665
+ case XDP_TX :
666
+ /* Send packet to TX ring for immediate transmission */
667
+ xdpf = xdp_convert_buff_to_frame (xdp );
668
+ if (unlikely (!xdpf )) {
669
+ ndev -> stats .tx_dropped ++ ;
670
+ goto drop ;
671
+ }
672
+
673
+ q_idx = smp_processor_id () % emac -> tx_ch_num ;
674
+ result = emac_xmit_xdp_frame (emac , xdpf , page , q_idx );
675
+ if (result == ICSSG_XDP_CONSUMED )
676
+ goto drop ;
677
+
678
+ dev_sw_netstats_rx_add (ndev , xdpf -> len );
679
+ return result ;
680
+ case XDP_REDIRECT :
681
+ err = xdp_do_redirect (emac -> ndev , xdp , xdp_prog );
682
+ if (err )
683
+ goto drop ;
684
+
685
+ dev_sw_netstats_rx_add (ndev , pkt_len );
686
+ return ICSSG_XDP_REDIR ;
687
+ default :
688
+ bpf_warn_invalid_xdp_action (emac -> ndev , xdp_prog , act );
689
+ fallthrough ;
690
+ case XDP_ABORTED :
691
+ drop :
692
+ trace_xdp_exception (emac -> ndev , xdp_prog , act );
693
+ fallthrough ; /* handle aborts by dropping packet */
694
+ case XDP_DROP :
695
+ ndev -> stats .rx_dropped ++ ;
696
+ page_pool_recycle_direct (emac -> rx_chns .pg_pool , page );
697
+ return ICSSG_XDP_CONSUMED ;
698
+ }
699
+ }
700
+
701
+ static int emac_rx_packet (struct prueth_emac * emac , u32 flow_id , u32 * xdp_state )
533
702
{
534
703
struct prueth_rx_chn * rx_chn = & emac -> rx_chns ;
535
704
u32 buf_dma_len , pkt_len , port_id = 0 ;
@@ -540,10 +709,12 @@ static int emac_rx_packet(struct prueth_emac *emac, u32 flow_id)
540
709
struct page * page , * new_page ;
541
710
struct page_pool * pool ;
542
711
struct sk_buff * skb ;
712
+ struct xdp_buff xdp ;
543
713
u32 * psdata ;
544
714
void * pa ;
545
715
int ret ;
546
716
717
+ * xdp_state = 0 ;
547
718
pool = rx_chn -> pg_pool ;
548
719
ret = k3_udma_glue_pop_rx_chn (rx_chn -> rx_chn , flow_id , & desc_dma );
549
720
if (ret ) {
@@ -584,9 +755,21 @@ static int emac_rx_packet(struct prueth_emac *emac, u32 flow_id)
584
755
goto requeue ;
585
756
}
586
757
587
- /* prepare skb and send to n/w stack */
588
758
pa = page_address (page );
589
- skb = napi_build_skb (pa , PAGE_SIZE );
759
+ if (emac -> xdp_prog ) {
760
+ xdp_init_buff (& xdp , PAGE_SIZE , & rx_chn -> xdp_rxq );
761
+ xdp_prepare_buff (& xdp , pa , PRUETH_HEADROOM , pkt_len , false);
762
+
763
+ * xdp_state = emac_run_xdp (emac , & xdp , page , & pkt_len );
764
+ if (* xdp_state == ICSSG_XDP_PASS )
765
+ skb = xdp_build_skb_from_buff (& xdp );
766
+ else
767
+ goto requeue ;
768
+ } else {
769
+ /* prepare skb and send to n/w stack */
770
+ skb = napi_build_skb (pa , PAGE_SIZE );
771
+ }
772
+
590
773
if (!skb ) {
591
774
ndev -> stats .rx_dropped ++ ;
592
775
page_pool_recycle_direct (pool , page );
@@ -849,13 +1032,23 @@ static void prueth_tx_cleanup(void *data, dma_addr_t desc_dma)
849
1032
struct prueth_tx_chn * tx_chn = data ;
850
1033
struct cppi5_host_desc_t * desc_tx ;
851
1034
struct prueth_swdata * swdata ;
1035
+ struct xdp_frame * xdpf ;
852
1036
struct sk_buff * skb ;
853
1037
854
1038
desc_tx = k3_cppi_desc_pool_dma2virt (tx_chn -> desc_pool , desc_dma );
855
1039
swdata = cppi5_hdesc_get_swdata (desc_tx );
856
- if (swdata -> type == PRUETH_SWDATA_SKB ) {
1040
+
1041
+ switch (swdata -> type ) {
1042
+ case PRUETH_SWDATA_SKB :
857
1043
skb = swdata -> data .skb ;
858
1044
dev_kfree_skb_any (skb );
1045
+ break ;
1046
+ case PRUETH_SWDATA_XDPF :
1047
+ xdpf = swdata -> data .xdpf ;
1048
+ xdp_return_frame (xdpf );
1049
+ break ;
1050
+ default :
1051
+ break ;
859
1052
}
860
1053
861
1054
prueth_xmit_free (tx_chn , desc_tx );
@@ -892,15 +1085,18 @@ int icssg_napi_rx_poll(struct napi_struct *napi_rx, int budget)
892
1085
PRUETH_RX_FLOW_DATA_SR1 : PRUETH_RX_FLOW_DATA ;
893
1086
int flow = emac -> is_sr1 ?
894
1087
PRUETH_MAX_RX_FLOWS_SR1 : PRUETH_MAX_RX_FLOWS ;
1088
+ int xdp_state_or = 0 ;
895
1089
int num_rx = 0 ;
896
1090
int cur_budget ;
1091
+ u32 xdp_state ;
897
1092
int ret ;
898
1093
899
1094
while (flow -- ) {
900
1095
cur_budget = budget - num_rx ;
901
1096
902
1097
while (cur_budget -- ) {
903
- ret = emac_rx_packet (emac , flow );
1098
+ ret = emac_rx_packet (emac , flow , & xdp_state );
1099
+ xdp_state_or |= xdp_state ;
904
1100
if (ret )
905
1101
break ;
906
1102
num_rx ++ ;
@@ -910,6 +1106,9 @@ int icssg_napi_rx_poll(struct napi_struct *napi_rx, int budget)
910
1106
break ;
911
1107
}
912
1108
1109
+ if (xdp_state_or & ICSSG_XDP_REDIR )
1110
+ xdp_do_flush ();
1111
+
913
1112
if (num_rx < budget && napi_complete_done (napi_rx , num_rx )) {
914
1113
if (unlikely (emac -> rx_pace_timeout_ns )) {
915
1114
hrtimer_start (& emac -> rx_hrtimer ,
0 commit comments