e10k: driver working using legacy descriptors
[barrelfish] / lib / devif / backends / net / e10k / e10k_queue.h
1 /*
2  * Copyright (c) 2007-2011, 2017, ETH Zurich.
3  * All rights reserved.
4  *
5  * This file is distributed under the terms in the attached LICENSE file.
6  * If you do not find this file, copies can be found by writing to:
7  * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
8  */
9
10 #ifndef E10K_QUEUE_H_
11 #define E10K_QUEUE_H_
12
13 #include <string.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <net_interfaces/flags.h>
17
18 #include <devif/queue_interface.h>
19 #include "../../../queue_interface_internal.h"
20 #include <dev/e10k_q_dev.h>
21
22 #define LEGACY_DESC 1
23
24 struct e10k_queue_ops {
25     errval_t (*update_txtail)(struct e10k_queue*, size_t);
26     errval_t (*update_rxtail)(struct e10k_queue*, size_t);
27 };
28
29 /**
30  * Context structure for RX descriptors. This is needed to implement RSC, since
31  * we need to be able to chain buffers together. */
32 struct e10k_queue_rxctx {
33     struct devq_buf         buf;
34     struct e10k_queue_rxctx *previous;
35     bool                    used;
36 };
37
38
39 struct region_entry {
40     uint32_t rid;
41     lpaddr_t phys;
42     lvaddr_t virt;
43     size_t size;
44     struct capref cap;
45     struct region_entry* next;
46 };
47
48 struct e10k_queue {
49     struct devq q;
50
51     // queue info
52     void* d;
53     bool enabled;
54     uint16_t id;
55     uint32_t rsbufsz;
56     bool use_vf; // use VF for this queue
57     bool use_rsc; // Receive Side Coalescing
58     bool use_vtd; // Virtual addressing (required for VF)
59     bool use_rxctx; // 
60     bool use_txhwb; //
61     size_t rxbufsz;
62     uint8_t pci_function; 
63     uint64_t mac;
64
65     // registered regions
66     struct region_entry* regions;   
67
68     // interrupt
69     bool use_irq;
70     uint8_t msix_intvec;
71     uint8_t msix_intdest;
72     size_t msix_index;
73     
74
75     // memory caps
76     struct capref                   rx_frame;
77     struct capref                   tx_frame;
78     struct capref                   txhwb_frame;
79     
80     struct capref                   regs;
81     // vf state
82     struct vf_state* vf;
83
84     // Communicatio to PF
85     struct e10k_vf_binding *binding;
86     bool bound;
87
88     // FIXME: Look for appropriate type for the _head/tail/size fields
89     e10k_q_tdesc_adv_wb_array_t*    tx_ring;
90     struct devq_buf*                tx_bufs;
91     bool*                           tx_isctx;
92     size_t                          tx_head;
93     size_t                          tx_tail, tx_lasttail;
94     size_t                          tx_size;
95     void*                           tx_hwb;
96
97     e10k_q_rdesc_adv_wb_array_t*    rx_ring;
98     struct devq_buf*                rx_bufs;
99     struct e10k_queue_rxctx*        rx_context;
100     size_t                          rx_head;
101     size_t                          rx_tail;
102     size_t                          rx_size;
103
104     struct e10k_queue_ops           ops;
105     void*                           opaque;
106     
107 };
108
109 typedef struct e10k_queue e10k_queue_t;
110
111 // Does not initalize the queue struct itself
112 static inline void e10k_queue_init(struct e10k_queue* q, void* tx, size_t tx_size,
113                                    uint32_t* tx_hwb, void* rx, size_t rx_size, 
114                                    struct e10k_queue_ops* ops)
115 {
116     q->tx_ring = tx;
117     q->tx_bufs = calloc(tx_size, sizeof(struct devq_buf));
118     q->tx_isctx = calloc(tx_size, sizeof(bool));
119     q->tx_head = 0;
120     q->tx_tail = q->tx_lasttail = 0;
121     q->tx_size = tx_size;
122     q->tx_hwb = tx_hwb;
123
124     q->rx_ring = rx;
125     q->rx_bufs = calloc(rx_size, sizeof(struct devq_buf));
126     q->rx_context = calloc(rx_size, sizeof(*q->rx_context));
127     q->rx_head = 0;
128     q->rx_tail = 0;
129     q->rx_size = rx_size;
130
131     q->ops = *ops;
132
133     // Initialize ring memory with zero
134     memset(tx, 0, tx_size * e10k_q_tdesc_adv_wb_size);
135     memset(rx, 0, rx_size * e10k_q_rdesc_adv_wb_size);
136     memset(q->tx_isctx, 0, tx_size*sizeof(bool));
137     memset(q->rx_context, 0, tx_size*sizeof(*q->rx_context));
138 }
139
140 static inline int e10k_queue_add_txcontext(e10k_queue_t* q, uint8_t idx,
141                                            uint8_t maclen, uint16_t iplen, 
142                                            uint8_t l4len, e10k_q_l4_type_t l4t)
143 {
144     e10k_q_tdesc_adv_ctx_t d;
145     size_t tail = q->tx_tail;
146
147     memset(q->tx_ring[tail], 0, e10k_q_tdesc_adv_wb_size);
148
149     // TODO: Check if there is room in the queue
150     q->tx_isctx[tail] = true;
151     d = q->tx_ring[tail];
152
153     e10k_q_tdesc_adv_rd_dtyp_insert(d, e10k_q_adv_ctx);
154     e10k_q_tdesc_adv_rd_dext_insert(d, 1);
155
156     /* e10k_q_tdesc_adv_ctx_bcntlen_insert(d, 0x3f); */
157     e10k_q_tdesc_adv_ctx_idx_insert(d, idx);
158     e10k_q_tdesc_adv_ctx_maclen_insert(d, maclen);
159     e10k_q_tdesc_adv_ctx_iplen_insert(d, iplen);
160     e10k_q_tdesc_adv_ctx_ipv4_insert(d, 1);
161     e10k_q_tdesc_adv_ctx_l4len_insert(d, l4len);
162     e10k_q_tdesc_adv_ctx_l4t_insert(d, l4t);
163
164     q->tx_lasttail = q->tx_tail;
165     q->tx_tail = (tail + 1) % q->tx_size;
166     return 0;
167 }
168
169 // len is only length of this descriptor where length is the total length
170 static inline int e10k_queue_add_txbuf_ctx(e10k_queue_t* q, lpaddr_t phys,
171                                            regionid_t rid,
172                                            genoffset_t offset,
173                                            genoffset_t length,
174                                            genoffset_t valid_data, 
175                                            genoffset_t valid_length,
176                                            uint64_t flags,
177                                            bool first, bool last,
178                                            size_t len, uint8_t ctx,
179                                            bool ixsm, bool txsm)
180 {
181     e10k_q_tdesc_adv_rd_t d;
182     size_t tail = q->tx_tail;
183
184     memset(q->tx_ring[tail], 0, e10k_q_tdesc_adv_wb_size);
185
186     // TODO: Check if there is room in the queue
187     q->tx_isctx[tail] = false;
188     struct devq_buf* buf = &q->tx_bufs[tail];
189     buf->rid = rid;
190     buf->offset = offset;
191     buf->length = length;
192     buf->valid_data = valid_data;
193     buf->valid_length = valid_length;
194     buf->flags = flags;  
195     d = q->tx_ring[tail];
196
197     e10k_q_tdesc_adv_rd_buffer_insert(d, phys);
198     e10k_q_tdesc_adv_rd_dtalen_insert(d, len);
199     if (first) {
200         e10k_q_tdesc_adv_rd_paylen_insert(d, length);
201     }
202     e10k_q_tdesc_adv_rd_dtyp_insert(d, e10k_q_adv_data);
203     e10k_q_tdesc_adv_rd_dext_insert(d, 1);
204     e10k_q_tdesc_adv_rd_rs_insert(d, (last == 1));
205     e10k_q_tdesc_adv_rd_ifcs_insert(d, 1);
206     e10k_q_tdesc_adv_rd_eop_insert(d, last);
207
208     if (ctx != (uint8_t)-1) {
209         e10k_q_tdesc_adv_rd_idx_insert(d, ctx);
210         e10k_q_tdesc_adv_rd_cc_insert(d, 1);
211         e10k_q_tdesc_adv_rd_ixsm_insert(d, ixsm);
212         e10k_q_tdesc_adv_rd_txsm_insert(d, txsm);
213     }
214
215     q->tx_lasttail = q->tx_tail;
216     q->tx_tail = (tail + 1) % q->tx_size;
217     return 0;
218
219 }
220
221
222 static inline int e10k_queue_add_txbuf_legacy(e10k_queue_t* q, lpaddr_t phys,
223                                        regionid_t rid,
224                                        genoffset_t offset,
225                                        genoffset_t length,      
226                                        genoffset_t valid_data,
227                                        genoffset_t valid_length,
228                                        uint64_t flags,
229                                        bool first, bool last,
230                                        size_t len)
231 {
232     e10k_q_tdesc_legacy_t d;
233     size_t tail = q->tx_tail;
234
235
236     struct devq_buf* buf = &q->tx_bufs[tail];
237     buf->rid = rid;
238     buf->offset = offset;
239     buf->length = length;
240     buf->valid_data = valid_data;
241     buf->valid_length = valid_length;
242     buf->flags = flags;  
243
244     d = q->tx_ring[tail];
245
246     e10k_q_tdesc_legacy_buffer_insert(d, phys);
247     e10k_q_tdesc_legacy_length_insert(d, len);
248     // OPTIMIZATION: Maybe only set rs on last packet?
249     e10k_q_tdesc_legacy_rs_insert(d, (last == 1));
250     e10k_q_tdesc_legacy_ifcs_insert(d,  1);
251     e10k_q_tdesc_legacy_eop_insert(d, last);
252
253     q->tx_tail = (tail + 1) % q->tx_size;
254     return 0;
255 }
256
257 static inline int e10k_queue_add_txbuf(e10k_queue_t* q, lpaddr_t phys,
258                                        regionid_t rid,
259                                        genoffset_t offset,
260                                        genoffset_t length,      
261                                        genoffset_t valid_data,
262                                        genoffset_t valid_length,
263                                        uint64_t flags,
264                                        bool first, bool last,
265                                        size_t len)
266 {
267 #ifdef LEGACY_DESC
268         return e10k_queue_add_txbuf_legacy(q, phys, rid, offset, length,
269                                     valid_data, valid_length, 
270                                     flags, first, last, 
271                                     len);
272 #else
273         return e10k_queue_add_txbuf_ctx(q, phys, rid, offset, length,
274                                     valid_data, valid_length, 
275                                     flags, first, last, 
276                                     len, -1, false, false);
277 #endif
278 }
279
280 /*
281  * Reclaim 1 packet from the TX queue once it's handled by the
282  * card. Call multiple times to reclaim more packets.
283  *
284  * \param       q       Queue to check
285  * \param       opaque  Contains opaque data of reclaimed packet, if any
286  *
287  * \return true if packet can be reclaimed otherwise false
288  */
289 static inline bool e10k_queue_get_txbuf_avd(e10k_queue_t* q, regionid_t* rid,   
290                                         genoffset_t* offset,
291                                         genoffset_t* length,
292                                         genoffset_t* valid_data,
293                                         genoffset_t* valid_length,
294                                         uint64_t* flags)
295 {
296     /* e10k_q_tdesc_adv_wb_t d; */
297     size_t head = q->tx_head;
298     bool result = false;
299
300     // If HWB is enabled, we can skip reading the descriptor if nothing happened
301     if (q->tx_hwb && *((uint32_t*)q->tx_hwb) == head) {
302         return false;
303     }
304
305     if(!q->tx_hwb) {
306         size_t idx = head;
307
308         // Skip over context and non-EOP descriptors
309         while(idx != q->tx_tail && q->tx_isctx[idx] && 
310               !e10k_q_tdesc_adv_wb_dd_extract(q->tx_ring[idx])) {
311             idx = (idx + 1) % q->tx_size;
312         }
313
314         if(idx == q->tx_tail) {
315             return false;
316         }
317     }
318
319     // That last packet got written out, now go reclaim from the head pointer.
320     if (!q->tx_isctx[head]) {
321         //*opaque = q->tx_opaque[head];
322         *rid = q->tx_bufs[head].rid;
323         *offset = q->tx_bufs[head].offset;
324         *length = q->tx_bufs[head].length;
325         *valid_data = q->tx_bufs[head].valid_data;
326         *valid_length = q->tx_bufs[head].valid_length;
327         *flags = q->tx_bufs[head].flags;
328
329         result = true;
330     }
331
332     /* memset(q->tx_ring[head], 0, e10k_q_tdesc_adv_wb_size); */
333     q->tx_head = (head + 1) % q->tx_size;
334     return result;
335 }
336
337 static inline bool e10k_queue_get_txbuf_legacy(e10k_queue_t* q, regionid_t* rid,   
338                                         genoffset_t* offset,
339                                         genoffset_t* length,
340                                         genoffset_t* valid_data,
341                                         genoffset_t* valid_length,
342                                         uint64_t* flags)
343 {
344
345     e10k_q_tdesc_legacy_t d;
346     size_t head = q->tx_head;
347
348     d = q->tx_ring[head];
349     if (e10k_q_tdesc_legacy_dd_extract(d)) {
350
351         *rid = q->tx_bufs[head].rid;
352         *offset = q->tx_bufs[head].offset;
353         *length = q->tx_bufs[head].length;
354         *valid_data = q->tx_bufs[head].valid_data;
355         *valid_length = q->tx_bufs[head].valid_length;
356         *flags = q->tx_bufs[head].flags;
357         memset(d, 0, e10k_q_tdesc_legacy_size);
358
359         q->tx_head = (head + 1) % q->tx_size;
360         return true;
361     } 
362
363     if (q->tx_hwb) {
364         head = *((uint32_t*) q->tx_hwb);
365         if (q->tx_head == head) {
366             return false;
367         } else {
368             *rid = q->tx_bufs[q->tx_head].rid;
369             *offset = q->tx_bufs[q->tx_head].offset;
370             *length = q->tx_bufs[q->tx_head].length;
371             *valid_data = q->tx_bufs[q->tx_head].valid_data;
372             *valid_length = q->tx_bufs[q->tx_head].valid_length;
373             *flags = q->tx_bufs[q->tx_head].flags;
374             memset(d, 0, e10k_q_tdesc_legacy_size);
375
376             q->tx_head = (q->tx_head + 1) % q->tx_size;
377             return true;
378         }
379     }
380
381     return false;
382 }
383
384 static inline bool e10k_queue_get_txbuf(e10k_queue_t* q, regionid_t* rid,   
385                                         genoffset_t* offset,
386                                         genoffset_t* length,
387                                         genoffset_t* valid_data,
388                                         genoffset_t* valid_length,
389                                         uint64_t* flags)
390 {
391 #ifdef LEGACY_DESC
392         return e10k_queue_get_txbuf_legacy(q, rid, offset, length, valid_data, 
393                                            valid_length, flags);
394 #else
395         return e10k_queue_get_txbuf_avd(q, rid, offset, length, valid_data, 
396                                         valid_length, flags);
397 #endif
398 }
399
400 static inline errval_t e10k_queue_bump_txtail(e10k_queue_t* q)
401 {
402     return q->ops.update_txtail(q, q->tx_tail);
403 }
404
405 static inline size_t e10k_queue_free_txslots(e10k_queue_t* q)
406 {
407     size_t head = q->tx_head;
408     size_t tail = q->tx_tail;
409     size_t size = q->tx_size;
410
411     if (tail >= head) {
412         return size - (tail - head) - 1; // TODO: could this be off by 1?
413     } else {
414         return size - (tail + size - head) - 1; // TODO: off by 1?
415     }
416
417 }
418
419 static inline int e10k_queue_add_rxbuf_adv(e10k_queue_t* q,
420                                        lpaddr_t phys,
421                                        regionid_t rid,
422                                        genoffset_t offset,
423                                        genoffset_t length,
424                                        genoffset_t valid_data,
425                                        genoffset_t valid_length,
426                                        uint64_t flags)
427 {
428     e10k_q_rdesc_adv_rd_t d;
429     size_t tail = q->rx_tail;
430     struct e10k_queue_rxctx *ctx;
431
432     ctx = q->rx_context + tail;
433     if (ctx->used) {
434         printf("e10k: Already used!\n");
435         return 1;
436     }
437
438     // TODO: Check if there is room in the queue
439     ctx->buf.rid = rid;
440     ctx->buf.offset = offset;
441     ctx->buf.length = length;
442     ctx->buf.valid_data = valid_data;
443     ctx->buf.valid_length = valid_length;
444     ctx->buf.flags = flags;
445     ctx->used = true;
446     d = (e10k_q_rdesc_adv_rd_t) q->rx_ring[tail];
447
448     e10k_q_rdesc_adv_rd_buffer_insert(d, phys);
449     // TODO: Does this make sense for RSC?
450     e10k_q_rdesc_adv_rd_hdr_buffer_insert(d, 0);
451
452     q->rx_tail = (tail + 1) % q->rx_size;
453
454     return 0;
455 }
456
457 static inline int e10k_queue_add_rxbuf_legacy(e10k_queue_t* q,
458                                        lpaddr_t phys,
459                                        regionid_t rid,
460                                        genoffset_t offset,
461                                        genoffset_t length,
462                                        genoffset_t valid_data,
463                                        genoffset_t valid_length,
464                                        uint64_t flags)
465 {
466     e10k_q_rdesc_legacy_t d;
467     size_t tail = q->rx_tail;
468
469
470     struct devq_buf* buf = &q->rx_bufs[tail];
471     buf->rid = rid;
472     buf->offset = offset;
473     buf->length = length;
474     buf->valid_data = valid_data;
475     buf->valid_length = valid_length;
476     buf->flags = flags;  
477     
478     d = q->rx_ring[tail];
479
480     e10k_q_rdesc_legacy_buffer_insert(d, phys);
481
482     q->rx_tail = (tail + 1) % q->rx_size;
483
484     return 0;
485 }
486
487
488 static inline int e10k_queue_add_rxbuf(e10k_queue_t* q,
489                                        lpaddr_t phys,
490                                        regionid_t rid,
491                                        genoffset_t offset,
492                                        genoffset_t length,
493                                        genoffset_t valid_data,
494                                        genoffset_t valid_length,
495                                        uint64_t flags)
496 {
497 #ifdef LEGACY_DESC
498     return e10k_queue_add_rxbuf_legacy(q, phys, rid, offset, length, valid_data,
499                                        valid_length, flags);
500 #else
501     return e10k_queue_add_rxbuf_adv(q, phys, rid, offset, length, valid_data,
502                                     valid_length, flags);
503 #endif
504 }
505 static inline uint64_t e10k_queue_convert_rxflags(e10k_q_rdesc_adv_wb_t d)
506 {
507     uint64_t flags = 0;
508
509     // IP checksum
510     if (e10k_q_rdesc_adv_wb_ipcs_extract(d)) {
511         flags |= NETIF_RXFLAG_IPCHECKSUM;
512         if (!e10k_q_rdesc_adv_wb_ipe_extract(d)) {
513             flags |= NETIF_RXFLAG_IPCHECKSUM_GOOD;
514         }
515     }
516
517     // L4 checksum
518     if (e10k_q_rdesc_adv_wb_l4i_extract(d)) {
519         flags |= NETIF_RXFLAG_L4CHECKSUM;
520         if (!e10k_q_rdesc_adv_wb_l4e_extract(d)) {
521             flags |= NETIF_RXFLAG_L4CHECKSUM_GOOD;
522         }
523     }
524
525     // Packet type
526     if (e10k_q_rdesc_adv_wb_pt_ipv4_extract(d)) {
527         flags |= NETIF_RXFLAG_TYPE_IPV4;
528     }
529     if (e10k_q_rdesc_adv_wb_pt_tcp_extract(d)) {
530         flags |= NETIF_RXFLAG_TYPE_TCP;
531     }
532     if (e10k_q_rdesc_adv_wb_pt_udp_extract(d)) {
533         flags |= NETIF_RXFLAG_TYPE_UDP;
534     }
535
536     return flags;
537 }
538
539 static inline bool e10k_queue_get_rxbuf_avd(e10k_queue_t* q, regionid_t* rid,
540                                         genoffset_t* offset,
541                                         genoffset_t* length,
542                                         genoffset_t* valid_data,
543                                         genoffset_t* valid_length,
544                                         uint64_t* flags,
545                                         int* last)
546 {
547     e10k_q_rdesc_adv_wb_t d;
548     size_t head = q->rx_head;
549     struct e10k_queue_rxctx *ctx;
550
551     d = q->rx_ring[head];
552     ctx = q->rx_context + head;
553
554     if (!e10k_q_rdesc_adv_wb_dd_extract(d)) {
555         return false;
556     }
557
558     // Barrier needed according to linux driver to make sure nothing else is
559     // read before the dd bit TODO: make sure
560     lfence();
561
562     // TODO add code for RSC
563
564     *flags = ctx->buf.flags;
565     // Set flags if it this is a descriptor with EOP
566     // TODO: with multi-part packets, we want these flags on the first packet
567     if (e10k_q_rdesc_adv_wb_eop_extract(d)) {
568         *flags = *flags | e10k_queue_convert_rxflags(d);
569     }
570
571     // TODO: Extract status (okay/error)
572     *last = e10k_q_rdesc_adv_wb_eop_extract(d);
573     *valid_length = e10k_q_rdesc_adv_wb_pkt_len_extract(d);
574     *rid = ctx->buf.rid;
575     *offset = ctx->buf.offset;
576     *length = ctx->buf.length;
577     *valid_data = ctx->buf.valid_data;
578
579     ctx->used = false;
580     memset(d, 0, e10k_q_rdesc_adv_wb_size);
581
582     q->rx_head = (head + 1) % q->rx_size;
583     return true;
584 }
585
586
587 static inline bool e10k_queue_get_rxbuf_legacy(e10k_queue_t* q, regionid_t* rid,
588                                         genoffset_t* offset,
589                                         genoffset_t* length,
590                                         genoffset_t* valid_data,
591                                         genoffset_t* valid_length,
592                                         uint64_t* flags,
593                                         int* last)
594 {
595
596     e10k_q_rdesc_legacy_t d;
597     size_t head = q->rx_head;
598     struct devq_buf* buf = &q->rx_bufs[head];
599
600     d = q->rx_ring[head];
601     if (e10k_q_rdesc_legacy_dd_extract(d)) {
602         *last = e10k_q_rdesc_legacy_eop_extract(d);
603         *valid_length = e10k_q_rdesc_legacy_length_extract(d);
604
605         *rid = buf->rid;
606         *offset = buf->offset;
607         *length = buf->length;
608         *valid_data = buf->valid_data;
609         *flags = buf->flags;
610
611         memset(d, 0, e10k_q_rdesc_legacy_size);
612
613         q->rx_head = (head + 1) % q->rx_size;
614         return true;
615     } else {
616         return false;
617     }
618 }
619
620
621 static inline bool e10k_queue_get_rxbuf(e10k_queue_t* q, regionid_t* rid,
622                                         genoffset_t* offset,
623                                         genoffset_t* length,
624                                         genoffset_t* valid_data,
625                                         genoffset_t* valid_length,
626                                         uint64_t* flags,
627                                         int* last)
628 {
629 #ifdef LEGACY_DESC
630        return e10k_queue_get_rxbuf_legacy(q, rid, offset, length, valid_data, valid_length,
631                                     flags, last);
632 #else 
633        return e10k_queue_get_rxbuf_avd(q, rid, offset, length, valid_data, valid_length,
634                                        flags, last);
635 #endif
636 }
637
638 static inline errval_t e10k_queue_bump_rxtail(e10k_queue_t* q)
639 {
640     return q->ops.update_rxtail(q, q->rx_tail);
641 }
642
643 static inline size_t e10k_queue_free_rxslots(e10k_queue_t* q)
644 {
645     size_t head = q->rx_head;
646     size_t tail = q->rx_tail;
647     size_t size = q->rx_size;
648
649     if (tail >= head) {
650         return size - (tail - head) - 1; // TODO: could this be off by 1?
651     } else {
652         return size - (tail + size - head) - 1; // TODO: off by 1?
653     }
654 }
655
656
657 #endif // ndef E10K_QUEUE_H_