1/*
2 * Copyright (c) 2007-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 "elb.h"
11
12#include <barrelfish/net_constants.h>
13#include <if/net_queue_manager_defs.h>
14#include <barrelfish/bulk_transfer_arch.h>
15#include <procon/procon.h>
16#include "elb_debug.h"
17
18#define MAX_SERVICE_NAME_LEN  256   // Max len that a name of service can have
19#define BUFFER_SIZE 2048
20
21// Defined in the benchmark file
22
23static void idc_register_buffer(struct net_queue_manager_binding *binding,
24                                struct capref buf, struct capref sp,
25                                uint64_t qid, uint64_t slots, uint8_t role);
26
27static uint64_t queue = 0;
28
29static struct net_queue_manager_binding *binding_rx = NULL;
30static struct shared_pool_private *spp_rx = NULL;
31static uint64_t bufid_rx = -1ULL;
32
33static struct net_queue_manager_binding *binding_tx = NULL;
34static struct shared_pool_private *spp_tx = NULL;
35static uint64_t bufid_tx = -1ULL;
36
37static struct capref buffer_frame;
38void *buffer_base = NULL;
39size_t buffer_size = 2048;
40
41/******************************************************************************/
42/* Buffer management */
43
44errval_t buffer_tx_add(size_t idx, size_t len)
45{
46    struct slot_data s = {
47        .buffer_id = bufid_tx,
48        .no_pbufs = 1,
49        .offset = idx * BUFFER_SIZE,
50        .len = len,
51        .client_data = idx + 1,
52    };
53    //printf("buffer_tx_add()\n");
54    bool ret = sp_produce_slot(spp_tx, &s);
55    if (ret) {
56        return (SYS_ERR_OK);
57    }
58    return CONT_ERR_NO_MORE_SLOTS;
59}
60
61void buffer_rx_add(size_t idx)
62{
63    bool result;
64    //printf("buffer_rx_add()\n");
65    copy_data_into_slot(spp_rx, bufid_rx,
66                        (spp_rx->c_read_id - 1) % spp_rx->c_size,
67                        idx * BUFFER_SIZE,
68                        BUFFER_SIZE, 1, idx + 1, 0);
69    result = sp_set_read_index(spp_rx,
70                               (spp_rx->c_read_id + 1) % spp_rx->c_size);
71    assert(result);
72}
73
74static void check_rx_ring(void)
75{
76    struct slot_data s;
77
78    while (1) {
79        if (!sp_ghost_read_slot(spp_rx, &s)) {
80            break;
81        }
82
83        //printf("benchmark_rx_done()\n");
84        benchmark_rx_done(s.client_data - 1, s.len);
85    }
86}
87
88static void check_tx_ring(void)
89{
90    struct slot_data s;
91    uint64_t start, stop, i;
92    bool res;
93
94    if (sp_queue_empty(spp_tx)) {
95        stop = spp_tx->c_write_id;
96    } else {
97        stop = spp_tx->c_read_id;
98    }
99    start = spp_tx->pre_write_id;
100
101    if (start == stop) {
102        return;
103    }
104
105    i = start;
106    while (sp_c_between(start, i, stop, spp_tx->c_size)) {
107        if (!sp_is_slot_clear(spp_tx, i)) {
108            res = sp_clear_slot(spp_tx, &s, i);
109            assert(res);
110            assert(s.client_data == 0);
111
112            //printf("benchmark_tx_done()\n");
113            benchmark_tx_done(s.client_data - 1);
114        }
115        i = (i + 1) % spp_tx->c_size;
116    }
117}
118
119static void alloc_mem(struct capref *frame, void** virt, size_t size)
120{
121    errval_t r;
122    vregion_flags_t flags;
123
124    r = frame_alloc(frame, size, NULL);
125    if (!err_is_ok(r)) {
126        USER_PANIC("Allocating memory region frame failed!");
127    }
128
129    flags = VREGION_FLAGS_READ_WRITE;
130    r = vspace_map_one_frame_attr(virt, size, *frame, flags, NULL, NULL);
131    if (!err_is_ok(r)) {
132        USER_PANIC("Mapping memory region frame failed!");
133    }
134    memset(*virt, 0, size);
135}
136
137static void buffers_init(size_t count)
138{
139    struct waitset *ws = get_default_waitset();
140    bool res;
141
142    alloc_mem(&buffer_frame, &buffer_base, BUFFER_SIZE * count);
143
144    // In the RX buffer we have to make sure the queue manager knows that there
145    // are no buffers in it atm.
146    spp_rx = sp_create_shared_pool(count, RX_BUFFER_ID);
147    res = sp_set_write_index(spp_rx, count - 1);
148    spp_rx->ghost_read_id = count - 1;
149    assert(res);
150
151    spp_tx = sp_create_shared_pool(count, TX_BUFFER_ID);
152
153    idc_register_buffer(binding_rx, buffer_frame, spp_rx->cap, queue, count,
154                        RX_BUFFER_ID);
155    while (bufid_rx == -1ULL) { event_dispatch(ws); }
156
157    idc_register_buffer(binding_tx, buffer_frame, spp_tx->cap, queue, count,
158                        TX_BUFFER_ID);
159    while (bufid_tx == -1ULL) { event_dispatch(ws); }
160}
161
162
163/******************************************************************************/
164/* Flounder interface */
165
166static void idc_register_buffer(struct net_queue_manager_binding *binding,
167                                struct capref buf, struct capref sp,
168                                uint64_t qid, uint64_t slots, uint8_t role)
169{
170    errval_t err;
171    err = net_queue_manager_register_buffer__tx(binding, NOP_CONT, buf, sp,
172                                                queue, slots, role);
173}
174
175static void new_buffer_id(struct net_queue_manager_binding *st, errval_t err,
176                          uint64_t queueid, uint64_t buffer_id)
177{
178    printf("new_buffer_id(%"PRIu64")\n", buffer_id);
179
180    assert(err_is_ok(err));
181
182    if (st == binding_rx) {
183        bufid_rx = buffer_id;
184    } else {
185        bufid_tx = buffer_id;
186    }
187}
188
189static void sp_notification_from_driver(struct net_queue_manager_binding *b,
190       uint64_t queueid, uint64_t type, uint64_t rts)
191{
192    //printf("sp_notification_from_driver\n");
193}
194
195static struct net_queue_manager_rx_vtbl rx_vtbl = {
196    .new_buffer_id = new_buffer_id,
197    .sp_notification_from_driver = sp_notification_from_driver,
198    //.get_mac_address_response = get_mac_address_response,
199};
200
201static void bind_cb(void *st, errval_t err, struct net_queue_manager_binding *b)
202{
203    assert(err_is_ok(err));
204
205    b->rx_vtbl = rx_vtbl;
206
207    if (binding_rx == NULL) {
208        binding_rx = b;
209    } else {
210        binding_tx = b;
211    }
212}
213
214static void connect_to_driver(const char *cname, uint64_t qid)
215{
216    errval_t err;
217    iref_t iref;
218    char qm_name[MAX_SERVICE_NAME_LEN] = { 0 };
219
220    snprintf(qm_name, sizeof(qm_name), "%s_%"PRIu64, cname, qid);
221    err = nameservice_blocking_lookup(qm_name, &iref);
222    assert(err_is_ok(err));
223
224    err = net_queue_manager_bind(iref, bind_cb, NULL, get_default_waitset(),
225                                 IDC_BIND_FLAGS_DEFAULT);
226    assert(err_is_ok(err));
227
228}
229
230void terminate_benchmark(void)
231{
232    vspace_unmap(buffer_base);
233    cap_delete(buffer_frame);
234    exit(-1);
235}
236
237static void process_cmdline(int argc, char* argv[])
238{
239    int i;
240    for (i = 1; i < argc; i++) {
241        benchmark_argument(argv[i]);
242    }
243}
244
245static void eventloop(void)
246{
247    struct waitset *ws = get_default_waitset();
248
249    while (1) {
250        event_dispatch_non_block(ws);
251        benchmark_do_pending_work();
252        check_rx_ring();
253        check_tx_ring();
254    }
255}
256
257int main(int argc, char* argv[])
258{
259    struct waitset *ws = get_default_waitset();
260
261    printf("elb_app: Started, v2\n");
262    process_cmdline(argc, argv);
263
264    char *cardname = get_cardname();
265    if (cardname == NULL) {
266        cardname = "e10k";
267    }
268    queue = get_cmdline_queueid();
269    printf("Using [%s] as cardname and %"PRIu64"\n", cardname,
270            queue);
271    ELB1_DEBUG("Using [%s] as cardname\n", cardname);
272    // Connect RX path
273    connect_to_driver(cardname, queue);
274    while (binding_rx == NULL) { event_dispatch(ws); }
275
276    // Connect TX path
277    connect_to_driver(cardname, queue);
278    while (binding_rx == NULL) { event_dispatch(ws); }
279
280    buffers_init(32);
281    benchmark_init(32);
282
283    eventloop();
284}
285
286