1/*
2 * Copyright (c) 2007-2011, 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 <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13#include <stdarg.h>
14
15#include <net_queue_manager/net_queue_manager.h>
16#include <barrelfish/nameservice_client.h>
17#include <barrelfish/spawn_client.h>
18#include <barrelfish/debug.h>
19#include <trace/trace.h>
20
21//#include "helper.h"
22#include "lo_debug.h"
23
24/// MTU is 1500 bytes, plus Ethernet header and CRC is max packet size
25//#define PACKET_SIZE     (1500 + 14 + 4)
26#define PACKET_SIZE     (2048)
27
28/// Maximum packet size is write buffer size
29#define WRITE_BUF_SIZE  PACKET_SIZE
30
31#define RECEIVE_BUFFER_SIZE (2048) // MAX size of ethernet packet
32
33#if 0
34#define MAX_ALLOWED_PKT_PER_ITERATION    (0xff)  // working value
35#define DRIVER_RECEIVE_BUFFERS   (1024 * 8) // Number of buffers with driver
36
37#define DRIVER_TRANSMIT_BUFFER   (1024 * 8)
38
39// Data-structure to map sent buffer slots back to application slots
40struct pbuf_desc {
41    void *opaque;
42};
43static struct pbuf_desc pbuf_list_tx[DRIVER_TRANSMIT_BUFFER];
44//remember the tx pbufs in use
45
46static uint32_t ether_transmit_index = 0, ether_transmit_bufptr = 0;
47
48/* TODO: check if these variables are used */
49static uint32_t receive_index = 0, receive_bufptr = 0;
50static uint32_t receive_free = 0;
51static void **receive_opaque = NULL;
52
53static bool handle_free_TX_slot_fn(void);
54#endif // 0
55
56// Buffer registered by net_queue_mgr library
57static uint8_t *packetbuf = NULL;
58static void *rx_packet_opaque = NULL;
59
60// variable identifying the loopback device
61extern bool is_loopback_device;
62
63
64// FIXME: This is just a placeholder function.  Should be removed
65static uint64_t rtl_tx_slots_count_fn(void)
66{
67    return 1000; // RTL_TX_RING_SIZE;
68}
69
70/**
71 * \brief Send Ethernet packet.
72 *
73 * The packet should be a complete Ethernet frame. Nothing is added
74 * by the card or the driver.
75 *
76 */
77static errval_t lo_send_ethernet_packet_fn(struct driver_buffer *buffers,
78                                           size_t  count)
79{
80    // Find the length of entire packet
81    uint64_t pkt_len = 0;
82    for (int idx = 0; idx < count; idx++) {
83        pkt_len += buffers[idx].len;
84    }
85
86    // copy packet to internal buffer
87    LO_DEBUG("sending ethernet packet with opaque %p\n", tx_opaque);
88    assert(pkt_len <= WRITE_BUF_SIZE);
89    assert(packetbuf != NULL);
90
91    pkt_len = 0;
92    for (int idx = 0; idx < count; idx++) {
93        memcpy_fast((packetbuf + pkt_len), buffers[idx].va,
94                buffers[idx].len);
95        pkt_len += buffers[idx].len;
96    }
97
98    // we are done with packet copying
99    // marking the packetbuf as NULL again so that next slot can be registerd
100    packetbuf = NULL;
101
102    // treat it as incoming packet and handle it!
103    //process_received_packet(rx_packet_opaque, pkt_len, true);
104    /* TODO ak: broken lo
105     * sf_process_received_packet_lo(rx_packet_opaque, tx_opaque, pkt_len, true,
106            0);*/
107
108    // Tell the client we sent them!!!
109    for (int idx = 0; idx < count; idx++) {
110        handle_tx_done(buffers[idx].opaque);
111    }
112
113    return SYS_ERR_OK;
114} // end function: lo_send_ethernet_packet_fn
115
116#if 0
117// commented as we receive packet directly in send path
118static void lo_receive_packet(void)
119{
120    assert(!"NYI");
121} // end function: lo_receive_packet
122#endif // 0
123
124static bool handle_free_TX_slot_fn(void)
125{
126    return false;
127}
128
129/**
130 * Callback for net_queue_mgr library. Since we do PIO anyways, we only ever use
131 * one buffer.
132 */
133static uint64_t find_rx_free_slot_count_fn(void)
134{
135    if (packetbuf == NULL) {
136        return 1;
137    } else {
138        return 0;
139    }
140}
141
142/** Callback for net_queue_mgr library. */
143static errval_t register_rx_buffer_fn(uint64_t paddr, void *vaddr,
144        void *rx_opaque)
145{
146    if (packetbuf != NULL) {
147        return ETHERSRV_ERR_TOO_MANY_BUFFERS;
148    }
149
150    packetbuf = vaddr;
151    rx_packet_opaque = rx_opaque;
152    return SYS_ERR_OK;
153}
154
155
156// *********************************************************************
157// Global state
158
159// Service name
160static char* service_name = "lo";
161
162static uint64_t assumed_queue_id = 0; // queue_id that will be initialized
163
164// Indicates whether we should rely on cache coherence for descriptor rings
165static bool cache_coherence = true;
166
167// Indicates whether TX head index write back should be used
168static bool use_txhwb = true;
169
170// *****************************************************************
171//  MAC address
172//  ****************************************************************
173static uint8_t macaddr[6] = {10,10,10,10,10,10};
174
175static void get_mac_address_fn(uint8_t *mac)
176{
177    memcpy(mac, macaddr, sizeof(macaddr));
178}
179
180
181static void parse_cmdline(int argc, char **argv)
182{
183    int i;
184    bool has_queue = false;
185
186    for (i = 1; i < argc; i++) {
187        if (strncmp(argv[i], "cardname=", strlen("cardname=") - 1) == 0) {
188            service_name = argv[i] + strlen("cardname=");
189        } else if (strncmp(argv[i], "queue=", strlen("queue=") - 1) == 0) {
190            assumed_queue_id = atol(argv[i] + strlen("queue="));
191            has_queue = true;
192        } else if (strncmp(argv[i], "cache_coherence=",
193                           strlen("cache_coherence=") - 1) == 0) {
194            cache_coherence = !!atol(argv[i] + strlen("cache_coherence="));
195        } else if (strncmp(argv[i], "head_idx_wb=",
196                           strlen("head_idx_wb=") - 1) == 0) {
197            use_txhwb = !!atol(argv[i] + strlen("head_idx_wb="));
198        } else {
199            ethersrv_argument(argv[i]);
200        }
201    }
202
203    if (!has_queue) {
204        USER_PANIC("For queue driver the queue= parameter has to be specified "
205                   "on the command line!");
206    }
207}
208
209
210static void eventloop(void)
211{
212    struct waitset *ws;
213    errval_t err;
214
215    printf("eventloop()\n");
216
217    ws = get_default_waitset();
218    while (1) {
219        err = event_dispatch_non_block(ws);
220        do_pending_work_for_all();
221//        check_for_new_packets();
222//        check_for_free_txbufs();
223    }
224}
225
226
227// *****************************************************************
228//  * Init
229// ****************************************************************
230
231static void lo_init(void)
232{
233    LO_DEBUG("starting loopback device init\n");
234    is_loopback_device = true;
235    ethersrv_init(service_name, assumed_queue_id, get_mac_address_fn, NULL,
236            lo_send_ethernet_packet_fn,
237            rtl_tx_slots_count_fn, handle_free_TX_slot_fn,
238            PACKET_SIZE, register_rx_buffer_fn, find_rx_free_slot_count_fn);
239}
240
241
242
243int main(int argc, char **argv)
244{
245    printf("Started lo_queuemanager\n");
246    parse_cmdline(argc, argv);
247    lo_init();
248    eventloop();
249}
250
251
252
253#if 0
254/*****************************************************************
255 * Transmit logic
256 ****************************************************************/
257/* check if there are enough free buffers with driver,
258 * so that packet can be sent
259 * */
260static bool can_transmit(int numbufs)
261{
262    uint64_t nr_free;
263    assert(numbufs < DRIVER_TRANSMIT_BUFFER);
264    if (ether_transmit_index >= ether_transmit_bufptr) {
265        nr_free = DRIVER_TRANSMIT_BUFFER -
266            ((ether_transmit_index - ether_transmit_bufptr) %
267                DRIVER_TRANSMIT_BUFFER);
268    } else {
269        nr_free = (ether_transmit_bufptr - ether_transmit_index) %
270            DRIVER_TRANSMIT_BUFFER;
271    }
272    return (nr_free > numbufs);
273}
274
275static uint64_t transmit_pbuf(uint64_t buffer_address,
276                              size_t packet_len, bool last, void *opaque)
277{
278    assert(!"NYI");
279    transmit_ring[ether_transmit_index] = tdesc;
280    pbuf_list_tx[ether_transmit_index].opaque = opaque;
281
282    ether_transmit_index = (ether_transmit_index + 1) % DRIVER_TRANSMIT_BUFFER;
283
284    // FIXME: copy the packet to destination memory slot
285
286    LO_DEBUG("ether_transmit_index %"PRIu32"\n", ether_transmit_index);
287    /* Actual place where packet is sent.  Adding trace_event here */
288#if TRACE_ETHERSRV_MODE
289    trace_event(TRACE_SUBSYS_NET, TRACE_EVENT_NET_NO_S,
290    		(uint32_t)client_data);
291#endif // TRACE_ETHERSRV_MODE
292
293    return 0;
294}
295
296
297/* Send the buffer to device driver TX ring.
298 * NOTE: This function will get called from ethersrv.c */
299static errval_t transmit_pbuf_list_fn(struct driver_buffer *buffers,
300                                      size_t                count,
301                                      void                 *opaque)
302{
303    errval_t r;
304    LO_DEBUG("transmit_pbuf_list_fn(count=%"PRIu64")\n", count);
305    if (!can_transmit(count)){
306        while(handle_free_TX_slot_fn());
307        if (!can_transmit(count)){
308            return ETHERSRV_ERR_CANT_TRANSMIT;
309        }
310    }
311
312    for (int i = 0; i < count; i++) {
313        r = transmit_pbuf(buffers[i].pa, buffers[i].len,
314                    i == (count - 1), //last?
315                    opaque);
316        if(err_is_fail(r)) {
317            //LO_DEBUG("ERROR:transmit_pbuf failed\n");
318            printf("ERROR:transmit_pbuf failed\n");
319            return r;
320        }
321        LO_DEBUG("transmit_pbuf done for pbuf 0x%p, index %"PRIu64"\n",
322            opaque, i);
323    } // end for: for each pbuf
324#if TRACE_ONLY_SUB_NNET
325    trace_event(TRACE_SUBSYS_NNET,  TRACE_EVENT_NNET_TXDRVADD,
326        (uint32_t)0);
327#endif // TRACE_ONLY_SUB_NNET
328
329    return SYS_ERR_OK;
330} // end function: transmit_pbuf_list_fn
331
332
333static uint64_t find_tx_free_slot_count_fn(void)
334{
335
336    uint64_t nr_free;
337    if (ether_transmit_index >= ether_transmit_bufptr) {
338        nr_free = DRIVER_TRANSMIT_BUFFER -
339            ((ether_transmit_index - ether_transmit_bufptr) %
340                DRIVER_TRANSMIT_BUFFER);
341    } else {
342        nr_free = (ether_transmit_bufptr - ether_transmit_index) %
343            DRIVER_TRANSMIT_BUFFER;
344    }
345
346    return nr_free;
347} // end function: find_tx_queue_len
348
349static bool handle_free_TX_slot_fn(void)
350{
351    uint64_t ts = rdtsc();
352    bool sent = false;
353    volatile struct tx_desc *txd;
354    if (ether_transmit_bufptr == ether_transmit_index) {
355        return false;
356    }
357
358    txd = &transmit_ring[ether_transmit_bufptr];
359    if (txd->ctrl.legacy.sta_rsv.d.dd != 1) {
360        return false;
361    }
362
363#if TRACE_ONLY_SUB_NNET
364    trace_event(TRACE_SUBSYS_NNET, TRACE_EVENT_NNET_TXDRVSEE,
365                0);
366#endif // TRACE_ONLY_SUB_NNET
367
368
369    sent = handle_tx_done(pbuf_list_tx[ether_transmit_bufptr].opaque);
370
371    ether_transmit_bufptr = (ether_transmit_bufptr + 1)%DRIVER_TRANSMIT_BUFFER;
372    netbench_record_event_simple(bm, RE_TX_DONE, ts);
373    return true;
374}
375
376static errval_t rx_register_buffer_fn(uint64_t paddr, void *vaddr,
377        void *opaque)
378{
379    return add_desc(paddr, opaque);
380}
381
382static uint64_t rx_find_free_slot_count_fn(void)
383{
384    return DRIVER_RECEIVE_BUFFERS - receive_free;
385}
386#endif // 0
387
388
389