0c51d7d8ff6113c933b0b5021084fdab102b649e
[vpp.git] / src / plugins / marvell / pp2 / input.c
1 /*
2  *------------------------------------------------------------------
3  * Copyright (c) 2018 Cisco and/or its affiliates.
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *------------------------------------------------------------------
16  */
17
18 #define _GNU_SOURCE
19 #include <stdint.h>
20 #include <net/if.h>
21 #include <sys/ioctl.h>
22 #include <sys/uio.h>
23
24 #include <vlib/vlib.h>
25 #include <vlib/unix/unix.h>
26 #include <vnet/ethernet/ethernet.h>
27 #include <vnet/devices/devices.h>
28 #include <vnet/interface/rx_queue_funcs.h>
29
30 #include <marvell/pp2/pp2.h>
31
32 #define foreach_mrvl_pp2_input_error \
33   _(PPIO_RECV, "pp2_ppio_recv error") \
34   _(BPOOL_GET_NUM_BUFFS, "pp2_bpool_get_num_buffs error") \
35   _(BPOOL_PUT_BUFFS, "pp2_bpool_put_buffs error") \
36   _(BUFFER_ALLOC, "buffer alloc error") \
37   _(MAC_CE, "MAC error (CRC error)") \
38   _(MAC_OR, "overrun error") \
39   _(MAC_RSVD, "unknown MAC error") \
40   _(MAC_RE, "resource error") \
41   _(IP_HDR, "ip4 header error")
42
43 typedef enum
44 {
45 #define _(f,s) MRVL_PP2_INPUT_ERROR_##f,
46   foreach_mrvl_pp2_input_error
47 #undef _
48     MRVL_PP2_INPUT_N_ERROR,
49 } mrvl_pp2_input_error_t;
50
51 static __clib_unused char *mrvl_pp2_input_error_strings[] = {
52 #define _(n,s) s,
53   foreach_mrvl_pp2_input_error
54 #undef _
55 };
56
57 static_always_inline void
58 mrvl_pp2_input_trace (vlib_main_t * vm, vlib_node_runtime_t * node, u32 next0,
59                       vlib_buffer_t * b0, uword * n_trace,
60                       mrvl_pp2_if_t * ppif, struct pp2_ppio_desc *d)
61 {
62   mrvl_pp2_input_trace_t *tr;
63   vlib_trace_buffer (vm, node, next0, b0,
64                      /* follow_chain */ 0);
65   vlib_set_trace_count (vm, node, --(*n_trace));
66   tr = vlib_add_trace (vm, node, b0, sizeof (*tr));
67   tr->next_index = next0;
68   tr->hw_if_index = ppif->hw_if_index;
69   clib_memcpy_fast (&tr->desc, d, sizeof (struct pp2_ppio_desc));
70 }
71
72 static_always_inline u16
73 mrvl_pp2_set_buf_data_len_flags (vlib_buffer_t * b, struct pp2_ppio_desc *d,
74                                  u32 add_flags)
75 {
76   u16 len;
77   len = pp2_ppio_inq_desc_get_pkt_len (d);
78   b->total_length_not_including_first_buffer = 0;
79   b->flags = VLIB_BUFFER_TOTAL_LENGTH_VALID | add_flags;
80
81   if (add_flags & VNET_BUFFER_F_L2_HDR_OFFSET_VALID)
82     vnet_buffer (b)->l2_hdr_offset = 2;
83
84   if (add_flags & VNET_BUFFER_F_L3_HDR_OFFSET_VALID)
85     {
86       u16 offset = DM_RXD_GET_L3_OFF (d);
87       vnet_buffer (b)->l3_hdr_offset = offset;
88       b->current_data = offset;
89       b->current_length = len - offset + 2;
90     }
91   else
92     {
93       b->current_data = 2;
94       b->current_length = len;
95     }
96
97   if (add_flags & VNET_BUFFER_F_L3_HDR_OFFSET_VALID)
98     vnet_buffer (b)->l4_hdr_offset = vnet_buffer (b)->l3_hdr_offset +
99       DM_RXD_GET_IPHDR_LEN (d) * 4;
100
101   return len;
102 }
103
104 static_always_inline u16
105 mrvl_pp2_next_from_desc (vlib_node_runtime_t * node, struct pp2_ppio_desc * d,
106                          vlib_buffer_t * b, u32 * next)
107 {
108   u8 l3_info;
109   /* ES bit set means MAC error  - drop and count */
110   if (PREDICT_FALSE (DM_RXD_GET_ES (d)))
111     {
112       *next = VNET_DEVICE_INPUT_NEXT_DROP;
113       u8 ec = DM_RXD_GET_EC (d);
114       if (ec == 0)
115         b->error = node->errors[MRVL_PP2_INPUT_ERROR_MAC_CE];
116       else if (ec == 1)
117         b->error = node->errors[MRVL_PP2_INPUT_ERROR_MAC_OR];
118       else if (ec == 2)
119         b->error = node->errors[MRVL_PP2_INPUT_ERROR_MAC_RSVD];
120       else if (ec == 3)
121         b->error = node->errors[MRVL_PP2_INPUT_ERROR_MAC_RE];
122       return mrvl_pp2_set_buf_data_len_flags (b, d, 0);
123     }
124   l3_info = DM_RXD_GET_L3_PRS_INFO (d);
125
126   /* ipv4 packet can be value 1, 2 or 3 */
127   if (PREDICT_TRUE ((l3_info - 1) < 3))
128     {
129       if (PREDICT_FALSE (DM_RXD_GET_L3_IP4_HDR_ERR (d) != 0))
130         {
131           *next = VNET_DEVICE_INPUT_NEXT_DROP;
132           b->error = node->errors[MRVL_PP2_INPUT_ERROR_IP_HDR];
133           return mrvl_pp2_set_buf_data_len_flags (b, d, 0);
134         }
135       *next = VNET_DEVICE_INPUT_NEXT_IP4_NCS_INPUT;
136       return mrvl_pp2_set_buf_data_len_flags
137         (b, d,
138          VNET_BUFFER_F_L2_HDR_OFFSET_VALID |
139          VNET_BUFFER_F_L3_HDR_OFFSET_VALID |
140          VNET_BUFFER_F_L4_HDR_OFFSET_VALID | VNET_BUFFER_F_IS_IP4);
141     }
142
143   /* ipv4 packet can be value 4 or 5 */
144   if (PREDICT_TRUE ((l3_info - 4) < 2))
145     {
146       *next = VNET_DEVICE_INPUT_NEXT_IP6_INPUT;
147       return mrvl_pp2_set_buf_data_len_flags
148         (b, d,
149          VNET_BUFFER_F_L2_HDR_OFFSET_VALID |
150          VNET_BUFFER_F_L3_HDR_OFFSET_VALID |
151          VNET_BUFFER_F_L4_HDR_OFFSET_VALID | VNET_BUFFER_F_IS_IP6);
152     }
153
154   *next = VNET_DEVICE_INPUT_NEXT_ETHERNET_INPUT;
155   return mrvl_pp2_set_buf_data_len_flags (b, d,
156                                           VNET_BUFFER_F_L2_HDR_OFFSET_VALID);
157 }
158
159 static_always_inline uword
160 mrvl_pp2_device_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
161                               vlib_frame_t * frame, mrvl_pp2_if_t * ppif,
162                               u16 qid)
163 {
164   vnet_main_t *vnm = vnet_get_main ();
165   mrvl_pp2_main_t *ppm = &mrvl_pp2_main;
166   u32 thread_index = vm->thread_index;
167   mrvl_pp2_inq_t *inq = vec_elt_at_index (ppif->inqs, qid);
168   uword n_trace = vlib_get_trace_count (vm, node);
169   mrvl_pp2_per_thread_data_t *ptd =
170     vec_elt_at_index (ppm->per_thread_data, thread_index);
171   u32 next_index = VNET_DEVICE_INPUT_NEXT_ETHERNET_INPUT;
172   u32 sw_if_index[VLIB_N_RX_TX];
173   u32 n_rx_packets = 0;
174   u32 n_rx_bytes = 0;
175   u32 *to_next = 0;
176   struct pp2_ppio_desc *d;
177   u16 n_desc = VLIB_FRAME_SIZE;
178   u32 n_bufs;
179   u32 *buffers;
180   int i;
181
182   vec_validate_aligned (ptd->descs, n_desc, CLIB_CACHE_LINE_BYTES);
183   if (PREDICT_FALSE (pp2_ppio_recv (ppif->ppio, 0, qid, ptd->descs, &n_desc)))
184     {
185       vlib_error_count (vm, node->node_index, MRVL_PP2_INPUT_ERROR_PPIO_RECV,
186                         1);
187       n_desc = 0;
188     }
189   n_rx_packets = n_desc;
190
191   for (i = 0; i < n_desc; i++)
192     ptd->buffers[i] = pp2_ppio_inq_desc_get_cookie (&ptd->descs[i]);
193
194   d = ptd->descs;
195   buffers = ptd->buffers;
196   sw_if_index[VLIB_RX] = ppif->sw_if_index;
197   sw_if_index[VLIB_TX] = (u32) ~ 0;
198   while (n_desc)
199     {
200       u32 n_left_to_next;
201       vlib_buffer_t *b0, *b1;
202       u32 bi0, bi1;
203       u32 next0, next1;
204       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
205       while (n_desc >= 4 && n_left_to_next >= 2)
206         {
207           /* prefetch */
208           bi0 = buffers[0];
209           bi1 = buffers[1];
210           to_next[0] = bi0;
211           to_next[1] = bi1;
212           b0 = vlib_get_buffer (vm, bi0);
213           b1 = vlib_get_buffer (vm, bi1);
214
215           if (PREDICT_TRUE (ppif->per_interface_next_index == ~0))
216             {
217               n_rx_bytes += mrvl_pp2_next_from_desc (node, d, b0, &next0);
218               n_rx_bytes += mrvl_pp2_next_from_desc (node, d + 1, b1, &next1);
219               vnet_feature_start_device_input_x2 (ppif->sw_if_index, &next0,
220                                                   &next1, b0, b1);
221             }
222           else
223             {
224               n_rx_bytes += mrvl_pp2_set_buf_data_len_flags (b0, d, 0);
225               n_rx_bytes += mrvl_pp2_set_buf_data_len_flags (b1, d + 1, 0);
226               next0 = next1 = ppif->per_interface_next_index;
227             }
228
229           clib_memcpy_fast (vnet_buffer (b0)->sw_if_index, sw_if_index,
230                             sizeof (sw_if_index));
231           clib_memcpy_fast (vnet_buffer (b1)->sw_if_index, sw_if_index,
232                             sizeof (sw_if_index));
233
234           VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b0);
235           VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b1);
236
237           if (PREDICT_FALSE (n_trace > 0))
238             {
239               mrvl_pp2_input_trace (vm, node, next0, b0, &n_trace, ppif, d);
240               if (n_trace > 0)
241                 mrvl_pp2_input_trace (vm, node, next1, b1, &n_trace, ppif,
242                                       d + 1);
243             }
244
245           to_next += 2;
246           n_left_to_next -= 2;
247           d += 2;
248           buffers += 2;
249           n_desc -= 2;
250
251           /* enqueue */
252           vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
253                                            n_left_to_next, bi0, bi1, next0,
254                                            next1);
255
256         }
257       while (n_desc && n_left_to_next)
258         {
259           u32 bi0 = buffers[0];
260           to_next[0] = bi0;
261           b0 = vlib_get_buffer (vm, bi0);
262
263           if (PREDICT_TRUE (ppif->per_interface_next_index == ~0))
264             {
265               n_rx_bytes += mrvl_pp2_next_from_desc (node, d, b0, &next0);
266               vnet_feature_start_device_input_x1 (ppif->sw_if_index, &next0,
267                                                   b0);
268             }
269           else
270             {
271               n_rx_bytes += mrvl_pp2_set_buf_data_len_flags (b0, d, 0);
272               next0 = ppif->per_interface_next_index;
273             }
274
275           clib_memcpy_fast (vnet_buffer (b0)->sw_if_index, sw_if_index,
276                             sizeof (sw_if_index));
277
278           VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b0);
279
280           if (PREDICT_FALSE (n_trace > 0))
281             mrvl_pp2_input_trace (vm, node, next0, b0, &n_trace, ppif, d);
282
283           to_next += 1;
284           n_left_to_next--;
285           d++;
286           buffers++;
287           n_desc--;
288
289           /* enqueue */
290           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
291                                            n_left_to_next, bi0, next0);
292         }
293       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
294     }
295   vlib_increment_combined_counter (vnm->
296                                    interface_main.combined_sw_if_counters +
297                                    VNET_INTERFACE_COUNTER_RX, thread_index,
298                                    ppif->hw_if_index, n_rx_packets,
299                                    n_rx_bytes);
300
301   if (PREDICT_FALSE (pp2_bpool_get_num_buffs (inq->bpool, &n_bufs)))
302     {
303       vlib_error_count (vm, node->node_index,
304                         MRVL_PP2_INPUT_ERROR_BPOOL_GET_NUM_BUFFS, 1);
305       goto done;
306     }
307
308   n_bufs = inq->size - n_bufs;
309   while (n_bufs >= MRVL_PP2_BUFF_BATCH_SZ)
310     {
311       u16 n_alloc, i;
312       struct buff_release_entry *e = ptd->bre;
313       u32 *buffers = ptd->buffers;
314
315       n_alloc = vlib_buffer_alloc (vm, ptd->buffers, MRVL_PP2_BUFF_BATCH_SZ);
316       i = n_alloc;
317
318       if (PREDICT_FALSE (n_alloc == 0))
319         {
320           vlib_error_count (vm, node->node_index,
321                             MRVL_PP2_INPUT_ERROR_BUFFER_ALLOC, 1);
322           goto done;
323         }
324
325       while (i--)
326         {
327           u32 bi = buffers[0];
328           vlib_buffer_t *b = vlib_get_buffer (vm, bi);
329           e->buff.addr = vlib_buffer_get_pa (vm, b) - 64;
330           e->buff.cookie = bi;
331           e->bpool = inq->bpool;
332           e++;
333           buffers++;
334         }
335
336       i = n_alloc;
337       if (PREDICT_FALSE (pp2_bpool_put_buffs (ptd->hif, ptd->bre, &i)))
338         {
339           vlib_error_count (vm, node->node_index,
340                             MRVL_PP2_INPUT_ERROR_BPOOL_PUT_BUFFS, 1);
341           vlib_buffer_free (vm, ptd->buffers, n_alloc);
342           goto done;
343         }
344
345       if (PREDICT_FALSE (i != n_alloc))
346         vlib_buffer_free (vm, ptd->buffers + i, n_alloc - i);
347
348       n_bufs -= i;
349     }
350
351 done:
352   return n_rx_packets;
353 }
354
355 uword
356 mrvl_pp2_input_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
357                    vlib_frame_t * frame)
358 {
359   u32 n_rx = 0;
360   mrvl_pp2_main_t *ppm = &mrvl_pp2_main;
361   vnet_hw_if_rxq_poll_vector_t *pv;
362
363   pv = vnet_hw_if_get_rxq_poll_vector (vm, node);
364
365   for (int i = 0; i < vec_len (pv); i++)
366     {
367       mrvl_pp2_if_t *ppif;
368       ppif = vec_elt_at_index (ppm->interfaces, pv[i].dev_instance);
369       if (ppif->flags & MRVL_PP2_IF_F_ADMIN_UP)
370         n_rx +=
371           mrvl_pp2_device_input_inline (vm, node, frame, ppif, pv[i].queue_id);
372     }
373   return n_rx;
374 }
375
376 /* *INDENT-OFF* */
377 VLIB_REGISTER_NODE (mrvl_pp2_input_node) = {
378   .function = mrvl_pp2_input_fn,
379   .flags = VLIB_NODE_FLAG_TRACE_SUPPORTED,
380   .name = "mrvl-pp2-input",
381   .sibling_of = "device-input",
382   .format_trace = format_mrvl_pp2_input_trace,
383   .type = VLIB_NODE_TYPE_INPUT,
384   .state = VLIB_NODE_STATE_POLLING,
385   .n_errors = MRVL_PP2_INPUT_N_ERROR,
386   .error_strings = mrvl_pp2_input_error_strings,
387 };
388
389 /* *INDENT-ON* */
390
391
392 /*
393  * fd.io coding-style-patch-verification: ON
394  *
395  * Local Variables:
396  * eval: (c-set-style "gnu")
397  * End:
398  */