xref: /freebsd/sys/dev/firewire/if_fwe.c (revision 1403ca10189c47ad1de3915eeb030deddc114685)
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 = 2;
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 	/* XXX keep promiscoud 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 #if 0
323 	/* attempt to start output */
324 	fwe_start(ifp);
325 #endif
326 }
327 
328 
329 static int
330 fwe_ioctl(if_t ifp, u_long cmd, caddr_t data)
331 {
332 	struct fwe_softc *fwe = ((struct fwe_eth_softc *)if_getsoftc(ifp))->fwe;
333 	struct ifstat *ifs = NULL;
334 	int error;
335 
336 	switch (cmd) {
337 		case SIOCSIFFLAGS:
338 			if (if_getflags(ifp) & IFF_UP) {
339 				if (!(if_getdrvflags(ifp) & IFF_DRV_RUNNING))
340 					fwe_init(&fwe->eth_softc);
341 			} else {
342 				if (if_getdrvflags(ifp) & IFF_DRV_RUNNING)
343 					fwe_stop(fwe);
344 			}
345 			/* XXX keep promiscoud mode */
346 			if_setflagbits(ifp, IFF_PROMISC, 0);
347 			break;
348 		case SIOCADDMULTI:
349 		case SIOCDELMULTI:
350 			break;
351 
352 		case SIOCGIFSTATUS:
353 			ifs = (struct ifstat *)data;
354 			snprintf(ifs->ascii, sizeof(ifs->ascii),
355 			    "\tch %d dma %d\n",	fwe->stream_ch, fwe->dma_ch);
356 			break;
357 		case SIOCSIFCAP:
358 #ifdef DEVICE_POLLING
359 		    {
360 			struct ifreq *ifr = (struct ifreq *) data;
361 
362 			error = fw_net_poll_ioctl(ifp, ifr,
363 			    fwe->fd.fc, fwe_poll);
364 			if (error >= 0)
365 				return (error);
366 		    }
367 #endif /* DEVICE_POLLING */
368 			break;
369 		default:
370 			error = ether_ioctl(ifp, cmd, data);
371 			return (error);
372 	}
373 
374 	return (0);
375 }
376 
377 static void
378 fwe_output_callback(struct fw_xfer *xfer)
379 {
380 	struct fwe_softc *fwe;
381 	if_t ifp;
382 
383 	fwe = (struct fwe_softc *)xfer->sc;
384 	ifp = fwe->eth_softc.ifp;
385 	/* XXX error check */
386 	FWEDEBUG(ifp, "resp = %d\n", xfer->resp);
387 	if (xfer->resp != 0)
388 		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
389 	m_freem(xfer->mbuf);
390 	fw_xfer_unload(xfer);
391 
392 	FWE_LOCK(fwe);
393 	STAILQ_INSERT_TAIL(&fwe->xferlist, xfer, link);
394 	FWE_UNLOCK(fwe);
395 
396 	/* for queue full */
397 	if (!if_sendq_empty(ifp))
398 		fwe_start(ifp);
399 }
400 
401 static void
402 fwe_start(if_t ifp)
403 {
404 	struct fwe_softc *fwe = ((struct fwe_eth_softc *)if_getsoftc(ifp))->fwe;
405 
406 	FWEDEBUG(ifp, "starting\n");
407 
408 	if (fwe->dma_ch < 0) {
409 		FWEDEBUG(ifp, "not ready\n");
410 
411 		fw_net_drain_sendq(ifp);
412 
413 		return;
414 	}
415 
416 	if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0);
417 
418 	if (!if_sendq_empty(ifp))
419 		fwe_as_output(fwe, ifp);
420 
421 	if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE);
422 }
423 
424 #define HDR_LEN 4
425 #ifndef ETHER_ALIGN
426 #define ETHER_ALIGN 2
427 #endif
428 /* Async. stream output */
429 static void
430 fwe_as_output(struct fwe_softc *fwe, if_t ifp)
431 {
432 	struct mbuf *m;
433 	struct fw_xfer *xfer;
434 	struct fw_xferq *xferq;
435 	struct fw_pkt *fp;
436 	int i = 0;
437 
438 	xfer = NULL;
439 	xferq = fwe->fd.fc->atq;
440 	while ((xferq->queued < xferq->maxq - 1) &&
441 			!if_sendq_empty(ifp)) {
442 		FWE_LOCK(fwe);
443 		xfer = STAILQ_FIRST(&fwe->xferlist);
444 		if (xfer == NULL) {
445 #if 0
446 			printf("if_fwe: lack of xfer\n");
447 #endif
448 			FWE_UNLOCK(fwe);
449 			break;
450 		}
451 		STAILQ_REMOVE_HEAD(&fwe->xferlist, link);
452 		FWE_UNLOCK(fwe);
453 
454 		m = if_dequeue(ifp);
455 		if (m == NULL) {
456 			FWE_LOCK(fwe);
457 			STAILQ_INSERT_HEAD(&fwe->xferlist, xfer, link);
458 			FWE_UNLOCK(fwe);
459 			break;
460 		}
461 		BPF_MTAP(ifp, m);
462 
463 		/* keep ip packet alignment for alpha */
464 		M_PREPEND(m, ETHER_ALIGN, M_NOWAIT);
465 		fp = &xfer->send.hdr;
466 		*(uint32_t *)&xfer->send.hdr = *(int32_t *)&fwe->pkt_hdr;
467 		fp->mode.stream.len = m->m_pkthdr.len;
468 		xfer->mbuf = m;
469 		xfer->send.pay_len = m->m_pkthdr.len;
470 
471 		if (fw_asyreq(fwe->fd.fc, -1, xfer) != 0) {
472 			/* error */
473 			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
474 			/* XXX set error code */
475 			fwe_output_callback(xfer);
476 		} else {
477 			if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
478 			i++;
479 		}
480 	}
481 #if 0
482 	if (i > 1)
483 		printf("%d queued\n", i);
484 #endif
485 	if (i > 0)
486 		xferq->start(fwe->fd.fc);
487 }
488 
489 /* Async. stream output */
490 static void
491 fwe_as_input(struct fw_xferq *xferq)
492 {
493 	struct mbuf *m, *m0;
494 	if_t ifp;
495 	struct fwe_softc *fwe;
496 	struct fw_bulkxfer *sxfer;
497 	struct fw_pkt *fp;
498 	struct epoch_tracker et;
499 #if 0
500 	u_char *c;
501 #endif
502 
503 	fwe = (struct fwe_softc *)xferq->sc;
504 	ifp = fwe->eth_softc.ifp;
505 
506 	/* We do not need a lock here because the bottom half is serialized */
507 	while ((sxfer = STAILQ_FIRST(&xferq->stvalid)) != NULL) {
508 		STAILQ_REMOVE_HEAD(&xferq->stvalid, link);
509 		fp = mtod(sxfer->mbuf, struct fw_pkt *);
510 		if (fwe->fd.fc->irx_post != NULL)
511 			fwe->fd.fc->irx_post(fwe->fd.fc, fp->mode.ld);
512 		m = sxfer->mbuf;
513 
514 		/* insert new rbuf */
515 		sxfer->mbuf = m0 = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
516 		if (m0 != NULL) {
517 			m0->m_len = m0->m_pkthdr.len = m0->m_ext.ext_size;
518 			STAILQ_INSERT_TAIL(&xferq->stfree, sxfer, link);
519 		} else
520 			printf("%s: m_getcl failed\n", __FUNCTION__);
521 
522 		if (sxfer->resp != 0 || fp->mode.stream.len <
523 		    ETHER_ALIGN + sizeof(struct ether_header)) {
524 			m_freem(m);
525 			if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
526 			continue;
527 		}
528 
529 		m->m_data += HDR_LEN + ETHER_ALIGN;
530 #if 0
531 		c = mtod(m, u_char *);
532 #endif
533 		m->m_len = m->m_pkthdr.len = fp->mode.stream.len - ETHER_ALIGN;
534 		m->m_pkthdr.rcvif = ifp;
535 #if 0
536 		FWEDEBUG(ifp, "%02x %02x %02x %02x %02x %02x\n"
537 			 "%02x %02x %02x %02x %02x %02x\n"
538 			 "%02x %02x %02x %02x\n"
539 			 "%02x %02x %02x %02x\n"
540 			 "%02x %02x %02x %02x\n"
541 			 "%02x %02x %02x %02x\n",
542 			 c[0], c[1], c[2], c[3], c[4], c[5],
543 			 c[6], c[7], c[8], c[9], c[10], c[11],
544 			 c[12], c[13], c[14], c[15],
545 			 c[16], c[17], c[18], c[19],
546 			 c[20], c[21], c[22], c[23],
547 			 c[20], c[21], c[22], c[23]
548 		);
549 #endif
550 		NET_EPOCH_ENTER(et);
551 		if_input(ifp, m);
552 		NET_EPOCH_EXIT(et);
553 		if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
554 	}
555 	if (STAILQ_FIRST(&xferq->stfree) != NULL)
556 		fwe->fd.fc->irx_enable(fwe->fd.fc, fwe->dma_ch);
557 }
558 
559 
560 static device_method_t fwe_methods[] = {
561 	/* device interface */
562 	DEVMETHOD(device_identify,	fwe_identify),
563 	DEVMETHOD(device_probe,		fwe_probe),
564 	DEVMETHOD(device_attach,	fwe_attach),
565 	DEVMETHOD(device_detach,	fwe_detach),
566 	DEVMETHOD_END
567 };
568 
569 static driver_t fwe_driver = {
570         "fwe",
571 	fwe_methods,
572 	sizeof(struct fwe_softc),
573 };
574 
575 
576 DRIVER_MODULE(fwe, firewire, fwe_driver, 0, 0);
577 MODULE_VERSION(fwe, 1);
578 MODULE_DEPEND(fwe, firewire, 1, 1, 1);
579