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