fwmem.c revision 129585
1103285Sikob/* 2113584Ssimokawa * Copyright (c) 2002-2003 3103285Sikob * Hidetoshi Shimokawa. All rights reserved. 4103285Sikob * 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. 21103285Sikob * 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. 33103285Sikob * 34103285Sikob */ 35103285Sikob 36127468Ssimokawa#ifdef __FreeBSD__ 37119418Sobrien#include <sys/cdefs.h> 38119418Sobrien__FBSDID("$FreeBSD: head/sys/dev/firewire/fwmem.c 129585 2004-05-22 16:14:17Z dfr $"); 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> 49127468Ssimokawa#if defined(__DragonFly__) || __FreeBSD_version < 500000 50120660Ssimokawa#include <sys/buf.h> 51120660Ssimokawa#else 52120660Ssimokawa#include <sys/bio.h> 53120660Ssimokawa#endif 54103285Sikob 55103285Sikob#include <sys/bus.h> 56113584Ssimokawa#include <machine/bus.h> 57103285Sikob 58103285Sikob#include <sys/signal.h> 59103285Sikob#include <sys/mman.h> 60103285Sikob#include <sys/ioccom.h> 61122228Ssimokawa#include <sys/fcntl.h> 62103285Sikob 63127468Ssimokawa#ifdef __DragonFly__ 64127468Ssimokawa#include "firewire.h" 65127468Ssimokawa#include "firewirereg.h" 66127468Ssimokawa#include "fwmem.h" 67127468Ssimokawa#else 68103285Sikob#include <dev/firewire/firewire.h> 69103285Sikob#include <dev/firewire/firewirereg.h> 70103285Sikob#include <dev/firewire/fwmem.h> 71127468Ssimokawa#endif 72103285Sikob 73106810Ssimokawastatic int fwmem_speed=2, fwmem_debug=0; 74106810Ssimokawastatic struct fw_eui64 fwmem_eui64; 75103285SikobSYSCTL_DECL(_hw_firewire); 76103285SikobSYSCTL_NODE(_hw_firewire, OID_AUTO, fwmem, CTLFLAG_RD, 0, 77108281Ssimokawa "FireWire Memory Access"); 78106810SsimokawaSYSCTL_UINT(_hw_firewire_fwmem, OID_AUTO, eui64_hi, CTLFLAG_RW, 79106810Ssimokawa &fwmem_eui64.hi, 0, "Fwmem target EUI64 high"); 80110582SsimokawaSYSCTL_UINT(_hw_firewire_fwmem, OID_AUTO, eui64_lo, CTLFLAG_RW, 81106810Ssimokawa &fwmem_eui64.lo, 0, "Fwmem target EUI64 low"); 82103285SikobSYSCTL_INT(_hw_firewire_fwmem, OID_AUTO, speed, CTLFLAG_RW, &fwmem_speed, 0, 83103285Sikob "Fwmem link speed"); 84103285SikobSYSCTL_INT(_debug, OID_AUTO, fwmem_debug, CTLFLAG_RW, &fwmem_debug, 0, 85103285Sikob "Fwmem driver debug flag"); 86103285Sikob 87124145SsimokawaMALLOC_DEFINE(M_FWMEM, "fwmem", "fwmem/FireWire"); 88124145Ssimokawa 89120660Ssimokawa#define MAXLEN (512 << fwmem_speed) 90120660Ssimokawa 91122228Ssimokawastruct fwmem_softc { 92122228Ssimokawa struct fw_eui64 eui; 93122228Ssimokawa int refcount; 94122228Ssimokawa}; 95122228Ssimokawa 96106816Ssimokawastatic struct fw_xfer * 97106816Ssimokawafwmem_xfer_req( 98106810Ssimokawa struct fw_device *fwdev, 99106816Ssimokawa caddr_t sc, 100106816Ssimokawa int spd, 101113584Ssimokawa int slen, 102113584Ssimokawa int rlen, 103106816Ssimokawa void *hand) 104103285Sikob{ 105103285Sikob struct fw_xfer *xfer; 106103285Sikob 107124145Ssimokawa xfer = fw_xfer_alloc(M_FWMEM); 108106804Ssimokawa if (xfer == NULL) 109103285Sikob return NULL; 110106804Ssimokawa 111106810Ssimokawa xfer->fc = fwdev->fc; 112120660Ssimokawa xfer->send.hdr.mode.hdr.dst = FWLOCALBUS | fwdev->dst; 113106816Ssimokawa if (spd < 0) 114120660Ssimokawa xfer->send.spd = fwdev->speed; 115106816Ssimokawa else 116120660Ssimokawa xfer->send.spd = min(spd, fwdev->speed); 117106804Ssimokawa xfer->act.hand = hand; 118103285Sikob xfer->retry_req = fw_asybusy; 119106816Ssimokawa xfer->sc = sc; 120120660Ssimokawa xfer->send.pay_len = slen; 121120660Ssimokawa xfer->recv.pay_len = rlen; 122103285Sikob 123106816Ssimokawa return xfer; 124106816Ssimokawa} 125106816Ssimokawa 126106816Ssimokawastruct fw_xfer * 127106816Ssimokawafwmem_read_quad( 128106816Ssimokawa struct fw_device *fwdev, 129106816Ssimokawa caddr_t sc, 130129585Sdfr uint8_t spd, 131129585Sdfr uint16_t dst_hi, 132129585Sdfr uint32_t dst_lo, 133120660Ssimokawa void *data, 134106816Ssimokawa void (*hand)(struct fw_xfer *)) 135106816Ssimokawa{ 136106816Ssimokawa struct fw_xfer *xfer; 137106816Ssimokawa struct fw_pkt *fp; 138106816Ssimokawa 139120660Ssimokawa xfer = fwmem_xfer_req(fwdev, (void *)sc, spd, 0, 4, hand); 140120660Ssimokawa if (xfer == NULL) { 141106816Ssimokawa return NULL; 142120660Ssimokawa } 143106816Ssimokawa 144120660Ssimokawa fp = &xfer->send.hdr; 145103285Sikob fp->mode.rreqq.tcode = FWTCODE_RREQQ; 146113584Ssimokawa fp->mode.rreqq.dest_hi = dst_hi; 147113584Ssimokawa fp->mode.rreqq.dest_lo = dst_lo; 148103285Sikob 149120660Ssimokawa xfer->send.payload = NULL; 150129585Sdfr xfer->recv.payload = (uint32_t *)data; 151120660Ssimokawa 152103285Sikob if (fwmem_debug) 153106816Ssimokawa printf("fwmem_read_quad: %d %04x:%08x\n", fwdev->dst, 154106816Ssimokawa dst_hi, dst_lo); 155106804Ssimokawa 156106810Ssimokawa if (fw_asyreq(xfer->fc, -1, xfer) == 0) 157103285Sikob return xfer; 158106804Ssimokawa 159103285Sikob fw_xfer_free(xfer); 160103285Sikob return NULL; 161103285Sikob} 162103285Sikob 163103285Sikobstruct fw_xfer * 164106810Ssimokawafwmem_write_quad( 165106810Ssimokawa struct fw_device *fwdev, 166106810Ssimokawa caddr_t sc, 167129585Sdfr uint8_t spd, 168129585Sdfr uint16_t dst_hi, 169129585Sdfr uint32_t dst_lo, 170120660Ssimokawa void *data, 171106810Ssimokawa void (*hand)(struct fw_xfer *)) 172106810Ssimokawa{ 173106810Ssimokawa struct fw_xfer *xfer; 174106810Ssimokawa struct fw_pkt *fp; 175106810Ssimokawa 176120660Ssimokawa xfer = fwmem_xfer_req(fwdev, sc, spd, 0, 0, hand); 177106810Ssimokawa if (xfer == NULL) 178106810Ssimokawa return NULL; 179106810Ssimokawa 180120660Ssimokawa fp = &xfer->send.hdr; 181110072Ssimokawa fp->mode.wreqq.tcode = FWTCODE_WREQQ; 182113584Ssimokawa fp->mode.wreqq.dest_hi = dst_hi; 183113584Ssimokawa fp->mode.wreqq.dest_lo = dst_lo; 184129585Sdfr fp->mode.wreqq.data = *(uint32_t *)data; 185106810Ssimokawa 186120660Ssimokawa xfer->send.payload = xfer->recv.payload = NULL; 187106810Ssimokawa 188106810Ssimokawa if (fwmem_debug) 189106816Ssimokawa printf("fwmem_write_quad: %d %04x:%08x %08x\n", fwdev->dst, 190129585Sdfr dst_hi, dst_lo, *(uint32_t *)data); 191106810Ssimokawa 192106810Ssimokawa if (fw_asyreq(xfer->fc, -1, xfer) == 0) 193106810Ssimokawa return xfer; 194106810Ssimokawa 195106810Ssimokawa fw_xfer_free(xfer); 196106810Ssimokawa return NULL; 197106810Ssimokawa} 198106810Ssimokawa 199106810Ssimokawastruct fw_xfer * 200103285Sikobfwmem_read_block( 201106810Ssimokawa struct fw_device *fwdev, 202106810Ssimokawa caddr_t sc, 203129585Sdfr uint8_t spd, 204129585Sdfr uint16_t dst_hi, 205129585Sdfr uint32_t dst_lo, 206106804Ssimokawa int len, 207120660Ssimokawa void *data, 208106804Ssimokawa void (*hand)(struct fw_xfer *)) 209103285Sikob{ 210103285Sikob struct fw_xfer *xfer; 211103285Sikob struct fw_pkt *fp; 212120660Ssimokawa 213120660Ssimokawa xfer = fwmem_xfer_req(fwdev, sc, spd, 0, roundup2(len, 4), hand); 214106804Ssimokawa if (xfer == NULL) 215103285Sikob return NULL; 216106804Ssimokawa 217120660Ssimokawa fp = &xfer->send.hdr; 218103285Sikob fp->mode.rreqb.tcode = FWTCODE_RREQB; 219113584Ssimokawa fp->mode.rreqb.dest_hi = dst_hi; 220113584Ssimokawa fp->mode.rreqb.dest_lo = dst_lo; 221113584Ssimokawa fp->mode.rreqb.len = len; 222120660Ssimokawa fp->mode.rreqb.extcode = 0; 223103285Sikob 224120660Ssimokawa xfer->send.payload = NULL; 225120660Ssimokawa xfer->recv.payload = data; 226120660Ssimokawa 227103285Sikob if (fwmem_debug) 228106816Ssimokawa printf("fwmem_read_block: %d %04x:%08x %d\n", fwdev->dst, 229106810Ssimokawa dst_hi, dst_lo, len); 230106810Ssimokawa if (fw_asyreq(xfer->fc, -1, xfer) == 0) 231103285Sikob return xfer; 232106804Ssimokawa 233103285Sikob fw_xfer_free(xfer); 234103285Sikob return NULL; 235103285Sikob} 236103285Sikob 237110337Ssimokawastruct fw_xfer * 238110337Ssimokawafwmem_write_block( 239110337Ssimokawa struct fw_device *fwdev, 240110337Ssimokawa caddr_t sc, 241129585Sdfr uint8_t spd, 242129585Sdfr uint16_t dst_hi, 243129585Sdfr uint32_t dst_lo, 244110337Ssimokawa int len, 245120660Ssimokawa void *data, 246110337Ssimokawa void (*hand)(struct fw_xfer *)) 247110337Ssimokawa{ 248110337Ssimokawa struct fw_xfer *xfer; 249110337Ssimokawa struct fw_pkt *fp; 250110337Ssimokawa 251120660Ssimokawa xfer = fwmem_xfer_req(fwdev, sc, spd, len, 0, hand); 252110337Ssimokawa if (xfer == NULL) 253110337Ssimokawa return NULL; 254110337Ssimokawa 255120660Ssimokawa fp = &xfer->send.hdr; 256110406Ssimokawa fp->mode.wreqb.tcode = FWTCODE_WREQB; 257113584Ssimokawa fp->mode.wreqb.dest_hi = dst_hi; 258113584Ssimokawa fp->mode.wreqb.dest_lo = dst_lo; 259113584Ssimokawa fp->mode.wreqb.len = len; 260120660Ssimokawa fp->mode.wreqb.extcode = 0; 261110337Ssimokawa 262120660Ssimokawa xfer->send.payload = data; 263120660Ssimokawa xfer->recv.payload = NULL; 264120660Ssimokawa 265110337Ssimokawa if (fwmem_debug) 266110337Ssimokawa printf("fwmem_write_block: %d %04x:%08x %d\n", fwdev->dst, 267110337Ssimokawa dst_hi, dst_lo, len); 268110337Ssimokawa if (fw_asyreq(xfer->fc, -1, xfer) == 0) 269110337Ssimokawa return xfer; 270110337Ssimokawa 271110337Ssimokawa fw_xfer_free(xfer); 272110337Ssimokawa return NULL; 273110337Ssimokawa} 274110337Ssimokawa 275110337Ssimokawa 276103285Sikobint 277103285Sikobfwmem_open (dev_t dev, int flags, int fmt, fw_proc *td) 278103285Sikob{ 279122228Ssimokawa struct fwmem_softc *fms; 280110582Ssimokawa 281122228Ssimokawa if (dev->si_drv1 != NULL) { 282122228Ssimokawa if ((flags & FWRITE) != 0) 283122228Ssimokawa return (EBUSY); 284122228Ssimokawa fms = (struct fwmem_softc *)dev->si_drv1; 285122228Ssimokawa fms->refcount ++; 286122228Ssimokawa } else { 287122228Ssimokawa fms = (struct fwmem_softc *)malloc(sizeof(struct fwmem_softc), 288124145Ssimokawa M_FWMEM, M_WAITOK); 289122228Ssimokawa if (fms == NULL) 290122228Ssimokawa return ENOMEM; 291122228Ssimokawa bcopy(&fwmem_eui64, &fms->eui, sizeof(struct fw_eui64)); 292122228Ssimokawa dev->si_drv1 = (void *)fms; 293122228Ssimokawa dev->si_iosize_max = DFLTPHYS; 294122228Ssimokawa fms->refcount = 1; 295122228Ssimokawa } 296122228Ssimokawa if (fwmem_debug) 297127468Ssimokawa printf("%s: refcount=%d\n", __func__, fms->refcount); 298110582Ssimokawa 299110582Ssimokawa return (0); 300103285Sikob} 301103285Sikob 302103285Sikobint 303103285Sikobfwmem_close (dev_t dev, int flags, int fmt, fw_proc *td) 304103285Sikob{ 305122228Ssimokawa struct fwmem_softc *fms; 306115786Ssimokawa 307122228Ssimokawa fms = (struct fwmem_softc *)dev->si_drv1; 308122228Ssimokawa fms->refcount --; 309122228Ssimokawa if (fwmem_debug) 310127468Ssimokawa printf("%s: refcount=%d\n", __func__, fms->refcount); 311122228Ssimokawa if (fms->refcount < 1) { 312122228Ssimokawa free(dev->si_drv1, M_FW); 313122228Ssimokawa dev->si_drv1 = NULL; 314122228Ssimokawa } 315122228Ssimokawa 316110582Ssimokawa return (0); 317103285Sikob} 318103285Sikob 319120660Ssimokawa 320120660Ssimokawastatic void 321120660Ssimokawafwmem_biodone(struct fw_xfer *xfer) 322103285Sikob{ 323120660Ssimokawa struct bio *bp; 324103285Sikob 325120660Ssimokawa bp = (struct bio *)xfer->sc; 326120660Ssimokawa bp->bio_error = xfer->resp; 327120660Ssimokawa 328120660Ssimokawa if (bp->bio_error != 0) { 329121381Ssimokawa if (fwmem_debug) 330127468Ssimokawa printf("%s: err=%d\n", __func__, bp->bio_error); 331120660Ssimokawa bp->bio_flags |= BIO_ERROR; 332120660Ssimokawa bp->bio_resid = bp->bio_bcount; 333106810Ssimokawa } 334103285Sikob 335120660Ssimokawa fw_xfer_free(xfer); 336120660Ssimokawa biodone(bp); 337103285Sikob} 338120660Ssimokawa 339120660Ssimokawavoid 340120660Ssimokawafwmem_strategy(struct bio *bp) 341103285Sikob{ 342110337Ssimokawa struct firewire_softc *sc; 343122228Ssimokawa struct fwmem_softc *fms; 344110337Ssimokawa struct fw_device *fwdev; 345110337Ssimokawa struct fw_xfer *xfer; 346120660Ssimokawa dev_t dev; 347120660Ssimokawa int unit, err=0, s, iolen; 348110337Ssimokawa 349120660Ssimokawa dev = bp->bio_dev; 350120660Ssimokawa /* XXX check request length */ 351120660Ssimokawa 352120660Ssimokawa unit = DEV2UNIT(dev); 353110337Ssimokawa sc = devclass_get_softc(firewire_devclass, unit); 354120660Ssimokawa 355120660Ssimokawa s = splfw(); 356122228Ssimokawa fms = (struct fwmem_softc *)dev->si_drv1; 357122228Ssimokawa fwdev = fw_noderesolve_eui64(sc->fc, &fms->eui); 358110337Ssimokawa if (fwdev == NULL) { 359110577Ssimokawa if (fwmem_debug) 360110577Ssimokawa printf("fwmem: no such device ID:%08x%08x\n", 361122228Ssimokawa 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, 370120660Ssimokawa (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, 375120660Ssimokawa (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 splx(s); 398120660Ssimokawa if (err != 0) { 399121381Ssimokawa if (fwmem_debug) 400127468Ssimokawa printf("%s: err=%d\n", __func__, err); 401120660Ssimokawa bp->bio_error = err; 402120660Ssimokawa bp->bio_flags |= BIO_ERROR; 403120660Ssimokawa bp->bio_resid = bp->bio_bcount; 404120660Ssimokawa biodone(bp); 405120660Ssimokawa } 406103285Sikob} 407110337Ssimokawa 408103285Sikobint 409103285Sikobfwmem_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td) 410103285Sikob{ 411122228Ssimokawa struct fwmem_softc *fms; 412110582Ssimokawa int err = 0; 413122228Ssimokawa 414122228Ssimokawa fms = (struct fwmem_softc *)dev->si_drv1; 415110582Ssimokawa switch (cmd) { 416110582Ssimokawa case FW_SDEUI64: 417122228Ssimokawa bcopy(data, &fms->eui, sizeof(struct fw_eui64)); 418110582Ssimokawa break; 419110582Ssimokawa case FW_GDEUI64: 420122228Ssimokawa bcopy(&fms->eui, data, sizeof(struct fw_eui64)); 421110582Ssimokawa break; 422110582Ssimokawa default: 423110582Ssimokawa err = EINVAL; 424110582Ssimokawa } 425110582Ssimokawa return(err); 426103285Sikob} 427103285Sikobint 428103285Sikobfwmem_poll (dev_t dev, int events, fw_proc *td) 429103285Sikob{ 430103285Sikob return EINVAL; 431103285Sikob} 432103285Sikobint 433127468Ssimokawa#if defined(__DragonFly__) || __FreeBSD_version < 500102 434111615Ssimokawafwmem_mmap (dev_t dev, vm_offset_t offset, int nproto) 435111615Ssimokawa#else 436113584Ssimokawafwmem_mmap (dev_t dev, vm_offset_t offset, vm_paddr_t *paddr, int nproto) 437111615Ssimokawa#endif 438103285Sikob{ 439103285Sikob return EINVAL; 440103285Sikob} 441