first public release
[dpdk.git] / app / test-pmd / ieee1588fwd.c
1 /*-
2  *   BSD LICENSE
3  * 
4  *   Copyright(c) 2010-2012 Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  * 
7  *   Redistribution and use in source and binary forms, with or without 
8  *   modification, are permitted provided that the following conditions 
9  *   are met:
10  * 
11  *     * Redistributions of source code must retain the above copyright 
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright 
14  *       notice, this list of conditions and the following disclaimer in 
15  *       the documentation and/or other materials provided with the 
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its 
18  *       contributors may be used to endorse or promote products derived 
19  *       from this software without specific prior written permission.
20  * 
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  * 
33  *  version: DPDK.L.1.2.3-3
34  */
35
36 #include <stdarg.h>
37 #include <stdio.h>
38 #include <string.h>
39 #include <errno.h>
40 #include <stdint.h>
41 #include <unistd.h>
42 #include <inttypes.h>
43
44 #include <sys/queue.h>
45 #include <sys/stat.h>
46
47 #include <rte_common.h>
48 #include <rte_byteorder.h>
49 #include <rte_log.h>
50 #include <rte_debug.h>
51 #include <rte_cycles.h>
52 #include <rte_memory.h>
53 #include <rte_memzone.h>
54 #include <rte_launch.h>
55 #include <rte_tailq.h>
56 #include <rte_eal.h>
57 #include <rte_per_lcore.h>
58 #include <rte_lcore.h>
59 #include <rte_atomic.h>
60 #include <rte_branch_prediction.h>
61 #include <rte_ring.h>
62 #include <rte_memory.h>
63 #include <rte_mempool.h>
64 #include <rte_mbuf.h>
65 #include <rte_interrupts.h>
66 #include <rte_pci.h>
67 #include <rte_ether.h>
68 #include <rte_ethdev.h>
69 #include <rte_string_fns.h>
70
71 #include "testpmd.h"
72
73 /**
74  * The structure of a PTP V2 packet.
75  *
76  * Only the minimum fields used by the ieee1588 test are represented.
77  */
78 struct ptpv2_msg {
79         uint8_t msg_id;
80         uint8_t version; /**< must be 0x02 */
81         uint8_t unused[34];
82 };
83 #define PTP_SYNC_MESSAGE                0x0
84 #define PTP_DELAY_REQ_MESSAGE           0x1
85 #define PTP_PATH_DELAY_REQ_MESSAGE      0x2
86 #define PTP_PATH_DELAY_RESP_MESSAGE     0x3
87 #define PTP_FOLLOWUP_MESSAGE            0x8
88 #define PTP_DELAY_RESP_MESSAGE          0x9
89 #define PTP_PATH_DELAY_FOLLOWUP_MESSAGE 0xA
90 #define PTP_ANNOUNCE_MESSAGE            0xB
91 #define PTP_SIGNALLING_MESSAGE          0xC
92 #define PTP_MANAGEMENT_MESSAGE          0xD
93
94 /*
95  * Forwarding of IEEE1588 Precise Time Protocol (PTP) packets.
96  *
97  * In this mode, packets are received one by one and are expected to be
98  * PTP V2 L2 Ethernet frames (with the specific Ethernet type "0x88F7")
99  * containing PTP "sync" messages (version 2 at offset 1, and message ID
100  * 0 at offset 0).
101  *
102  * Check that each received packet is a IEEE1588 PTP V2 packet of type
103  * PTP_SYNC_MESSAGE, and that it has been identified and timestamped
104  * by the hardware.
105  * Check that the value of the last RX timestamp recorded by the controller
106  * is greater than the previous one.
107  *
108  * If everything is OK, send the received packet back on the same port,
109  * requesting for it to be timestamped by the hardware.
110  * Check that the value of the last TX timestamp recorded by the controller
111  * is greater than the previous one.
112  */
113
114 /*
115  * 1GbE 82576 Kawela registers used for IEEE1588 hardware support
116  */
117 #define IGBE_82576_ETQF(n) (0x05CB0 + (4 * (n)))
118 #define IGBE_82576_ETQF_FILTER_ENABLE  (1 << 26)
119 #define IGBE_82576_ETQF_1588_TIMESTAMP (1 << 30)
120
121 #define IGBE_82576_TSYNCRXCTL  0x0B620
122 #define IGBE_82576_TSYNCRXCTL_RXTS_ENABLE (1 << 4)
123
124 #define IGBE_82576_RXSTMPL     0x0B624
125 #define IGBE_82576_RXSTMPH     0x0B628
126 #define IGBE_82576_RXSATRL     0x0B62C
127 #define IGBE_82576_RXSATRH     0x0B630
128 #define IGBE_82576_TSYNCTXCTL  0x0B614
129 #define IGBE_82576_TSYNCTXCTL_TXTS_ENABLE (1 << 4)
130
131 #define IGBE_82576_TXSTMPL     0x0B618
132 #define IGBE_82576_TXSTMPH     0x0B61C
133 #define IGBE_82576_SYSTIML     0x0B600
134 #define IGBE_82576_SYSTIMH     0x0B604
135 #define IGBE_82576_TIMINCA     0x0B608
136 #define IGBE_82576_TIMADJL     0x0B60C
137 #define IGBE_82576_TIMADJH     0x0B610
138 #define IGBE_82576_TSAUXC      0x0B640
139 #define IGBE_82576_TRGTTIML0   0x0B644
140 #define IGBE_82576_TRGTTIMH0   0x0B648
141 #define IGBE_82576_TRGTTIML1   0x0B64C
142 #define IGBE_82576_TRGTTIMH1   0x0B650
143 #define IGBE_82576_AUXSTMPL0   0x0B65C
144 #define IGBE_82576_AUXSTMPH0   0x0B660
145 #define IGBE_82576_AUXSTMPL1   0x0B664
146 #define IGBE_82576_AUXSTMPH1   0x0B668
147 #define IGBE_82576_TSYNCRXCFG  0x05F50
148 #define IGBE_82576_TSSDP       0x0003C
149
150 /*
151  * 10GbE 82599 Niantic registers used for IEEE1588 hardware support
152  */
153 #define IXGBE_82599_ETQF(n) (0x05128 + (4 * (n)))
154 #define IXGBE_82599_ETQF_FILTER_ENABLE  (1 << 31)
155 #define IXGBE_82599_ETQF_1588_TIMESTAMP (1 << 30)
156
157 #define IXGBE_82599_TSYNCRXCTL 0x05188
158 #define IXGBE_82599_TSYNCRXCTL_RXTS_ENABLE (1 << 4)
159
160 #define IXGBE_82599_RXSTMPL    0x051E8
161 #define IXGBE_82599_RXSTMPH    0x051A4
162 #define IXGBE_82599_RXSATRL    0x051A0
163 #define IXGBE_82599_RXSATRH    0x051A8
164 #define IXGBE_82599_RXMTRL     0x05120
165 #define IXGBE_82599_TSYNCTXCTL 0x08C00
166 #define IXGBE_82599_TSYNCTXCTL_TXTS_ENABLE (1 << 4)
167
168 #define IXGBE_82599_TXSTMPL    0x08C04
169 #define IXGBE_82599_TXSTMPH    0x08C08
170 #define IXGBE_82599_SYSTIML    0x08C0C
171 #define IXGBE_82599_SYSTIMH    0x08C10
172 #define IXGBE_82599_TIMINCA    0x08C14
173 #define IXGBE_82599_TIMADJL    0x08C18
174 #define IXGBE_82599_TIMADJH    0x08C1C
175 #define IXGBE_82599_TSAUXC     0x08C20
176 #define IXGBE_82599_TRGTTIML0  0x08C24
177 #define IXGBE_82599_TRGTTIMH0  0x08C28
178 #define IXGBE_82599_TRGTTIML1  0x08C2C
179 #define IXGBE_82599_TRGTTIMH1  0x08C30
180 #define IXGBE_82599_AUXSTMPL0  0x08C3C
181 #define IXGBE_82599_AUXSTMPH0  0x08C40
182 #define IXGBE_82599_AUXSTMPL1  0x08C44
183 #define IXGBE_82599_AUXSTMPH1  0x08C48
184
185 /**
186  * Mandatory ETQF register for IEEE1588 packets filter.
187  */
188 #define ETQF_FILTER_1588_REG 3
189
190 /**
191  * Recommended value for increment and period of
192  * the Increment Attribute Register.
193  */
194 #define IEEE1588_TIMINCA_INIT ((0x02 << 24) | 0x00F42400)
195
196 /**
197  * Data structure with pointers to port-specific functions.
198  */
199 typedef void (*ieee1588_start_t)(portid_t pi); /**< Start IEEE1588 feature. */
200 typedef void (*ieee1588_stop_t)(portid_t pi);  /**< Stop IEEE1588 feature.  */
201 typedef int  (*tmst_read_t)(portid_t pi, uint64_t *tmst); /**< Read TMST regs */
202
203 struct port_ieee1588_ops {
204         ieee1588_start_t ieee1588_start;
205         ieee1588_stop_t  ieee1588_stop;
206         tmst_read_t      rx_tmst_read;
207         tmst_read_t      tx_tmst_read;
208 };
209
210 /**
211  * 1GbE 82576 IEEE1588 operations.
212  */
213 static void
214 igbe_82576_ieee1588_start(portid_t pi)
215 {
216         uint32_t tsync_ctl;
217
218         /*
219          * Start incrementation of the System Time registers used to
220          * timestamp PTP packets.
221          */
222         port_id_pci_reg_write(pi, IGBE_82576_TIMINCA, IEEE1588_TIMINCA_INIT);
223         port_id_pci_reg_write(pi, IGBE_82576_TSAUXC, 0);
224
225         /*
226          * Enable L2 filtering of IEEE1588 Ethernet frame types.
227          */
228         port_id_pci_reg_write(pi, IGBE_82576_ETQF(ETQF_FILTER_1588_REG),
229                               (ETHER_TYPE_1588 |
230                                IGBE_82576_ETQF_FILTER_ENABLE |
231                                IGBE_82576_ETQF_1588_TIMESTAMP));
232
233         /*
234          * Enable timestamping of received PTP packets.
235          */
236         tsync_ctl = port_id_pci_reg_read(pi, IGBE_82576_TSYNCRXCTL);
237         tsync_ctl |= IGBE_82576_TSYNCRXCTL_RXTS_ENABLE;
238         port_id_pci_reg_write(pi, IGBE_82576_TSYNCRXCTL, tsync_ctl);
239
240         /*
241          * Enable Timestamping of transmitted PTP packets.
242          */
243         tsync_ctl = port_id_pci_reg_read(pi, IGBE_82576_TSYNCTXCTL);
244         tsync_ctl |= IGBE_82576_TSYNCTXCTL_TXTS_ENABLE;
245         port_id_pci_reg_write(pi, IGBE_82576_TSYNCTXCTL, tsync_ctl);
246 }
247
248 static void
249 igbe_82576_ieee1588_stop(portid_t pi)
250 {
251         uint32_t tsync_ctl;
252
253         /*
254          * Disable Timestamping of transmitted PTP packets.
255          */
256         tsync_ctl = port_id_pci_reg_read(pi, IGBE_82576_TSYNCTXCTL);
257         tsync_ctl &= ~IGBE_82576_TSYNCTXCTL_TXTS_ENABLE;
258         port_id_pci_reg_write(pi, IGBE_82576_TSYNCTXCTL, tsync_ctl);
259
260         /*
261          * Disable timestamping of received PTP packets.
262          */
263         tsync_ctl = port_id_pci_reg_read(pi, IGBE_82576_TSYNCRXCTL);
264         tsync_ctl &= ~IGBE_82576_TSYNCRXCTL_RXTS_ENABLE;
265         port_id_pci_reg_write(pi, IGBE_82576_TSYNCRXCTL, tsync_ctl);
266
267         /*
268          * Disable L2 filtering of IEEE1588 Ethernet types.
269          */
270         port_id_pci_reg_write(pi, IGBE_82576_ETQF(ETQF_FILTER_1588_REG), 0);
271
272         /*
273          * Stop incrementation of the System Time registers.
274          */
275         port_id_pci_reg_write(pi, IGBE_82576_TIMINCA, 0);
276 }
277
278 /**
279  * Return the 64-bit value contained in the RX IEEE1588 timestamp registers
280  * of a 1GbE 82576 port.
281  *
282  * @param pi
283  *   The port identifier.
284  *
285  * @param tmst
286  *   The address of a 64-bit variable to return the value of the RX timestamp.
287  *
288  * @return
289  *  -1: the RXSTMPL and RXSTMPH registers of the port are not valid.
290  *   0: the variable pointed to by the "tmst" parameter contains the value
291  *      of the RXSTMPL and RXSTMPH registers of the port.
292  */
293 static int
294 igbe_82576_rx_timestamp_read(portid_t pi, uint64_t *tmst)
295 {
296         uint32_t tsync_rxctl;
297         uint32_t rx_stmpl;
298         uint32_t rx_stmph;
299
300         tsync_rxctl = port_id_pci_reg_read(pi, IGBE_82576_TSYNCRXCTL);
301         if ((tsync_rxctl & 0x01) == 0)
302                 return (-1);
303
304         rx_stmpl = port_id_pci_reg_read(pi, IGBE_82576_RXSTMPL);
305         rx_stmph = port_id_pci_reg_read(pi, IGBE_82576_RXSTMPH);
306         *tmst = (uint64_t)(((uint64_t) rx_stmph << 32) | rx_stmpl);
307         return (0);
308 }
309
310 /**
311  * Return the 64-bit value contained in the TX IEEE1588 timestamp registers
312  * of a 1GbE 82576 port.
313  *
314  * @param pi
315  *   The port identifier.
316  *
317  * @param tmst
318  *   The address of a 64-bit variable to return the value of the TX timestamp.
319  *
320  * @return
321  *  -1: the TXSTMPL and TXSTMPH registers of the port are not valid.
322  *   0: the variable pointed to by the "tmst" parameter contains the value
323  *      of the TXSTMPL and TXSTMPH registers of the port.
324  */
325 static int
326 igbe_82576_tx_timestamp_read(portid_t pi, uint64_t *tmst)
327 {
328         uint32_t tsync_txctl;
329         uint32_t tx_stmpl;
330         uint32_t tx_stmph;
331
332         tsync_txctl = port_id_pci_reg_read(pi, IGBE_82576_TSYNCTXCTL);
333         if ((tsync_txctl & 0x01) == 0)
334                 return (-1);
335
336         tx_stmpl = port_id_pci_reg_read(pi, IGBE_82576_TXSTMPL);
337         tx_stmph = port_id_pci_reg_read(pi, IGBE_82576_TXSTMPH);
338         *tmst = (uint64_t)(((uint64_t) tx_stmph << 32) | tx_stmpl);
339         return (0);
340 }
341
342 static struct port_ieee1588_ops igbe_82576_ieee1588_ops = {
343         .ieee1588_start = igbe_82576_ieee1588_start,
344         .ieee1588_stop  = igbe_82576_ieee1588_stop,
345         .rx_tmst_read   = igbe_82576_rx_timestamp_read,
346         .tx_tmst_read   = igbe_82576_tx_timestamp_read,
347 };
348
349 /**
350  * 10GbE 82599 IEEE1588 operations.
351  */
352 static void
353 ixgbe_82599_ieee1588_start(portid_t pi)
354 {
355         uint32_t tsync_ctl;
356
357         /*
358          * Start incrementation of the System Time registers used to
359          * timestamp PTP packets.
360          */
361         port_id_pci_reg_write(pi, IXGBE_82599_TIMINCA, IEEE1588_TIMINCA_INIT);
362
363         /*
364          * Enable L2 filtering of IEEE1588 Ethernet frame types.
365          */
366         port_id_pci_reg_write(pi, IXGBE_82599_ETQF(ETQF_FILTER_1588_REG),
367                               (ETHER_TYPE_1588 |
368                                IXGBE_82599_ETQF_FILTER_ENABLE |
369                                IXGBE_82599_ETQF_1588_TIMESTAMP));
370
371         /*
372          * Enable timestamping of received PTP packets.
373          */
374         tsync_ctl = port_id_pci_reg_read(pi, IXGBE_82599_TSYNCRXCTL);
375         tsync_ctl |= IXGBE_82599_TSYNCRXCTL_RXTS_ENABLE;
376         port_id_pci_reg_write(pi, IXGBE_82599_TSYNCRXCTL, tsync_ctl);
377
378         /*
379          * Enable Timestamping of transmitted PTP packets.
380          */
381         tsync_ctl = port_id_pci_reg_read(pi, IXGBE_82599_TSYNCTXCTL);
382         tsync_ctl |= IXGBE_82599_TSYNCTXCTL_TXTS_ENABLE;
383         port_id_pci_reg_write(pi, IXGBE_82599_TSYNCTXCTL, tsync_ctl);
384 }
385
386 static void
387 ixgbe_82599_ieee1588_stop(portid_t pi)
388 {
389         uint32_t tsync_ctl;
390
391         /*
392          * Disable Timestamping of transmitted PTP packets.
393          */
394         tsync_ctl = port_id_pci_reg_read(pi, IXGBE_82599_TSYNCTXCTL);
395         tsync_ctl &= ~IXGBE_82599_TSYNCTXCTL_TXTS_ENABLE;
396         port_id_pci_reg_write(pi, IXGBE_82599_TSYNCTXCTL, tsync_ctl);
397
398         /*
399          * Disable timestamping of received PTP packets.
400          */
401         tsync_ctl = port_id_pci_reg_read(pi, IXGBE_82599_TSYNCRXCTL);
402         tsync_ctl &= ~IXGBE_82599_TSYNCRXCTL_RXTS_ENABLE;
403         port_id_pci_reg_write(pi, IXGBE_82599_TSYNCRXCTL, tsync_ctl);
404
405         /*
406          * Disable L2 filtering of IEEE1588 Ethernet frame types.
407          */
408         port_id_pci_reg_write(pi, IXGBE_82599_ETQF(ETQF_FILTER_1588_REG), 0);
409
410         /*
411          * Stop incrementation of the System Time registers.
412          */
413         port_id_pci_reg_write(pi, IXGBE_82599_TIMINCA, 0);
414 }
415
416 /**
417  * Return the 64-bit value contained in the RX IEEE1588 timestamp registers
418  * of a 10GbE 82599 port.
419  *
420  * @param pi
421  *   The port identifier.
422  *
423  * @param tmst
424  *   The address of a 64-bit variable to return the value of the TX timestamp.
425  *
426  * @return
427  *  -1: the RX timestamp registers of the port are not valid.
428  *   0: the variable pointed to by the "tmst" parameter contains the value
429  *      of the RXSTMPL and RXSTMPH registers of the port.
430  */
431 static int
432 ixgbe_82599_rx_timestamp_read(portid_t pi, uint64_t *tmst)
433 {
434         uint32_t tsync_rxctl;
435         uint32_t rx_stmpl;
436         uint32_t rx_stmph;
437
438         tsync_rxctl = port_id_pci_reg_read(pi, IXGBE_82599_TSYNCRXCTL);
439         if ((tsync_rxctl & 0x01) == 0)
440                 return (-1);
441
442         rx_stmpl = port_id_pci_reg_read(pi, IXGBE_82599_RXSTMPL);
443         rx_stmph = port_id_pci_reg_read(pi, IXGBE_82599_RXSTMPH);
444         *tmst = (uint64_t)(((uint64_t) rx_stmph << 32) | rx_stmpl);
445         return (0);
446 }
447
448 /**
449  * Return the 64-bit value contained in the TX IEEE1588 timestamp registers
450  * of a 10GbE 82599 port.
451  *
452  * @param pi
453  *   The port identifier.
454  *
455  * @param tmst
456  *   The address of a 64-bit variable to return the value of the TX timestamp.
457  *
458  * @return
459  *  -1: the TXSTMPL and TXSTMPH registers of the port are not valid.
460  *   0: the variable pointed to by the "tmst" parameter contains the value
461  *      of the TXSTMPL and TXSTMPH registers of the port.
462  */
463 static int
464 ixgbe_82599_tx_timestamp_read(portid_t pi, uint64_t *tmst)
465 {
466         uint32_t tsync_txctl;
467         uint32_t tx_stmpl;
468         uint32_t tx_stmph;
469
470         tsync_txctl = port_id_pci_reg_read(pi, IXGBE_82599_TSYNCTXCTL);
471         if ((tsync_txctl & 0x01) == 0)
472                 return (-1);
473
474         tx_stmpl = port_id_pci_reg_read(pi, IXGBE_82599_TXSTMPL);
475         tx_stmph = port_id_pci_reg_read(pi, IXGBE_82599_TXSTMPH);
476         *tmst = (uint64_t)(((uint64_t) tx_stmph << 32) | tx_stmpl);
477         return (0);
478 }
479
480 static struct port_ieee1588_ops ixgbe_82599_ieee1588_ops = {
481         .ieee1588_start = ixgbe_82599_ieee1588_start,
482         .ieee1588_stop  = ixgbe_82599_ieee1588_stop,
483         .rx_tmst_read   = ixgbe_82599_rx_timestamp_read,
484         .tx_tmst_read   = ixgbe_82599_tx_timestamp_read,
485 };
486
487 static void
488 port_ieee1588_rx_timestamp_check(portid_t pi)
489 {
490         struct port_ieee1588_ops *ieee_ops;
491         uint64_t rx_tmst;
492
493         ieee_ops = (struct port_ieee1588_ops *)ports[pi].fwd_ctx;
494         if (ieee_ops->rx_tmst_read(pi, &rx_tmst) < 0) {
495                 printf("Port %u: RX timestamp registers not valid\n",
496                        (unsigned) pi);
497                 return;
498         }
499         printf("Port %u RX timestamp value 0x%"PRIu64"\n",
500                (unsigned) pi, rx_tmst);
501 }
502
503 #define MAX_TX_TMST_WAIT_MICROSECS 1000 /**< 1 milli-second */
504
505 static void
506 port_ieee1588_tx_timestamp_check(portid_t pi)
507 {
508         struct port_ieee1588_ops *ieee_ops;
509         uint64_t tx_tmst;
510         unsigned wait_us;
511
512         ieee_ops = (struct port_ieee1588_ops *)ports[pi].fwd_ctx;
513         wait_us = 0;
514         while ((ieee_ops->tx_tmst_read(pi, &tx_tmst) < 0) &&
515                (wait_us < MAX_TX_TMST_WAIT_MICROSECS)) {
516                 rte_delay_us(1);
517                 wait_us++;
518         }
519         if (wait_us >= MAX_TX_TMST_WAIT_MICROSECS) {
520                 printf("Port %u: TX timestamp registers not valid after"
521                        "%u micro-seconds\n",
522                        (unsigned) pi, (unsigned) MAX_TX_TMST_WAIT_MICROSECS);
523                 return;
524         }
525         printf("Port %u TX timestamp value 0x%"PRIu64" validated after "
526                "%u micro-second%s\n",
527                (unsigned) pi, tx_tmst, wait_us,
528                (wait_us == 1) ? "" : "s");
529 }
530
531 static void
532 ieee1588_packet_fwd(struct fwd_stream *fs)
533 {
534         struct rte_mbuf  *mb;
535         struct ether_hdr *eth_hdr;
536         struct ptpv2_msg *ptp_hdr;
537         uint16_t eth_type;
538
539         /*
540          * Receive 1 packet at a time.
541          */
542         if (rte_eth_rx_burst(fs->rx_port, fs->rx_queue, &mb, 1) == 0)
543                 return;
544
545         fs->rx_packets += 1;
546
547         /*
548          * Check that the received packet is a PTP packet that was detected
549          * by the hardware.
550          */
551         eth_hdr = (struct ether_hdr *)mb->pkt.data;
552         eth_type = rte_be_to_cpu_16(eth_hdr->ether_type);
553         if (! (mb->ol_flags & PKT_RX_IEEE1588_PTP)) {
554                 if (eth_type == ETHER_TYPE_1588) {
555                         printf("Port %u Received PTP packet not filtered"
556                                " by hardware\n",
557                                (unsigned) fs->rx_port);
558                 } else {
559                         printf("Port %u Received non PTP packet type=0x%4x "
560                                "len=%u\n",
561                                (unsigned) fs->rx_port, eth_type,
562                                (unsigned) mb->pkt.pkt_len);
563                 }
564                 rte_pktmbuf_free(mb);
565                 return;
566         }
567         if (eth_type != ETHER_TYPE_1588) {
568                 printf("Port %u Received NON PTP packet wrongly"
569                        " detected by hardware\n",
570                        (unsigned) fs->rx_port);
571                 rte_pktmbuf_free(mb);
572                 return;
573         }
574
575         /*
576          * Check that the received PTP packet is a PTP V2 packet of type
577          * PTP_SYNC_MESSAGE.
578          */
579         ptp_hdr = (struct ptpv2_msg *) ((char *) mb->pkt.data +
580                                         sizeof(struct ether_hdr));
581         if (ptp_hdr->version != 0x02) {
582                 printf("Port %u Received PTP V2 Ethernet frame with wrong PTP"
583                        " protocol version 0x%x (should be 0x02)\n",
584                        (unsigned) fs->rx_port, ptp_hdr->version);
585                 rte_pktmbuf_free(mb);
586                 return;
587         }
588         if (ptp_hdr->msg_id != PTP_SYNC_MESSAGE) {
589                 printf("Port %u Received PTP V2 Ethernet frame with unexpected"
590                        " messageID 0x%x (expected 0x0 - PTP_SYNC_MESSAGE)\n",
591                        (unsigned) fs->rx_port, ptp_hdr->msg_id);
592                 rte_pktmbuf_free(mb);
593                 return;
594         }
595         printf("Port %u IEEE1588 PTP V2 SYNC Message filtered by hardware\n",
596                (unsigned) fs->rx_port);
597
598         /*
599          * Check that the received PTP packet has been timestamped by the
600          * hardware.
601          */
602         if (! (mb->ol_flags & PKT_RX_IEEE1588_TMST)) {
603                 printf("Port %u Received PTP packet not timestamped"
604                        " by hardware\n",
605                        (unsigned) fs->rx_port);
606                 rte_pktmbuf_free(mb);
607                 return;
608         }
609
610         /* Check the RX timestamp */
611         port_ieee1588_rx_timestamp_check(fs->rx_port);
612
613         /* Forward PTP packet with hardware TX timestamp */
614         mb->ol_flags |= PKT_TX_IEEE1588_TMST;
615         fs->tx_packets += 1;
616         if (rte_eth_tx_burst(fs->rx_port, fs->tx_queue, &mb, 1) == 0) {
617                 printf("Port %u sent PTP packet dropped\n",
618                        (unsigned) fs->rx_port);
619                 fs->fwd_dropped += 1;
620                 rte_pktmbuf_free(mb);
621                 return;
622         }
623
624         /*
625          * Check the TX timestamp.
626          */
627         port_ieee1588_tx_timestamp_check(fs->rx_port);
628 }
629
630 static void
631 port_ieee1588_fwd_begin(portid_t pi)
632 {
633         struct port_ieee1588_ops *ieee_ops;
634
635         if (strcmp(ports[pi].dev_info.driver_name, "rte_igb_pmd") == 0)
636                 ieee_ops = &igbe_82576_ieee1588_ops;
637         else
638                 ieee_ops = &ixgbe_82599_ieee1588_ops;
639         ports[pi].fwd_ctx = ieee_ops;
640         (ieee_ops->ieee1588_start)(pi);
641 }
642
643 static void
644 port_ieee1588_fwd_end(portid_t pi)
645 {
646         struct port_ieee1588_ops *ieee_ops;
647
648         ieee_ops = (struct port_ieee1588_ops *)ports[pi].fwd_ctx;
649         (ieee_ops->ieee1588_stop)(pi);
650 }
651
652 struct fwd_engine ieee1588_fwd_engine = {
653         .fwd_mode_name  = "ieee1588",
654         .port_fwd_begin = port_ieee1588_fwd_begin,
655         .port_fwd_end   = port_ieee1588_fwd_end,
656         .packet_fwd     = ieee1588_packet_fwd,
657 };