d082cf16eb85cae45516e65100e2e7c941f8aec9
[barrelfish] / usr / tests / devif / queue_interface.c
1 /*
2  * Copyright (c) 2007, 2008, 2009, 2010, 2011, 2012, 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 #include <stdlib.h>
11 #include <stdio.h>
12 #include <time.h>
13 #include <barrelfish/barrelfish.h>
14 #include <barrelfish/waitset.h>
15 #include <barrelfish/waitset_chan.h>
16 #include <barrelfish/deferred.h>
17 #include <devif/queue_interface.h>
18 #include <devif/backends/net/sfn5122f_devif.h>
19 #include <devif/backends/net/e10k_devif.h>
20 #include <devif/backends/descq.h>
21 #include <bench/bench.h>
22 #include <net_interfaces/flags.h>
23
24
25 //#define DEBUG(x...) printf("devif_test: " x)
26 #define DEBUG(x...) do {} while (0)
27
28 #define TX_BUF_SIZE 2048
29 #define RX_BUF_SIZE 2048
30 #define NUM_ENQ 512
31 #define NUM_RX_BUF 1024
32 #define NUM_ROUNDS_TX 16384
33 #define NUM_ROUNDS_RX 128
34 #define MEMORY_SIZE BASE_PAGE_SIZE*512
35
36 static char* card;
37
38 static struct capref memory_rx;
39 static struct capref memory_tx;
40 static regionid_t regid_rx;
41 static regionid_t regid_tx;
42 static struct frame_identity id;
43 static lpaddr_t phys_rx;
44 static lpaddr_t phys_tx;
45
46 static volatile uint32_t num_tx = 0;
47 static volatile uint32_t num_rx = 0;
48
49 static void* va_rx;
50 static void* va_tx;
51
52 struct direct_state {
53     struct list_ele* first;
54     struct list_ele* last;
55 };
56
57 struct list_ele{
58     regionid_t rid;
59     bufferid_t bid;
60     lpaddr_t addr;
61     size_t len;
62     uint64_t flags;
63    
64     struct list_ele* next;
65 };
66
67
68 static struct waitset_chanstate *chan = NULL;
69 static struct waitset card_ws;
70
71
72 static uint8_t udp_header[8] = {
73     0x07, 0xD0, 0x07, 0xD0,
74     0x00, 0x80, 0x00, 0x00,
75 };
76
77 static void print_buffer(size_t len, bufferid_t bid)
78 {
79    /*
80     uint8_t* buf = (uint8_t*) va_rx+bid;
81     printf("Packet in region %p at address %p len %zu \n",
82            va_rx, buf, len);
83     for (int i = 0; i < len; i++) {
84         if (((i % 10) == 0) && i > 0) {
85             printf("\n");
86         }
87         printf("%2X ", buf[i]);
88     }
89     printf("\n");
90     */
91 }
92
93 static void wait_for_interrupt(void)
94 {
95     errval_t err = event_dispatch(&card_ws);
96     if (err_is_fail(err)) {
97         USER_PANIC_ERR(err, "error in event_dispatch for wait_for_interrupt");
98     }
99 }
100
101 static void event_cb(void* queue)
102 {
103     struct devq* q = (struct devq*) queue;
104
105     errval_t err;
106
107     regionid_t rid;
108     genoffset_t offset;
109     genoffset_t length;
110     genoffset_t valid_data;
111     genoffset_t valid_length;
112     uint64_t flags;
113
114     err = SYS_ERR_OK;
115
116     while (err == SYS_ERR_OK) {
117         err = devq_dequeue(q, &rid, &offset, &length, &valid_data,
118                            &valid_length, &flags);
119         if (err_is_fail(err)) {
120             break;
121         }
122
123         if (flags & NETIF_TXFLAG) {
124             DEBUG("Received TX buffer back \n");
125             num_tx++;
126         } else if (flags & NETIF_RXFLAG) {
127             num_rx++;
128             DEBUG("Received RX buffer \n");
129             print_buffer(valid_length, offset);
130         } else {
131             printf("Unknown flags %lx \n", flags);
132         }
133     }
134
135     // MSIX is not working on so we have to "simulate interrupts"
136     err = waitset_chan_register(&card_ws, chan,
137                                 MKCLOSURE(event_cb, queue));
138     if (err_is_fail(err) && err_no(err) == LIB_ERR_CHAN_ALREADY_REGISTERED) {
139         printf("Got actual interrupt?\n");
140     }
141     else if (err_is_fail(err)) {
142         USER_PANIC_ERR(err, "Can't register our dummy channel.");
143     }
144     err = waitset_chan_trigger(chan);
145     if (err_is_fail(err)) {
146         USER_PANIC_ERR(err, "trigger failed.");
147     }
148 }
149
150 static struct devq* create_net_queue(char* card_name)
151 {
152     errval_t err;
153     if (strcmp(card_name, "sfn5122f") == 0) {
154         struct sfn5122f_queue* q;
155         
156         err = sfn5122f_queue_create(&q, event_cb, /* userlevel*/ true,
157                                     /*MSIX interrupts*/ false);
158         if (err_is_fail(err)){
159             USER_PANIC("Allocating devq failed \n");
160         }
161         return (struct devq*) q;
162     }
163
164     if (strcmp(card_name, "e10k") == 0) {
165         struct e10k_queue* q;
166         
167         err = e10k_queue_create(&q, event_cb, /*VFs */ false,
168                                 /*MSIX interrupts*/ false);
169         if (err_is_fail(err)){
170             USER_PANIC("Allocating devq failed \n");
171         }
172         return (struct devq*) q;
173     }
174
175     USER_PANIC("Unknown card name\n");
176
177     return NULL;
178 }
179
180 static errval_t destroy_net_queue(struct devq* q, char* card_name)
181 {
182     errval_t err;
183     if (strcmp(card_name, "sfn5122f") == 0) {
184         err = sfn5122f_queue_destroy((struct sfn5122f_queue*)q);
185         if (err_is_fail(err)){
186             USER_PANIC("Destroying devq failed \n");
187         }
188         return err;
189     }
190
191     if (strcmp(card_name, "e10k") == 0) {
192         err = e10k_queue_destroy((struct e10k_queue*)q);
193         if (err_is_fail(err)){
194             USER_PANIC("Destroying devq failed \n");
195         }
196         return err;
197     }
198
199     USER_PANIC("Unknown card name\n");
200
201     return SYS_ERR_OK;
202 }
203
204 static void test_net_tx(void)
205 {
206     num_tx = 0;
207     num_rx = 0;
208
209     errval_t err;
210     struct devq* q;
211     
212
213     q = create_net_queue(card);
214     assert(q != NULL);
215
216     waitset_init(&card_ws);
217
218     // MSIX is not working on sfn5122f yet so we have to "simulate interrupts"
219     chan = malloc(sizeof(struct waitset_chanstate));
220     waitset_chanstate_init(chan, CHANTYPE_AHCI);
221
222     err = waitset_chan_register(&card_ws, chan, MKCLOSURE(event_cb, q));
223     if (err_is_fail(err)) {
224         USER_PANIC_ERR(err, "waitset_chan_regster failed.");
225     }
226
227     err = waitset_chan_trigger(chan);
228     if (err_is_fail(err)) {
229         USER_PANIC_ERR(err, "trigger failed.");
230     }
231
232     err = devq_register(q, memory_tx, &regid_tx);
233     if (err_is_fail(err)){
234         USER_PANIC("Registering memory to devq failed \n");
235     }
236     
237
238     // write something into the buffers
239     char* write = NULL;
240
241     for (int i = 0; i < NUM_ENQ; i++) {
242         write = va_tx + i*(TX_BUF_SIZE);
243         for (int j = 0; j < 8; j++) {
244             write[j] = udp_header[j];
245         }
246         for (int j = 8; j < TX_BUF_SIZE; j++) {
247             write[j] = 'a';
248         }
249     }
250
251     // Send something
252     cycles_t t1 = bench_tsc();
253
254     for (int z = 0; z < NUM_ROUNDS_TX; z++) {
255         for (int i = 0; i < NUM_ENQ; i++) {
256             err = devq_enqueue(q, regid_tx, i*(TX_BUF_SIZE), TX_BUF_SIZE,
257                                0, TX_BUF_SIZE,
258                                NETIF_TXFLAG | NETIF_TXFLAG_LAST);
259             if (err_is_fail(err)){
260                 USER_PANIC("Devq enqueue failed \n");
261             }
262         }
263
264         while(true) {
265             if ((num_tx < NUM_ENQ)) {
266                 wait_for_interrupt();
267             } else {
268                 break;
269             }
270         }
271         num_tx = 0;
272     }
273
274     cycles_t t2 = bench_tsc();
275     cycles_t result = (t2 -t1 - bench_tscoverhead());
276  
277     uint64_t sent_bytes = (uint64_t) TX_BUF_SIZE*NUM_ENQ*NUM_ROUNDS_TX;
278     double result_ms = (double) bench_tsc_to_ms(result);
279     double bw = sent_bytes / result_ms / 1000;
280     
281     printf("Write throughput %.2f [MB/s] for %.2f ms \n", bw, result_ms);
282
283     err = devq_control(q, 1, 1, NULL);
284     if (err_is_fail(err)){
285         printf("%s \n", err_getstring(err));
286         USER_PANIC("Devq control failed \n");
287     }
288
289     err = devq_deregister(q, regid_tx, &memory_tx);
290     if (err_is_fail(err)){
291         printf("%s \n", err_getstring(err));
292         USER_PANIC("Devq deregister tx failed \n");
293     }
294     
295     err = destroy_net_queue(q, card);
296     if (err_is_fail(err)){
297         printf("%s \n", err_getstring(err));
298         USER_PANIC("Destroying %s queue failed \n", card);
299     }
300
301     printf("SUCCESS: %s tx test ended\n", card);
302 }
303
304
305 static void test_net_rx(void)
306 {
307
308     num_tx = 0;
309     num_rx = 0;
310
311     errval_t err;
312     struct devq* q;
313    
314     q = create_net_queue(card);
315     assert(q != NULL);
316
317     waitset_init(&card_ws);
318
319     // MSIX is not working on sfn5122f yet so we have to "simulate interrupts"
320     chan = malloc(sizeof(struct waitset_chanstate));
321     waitset_chanstate_init(chan, CHANTYPE_AHCI);
322
323     err = waitset_chan_register(&card_ws, chan, MKCLOSURE(event_cb, q));
324     if (err_is_fail(err)) {
325         USER_PANIC_ERR(err, "waitset_chan_regster failed.");
326     }
327
328     err = waitset_chan_trigger(chan);
329     if (err_is_fail(err)) {
330         USER_PANIC_ERR(err, "trigger failed.");
331     }
332
333     err = devq_register(q, memory_rx, &regid_rx);
334     if (err_is_fail(err)){
335         USER_PANIC("Registering memory to devq failed \n");
336     }
337     
338     // Enqueue RX buffers to receive into
339     for (int i = 0; i < NUM_ROUNDS_RX; i++){
340         err = devq_enqueue(q, regid_rx, i*RX_BUF_SIZE, RX_BUF_SIZE,
341                            0, RX_BUF_SIZE,
342                            NETIF_RXFLAG);
343         if (err_is_fail(err)){
344             USER_PANIC("Devq enqueue failed: %s\n", err_getstring(err));
345         }
346
347     }
348
349     while (true) {
350         if ((num_rx < NUM_ROUNDS_RX)) {
351             wait_for_interrupt();
352         } else {
353             break;
354         }
355     }
356
357
358     err = devq_control(q, 1, 1, NULL);
359     if (err_is_fail(err)){
360         printf("%s \n", err_getstring(err));
361         USER_PANIC("Devq control failed \n");
362     }
363
364     err = devq_deregister(q, regid_rx, &memory_rx);
365     if (err_is_fail(err)){
366         printf("%s \n", err_getstring(err));
367         USER_PANIC("Devq deregister rx failed \n");
368     }
369    
370     err = destroy_net_queue(q, card);
371     if (err_is_fail(err)){
372         printf("%s \n", err_getstring(err));
373         USER_PANIC("Destroying %s queue failed \n", card);
374     }
375
376     printf("SUCCESS: %s rx test ended\n", card);
377 }
378
379
380 static errval_t descq_notify(struct descq* q)
381 {
382     errval_t err = SYS_ERR_OK;
383     struct devq* queue = (struct devq*) q;
384     
385     regionid_t rid;
386     genoffset_t offset;
387     genoffset_t length;
388     genoffset_t valid_data;
389     genoffset_t valid_length;
390     uint64_t flags;
391
392     while(err_is_ok(err)) {
393         err = devq_dequeue(queue, &rid, &offset, &length, &valid_data,
394                            &valid_length, &flags);
395         if (err_is_ok(err)){
396             num_rx++;
397         }
398     }
399     return SYS_ERR_OK;
400 }
401
402 static void test_idc_queue(void)
403 {
404     num_tx = 0;
405     num_rx = 0;
406
407     errval_t err;
408     struct devq* q;
409     struct descq* queue;
410     struct descq_func_pointer f;
411     f.notify = descq_notify;
412     
413     debug_printf("Descriptor queue test started \n");
414     err = descq_create(&queue, DESCQ_DEFAULT_SIZE, "test_queue",
415                        false, true, true, NULL, &f);
416     if (err_is_fail(err)){
417         USER_PANIC("Allocating devq failed \n");
418     }
419    
420     q = (struct devq*) queue;
421
422     err = devq_register(q, memory_rx, &regid_rx);
423     if (err_is_fail(err)){
424         USER_PANIC("Registering memory to devq failed \n");
425     }
426   
427     err = devq_register(q, memory_tx, &regid_tx);
428     if (err_is_fail(err)){
429         USER_PANIC("Registering memory to devq failed \n");
430     }
431  
432     // Enqueue RX buffers to receive into
433     for (int j = 0; j < 1000000; j++){
434         for (int i = 0; i < 32; i++){
435             err = devq_enqueue(q, regid_rx, i*2048, 2048, 
436                                0, 2048, 0);
437             if (err_is_fail(err)){
438                 // retry
439                 i--;
440             } else {
441                 num_tx++;
442             }
443         }
444
445         err = devq_notify(q);
446         if (err_is_fail(err)) {
447                 USER_PANIC("Devq notify failed: %s\n", err_getstring(err));
448         }
449         event_dispatch(get_default_waitset());
450     }    
451
452     while(num_tx != num_rx) {
453         event_dispatch(get_default_waitset());
454     }
455
456     err = devq_control(q, 1, 1, NULL);
457     if (err_is_fail(err)){
458         printf("%s \n", err_getstring(err));
459         USER_PANIC("Devq control failed \n");
460     }
461
462     err = devq_deregister(q, regid_rx, &memory_rx);
463     if (err_is_fail(err)){
464         printf("%s \n", err_getstring(err));
465         USER_PANIC("Devq deregister rx failed \n");
466     }
467
468     err = devq_deregister(q, regid_tx, &memory_tx);
469     if (err_is_fail(err)){
470         printf("%s \n", err_getstring(err));
471         USER_PANIC("Devq deregister tx failed \n");
472     }
473
474     printf("SUCCESS: IDC queue\n");
475 }
476
477 int main(int argc, char *argv[])
478 {
479     errval_t err;
480     // Allocate memory
481     err = frame_alloc(&memory_rx, MEMORY_SIZE, NULL);
482     if (err_is_fail(err)){
483         USER_PANIC("Allocating cap failed \n");
484     }
485
486     err = frame_alloc(&memory_tx, MEMORY_SIZE, NULL);
487     if (err_is_fail(err)){
488         USER_PANIC("Allocating cap failed \n");
489     }
490     
491     // RX frame
492     err = invoke_frame_identify(memory_rx, &id);
493     if (err_is_fail(err)) {
494         USER_PANIC("Frame identify failed \n");
495     }
496
497     err = vspace_map_one_frame_attr(&va_rx, id.bytes, memory_rx,
498                                     VREGION_FLAGS_READ, NULL, NULL);
499     if (err_is_fail(err)) {
500         USER_PANIC("Frame mapping failed \n");
501     }
502
503     phys_rx = id.base;
504
505     // TX Frame
506     err = invoke_frame_identify(memory_tx, &id);
507     if (err_is_fail(err)) {
508         USER_PANIC("Frame identify failed \n");
509     }
510    
511     err = vspace_map_one_frame_attr(&va_tx, id.bytes, memory_tx,
512                                     VREGION_FLAGS_WRITE, NULL, NULL);
513     if (err_is_fail(err)) {
514         USER_PANIC("Frame mapping failed \n");
515     }
516
517     phys_tx = id.base;
518
519     if (argc > 2) {
520         card = argv[2];
521         printf("Card =%s \n", card);
522     } else {
523         card = "e10k";
524     }
525
526     if (strcmp(argv[1], "net_tx") == 0) {
527         test_net_tx();
528     }
529
530     if (strcmp(argv[1], "net_rx") == 0) {
531         test_net_rx();
532     }
533
534     if (strcmp(argv[1], "idc") == 0) {
535         test_idc_queue();
536     }
537    
538     barrelfish_usleep(1000*1000*5);
539 }
540