xref: /freebsd/sys/dev/firewire/if_fwe.c (revision f5dc2263ab1be8a35a7e27e82103f9ccd41ae584)
1 /*-
2  * SPDX-License-Identifier: BSD-4-Clause
3  *
4  * Copyright (c) 2002-2003
5  * 	Hidetoshi Shimokawa. All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *
18  *	This product includes software developed by Hidetoshi Shimokawa.
19  *
20  * 4. Neither the name of the author nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36 
37 #ifdef HAVE_KERNEL_OPTION_HEADERS
38 #include "opt_device_polling.h"
39 #include "opt_inet.h"
40 #endif
41 
42 #include <sys/param.h>
43 #include <sys/kernel.h>
44 #include <sys/malloc.h>
45 #include <sys/mbuf.h>
46 #include <sys/socket.h>
47 #include <sys/sockio.h>
48 #include <sys/sysctl.h>
49 #include <sys/systm.h>
50 #include <sys/module.h>
51 #include <sys/bus.h>
52 #include <machine/bus.h>
53 
54 #include <net/bpf.h>
55 #include <net/ethernet.h>
56 #include <net/if.h>
57 #include <net/if_var.h>
58 #include <net/if_arp.h>
59 #include <net/if_types.h>
60 #include <net/if_vlan_var.h>
61 
62 #include <dev/firewire/firewire.h>
63 #include <dev/firewire/firewirereg.h>
64 #include <dev/firewire/if_fwevar.h>
65 #include <dev/firewire/fw_net.h>
66 
67 #define FWEDEBUG	if (fwedebug) if_printf
68 #define TX_MAX_QUEUE	(FWMAXQUEUE - 1)
69 
70 /* network interface */
71 static void fwe_start (if_t);
72 static int fwe_ioctl (if_t, u_long, caddr_t);
73 static void fwe_init (void *);
74 
75 static void fwe_output_callback (struct fw_xfer *);
76 static void fwe_as_output (struct fwe_softc *, if_t);
77 static void fwe_as_input (struct fw_xferq *);
78 
79 static int fwedebug = 0;
80 static int stream_ch = 1;
81 static int tx_speed = FWSPD_S400;
82 static int rx_queue_len = FWMAXQUEUE;
83 
84 static MALLOC_DEFINE(M_FWE, "if_fwe", "Ethernet over FireWire interface");
85 SYSCTL_INT(_debug, OID_AUTO, if_fwe_debug, CTLFLAG_RWTUN, &fwedebug, 0, "");
86 SYSCTL_DECL(_hw_firewire);
87 static SYSCTL_NODE(_hw_firewire, OID_AUTO, fwe, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
88     "Ethernet emulation subsystem");
89 SYSCTL_INT(_hw_firewire_fwe, OID_AUTO, stream_ch, CTLFLAG_RWTUN, &stream_ch, 0,
90 	"Stream channel to use");
91 SYSCTL_INT(_hw_firewire_fwe, OID_AUTO, tx_speed, CTLFLAG_RWTUN, &tx_speed, 0,
92 	"Transmission speed");
93 SYSCTL_INT(_hw_firewire_fwe, OID_AUTO, rx_queue_len, CTLFLAG_RWTUN, &rx_queue_len,
94 	0, "Length of the receive queue");
95 
96 #ifdef DEVICE_POLLING
97 static poll_handler_t fwe_poll;
98 
99 static int
100 fwe_poll(if_t ifp, enum poll_cmd cmd, int count)
101 {
102 	struct fwe_softc *fwe;
103 	struct firewire_comm *fc;
104 
105 	if (!(if_getdrvflags(ifp) & IFF_DRV_RUNNING))
106 		return (0);
107 
108 	fwe = ((struct fwe_eth_softc *)if_getsoftc(ifp))->fwe;
109 	fc = fwe->fd.fc;
110 	fc->poll(fc, (cmd == POLL_AND_CHECK_STATUS)?0:1, count);
111 	return (0);
112 }
113 #endif /* DEVICE_POLLING */
114 
115 static void
116 fwe_identify(driver_t *driver, device_t parent)
117 {
118 	BUS_ADD_CHILD(parent, 0, "fwe", device_get_unit(parent));
119 }
120 
121 static int
122 fwe_probe(device_t dev)
123 {
124 	device_t pa;
125 
126 	if (fw_get_unit(dev) != NULL)
127 		return (ENXIO);
128 
129 	pa = device_get_parent(dev);
130 	if (device_get_unit(dev) != device_get_unit(pa))
131 		return (ENXIO);
132 
133 	device_set_desc(dev, "Ethernet over FireWire");
134 	return (0);
135 }
136 
137 static int
138 fwe_attach(device_t dev)
139 {
140 	struct fwe_softc *fwe;
141 	if_t ifp;
142 	int unit;
143 	u_char eaddr[6];
144 	struct fw_eui64 *eui;
145 
146 	fwe = ((struct fwe_softc *)device_get_softc(dev));
147 	unit = device_get_unit(dev);
148 
149 	bzero(fwe, sizeof(struct fwe_softc));
150 	mtx_init(&fwe->mtx, "fwe", NULL, MTX_DEF);
151 	/* XXX */
152 	fwe->stream_ch = stream_ch;
153 	fwe->dma_ch = -1;
154 
155 	fwe->fd.fc = fw_get_comm(dev);
156 	if (tx_speed < 0)
157 		tx_speed = fwe->fd.fc->speed;
158 
159 	fwe->fd.dev = dev;
160 	fwe->fd.post_explore = NULL;
161 	fwe->eth_softc.fwe = fwe;
162 
163 	fwe->pkt_hdr.mode.stream.tcode = FWTCODE_STREAM;
164 	fwe->pkt_hdr.mode.stream.sy = 0;
165 	fwe->pkt_hdr.mode.stream.chtag = fwe->stream_ch;
166 
167 	/* generate fake MAC address: first and last 3bytes from eui64 */
168 #define LOCAL (0x02)
169 #define GROUP (0x01)
170 
171 	eui = &fwe->fd.fc->eui;
172 	eaddr[0] = (FW_EUI64_BYTE(eui, 0) | LOCAL) & ~GROUP;
173 	eaddr[1] = FW_EUI64_BYTE(eui, 1);
174 	eaddr[2] = FW_EUI64_BYTE(eui, 2);
175 	eaddr[3] = FW_EUI64_BYTE(eui, 5);
176 	eaddr[4] = FW_EUI64_BYTE(eui, 6);
177 	eaddr[5] = FW_EUI64_BYTE(eui, 7);
178 	printf("if_fwe%d: Fake Ethernet address: "
179 		"%02x:%02x:%02x:%02x:%02x:%02x\n", unit,
180 		eaddr[0], eaddr[1], eaddr[2], eaddr[3], eaddr[4], eaddr[5]);
181 
182 	/* fill the rest and attach interface */
183 	ifp = fwe->eth_softc.ifp = if_alloc(IFT_ETHER);
184 	if_setsoftc(ifp, &fwe->eth_softc);
185 
186 	if_initname(ifp, device_get_name(dev), unit);
187 	if_setinitfn(ifp, fwe_init);
188 	if_setstartfn(ifp, fwe_start);
189 	if_setioctlfn(ifp, fwe_ioctl);
190 	if_setflags(ifp, (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST));
191 	if_setsendqlen(ifp, TX_MAX_QUEUE);
192 
193 	ether_ifattach(ifp, eaddr);
194 
195         /* Tell the upper layer(s) we support long frames. */
196 	if_setifheaderlen(ifp, sizeof(struct ether_vlan_header));
197 	if_setcapabilitiesbit(ifp, IFCAP_VLAN_MTU | IFCAP_POLLING, 0);
198 	if_setcapenablebit(ifp, IFCAP_VLAN_MTU, 0);
199 
200 	FWEDEBUG(ifp, "interface created\n");
201 	return (0);
202 }
203 
204 static void
205 fwe_stop(struct fwe_softc *fwe)
206 {
207 	struct firewire_comm *fc;
208 	struct fw_xferq *xferq;
209 	if_t ifp = fwe->eth_softc.ifp;
210 	int i;
211 
212 	fc = fwe->fd.fc;
213 
214 	if (fwe->dma_ch >= 0) {
215 		xferq = fc->ir[fwe->dma_ch];
216 
217 		if (xferq->flag & FWXFERQ_RUNNING)
218 			fc->irx_disable(fc, fwe->dma_ch);
219 		xferq->flag &=
220 			~(FWXFERQ_MODEMASK | FWXFERQ_OPEN | FWXFERQ_STREAM |
221 			FWXFERQ_EXTBUF | FWXFERQ_HANDLER | FWXFERQ_CHTAGMASK);
222 		xferq->hand =  NULL;
223 
224 		for (i = 0; i < xferq->bnchunk; i++)
225 			m_freem(xferq->bulkxfer[i].mbuf);
226 		free(xferq->bulkxfer, M_FWE);
227 
228 		FW_NET_FREE_XFERLIST(&fwe->xferlist);
229 		STAILQ_INIT(&fwe->xferlist);
230 
231 		xferq->bulkxfer =  NULL;
232 		fwe->dma_ch = -1;
233 	}
234 
235 	if_setdrvflagbits(ifp, 0, (IFF_DRV_RUNNING | IFF_DRV_OACTIVE));
236 }
237 
238 static int
239 fwe_detach(device_t dev)
240 {
241 	struct fwe_softc *fwe;
242 	if_t ifp;
243 
244 	fwe = device_get_softc(dev);
245 	ifp = fwe->eth_softc.ifp;
246 
247 #ifdef DEVICE_POLLING
248 	if (if_getcapenable(ifp) & IFCAP_POLLING)
249 		ether_poll_deregister(ifp);
250 #endif
251 
252 	fwe_stop(fwe);
253 	ether_ifdetach(ifp);
254 	if_free(ifp);
255 
256 	mtx_destroy(&fwe->mtx);
257 	return 0;
258 }
259 
260 static void
261 fwe_init(void *arg)
262 {
263 	struct fwe_softc *fwe = ((struct fwe_eth_softc *)arg)->fwe;
264 	struct firewire_comm *fc;
265 	if_t ifp = fwe->eth_softc.ifp;
266 	struct fw_xferq *xferq;
267 	struct fw_xfer *xfer;
268 	int i;
269 
270 	FWEDEBUG(ifp, "initializing\n");
271 
272 	/* keep promiscuous mode */
273 	if_setflagbits(ifp, IFF_PROMISC, 0);
274 
275 	fc = fwe->fd.fc;
276 	if (fwe->dma_ch < 0) {
277 		fwe->dma_ch = fw_open_isodma(fc, /* tx */0);
278 		if (fwe->dma_ch < 0)
279 			return;
280 		xferq = fc->ir[fwe->dma_ch];
281 		xferq->flag |= FWXFERQ_EXTBUF |
282 				FWXFERQ_HANDLER | FWXFERQ_STREAM;
283 		fwe->stream_ch = stream_ch;
284 		fwe->pkt_hdr.mode.stream.chtag = fwe->stream_ch;
285 		xferq->flag &= ~0xff;
286 		xferq->flag |= fwe->stream_ch & 0xff;
287 		/* register fwe_input handler */
288 		xferq->sc = (caddr_t) fwe;
289 		xferq->hand = fwe_as_input;
290 		xferq->bnchunk = rx_queue_len;
291 		xferq->bnpacket = 1;
292 		xferq->psize = MCLBYTES;
293 		xferq->queued = 0;
294 		xferq->buf = NULL;
295 		xferq->bulkxfer = (struct fw_bulkxfer *) malloc(
296 			sizeof(struct fw_bulkxfer) * xferq->bnchunk,
297 							M_FWE, M_WAITOK);
298 		STAILQ_INIT(&xferq->stvalid);
299 		STAILQ_INIT(&xferq->stfree);
300 		STAILQ_INIT(&xferq->stdma);
301 		xferq->stproc = NULL;
302 		fw_net_init_iso_chunks(xferq);
303 		STAILQ_INIT(&fwe->xferlist);
304 		for (i = 0; i < TX_MAX_QUEUE; i++) {
305 			xfer = fw_net_alloc_txfer(fwe->fd.fc, tx_speed,
306 			    fwe, fwe_output_callback, M_FWE);
307 			if (xfer == NULL)
308 				break;
309 			STAILQ_INSERT_TAIL(&fwe->xferlist, xfer, link);
310 		}
311 	} else
312 		xferq = fc->ir[fwe->dma_ch];
313 
314 
315 	/* start dma */
316 	if ((xferq->flag & FWXFERQ_RUNNING) == 0)
317 		fc->irx_enable(fc, fwe->dma_ch);
318 
319 	if_setdrvflagbits(ifp, IFF_DRV_RUNNING, 0);
320 	if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE);
321 
322 }
323 
324 
325 static int
326 fwe_ioctl(if_t ifp, u_long cmd, caddr_t data)
327 {
328 	struct fwe_softc *fwe = ((struct fwe_eth_softc *)if_getsoftc(ifp))->fwe;
329 	struct ifstat *ifs = NULL;
330 	int error;
331 
332 	switch (cmd) {
333 		case SIOCSIFFLAGS:
334 			if (if_getflags(ifp) & IFF_UP) {
335 				if (!(if_getdrvflags(ifp) & IFF_DRV_RUNNING))
336 					fwe_init(&fwe->eth_softc);
337 			} else {
338 				if (if_getdrvflags(ifp) & IFF_DRV_RUNNING)
339 					fwe_stop(fwe);
340 			}
341 			/* keep promiscuous mode */
342 			if_setflagbits(ifp, IFF_PROMISC, 0);
343 			break;
344 		case SIOCADDMULTI:
345 		case SIOCDELMULTI:
346 			break;
347 
348 		case SIOCGIFSTATUS:
349 			ifs = (struct ifstat *)data;
350 			snprintf(ifs->ascii, sizeof(ifs->ascii),
351 			    "\tch %d dma %d\n",	fwe->stream_ch, fwe->dma_ch);
352 			break;
353 		case SIOCSIFCAP:
354 #ifdef DEVICE_POLLING
355 		    {
356 			struct ifreq *ifr = (struct ifreq *) data;
357 
358 			error = fw_net_poll_ioctl(ifp, ifr,
359 			    fwe->fd.fc, fwe_poll);
360 			if (error >= 0)
361 				return (error);
362 		    }
363 #endif /* DEVICE_POLLING */
364 			break;
365 		default:
366 			error = ether_ioctl(ifp, cmd, data);
367 			return (error);
368 	}
369 
370 	return (0);
371 }
372 
373 static void
374 fwe_output_callback(struct fw_xfer *xfer)
375 {
376 	struct fwe_softc *fwe;
377 	if_t ifp;
378 
379 	fwe = (struct fwe_softc *)xfer->sc;
380 	ifp = fwe->eth_softc.ifp;
381 	/* XXX error check */
382 	FWEDEBUG(ifp, "resp = %d\n", xfer->resp);
383 	if (xfer->resp != 0)
384 		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
385 	m_freem(xfer->mbuf);
386 	fw_xfer_unload(xfer);
387 
388 	FWE_LOCK(fwe);
389 	STAILQ_INSERT_TAIL(&fwe->xferlist, xfer, link);
390 	FWE_UNLOCK(fwe);
391 
392 	/* for queue full */
393 	if (!if_sendq_empty(ifp))
394 		fwe_start(ifp);
395 }
396 
397 static void
398 fwe_start(if_t ifp)
399 {
400 	struct fwe_softc *fwe = ((struct fwe_eth_softc *)if_getsoftc(ifp))->fwe;
401 
402 	FWEDEBUG(ifp, "starting\n");
403 
404 	if (fwe->dma_ch < 0) {
405 		FWEDEBUG(ifp, "not ready\n");
406 
407 		fw_net_drain_sendq(ifp);
408 
409 		return;
410 	}
411 
412 	if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0);
413 
414 	if (!if_sendq_empty(ifp))
415 		fwe_as_output(fwe, ifp);
416 
417 	if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE);
418 }
419 
420 #define HDR_LEN 4
421 #ifndef ETHER_ALIGN
422 #define ETHER_ALIGN 2
423 #endif
424 /* Async. stream output */
425 static void
426 fwe_as_output(struct fwe_softc *fwe, if_t ifp)
427 {
428 	struct mbuf *m;
429 	struct fw_xfer *xfer;
430 	struct fw_xferq *xferq;
431 	struct fw_pkt *fp;
432 	int i = 0;
433 
434 	xfer = NULL;
435 	xferq = fwe->fd.fc->atq;
436 	while ((xferq->queued < xferq->maxq - 1) &&
437 			!if_sendq_empty(ifp)) {
438 		FWE_LOCK(fwe);
439 		xfer = STAILQ_FIRST(&fwe->xferlist);
440 		if (xfer == NULL) {
441 			FWE_UNLOCK(fwe);
442 			break;
443 		}
444 		STAILQ_REMOVE_HEAD(&fwe->xferlist, link);
445 		FWE_UNLOCK(fwe);
446 
447 		m = if_dequeue(ifp);
448 		if (m == NULL) {
449 			FWE_LOCK(fwe);
450 			STAILQ_INSERT_HEAD(&fwe->xferlist, xfer, link);
451 			FWE_UNLOCK(fwe);
452 			break;
453 		}
454 		BPF_MTAP(ifp, m);
455 
456 		/* keep ip packet alignment for alpha */
457 		M_PREPEND(m, ETHER_ALIGN, M_NOWAIT);
458 		fp = &xfer->send.hdr;
459 		*(uint32_t *)&xfer->send.hdr = *(int32_t *)&fwe->pkt_hdr;
460 		fp->mode.stream.len = m->m_pkthdr.len;
461 		xfer->mbuf = m;
462 		xfer->send.pay_len = m->m_pkthdr.len;
463 
464 		if (fw_asyreq(fwe->fd.fc, -1, xfer) != 0) {
465 			/* error */
466 			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
467 			/* XXX set error code */
468 			fwe_output_callback(xfer);
469 		} else {
470 			if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
471 			i++;
472 		}
473 	}
474 	if (i > 0)
475 		xferq->start(fwe->fd.fc);
476 }
477 
478 /* Async. stream output */
479 static void
480 fwe_as_input(struct fw_xferq *xferq)
481 {
482 	struct mbuf *m, *m0;
483 	if_t ifp;
484 	struct fwe_softc *fwe;
485 	struct fw_bulkxfer *sxfer;
486 	struct fw_pkt *fp;
487 	struct epoch_tracker et;
488 
489 	fwe = (struct fwe_softc *)xferq->sc;
490 	ifp = fwe->eth_softc.ifp;
491 
492 	/* We do not need a lock here because the bottom half is serialized */
493 	while ((sxfer = STAILQ_FIRST(&xferq->stvalid)) != NULL) {
494 		STAILQ_REMOVE_HEAD(&xferq->stvalid, link);
495 		fp = mtod(sxfer->mbuf, struct fw_pkt *);
496 		if (fwe->fd.fc->irx_post != NULL)
497 			fwe->fd.fc->irx_post(fwe->fd.fc, fp->mode.ld);
498 		m = sxfer->mbuf;
499 
500 		/* insert new rbuf */
501 		sxfer->mbuf = m0 = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
502 		if (m0 != NULL) {
503 			m0->m_len = m0->m_pkthdr.len = m0->m_ext.ext_size;
504 			STAILQ_INSERT_TAIL(&xferq->stfree, sxfer, link);
505 		} else
506 			printf("%s: m_getcl failed\n", __FUNCTION__);
507 
508 		if (sxfer->resp != 0 || fp->mode.stream.len <
509 		    ETHER_ALIGN + sizeof(struct ether_header)) {
510 			m_freem(m);
511 			if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
512 			continue;
513 		}
514 
515 		m->m_data += HDR_LEN + ETHER_ALIGN;
516 		m->m_len = m->m_pkthdr.len = fp->mode.stream.len - ETHER_ALIGN;
517 		m->m_pkthdr.rcvif = ifp;
518 		NET_EPOCH_ENTER(et);
519 		if_input(ifp, m);
520 		NET_EPOCH_EXIT(et);
521 		if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
522 	}
523 	if (STAILQ_FIRST(&xferq->stfree) != NULL)
524 		fwe->fd.fc->irx_enable(fwe->fd.fc, fwe->dma_ch);
525 }
526 
527 
528 static device_method_t fwe_methods[] = {
529 	/* device interface */
530 	DEVMETHOD(device_identify,	fwe_identify),
531 	DEVMETHOD(device_probe,		fwe_probe),
532 	DEVMETHOD(device_attach,	fwe_attach),
533 	DEVMETHOD(device_detach,	fwe_detach),
534 	DEVMETHOD_END
535 };
536 
537 static driver_t fwe_driver = {
538         "fwe",
539 	fwe_methods,
540 	sizeof(struct fwe_softc),
541 };
542 
543 
544 DRIVER_MODULE(fwe, firewire, fwe_driver, 0, 0);
545 MODULE_VERSION(fwe, 1);
546 MODULE_DEPEND(fwe, firewire, 1, 1, 1);
547