Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright 2021-2024 NXP
3 : : */
4 : :
5 : : #include <rte_mbuf.h>
6 : : #include <rte_io.h>
7 : : #include <ethdev_driver.h>
8 : : #include "enet_regs.h"
9 : : #include "enet_ethdev.h"
10 : : #include "enet_pmd_logs.h"
11 : :
12 : : /* This function does enetfec_rx_queue processing. Dequeue packet from Rx queue
13 : : * When update through the ring, just set the empty indicator.
14 : : */
15 : : uint16_t
16 : 0 : enetfec_recv_pkts(void *rxq1, struct rte_mbuf **rx_pkts,
17 : : uint16_t nb_pkts)
18 : : {
19 : : struct rte_mempool *pool;
20 : : struct rte_mbuf *mbuf, *new_mbuf = NULL;
21 : : unsigned short status;
22 : : unsigned short pkt_len;
23 : : int pkt_received = 0, index = 0;
24 : : struct rte_ether_hdr *eth;
25 : : void *data, *mbuf_data;
26 : : struct bufdesc *bdp;
27 : : uint16_t vlan_tag;
28 : : struct bufdesc_ex *ebdp = NULL;
29 : : bool vlan_packet_rcvd = false;
30 : : struct enetfec_priv_rx_q *rxq = (struct enetfec_priv_rx_q *)rxq1;
31 : 0 : struct rte_eth_stats *stats = &rxq->fep->stats;
32 : 0 : struct rte_eth_conf *eth_conf = &rxq->fep->dev->data->dev_conf;
33 : 0 : uint64_t rx_offloads = eth_conf->rxmode.offloads;
34 : 0 : pool = rxq->pool;
35 : 0 : bdp = rxq->bd.cur;
36 : :
37 : : /* Process the incoming packet */
38 : : status = rte_le_to_cpu_16(rte_read16(&bdp->bd_sc));
39 [ # # ]: 0 : while ((status & RX_BD_EMPTY) == 0) {
40 [ # # ]: 0 : if (pkt_received >= nb_pkts)
41 : : break;
42 : :
43 : : /* Check for errors. */
44 : 0 : status ^= RX_BD_LAST;
45 [ # # ]: 0 : if (status & (RX_BD_LG | RX_BD_SH | RX_BD_NO |
46 : : RX_BD_CR | RX_BD_OV | RX_BD_LAST |
47 : : RX_BD_TR)) {
48 : 0 : stats->ierrors++;
49 [ # # ]: 0 : if (status & RX_BD_OV) {
50 : : /* FIFO overrun */
51 : : /* enet_dump_rx(rxq); */
52 : : ENETFEC_DP_LOG(DEBUG, "rx_fifo_error");
53 : 0 : goto rx_processing_done;
54 : : }
55 : : if (status & (RX_BD_LG | RX_BD_SH
56 : : | RX_BD_LAST)) {
57 : : /* Frame too long or too short. */
58 : : ENETFEC_DP_LOG(DEBUG, "rx_length_error");
59 : : if (status & RX_BD_LAST)
60 : : ENETFEC_DP_LOG(DEBUG, "rcv is not +last");
61 : : }
62 : : if (status & RX_BD_CR) { /* CRC Error */
63 : : ENETFEC_DP_LOG(DEBUG, "rx_crc_errors");
64 : : }
65 : : /* Report late collisions as a frame error. */
66 : : if (status & (RX_BD_NO | RX_BD_TR))
67 : : ENETFEC_DP_LOG(DEBUG, "rx_frame_error");
68 : 0 : goto rx_processing_done;
69 : : }
70 : :
71 : 0 : new_mbuf = rte_pktmbuf_alloc(pool);
72 [ # # ]: 0 : if (unlikely(new_mbuf == NULL)) {
73 : 0 : stats->rx_nombuf++;
74 : 0 : break;
75 : : }
76 : :
77 : : /* Process the incoming frame. */
78 : 0 : stats->ipackets++;
79 : : pkt_len = rte_le_to_cpu_16(rte_read16(&bdp->bd_datlen));
80 : 0 : stats->ibytes += pkt_len;
81 : :
82 : : /* shows data with respect to the data_off field. */
83 : : index = enet_get_bd_index(bdp, &rxq->bd);
84 : 0 : mbuf = rxq->rx_mbuf[index];
85 : :
86 : 0 : data = rte_pktmbuf_mtod(mbuf, uint8_t *);
87 : : mbuf_data = data;
88 : : rte_prefetch0(data);
89 : : rte_pktmbuf_append((struct rte_mbuf *)mbuf,
90 : 0 : pkt_len - 4);
91 : :
92 [ # # ]: 0 : if (rxq->fep->quirks & QUIRK_RACC)
93 : : data = rte_pktmbuf_adj(mbuf, 2);
94 : :
95 : 0 : rx_pkts[pkt_received] = mbuf;
96 : :
97 : : /* Assuming Ethernet packets, doing software packet type parsing.
98 : : * To be replaced by HW packet parsing
99 : : */
100 : 0 : eth = rte_pktmbuf_mtod(mbuf, struct rte_ether_hdr *);
101 : 0 : mbuf->packet_type = RTE_PTYPE_L2_ETHER;
102 [ # # # # ]: 0 : if (rte_be_to_cpu_16(eth->ether_type) == RTE_ETHER_TYPE_IPV4)
103 : 0 : mbuf->packet_type |= RTE_PTYPE_L3_IPV4;
104 [ # # # # ]: 0 : if (rte_be_to_cpu_16(eth->ether_type) == RTE_ETHER_TYPE_IPV6)
105 : 0 : mbuf->packet_type |= RTE_PTYPE_L3_IPV6;
106 : 0 : pkt_received++;
107 : :
108 : : /* Extract the enhanced buffer descriptor */
109 : : ebdp = NULL;
110 [ # # ]: 0 : if (rxq->fep->bufdesc_ex)
111 : : ebdp = (struct bufdesc_ex *)bdp;
112 : :
113 : : /* If this is a VLAN packet remove the VLAN Tag */
114 : : vlan_packet_rcvd = false;
115 [ # # # # ]: 0 : if ((rx_offloads & RTE_ETH_RX_OFFLOAD_VLAN) &&
116 : 0 : rxq->fep->bufdesc_ex &&
117 [ # # ]: 0 : (rte_read32(&ebdp->bd_esc) &
118 : : rte_cpu_to_le_32(BD_ENETFEC_RX_VLAN))) {
119 : : /* Push and remove the vlan tag */
120 : : struct rte_vlan_hdr *vlan_header =
121 : : (struct rte_vlan_hdr *)
122 : : ((uint8_t *)data + ETH_HLEN);
123 [ # # ]: 0 : vlan_tag = rte_be_to_cpu_16(vlan_header->vlan_tci);
124 : :
125 : : vlan_packet_rcvd = true;
126 [ # # ]: 0 : memmove((uint8_t *)mbuf_data + RTE_VLAN_HLEN,
127 : : data, RTE_ETHER_ADDR_LEN * 2);
128 : : rte_pktmbuf_adj(mbuf, RTE_VLAN_HLEN);
129 : : }
130 : :
131 [ # # ]: 0 : if (rxq->fep->bufdesc_ex &&
132 [ # # ]: 0 : (rxq->fep->flag_csum & RX_FLAG_CSUM_EN)) {
133 [ # # ]: 0 : if ((rte_read32(&ebdp->bd_esc) &
134 : : rte_cpu_to_le_32(RX_FLAG_CSUM_ERR)) == 0) {
135 : : /* No checksum error - checksum is good */
136 : 0 : mbuf->ol_flags = RTE_MBUF_F_RX_IP_CKSUM_GOOD;
137 : : } else {
138 : : /* Checksum error detected */
139 : 0 : mbuf->ol_flags = RTE_MBUF_F_RX_IP_CKSUM_BAD;
140 : : }
141 : : }
142 : :
143 : : /* Handle received VLAN packets */
144 [ # # ]: 0 : if (vlan_packet_rcvd) {
145 : 0 : mbuf->vlan_tci = vlan_tag;
146 : 0 : mbuf->ol_flags |= RTE_MBUF_F_RX_VLAN_STRIPPED
147 : : | RTE_MBUF_F_RX_VLAN;
148 : : }
149 : :
150 : 0 : rxq->rx_mbuf[index] = new_mbuf;
151 : 0 : rte_write32(rte_cpu_to_le_32(rte_pktmbuf_iova(new_mbuf)),
152 : : &bdp->bd_bufaddr);
153 : 0 : rx_processing_done:
154 : : /* when rx_processing_done clear the status flags
155 : : * for this buffer
156 : : */
157 : 0 : status &= ~RX_BD_STATS;
158 : :
159 : : /* Mark the buffer empty */
160 : 0 : status |= RX_BD_EMPTY;
161 : :
162 [ # # ]: 0 : if (rxq->fep->bufdesc_ex) {
163 : : struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp;
164 : : rte_write32(rte_cpu_to_le_32(RX_BD_INT),
165 : : &ebdp->bd_esc);
166 : : rte_write32(0, &ebdp->bd_prot);
167 : : rte_write32(0, &ebdp->bd_bdu);
168 : : }
169 : :
170 : : /* Make sure the updates to rest of the descriptor are
171 : : * performed before transferring ownership.
172 : : */
173 : : rte_wmb();
174 : : rte_write16(rte_cpu_to_le_16(status), &bdp->bd_sc);
175 : :
176 : : /* Update BD pointer to next entry */
177 : : bdp = enet_get_nextdesc(bdp, &rxq->bd);
178 : :
179 : : /* Doing this here will keep the FEC running while we process
180 : : * incoming frames.
181 : : */
182 : 0 : rte_write32(0, rxq->bd.active_reg_desc);
183 : : status = rte_le_to_cpu_16(rte_read16(&bdp->bd_sc));
184 : : }
185 : 0 : rxq->bd.cur = bdp;
186 : 0 : return pkt_received;
187 : : }
188 : :
189 : : uint16_t
190 : 0 : enetfec_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
191 : : {
192 : : struct enetfec_priv_tx_q *txq =
193 : : (struct enetfec_priv_tx_q *)tx_queue;
194 : 0 : struct rte_eth_stats *stats = &txq->fep->stats;
195 : : struct bufdesc *bdp, *last_bdp;
196 : : struct rte_mbuf *mbuf;
197 : : unsigned short status;
198 : : unsigned short buflen;
199 : : unsigned int index, estatus = 0;
200 : : unsigned int i, pkt_transmitted = 0;
201 : : uint8_t *data;
202 : : int tx_st = 1;
203 : :
204 : 0 : while (tx_st) {
205 [ # # ]: 0 : if (pkt_transmitted >= nb_pkts) {
206 : : tx_st = 0;
207 : : break;
208 : : }
209 : :
210 : 0 : mbuf = *(tx_pkts);
211 [ # # ]: 0 : if (mbuf->nb_segs > 1) {
212 : : ENETFEC_DP_LOG(DEBUG, "SG not supported");
213 : 0 : return pkt_transmitted;
214 : : }
215 : :
216 : 0 : tx_pkts++;
217 : 0 : bdp = txq->bd.cur;
218 : :
219 : : /* First clean the ring */
220 : 0 : index = enet_get_bd_index(bdp, &txq->bd);
221 : : status = rte_le_to_cpu_16(rte_read16(&bdp->bd_sc));
222 : :
223 [ # # ]: 0 : if (status & TX_BD_READY) {
224 : 0 : stats->oerrors++;
225 : 0 : break;
226 : : }
227 [ # # ]: 0 : if (txq->tx_mbuf[index]) {
228 : 0 : rte_pktmbuf_free(txq->tx_mbuf[index]);
229 : 0 : txq->tx_mbuf[index] = NULL;
230 : : }
231 : :
232 : : /* Fill in a Tx ring entry */
233 : : last_bdp = bdp;
234 : 0 : status &= ~TX_BD_STATS;
235 : :
236 : : /* Set buffer length and buffer pointer */
237 : 0 : buflen = rte_pktmbuf_pkt_len(mbuf);
238 : 0 : stats->opackets++;
239 : 0 : stats->obytes += buflen;
240 : :
241 : : status |= (TX_BD_LAST);
242 : 0 : data = rte_pktmbuf_mtod(mbuf, void *);
243 [ # # ]: 0 : for (i = 0; i <= buflen; i += RTE_CACHE_LINE_SIZE)
244 : : dccivac(data + i);
245 : :
246 : 0 : rte_write32(rte_cpu_to_le_32(rte_pktmbuf_iova(mbuf)),
247 : : &bdp->bd_bufaddr);
248 : : rte_write16(rte_cpu_to_le_16(buflen), &bdp->bd_datlen);
249 : :
250 [ # # ]: 0 : if (txq->fep->bufdesc_ex) {
251 : : struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp;
252 : :
253 [ # # ]: 0 : if (mbuf->ol_flags & (RTE_MBUF_F_TX_IP_CKSUM | RTE_MBUF_F_TX_TCP_CKSUM |
254 : : RTE_MBUF_F_TX_UDP_CKSUM | RTE_MBUF_F_TX_SCTP_CKSUM))
255 : : estatus |= TX_BD_PINS | TX_BD_IINS;
256 : :
257 : : rte_write32(0, &ebdp->bd_bdu);
258 : : rte_write32(rte_cpu_to_le_32(estatus),
259 : : &ebdp->bd_esc);
260 : : }
261 : :
262 : 0 : index = enet_get_bd_index(last_bdp, &txq->bd);
263 : : /* Save mbuf pointer */
264 : 0 : txq->tx_mbuf[index] = mbuf;
265 : :
266 : : /* Make sure the updates to rest of the descriptor are performed
267 : : * before transferring ownership.
268 : : */
269 : 0 : status |= (TX_BD_READY | TX_BD_TC);
270 : : rte_wmb();
271 : : rte_write16(rte_cpu_to_le_16(status), &bdp->bd_sc);
272 : :
273 : : /* Trigger transmission start */
274 : 0 : rte_write32(0, txq->bd.active_reg_desc);
275 [ # # ]: 0 : pkt_transmitted++;
276 : :
277 : : /* If this was the last BD in the ring, start at the
278 : : * beginning again.
279 : : */
280 : : bdp = enet_get_nextdesc(last_bdp, &txq->bd);
281 : :
282 : : /* Make sure the update to bdp and tx_skbuff are performed
283 : : * before txq->bd.cur.
284 : : */
285 : 0 : txq->bd.cur = bdp;
286 : : }
287 : 0 : return pkt_transmitted;
288 : : }
|