1/* 2 * Copyright (c) 2014 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, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group. 8 */ 9 10#include <string.h> 11#include <barrelfish/barrelfish.h> 12#include <barrelfish/nameservice_client.h> 13 14#include <dma_internal.h> 15#include <dma/dma_manager_client.h> 16#include <debug.h> 17 18#include <if/dma_mgr_defs.h> 19#include <if/dma_mgr_defs.h> 20 21/// DMA manager RPC client 22static struct dma_mgr_binding *dma_mgr_client; 23 24/// connected flag 25uint8_t dma_mgr_connected = 0x0; 26 27/// state for binding 28struct dma_mgr_bind_st 29{ 30 uint8_t bound; 31 errval_t err; 32}; 33 34/* 35 * --------------------------------------------------------------------------- 36 * Service Binding 37 * --------------------------------------------------------------------------- 38 */ 39 40static void bind_cb(void *st, 41 errval_t err, 42 struct dma_mgr_binding *b) 43{ 44 assert(st); 45 struct dma_mgr_bind_st *bindst = st; 46 47 bindst->err = err; 48 49 if (err_is_fail(err)) { 50 DMAMGR_DEBUG("connect: connection to {%s} failed.\n", DMA_MGR_SVC_NAME); 51 bindst->bound = 0x1; 52 return; 53 } 54 55 DMAMGR_DEBUG("connect: connection to {%s} established.\n", DMA_MGR_SVC_NAME); 56 dma_mgr_client = b; 57 dma_mgr_rpc_client_init(dma_mgr_client); 58 59 bindst->bound = 0x1; 60} 61 62static errval_t dma_manager_connect(void) 63{ 64 errval_t err; 65 iref_t iref; 66 67 DMAMGR_DEBUG("connect: looking up service name {%s}\n", DMA_MGR_SVC_NAME); 68 err = nameservice_blocking_lookup(DMA_MGR_SVC_NAME, &iref); 69 if (err_is_fail(err)) { 70 return err; 71 } 72 73 struct dma_mgr_bind_st st = { 74 .bound = 0x0 75 }; 76 77 DMAMGR_DEBUG("connect: binding to iref [%"PRIxIREF"]\n", iref); 78 struct waitset *ws = get_default_waitset(); 79 err = dma_mgr_bind(iref, bind_cb, &st, ws, IDC_BIND_FLAGS_DEFAULT); 80 if (err_is_fail(err)) { 81 return err; 82 } 83 84 while (st.bound == 0x0) { 85 messages_wait_and_handle_next(); 86 } 87 88 if (err_is_ok(st.err)) { 89 dma_mgr_connected = 0x1; 90 } 91 92 return st.err; 93} 94 95/* 96 * ============================================================================ 97 * Public Interface 98 * ============================================================================ 99 */ 100 101/** 102 * \brief initializes the connection to the DMA manager service in an eager way 103 * 104 * \returns SYS_ERR_OK on success 105 * errval on error 106 */ 107errval_t dma_manager_client_init(void) 108{ 109 errval_t err; 110 111 if (dma_mgr_connected == 0) { 112 err = dma_manager_connect(); 113 if (err_is_fail(err)) { 114 return err; 115 } 116 } 117 return SYS_ERR_OK; 118} 119 120/** 121 * \brief registers a DMA driver with the DMA driver manager 122 * 123 * \param mem_low lower end of the supported memory range 124 * \param mem_high upper end of the supported memory range 125 * \param type DMA device type 126 * \param iref the iref of the exported DMA service 127 * 128 * \returns SYS_ERR_OK on success 129 * DMA_ERR_* on failure 130 */ 131errval_t dma_manager_register_driver(lpaddr_t mem_low, 132 lpaddr_t mem_high, 133 uint8_t type, 134 iref_t iref) 135{ 136#ifdef __k1om__ 137 char buf[30]; 138 snprintf(buf, 30, "%s_%u_%u", DMA_MGR_REGISTERED_DRIVER, 139 (uint8_t) DMA_DEV_TYPE_XEON_PHI, disp_xeon_phi_id()); 140 141 DMAMGR_DEBUG("registering Xeon Phi Driver: {%s}\n", buf); 142 143 return nameservice_register(buf, iref); 144#else 145 errval_t err; 146 errval_t msgerr; 147 148 if (dma_mgr_connected == 0) { 149 err = dma_manager_connect(); 150 if (err_is_fail(err)) { 151 return err; 152 } 153 } 154 155 DMAMGR_DEBUG("register driver: {%016lx, %016lx} @ %"PRIxIREF"\n", mem_low, 156 mem_high, iref); 157 158 //XXX need to figure this out otherwise 159 uint8_t numa_node = (disp_get_core_id() >= 20); 160 161 err = dma_mgr_client->rpc_tx_vtbl.register_driver(dma_mgr_client, mem_low, mem_high, 162 numa_node, type, iref, &msgerr); 163 if (err_is_fail(err)) { 164 DMAMGR_DEBUG("register driver: RPC failed %s\n", err_getstring(err)); 165 return err; 166 } 167 168 return msgerr; 169#endif 170} 171 172/** 173 * \brief queries the DMA manager for a suitable DMA driver for a address, size 174 * pair 175 * 176 * \param addr address of the transfer 177 * \param size size of the desired transfer 178 * \param info returns the driver info 179 * 180 * \returns SYS_ERR_OK on success 181 * DMA_ERR_* on failure 182 */ 183errval_t dma_manager_lookup_driver(lpaddr_t addr, 184 lpaddr_t size, 185 struct dma_mgr_driver_info *info) 186{ 187#ifdef __k1om__ 188 errval_t err; 189 190 if (addr + size > (1UL << 40)) { 191 return DMA_ERR_MEM_OUT_OF_RANGE; 192 } 193 194 char buf[30]; 195 snprintf(buf, 30, "%s_%u_%u", DMA_MGR_REGISTERED_DRIVER, 196 (uint8_t) DMA_DEV_TYPE_XEON_PHI, disp_xeon_phi_id()); 197 198 err = nameservice_lookup(buf, &info->iref); 199 if (err_is_fail(err)) { 200 return DMA_ERR_SVC_VOID; 201 } 202 info->mem_high = (1UL << 40); 203 info->mem_low = 0; 204 info->numa_node = disp_xeon_phi_id(); 205 info->type = DMA_DEV_TYPE_XEON_PHI; 206 return SYS_ERR_OK; 207#else 208 209 errval_t err, msgerr; 210 211 if (dma_mgr_connected == 0) { 212 err = dma_manager_connect(); 213 if (err_is_fail(err)) { 214 return err; 215 } 216 } 217 218 DMAMGR_DEBUG("lookup driver: [%016lx, %016lx]\n", addr, size); 219 220 uint8_t numa_node = (disp_get_core_id() >= 20); 221 222 err = dma_mgr_client->rpc_tx_vtbl.lookup_driver(dma_mgr_client, addr, size, 223 numa_node, &msgerr, &info->mem_low, 224 &info->mem_high, &info->numa_node, 225 (uint8_t*) &info->type, &info->iref); 226 if (err_is_fail(err)) { 227 DMAMGR_DEBUG("register driver: RPC failed %s\n", err_getstring(err)); 228 return err; 229 } 230 231 return msgerr; 232#endif 233} 234 235/** 236 * \brief queries the DMA driver manager based on the service iref 237 * 238 * \param iref iref ot the exported driver service 239 * \param info returns the driver info 240 * 241 * \returns SYS_ERR_OK on success 242 * DMA_ERR_* on failure 243 */ 244errval_t dma_manager_lookup_by_iref(iref_t iref, 245 struct dma_mgr_driver_info *info) 246{ 247#ifdef __k1om__ 248 info->mem_high = (1UL << 40); 249 info->mem_low = 0; 250 info->numa_node = disp_xeon_phi_id(); 251 info->type = DMA_DEV_TYPE_XEON_PHI; 252 info->iref = iref; 253 return SYS_ERR_OK; 254#else 255 errval_t err, msgerr; 256 257 if (dma_mgr_connected == 0) { 258 err = dma_manager_connect(); 259 if (err_is_fail(err)) { 260 return err; 261 } 262 } 263 264 DMAMGR_DEBUG("lookup driver by iref:%"PRIxIREF"\n", iref); 265 266 err = dma_mgr_client->rpc_tx_vtbl.lookup_driver_by_iref(dma_mgr_client, iref, 267 &msgerr, &info->mem_low, 268 &info->mem_high, 269 &info->numa_node, 270 (uint8_t*) &info->type); 271 if (err_is_fail(err)) { 272 DMAMGR_DEBUG("register driver: RPC failed %s\n", err_getstring(err)); 273 return err; 274 } 275 276 info->iref = iref; 277 278 return msgerr; 279#endif 280} 281 282/** 283 * \brief waits until a device driver for the supplied device type is ready 284 * 285 * \param device DMA device type 286 * \param numa_node Numanode of the DMA device driver 287 * 288 * \returns SYS_ERR_OK when the driver is ready 289 * errval if there was something wrong 290 */ 291errval_t dma_manager_wait_for_driver(dma_dev_type_t device, 292 uint8_t numa_node) 293{ 294 char buf[30]; 295 snprintf(buf, 30, "%s_%u_%u", DMA_MGR_REGISTERED_DRIVER, (uint8_t) device, 296 numa_node); 297 298 DMAMGR_DEBUG("waiting for driver: {%s}\n", buf); 299 300 iref_t dummy_iref; 301 return nameservice_blocking_lookup(buf, &dummy_iref); 302} 303