swdmover.c revision 1.4
1/* $NetBSD: swdmover.c,v 1.4 2003/03/06 21:10:45 thorpej Exp $ */ 2 3/* 4 * Copyright (c) 2002 Wasabi Systems, Inc. 5 * All rights reserved. 6 * 7 * Written by Jason R. Thorpe for Wasabi Systems, Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed for the NetBSD Project by 20 * Wasabi Systems, Inc. 21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22 * or promote products derived from this software without specific prior 23 * written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38/* 39 * swdmover.c: Software back-end providing the dmover functions 40 * mentioned in dmover(9). 41 * 42 * This module provides a fallback for cases where no hardware 43 * data movers are present in a system, and also serves an an 44 * example of how to write a dmover back-end. 45 * 46 * Note that even through the software dmover doesn't require 47 * interrupts to be blocked, we block them anyway to demonstrate 48 * the locking protocol. 49 */ 50 51#include <sys/cdefs.h> 52__KERNEL_RCSID(0, "$NetBSD: swdmover.c,v 1.4 2003/03/06 21:10:45 thorpej Exp $"); 53 54#include <sys/param.h> 55#include <sys/lock.h> 56#include <sys/kthread.h> 57#include <sys/systm.h> 58#include <sys/uio.h> 59 60#include <dev/dmover/dmovervar.h> 61 62struct swdmover_function { 63 void (*sdf_process)(struct dmover_request *); 64}; 65 66static struct dmover_backend swdmover_backend; 67static struct proc *swdmover_proc; 68static int swdmover_cv; 69 70void swdmoverattach(int); 71 72/* 73 * swdmover_process: 74 * 75 * Dmover back-end entry point. 76 */ 77static void 78swdmover_process(struct dmover_backend *dmb) 79{ 80 int s; 81 82 /* 83 * Just wake up the processing thread. This will allow 84 * requests to linger on the middle-end's queue so that 85 * they can be cancelled, if need-be. 86 */ 87 s = splbio(); 88 /* XXXLOCK */ 89 if (TAILQ_EMPTY(&dmb->dmb_pendreqs) == 0) 90 wakeup(&swdmover_cv); 91 /* XXXUNLOCK */ 92 splx(s); 93} 94 95/* 96 * swdmover_thread: 97 * 98 * Request processing thread. 99 */ 100static void 101swdmover_thread(void *arg) 102{ 103 struct dmover_backend *dmb = arg; 104 struct dmover_request *dreq; 105 struct swdmover_function *sdf; 106 int s; 107 108 s = splbio(); 109 /* XXXLOCK */ 110 111 for (;;) { 112 dreq = TAILQ_FIRST(&dmb->dmb_pendreqs); 113 if (dreq == NULL) { 114 /* XXXUNLOCK */ 115 (void) tsleep(&swdmover_cv, PRIBIO, "swdmvr", 0); 116 continue; 117 } 118 119 dmover_backend_remque(dmb, dreq); 120 dreq->dreq_flags |= DMOVER_REQ_RUNNING; 121 122 /* XXXUNLOCK */ 123 splx(s); 124 125 sdf = dreq->dreq_assignment->das_algdesc->dad_data; 126 (*sdf->sdf_process)(dreq); 127 128 s = splbio(); 129 /* XXXLOCK */ 130 } 131} 132 133/* 134 * swdmover_func_zero_process: 135 * 136 * Processing routine for the "zero" function. 137 */ 138static void 139swdmover_func_zero_process(struct dmover_request *dreq) 140{ 141 142 switch (dreq->dreq_outbuf_type) { 143 case DMOVER_BUF_LINEAR: 144 memset(dreq->dreq_outbuf.dmbuf_linear.l_addr, 0, 145 dreq->dreq_outbuf.dmbuf_linear.l_len); 146 break; 147 148 case DMOVER_BUF_UIO: 149 { 150 struct uio *uio = dreq->dreq_outbuf.dmbuf_uio; 151 char *cp; 152 size_t count, buflen; 153 int error; 154 155 if (uio->uio_rw != UIO_READ) { 156 /* XXXLOCK */ 157 dreq->dreq_error = EINVAL; 158 dreq->dreq_flags |= DMOVER_REQ_ERROR; 159 /* XXXUNLOCK */ 160 break; 161 } 162 163 buflen = uio->uio_resid; 164 if (buflen > 1024) 165 buflen = 1024; 166 cp = alloca(buflen); 167 memset(cp, 0, buflen); 168 169 while ((count = uio->uio_resid) != 0) { 170 if (count > buflen) 171 count = buflen; 172 error = uiomove(cp, count, uio); 173 if (error) { 174 /* XXXLOCK */ 175 dreq->dreq_error = error; 176 dreq->dreq_flags |= DMOVER_REQ_ERROR; 177 /* XXXUNLOCK */ 178 break; 179 } 180 } 181 break; 182 } 183 184 default: 185 /* XXXLOCK */ 186 dreq->dreq_error = EINVAL; 187 dreq->dreq_flags |= DMOVER_REQ_ERROR; 188 /* XXXUNLOCK */ 189 } 190 191 dmover_done(dreq); 192} 193 194/* 195 * swdmover_func_fill8_process: 196 * 197 * Processing routine for the "fill8" function. 198 */ 199static void 200swdmover_func_fill8_process(struct dmover_request *dreq) 201{ 202 203 switch (dreq->dreq_outbuf_type) { 204 case DMOVER_BUF_LINEAR: 205 memset(dreq->dreq_outbuf.dmbuf_linear.l_addr, 206 dreq->dreq_immediate[0], 207 dreq->dreq_outbuf.dmbuf_linear.l_len); 208 break; 209 210 case DMOVER_BUF_UIO: 211 { 212 struct uio *uio = dreq->dreq_outbuf.dmbuf_uio; 213 char *cp; 214 size_t count, buflen; 215 int error; 216 217 if (uio->uio_rw != UIO_READ) { 218 /* XXXLOCK */ 219 dreq->dreq_error = EINVAL; 220 dreq->dreq_flags |= DMOVER_REQ_ERROR; 221 /* XXXUNLOCK */ 222 break; 223 } 224 225 buflen = uio->uio_resid; 226 if (buflen > 1024) 227 buflen = 1024; 228 cp = alloca(buflen); 229 memset(cp, dreq->dreq_immediate[0], buflen); 230 231 while ((count = uio->uio_resid) != 0) { 232 if (count > buflen) 233 count = buflen; 234 error = uiomove(cp, count, uio); 235 if (error) { 236 /* XXXLOCK */ 237 dreq->dreq_error = error; 238 dreq->dreq_flags |= DMOVER_REQ_ERROR; 239 /* XXXUNLOCK */ 240 break; 241 } 242 } 243 break; 244 } 245 246 default: 247 /* XXXLOCK */ 248 dreq->dreq_error = EINVAL; 249 dreq->dreq_flags |= DMOVER_REQ_ERROR; 250 /* XXXUNLOCK */ 251 } 252 253 dmover_done(dreq); 254} 255 256/* 257 * swdmover_func_copy_process: 258 * 259 * Processing routine for the "copy" function. 260 */ 261static void 262swdmover_func_copy_process(struct dmover_request *dreq) 263{ 264 265 /* XXX Currently, both buffers must be of same type. */ 266 if (dreq->dreq_inbuf_type != dreq->dreq_outbuf_type) { 267 /* XXXLOCK */ 268 dreq->dreq_error = EINVAL; 269 dreq->dreq_flags |= DMOVER_REQ_ERROR; 270 /* XXXUNLOCK */ 271 goto done; 272 } 273 274 switch (dreq->dreq_outbuf_type) { 275 case DMOVER_BUF_LINEAR: 276 if (dreq->dreq_outbuf.dmbuf_linear.l_len != 277 dreq->dreq_inbuf[0].dmbuf_linear.l_len) { 278 /* XXXLOCK */ 279 dreq->dreq_error = EINVAL; 280 dreq->dreq_flags |= DMOVER_REQ_ERROR; 281 /* XXXUNLOCK */ 282 break; 283 } 284 memcpy(dreq->dreq_outbuf.dmbuf_linear.l_addr, 285 dreq->dreq_inbuf[0].dmbuf_linear.l_addr, 286 dreq->dreq_outbuf.dmbuf_linear.l_len); 287 break; 288 289 case DMOVER_BUF_UIO: 290 { 291 struct uio *uio_out = dreq->dreq_outbuf.dmbuf_uio; 292 struct uio *uio_in = dreq->dreq_inbuf[0].dmbuf_uio; 293 char *cp; 294 size_t count, buflen; 295 int error; 296 297 if (uio_in->uio_rw != UIO_WRITE || 298 uio_out->uio_rw != UIO_READ || 299 uio_in->uio_resid != uio_out->uio_resid) { 300 /* XXXLOCK */ 301 dreq->dreq_error = EINVAL; 302 dreq->dreq_flags |= DMOVER_REQ_ERROR; 303 /* XXXUNLOCK */ 304 break; 305 } 306 307 buflen = uio_in->uio_resid; 308 if (buflen > 1024) 309 buflen = 1024; 310 cp = alloca(buflen); 311 312 while ((count = uio_in->uio_resid) != 0) { 313 if (count > buflen) 314 count = buflen; 315 error = uiomove(cp, count, uio_in); 316 if (error == 0) 317 error = uiomove(cp, count, uio_out); 318 if (error) { 319 /* XXXLOCK */ 320 dreq->dreq_error = error; 321 dreq->dreq_flags |= DMOVER_REQ_ERROR; 322 /* XXXUNLOCK */ 323 break; 324 } 325 } 326 break; 327 } 328 329 default: 330 /* XXXLOCK */ 331 dreq->dreq_error = EINVAL; 332 dreq->dreq_flags |= DMOVER_REQ_ERROR; 333 /* XXXUNLOCK */ 334 } 335 336 done: 337 dmover_done(dreq); 338} 339 340static struct swdmover_function swdmover_func_zero = { 341 swdmover_func_zero_process 342}; 343 344static struct swdmover_function swdmover_func_fill8 = { 345 swdmover_func_fill8_process 346}; 347 348struct swdmover_function swdmover_func_copy = { 349 swdmover_func_copy_process 350}; 351 352const struct dmover_algdesc swdmover_algdescs[] = { 353 { 354 DMOVER_FUNC_ZERO, 355 &swdmover_func_zero, 356 0 357 }, 358 { 359 DMOVER_FUNC_FILL8, 360 &swdmover_func_fill8, 361 0 362 }, 363 { 364 DMOVER_FUNC_COPY, 365 &swdmover_func_copy, 366 1 367 }, 368}; 369#define SWDMOVER_ALGDESC_COUNT \ 370 (sizeof(swdmover_algdescs) / sizeof(swdmover_algdescs[0])) 371 372/* 373 * swdmover_create_thread: 374 * 375 * Actually create the swdmover processing thread. 376 */ 377static void 378swdmover_create_thread(void *arg) 379{ 380 int error; 381 382 error = kthread_create1(swdmover_thread, arg, &swdmover_proc, 383 "swdmover"); 384 if (error) 385 printf("WARNING: unable to create swdmover thread, " 386 "error = %d\n", error); 387} 388 389/* 390 * swdmoverattach: 391 * 392 * Pesudo-device attach routine. 393 */ 394void 395swdmoverattach(int count) 396{ 397 398 swdmover_backend.dmb_name = "swdmover"; 399 swdmover_backend.dmb_speed = 1; /* XXX */ 400 swdmover_backend.dmb_cookie = NULL; 401 swdmover_backend.dmb_algdescs = swdmover_algdescs; 402 swdmover_backend.dmb_nalgdescs = SWDMOVER_ALGDESC_COUNT; 403 swdmover_backend.dmb_process = swdmover_process; 404 405 kthread_create(swdmover_create_thread, &swdmover_backend); 406 407 /* XXX Should only register this when kthread creation succeeds. */ 408 dmover_backend_register(&swdmover_backend); 409} 410