fwmem.c revision 296591
1204431Sraj/*- 2204431Sraj * Copyright (c) 2002-2003 3204431Sraj * Hidetoshi Shimokawa. All rights reserved. 4204431Sraj * 5204431Sraj * Redistribution and use in source and binary forms, with or without 6204431Sraj * modification, are permitted provided that the following conditions 7204431Sraj * are met: 8204431Sraj * 1. Redistributions of source code must retain the above copyright 9204431Sraj * notice, this list of conditions and the following disclaimer. 10204431Sraj * 2. Redistributions in binary form must reproduce the above copyright 11204431Sraj * notice, this list of conditions and the following disclaimer in the 12204431Sraj * documentation and/or other materials provided with the distribution. 13204431Sraj * 3. All advertising materials mentioning features or use of this software 14204431Sraj * must display the following acknowledgement: 15204431Sraj * 16204431Sraj * This product includes software developed by Hidetoshi Shimokawa. 17204431Sraj * 18204431Sraj * 4. Neither the name of the author nor the names of its contributors 19204431Sraj * may be used to endorse or promote products derived from this software 20204431Sraj * without specific prior written permission. 21204431Sraj * 22204431Sraj * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23204431Sraj * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24204431Sraj * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25204431Sraj * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26204431Sraj * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27204431Sraj * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28204431Sraj * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29204431Sraj * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30204431Sraj * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31204431Sraj * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32204431Sraj * SUCH DAMAGE. 33204431Sraj * 34204431Sraj */ 35204431Sraj 36204431Sraj#ifdef __FreeBSD__ 37204431Sraj#include <sys/cdefs.h> 38204431Sraj__FBSDID("$FreeBSD: head/sys/dev/firewire/fwmem.c 296591 2016-03-10 00:36:45Z imp $"); 39204431Sraj#endif 40204431Sraj 41204431Sraj#include <sys/param.h> 42204431Sraj#include <sys/systm.h> 43204431Sraj#include <sys/types.h> 44204431Sraj 45204431Sraj#include <sys/kernel.h> 46204431Sraj#include <sys/malloc.h> 47204431Sraj#include <sys/conf.h> 48204431Sraj#include <sys/sysctl.h> 49204431Sraj#include <sys/bio.h> 50204431Sraj 51204431Sraj#include <sys/bus.h> 52204431Sraj#include <machine/bus.h> 53204431Sraj 54204431Sraj#include <sys/signal.h> 55204431Sraj#include <sys/mman.h> 56204431Sraj#include <sys/ioccom.h> 57204431Sraj#include <sys/fcntl.h> 58204431Sraj 59204431Sraj#include <dev/firewire/firewire.h> 60204431Sraj#include <dev/firewire/firewirereg.h> 61204431Sraj#include <dev/firewire/fwmem.h> 62204431Sraj 63204431Srajstatic int fwmem_speed = 2, fwmem_debug = 0; 64204431Srajstatic struct fw_eui64 fwmem_eui64; 65204431SrajSYSCTL_DECL(_hw_firewire); 66204431Srajstatic SYSCTL_NODE(_hw_firewire, OID_AUTO, fwmem, CTLFLAG_RD, 0, 67204431Sraj "FireWire Memory Access"); 68204431SrajSYSCTL_UINT(_hw_firewire_fwmem, OID_AUTO, eui64_hi, CTLFLAG_RW, 69204431Sraj &fwmem_eui64.hi, 0, "Fwmem target EUI64 high"); 70204431SrajSYSCTL_UINT(_hw_firewire_fwmem, OID_AUTO, eui64_lo, CTLFLAG_RW, 71204431Sraj &fwmem_eui64.lo, 0, "Fwmem target EUI64 low"); 72204431SrajSYSCTL_INT(_hw_firewire_fwmem, OID_AUTO, speed, CTLFLAG_RW, &fwmem_speed, 0, 73204431Sraj "Fwmem link speed"); 74204431SrajSYSCTL_INT(_debug, OID_AUTO, fwmem_debug, CTLFLAG_RW, &fwmem_debug, 0, 75204431Sraj "Fwmem driver debug flag"); 76204431Sraj 77204431Srajstatic MALLOC_DEFINE(M_FWMEM, "fwmem", "fwmem/FireWire"); 78204431Sraj 79204431Sraj#define MAXLEN (512 << fwmem_speed) 80204431Sraj 81204431Srajstruct fwmem_softc { 82204431Sraj struct fw_eui64 eui; 83204431Sraj struct firewire_softc *sc; 84204431Sraj int refcount; 85204431Sraj}; 86204431Sraj 87204431Srajstatic struct fw_xfer * 88204431Srajfwmem_xfer_req( 89204431Sraj struct fw_device *fwdev, 90204431Sraj caddr_t sc, 91204431Sraj int spd, 92204431Sraj int slen, 93204431Sraj int rlen, 94204431Sraj void *hand) 95204431Sraj{ 96204431Sraj struct fw_xfer *xfer; 97204431Sraj 98204431Sraj xfer = fw_xfer_alloc(M_FWMEM); 99204431Sraj if (xfer == NULL) 100204431Sraj return NULL; 101204431Sraj 102204431Sraj xfer->fc = fwdev->fc; 103204431Sraj xfer->send.hdr.mode.hdr.dst = FWLOCALBUS | fwdev->dst; 104204431Sraj if (spd < 0) 105204431Sraj xfer->send.spd = fwdev->speed; 106204431Sraj else 107204431Sraj xfer->send.spd = min(spd, fwdev->speed); 108204431Sraj xfer->hand = hand; 109204431Sraj xfer->sc = sc; 110204431Sraj xfer->send.pay_len = slen; 111204431Sraj xfer->recv.pay_len = rlen; 112204431Sraj 113204431Sraj return xfer; 114204431Sraj} 115204431Sraj 116204431Srajstruct fw_xfer * 117204431Srajfwmem_read_quad( 118204431Sraj struct fw_device *fwdev, 119204431Sraj caddr_t sc, 120204431Sraj uint8_t spd, 121204431Sraj uint16_t dst_hi, 122204431Sraj uint32_t dst_lo, 123204431Sraj void *data, 124204431Sraj void (*hand)(struct fw_xfer *)) 125204431Sraj{ 126204431Sraj struct fw_xfer *xfer; 127204431Sraj struct fw_pkt *fp; 128204431Sraj 129204431Sraj xfer = fwmem_xfer_req(fwdev, sc, spd, 0, 4, hand); 130204431Sraj if (xfer == NULL) { 131204431Sraj return NULL; 132204431Sraj } 133204431Sraj 134204431Sraj fp = &xfer->send.hdr; 135204431Sraj fp->mode.rreqq.tcode = FWTCODE_RREQQ; 136204431Sraj fp->mode.rreqq.dest_hi = dst_hi; 137204431Sraj fp->mode.rreqq.dest_lo = dst_lo; 138204431Sraj 139204431Sraj xfer->send.payload = NULL; 140204431Sraj xfer->recv.payload = (uint32_t *)data; 141204431Sraj 142204431Sraj if (fwmem_debug) 143204431Sraj printf("fwmem_read_quad: %d %04x:%08x\n", fwdev->dst, 144204431Sraj dst_hi, dst_lo); 145204431Sraj 146204431Sraj if (fw_asyreq(xfer->fc, -1, xfer) == 0) 147204431Sraj return xfer; 148204431Sraj 149204431Sraj fw_xfer_free(xfer); 150204431Sraj return NULL; 151204431Sraj} 152204431Sraj 153204431Srajstruct fw_xfer * 154204431Srajfwmem_write_quad( 155204431Sraj struct fw_device *fwdev, 156204431Sraj caddr_t sc, 157204431Sraj uint8_t spd, 158204431Sraj uint16_t dst_hi, 159204431Sraj uint32_t dst_lo, 160204431Sraj void *data, 161204431Sraj void (*hand)(struct fw_xfer *)) 162204431Sraj{ 163204431Sraj struct fw_xfer *xfer; 164204431Sraj struct fw_pkt *fp; 165204431Sraj 166204431Sraj xfer = fwmem_xfer_req(fwdev, sc, spd, 0, 0, hand); 167204431Sraj if (xfer == NULL) 168204431Sraj return NULL; 169204431Sraj 170204431Sraj fp = &xfer->send.hdr; 171204431Sraj fp->mode.wreqq.tcode = FWTCODE_WREQQ; 172204431Sraj fp->mode.wreqq.dest_hi = dst_hi; 173204431Sraj fp->mode.wreqq.dest_lo = dst_lo; 174204431Sraj fp->mode.wreqq.data = *(uint32_t *)data; 175204431Sraj 176204431Sraj xfer->send.payload = xfer->recv.payload = NULL; 177204431Sraj 178204431Sraj if (fwmem_debug) 179204431Sraj printf("fwmem_write_quad: %d %04x:%08x %08x\n", fwdev->dst, 180204431Sraj dst_hi, dst_lo, *(uint32_t *)data); 181204431Sraj 182204431Sraj if (fw_asyreq(xfer->fc, -1, xfer) == 0) 183204431Sraj return xfer; 184204431Sraj 185204431Sraj fw_xfer_free(xfer); 186204431Sraj return NULL; 187204431Sraj} 188204431Sraj 189204431Srajstruct fw_xfer * 190204431Srajfwmem_read_block( 191204431Sraj struct fw_device *fwdev, 192204431Sraj caddr_t sc, 193204431Sraj uint8_t spd, 194204431Sraj uint16_t dst_hi, 195204431Sraj uint32_t dst_lo, 196204431Sraj int len, 197204431Sraj void *data, 198204431Sraj void (*hand)(struct fw_xfer *)) 199204431Sraj{ 200204431Sraj struct fw_xfer *xfer; 201204431Sraj struct fw_pkt *fp; 202204431Sraj 203204431Sraj xfer = fwmem_xfer_req(fwdev, sc, spd, 0, roundup2(len, 4), hand); 204204431Sraj if (xfer == NULL) 205204431Sraj return NULL; 206204431Sraj 207204431Sraj fp = &xfer->send.hdr; 208204431Sraj fp->mode.rreqb.tcode = FWTCODE_RREQB; 209204431Sraj fp->mode.rreqb.dest_hi = dst_hi; 210204431Sraj fp->mode.rreqb.dest_lo = dst_lo; 211204431Sraj fp->mode.rreqb.len = len; 212204431Sraj fp->mode.rreqb.extcode = 0; 213204431Sraj 214204431Sraj xfer->send.payload = NULL; 215204431Sraj xfer->recv.payload = data; 216204431Sraj 217204431Sraj if (fwmem_debug) 218204431Sraj printf("fwmem_read_block: %d %04x:%08x %d\n", fwdev->dst, 219204431Sraj dst_hi, dst_lo, len); 220204431Sraj if (fw_asyreq(xfer->fc, -1, xfer) == 0) 221204431Sraj return xfer; 222204431Sraj 223204431Sraj fw_xfer_free(xfer); 224204431Sraj return NULL; 225204431Sraj} 226204431Sraj 227204431Srajstruct fw_xfer * 228204431Srajfwmem_write_block( 229204431Sraj struct fw_device *fwdev, 230204431Sraj caddr_t sc, 231204431Sraj uint8_t spd, 232204431Sraj uint16_t dst_hi, 233204431Sraj uint32_t dst_lo, 234204431Sraj int len, 235204431Sraj void *data, 236204431Sraj void (*hand)(struct fw_xfer *)) 237204431Sraj{ 238204431Sraj struct fw_xfer *xfer; 239204431Sraj struct fw_pkt *fp; 240204431Sraj 241204431Sraj xfer = fwmem_xfer_req(fwdev, sc, spd, len, 0, hand); 242204431Sraj if (xfer == NULL) 243204431Sraj return NULL; 244204431Sraj 245204431Sraj fp = &xfer->send.hdr; 246204431Sraj fp->mode.wreqb.tcode = FWTCODE_WREQB; 247204431Sraj fp->mode.wreqb.dest_hi = dst_hi; 248204431Sraj fp->mode.wreqb.dest_lo = dst_lo; 249204431Sraj fp->mode.wreqb.len = len; 250204431Sraj fp->mode.wreqb.extcode = 0; 251204431Sraj 252204431Sraj xfer->send.payload = data; 253204431Sraj xfer->recv.payload = NULL; 254204431Sraj 255204431Sraj if (fwmem_debug) 256204431Sraj printf("fwmem_write_block: %d %04x:%08x %d\n", fwdev->dst, 257204431Sraj dst_hi, dst_lo, len); 258204431Sraj if (fw_asyreq(xfer->fc, -1, xfer) == 0) 259204431Sraj return xfer; 260204431Sraj 261204431Sraj fw_xfer_free(xfer); 262204431Sraj return NULL; 263204431Sraj} 264204431Sraj 265204431Srajint 266204431Srajfwmem_open(struct cdev *dev, int flags, int fmt, fw_proc *td) 267204431Sraj{ 268204431Sraj struct fwmem_softc *fms; 269204431Sraj struct firewire_softc *sc; 270204431Sraj int unit = DEV2UNIT(dev); 271204431Sraj 272204431Sraj sc = devclass_get_softc(firewire_devclass, unit); 273204431Sraj if (sc == NULL) 274204431Sraj return (ENXIO); 275204431Sraj 276204431Sraj FW_GLOCK(sc->fc); 277204431Sraj if (dev->si_drv1 != NULL) { 278204431Sraj if ((flags & FWRITE) != 0) { 279 FW_GUNLOCK(sc->fc); 280 return (EBUSY); 281 } 282 FW_GUNLOCK(sc->fc); 283 fms = dev->si_drv1; 284 fms->refcount++; 285 } else { 286 dev->si_drv1 = (void *)-1; 287 FW_GUNLOCK(sc->fc); 288 dev->si_drv1 = malloc(sizeof(struct fwmem_softc), 289 M_FWMEM, M_WAITOK); 290 if (dev->si_drv1 == NULL) 291 return (ENOMEM); 292 dev->si_iosize_max = DFLTPHYS; 293 fms = dev->si_drv1; 294 bcopy(&fwmem_eui64, &fms->eui, sizeof(struct fw_eui64)); 295 fms->sc = sc; 296 fms->refcount = 1; 297 } 298 if (fwmem_debug) 299 printf("%s: refcount=%d\n", __func__, fms->refcount); 300 301 return (0); 302} 303 304int 305fwmem_close (struct cdev *dev, int flags, int fmt, fw_proc *td) 306{ 307 struct fwmem_softc *fms; 308 309 fms = dev->si_drv1; 310 311 FW_GLOCK(fms->sc->fc); 312 fms->refcount--; 313 FW_GUNLOCK(fms->sc->fc); 314 if (fwmem_debug) 315 printf("%s: refcount=%d\n", __func__, fms->refcount); 316 if (fms->refcount < 1) { 317 free(dev->si_drv1, M_FWMEM); 318 dev->si_drv1 = NULL; 319 } 320 321 return (0); 322} 323 324 325static void 326fwmem_biodone(struct fw_xfer *xfer) 327{ 328 struct bio *bp; 329 330 bp = (struct bio *)xfer->sc; 331 bp->bio_error = xfer->resp; 332 333 if (bp->bio_error != 0) { 334 if (fwmem_debug) 335 printf("%s: err=%d\n", __func__, bp->bio_error); 336 bp->bio_flags |= BIO_ERROR; 337 bp->bio_resid = bp->bio_bcount; 338 } 339 340 fw_xfer_free(xfer); 341 biodone(bp); 342} 343 344void 345fwmem_strategy(struct bio *bp) 346{ 347 struct fwmem_softc *fms; 348 struct fw_device *fwdev; 349 struct fw_xfer *xfer; 350 struct cdev *dev; 351 int err = 0, iolen; 352 353 dev = bp->bio_dev; 354 /* XXX check request length */ 355 356 fms = dev->si_drv1; 357 fwdev = fw_noderesolve_eui64(fms->sc->fc, &fms->eui); 358 if (fwdev == NULL) { 359 if (fwmem_debug) 360 printf("fwmem: no such device ID:%08x%08x\n", 361 fms->eui.hi, fms->eui.lo); 362 err = EINVAL; 363 goto error; 364 } 365 366 iolen = MIN(bp->bio_bcount, MAXLEN); 367 if (bp->bio_cmd == BIO_READ) { 368 if (iolen == 4 && (bp->bio_offset & 3) == 0) 369 xfer = fwmem_read_quad(fwdev, 370 (void *)bp, fwmem_speed, 371 bp->bio_offset >> 32, bp->bio_offset & 0xffffffff, 372 bp->bio_data, fwmem_biodone); 373 else 374 xfer = fwmem_read_block(fwdev, 375 (void *)bp, fwmem_speed, 376 bp->bio_offset >> 32, bp->bio_offset & 0xffffffff, 377 iolen, bp->bio_data, fwmem_biodone); 378 } else { 379 if (iolen == 4 && (bp->bio_offset & 3) == 0) 380 xfer = fwmem_write_quad(fwdev, 381 (void *)bp, fwmem_speed, 382 bp->bio_offset >> 32, bp->bio_offset & 0xffffffff, 383 bp->bio_data, fwmem_biodone); 384 else 385 xfer = fwmem_write_block(fwdev, 386 (void *)bp, fwmem_speed, 387 bp->bio_offset >> 32, bp->bio_offset & 0xffffffff, 388 iolen, bp->bio_data, fwmem_biodone); 389 } 390 if (xfer == NULL) { 391 err = EIO; 392 goto error; 393 } 394 /* XXX */ 395 bp->bio_resid = bp->bio_bcount - iolen; 396error: 397 if (err != 0) { 398 if (fwmem_debug) 399 printf("%s: err=%d\n", __func__, err); 400 bp->bio_error = err; 401 bp->bio_flags |= BIO_ERROR; 402 bp->bio_resid = bp->bio_bcount; 403 biodone(bp); 404 } 405} 406 407int 408fwmem_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, fw_proc *td) 409{ 410 struct fwmem_softc *fms; 411 int err = 0; 412 413 fms = dev->si_drv1; 414 switch (cmd) { 415 case FW_SDEUI64: 416 bcopy(data, &fms->eui, sizeof(struct fw_eui64)); 417 break; 418 case FW_GDEUI64: 419 bcopy(&fms->eui, data, sizeof(struct fw_eui64)); 420 break; 421 default: 422 err = EINVAL; 423 } 424 return (err); 425} 426 427int 428fwmem_poll(struct cdev *dev, int events, fw_proc *td) 429{ 430 return EINVAL; 431} 432 433int 434fwmem_mmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr, 435 int nproto, vm_memattr_t *memattr) 436{ 437 return EINVAL; 438} 439