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