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
fwe_poll(if_t ifp,enum poll_cmd cmd,int count)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
fwe_identify(driver_t * driver,device_t parent)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
fwe_probe(device_t dev)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
fwe_attach(device_t dev)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
fwe_stop(struct fwe_softc * fwe)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
fwe_detach(device_t dev)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
fwe_init(void * arg)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
fwe_ioctl(if_t ifp,u_long cmd,caddr_t data)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
fwe_output_callback(struct fw_xfer * xfer)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
fwe_start(if_t ifp)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
fwe_as_output(struct fwe_softc * fwe,if_t ifp)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
fwe_as_input(struct fw_xferq * xferq)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