DeviceQueue: Solarflare driver removed mac stats cap transfer
[barrelfish] / usr / drivers / solarflare / sfn5122f_qdriver.c
1 /* Copyright (c) 2007-2011, ETH Zurich.
2  * All rights reserved.
3  *
4  * This file is distributed under the terms in the attached LICENSE file.
5  * If you do not find this file, copies can be found by writing to:
6  * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
7  */
8 #include <stdlib.h>
9 #include <string.h>
10 #include <stdarg.h>
11
12 #include <net_queue_manager/net_queue_manager.h>
13 #include <barrelfish/nameservice_client.h>
14 #include <barrelfish/spawn_client.h>
15 #include <barrelfish/debug.h>
16 #include <barrelfish/deferred.h>
17 #include <pci/pci.h>
18
19
20 #include <if/sfn5122f_defs.h>
21 #include <dev/sfn5122f_dev.h>
22 #include <dev/sfn5122f_q_dev.h>
23
24 #include "helper.h"
25 #include "sfn5122f.h"
26 #include "sfn5122f_queue.h"
27 #include "sfn5122f_debug.h"
28 #include "buffer_tbl.h"
29
30 /******************************************************************************/
31 /* Prototypes */
32
33 static void idc_register_queue_memory(uint8_t queue,
34                                       struct capref tx_frame,
35                                       struct capref ev_frame,
36                                       struct capref rx_frame,
37                                       uint32_t rxbufsz,
38                                       uint8_t vector,
39                                       coreid_t core);
40
41 static void idc_terminate_queue(void);
42
43 void qd_queue_init_data(struct sfn5122f_binding *b, struct capref registers,
44         uint64_t macaddr);
45 void qd_queue_memory_registered(struct sfn5122f_binding *b);
46 void qd_write_queue_tails(struct sfn5122f_binding *b);
47
48 void qd_argument(const char *arg);
49 void qd_main(void);
50 int main(int argc, char **argv) __attribute__((weak));
51
52 /* Global state */
53 static const char* service_name = "sfn5122f";
54
55 /** Binding to the internal sfn5122f management service */
56 static struct sfn5122f_binding *binding = NULL;
57
58 /** Queue index for this manager instance */
59 static int qi = -1;
60
61 /** Mackerel handle for device */
62 static sfn5122f_t *d = NULL;
63
64 /** Queue handle for queue management library */
65 static sfn5122f_queue_t *q;
66
67 /** MAC address to be used */
68 static uint64_t mac_address = 0;
69
70 /** Indicates if the initialization is done */
71 static int initialized = 0;
72
73 /**
74  * Indicates whether we should rely on cache coherence for the descriptor
75  * rings.
76  */
77 static bool cache_coherence = true;
78
79 /** Indicates whether Interrupts should be used */
80 static bool use_interrupts = false;
81 static bool use_msix = false;
82 static coreid_t core = 0;
83 static uint8_t vector = 0;
84
85 /** Capability for hardware TX ring */
86 static struct capref tx_frame;
87
88 /** Capability for hardware RX ring */
89 static struct capref rx_frame;
90
91 /** Capability for hardware EV ring */
92 static struct capref ev_frame;
93
94 //static void* mac_virt;
95 uint64_t mac_stats_array[NUM_MAC_STATS];
96
97 /**  Userspace networking enable  */
98 static bool userspace = 0;
99
100 /******************************************************************************/
101 /* Transmit path */
102 static uint64_t find_tx_free_slot_count_fn(void)
103 {
104     return sfn5122f_queue_free_txslots(q);
105 }
106
107 static errval_t transmit_pbuf_list_fn(struct driver_buffer *buffers,
108                                       size_t                count)
109 {
110     size_t i;
111     
112     if (find_tx_free_slot_count_fn() < count) {
113         return ETHERSRV_ERR_CANT_TRANSMIT;
114     }
115
116     for (i = 0; i < count; i++) {
117         sfn5122f_queue_add_txbuf(q, buffers[i].pa,
118                                  buffers[i].len, buffers[i].opaque, 
119                                  (i == count - 1)); 
120     }
121
122     sfn5122f_queue_bump_txtail(q);
123
124     return SYS_ERR_OK;
125 }
126
127 static bool handle_free_tx_slot_fn(void)
128 {
129     return false;
130 }
131
132
133
134 /******************************************************************************/
135 /* Receive path */
136
137 static uint64_t find_rx_free_slot_count_fn(void)
138 {
139    return sfn5122f_queue_free_rxslots(q);
140 }
141
142 static errval_t register_rx_buffer_fn(uint64_t paddr, void *vaddr, void *opaque)
143 {
144     if (find_rx_free_slot_count_fn() == 0) {
145         printf("SFN5122F_%d: Not enough space in RX ring, not adding buffer\n", 
146                 qi);
147         return ETHERSRV_ERR_TOO_MANY_BUFFERS;
148     }
149
150     sfn5122f_queue_add_rxbuf(q, paddr, opaque);
151     sfn5122f_queue_bump_rxtail(q);
152     
153     return SYS_ERR_OK;
154 }
155
156
157 /*  polling event queue for new events         */
158 static size_t check_for_new_events(void)
159 {
160     size_t len = 0;
161     size_t count = 0;
162     uint8_t ev_code;
163     // TODO add constant
164     struct driver_rx_buffer buf[16];
165
166     // need to block until initalized
167     if (!initialized) {
168         return 0;
169     }
170  
171     ev_code = sfn5122f_get_event_code(q);
172     while (ev_code != 15 && count < 100){
173           void *op = NULL;
174           ev_code = sfn5122f_get_event_code(q);
175           switch(ev_code){
176    
177               case EV_CODE_RX:
178                    // TODO multiple packets
179                    if (sfn5122f_queue_handle_rx_ev(q, &op, &len) == SYS_ERR_OK) {
180                         buf[0].len = len;
181                         buf[0].opaque = op;
182                         process_received_packet(buf, 1, 0);
183                    } else {
184                         // TODO how to tell the the upper layer that it can reuse
185                         // the rx buffer
186                    }
187
188                    DEBUG_QUEUE(" RX_EV Q_ID: %d len %ld \n", qi, len);
189                    sfn5122f_queue_bump_evhead(q);
190                    break;
191               case EV_CODE_TX:
192                    if (sfn5122f_queue_handle_tx_ev(q, &op) == SYS_ERR_OK) {
193                         DEBUG_QUEUE("TX EVENT OK %d \n", qi);
194                         handle_tx_done(op); 
195                    } else {
196                         DEBUG_QUEUE("TX EVENT ERR %d \n", qi);
197                    }
198                    sfn5122f_queue_bump_evhead(q);
199                    break;
200               case EV_CODE_DRV:
201                    //DEBUG_QUEUE("DRIVER EVENT %d\n", qi);
202                    sfn5122f_handle_drv_ev(q, qi);
203                    sfn5122f_queue_bump_evhead(q);
204                    break;
205               case EV_CODE_DRV_GEN:
206                    DEBUG_QUEUE("DRIVER GENERATED EVENT \n");
207                    sfn5122f_queue_bump_evhead(q);
208                    break;
209               case EV_CODE_USER:
210                    DEBUG_QUEUE("USER EVENT \n");
211                    sfn5122f_queue_bump_evhead(q);
212                    break;
213               case EV_CODE_MCDI:
214                    //DEBUG_QUEUE("MCDI EVENT \n");
215                    sfn5122f_queue_handle_mcdi_event(q);
216                    sfn5122f_queue_bump_evhead(q);
217                    break;
218               case EV_CODE_GLOBAL:
219                    DEBUG_QUEUE("GLOBAL EVENT \n");
220                    sfn5122f_queue_bump_evhead(q);
221                    break;
222           }
223           count++;
224     }
225     /* update event queue tail */
226     //if (count > 0) {
227         sfn5122f_evq_rptr_reg_wr(d, qi, q->ev_head);
228     //}
229
230     return count-1;
231 }
232
233 /**  Misc             */
234 static errval_t update_rxtail(void *opaque, size_t tail)
235 {
236     assert(d != NULL);
237     uint64_t reg = 0;
238
239     reg = sfn5122f_rx_desc_upd_reg_hi_rx_desc_wptr_insert(reg, tail);
240     /* don't want to push an additional rx descriptor with the write pointer */
241     reg = sfn5122f_rx_desc_upd_reg_hi_rx_desc_push_cmd_insert(reg, 0);
242     /* the lower register will be ignored   */
243     sfn5122f_rx_desc_upd_reg_lo_wr(d, qi, 0);
244     sfn5122f_rx_desc_upd_reg_hi_wr(d, qi, reg);
245
246     return SYS_ERR_OK;
247 }
248
249 static errval_t update_txtail(void *opaque, size_t tail)
250 {
251     assert(d != NULL);
252     uint64_t reg = 0;
253     reg = sfn5122f_tx_desc_upd_reg_hi_tx_desc_wptr_insert(reg, tail);
254     /* don't want to push an additional tx descriptor with the write pointer */
255     reg = sfn5122f_tx_desc_upd_reg_hi_tx_desc_push_cmd_insert(reg, 0);
256     reg = sfn5122f_tx_desc_upd_reg_hi_tx_desc_insert(reg, 0);
257
258     /*  the lower register will be ignored  */
259     sfn5122f_tx_desc_upd_reg_lo_wr(d, qi, 0);
260     sfn5122f_tx_desc_upd_reg_hi_wr(d, qi, reg);
261     return SYS_ERR_OK;
262 }
263
264 /** Callback to get card's MAC address */
265 static void get_mac_address_fn(uint8_t* mac)
266 {
267     memcpy(mac, &mac_address, 6);
268 }
269 /******************************************************************************/
270 /* Interrupts */
271
272 static void qd_interrupt(void)
273 {
274     size_t count;
275     
276     count = check_for_new_events();
277     if (count <= 0) {
278         DEBUG_QUEUE("qd_int_%d: qid=%d no events \n", disp_get_core_id(), qi);
279     } else {
280         DEBUG_QUEUE("qd_int_%d: qid=%d events processed=%ld \n", disp_get_core_id(), 
281                     qi, count);
282     }
283
284 }
285
286 static void interrupt_handler(void *data)
287 {
288     qd_interrupt();
289 }
290
291 /******************************************************************************/
292 /* Device/queue initialization */
293
294 /** Allocate queue n and return handle for queue manager */
295
296 static void setup_queue(void)
297 {
298     size_t tx_size, rx_size, ev_size;
299     void *tx_virt, *rx_virt, *ev_virt;
300     vregion_flags_t flags_vreg;
301     
302     struct sfn5122f_queue_ops ops = {
303         .update_txtail = update_txtail,
304         .update_rxtail = update_rxtail
305      };
306
307     // Decide on which flags to use for the mappings
308     flags_vreg = (cache_coherence ? VREGION_FLAGS_READ_WRITE :
309                                VREGION_FLAGS_READ_WRITE_NOCACHE);
310
311    
312     /* Allocate memory for descriptor rings  
313        No difference for userspace networking*/
314     tx_size = sfn5122f_q_tx_ker_desc_size * TX_ENTRIES;
315     tx_virt = alloc_map_frame(flags_vreg, tx_size, &tx_frame);
316
317     assert(tx_virt != NULL);
318
319     if (!userspace) {
320          rx_size = sfn5122f_q_rx_ker_desc_size * RX_ENTRIES;
321     } else {
322          rx_size = sfn5122f_q_rx_user_desc_size * RX_ENTRIES;
323     }
324
325     rx_virt = alloc_map_frame(flags_vreg, rx_size, &rx_frame);
326     assert(rx_virt != NULL);
327
328     ev_size = sfn5122f_q_event_entry_size * EV_ENTRIES;
329     ev_virt = alloc_map_frame(flags_vreg, ev_size, &ev_frame);
330     assert(ev_virt != NULL);
331
332     if (use_interrupts && use_msix) {
333         DEBUG_QUEUE("Enabling MSI-X interrupts\n");
334         errval_t err = pci_setup_inthandler(interrupt_handler, NULL, &vector);
335         assert(err_is_ok(err));
336         core = disp_get_core_id();
337     } else {
338         if (use_interrupts) {
339             DEBUG_QUEUE("Enabling legacy interrupts\n");
340         }
341         vector = 0;
342         core = 0;
343     }
344
345
346     // Initialize queue manager
347     q = sfn5122f_queue_init(tx_virt, TX_ENTRIES, rx_virt, RX_ENTRIES,
348                             ev_virt, EV_ENTRIES, &ops,  NULL, userspace);
349     idc_register_queue_memory(qi, tx_frame, rx_frame,
350                               ev_frame, MTU_MAX, vector, core);
351
352 }
353
354 /** Terminate this queue driver */
355 static void terminate_queue_fn(void)
356 {
357     idc_terminate_queue();
358 }
359
360 /******************************************************************************/
361 /* Management interface implemetation */
362
363 /** Request device register cap from card driver */
364
365 static void idc_request_device_info(void)
366 {
367
368     errval_t r;
369     DEBUG_QUEUE("idc_request_device_info()\n");
370
371     r = sfn5122f_request_device_info__tx(binding, NOP_CONT);
372     // TODO: handle busy
373     assert(err_is_ok(r));
374 }
375
376 /** Send memory caps to card driver */
377 static void idc_register_queue_memory(uint8_t queue,
378                                       struct capref tx,
379                                       struct capref rx,
380                                       struct capref ev,
381                                       uint32_t rxbufsz,
382                                       uint8_t vec,
383                                       coreid_t cid)
384 {
385
386     errval_t r;
387     DEBUG_QUEUE("idc_register_queue_memory()\n");
388
389     r = sfn5122f_register_queue_memory__tx(binding, NOP_CONT, queue,
390                                            tx, rx, ev, rxbufsz, 
391                                            use_interrupts, userspace,
392                                            vec, cid);
393     // TODO: handle busy
394     assert(err_is_ok(r));
395 }
396
397 // Callback from device manager
398 void qd_queue_init_data(struct sfn5122f_binding *b, struct capref registers,
399                         uint64_t macaddr)
400 {
401     struct frame_identity frameid = { .base = 0, .bytes = 0 };
402     errval_t err;
403     void *virt;
404
405     DEBUG_QUEUE("idc_queue_init_data\n");
406
407     mac_address = macaddr;
408
409     // Map device registers
410     invoke_frame_identify(registers, &frameid);
411     err = vspace_map_one_frame_attr(&virt, frameid.bytes, registers,
412             VREGION_FLAGS_READ_WRITE_NOCACHE, NULL, NULL);
413
414     assert(err_is_ok(err));
415
416     // Initialize mackerel device
417     d = malloc(sizeof(*d));
418     sfn5122f_initialize(d, virt);
419     // Initialize queue
420     setup_queue();
421 }
422
423 /** Tell card driver to stop this queue. */
424 static void idc_terminate_queue(void)
425 {
426     errval_t r;
427     DEBUG_QUEUE("idc_terminate_queue()\n");
428
429     r = sfn5122f_terminate_queue__tx(binding, NOP_CONT, qi);
430     // TODO: handle busy
431     assert(err_is_ok(r));
432 }
433
434 // Callback from device manager
435 void qd_queue_memory_registered(struct sfn5122f_binding *b)
436 {
437     initialized = 1;
438     // Register queue with queue_mgr library
439     DEBUG_QUEUE("Called ethersrv_init() \n");
440     ethersrv_init((char*) service_name, qi, 
441                   get_mac_address_fn, 
442                   terminate_queue_fn,
443                   transmit_pbuf_list_fn, 
444                   find_tx_free_slot_count_fn,
445                   handle_free_tx_slot_fn, 
446                   MTU_MAX, 
447                   register_rx_buffer_fn,
448                   find_rx_free_slot_count_fn);
449 }
450
451 // Callback from device manager
452 void qd_write_queue_tails(struct sfn5122f_binding *b)
453 {
454     DEBUG_QUEUE("idc_write_queue_tails()\n");
455
456     sfn5122f_queue_bump_rxtail(q);
457     sfn5122f_queue_bump_txtail(q);
458 }
459
460
461 // Callback from device manager
462 static void idc_queue_terminated(struct sfn5122f_binding *b)
463 {
464     errval_t err;
465
466     DEBUG_QUEUE("idc_queue_terminated()\n");
467
468     // Free memory for hardware ring buffers
469     if (q->userspace) {
470         err = vspace_unmap(q->tx_ring.user);
471         assert(err_is_ok(err));
472         err = vspace_unmap(q->rx_ring.user);
473         assert(err_is_ok(err));
474     } else {
475         err = vspace_unmap(q->tx_ring.ker);
476         assert(err_is_ok(err));
477         err = vspace_unmap(q->rx_ring.ker);
478         assert(err_is_ok(err));
479     }
480
481     err = vspace_unmap(q->ev_ring);
482     assert(err_is_ok(err));
483     err = cap_delete(tx_frame);
484     assert(err_is_ok(err));
485     err = cap_delete(rx_frame);
486     assert(err_is_ok(err));
487     err = cap_delete(ev_frame);
488     assert(err_is_ok(err));
489
490     exit(0);
491 }
492
493 static struct sfn5122f_rx_vtbl rx_vtbl = {
494     .queue_init_data = qd_queue_init_data,
495     .queue_memory_registered = qd_queue_memory_registered,
496     .write_queue_tails = qd_write_queue_tails,
497     .queue_terminated = idc_queue_terminated,
498 };
499
500 static void bind_cb(void *st, errval_t err, struct sfn5122f_binding *b)
501 {
502     assert(err_is_ok(err));
503
504     DEBUG_QUEUE("Sucessfully connected to management interface\n");
505
506     b->rx_vtbl = rx_vtbl;
507     binding = b;
508
509     idc_request_device_info();
510 }
511
512 /** Connect to the management interface */
513 static void connect_to_mngif(void)
514 {
515     errval_t r;
516     iref_t iref;
517     const char *suffix = "_sfn5122fmng";
518     char name[strlen(service_name) + strlen(suffix) + 1];
519
520     // Build label for interal management service
521     sprintf(name, "%s%s", service_name, suffix);
522
523     // Connect to service
524     DEBUG_QUEUE("Looking up management interface (%s)\n", name);
525     r = nameservice_blocking_lookup(name, &iref);
526     assert(err_is_ok(r));
527
528     DEBUG_QUEUE("Binding to management interface\n");
529     r = sfn5122f_bind(iref, bind_cb, NULL, get_default_waitset(),
530             IDC_BIND_FLAGS_DEFAULT);
531     assert(err_is_ok(r));
532 }
533
534 void qd_argument(const char *arg)
535 {
536     if (strncmp(arg, "cardname=", strlen("cardname=") - 1) == 0) {
537         service_name = arg + strlen("cardname=");
538         ethersrv_argument(arg);
539
540     } else if (strncmp(arg, "queue=", strlen("queue=") - 1) == 0) {
541         qi = atol(arg + strlen("queue="));
542         ethersrv_argument(arg);
543
544     } else if (strncmp(arg, "cache_coherence=", 
545                        strlen("cache_coherence=") - 1) == 0) {
546         cache_coherence = !!atol(arg + strlen("cache_coherence="));
547
548     } else if (strncmp(arg, "interrupts=", strlen("interrupts=") - 1) == 0) {
549         use_interrupts = !!atol(arg + strlen("interrupts="));
550         DEBUG_QUEUE("Interrupts enabled: legacy interrupts for fatal device errors\n");
551     } else if (strncmp(arg, "msix=", strlen("msix=") - 1) == 0) {
552         USER_PANIC("MSI-X not fully implemented yet!");
553         use_msix = !!atol(arg + strlen("msix="));
554         DEBUG_QUEUE("Using msix \n");
555     } else if (strncmp(arg, "userspace=", strlen("userspace=") - 1) == 0) {
556        USER_PANIC("Userspace networking for SFN5122F not implemented!");
557        /*
558         userspace = atol(arg + strlen("userspace="));
559         ethersrv_argument(arg);
560        */
561     } else {
562         ethersrv_argument(arg);
563     }
564 }
565
566 static void parse_cmdline(int argc, char **argv)
567 {
568     int i;
569     for (i = 1; i < argc; i++) {
570         qd_argument(argv[i]);
571     }
572 }
573
574 static void eventloop(void)
575 {
576     struct waitset *ws;
577     errval_t err;
578
579     DEBUG_QUEUE("eventloop()\n");
580
581     ws = get_default_waitset();
582     while (1) {
583         err = event_dispatch_non_block(ws);
584         do_pending_work_for_all();
585         check_for_new_events();
586     }
587 }
588
589 static void eventloop_ints(void)
590 {
591     struct waitset *ws;
592     DEBUG_QUEUE("eventloop_ints()\n");
593
594     ws = get_default_waitset();
595     while (1) {
596         event_dispatch(ws);
597         do_pending_work_for_all();
598     }
599 }
600
601 void qd_main(void)
602 {
603     // Validate some settings
604     if (qi == -1) {
605         USER_PANIC("For queue driver the queue= parameter has to be specified "
606                    "on the command line!");
607     }
608
609     connect_to_mngif();
610  
611     if (use_interrupts) {
612         eventloop_ints();
613     } else {
614         eventloop();
615     }
616 }
617
618 int main(int argc, char **argv)
619 {
620     DEBUG_QUEUE("Started\n");
621     parse_cmdline(argc, argv);
622     qd_main();
623 }