1 /* $NetBSD: fwmem.c,v 1.2 2005/12/11 12:22:02 christos Exp $ */
2 /*-
3 * Copyright (c) 2002-2003
4 * Hidetoshi Shimokawa. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 *
17 * This product includes software developed by Hidetoshi Shimokawa.
18 *
19 * 4. Neither the name of the author nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 */
36
37 #include <sys/cdefs.h>
38 #ifdef __FBSDID
39 __FBSDID("$FreeBSD: /repoman/r/ncvs/src/sys/dev/firewire/fwmem.c,v 1.31 2005/01/06 01:42:41 imp Exp $");
40 #endif
41
42 #if defined(__FreeBSD__)
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/types.h>
46
47 #include <sys/kernel.h>
48 #include <sys/malloc.h>
49 #include <sys/conf.h>
50 #include <sys/sysctl.h>
51 #if defined(__DragonFly__) || __FreeBSD_version < 500000
52 #include <sys/buf.h>
53 #else
54 #include <sys/bio.h>
55 #endif
56
57 #include <sys/bus.h>
58 #include <machine/bus.h>
59
60 #include <sys/signal.h>
61 #include <sys/mman.h>
62 #include <sys/ioccom.h>
63 #include <sys/fcntl.h>
64 #include <sys/ktr.h>
65
66 #ifdef __DragonFly__
67 #include "fw_port.h"
68 #include "firewire.h"
69 #include "firewirereg.h"
70 #include "fwmem.h"
71 #else
72 #include <dev/firewire/fw_port.h>
73 #include <dev/firewire/firewire.h>
74 #include <dev/firewire/firewirereg.h>
75 #include <dev/firewire/fwmem.h>
76 #endif
77 #elif defined(__NetBSD__)
78 #include <sys/param.h>
79 #include <sys/device.h>
80 #include <sys/errno.h>
81 #include <sys/buf.h>
82 #include <sys/conf.h>
83 #include <sys/fcntl.h>
84 #include <sys/malloc.h>
85 #include <sys/sysctl.h>
86
87 #include <machine/bus.h>
88
89 #include <dev/ieee1394/fw_port.h>
90 #include <dev/ieee1394/firewire.h>
91 #include <dev/ieee1394/firewirereg.h>
92 #include <dev/ieee1394/fwmem.h>
93 #endif
94
95 static int fwmem_speed=2, fwmem_debug=0;
96 static struct fw_eui64 fwmem_eui64;
97 #if defined(__FreeBSD__)
98 SYSCTL_DECL(_hw_firewire);
99 SYSCTL_NODE(_hw_firewire, OID_AUTO, fwmem, CTLFLAG_RD, 0,
100 "FireWire Memory Access");
101 SYSCTL_UINT(_hw_firewire_fwmem, OID_AUTO, eui64_hi, CTLFLAG_RW,
102 &fwmem_eui64.hi, 0, "Fwmem target EUI64 high");
103 SYSCTL_UINT(_hw_firewire_fwmem, OID_AUTO, eui64_lo, CTLFLAG_RW,
104 &fwmem_eui64.lo, 0, "Fwmem target EUI64 low");
105 SYSCTL_INT(_hw_firewire_fwmem, OID_AUTO, speed, CTLFLAG_RW, &fwmem_speed, 0,
106 "Fwmem link speed");
107 SYSCTL_INT(_debug, OID_AUTO, fwmem_debug, CTLFLAG_RW, &fwmem_debug, 0,
108 "Fwmem driver debug flag");
109 MALLOC_DEFINE(M_FWMEM, "fwmem", "fwmem/FireWire");
110 #elif defined(__NetBSD__)
111 static int sysctl_fwmem_verify(SYSCTLFN_PROTO, int, int);
112 static int sysctl_fwmem_verify_speed(SYSCTLFN_PROTO);
113
114 /*
115 * Setup sysctl(3) MIB, hw.fwmem.*
116 *
117 * TBD condition CTLFLAG_PERMANENT on being an LKM or not
118 */
119 SYSCTL_SETUP(sysctl_fwmem, "sysctl fwmem subtree setup")
120 {
121 int rc, fwmem_node_num;
122 const struct sysctlnode *node;
123
124 if ((rc = sysctl_createv(clog, 0, NULL, NULL,
125 CTLFLAG_PERMANENT, CTLTYPE_NODE, "hw", NULL,
126 NULL, 0, NULL, 0, CTL_HW, CTL_EOL)) != 0) {
127 goto err;
128 }
129
130 if ((rc = sysctl_createv(clog, 0, NULL, &node,
131 CTLFLAG_PERMANENT, CTLTYPE_NODE, "fwmem",
132 SYSCTL_DESCR("IEEE1394 Memory Access"),
133 NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL)) != 0) {
134 goto err;
135 }
136 fwmem_node_num = node->sysctl_num;
137
138 /* fwmem target EUI64 high/low */
139 if ((rc = sysctl_createv(clog, 0, NULL, &node,
140 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, CTLTYPE_INT,
141 "eui64_hi", SYSCTL_DESCR("Fwmem target EUI64 high"),
142 NULL, 0, &fwmem_eui64.hi,
143 0, CTL_HW, fwmem_node_num, CTL_CREATE, CTL_EOL)) != 0) {
144 goto err;
145 }
146 if ((rc = sysctl_createv(clog, 0, NULL, &node,
147 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, CTLTYPE_INT,
148 "eui64_lo", SYSCTL_DESCR("Fwmem target EUI64 low"),
149 NULL, 0, &fwmem_eui64.lo,
150 0, CTL_HW, fwmem_node_num, CTL_CREATE, CTL_EOL)) != 0) {
151 goto err;
152 }
153
154 /* fwmem link speed */
155 if ((rc = sysctl_createv(clog, 0, NULL, &node,
156 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, CTLTYPE_INT,
157 "speed", SYSCTL_DESCR("Fwmem link speed"),
158 sysctl_fwmem_verify_speed, 0, &fwmem_speed,
159 0, CTL_HW, fwmem_node_num, CTL_CREATE, CTL_EOL)) != 0) {
160 goto err;
161 }
162
163 /* fwmem driver debug flag */
164 if ((rc = sysctl_createv(clog, 0, NULL, &node,
165 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, CTLTYPE_INT,
166 "fwmem_debug", SYSCTL_DESCR("Fwmem driver debug flag"),
167 NULL, 0, &fwmem_debug,
168 0, CTL_HW, fwmem_node_num, CTL_CREATE, CTL_EOL)) != 0) {
169 goto err;
170 }
171
172 return;
173
174 err:
175 printf("%s: sysctl_createv failed (rc = %d)\n", __func__, rc);
176 }
177
178 static int
179 sysctl_fwmem_verify(SYSCTLFN_ARGS, int lower, int upper)
180 {
181 int error, t;
182 struct sysctlnode node;
183
184 node = *rnode;
185 t = *(int*)rnode->sysctl_data;
186 node.sysctl_data = &t;
187 error = sysctl_lookup(SYSCTLFN_CALL(&node));
188 if (error || newp == NULL)
189 return (error);
190
191 if (t < lower || t > upper)
192 return (EINVAL);
193
194 *(int*)rnode->sysctl_data = t;
195
196 return (0);
197 }
198
199 static int
200 sysctl_fwmem_verify_speed(SYSCTLFN_ARGS)
201 {
202 return (sysctl_fwmem_verify(SYSCTLFN_CALL(rnode), 0, FWSPD_S400));
203 }
204
205 MALLOC_DEFINE(M_FWMEM, "fwmem", "fwmem/IEEE1394");
206 #endif
207
208 #define MAXLEN (512 << fwmem_speed)
209
210 struct fwmem_softc {
211 struct fw_eui64 eui;
212 int refcount;
213 STAILQ_HEAD(, fw_xfer) xferlist;
214 };
215
216 static struct fw_xfer *
217 fwmem_xfer_req(
218 struct fw_device *fwdev,
219 caddr_t sc,
220 int spd,
221 int slen,
222 int rlen,
223 void *hand)
224 {
225 struct fw_xfer *xfer;
226
227 xfer = fw_xfer_alloc(M_FWMEM);
228 if (xfer == NULL)
229 return NULL;
230
231 xfer->fc = fwdev->fc;
232 xfer->send.hdr.mode.hdr.dst = FWLOCALBUS | fwdev->dst;
233 if (spd < 0)
234 xfer->send.spd = fwdev->speed;
235 else
236 xfer->send.spd = min(spd, fwdev->speed);
237 xfer->hand = hand;
238 xfer->sc = sc;
239 xfer->send.pay_len = slen;
240 xfer->recv.pay_len = rlen;
241
242 return xfer;
243 }
244
245 struct fw_xfer *
246 fwmem_read_quad(
247 struct fw_device *fwdev,
248 caddr_t sc,
249 uint8_t spd,
250 uint16_t dst_hi,
251 uint32_t dst_lo,
252 void *data,
253 void (*hand)(struct fw_xfer *))
254 {
255 struct fw_xfer *xfer;
256 struct fw_pkt *fp;
257
258 xfer = fwmem_xfer_req(fwdev, (void *)sc, spd, 0, 4, hand);
259 if (xfer == NULL) {
260 return NULL;
261 }
262
263 fp = &xfer->send.hdr;
264 fp->mode.rreqq.tcode = FWTCODE_RREQQ;
265 fp->mode.rreqq.dest_hi = dst_hi;
266 fp->mode.rreqq.dest_lo = dst_lo;
267
268 xfer->send.payload = NULL;
269 xfer->recv.payload = (uint32_t *)data;
270
271 if (fwmem_debug)
272 printf("fwmem_read_quad: %d %04x:%08x\n", fwdev->dst,
273 dst_hi, dst_lo);
274
275 if (fw_asyreq(xfer->fc, -1, xfer) == 0)
276 return xfer;
277
278 fw_xfer_free(xfer);
279 return NULL;
280 }
281
282 struct fw_xfer *
283 fwmem_write_quad(
284 struct fw_device *fwdev,
285 caddr_t sc,
286 uint8_t spd,
287 uint16_t dst_hi,
288 uint32_t dst_lo,
289 void *data,
290 void (*hand)(struct fw_xfer *))
291 {
292 struct fw_xfer *xfer;
293 struct fw_pkt *fp;
294
295 xfer = fwmem_xfer_req(fwdev, sc, spd, 0, 0, hand);
296 if (xfer == NULL)
297 return NULL;
298
299 fp = &xfer->send.hdr;
300 fp->mode.wreqq.tcode = FWTCODE_WREQQ;
301 fp->mode.wreqq.dest_hi = dst_hi;
302 fp->mode.wreqq.dest_lo = dst_lo;
303 fp->mode.wreqq.data = *(uint32_t *)data;
304
305 xfer->send.payload = xfer->recv.payload = NULL;
306
307 if (fwmem_debug)
308 printf("fwmem_write_quad: %d %04x:%08x %08x\n", fwdev->dst,
309 dst_hi, dst_lo, *(uint32_t *)data);
310
311 if (fw_asyreq(xfer->fc, -1, xfer) == 0)
312 return xfer;
313
314 fw_xfer_free(xfer);
315 return NULL;
316 }
317
318 struct fw_xfer *
319 fwmem_read_block(
320 struct fw_device *fwdev,
321 caddr_t sc,
322 uint8_t spd,
323 uint16_t dst_hi,
324 uint32_t dst_lo,
325 int len,
326 void *data,
327 void (*hand)(struct fw_xfer *))
328 {
329 struct fw_xfer *xfer;
330 struct fw_pkt *fp;
331
332 xfer = fwmem_xfer_req(fwdev, sc, spd, 0, roundup2(len, 4), hand);
333 if (xfer == NULL)
334 return NULL;
335
336 fp = &xfer->send.hdr;
337 fp->mode.rreqb.tcode = FWTCODE_RREQB;
338 fp->mode.rreqb.dest_hi = dst_hi;
339 fp->mode.rreqb.dest_lo = dst_lo;
340 fp->mode.rreqb.len = len;
341 fp->mode.rreqb.extcode = 0;
342
343 xfer->send.payload = NULL;
344 xfer->recv.payload = data;
345
346 if (fwmem_debug)
347 printf("fwmem_read_block: %d %04x:%08x %d\n", fwdev->dst,
348 dst_hi, dst_lo, len);
349 if (fw_asyreq(xfer->fc, -1, xfer) == 0)
350 return xfer;
351
352 fw_xfer_free(xfer);
353 return NULL;
354 }
355
356 struct fw_xfer *
357 fwmem_write_block(
358 struct fw_device *fwdev,
359 caddr_t sc,
360 uint8_t spd,
361 uint16_t dst_hi,
362 uint32_t dst_lo,
363 int len,
364 void *data,
365 void (*hand)(struct fw_xfer *))
366 {
367 struct fw_xfer *xfer;
368 struct fw_pkt *fp;
369
370 xfer = fwmem_xfer_req(fwdev, sc, spd, len, 0, hand);
371 if (xfer == NULL)
372 return NULL;
373
374 fp = &xfer->send.hdr;
375 fp->mode.wreqb.tcode = FWTCODE_WREQB;
376 fp->mode.wreqb.dest_hi = dst_hi;
377 fp->mode.wreqb.dest_lo = dst_lo;
378 fp->mode.wreqb.len = len;
379 fp->mode.wreqb.extcode = 0;
380
381 xfer->send.payload = data;
382 xfer->recv.payload = NULL;
383
384 if (fwmem_debug)
385 printf("fwmem_write_block: %d %04x:%08x %d\n", fwdev->dst,
386 dst_hi, dst_lo, len);
387 if (fw_asyreq(xfer->fc, -1, xfer) == 0)
388 return xfer;
389
390 fw_xfer_free(xfer);
391 return NULL;
392 }
393
394
395 FW_OPEN(fwmem)
396 {
397 struct fwmem_softc *fms;
398 struct fw_xfer *xfer;
399 FW_OPEN_START;
400
401 if (dev->si_drv1 != NULL) {
402 if ((flags & FWRITE) != 0)
403 return (EBUSY);
404 fms = (struct fwmem_softc *)dev->si_drv1;
405 fms->refcount ++;
406 } else {
407 fms = (struct fwmem_softc *)malloc(sizeof(struct fwmem_softc),
408 M_FWMEM, M_WAITOK);
409 if (fms == NULL)
410 return ENOMEM;
411 bcopy(&fwmem_eui64, &fms->eui, sizeof(struct fw_eui64));
412 dev->si_drv1 = (void *)fms;
413 dev->si_iosize_max = DFLTPHYS;
414 fms->refcount = 1;
415 STAILQ_INIT(&fms->xferlist);
416 xfer = fw_xfer_alloc(M_FWMEM);
417 STAILQ_INSERT_TAIL(&fms->xferlist, xfer, link);
418 }
419 if (fwmem_debug)
420 printf("%s: refcount=%d\n", __func__, fms->refcount);
421
422 return (0);
423 }
424
425 FW_CLOSE(fwmem)
426 {
427 struct fwmem_softc *fms;
428 struct fw_xfer *xfer;
429 FW_CLOSE_START;
430
431 fms = (struct fwmem_softc *)dev->si_drv1;
432 fms->refcount --;
433 if (fwmem_debug)
434 printf("%s: refcount=%d\n", __func__, fms->refcount);
435 if (fms->refcount < 1) {
436 while ((xfer = STAILQ_FIRST(&fms->xferlist)) != NULL) {
437 STAILQ_REMOVE_HEAD(&fms->xferlist, link);
438 fw_xfer_free(xfer);
439 }
440 free(dev->si_drv1, M_FW);
441 dev->si_drv1 = NULL;
442 }
443
444 return (0);
445 }
446
447
448 static void
449 fwmem_biodone(struct fw_xfer *xfer)
450 {
451 struct bio *bp;
452
453 bp = (struct bio *)xfer->sc;
454 bp->bio_error = xfer->resp;
455
456 if (bp->bio_error != 0) {
457 if (fwmem_debug)
458 printf("%s: err=%d\n", __func__, bp->bio_error);
459 bp->bio_flags |= BIO_ERROR;
460 bp->bio_resid = bp->bio_bcount;
461 }
462
463 CTR0(KTR_DEV, "biodone0");
464 fw_xfer_free(xfer);
465 CTR0(KTR_DEV, "biodone1");
466 biodone(bp);
467 CTR0(KTR_DEV, "biodone2");
468 }
469
470 void
471 fwmem_strategy(struct bio *bp)
472 {
473 FW_STRATEGY_START;
474 struct fwmem_softc *fms;
475 struct fw_device *fwdev;
476 struct fw_xfer *xfer;
477 int err=0, s, iolen;
478
479 CTR0(KTR_DEV, "strategy");
480
481 /* XXX check request length */
482
483 s = splfw();
484 fms = (struct fwmem_softc *)dev->si_drv1;
485 fwdev = fw_noderesolve_eui64(sc->fc, &fms->eui);
486 if (fwdev == NULL) {
487 if (fwmem_debug)
488 printf("fwmem: no such device ID:%08x%08x\n",
489 fms->eui.hi, fms->eui.lo);
490 err = EINVAL;
491 goto error;
492 }
493
494 iolen = MIN(bp->bio_bcount, MAXLEN);
495 if ((bp->bio_cmd & BIO_READ) == BIO_READ) {
496 if (iolen == 4 && (bp->bio_offset & 3) == 0)
497 xfer = fwmem_read_quad(fwdev,
498 (void *) bp, fwmem_speed,
499 bp->bio_offset >> 32, bp->bio_offset & 0xffffffff,
500 bp->bio_data, fwmem_biodone);
501 else
502 xfer = fwmem_read_block(fwdev,
503 (void *) bp, fwmem_speed,
504 bp->bio_offset >> 32, bp->bio_offset & 0xffffffff,
505 iolen, bp->bio_data, fwmem_biodone);
506 } else {
507 if (iolen == 4 && (bp->bio_offset & 3) == 0)
508 xfer = fwmem_write_quad(fwdev,
509 (void *)bp, fwmem_speed,
510 bp->bio_offset >> 32, bp->bio_offset & 0xffffffff,
511 bp->bio_data, fwmem_biodone);
512 else
513 xfer = fwmem_write_block(fwdev,
514 (void *)bp, fwmem_speed,
515 bp->bio_offset >> 32, bp->bio_offset & 0xffffffff,
516 iolen, bp->bio_data, fwmem_biodone);
517 }
518 if (xfer == NULL) {
519 err = EIO;
520 goto error;
521 }
522 /* XXX */
523 bp->bio_resid = bp->bio_bcount - iolen;
524 error:
525 splx(s);
526 if (err != 0) {
527 if (fwmem_debug)
528 printf("%s: err=%d\n", __func__, err);
529 bp->bio_error = err;
530 bp->bio_flags |= BIO_ERROR;
531 bp->bio_resid = bp->bio_bcount;
532 biodone(bp);
533 }
534 }
535
536 FW_IOCTL(fwmem)
537 {
538 FW_IOCTL_START;
539 struct fwmem_softc *fms;
540 int err = 0;
541
542 fms = (struct fwmem_softc *)dev->si_drv1;
543 switch (cmd) {
544 case FW_SDEUI64:
545 bcopy(data, &fms->eui, sizeof(struct fw_eui64));
546 break;
547 case FW_GDEUI64:
548 bcopy(&fms->eui, data, sizeof(struct fw_eui64));
549 break;
550 default:
551 err = EINVAL;
552 }
553 return(err);
554 }
555
556 FW_POLL(fwmem)
557 {
558 return EINVAL;
559 }
560
561 FW_MMAP(fwmem)
562 {
563 return EINVAL;
564 }
Cache object: e4b848331b28750ea509b33e3fd4d7c0
|