fwmem.c revision 277509
1139749Simp/*- 2113584Ssimokawa * Copyright (c) 2002-2003 3103285Sikob * Hidetoshi Shimokawa. All rights reserved. 4272214Skan * 5103285Sikob * Redistribution and use in source and binary forms, with or without 6103285Sikob * modification, are permitted provided that the following conditions 7103285Sikob * are met: 8103285Sikob * 1. Redistributions of source code must retain the above copyright 9103285Sikob * notice, this list of conditions and the following disclaimer. 10103285Sikob * 2. Redistributions in binary form must reproduce the above copyright 11103285Sikob * notice, this list of conditions and the following disclaimer in the 12103285Sikob * documentation and/or other materials provided with the distribution. 13103285Sikob * 3. All advertising materials mentioning features or use of this software 14103285Sikob * must display the following acknowledgement: 15103285Sikob * 16103285Sikob * This product includes software developed by Hidetoshi Shimokawa. 17103285Sikob * 18103285Sikob * 4. Neither the name of the author nor the names of its contributors 19103285Sikob * may be used to endorse or promote products derived from this software 20103285Sikob * without specific prior written permission. 21272214Skan * 22103285Sikob * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23103285Sikob * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24103285Sikob * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25103285Sikob * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26103285Sikob * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27103285Sikob * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28103285Sikob * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29103285Sikob * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30103285Sikob * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31103285Sikob * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32103285Sikob * SUCH DAMAGE. 33272214Skan * 34103285Sikob */ 35103285Sikob 36127468Ssimokawa#ifdef __FreeBSD__ 37119418Sobrien#include <sys/cdefs.h> 38119418Sobrien__FBSDID("$FreeBSD: head/sys/dev/firewire/fwmem.c 277509 2015-01-21 20:05:10Z will $"); 39127468Ssimokawa#endif 40119418Sobrien 41103285Sikob#include <sys/param.h> 42103285Sikob#include <sys/systm.h> 43103285Sikob#include <sys/types.h> 44103285Sikob 45103285Sikob#include <sys/kernel.h> 46103285Sikob#include <sys/malloc.h> 47103285Sikob#include <sys/conf.h> 48103285Sikob#include <sys/sysctl.h> 49120660Ssimokawa#include <sys/bio.h> 50103285Sikob 51103285Sikob#include <sys/bus.h> 52113584Ssimokawa#include <machine/bus.h> 53103285Sikob 54103285Sikob#include <sys/signal.h> 55103285Sikob#include <sys/mman.h> 56103285Sikob#include <sys/ioccom.h> 57122228Ssimokawa#include <sys/fcntl.h> 58103285Sikob 59103285Sikob#include <dev/firewire/firewire.h> 60103285Sikob#include <dev/firewire/firewirereg.h> 61103285Sikob#include <dev/firewire/fwmem.h> 62103285Sikob 63272214Skanstatic int fwmem_speed = 2, fwmem_debug = 0; 64106810Ssimokawastatic struct fw_eui64 fwmem_eui64; 65103285SikobSYSCTL_DECL(_hw_firewire); 66227309Sedstatic SYSCTL_NODE(_hw_firewire, OID_AUTO, fwmem, CTLFLAG_RD, 0, 67108281Ssimokawa "FireWire Memory Access"); 68106810SsimokawaSYSCTL_UINT(_hw_firewire_fwmem, OID_AUTO, eui64_hi, CTLFLAG_RW, 69106810Ssimokawa &fwmem_eui64.hi, 0, "Fwmem target EUI64 high"); 70110582SsimokawaSYSCTL_UINT(_hw_firewire_fwmem, OID_AUTO, eui64_lo, CTLFLAG_RW, 71106810Ssimokawa &fwmem_eui64.lo, 0, "Fwmem target EUI64 low"); 72103285SikobSYSCTL_INT(_hw_firewire_fwmem, OID_AUTO, speed, CTLFLAG_RW, &fwmem_speed, 0, 73103285Sikob "Fwmem link speed"); 74103285SikobSYSCTL_INT(_debug, OID_AUTO, fwmem_debug, CTLFLAG_RW, &fwmem_debug, 0, 75103285Sikob "Fwmem driver debug flag"); 76103285Sikob 77227293Sedstatic MALLOC_DEFINE(M_FWMEM, "fwmem", "fwmem/FireWire"); 78124145Ssimokawa 79120660Ssimokawa#define MAXLEN (512 << fwmem_speed) 80120660Ssimokawa 81122228Ssimokawastruct fwmem_softc { 82122228Ssimokawa struct fw_eui64 eui; 83170374Ssimokawa struct firewire_softc *sc; 84122228Ssimokawa int refcount; 85122228Ssimokawa}; 86122228Ssimokawa 87106816Ssimokawastatic struct fw_xfer * 88106816Ssimokawafwmem_xfer_req( 89106810Ssimokawa struct fw_device *fwdev, 90106816Ssimokawa caddr_t sc, 91106816Ssimokawa int spd, 92113584Ssimokawa int slen, 93113584Ssimokawa int rlen, 94106816Ssimokawa void *hand) 95103285Sikob{ 96103285Sikob struct fw_xfer *xfer; 97103285Sikob 98124145Ssimokawa xfer = fw_xfer_alloc(M_FWMEM); 99106804Ssimokawa if (xfer == NULL) 100103285Sikob return NULL; 101106804Ssimokawa 102106810Ssimokawa xfer->fc = fwdev->fc; 103120660Ssimokawa xfer->send.hdr.mode.hdr.dst = FWLOCALBUS | fwdev->dst; 104106816Ssimokawa if (spd < 0) 105120660Ssimokawa xfer->send.spd = fwdev->speed; 106106816Ssimokawa else 107120660Ssimokawa xfer->send.spd = min(spd, fwdev->speed); 108167632Ssimokawa xfer->hand = hand; 109106816Ssimokawa xfer->sc = sc; 110120660Ssimokawa xfer->send.pay_len = slen; 111120660Ssimokawa xfer->recv.pay_len = rlen; 112103285Sikob 113106816Ssimokawa return xfer; 114106816Ssimokawa} 115106816Ssimokawa 116106816Ssimokawastruct fw_xfer * 117106816Ssimokawafwmem_read_quad( 118106816Ssimokawa struct fw_device *fwdev, 119106816Ssimokawa caddr_t sc, 120129585Sdfr uint8_t spd, 121129585Sdfr uint16_t dst_hi, 122129585Sdfr uint32_t dst_lo, 123120660Ssimokawa void *data, 124106816Ssimokawa void (*hand)(struct fw_xfer *)) 125106816Ssimokawa{ 126106816Ssimokawa struct fw_xfer *xfer; 127106816Ssimokawa struct fw_pkt *fp; 128106816Ssimokawa 129272214Skan xfer = fwmem_xfer_req(fwdev, sc, spd, 0, 4, hand); 130120660Ssimokawa if (xfer == NULL) { 131106816Ssimokawa return NULL; 132120660Ssimokawa } 133106816Ssimokawa 134120660Ssimokawa fp = &xfer->send.hdr; 135103285Sikob fp->mode.rreqq.tcode = FWTCODE_RREQQ; 136113584Ssimokawa fp->mode.rreqq.dest_hi = dst_hi; 137113584Ssimokawa fp->mode.rreqq.dest_lo = dst_lo; 138103285Sikob 139120660Ssimokawa xfer->send.payload = NULL; 140129585Sdfr xfer->recv.payload = (uint32_t *)data; 141120660Ssimokawa 142103285Sikob if (fwmem_debug) 143106816Ssimokawa printf("fwmem_read_quad: %d %04x:%08x\n", fwdev->dst, 144272214Skan dst_hi, dst_lo); 145106804Ssimokawa 146106810Ssimokawa if (fw_asyreq(xfer->fc, -1, xfer) == 0) 147103285Sikob return xfer; 148106804Ssimokawa 149103285Sikob fw_xfer_free(xfer); 150103285Sikob return NULL; 151103285Sikob} 152103285Sikob 153103285Sikobstruct fw_xfer * 154106810Ssimokawafwmem_write_quad( 155106810Ssimokawa struct fw_device *fwdev, 156106810Ssimokawa caddr_t sc, 157129585Sdfr uint8_t spd, 158129585Sdfr uint16_t dst_hi, 159129585Sdfr uint32_t dst_lo, 160120660Ssimokawa void *data, 161106810Ssimokawa void (*hand)(struct fw_xfer *)) 162106810Ssimokawa{ 163106810Ssimokawa struct fw_xfer *xfer; 164106810Ssimokawa struct fw_pkt *fp; 165106810Ssimokawa 166120660Ssimokawa xfer = fwmem_xfer_req(fwdev, sc, spd, 0, 0, hand); 167106810Ssimokawa if (xfer == NULL) 168106810Ssimokawa return NULL; 169106810Ssimokawa 170120660Ssimokawa fp = &xfer->send.hdr; 171110072Ssimokawa fp->mode.wreqq.tcode = FWTCODE_WREQQ; 172113584Ssimokawa fp->mode.wreqq.dest_hi = dst_hi; 173113584Ssimokawa fp->mode.wreqq.dest_lo = dst_lo; 174129585Sdfr fp->mode.wreqq.data = *(uint32_t *)data; 175106810Ssimokawa 176120660Ssimokawa xfer->send.payload = xfer->recv.payload = NULL; 177106810Ssimokawa 178106810Ssimokawa if (fwmem_debug) 179106816Ssimokawa printf("fwmem_write_quad: %d %04x:%08x %08x\n", fwdev->dst, 180272214Skan dst_hi, dst_lo, *(uint32_t *)data); 181106810Ssimokawa 182106810Ssimokawa if (fw_asyreq(xfer->fc, -1, xfer) == 0) 183106810Ssimokawa return xfer; 184106810Ssimokawa 185106810Ssimokawa fw_xfer_free(xfer); 186106810Ssimokawa return NULL; 187106810Ssimokawa} 188106810Ssimokawa 189106810Ssimokawastruct fw_xfer * 190103285Sikobfwmem_read_block( 191106810Ssimokawa struct fw_device *fwdev, 192106810Ssimokawa caddr_t sc, 193129585Sdfr uint8_t spd, 194129585Sdfr uint16_t dst_hi, 195129585Sdfr uint32_t dst_lo, 196106804Ssimokawa int len, 197120660Ssimokawa void *data, 198106804Ssimokawa void (*hand)(struct fw_xfer *)) 199103285Sikob{ 200103285Sikob struct fw_xfer *xfer; 201103285Sikob struct fw_pkt *fp; 202272214Skan 203120660Ssimokawa xfer = fwmem_xfer_req(fwdev, sc, spd, 0, roundup2(len, 4), hand); 204106804Ssimokawa if (xfer == NULL) 205103285Sikob return NULL; 206106804Ssimokawa 207120660Ssimokawa fp = &xfer->send.hdr; 208103285Sikob fp->mode.rreqb.tcode = FWTCODE_RREQB; 209113584Ssimokawa fp->mode.rreqb.dest_hi = dst_hi; 210113584Ssimokawa fp->mode.rreqb.dest_lo = dst_lo; 211113584Ssimokawa fp->mode.rreqb.len = len; 212120660Ssimokawa fp->mode.rreqb.extcode = 0; 213103285Sikob 214120660Ssimokawa xfer->send.payload = NULL; 215120660Ssimokawa xfer->recv.payload = data; 216120660Ssimokawa 217103285Sikob if (fwmem_debug) 218106816Ssimokawa printf("fwmem_read_block: %d %04x:%08x %d\n", fwdev->dst, 219272214Skan dst_hi, dst_lo, len); 220106810Ssimokawa if (fw_asyreq(xfer->fc, -1, xfer) == 0) 221103285Sikob return xfer; 222106804Ssimokawa 223103285Sikob fw_xfer_free(xfer); 224103285Sikob return NULL; 225103285Sikob} 226103285Sikob 227110337Ssimokawastruct fw_xfer * 228110337Ssimokawafwmem_write_block( 229110337Ssimokawa struct fw_device *fwdev, 230110337Ssimokawa caddr_t sc, 231129585Sdfr uint8_t spd, 232129585Sdfr uint16_t dst_hi, 233129585Sdfr uint32_t dst_lo, 234110337Ssimokawa int len, 235120660Ssimokawa void *data, 236110337Ssimokawa void (*hand)(struct fw_xfer *)) 237110337Ssimokawa{ 238110337Ssimokawa struct fw_xfer *xfer; 239110337Ssimokawa struct fw_pkt *fp; 240110337Ssimokawa 241120660Ssimokawa xfer = fwmem_xfer_req(fwdev, sc, spd, len, 0, hand); 242110337Ssimokawa if (xfer == NULL) 243110337Ssimokawa return NULL; 244110337Ssimokawa 245120660Ssimokawa fp = &xfer->send.hdr; 246110406Ssimokawa fp->mode.wreqb.tcode = FWTCODE_WREQB; 247113584Ssimokawa fp->mode.wreqb.dest_hi = dst_hi; 248113584Ssimokawa fp->mode.wreqb.dest_lo = dst_lo; 249113584Ssimokawa fp->mode.wreqb.len = len; 250120660Ssimokawa fp->mode.wreqb.extcode = 0; 251110337Ssimokawa 252120660Ssimokawa xfer->send.payload = data; 253120660Ssimokawa xfer->recv.payload = NULL; 254120660Ssimokawa 255110337Ssimokawa if (fwmem_debug) 256110337Ssimokawa printf("fwmem_write_block: %d %04x:%08x %d\n", fwdev->dst, 257110337Ssimokawa dst_hi, dst_lo, len); 258110337Ssimokawa if (fw_asyreq(xfer->fc, -1, xfer) == 0) 259110337Ssimokawa return xfer; 260110337Ssimokawa 261110337Ssimokawa fw_xfer_free(xfer); 262110337Ssimokawa return NULL; 263110337Ssimokawa} 264110337Ssimokawa 265103285Sikobint 266272214Skanfwmem_open(struct cdev *dev, int flags, int fmt, fw_proc *td) 267103285Sikob{ 268122228Ssimokawa struct fwmem_softc *fms; 269170374Ssimokawa struct firewire_softc *sc; 270170374Ssimokawa int unit = DEV2UNIT(dev); 271110582Ssimokawa 272170374Ssimokawa sc = devclass_get_softc(firewire_devclass, unit); 273170374Ssimokawa if (sc == NULL) 274170374Ssimokawa return (ENXIO); 275170374Ssimokawa 276170374Ssimokawa FW_GLOCK(sc->fc); 277122228Ssimokawa if (dev->si_drv1 != NULL) { 278170374Ssimokawa if ((flags & FWRITE) != 0) { 279170374Ssimokawa FW_GUNLOCK(sc->fc); 280272214Skan return (EBUSY); 281170374Ssimokawa } 282170374Ssimokawa FW_GUNLOCK(sc->fc); 283272214Skan fms = dev->si_drv1; 284272214Skan fms->refcount++; 285122228Ssimokawa } else { 286170374Ssimokawa dev->si_drv1 = (void *)-1; 287170374Ssimokawa FW_GUNLOCK(sc->fc); 288170374Ssimokawa dev->si_drv1 = malloc(sizeof(struct fwmem_softc), 289272214Skan M_FWMEM, M_WAITOK); 290170374Ssimokawa if (dev->si_drv1 == NULL) 291272214Skan return (ENOMEM); 292170374Ssimokawa dev->si_iosize_max = DFLTPHYS; 293272214Skan fms = dev->si_drv1; 294122228Ssimokawa bcopy(&fwmem_eui64, &fms->eui, sizeof(struct fw_eui64)); 295170374Ssimokawa fms->sc = sc; 296122228Ssimokawa fms->refcount = 1; 297122228Ssimokawa } 298122228Ssimokawa if (fwmem_debug) 299127468Ssimokawa printf("%s: refcount=%d\n", __func__, fms->refcount); 300110582Ssimokawa 301110582Ssimokawa return (0); 302103285Sikob} 303103285Sikob 304103285Sikobint 305130585Sphkfwmem_close (struct cdev *dev, int flags, int fmt, fw_proc *td) 306103285Sikob{ 307122228Ssimokawa struct fwmem_softc *fms; 308115786Ssimokawa 309272214Skan fms = dev->si_drv1; 310170374Ssimokawa 311170374Ssimokawa FW_GLOCK(fms->sc->fc); 312272214Skan fms->refcount--; 313170374Ssimokawa FW_GUNLOCK(fms->sc->fc); 314122228Ssimokawa if (fwmem_debug) 315127468Ssimokawa printf("%s: refcount=%d\n", __func__, fms->refcount); 316122228Ssimokawa if (fms->refcount < 1) { 317137503Ssimokawa free(dev->si_drv1, M_FWMEM); 318122228Ssimokawa dev->si_drv1 = NULL; 319122228Ssimokawa } 320122228Ssimokawa 321110582Ssimokawa return (0); 322103285Sikob} 323103285Sikob 324120660Ssimokawa 325120660Ssimokawastatic void 326120660Ssimokawafwmem_biodone(struct fw_xfer *xfer) 327103285Sikob{ 328120660Ssimokawa struct bio *bp; 329103285Sikob 330120660Ssimokawa bp = (struct bio *)xfer->sc; 331120660Ssimokawa bp->bio_error = xfer->resp; 332120660Ssimokawa 333120660Ssimokawa if (bp->bio_error != 0) { 334121381Ssimokawa if (fwmem_debug) 335127468Ssimokawa printf("%s: err=%d\n", __func__, bp->bio_error); 336120660Ssimokawa bp->bio_flags |= BIO_ERROR; 337120660Ssimokawa bp->bio_resid = bp->bio_bcount; 338106810Ssimokawa } 339103285Sikob 340120660Ssimokawa fw_xfer_free(xfer); 341120660Ssimokawa biodone(bp); 342103285Sikob} 343120660Ssimokawa 344120660Ssimokawavoid 345120660Ssimokawafwmem_strategy(struct bio *bp) 346103285Sikob{ 347122228Ssimokawa struct fwmem_softc *fms; 348110337Ssimokawa struct fw_device *fwdev; 349110337Ssimokawa struct fw_xfer *xfer; 350130585Sphk struct cdev *dev; 351277509Swill int err = 0, iolen; 352110337Ssimokawa 353120660Ssimokawa dev = bp->bio_dev; 354120660Ssimokawa /* XXX check request length */ 355120660Ssimokawa 356272214Skan fms = dev->si_drv1; 357170374Ssimokawa fwdev = fw_noderesolve_eui64(fms->sc->fc, &fms->eui); 358110337Ssimokawa if (fwdev == NULL) { 359110577Ssimokawa if (fwmem_debug) 360110577Ssimokawa printf("fwmem: no such device ID:%08x%08x\n", 361272214Skan fms->eui.hi, fms->eui.lo); 362120660Ssimokawa err = EINVAL; 363120660Ssimokawa goto error; 364110337Ssimokawa } 365110337Ssimokawa 366120660Ssimokawa iolen = MIN(bp->bio_bcount, MAXLEN); 367120660Ssimokawa if ((bp->bio_cmd & BIO_READ) == BIO_READ) { 368120660Ssimokawa if (iolen == 4 && (bp->bio_offset & 3) == 0) 369120660Ssimokawa xfer = fwmem_read_quad(fwdev, 370272214Skan (void *)bp, fwmem_speed, 371120660Ssimokawa bp->bio_offset >> 32, bp->bio_offset & 0xffffffff, 372120660Ssimokawa bp->bio_data, fwmem_biodone); 373120660Ssimokawa else 374120660Ssimokawa xfer = fwmem_read_block(fwdev, 375272214Skan (void *)bp, fwmem_speed, 376120660Ssimokawa bp->bio_offset >> 32, bp->bio_offset & 0xffffffff, 377120660Ssimokawa iolen, bp->bio_data, fwmem_biodone); 378120660Ssimokawa } else { 379120660Ssimokawa if (iolen == 4 && (bp->bio_offset & 3) == 0) 380120660Ssimokawa xfer = fwmem_write_quad(fwdev, 381120660Ssimokawa (void *)bp, fwmem_speed, 382120660Ssimokawa bp->bio_offset >> 32, bp->bio_offset & 0xffffffff, 383120660Ssimokawa bp->bio_data, fwmem_biodone); 384120660Ssimokawa else 385120660Ssimokawa xfer = fwmem_write_block(fwdev, 386120660Ssimokawa (void *)bp, fwmem_speed, 387120660Ssimokawa bp->bio_offset >> 32, bp->bio_offset & 0xffffffff, 388120660Ssimokawa iolen, bp->bio_data, fwmem_biodone); 389110337Ssimokawa } 390120660Ssimokawa if (xfer == NULL) { 391120660Ssimokawa err = EIO; 392120660Ssimokawa goto error; 393120660Ssimokawa } 394120660Ssimokawa /* XXX */ 395120660Ssimokawa bp->bio_resid = bp->bio_bcount - iolen; 396120660Ssimokawaerror: 397120660Ssimokawa if (err != 0) { 398121381Ssimokawa if (fwmem_debug) 399127468Ssimokawa printf("%s: err=%d\n", __func__, err); 400120660Ssimokawa bp->bio_error = err; 401120660Ssimokawa bp->bio_flags |= BIO_ERROR; 402120660Ssimokawa bp->bio_resid = bp->bio_bcount; 403120660Ssimokawa biodone(bp); 404120660Ssimokawa } 405103285Sikob} 406110337Ssimokawa 407103285Sikobint 408272214Skanfwmem_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, fw_proc *td) 409103285Sikob{ 410122228Ssimokawa struct fwmem_softc *fms; 411110582Ssimokawa int err = 0; 412122228Ssimokawa 413272214Skan fms = dev->si_drv1; 414110582Ssimokawa switch (cmd) { 415110582Ssimokawa case FW_SDEUI64: 416122228Ssimokawa bcopy(data, &fms->eui, sizeof(struct fw_eui64)); 417110582Ssimokawa break; 418110582Ssimokawa case FW_GDEUI64: 419122228Ssimokawa bcopy(&fms->eui, data, sizeof(struct fw_eui64)); 420110582Ssimokawa break; 421110582Ssimokawa default: 422110582Ssimokawa err = EINVAL; 423110582Ssimokawa } 424272214Skan return (err); 425103285Sikob} 426272214Skan 427103285Sikobint 428272214Skanfwmem_poll(struct cdev *dev, int events, fw_proc *td) 429272214Skan{ 430103285Sikob return EINVAL; 431103285Sikob} 432272214Skan 433103285Sikobint 434272214Skanfwmem_mmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr, 435201223Srnoland int nproto, vm_memattr_t *memattr) 436272214Skan{ 437103285Sikob return EINVAL; 438103285Sikob} 439