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