9bf5a497fd1635f0d6e1aeb7c3cbc34e51bc59b3
[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
23 struct e10k_queue_ops {
24     errval_t (*update_txtail)(struct e10k_queue*, size_t);
25     errval_t (*update_rxtail)(struct e10k_queue*, size_t);
26 };
27
28 /**
29  * Context structure for RX descriptors. This is needed to implement RSC, since
30  * we need to be able to chain buffers together. */
31 struct e10k_queue_rxctx {
32     struct devq_buf         buf;
33     struct e10k_queue_rxctx *previous;
34     bool                    used;
35 };
36
37
38 struct region_entry {
39     uint32_t rid;
40     lpaddr_t phys;
41     lvaddr_t virt;
42     size_t size;
43     struct capref cap;
44     struct region_entry* next;
45 };
46
47 struct e10k_queue {
48     struct devq q;
49
50     // queue info
51     void* d;
52     bool enabled;
53     uint16_t id;
54     uint32_t rsbufsz;
55     bool use_vf; // use VF for this queue
56     bool use_rsc; // Receive Side Coalescing
57     bool use_vtd; // Virtual addressing (required for VF)
58     bool use_rxctx; // 
59     bool use_txhwb; 
60     size_t rxbufsz;
61     uint8_t pci_function; 
62     uint64_t mac;
63
64     // registered regions
65     struct region_entry* regions;   
66
67     // interrupt
68     bool use_irq;
69     uint8_t msix_intvec;
70     uint8_t msix_intdest;
71     size_t msix_index;
72     
73
74     // memory caps
75     struct capref                   rx_frame;
76     struct capref                   tx_frame;
77     struct capref                   txhwb_frame;
78     
79     struct capref                   regs;
80     // vf state
81     struct vf_state* vf;
82
83     // Communicatio to PF
84     struct e10k_vf_binding *binding;
85     bool bound;
86
87     // FIXME: Look for appropriate type for the _head/tail/size fields
88     e10k_q_tdesc_adv_wb_array_t*    tx_ring;
89     struct devq_buf*                tx_bufs;
90     bool*                           tx_isctx;
91     size_t                          tx_head;
92     size_t                          tx_tail, tx_lasttail;
93     size_t                          tx_size;
94     void*                           tx_hwb;
95
96     e10k_q_rdesc_adv_wb_array_t*    rx_ring;
97     struct e10k_queue_rxctx*        rx_context;
98     size_t                          rx_head;
99     size_t                          rx_tail;
100     size_t                          rx_size;
101
102     struct e10k_queue_ops           ops;
103     void*                           opaque;
104     
105 };
106
107 typedef struct e10k_queue e10k_queue_t;
108
109 // Does not initalize the queue struct itself
110 static inline void e10k_queue_init(struct e10k_queue* q, void* tx, size_t tx_size,
111                                    uint32_t* tx_hwb, void* rx, size_t rx_size, 
112                                    struct e10k_queue_ops* ops)
113 {
114     q->tx_ring = tx;
115     q->tx_bufs = calloc(tx_size, sizeof(struct devq_buf));
116     q->tx_isctx = calloc(tx_size, sizeof(bool));
117     q->tx_head = 0;
118     q->tx_tail = q->tx_lasttail = 0;
119     q->tx_size = tx_size;
120     q->tx_hwb = tx_hwb;
121
122     q->rx_ring = rx;
123     q->rx_context = calloc(rx_size, sizeof(*q->rx_context));
124     q->rx_head = 0;
125     q->rx_tail = 0;
126     q->rx_size = rx_size;
127
128     q->ops = *ops;
129
130     // Initialize ring memory with zero
131     memset(tx, 0, tx_size * e10k_q_tdesc_adv_wb_size);
132     memset(rx, 0, rx_size * e10k_q_rdesc_adv_wb_size);
133     memset(q->tx_isctx, 0, tx_size*sizeof(bool));
134     memset(q->rx_context, 0, tx_size*sizeof(*q->rx_context));
135 }
136
137 static inline int e10k_queue_add_txcontext(e10k_queue_t* q, uint8_t idx,
138                                            uint8_t maclen, uint16_t iplen, 
139                                            uint8_t l4len, e10k_q_l4_type_t l4t)
140 {
141     e10k_q_tdesc_adv_ctx_t d;
142     size_t tail = q->tx_tail;
143
144     memset(q->tx_ring[tail], 0, e10k_q_tdesc_adv_wb_size);
145
146     // TODO: Check if there is room in the queue
147     q->tx_isctx[tail] = true;
148     d = q->tx_ring[tail];
149
150     e10k_q_tdesc_adv_rd_dtyp_insert(d, e10k_q_adv_ctx);
151     e10k_q_tdesc_adv_rd_dext_insert(d, 1);
152
153     /* e10k_q_tdesc_adv_ctx_bcntlen_insert(d, 0x3f); */
154     e10k_q_tdesc_adv_ctx_idx_insert(d, idx);
155     e10k_q_tdesc_adv_ctx_maclen_insert(d, maclen);
156     e10k_q_tdesc_adv_ctx_iplen_insert(d, iplen);
157     e10k_q_tdesc_adv_ctx_ipv4_insert(d, 1);
158     e10k_q_tdesc_adv_ctx_l4len_insert(d, l4len);
159     e10k_q_tdesc_adv_ctx_l4t_insert(d, l4t);
160
161     q->tx_lasttail = q->tx_tail;
162     q->tx_tail = (tail + 1) % q->tx_size;
163     return 0;
164 }
165
166 // len is only length of this descriptor where length is the total length
167 static inline int e10k_queue_add_txbuf_ctx(e10k_queue_t* q, lpaddr_t phys,
168                                            regionid_t rid,
169                                            genoffset_t offset,
170                                            genoffset_t length,
171                                            genoffset_t valid_data, 
172                                            genoffset_t valid_length,
173                                            uint64_t flags,
174                                            bool first, bool last,
175                                            size_t len, uint8_t ctx,
176                                            bool ixsm, bool txsm)
177 {
178     e10k_q_tdesc_adv_rd_t d;
179     size_t tail = q->tx_tail;
180
181     memset(q->tx_ring[tail], 0, e10k_q_tdesc_adv_wb_size);
182
183     // TODO: Check if there is room in the queue
184     q->tx_isctx[tail] = false;
185     struct devq_buf* buf = &q->tx_bufs[tail];
186     buf->rid = rid;
187     buf->offset = offset;
188     buf->length = length;
189     buf->valid_data = valid_data;
190     buf->valid_length = valid_length;
191     buf->flags = flags;  
192     d = q->tx_ring[tail];
193
194     e10k_q_tdesc_adv_rd_buffer_insert(d, phys);
195     e10k_q_tdesc_adv_rd_dtalen_insert(d, len);
196     if (first) {
197         e10k_q_tdesc_adv_rd_paylen_insert(d, length);
198     }
199     e10k_q_tdesc_adv_rd_dtyp_insert(d, e10k_q_adv_data);
200     e10k_q_tdesc_adv_rd_dext_insert(d, 1);
201     e10k_q_tdesc_adv_rd_rs_insert(d, (last == 1));
202     e10k_q_tdesc_adv_rd_ifcs_insert(d, 1);
203     e10k_q_tdesc_adv_rd_eop_insert(d, last);
204
205     if (ctx != (uint8_t)-1) {
206         e10k_q_tdesc_adv_rd_idx_insert(d, ctx);
207         e10k_q_tdesc_adv_rd_cc_insert(d, 1);
208         e10k_q_tdesc_adv_rd_ixsm_insert(d, ixsm);
209         e10k_q_tdesc_adv_rd_txsm_insert(d, txsm);
210     }
211
212     q->tx_lasttail = q->tx_tail;
213     q->tx_tail = (tail + 1) % q->tx_size;
214     return 0;
215
216 }
217
218 static inline int e10k_queue_add_txbuf(e10k_queue_t* q, lpaddr_t phys,
219                                        regionid_t rid,
220                                        genoffset_t offset,
221                                        genoffset_t length,      
222                                        genoffset_t valid_data,
223                                        genoffset_t valid_length,
224                                        uint64_t flags,
225                                        bool first, bool last,
226                                        size_t len)
227 {
228     return e10k_queue_add_txbuf_ctx(q, phys, rid, offset, length,
229                                     valid_data, valid_length, 
230                                     flags, first, last, 
231                                     len, -1, false, false);
232 }
233
234 /*
235  * Reclaim 1 packet from the TX queue once it's handled by the
236  * card. Call multiple times to reclaim more packets.
237  *
238  * \param       q       Queue to check
239  * \param       opaque  Contains opaque data of reclaimed packet, if any
240  *
241  * \return true if packet can be reclaimed otherwise false
242  */
243 static inline bool e10k_queue_get_txbuf(e10k_queue_t* q, regionid_t* rid,   
244                                         genoffset_t* offset,
245                                         genoffset_t* length,
246                                         genoffset_t* valid_data,
247                                         genoffset_t* valid_length,
248                                         uint64_t* flags)
249 {
250     /* e10k_q_tdesc_adv_wb_t d; */
251     size_t head = q->tx_head;
252     bool result = false;
253
254     // If HWB is enabled, we can skip reading the descriptor if nothing happened
255     if (q->tx_hwb && *((uint32_t*)q->tx_hwb) == head) {
256         return false;
257     }
258
259     if(!q->tx_hwb) {
260         size_t idx = head;
261
262         // Skip over context and non-EOP descriptors
263         while(idx != q->tx_tail && q->tx_isctx[idx] && 
264               !e10k_q_tdesc_adv_wb_dd_extract(q->tx_ring[idx])) {
265             idx = (idx + 1) % q->tx_size;
266         }
267
268         if(idx == q->tx_tail) {
269             return false;
270         }
271     }
272
273     // That last packet got written out, now go reclaim from the head pointer.
274     if (!q->tx_isctx[head]) {
275         //*opaque = q->tx_opaque[head];
276         *rid = q->tx_bufs[head].rid;
277         *offset = q->tx_bufs[head].offset;
278         *length = q->tx_bufs[head].length;
279         *valid_data = q->tx_bufs[head].valid_data;
280         *valid_length = q->tx_bufs[head].valid_length;
281         *flags = q->tx_bufs[head].flags;
282
283         result = true;
284     }
285
286     /* memset(q->tx_ring[head], 0, e10k_q_tdesc_adv_wb_size); */
287     q->tx_head = (head + 1) % q->tx_size;
288     return result;
289 }
290
291 static inline errval_t e10k_queue_bump_txtail(e10k_queue_t* q)
292 {
293     return q->ops.update_txtail(q, q->tx_tail);
294 }
295
296 static inline size_t e10k_queue_free_txslots(e10k_queue_t* q)
297 {
298     size_t head = q->tx_head;
299     size_t tail = q->tx_tail;
300     size_t size = q->tx_size;
301
302     if (tail >= head) {
303         return size - (tail - head) - 1; // TODO: could this be off by 1?
304     } else {
305         return size - (tail + size - head) - 1; // TODO: off by 1?
306     }
307
308 }
309
310 static inline int e10k_queue_add_rxbuf(e10k_queue_t* q,
311                                        lpaddr_t phys,
312                                        regionid_t rid,
313                                        genoffset_t offset,
314                                        genoffset_t length,
315                                        genoffset_t valid_data,
316                                        genoffset_t valid_length,
317                                        uint64_t flags)
318 {
319     e10k_q_rdesc_adv_rd_t d;
320     size_t tail = q->rx_tail;
321     struct e10k_queue_rxctx *ctx;
322
323     ctx = q->rx_context + tail;
324     if (ctx->used) {
325         printf("e10k: Already used!\n");
326         return 1;
327     }
328
329     // TODO: Check if there is room in the queue
330     ctx->buf.rid = rid;
331     ctx->buf.offset = offset;
332     ctx->buf.length = length;
333     ctx->buf.valid_data = valid_data;
334     ctx->buf.valid_length = valid_length;
335     ctx->buf.flags = flags;
336     ctx->used = true;
337     d = (e10k_q_rdesc_adv_rd_t) q->rx_ring[tail];
338
339     e10k_q_rdesc_adv_rd_buffer_insert(d, phys);
340     // TODO: Does this make sense for RSC?
341     e10k_q_rdesc_adv_rd_hdr_buffer_insert(d, 0);
342
343     q->rx_tail = (tail + 1) % q->rx_size;
344
345     return 0;
346 }
347
348 static inline uint64_t e10k_queue_convert_rxflags(e10k_q_rdesc_adv_wb_t d)
349 {
350     uint64_t flags = 0;
351
352     // IP checksum
353     if (e10k_q_rdesc_adv_wb_ipcs_extract(d)) {
354         flags |= NETIF_RXFLAG_IPCHECKSUM;
355         if (!e10k_q_rdesc_adv_wb_ipe_extract(d)) {
356             flags |= NETIF_RXFLAG_IPCHECKSUM_GOOD;
357         }
358     }
359
360     // L4 checksum
361     if (e10k_q_rdesc_adv_wb_l4i_extract(d)) {
362         flags |= NETIF_RXFLAG_L4CHECKSUM;
363         if (!e10k_q_rdesc_adv_wb_l4e_extract(d)) {
364             flags |= NETIF_RXFLAG_L4CHECKSUM_GOOD;
365         }
366     }
367
368     // Packet type
369     if (e10k_q_rdesc_adv_wb_pt_ipv4_extract(d)) {
370         flags |= NETIF_RXFLAG_TYPE_IPV4;
371     }
372     if (e10k_q_rdesc_adv_wb_pt_tcp_extract(d)) {
373         flags |= NETIF_RXFLAG_TYPE_TCP;
374     }
375     if (e10k_q_rdesc_adv_wb_pt_udp_extract(d)) {
376         flags |= NETIF_RXFLAG_TYPE_UDP;
377     }
378
379     return flags;
380 }
381
382 static inline bool e10k_queue_get_rxbuf(e10k_queue_t* q, regionid_t* rid,
383                                         genoffset_t* offset,
384                                         genoffset_t* length,
385                                         genoffset_t* valid_data,
386                                         genoffset_t* valid_length,
387                                         uint64_t* flags,
388                                         int* last)
389 {
390     e10k_q_rdesc_adv_wb_t d;
391     size_t head = q->rx_head;
392     struct e10k_queue_rxctx *ctx;
393
394     d = q->rx_ring[head];
395     ctx = q->rx_context + head;
396
397     if (!e10k_q_rdesc_adv_wb_dd_extract(d)) {
398         return false;
399     }
400
401     // Barrier needed according to linux driver to make sure nothing else is
402     // read before the dd bit TODO: make sure
403     lfence();
404
405     // TODO add code for RSC
406
407     *flags = ctx->buf.flags;
408     // Set flags if it this is a descriptor with EOP
409     // TODO: with multi-part packets, we want these flags on the first packet
410     if (e10k_q_rdesc_adv_wb_eop_extract(d)) {
411         *flags = *flags | e10k_queue_convert_rxflags(d);
412     }
413
414     // TODO: Extract status (okay/error)
415     *last = e10k_q_rdesc_adv_wb_eop_extract(d);
416     *valid_length = e10k_q_rdesc_adv_wb_pkt_len_extract(d);
417     *rid = ctx->buf.rid;
418     *offset = ctx->buf.offset;
419     *length = ctx->buf.length;
420     *valid_data = ctx->buf.valid_data;
421
422     ctx->used = false;
423     memset(d, 0, e10k_q_rdesc_adv_wb_size);
424
425     q->rx_head = (head + 1) % q->rx_size;
426     return true;
427 }
428
429 static inline errval_t e10k_queue_bump_rxtail(e10k_queue_t* q)
430 {
431     return q->ops.update_rxtail(q, q->rx_tail);
432 }
433
434 static inline size_t e10k_queue_free_rxslots(e10k_queue_t* q)
435 {
436     size_t head = q->rx_head;
437     size_t tail = q->rx_tail;
438     size_t size = q->rx_size;
439
440     if (tail >= head) {
441         return size - (tail - head) - 1; // TODO: could this be off by 1?
442     } else {
443         return size - (tail + size - head) - 1; // TODO: off by 1?
444     }
445 }
446
447
448 #endif // ndef E10K_QUEUE_H_