2 * Copyright (c) 2002-2003
3 * Hidetoshi Shimokawa. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
16 * This product includes software developed by Hidetoshi Shimokawa.
18 * 4. Neither the name of the author nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * $FreeBSD: src/sys/dev/firewire/if_fwe.c,v 1.27 2004/01/08 14:58:09 simokawa Exp $
35 * $DragonFly: src/sys/dev/netif/fwe/if_fwe.c,v 1.31 2008/05/14 11:59:20 sephe Exp $
39 #include "opt_polling.h"
41 #include <sys/param.h>
43 #include <sys/kernel.h>
44 #include <sys/malloc.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>
52 #include <sys/thread2.h>
55 #include <net/ethernet.h>
57 #include <net/if_arp.h>
59 #include <net/ifq_var.h>
60 #include <net/vlan/if_vlan_var.h>
61 #include <bus/firewire/firewire.h>
62 #include <bus/firewire/firewirereg.h>
63 #include "if_fwevar.h"
65 #include <net/if_vlan_var.h>
67 #include <dev/firewire/firewire.h>
68 #include <dev/firewire/firewirereg.h>
69 #include <dev/firewire/if_fwevar.h>
72 #define FWEDEBUG if (fwedebug) if_printf
73 #define TX_MAX_QUEUE (FWMAXQUEUE - 1)
75 /* network interface */
76 static void fwe_start (struct ifnet
*);
77 static int fwe_ioctl (struct ifnet
*, u_long
, caddr_t
, struct ucred
*);
78 static void fwe_init (void *);
80 static void fwe_output_callback (struct fw_xfer
*);
81 static void fwe_as_output (struct fwe_softc
*, struct ifnet
*);
82 static void fwe_as_input (struct fw_xferq
*);
84 static int fwedebug
= 0;
85 static int stream_ch
= 1;
86 static int tx_speed
= 2;
87 static int rx_queue_len
= FWMAXQUEUE
;
89 MALLOC_DEFINE(M_FWE
, "if_fwe", "Ethernet over FireWire interface");
90 SYSCTL_INT(_debug
, OID_AUTO
, if_fwe_debug
, CTLFLAG_RW
, &fwedebug
, 0, "");
91 SYSCTL_DECL(_hw_firewire
);
92 SYSCTL_NODE(_hw_firewire
, OID_AUTO
, fwe
, CTLFLAG_RD
, 0,
93 "Ethernet emulation subsystem");
94 SYSCTL_INT(_hw_firewire_fwe
, OID_AUTO
, stream_ch
, CTLFLAG_RW
, &stream_ch
, 0,
95 "Stream channel to use");
96 SYSCTL_INT(_hw_firewire_fwe
, OID_AUTO
, tx_speed
, CTLFLAG_RW
, &tx_speed
, 0,
97 "Transmission speed");
98 SYSCTL_INT(_hw_firewire_fwe
, OID_AUTO
, rx_queue_len
, CTLFLAG_RW
, &rx_queue_len
,
99 0, "Length of the receive queue");
101 TUNABLE_INT("hw.firewire.fwe.stream_ch", &stream_ch
);
102 TUNABLE_INT("hw.firewire.fwe.tx_speed", &tx_speed
);
103 TUNABLE_INT("hw.firewire.fwe.rx_queue_len", &rx_queue_len
);
105 #ifdef DEVICE_POLLING
108 fwe_poll(struct ifnet
*ifp
, enum poll_cmd cmd
, int count
)
110 struct fwe_softc
*fwe
;
111 struct firewire_comm
*fc
;
113 fwe
= ((struct fwe_eth_softc
*)ifp
->if_softc
)->fwe
;
117 /* disable interrupts */
120 case POLL_DEREGISTER
:
121 /* enable interrupts */
125 fc
->poll(fc
, (cmd
== POLL_AND_CHECK_STATUS
)?0:1, count
);
133 fwe_probe(device_t dev
)
137 pa
= device_get_parent(dev
);
138 if(device_get_unit(dev
) != device_get_unit(pa
)){
142 device_set_desc(dev
, "Ethernet over FireWire");
147 fwe_attach(device_t dev
)
149 struct fwe_softc
*fwe
;
151 uint8_t eaddr
[ETHER_ADDR_LEN
];
152 struct fw_eui64
*eui
;
154 fwe
= ((struct fwe_softc
*)device_get_softc(dev
));
157 fwe
->stream_ch
= stream_ch
;
160 fwe
->fd
.fc
= device_get_ivars(dev
);
162 tx_speed
= fwe
->fd
.fc
->speed
;
165 fwe
->fd
.post_explore
= NULL
;
166 fwe
->eth_softc
.fwe
= fwe
;
168 fwe
->pkt_hdr
.mode
.stream
.tcode
= FWTCODE_STREAM
;
169 fwe
->pkt_hdr
.mode
.stream
.sy
= 0;
170 fwe
->pkt_hdr
.mode
.stream
.chtag
= fwe
->stream_ch
;
172 /* generate fake MAC address: first and last 3bytes from eui64 */
176 eui
= &fwe
->fd
.fc
->eui
;
177 eaddr
[0] = (FW_EUI64_BYTE(eui
, 0) | LOCAL
) & ~GROUP
;
178 eaddr
[1] = FW_EUI64_BYTE(eui
, 1);
179 eaddr
[2] = FW_EUI64_BYTE(eui
, 2);
180 eaddr
[3] = FW_EUI64_BYTE(eui
, 5);
181 eaddr
[4] = FW_EUI64_BYTE(eui
, 6);
182 eaddr
[5] = FW_EUI64_BYTE(eui
, 7);
184 /* fill the rest and attach interface */
186 ifp
->if_softc
= &fwe
->eth_softc
;
188 if_initname(ifp
, device_get_name(dev
), device_get_unit(dev
));
189 ifp
->if_init
= fwe_init
;
190 ifp
->if_start
= fwe_start
;
191 ifp
->if_ioctl
= fwe_ioctl
;
192 ifp
->if_capabilities
= IFCAP_VLAN_MTU
;
193 #ifdef DEVICE_POLLING
194 ifp
->if_poll
= fwe_poll
;
196 ifp
->if_mtu
= ETHERMTU
;
197 ifp
->if_flags
= (IFF_BROADCAST
|IFF_SIMPLEX
|IFF_MULTICAST
);
198 ifq_set_maxlen(&ifp
->if_snd
, TX_MAX_QUEUE
);
199 ifq_set_ready(&ifp
->if_snd
);
201 ether_ifattach(ifp
, eaddr
, NULL
);
203 /* Tell the upper layer(s) we support long frames. */
204 ifp
->if_data
.ifi_hdrlen
= sizeof(struct ether_vlan_header
);
207 FWEDEBUG(ifp
, "interface created\n");
212 fwe_stop(struct fwe_softc
*fwe
)
214 struct firewire_comm
*fc
;
215 struct fw_xferq
*xferq
;
216 struct ifnet
*ifp
= &fwe
->fwe_if
;
217 struct fw_xfer
*xfer
, *next
;
222 ifp
->if_flags
&= ~(IFF_RUNNING
| IFF_OACTIVE
);
224 if (fwe
->dma_ch
>= 0) {
225 xferq
= fc
->ir
[fwe
->dma_ch
];
227 if (xferq
->flag
& FWXFERQ_RUNNING
)
228 fc
->irx_disable(fc
, fwe
->dma_ch
);
230 ~(FWXFERQ_MODEMASK
| FWXFERQ_OPEN
| FWXFERQ_STREAM
|
231 FWXFERQ_EXTBUF
| FWXFERQ_HANDLER
| FWXFERQ_CHTAGMASK
);
234 for (i
= 0; i
< xferq
->bnchunk
; i
++)
235 m_freem(xferq
->bulkxfer
[i
].mbuf
);
236 kfree(xferq
->bulkxfer
, M_FWE
);
238 for (xfer
= STAILQ_FIRST(&fwe
->xferlist
); xfer
!= NULL
;
240 next
= STAILQ_NEXT(xfer
, link
);
243 STAILQ_INIT(&fwe
->xferlist
);
245 xferq
->bulkxfer
= NULL
;
251 fwe_detach(device_t dev
)
253 struct fwe_softc
*fwe
= device_get_softc(dev
);
255 lwkt_serialize_enter(fwe
->fwe_if
.if_serializer
);
257 lwkt_serialize_exit(fwe
->fwe_if
.if_serializer
);
259 ether_ifdetach(&fwe
->fwe_if
);
266 struct fwe_softc
*fwe
= ((struct fwe_eth_softc
*)arg
)->fwe
;
267 struct firewire_comm
*fc
;
268 struct ifnet
*ifp
= &fwe
->fwe_if
;
269 struct fw_xferq
*xferq
;
270 struct fw_xfer
*xfer
;
274 FWEDEBUG(ifp
, "initializing\n");
276 /* XXX keep promiscoud mode */
277 ifp
->if_flags
|= IFF_PROMISC
;
281 if (fwe
->dma_ch
< 0) {
282 for (i
= START
; i
< fc
->nisodma
; i
++) {
284 if ((xferq
->flag
& FWXFERQ_OPEN
) == 0)
287 if_printf(ifp
, "no free dma channel\n");
291 fwe
->stream_ch
= stream_ch
;
292 fwe
->pkt_hdr
.mode
.stream
.chtag
= fwe
->stream_ch
;
293 /* allocate DMA channel and init packet mode */
294 xferq
->flag
|= FWXFERQ_OPEN
| FWXFERQ_EXTBUF
|
295 FWXFERQ_HANDLER
| FWXFERQ_STREAM
;
296 xferq
->flag
&= ~0xff;
297 xferq
->flag
|= fwe
->stream_ch
& 0xff;
298 /* register fwe_input handler */
299 xferq
->sc
= (caddr_t
) fwe
;
300 xferq
->hand
= fwe_as_input
;
301 xferq
->bnchunk
= rx_queue_len
;
303 xferq
->psize
= MCLBYTES
;
306 xferq
->bulkxfer
= (struct fw_bulkxfer
*) kmalloc(
307 sizeof(struct fw_bulkxfer
) * xferq
->bnchunk
,
309 STAILQ_INIT(&xferq
->stvalid
);
310 STAILQ_INIT(&xferq
->stfree
);
311 STAILQ_INIT(&xferq
->stdma
);
312 xferq
->stproc
= NULL
;
313 for (i
= 0; i
< xferq
->bnchunk
; i
++) {
314 m
= m_getcl(MB_WAIT
, MT_DATA
, M_PKTHDR
);
315 xferq
->bulkxfer
[i
].mbuf
= m
;
317 m
->m_len
= m
->m_pkthdr
.len
= m
->m_ext
.ext_size
;
318 STAILQ_INSERT_TAIL(&xferq
->stfree
,
319 &xferq
->bulkxfer
[i
], link
);
321 if_printf(ifp
, "fwe_init: m_getcl failed\n");
324 STAILQ_INIT(&fwe
->xferlist
);
325 for (i
= 0; i
< TX_MAX_QUEUE
; i
++) {
326 xfer
= fw_xfer_alloc(M_FWE
);
329 xfer
->send
.spd
= tx_speed
;
330 xfer
->fc
= fwe
->fd
.fc
;
331 xfer
->retry_req
= fw_asybusy
;
332 xfer
->sc
= (caddr_t
)fwe
;
333 xfer
->act
.hand
= fwe_output_callback
;
334 STAILQ_INSERT_TAIL(&fwe
->xferlist
, xfer
, link
);
337 xferq
= fc
->ir
[fwe
->dma_ch
];
339 #ifdef DEVICE_POLLING
340 /* Disable interrupt, if polling(4) is enabled */
341 if (ifp
->if_flags
& IFF_POLLING
)
348 if ((xferq
->flag
& FWXFERQ_RUNNING
) == 0)
349 fc
->irx_enable(fc
, fwe
->dma_ch
);
351 ifp
->if_flags
|= IFF_RUNNING
;
352 ifp
->if_flags
&= ~IFF_OACTIVE
;
357 fwe_ioctl(struct ifnet
*ifp
, u_long cmd
, caddr_t data
, struct ucred
*cr
)
359 struct fwe_softc
*fwe
= ((struct fwe_eth_softc
*)ifp
->if_softc
)->fwe
;
360 struct ifstat
*ifs
= NULL
;
365 if (ifp
->if_flags
& IFF_UP
) {
366 if (!(ifp
->if_flags
& IFF_RUNNING
))
367 fwe_init(&fwe
->eth_softc
);
369 if (ifp
->if_flags
& IFF_RUNNING
)
372 /* XXX keep promiscoud mode */
373 ifp
->if_flags
|= IFF_PROMISC
;
380 ifs
= (struct ifstat
*)data
;
381 len
= strlen(ifs
->ascii
);
382 if (len
< sizeof(ifs
->ascii
))
383 ksnprintf(ifs
->ascii
+ len
,
384 sizeof(ifs
->ascii
) - len
,
386 fwe
->stream_ch
, fwe
->dma_ch
);
389 error
= ether_ioctl(ifp
, cmd
, data
);
396 fwe_output_callback(struct fw_xfer
*xfer
)
398 struct fwe_softc
*fwe
;
401 fwe
= (struct fwe_softc
*)xfer
->sc
;
403 lwkt_serialize_enter(ifp
->if_serializer
);
404 /* XXX error check */
405 FWEDEBUG(ifp
, "resp = %d\n", xfer
->resp
);
410 fw_xfer_unload(xfer
);
412 STAILQ_INSERT_TAIL(&fwe
->xferlist
, xfer
, link
);
415 if (!ifq_is_empty(&ifp
->if_snd
))
417 lwkt_serialize_exit(ifp
->if_serializer
);
421 fwe_start(struct ifnet
*ifp
)
423 struct fwe_softc
*fwe
= ((struct fwe_eth_softc
*)ifp
->if_softc
)->fwe
;
425 FWEDEBUG(ifp
, "starting\n");
427 if (fwe
->dma_ch
< 0) {
428 FWEDEBUG(ifp
, "not ready\n");
430 ifq_purge(&ifp
->if_snd
);
432 ifp
->if_flags
|= IFF_OACTIVE
;
434 if (!ifq_is_empty(&ifp
->if_snd
))
435 fwe_as_output(fwe
, ifp
);
437 ifp
->if_flags
&= ~IFF_OACTIVE
;
443 #define ETHER_ALIGN 2
445 /* Async. stream output */
447 fwe_as_output(struct fwe_softc
*fwe
, struct ifnet
*ifp
)
450 struct fw_xfer
*xfer
;
451 struct fw_xferq
*xferq
;
456 xferq
= fwe
->fd
.fc
->atq
;
457 while (xferq
->queued
< xferq
->maxq
- 1) {
458 xfer
= STAILQ_FIRST(&fwe
->xferlist
);
460 if_printf(ifp
, "lack of xfer\n");
463 m
= ifq_dequeue(&ifp
->if_snd
, NULL
);
466 STAILQ_REMOVE_HEAD(&fwe
->xferlist
, link
);
469 /* keep ip packet alignment for alpha */
470 M_PREPEND(m
, ETHER_ALIGN
, MB_DONTWAIT
);
471 fp
= &xfer
->send
.hdr
;
472 *(u_int32_t
*)&xfer
->send
.hdr
= *(int32_t *)&fwe
->pkt_hdr
;
473 fp
->mode
.stream
.len
= m
->m_pkthdr
.len
;
475 xfer
->send
.pay_len
= m
->m_pkthdr
.len
;
477 if (fw_asyreq(fwe
->fd
.fc
, -1, xfer
) != 0) {
480 /* XXX set error code */
481 fwe_output_callback(xfer
);
489 if_printf(ifp
, "%d queued\n", i
);
492 xferq
->start(fwe
->fd
.fc
);
495 /* Async. stream output */
497 fwe_as_input(struct fw_xferq
*xferq
)
501 struct fwe_softc
*fwe
;
502 struct fw_bulkxfer
*sxfer
;
506 fwe
= (struct fwe_softc
*)xferq
->sc
;
508 lwkt_serialize_enter(ifp
->if_serializer
);
509 while ((sxfer
= STAILQ_FIRST(&xferq
->stvalid
)) != NULL
) {
510 STAILQ_REMOVE_HEAD(&xferq
->stvalid
, link
);
511 fp
= mtod(sxfer
->mbuf
, struct fw_pkt
*);
512 if (fwe
->fd
.fc
->irx_post
!= NULL
)
513 fwe
->fd
.fc
->irx_post(fwe
->fd
.fc
, fp
->mode
.ld
);
516 /* insert new rbuf */
517 sxfer
->mbuf
= m0
= m_getcl(MB_DONTWAIT
, MT_DATA
, M_PKTHDR
);
519 m0
->m_len
= m0
->m_pkthdr
.len
= m0
->m_ext
.ext_size
;
520 STAILQ_INSERT_TAIL(&xferq
->stfree
, sxfer
, link
);
522 if_printf(ifp
, "fwe_as_input: m_getcl failed\n");
525 if (sxfer
->resp
!= 0 || fp
->mode
.stream
.len
<
526 ETHER_ALIGN
+ sizeof(struct ether_header
)) {
532 m
->m_data
+= HDR_LEN
+ ETHER_ALIGN
;
534 m
->m_len
= m
->m_pkthdr
.len
=
535 fp
->mode
.stream
.len
- ETHER_ALIGN
;
536 m
->m_pkthdr
.rcvif
= ifp
;
538 FWEDEBUG(ifp
, "%02x %02x %02x %02x %02x %02x\n"
539 "%02x %02x %02x %02x %02x %02x\n"
540 "%02x %02x %02x %02x\n"
541 "%02x %02x %02x %02x\n"
542 "%02x %02x %02x %02x\n"
543 "%02x %02x %02x %02x\n",
544 c
[0], c
[1], c
[2], c
[3], c
[4], c
[5],
545 c
[6], c
[7], c
[8], c
[9], c
[10], c
[11],
546 c
[12], c
[13], c
[14], c
[15],
547 c
[16], c
[17], c
[18], c
[19],
548 c
[20], c
[21], c
[22], c
[23],
549 c
[20], c
[21], c
[22], c
[23]
552 ifp
->if_input(ifp
, m
);
555 if (STAILQ_FIRST(&xferq
->stfree
) != NULL
)
556 fwe
->fd
.fc
->irx_enable(fwe
->fd
.fc
, fwe
->dma_ch
);
557 lwkt_serialize_exit(ifp
->if_serializer
);
561 static devclass_t fwe_devclass
;
564 * Because fwe is a static device that always exists under any attached
565 * firewire device, and not scanned by the firewire device, we need an
566 * identify function to install the device.
568 static device_method_t fwe_methods
[] = {
569 /* device interface */
570 DEVMETHOD(device_identify
, bus_generic_identify_sameunit
),
571 DEVMETHOD(device_probe
, fwe_probe
),
572 DEVMETHOD(device_attach
, fwe_attach
),
573 DEVMETHOD(device_detach
, fwe_detach
),
577 static driver_t fwe_driver
= {
580 sizeof(struct fwe_softc
),
584 DECLARE_DUMMY_MODULE(fwe
);
585 DRIVER_MODULE(fwe
, firewire
, fwe_driver
, fwe_devclass
, 0, 0);
586 MODULE_VERSION(fwe
, 1);
587 MODULE_DEPEND(fwe
, firewire
, 1, 1, 1);