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 <barrelfish/barrelfish.h> 11#include <bench/bench.h> 12 13#include <dma_internal.h> 14#include <dma_device_internal.h> 15#include <dma_channel_internal.h> 16#include <dma_request_internal.h> 17#include <debug.h> 18 19/* 20 * --------------------------------------------------------------------------- 21 * Request ID generation 22 * --------------------------------------------------------------------------- 23 */ 24 25inline dma_req_id_t dma_request_generate_req_id(struct dma_channel *chan) 26{ 27 return dma_request_id_build(chan, dma_channel_incr_req_count(chan)); 28} 29 30/** 31 * \brief initializes the common part of a DMA request 32 * 33 * \param req DMA request to initialize 34 * \param chan Channel this request gets executed on 35 * \param type The type of the DMA request 36 * 37 * \return SYS_ERR_OK on success 38 * errval on failure 39 */ 40errval_t dma_request_common_init(struct dma_request *req, 41 struct dma_channel *chan, 42 dma_req_st_t type) 43{ 44 req->id = dma_request_id_build(chan, dma_channel_incr_req_count(chan)); 45 req->type = type; 46 req->state = DMA_REQ_ST_INVALID; 47 48#if DMA_BENCH_ENABLED 49 req->timer_start = bench_tsc(); 50#endif 51 return SYS_ERR_OK; 52} 53 54/** 55 * \brief handles the processing of completed DMA requests 56 * 57 * \param req the DMA request to process 58 * 59 * \returns SYS_ERR_OK on sucess 60 * errval on failure 61 */ 62errval_t dma_request_process(struct dma_request *req) 63{ 64 DMAREQ_DEBUG("Processing done request [%016lx]:\n", req->id); 65 66 errval_t err; 67 68 switch (req->state) { 69 case DMA_REQ_ST_DONE: 70 err = SYS_ERR_OK; 71 break; 72 default: 73 err = DMA_ERR_CHAN_ERROR; // todo: error code 74 break; 75 } 76 77#if DMA_BENCH_ENABLED 78 cycles_t timer_end = bench_tsc(); 79 debug_printf("DMA request %016lx took %lu cycles (%lu ms)\n", 80 req->id, timer_end - req->timer_start, 81 bench_tsc_to_ms(timer_end - req->timer_start)); 82#endif 83 84 if (req->setup.done_cb) { 85 req->setup.done_cb(err, req->id, req->setup.cb_arg); 86 } 87 88 return SYS_ERR_OK; 89} 90 91/* 92 * ---------------------------------------------------------------------------- 93 * Getter / Setter Functions 94 * ---------------------------------------------------------------------------- 95 */ 96 97/** 98 * \brief returns the state of a DMA request 99 * 100 * \param req DMA request 101 * 102 * \returns DMA request state 103 */ 104inline dma_req_st_t dma_request_get_state(struct dma_request *req) 105{ 106 return req->state; 107} 108 109/** 110 * \brief returns the ID of a DMA request 111 * 112 * \param req DMA request 113 * 114 * \returns DMA request ID 115 */ 116inline dma_req_id_t dma_request_get_id(struct dma_request *req) 117{ 118 return req->id; 119} 120 121/** 122 * \brief returns the next DMA request of the given request 123 * 124 * \param req DMA request 125 * 126 * \returns DMA request if there was one 127 * NULL if the request is at the end of the chain 128 */ 129inline struct dma_request *dma_request_get_next(struct dma_request *req) 130{ 131 return req->next; 132} 133 134/** 135 * \brief sets the next DMA request of the given request 136 * 137 * \param req DMA request 138 * \param next DMA request 139 */ 140inline void dma_request_set_next(struct dma_request *req, 141 struct dma_request *next) 142{ 143 req->next = next; 144} 145 146/* 147 * ============================================================================ 148 * Public Interface 149 * ============================================================================ 150 */ 151 152/* 153 * ---------------------------------------------------------------------------- 154 * Memory Registration 155 * ---------------------------------------------------------------------------- 156 */ 157 158/** 159 * \brief registers a memory region for future use 160 * 161 * \param frame the memory frame to register 162 * 163 * \returns SYS_ERR_OK on succes 164 * errval on error 165 */ 166errval_t dma_register_memory(struct dma_device *dev, 167 struct capref frame) 168{ 169 if (dev->f.register_memory == NULL) { 170 return DMA_ERR_REQUEST_UNSUPPORTED; 171 } 172 return dev->f.register_memory(dev, frame); 173} 174 175/** 176 * \brief deregisters a previously registered memory region 177 * 178 * \param frame the memory frame to register 179 * 180 * \returns SYS_ERR_OK on succes 181 * errval on error 182 */ 183errval_t dma_request_deregister_memory(struct dma_device *dev, 184 struct capref frame) 185{ 186 if (dev->f.deregister_memory == NULL) { 187 return DMA_ERR_REQUEST_UNSUPPORTED; 188 } 189 return dev->f.deregister_memory(dev, frame); 190} 191 192/* 193 * ---------------------------------------------------------------------------- 194 * Request Execution 195 * ---------------------------------------------------------------------------- 196 */ 197 198/** 199 * \brief issues a new DMA memcpy request based on the setup information 200 * 201 * \param chan DMA channel 202 * \param setup DMA request setup information 203 * \param id returns the DMA request ID 204 * 205 * \returns SYS_ERR_OK on success 206 * errval on error 207 */ 208errval_t dma_request_memcpy_chan(struct dma_channel *chan, 209 struct dma_req_setup *setup, 210 dma_req_id_t *id) 211{ 212 /* check for overlap */ 213 if (setup->args.memcpy.dst < setup->args.memcpy.src) { 214 if ((setup->args.memcpy.dst + setup->args.memcpy.bytes) > setup->args.memcpy.src) { 215 return DMA_ERR_MEM_OVERLAP; 216 } 217 } else if ((setup->args.memcpy.dst > setup->args.memcpy.src)) { 218 if ((setup->args.memcpy.src + setup->args.memcpy.bytes) > setup->args.memcpy.dst) { 219 return DMA_ERR_MEM_OVERLAP; 220 } 221 } else { 222 /* they are equal so they will overlap */ 223 return DMA_ERR_MEM_OVERLAP; 224 } 225 226 if (chan->f.memcpy == NULL) { 227 return DMA_ERR_REQUEST_UNSUPPORTED; 228 } 229 230 return chan->f.memcpy(chan, setup, id); 231} 232 233/** 234 * \brief issues a new DMA memcpy request based on the setup information 235 * 236 * \param dev DMA device 237 * \param setup DMA request setup information 238 * \param id returns the DMA request ID 239 * 240 * \returns SYS_ERR_OK on success 241 * errval on error 242 */ 243errval_t dma_request_memcpy(struct dma_device *dev, 244 struct dma_req_setup *setup, 245 dma_req_id_t *id) 246{ 247 struct dma_channel *chan = dma_device_get_channel(dev); 248 return dma_request_memcpy_chan(chan, setup, id); 249} 250 251/** 252 * \brief issues a new DMA memcpy request based on the setup information 253 * 254 * \param chan DMA channel 255 * \param setup DMA request setup information 256 * \param id returns the DMA request ID 257 * 258 * \returns SYS_ERR_OK on success 259 * errval on error 260 */ 261errval_t dma_request_memset_chan(struct dma_channel *chan, 262 struct dma_req_setup *setup, 263 dma_req_id_t *id) 264{ 265 if (chan->f.memset == NULL) { 266 return DMA_ERR_REQUEST_UNSUPPORTED; 267 } 268 269 return chan->f.memset(chan, setup, id); 270} 271 272/** 273 * \brief issues a new DMA memcpy request based on the setup information 274 * 275 * \param dev DMA device 276 * \param setup DMA request setup information 277 * \param id returns the DMA request ID 278 * 279 * \returns SYS_ERR_OK on success 280 * errval on error 281 */ 282errval_t dma_request_memset(struct dma_device *dev, 283 struct dma_req_setup *setup, 284 dma_req_id_t *id) 285{ 286 struct dma_channel *chan = dma_device_get_channel(dev); 287 return dma_request_memset_chan(chan, setup, id); 288} 289 290 291