Home | History | Annotate | Line # | Download | only in ieee1394
fwmem.c revision 1.7
      1 /*	$NetBSD: fwmem.c,v 1.7 2007/11/05 19:08:56 kiyohara 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: src/sys/dev/firewire/fwmem.c,v 1.34 2007/06/06 14:31:36 simokawa 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 <sys/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 <sys/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 	struct firewire_softc *sc;
    213 	int refcount;
    214 	STAILQ_HEAD(, fw_xfer) xferlist;
    215 };
    216 
    217 static struct fw_xfer *
    218 fwmem_xfer_req(
    219 	struct fw_device *fwdev,
    220 	void *sc,
    221 	int spd,
    222 	int slen,
    223 	int rlen,
    224 	void *hand)
    225 {
    226 	struct fw_xfer *xfer;
    227 
    228 	xfer = fw_xfer_alloc(M_FWMEM);
    229 	if (xfer == NULL)
    230 		return NULL;
    231 
    232 	xfer->fc = fwdev->fc;
    233 	xfer->send.hdr.mode.hdr.dst = FWLOCALBUS | fwdev->dst;
    234 	if (spd < 0)
    235 		xfer->send.spd = fwdev->speed;
    236 	else
    237 		xfer->send.spd = min(spd, fwdev->speed);
    238 	xfer->hand = hand;
    239 	xfer->sc = sc;
    240 	xfer->send.pay_len = slen;
    241 	xfer->recv.pay_len = rlen;
    242 
    243 	return xfer;
    244 }
    245 
    246 struct fw_xfer *
    247 fwmem_read_quad(
    248 	struct fw_device *fwdev,
    249 	void *	sc,
    250 	uint8_t spd,
    251 	uint16_t dst_hi,
    252 	uint32_t dst_lo,
    253 	void *data,
    254 	void (*hand)(struct fw_xfer *))
    255 {
    256 	struct fw_xfer *xfer;
    257 	struct fw_pkt *fp;
    258 
    259 	xfer = fwmem_xfer_req(fwdev, (void *)sc, spd, 0, 4, hand);
    260 	if (xfer == NULL) {
    261 		return NULL;
    262 	}
    263 
    264 	fp = &xfer->send.hdr;
    265 	fp->mode.rreqq.tcode = FWTCODE_RREQQ;
    266 	fp->mode.rreqq.dest_hi = dst_hi;
    267 	fp->mode.rreqq.dest_lo = dst_lo;
    268 
    269 	xfer->send.payload = NULL;
    270 	xfer->recv.payload = (uint32_t *)data;
    271 
    272 	if (fwmem_debug)
    273 		printf("fwmem_read_quad: %d %04x:%08x\n", fwdev->dst,
    274 				dst_hi, dst_lo);
    275 
    276 	if (fw_asyreq(xfer->fc, -1, xfer) == 0)
    277 		return xfer;
    278 
    279 	fw_xfer_free(xfer);
    280 	return NULL;
    281 }
    282 
    283 struct fw_xfer *
    284 fwmem_write_quad(
    285 	struct fw_device *fwdev,
    286 	void *	sc,
    287 	uint8_t spd,
    288 	uint16_t dst_hi,
    289 	uint32_t dst_lo,
    290 	void *data,
    291 	void (*hand)(struct fw_xfer *))
    292 {
    293 	struct fw_xfer *xfer;
    294 	struct fw_pkt *fp;
    295 
    296 	xfer = fwmem_xfer_req(fwdev, sc, spd, 0, 0, hand);
    297 	if (xfer == NULL)
    298 		return NULL;
    299 
    300 	fp = &xfer->send.hdr;
    301 	fp->mode.wreqq.tcode = FWTCODE_WREQQ;
    302 	fp->mode.wreqq.dest_hi = dst_hi;
    303 	fp->mode.wreqq.dest_lo = dst_lo;
    304 	fp->mode.wreqq.data = *(uint32_t *)data;
    305 
    306 	xfer->send.payload = xfer->recv.payload = NULL;
    307 
    308 	if (fwmem_debug)
    309 		printf("fwmem_write_quad: %d %04x:%08x %08x\n", fwdev->dst,
    310 			dst_hi, dst_lo, *(uint32_t *)data);
    311 
    312 	if (fw_asyreq(xfer->fc, -1, xfer) == 0)
    313 		return xfer;
    314 
    315 	fw_xfer_free(xfer);
    316 	return NULL;
    317 }
    318 
    319 struct fw_xfer *
    320 fwmem_read_block(
    321 	struct fw_device *fwdev,
    322 	void *	sc,
    323 	uint8_t spd,
    324 	uint16_t dst_hi,
    325 	uint32_t dst_lo,
    326 	int len,
    327 	void *data,
    328 	void (*hand)(struct fw_xfer *))
    329 {
    330 	struct fw_xfer *xfer;
    331 	struct fw_pkt *fp;
    332 
    333 	xfer = fwmem_xfer_req(fwdev, sc, spd, 0, roundup2(len, 4), hand);
    334 	if (xfer == NULL)
    335 		return NULL;
    336 
    337 	fp = &xfer->send.hdr;
    338 	fp->mode.rreqb.tcode = FWTCODE_RREQB;
    339 	fp->mode.rreqb.dest_hi = dst_hi;
    340 	fp->mode.rreqb.dest_lo = dst_lo;
    341 	fp->mode.rreqb.len = len;
    342 	fp->mode.rreqb.extcode = 0;
    343 
    344 	xfer->send.payload = NULL;
    345 	xfer->recv.payload = data;
    346 
    347 	if (fwmem_debug)
    348 		printf("fwmem_read_block: %d %04x:%08x %d\n", fwdev->dst,
    349 				dst_hi, dst_lo, len);
    350 	if (fw_asyreq(xfer->fc, -1, xfer) == 0)
    351 		return xfer;
    352 
    353 	fw_xfer_free(xfer);
    354 	return NULL;
    355 }
    356 
    357 struct fw_xfer *
    358 fwmem_write_block(
    359 	struct fw_device *fwdev,
    360 	void *	sc,
    361 	uint8_t spd,
    362 	uint16_t dst_hi,
    363 	uint32_t dst_lo,
    364 	int len,
    365 	void *data,
    366 	void (*hand)(struct fw_xfer *))
    367 {
    368 	struct fw_xfer *xfer;
    369 	struct fw_pkt *fp;
    370 
    371 	xfer = fwmem_xfer_req(fwdev, sc, spd, len, 0, hand);
    372 	if (xfer == NULL)
    373 		return NULL;
    374 
    375 	fp = &xfer->send.hdr;
    376 	fp->mode.wreqb.tcode = FWTCODE_WREQB;
    377 	fp->mode.wreqb.dest_hi = dst_hi;
    378 	fp->mode.wreqb.dest_lo = dst_lo;
    379 	fp->mode.wreqb.len = len;
    380 	fp->mode.wreqb.extcode = 0;
    381 
    382 	xfer->send.payload = data;
    383 	xfer->recv.payload = NULL;
    384 
    385 	if (fwmem_debug)
    386 		printf("fwmem_write_block: %d %04x:%08x %d\n", fwdev->dst,
    387 				dst_hi, dst_lo, len);
    388 	if (fw_asyreq(xfer->fc, -1, xfer) == 0)
    389 		return xfer;
    390 
    391 	fw_xfer_free(xfer);
    392 	return NULL;
    393 }
    394 
    395 
    396 FW_OPEN(fwmem)
    397 {
    398 	struct fwmem_softc *fms;
    399 	struct fw_xfer *xfer;
    400 	FW_OPEN_START;
    401 
    402 	if (dev->si_drv1 != NULL) {
    403 		if ((flags & FWRITE) != 0) {
    404 			FW_GUNLOCK(sc->fc);
    405 			return (EBUSY);
    406 		}
    407 		FW_GUNLOCK(sc->fc);
    408 		fms = (struct fwmem_softc *)dev->si_drv1;
    409 		fms->refcount ++;
    410 	} else {
    411 		dev->si_drv1 = (void *)-1;
    412 		FW_GUNLOCK(sc->fc);
    413 		dev->si_drv1 = malloc(sizeof(struct fwmem_softc),
    414 		    M_FWMEM, M_WAITOK);
    415 		if (dev->si_drv1 == NULL)
    416 			return ENOMEM;
    417 		dev->si_iosize_max = DFLTPHYS;
    418 		fms = (struct fwmem_softc *)dev->si_drv1;
    419 		bcopy(&fwmem_eui64, &fms->eui, sizeof(struct fw_eui64));
    420 		fms->sc = sc;
    421 		fms->refcount = 1;
    422 		STAILQ_INIT(&fms->xferlist);
    423 		xfer = fw_xfer_alloc(M_FWMEM);
    424 		STAILQ_INSERT_TAIL(&fms->xferlist, xfer, link);
    425 	}
    426 	if (fwmem_debug)
    427 		printf("%s: refcount=%d\n", __func__, fms->refcount);
    428 
    429 	return (0);
    430 }
    431 
    432 FW_CLOSE(fwmem)
    433 {
    434 	struct fwmem_softc *fms;
    435 	struct fw_xfer *xfer;
    436 	FW_CLOSE_START;
    437 
    438 	fms = (struct fwmem_softc *)dev->si_drv1;
    439 
    440 	FW_GLOCK(fms->sc->fc);
    441 	fms->refcount --;
    442 	FW_GUNLOCK(fms->sc->fc);
    443 	if (fwmem_debug)
    444 		printf("%s: refcount=%d\n", __func__, fms->refcount);
    445 	if (fms->refcount < 1) {
    446 		while ((xfer = STAILQ_FIRST(&fms->xferlist)) != NULL) {
    447 			STAILQ_REMOVE_HEAD(&fms->xferlist, link);
    448 			fw_xfer_free(xfer);
    449 		}
    450 		free(dev->si_drv1, M_FW);
    451 		dev->si_drv1 = NULL;
    452 	}
    453 
    454 	return (0);
    455 }
    456 
    457 
    458 static void
    459 fwmem_biodone(struct fw_xfer *xfer)
    460 {
    461 	struct bio *bp;
    462 
    463 	bp = (struct bio *)xfer->sc;
    464 	bp->bio_error = xfer->resp;
    465 
    466 	if (bp->bio_error != 0) {
    467 		if (fwmem_debug)
    468 			printf("%s: err=%d\n", __func__, bp->bio_error);
    469 		bp->bio_resid = bp->bio_bcount;
    470 	}
    471 
    472 	CTR0(KTR_DEV, "biodone0");
    473 	fw_xfer_free(xfer);
    474 	CTR0(KTR_DEV, "biodone1");
    475 	biodone(bp);
    476 	CTR0(KTR_DEV, "biodone2");
    477 }
    478 
    479 void
    480 fwmem_strategy(struct bio *bp)
    481 {
    482 	FW_STRATEGY_START;
    483 	struct fwmem_softc *fms;
    484 	struct fw_device *fwdev;
    485 	struct fw_xfer *xfer;
    486 	int err = 0, s, iolen;
    487 
    488 	CTR0(KTR_DEV, "strategy");
    489 
    490 	/* XXX check request length */
    491 
    492 	s = splfw();
    493 	fms = (struct fwmem_softc *)dev->si_drv1;
    494 	fwdev = fw_noderesolve_eui64(fms->sc->fc, &fms->eui);
    495 	if (fwdev == NULL) {
    496 		if (fwmem_debug)
    497 			printf("fwmem: no such device ID:%08x%08x\n",
    498 					fms->eui.hi, fms->eui.lo);
    499 		err = EINVAL;
    500 		goto error;
    501 	}
    502 
    503 	iolen = MIN(bp->bio_bcount, MAXLEN);
    504 	if ((bp->bio_cmd & BIO_READ) == BIO_READ) {
    505 		if (iolen == 4 && (bp->bio_offset & 3) == 0)
    506 			xfer = fwmem_read_quad(fwdev,
    507 			    (void *) bp, fwmem_speed,
    508 			    bp->bio_offset >> 32, bp->bio_offset & 0xffffffff,
    509 			    bp->bio_data, fwmem_biodone);
    510 		else
    511 			xfer = fwmem_read_block(fwdev,
    512 			    (void *) bp, fwmem_speed,
    513 			    bp->bio_offset >> 32, bp->bio_offset & 0xffffffff,
    514 			    iolen, bp->bio_data, fwmem_biodone);
    515 	} else {
    516 		if (iolen == 4 && (bp->bio_offset & 3) == 0)
    517 			xfer = fwmem_write_quad(fwdev,
    518 			    (void *)bp, fwmem_speed,
    519 			    bp->bio_offset >> 32, bp->bio_offset & 0xffffffff,
    520 			    bp->bio_data, fwmem_biodone);
    521 		else
    522 			xfer = fwmem_write_block(fwdev,
    523 			    (void *)bp, fwmem_speed,
    524 			    bp->bio_offset >> 32, bp->bio_offset & 0xffffffff,
    525 			    iolen, bp->bio_data, fwmem_biodone);
    526 	}
    527 	if (xfer == NULL) {
    528 		err = EIO;
    529 		goto error;
    530 	}
    531 	/* XXX */
    532 	bp->bio_resid = bp->bio_bcount - iolen;
    533 error:
    534 	splx(s);
    535 	if (err != 0) {
    536 		if (fwmem_debug)
    537 			printf("%s: err=%d\n", __func__, err);
    538 		bp->bio_error = err;
    539 		bp->bio_resid = bp->bio_bcount;
    540 		biodone(bp);
    541 	}
    542 }
    543 
    544 FW_IOCTL(fwmem)
    545 {
    546 	FW_IOCTL_START;
    547 	struct fwmem_softc *fms;
    548 	int err = 0;
    549 
    550 	fms = (struct fwmem_softc *)dev->si_drv1;
    551 	switch (cmd) {
    552 	case FW_SDEUI64:
    553 		bcopy(data, &fms->eui, sizeof(struct fw_eui64));
    554 		break;
    555 	case FW_GDEUI64:
    556 		bcopy(&fms->eui, data, sizeof(struct fw_eui64));
    557 		break;
    558 	default:
    559 		err = EINVAL;
    560 	}
    561 	return(err);
    562 }
    563 
    564 FW_POLL(fwmem)
    565 {
    566 	return EINVAL;
    567 }
    568 
    569 FW_MMAP(fwmem)
    570 {
    571 	return EINVAL;
    572 }
    573