1/* 2 * Copyright (c) 2014, ETH Zurich. All rights reserved. 3 * 4 * This file is distributed under the terms in the attached LICENSE file. 5 * If you do not find this file, copies can be found by writing to: 6 * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group. 7 */ 8/* 9 * 10 * 11 */ 12#include <stdio.h> 13#include <string.h> 14 15#include <barrelfish/barrelfish.h> 16#include <barrelfish/nameservice_client.h> 17#include <flounder/flounder_txqueue.h> 18#include <dma/dma_manager_client.h> 19 20#include <if/dma_mgr_defs.h> 21 22#include "dma_mgr.h" 23#include "debug.h" 24 25/** 26 * enumration of all possible states of the service exportation process 27 */ 28enum svc_state 29{ 30 SVC_STATE_EXPORTING, 31 SVC_STATE_EXPORT_OK, 32 SVC_STATE_EXPORT_FAIL, 33 SVC_STATE_NS_REGISTERING, 34 SVC_STATE_NS_REGISTER_OK, 35 SVC_STATE_NS_REGISTER_FAIL, 36 SVC_STATE_RUNNING 37}; 38 39/// represents the current state of the exporting process 40static enum svc_state dma_svc_state = SVC_STATE_EXPORTING; 41 42/// our own iref of the exported service 43static iref_t svc_iref; 44 45/* 46 * ---------------------------------------------------------------------------- 47 * Reply State Cache 48 * ---------------------------------------------------------------------------- 49 */ 50struct svc_reply_st 51{ 52 struct txq_msg_st common; 53 54 /* union of arguments */ 55 union 56 { 57 struct dma_mgr_driver_info *lookup; 58 } args; 59}; 60 61/* 62 * ---------------------------------------------------------------------------- 63 * Driver Registration 64 * ---------------------------------------------------------------------------- 65 */ 66 67static errval_t svc_register_response_tx(struct txq_msg_st *msg_st) 68{ 69 70 return dma_mgr_register_driver_response__tx(msg_st->queue->binding, 71 TXQCONT(msg_st), msg_st->err); 72 73} 74 75static void svc_register_call_rx(struct dma_mgr_binding *_binding, 76 uint64_t mem_low, 77 uint64_t mem_high, 78 uint8_t numa_node, 79 uint8_t type, 80 iref_t iref) 81{ 82 errval_t err; 83 84 SVC_DEBUG("register call: [%016lx, %016lx]\n", mem_low, mem_high); 85 86 struct tx_queue *txq = _binding->st; 87 88 struct txq_msg_st *msg_st = txq_msg_st_alloc(txq); 89 if (msg_st == NULL) { 90 USER_PANIC("could not allocate reply state\n"); 91 } 92 93 msg_st->send = svc_register_response_tx; 94 95 msg_st->err = driver_store_insert(mem_low, mem_high, numa_node, type, iref); 96 97 if (err_is_ok(msg_st->err)) { 98 char buf[30]; 99 snprintf(buf, 30, "%s_%u_%u", DMA_MGR_REGISTERED_DRIVER, type, numa_node); 100 SVC_DEBUG("registering with nameservice {%s}\n", buf); 101 err = nameservice_register(buf, 0x123); 102 if (err_is_fail(err)) { 103 SVC_DEBUG("registering failed: %s\n", err_getstring(err)); 104 } 105 } 106 107 txq_send(msg_st); 108} 109 110/* 111 * ---------------------------------------------------------------------------- 112 * Query for DMA driver service 113 * ---------------------------------------------------------------------------- 114 */ 115 116static errval_t svc_lookup_response_tx(struct txq_msg_st *msg_st) 117{ 118 struct svc_reply_st *st = (struct svc_reply_st *) msg_st; 119 struct dma_mgr_driver_info *di = st->args.lookup; 120 121 if (err_is_fail(msg_st->err)) { 122 return dma_mgr_lookup_driver_response__tx(msg_st->queue->binding, 123 TXQCONT(msg_st), msg_st->err, 0, 0, 124 0, 0, 0); 125 } else { 126 assert(di); 127 return dma_mgr_lookup_driver_response__tx(msg_st->queue->binding, 128 TXQCONT(msg_st), msg_st->err, 129 di->mem_low, di->mem_high, 130 di->numa_node, di->type, di->iref); 131 } 132} 133 134static errval_t svc_lookup_by_iref_response_tx(struct txq_msg_st *msg_st) 135{ 136 struct svc_reply_st *st = (struct svc_reply_st *) msg_st; 137 138 struct dma_mgr_driver_info *di = st->args.lookup; 139 140 if (err_is_fail(msg_st->err)) { 141 return dma_mgr_lookup_driver_by_iref_response__tx(msg_st->queue->binding, 142 TXQCONT(msg_st), 143 msg_st->err, 0, 0, 0, 0); 144 } else { 145 assert(di); 146 return dma_mgr_lookup_driver_by_iref_response__tx(msg_st->queue->binding, 147 TXQCONT(msg_st), 148 msg_st->err, di->mem_low, 149 di->mem_high, 150 di->numa_node, di->type); 151 } 152} 153 154static void svc_lookup_call_rx(struct dma_mgr_binding *_binding, 155 uint64_t addr, 156 uint64_t size, 157 uint8_t numa_node) 158{ 159 SVC_DEBUG("lookup call: [%016lx, %016lx]\n", addr, size); 160 161 struct tx_queue *txq = _binding->st; 162 163 struct txq_msg_st *msg_st = txq_msg_st_alloc(txq); 164 if (msg_st == NULL) { 165 USER_PANIC("could not allocate reply state\n"); 166 } 167 168 msg_st->send = svc_lookup_response_tx; 169 170 struct svc_reply_st *st = (struct svc_reply_st *) msg_st; 171 172 msg_st->err = driver_store_lookup(addr, size, numa_node, &st->args.lookup); 173 174 txq_send(msg_st); 175} 176 177static void svc_lookup_by_iref_call_rx(struct dma_mgr_binding *_binding, 178 iref_t iref) 179{ 180 SVC_DEBUG("lookup call by iref: %"PRIxIREF"\n", iref); 181 182 struct tx_queue *txq = _binding->st; 183 184 struct txq_msg_st *msg_st = txq_msg_st_alloc(txq); 185 if (msg_st == NULL) { 186 USER_PANIC("could not allocate reply state\n"); 187 } 188 189 msg_st->send = svc_lookup_by_iref_response_tx; 190 191 struct svc_reply_st *st = (struct svc_reply_st *) msg_st; 192 193 msg_st->err = driver_store_lookup_by_iref(iref, &st->args.lookup); 194 195 txq_send(msg_st); 196} 197 198struct dma_mgr_rx_vtbl svc_rx_vtbl = { 199 .register_driver_call = svc_register_call_rx, 200 .lookup_driver_call = svc_lookup_call_rx, 201 .lookup_driver_by_iref_call = svc_lookup_by_iref_call_rx 202}; 203 204/* 205 * ---------------------------------------------------------------------------- 206 * Service export and connect handling 207 * ---------------------------------------------------------------------------- 208 */ 209 210static errval_t svc_connect_cb(void *st, 211 struct dma_mgr_binding *binding) 212{ 213 SVC_DEBUG("New connection to the DMA service\n"); 214 215 binding->rx_vtbl = svc_rx_vtbl; 216 217 struct tx_queue *txq = calloc(1, sizeof(*txq)); 218 if (txq == NULL) { 219 return LIB_ERR_MALLOC_FAIL; 220 } 221 222 txq_init(txq, binding, binding->waitset, 223 (txq_register_fn_t) binding->register_send, 224 sizeof(struct svc_reply_st)); 225 226 binding->st = txq; 227 228 return SYS_ERR_OK; 229} 230 231static void svc_export_cb(void *st, 232 errval_t err, 233 iref_t iref) 234{ 235 *((errval_t *) st) = err; 236 237 if (err_is_fail(err)) { 238 dma_svc_state = SVC_STATE_EXPORT_FAIL; 239 return; 240 } 241 242 svc_iref = iref; 243 dma_svc_state = SVC_STATE_EXPORT_OK; 244} 245 246/* 247 * ============================================================================ 248 * Public Interface 249 * ============================================================================ 250 */ 251 252/** 253 * \brief initializes the DMA manager service service 254 * 255 * \param svc_name The name of the service for nameservice registration 256 * \param cb Callback function pointers 257 * 258 * \returns SYS_ERR_OK on success 259 * errval on error 260 */ 261errval_t dma_mgr_svc_start(void) 262{ 263 errval_t err, export_err; 264 265 SVC_DEBUG("Initializing DMA service...\n"); 266 267 err = dma_mgr_export(&export_err, svc_export_cb, svc_connect_cb, 268 get_default_waitset(), 269 IDC_EXPORT_FLAGS_DEFAULT); 270 if (err_is_fail(err)) { 271 return err; 272 } 273 274 while (dma_svc_state == SVC_STATE_EXPORTING) { 275 messages_wait_and_handle_next(); 276 } 277 278 if (dma_svc_state == SVC_STATE_EXPORT_FAIL) { 279 return export_err; 280 } 281 282 dma_svc_state = SVC_STATE_NS_REGISTERING; 283 284 SVC_DEBUG("Registering service [%s] with iref [0x%"PRIxIREF"]\n", 285 DMA_MGR_SVC_NAME, svc_iref); 286 287 err = nameservice_register(DMA_MGR_SVC_NAME, svc_iref); 288 if (err_is_fail(err)) { 289 dma_svc_state = SVC_STATE_NS_REGISTER_FAIL; 290 return err; 291 } 292 293 dma_svc_state = SVC_STATE_RUNNING; 294 295 SVC_DEBUG("DMA service up and running.\n"); 296 297 return SYS_ERR_OK; 298} 299 300