1 /* $NetBSD: fwmem.c,v 1.10 2009/03/18 17:06:49 cegger Exp $ */
3 * Copyright (c) 2002-2003
4 * Hidetoshi Shimokawa. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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:
17 * This product includes software developed by Hidetoshi Shimokawa.
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.
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
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: fwmem.c,v 1.10 2009/03/18 17:06:49 cegger Exp $");
39 #if defined(__FreeBSD__)
40 __FBSDID("$FreeBSD: src/sys/dev/firewire/fwmem.c,v 1.34 2007/06/06 14:31:36 simokawa Exp $");
43 #if defined(__FreeBSD__)
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/types.h>
48 #include <sys/kernel.h>
49 #include <sys/malloc.h>
51 #include <sys/sysctl.h>
52 #if defined(__DragonFly__) || __FreeBSD_version < 500000
61 #include <sys/signal.h>
63 #include <sys/ioccom.h>
64 #include <sys/fcntl.h>
70 #include "firewirereg.h"
73 #include <dev/firewire/fw_port.h>
74 #include <dev/firewire/firewire.h>
75 #include <dev/firewire/firewirereg.h>
76 #include <dev/firewire/fwmem.h>
78 #elif defined(__NetBSD__)
79 #include <sys/param.h>
80 #include <sys/device.h>
81 #include <sys/errno.h>
84 #include <sys/fcntl.h>
85 #include <sys/malloc.h>
86 #include <sys/sysctl.h>
90 #include <dev/ieee1394/fw_port.h>
91 #include <dev/ieee1394/firewire.h>
92 #include <dev/ieee1394/firewirereg.h>
93 #include <dev/ieee1394/fwmem.h>
96 static int fwmem_speed
=2, fwmem_debug
=0;
97 static struct fw_eui64 fwmem_eui64
;
98 #if defined(__FreeBSD__)
99 SYSCTL_DECL(_hw_firewire
);
100 SYSCTL_NODE(_hw_firewire
, OID_AUTO
, fwmem
, CTLFLAG_RD
, 0,
101 "FireWire Memory Access");
102 SYSCTL_UINT(_hw_firewire_fwmem
, OID_AUTO
, eui64_hi
, CTLFLAG_RW
,
103 &fwmem_eui64
.hi
, 0, "Fwmem target EUI64 high");
104 SYSCTL_UINT(_hw_firewire_fwmem
, OID_AUTO
, eui64_lo
, CTLFLAG_RW
,
105 &fwmem_eui64
.lo
, 0, "Fwmem target EUI64 low");
106 SYSCTL_INT(_hw_firewire_fwmem
, OID_AUTO
, speed
, CTLFLAG_RW
, &fwmem_speed
, 0,
108 SYSCTL_INT(_debug
, OID_AUTO
, fwmem_debug
, CTLFLAG_RW
, &fwmem_debug
, 0,
109 "Fwmem driver debug flag");
110 MALLOC_DEFINE(M_FWMEM
, "fwmem", "fwmem/FireWire");
111 #elif defined(__NetBSD__)
112 static int sysctl_fwmem_verify(SYSCTLFN_PROTO
, int, int);
113 static int sysctl_fwmem_verify_speed(SYSCTLFN_PROTO
);
116 * Setup sysctl(3) MIB, hw.fwmem.*
118 * TBD condition CTLFLAG_PERMANENT on being a module or not
120 SYSCTL_SETUP(sysctl_fwmem
, "sysctl fwmem subtree setup")
122 int rc
, fwmem_node_num
;
123 const struct sysctlnode
*node
;
125 if ((rc
= sysctl_createv(clog
, 0, NULL
, NULL
,
126 CTLFLAG_PERMANENT
, CTLTYPE_NODE
, "hw", NULL
,
127 NULL
, 0, NULL
, 0, CTL_HW
, CTL_EOL
)) != 0) {
131 if ((rc
= sysctl_createv(clog
, 0, NULL
, &node
,
132 CTLFLAG_PERMANENT
, CTLTYPE_NODE
, "fwmem",
133 SYSCTL_DESCR("IEEE1394 Memory Access"),
134 NULL
, 0, NULL
, 0, CTL_HW
, CTL_CREATE
, CTL_EOL
)) != 0) {
137 fwmem_node_num
= node
->sysctl_num
;
139 /* fwmem target EUI64 high/low */
140 if ((rc
= sysctl_createv(clog
, 0, NULL
, &node
,
141 CTLFLAG_PERMANENT
| CTLFLAG_READWRITE
, CTLTYPE_INT
,
142 "eui64_hi", SYSCTL_DESCR("Fwmem target EUI64 high"),
143 NULL
, 0, &fwmem_eui64
.hi
,
144 0, CTL_HW
, fwmem_node_num
, CTL_CREATE
, CTL_EOL
)) != 0) {
147 if ((rc
= sysctl_createv(clog
, 0, NULL
, &node
,
148 CTLFLAG_PERMANENT
| CTLFLAG_READWRITE
, CTLTYPE_INT
,
149 "eui64_lo", SYSCTL_DESCR("Fwmem target EUI64 low"),
150 NULL
, 0, &fwmem_eui64
.lo
,
151 0, CTL_HW
, fwmem_node_num
, CTL_CREATE
, CTL_EOL
)) != 0) {
155 /* fwmem link speed */
156 if ((rc
= sysctl_createv(clog
, 0, NULL
, &node
,
157 CTLFLAG_PERMANENT
| CTLFLAG_READWRITE
, CTLTYPE_INT
,
158 "speed", SYSCTL_DESCR("Fwmem link speed"),
159 sysctl_fwmem_verify_speed
, 0, &fwmem_speed
,
160 0, CTL_HW
, fwmem_node_num
, CTL_CREATE
, CTL_EOL
)) != 0) {
164 /* fwmem driver debug flag */
165 if ((rc
= sysctl_createv(clog
, 0, NULL
, &node
,
166 CTLFLAG_PERMANENT
| CTLFLAG_READWRITE
, CTLTYPE_INT
,
167 "fwmem_debug", SYSCTL_DESCR("Fwmem driver debug flag"),
168 NULL
, 0, &fwmem_debug
,
169 0, CTL_HW
, fwmem_node_num
, CTL_CREATE
, CTL_EOL
)) != 0) {
176 printf("%s: sysctl_createv failed (rc = %d)\n", __func__
, rc
);
180 sysctl_fwmem_verify(SYSCTLFN_ARGS
, int lower
, int upper
)
183 struct sysctlnode node
;
186 t
= *(int*)rnode
->sysctl_data
;
187 node
.sysctl_data
= &t
;
188 error
= sysctl_lookup(SYSCTLFN_CALL(&node
));
189 if (error
|| newp
== NULL
)
192 if (t
< lower
|| t
> upper
)
195 *(int*)rnode
->sysctl_data
= t
;
201 sysctl_fwmem_verify_speed(SYSCTLFN_ARGS
)
203 return (sysctl_fwmem_verify(SYSCTLFN_CALL(rnode
), 0, FWSPD_S400
));
206 MALLOC_DEFINE(M_FWMEM
, "fwmem", "fwmem/IEEE1394");
209 #define MAXLEN (512 << fwmem_speed)
213 struct firewire_softc
*sc
;
215 STAILQ_HEAD(, fw_xfer
) xferlist
;
218 static struct fw_xfer
*
220 struct fw_device
*fwdev
,
227 struct fw_xfer
*xfer
;
229 xfer
= fw_xfer_alloc(M_FWMEM
);
233 xfer
->fc
= fwdev
->fc
;
234 xfer
->send
.hdr
.mode
.hdr
.dst
= FWLOCALBUS
| fwdev
->dst
;
236 xfer
->send
.spd
= fwdev
->speed
;
238 xfer
->send
.spd
= min(spd
, fwdev
->speed
);
241 xfer
->send
.pay_len
= slen
;
242 xfer
->recv
.pay_len
= rlen
;
249 struct fw_device
*fwdev
,
255 void (*hand
)(struct fw_xfer
*))
257 struct fw_xfer
*xfer
;
260 xfer
= fwmem_xfer_req(fwdev
, (void *)sc
, spd
, 0, 4, hand
);
265 fp
= &xfer
->send
.hdr
;
266 fp
->mode
.rreqq
.tcode
= FWTCODE_RREQQ
;
267 fp
->mode
.rreqq
.dest_hi
= dst_hi
;
268 fp
->mode
.rreqq
.dest_lo
= dst_lo
;
270 xfer
->send
.payload
= NULL
;
271 xfer
->recv
.payload
= (uint32_t *)data
;
274 printf("fwmem_read_quad: %d %04x:%08x\n", fwdev
->dst
,
277 if (fw_asyreq(xfer
->fc
, -1, xfer
) == 0)
286 struct fw_device
*fwdev
,
292 void (*hand
)(struct fw_xfer
*))
294 struct fw_xfer
*xfer
;
297 xfer
= fwmem_xfer_req(fwdev
, sc
, spd
, 0, 0, hand
);
301 fp
= &xfer
->send
.hdr
;
302 fp
->mode
.wreqq
.tcode
= FWTCODE_WREQQ
;
303 fp
->mode
.wreqq
.dest_hi
= dst_hi
;
304 fp
->mode
.wreqq
.dest_lo
= dst_lo
;
305 fp
->mode
.wreqq
.data
= *(uint32_t *)data
;
307 xfer
->send
.payload
= xfer
->recv
.payload
= NULL
;
310 printf("fwmem_write_quad: %d %04x:%08x %08x\n", fwdev
->dst
,
311 dst_hi
, dst_lo
, *(uint32_t *)data
);
313 if (fw_asyreq(xfer
->fc
, -1, xfer
) == 0)
322 struct fw_device
*fwdev
,
329 void (*hand
)(struct fw_xfer
*))
331 struct fw_xfer
*xfer
;
334 xfer
= fwmem_xfer_req(fwdev
, sc
, spd
, 0, roundup2(len
, 4), hand
);
338 fp
= &xfer
->send
.hdr
;
339 fp
->mode
.rreqb
.tcode
= FWTCODE_RREQB
;
340 fp
->mode
.rreqb
.dest_hi
= dst_hi
;
341 fp
->mode
.rreqb
.dest_lo
= dst_lo
;
342 fp
->mode
.rreqb
.len
= len
;
343 fp
->mode
.rreqb
.extcode
= 0;
345 xfer
->send
.payload
= NULL
;
346 xfer
->recv
.payload
= data
;
349 printf("fwmem_read_block: %d %04x:%08x %d\n", fwdev
->dst
,
350 dst_hi
, dst_lo
, len
);
351 if (fw_asyreq(xfer
->fc
, -1, xfer
) == 0)
360 struct fw_device
*fwdev
,
367 void (*hand
)(struct fw_xfer
*))
369 struct fw_xfer
*xfer
;
372 xfer
= fwmem_xfer_req(fwdev
, sc
, spd
, len
, 0, hand
);
376 fp
= &xfer
->send
.hdr
;
377 fp
->mode
.wreqb
.tcode
= FWTCODE_WREQB
;
378 fp
->mode
.wreqb
.dest_hi
= dst_hi
;
379 fp
->mode
.wreqb
.dest_lo
= dst_lo
;
380 fp
->mode
.wreqb
.len
= len
;
381 fp
->mode
.wreqb
.extcode
= 0;
383 xfer
->send
.payload
= data
;
384 xfer
->recv
.payload
= NULL
;
387 printf("fwmem_write_block: %d %04x:%08x %d\n", fwdev
->dst
,
388 dst_hi
, dst_lo
, len
);
389 if (fw_asyreq(xfer
->fc
, -1, xfer
) == 0)
399 struct fwmem_softc
*fms
;
400 struct fw_xfer
*xfer
;
403 if (dev
->si_drv1
!= NULL
) {
404 if ((flags
& FWRITE
) != 0) {
409 fms
= (struct fwmem_softc
*)dev
->si_drv1
;
412 dev
->si_drv1
= (void *)-1;
414 dev
->si_drv1
= malloc(sizeof(struct fwmem_softc
),
416 if (dev
->si_drv1
== NULL
)
418 dev
->si_iosize_max
= DFLTPHYS
;
419 fms
= (struct fwmem_softc
*)dev
->si_drv1
;
420 memcpy(&fms
->eui
, &fwmem_eui64
, sizeof(struct fw_eui64
));
423 STAILQ_INIT(&fms
->xferlist
);
424 xfer
= fw_xfer_alloc(M_FWMEM
);
425 STAILQ_INSERT_TAIL(&fms
->xferlist
, xfer
, link
);
428 printf("%s: refcount=%d\n", __func__
, fms
->refcount
);
435 struct fwmem_softc
*fms
;
436 struct fw_xfer
*xfer
;
439 fms
= (struct fwmem_softc
*)dev
->si_drv1
;
441 FW_GLOCK(fms
->sc
->fc
);
443 FW_GUNLOCK(fms
->sc
->fc
);
445 printf("%s: refcount=%d\n", __func__
, fms
->refcount
);
446 if (fms
->refcount
< 1) {
447 while ((xfer
= STAILQ_FIRST(&fms
->xferlist
)) != NULL
) {
448 STAILQ_REMOVE_HEAD(&fms
->xferlist
, link
);
451 free(dev
->si_drv1
, M_FW
);
460 fwmem_biodone(struct fw_xfer
*xfer
)
464 bp
= (struct bio
*)xfer
->sc
;
465 bp
->bio_error
= xfer
->resp
;
467 if (bp
->bio_error
!= 0) {
469 printf("%s: err=%d\n", __func__
, bp
->bio_error
);
470 bp
->bio_resid
= bp
->bio_bcount
;
473 CTR0(KTR_DEV
, "biodone0");
475 CTR0(KTR_DEV
, "biodone1");
477 CTR0(KTR_DEV
, "biodone2");
481 fwmem_strategy(struct bio
*bp
)
484 struct fwmem_softc
*fms
;
485 struct fw_device
*fwdev
;
486 struct fw_xfer
*xfer
;
487 int err
= 0, s
, iolen
;
489 CTR0(KTR_DEV
, "strategy");
491 /* XXX check request length */
494 fms
= (struct fwmem_softc
*)dev
->si_drv1
;
495 fwdev
= fw_noderesolve_eui64(fms
->sc
->fc
, &fms
->eui
);
498 printf("fwmem: no such device ID:%08x%08x\n",
499 fms
->eui
.hi
, fms
->eui
.lo
);
504 iolen
= MIN(bp
->bio_bcount
, MAXLEN
);
505 if ((bp
->bio_cmd
& BIO_READ
) == BIO_READ
) {
506 if (iolen
== 4 && (bp
->bio_offset
& 3) == 0)
507 xfer
= fwmem_read_quad(fwdev
,
508 (void *) bp
, fwmem_speed
,
509 bp
->bio_offset
>> 32, bp
->bio_offset
& 0xffffffff,
510 bp
->bio_data
, fwmem_biodone
);
512 xfer
= fwmem_read_block(fwdev
,
513 (void *) bp
, fwmem_speed
,
514 bp
->bio_offset
>> 32, bp
->bio_offset
& 0xffffffff,
515 iolen
, bp
->bio_data
, fwmem_biodone
);
517 if (iolen
== 4 && (bp
->bio_offset
& 3) == 0)
518 xfer
= fwmem_write_quad(fwdev
,
519 (void *)bp
, fwmem_speed
,
520 bp
->bio_offset
>> 32, bp
->bio_offset
& 0xffffffff,
521 bp
->bio_data
, fwmem_biodone
);
523 xfer
= fwmem_write_block(fwdev
,
524 (void *)bp
, fwmem_speed
,
525 bp
->bio_offset
>> 32, bp
->bio_offset
& 0xffffffff,
526 iolen
, bp
->bio_data
, fwmem_biodone
);
533 bp
->bio_resid
= bp
->bio_bcount
- iolen
;
538 printf("%s: err=%d\n", __func__
, err
);
540 bp
->bio_resid
= bp
->bio_bcount
;
548 struct fwmem_softc
*fms
;
551 fms
= (struct fwmem_softc
*)dev
->si_drv1
;
554 memcpy(&fms
->eui
, data
, sizeof(struct fw_eui64
));
557 memcpy(data
, &fms
->eui
, sizeof(struct fw_eui64
));