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