if_fwe.c revision 167630
1351280Sdim/*-
2351280Sdim * Copyright (c) 2002-2003
3351280Sdim * 	Hidetoshi Shimokawa. All rights reserved.
4351280Sdim *
5351280Sdim * Redistribution and use in source and binary forms, with or without
6351280Sdim * modification, are permitted provided that the following conditions
7351280Sdim * are met:
8351280Sdim * 1. Redistributions of source code must retain the above copyright
9351280Sdim *    notice, this list of conditions and the following disclaimer.
10351280Sdim * 2. Redistributions in binary form must reproduce the above copyright
11351280Sdim *    notice, this list of conditions and the following disclaimer in the
12351280Sdim *    documentation and/or other materials provided with the distribution.
13351280Sdim * 3. All advertising materials mentioning features or use of this software
14351280Sdim *    must display the following acknowledgement:
15351280Sdim *
16351280Sdim *	This product includes software developed by Hidetoshi Shimokawa.
17351280Sdim *
18351280Sdim * 4. Neither the name of the author nor the names of its contributors
19351280Sdim *    may be used to endorse or promote products derived from this software
20351280Sdim *    without specific prior written permission.
21351280Sdim *
22351280Sdim * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23351280Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24351280Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25351280Sdim * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26351280Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27351280Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28351280Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29351280Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30351280Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31351280Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32351280Sdim * SUCH DAMAGE.
33351280Sdim *
34351280Sdim * $FreeBSD: head/sys/dev/firewire/if_fwe.c 167630 2007-03-16 05:11:42Z simokawa $
35351280Sdim */
36351280Sdim
37351280Sdim#ifdef HAVE_KERNEL_OPTION_HEADERS
38351280Sdim#include "opt_device_polling.h"
39351280Sdim#include "opt_inet.h"
40351280Sdim#endif
41351280Sdim
42351280Sdim#include <sys/param.h>
43351280Sdim#include <sys/kernel.h>
44351280Sdim#include <sys/malloc.h>
45351280Sdim#include <sys/mbuf.h>
46351280Sdim#include <sys/socket.h>
47351280Sdim#include <sys/sockio.h>
48351280Sdim#include <sys/sysctl.h>
49351280Sdim#include <sys/systm.h>
50351280Sdim#include <sys/module.h>
51351280Sdim#include <sys/bus.h>
52351280Sdim#include <machine/bus.h>
53351280Sdim
54351280Sdim#include <net/bpf.h>
55351280Sdim#include <net/ethernet.h>
56351280Sdim#include <net/if.h>
57351280Sdim#include <net/if_arp.h>
58351280Sdim#include <net/if_types.h>
59351280Sdim#ifdef __DragonFly__
60351280Sdim#include <net/vlan/if_vlan_var.h>
61351280Sdim#include <bus/firewire/firewire.h>
62351280Sdim#include <bus/firewire/firewirereg.h>
63351280Sdim#include "if_fwevar.h"
64351280Sdim#else
65351280Sdim#include <net/if_vlan_var.h>
66351280Sdim
67351280Sdim#include <dev/firewire/firewire.h>
68351280Sdim#include <dev/firewire/firewirereg.h>
69351280Sdim#include <dev/firewire/if_fwevar.h>
70351280Sdim#endif
71351280Sdim
72351280Sdim#define FWEDEBUG	if (fwedebug) if_printf
73351280Sdim#define TX_MAX_QUEUE	(FWMAXQUEUE - 1)
74351280Sdim
75351280Sdim/* network interface */
76351280Sdimstatic void fwe_start (struct ifnet *);
77351280Sdimstatic int fwe_ioctl (struct ifnet *, u_long, caddr_t);
78351280Sdimstatic void fwe_init (void *);
79351280Sdim
80351280Sdimstatic void fwe_output_callback (struct fw_xfer *);
81351280Sdimstatic void fwe_as_output (struct fwe_softc *, struct ifnet *);
82351280Sdimstatic void fwe_as_input (struct fw_xferq *);
83351280Sdim
84351280Sdimstatic int fwedebug = 0;
85351280Sdimstatic int stream_ch = 1;
86351280Sdimstatic int tx_speed = 2;
87351280Sdimstatic int rx_queue_len = FWMAXQUEUE;
88351280Sdim
89351280SdimMALLOC_DEFINE(M_FWE, "if_fwe", "Ethernet over FireWire interface");
90351280SdimSYSCTL_INT(_debug, OID_AUTO, if_fwe_debug, CTLFLAG_RW, &fwedebug, 0, "");
91351280SdimSYSCTL_DECL(_hw_firewire);
92351280SdimSYSCTL_NODE(_hw_firewire, OID_AUTO, fwe, CTLFLAG_RD, 0,
93351280Sdim	"Ethernet emulation subsystem");
94351280SdimSYSCTL_INT(_hw_firewire_fwe, OID_AUTO, stream_ch, CTLFLAG_RW, &stream_ch, 0,
95351280Sdim	"Stream channel to use");
96351280SdimSYSCTL_INT(_hw_firewire_fwe, OID_AUTO, tx_speed, CTLFLAG_RW, &tx_speed, 0,
97351280Sdim	"Transmission speed");
98351280SdimSYSCTL_INT(_hw_firewire_fwe, OID_AUTO, rx_queue_len, CTLFLAG_RW, &rx_queue_len,
99351280Sdim	0, "Length of the receive queue");
100351280Sdim
101351280SdimTUNABLE_INT("hw.firewire.fwe.stream_ch", &stream_ch);
102351280SdimTUNABLE_INT("hw.firewire.fwe.tx_speed", &tx_speed);
103351280SdimTUNABLE_INT("hw.firewire.fwe.rx_queue_len", &rx_queue_len);
104351280Sdim
105351280Sdim#ifdef DEVICE_POLLING
106351280Sdimstatic poll_handler_t fwe_poll;
107351280Sdim
108351280Sdimstatic void
109351280Sdimfwe_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
110351280Sdim{
111351280Sdim	struct fwe_softc *fwe;
112351280Sdim	struct firewire_comm *fc;
113351280Sdim
114351280Sdim	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
115351280Sdim		return;
116351280Sdim
117351280Sdim	fwe = ((struct fwe_eth_softc *)ifp->if_softc)->fwe;
118351280Sdim	fc = fwe->fd.fc;
119351280Sdim	fc->poll(fc, (cmd == POLL_AND_CHECK_STATUS)?0:1, count);
120351280Sdim}
121351280Sdim#endif /* DEVICE_POLLING */
122351280Sdim
123351280Sdimstatic void
124351280Sdimfwe_identify(driver_t *driver, device_t parent)
125351280Sdim{
126351280Sdim	BUS_ADD_CHILD(parent, 0, "fwe", device_get_unit(parent));
127351280Sdim}
128351280Sdim
129351280Sdimstatic int
130351280Sdimfwe_probe(device_t dev)
131351280Sdim{
132351280Sdim	device_t pa;
133351280Sdim
134351280Sdim	pa = device_get_parent(dev);
135351280Sdim	if(device_get_unit(dev) != device_get_unit(pa)){
136351280Sdim		return(ENXIO);
137351280Sdim	}
138351280Sdim
139351280Sdim	device_set_desc(dev, "Ethernet over FireWire");
140351280Sdim	return (0);
141351280Sdim}
142351280Sdim
143351280Sdimstatic int
144351280Sdimfwe_attach(device_t dev)
145351280Sdim{
146351280Sdim	struct fwe_softc *fwe;
147351280Sdim	struct ifnet *ifp;
148351280Sdim	int unit, s;
149351280Sdim#if defined(__DragonFly__) || __FreeBSD_version < 500000
150351280Sdim	u_char *eaddr;
151351280Sdim#else
152351280Sdim	u_char eaddr[6];
153351280Sdim#endif
154351280Sdim	struct fw_eui64 *eui;
155351280Sdim
156351280Sdim	fwe = ((struct fwe_softc *)device_get_softc(dev));
157351280Sdim	unit = device_get_unit(dev);
158351280Sdim
159351280Sdim	bzero(fwe, sizeof(struct fwe_softc));
160351280Sdim	/* XXX */
161351280Sdim	fwe->stream_ch = stream_ch;
162351280Sdim	fwe->dma_ch = -1;
163351280Sdim
164351280Sdim	fwe->fd.fc = device_get_ivars(dev);
165351280Sdim	if (tx_speed < 0)
166351280Sdim		tx_speed = fwe->fd.fc->speed;
167351280Sdim
168351280Sdim	fwe->fd.dev = dev;
169351280Sdim	fwe->fd.post_explore = NULL;
170351280Sdim	fwe->eth_softc.fwe = fwe;
171351280Sdim
172351280Sdim	fwe->pkt_hdr.mode.stream.tcode = FWTCODE_STREAM;
173351280Sdim	fwe->pkt_hdr.mode.stream.sy = 0;
174351280Sdim	fwe->pkt_hdr.mode.stream.chtag = fwe->stream_ch;
175351280Sdim
176351280Sdim	/* generate fake MAC address: first and last 3bytes from eui64 */
177351280Sdim#define LOCAL (0x02)
178351280Sdim#define GROUP (0x01)
179351280Sdim#if defined(__DragonFly__) || __FreeBSD_version < 500000
180351280Sdim	eaddr = &IFP2ENADDR(fwe->eth_softc.ifp)[0];
181351280Sdim#endif
182351280Sdim
183351280Sdim
184351280Sdim	eui = &fwe->fd.fc->eui;
185351280Sdim	eaddr[0] = (FW_EUI64_BYTE(eui, 0) | LOCAL) & ~GROUP;
186351280Sdim	eaddr[1] = FW_EUI64_BYTE(eui, 1);
187351280Sdim	eaddr[2] = FW_EUI64_BYTE(eui, 2);
188351280Sdim	eaddr[3] = FW_EUI64_BYTE(eui, 5);
189351280Sdim	eaddr[4] = FW_EUI64_BYTE(eui, 6);
190351280Sdim	eaddr[5] = FW_EUI64_BYTE(eui, 7);
191351280Sdim	printf("if_fwe%d: Fake Ethernet address: "
192351280Sdim		"%02x:%02x:%02x:%02x:%02x:%02x\n", unit,
193351280Sdim		eaddr[0], eaddr[1], eaddr[2], eaddr[3], eaddr[4], eaddr[5]);
194351280Sdim
195351280Sdim	/* fill the rest and attach interface */
196351280Sdim	ifp = fwe->eth_softc.ifp = if_alloc(IFT_ETHER);
197351280Sdim	if (ifp == NULL) {
198351280Sdim		device_printf(dev, "can not if_alloc()\n");
199351280Sdim		return (ENOSPC);
200351280Sdim	}
201351280Sdim	ifp->if_softc = &fwe->eth_softc;
202351280Sdim
203351280Sdim#if __FreeBSD_version >= 501113 || defined(__DragonFly__)
204351280Sdim	if_initname(ifp, device_get_name(dev), unit);
205351280Sdim#else
206351280Sdim	ifp->if_unit = unit;
207351280Sdim	ifp->if_name = "fwe";
208351280Sdim#endif
209351280Sdim	ifp->if_init = fwe_init;
210351280Sdim#if defined(__DragonFly__) || __FreeBSD_version < 500000
211351280Sdim	ifp->if_output = ether_output;
212351280Sdim#endif
213351280Sdim	ifp->if_start = fwe_start;
214351280Sdim	ifp->if_ioctl = fwe_ioctl;
215351280Sdim	ifp->if_mtu = ETHERMTU;
216351280Sdim	ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST|
217351280Sdim	    IFF_NEEDSGIANT);
218351280Sdim	ifp->if_snd.ifq_maxlen = TX_MAX_QUEUE;
219351280Sdim
220351280Sdim	s = splimp();
221351280Sdim#if defined(__DragonFly__) || __FreeBSD_version < 500000
222351280Sdim	ether_ifattach(ifp, 1);
223351280Sdim#else
224351280Sdim	ether_ifattach(ifp, eaddr);
225351280Sdim#endif
226351280Sdim	splx(s);
227351280Sdim
228351280Sdim        /* Tell the upper layer(s) we support long frames. */
229351280Sdim	ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header);
230351280Sdim#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
231351280Sdim	ifp->if_capabilities |= IFCAP_VLAN_MTU | IFCAP_POLLING;
232351280Sdim	ifp->if_capenable |= IFCAP_VLAN_MTU;
233351280Sdim#endif
234351280Sdim
235351280Sdim
236351280Sdim	FWEDEBUG(ifp, "interface created\n");
237351280Sdim	return 0;
238351280Sdim}
239351280Sdim
240351280Sdimstatic void
241351280Sdimfwe_stop(struct fwe_softc *fwe)
242351280Sdim{
243351280Sdim	struct firewire_comm *fc;
244351280Sdim	struct fw_xferq *xferq;
245351280Sdim	struct ifnet *ifp = fwe->eth_softc.ifp;
246351280Sdim	struct fw_xfer *xfer, *next;
247351280Sdim	int i;
248351280Sdim
249351280Sdim	fc = fwe->fd.fc;
250351280Sdim
251351280Sdim	if (fwe->dma_ch >= 0) {
252351280Sdim		xferq = fc->ir[fwe->dma_ch];
253351280Sdim
254351280Sdim		if (xferq->flag & FWXFERQ_RUNNING)
255351280Sdim			fc->irx_disable(fc, fwe->dma_ch);
256351280Sdim		xferq->flag &=
257351280Sdim			~(FWXFERQ_MODEMASK | FWXFERQ_OPEN | FWXFERQ_STREAM |
258351280Sdim			FWXFERQ_EXTBUF | FWXFERQ_HANDLER | FWXFERQ_CHTAGMASK);
259351280Sdim		xferq->hand =  NULL;
260351280Sdim
261351280Sdim		for (i = 0; i < xferq->bnchunk; i ++)
262351280Sdim			m_freem(xferq->bulkxfer[i].mbuf);
263351280Sdim		free(xferq->bulkxfer, M_FWE);
264351280Sdim
265351280Sdim		for (xfer = STAILQ_FIRST(&fwe->xferlist); xfer != NULL;
266351280Sdim					xfer = next) {
267351280Sdim			next = STAILQ_NEXT(xfer, link);
268351280Sdim			fw_xfer_free(xfer);
269351280Sdim		}
270351280Sdim		STAILQ_INIT(&fwe->xferlist);
271351280Sdim
272351280Sdim		xferq->bulkxfer =  NULL;
273351280Sdim		fwe->dma_ch = -1;
274351280Sdim	}
275351280Sdim
276351280Sdim#if defined(__FreeBSD__)
277351280Sdim	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
278351280Sdim#else
279351280Sdim	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
280#endif
281}
282
283static int
284fwe_detach(device_t dev)
285{
286	struct fwe_softc *fwe;
287	struct ifnet *ifp;
288	int s;
289
290	fwe = device_get_softc(dev);
291	ifp = fwe->eth_softc.ifp;
292
293#ifdef DEVICE_POLLING
294	if (ifp->if_capenable & IFCAP_POLLING)
295		ether_poll_deregister(ifp);
296#endif
297	s = splimp();
298
299	fwe_stop(fwe);
300#if defined(__DragonFly__) || __FreeBSD_version < 500000
301	ether_ifdetach(ifp, 1);
302#else
303	ether_ifdetach(ifp);
304	if_free(ifp);
305#endif
306
307	splx(s);
308	return 0;
309}
310
311static void
312fwe_init(void *arg)
313{
314	struct fwe_softc *fwe = ((struct fwe_eth_softc *)arg)->fwe;
315	struct firewire_comm *fc;
316	struct ifnet *ifp = fwe->eth_softc.ifp;
317	struct fw_xferq *xferq;
318	struct fw_xfer *xfer;
319	struct mbuf *m;
320	int i;
321
322	FWEDEBUG(ifp, "initializing\n");
323
324	/* XXX keep promiscoud mode */
325	ifp->if_flags |= IFF_PROMISC;
326
327	fc = fwe->fd.fc;
328#define START 0
329	if (fwe->dma_ch < 0) {
330		for (i = START; i < fc->nisodma; i ++) {
331			xferq = fc->ir[i];
332			if ((xferq->flag & FWXFERQ_OPEN) == 0)
333				goto found;
334		}
335		printf("no free dma channel\n");
336		return;
337found:
338		fwe->dma_ch = i;
339		fwe->stream_ch = stream_ch;
340		fwe->pkt_hdr.mode.stream.chtag = fwe->stream_ch;
341		/* allocate DMA channel and init packet mode */
342		xferq->flag |= FWXFERQ_OPEN | FWXFERQ_EXTBUF |
343				FWXFERQ_HANDLER | FWXFERQ_STREAM;
344		xferq->flag &= ~0xff;
345		xferq->flag |= fwe->stream_ch & 0xff;
346		/* register fwe_input handler */
347		xferq->sc = (caddr_t) fwe;
348		xferq->hand = fwe_as_input;
349		xferq->bnchunk = rx_queue_len;
350		xferq->bnpacket = 1;
351		xferq->psize = MCLBYTES;
352		xferq->queued = 0;
353		xferq->buf = NULL;
354		xferq->bulkxfer = (struct fw_bulkxfer *) malloc(
355			sizeof(struct fw_bulkxfer) * xferq->bnchunk,
356							M_FWE, M_WAITOK);
357		if (xferq->bulkxfer == NULL) {
358			printf("if_fwe: malloc failed\n");
359			return;
360		}
361		STAILQ_INIT(&xferq->stvalid);
362		STAILQ_INIT(&xferq->stfree);
363		STAILQ_INIT(&xferq->stdma);
364		xferq->stproc = NULL;
365		for (i = 0; i < xferq->bnchunk; i ++) {
366			m =
367#if defined(__DragonFly__) || __FreeBSD_version < 500000
368				m_getcl(M_WAIT, MT_DATA, M_PKTHDR);
369#else
370				m_getcl(M_TRYWAIT, MT_DATA, M_PKTHDR);
371#endif
372			xferq->bulkxfer[i].mbuf = m;
373			if (m != NULL) {
374				m->m_len = m->m_pkthdr.len = m->m_ext.ext_size;
375				STAILQ_INSERT_TAIL(&xferq->stfree,
376						&xferq->bulkxfer[i], link);
377			} else
378				printf("fwe_as_input: m_getcl failed\n");
379		}
380		STAILQ_INIT(&fwe->xferlist);
381		for (i = 0; i < TX_MAX_QUEUE; i++) {
382			xfer = fw_xfer_alloc(M_FWE);
383			if (xfer == NULL)
384				break;
385			xfer->send.spd = tx_speed;
386			xfer->fc = fwe->fd.fc;
387			xfer->sc = (caddr_t)fwe;
388			xfer->act.hand = fwe_output_callback;
389			STAILQ_INSERT_TAIL(&fwe->xferlist, xfer, link);
390		}
391	} else
392		xferq = fc->ir[fwe->dma_ch];
393
394
395	/* start dma */
396	if ((xferq->flag & FWXFERQ_RUNNING) == 0)
397		fc->irx_enable(fc, fwe->dma_ch);
398
399#if defined(__FreeBSD__)
400	ifp->if_drv_flags |= IFF_DRV_RUNNING;
401	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
402#else
403	ifp->if_flags |= IFF_RUNNING;
404	ifp->if_flags &= ~IFF_OACTIVE;
405#endif
406
407#if 0
408	/* attempt to start output */
409	fwe_start(ifp);
410#endif
411}
412
413
414static int
415fwe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
416{
417	struct fwe_softc *fwe = ((struct fwe_eth_softc *)ifp->if_softc)->fwe;
418	struct ifstat *ifs = NULL;
419	int s, error, len;
420
421	switch (cmd) {
422		case SIOCSIFFLAGS:
423			s = splimp();
424			if (ifp->if_flags & IFF_UP) {
425#if defined(__FreeBSD__)
426				if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
427#else
428				if (!(ifp->if_flags & IFF_RUNNING))
429#endif
430					fwe_init(&fwe->eth_softc);
431			} else {
432#if defined(__FreeBSD__)
433				if (ifp->if_drv_flags & IFF_DRV_RUNNING)
434#else
435				if (ifp->if_flags & IFF_RUNNING)
436#endif
437					fwe_stop(fwe);
438			}
439			/* XXX keep promiscoud mode */
440			ifp->if_flags |= IFF_PROMISC;
441			splx(s);
442			break;
443		case SIOCADDMULTI:
444		case SIOCDELMULTI:
445			break;
446
447		case SIOCGIFSTATUS:
448			s = splimp();
449			ifs = (struct ifstat *)data;
450			len = strlen(ifs->ascii);
451			if (len < sizeof(ifs->ascii))
452				snprintf(ifs->ascii + len,
453					sizeof(ifs->ascii) - len,
454					"\tch %d dma %d\n",
455						fwe->stream_ch, fwe->dma_ch);
456			splx(s);
457			break;
458		case SIOCSIFCAP:
459#ifdef DEVICE_POLLING
460		    {
461			struct ifreq *ifr = (struct ifreq *) data;
462			struct firewire_comm *fc = fc = fwe->fd.fc;
463
464			if (ifr->ifr_reqcap & IFCAP_POLLING &&
465			    !(ifp->if_capenable & IFCAP_POLLING)) {
466				error = ether_poll_register(fwe_poll, ifp);
467				if (error)
468					return(error);
469				/* Disable interrupts */
470				fc->set_intr(fc, 0);
471				ifp->if_capenable |= IFCAP_POLLING;
472				return (error);
473			}
474			if (!(ifr->ifr_reqcap & IFCAP_POLLING) &&
475			    ifp->if_capenable & IFCAP_POLLING) {
476				error = ether_poll_deregister(ifp);
477				/* Enable interrupts. */
478				fc->set_intr(fc, 1);
479				ifp->if_capenable &= ~IFCAP_POLLING;
480				return (error);
481			}
482		    }
483#endif /* DEVICE_POLLING */
484			break;
485#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
486		default:
487#else
488		case SIOCSIFADDR:
489		case SIOCGIFADDR:
490		case SIOCSIFMTU:
491#endif
492			s = splimp();
493			error = ether_ioctl(ifp, cmd, data);
494			splx(s);
495			return (error);
496#if defined(__DragonFly__) || __FreeBSD_version < 500000
497		default:
498			return (EINVAL);
499#endif
500	}
501
502	return (0);
503}
504
505static void
506fwe_output_callback(struct fw_xfer *xfer)
507{
508	struct fwe_softc *fwe;
509	struct ifnet *ifp;
510	int s;
511
512	fwe = (struct fwe_softc *)xfer->sc;
513	ifp = fwe->eth_softc.ifp;
514	/* XXX error check */
515	FWEDEBUG(ifp, "resp = %d\n", xfer->resp);
516	if (xfer->resp != 0)
517		ifp->if_oerrors ++;
518
519	m_freem(xfer->mbuf);
520	fw_xfer_unload(xfer);
521
522	s = splimp();
523	STAILQ_INSERT_TAIL(&fwe->xferlist, xfer, link);
524	splx(s);
525
526	/* for queue full */
527	if (ifp->if_snd.ifq_head != NULL)
528		fwe_start(ifp);
529}
530
531static void
532fwe_start(struct ifnet *ifp)
533{
534	struct fwe_softc *fwe = ((struct fwe_eth_softc *)ifp->if_softc)->fwe;
535	int s;
536
537	GIANT_REQUIRED;
538
539	FWEDEBUG(ifp, "starting\n");
540
541	if (fwe->dma_ch < 0) {
542		struct mbuf	*m = NULL;
543
544		FWEDEBUG(ifp, "not ready\n");
545
546		s = splimp();
547		do {
548			IF_DEQUEUE(&ifp->if_snd, m);
549			if (m != NULL)
550				m_freem(m);
551			ifp->if_oerrors ++;
552		} while (m != NULL);
553		splx(s);
554
555		return;
556	}
557
558	s = splimp();
559#if defined(__FreeBSD__)
560	ifp->if_drv_flags |= IFF_DRV_OACTIVE;
561#else
562	ifp->if_flags |= IFF_OACTIVE;
563#endif
564
565	if (ifp->if_snd.ifq_len != 0)
566		fwe_as_output(fwe, ifp);
567
568#if defined(__FreeBSD__)
569	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
570#else
571	ifp->if_flags &= ~IFF_OACTIVE;
572#endif
573	splx(s);
574}
575
576#define HDR_LEN 4
577#ifndef ETHER_ALIGN
578#define ETHER_ALIGN 2
579#endif
580/* Async. stream output */
581static void
582fwe_as_output(struct fwe_softc *fwe, struct ifnet *ifp)
583{
584	struct mbuf *m;
585	struct fw_xfer *xfer;
586	struct fw_xferq *xferq;
587	struct fw_pkt *fp;
588	int i = 0;
589
590	xfer = NULL;
591	xferq = fwe->fd.fc->atq;
592	while (xferq->queued < xferq->maxq - 1) {
593		xfer = STAILQ_FIRST(&fwe->xferlist);
594		if (xfer == NULL) {
595			printf("if_fwe: lack of xfer\n");
596			return;
597		}
598		IF_DEQUEUE(&ifp->if_snd, m);
599		if (m == NULL)
600			break;
601		STAILQ_REMOVE_HEAD(&fwe->xferlist, link);
602#if defined(__DragonFly__) || __FreeBSD_version < 500000
603		if (ifp->if_bpf != NULL)
604			bpf_mtap(ifp, m);
605#else
606		BPF_MTAP(ifp, m);
607#endif
608
609		/* keep ip packet alignment for alpha */
610		M_PREPEND(m, ETHER_ALIGN, M_DONTWAIT);
611		fp = &xfer->send.hdr;
612		*(uint32_t *)&xfer->send.hdr = *(int32_t *)&fwe->pkt_hdr;
613		fp->mode.stream.len = m->m_pkthdr.len;
614		xfer->mbuf = m;
615		xfer->send.pay_len = m->m_pkthdr.len;
616
617		if (fw_asyreq(fwe->fd.fc, -1, xfer) != 0) {
618			/* error */
619			ifp->if_oerrors ++;
620			/* XXX set error code */
621			fwe_output_callback(xfer);
622		} else {
623			ifp->if_opackets ++;
624			i++;
625		}
626	}
627#if 0
628	if (i > 1)
629		printf("%d queued\n", i);
630#endif
631	if (i > 0)
632		xferq->start(fwe->fd.fc);
633}
634
635/* Async. stream output */
636static void
637fwe_as_input(struct fw_xferq *xferq)
638{
639	struct mbuf *m, *m0;
640	struct ifnet *ifp;
641	struct fwe_softc *fwe;
642	struct fw_bulkxfer *sxfer;
643	struct fw_pkt *fp;
644	u_char *c;
645#if defined(__DragonFly__) || __FreeBSD_version < 500000
646	struct ether_header *eh;
647#endif
648
649	fwe = (struct fwe_softc *)xferq->sc;
650	ifp = fwe->eth_softc.ifp;
651
652	while ((sxfer = STAILQ_FIRST(&xferq->stvalid)) != NULL) {
653		STAILQ_REMOVE_HEAD(&xferq->stvalid, link);
654		fp = mtod(sxfer->mbuf, struct fw_pkt *);
655		if (fwe->fd.fc->irx_post != NULL)
656			fwe->fd.fc->irx_post(fwe->fd.fc, fp->mode.ld);
657		m = sxfer->mbuf;
658
659		/* insert new rbuf */
660		sxfer->mbuf = m0 = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
661		if (m0 != NULL) {
662			m0->m_len = m0->m_pkthdr.len = m0->m_ext.ext_size;
663			STAILQ_INSERT_TAIL(&xferq->stfree, sxfer, link);
664		} else
665			printf("fwe_as_input: m_getcl failed\n");
666
667		if (sxfer->resp != 0 || fp->mode.stream.len <
668		    ETHER_ALIGN + sizeof(struct ether_header)) {
669			m_freem(m);
670			ifp->if_ierrors ++;
671			continue;
672		}
673
674		m->m_data += HDR_LEN + ETHER_ALIGN;
675		c = mtod(m, char *);
676#if defined(__DragonFly__) || __FreeBSD_version < 500000
677		eh = (struct ether_header *)c;
678		m->m_data += sizeof(struct ether_header);
679		m->m_len = m->m_pkthdr.len = fp->mode.stream.len - ETHER_ALIGN
680		    - sizeof(struct ether_header);
681#else
682		m->m_len = m->m_pkthdr.len = fp->mode.stream.len - ETHER_ALIGN;
683#endif
684		m->m_pkthdr.rcvif = ifp;
685#if 0
686		FWEDEBUG(ifp, "%02x %02x %02x %02x %02x %02x\n"
687			 "%02x %02x %02x %02x %02x %02x\n"
688			 "%02x %02x %02x %02x\n"
689			 "%02x %02x %02x %02x\n"
690			 "%02x %02x %02x %02x\n"
691			 "%02x %02x %02x %02x\n",
692			 c[0], c[1], c[2], c[3], c[4], c[5],
693			 c[6], c[7], c[8], c[9], c[10], c[11],
694			 c[12], c[13], c[14], c[15],
695			 c[16], c[17], c[18], c[19],
696			 c[20], c[21], c[22], c[23],
697			 c[20], c[21], c[22], c[23]
698		 );
699#endif
700#if defined(__DragonFly__) || __FreeBSD_version < 500000
701		ether_input(ifp, eh, m);
702#else
703		(*ifp->if_input)(ifp, m);
704#endif
705		ifp->if_ipackets ++;
706	}
707	if (STAILQ_FIRST(&xferq->stfree) != NULL)
708		fwe->fd.fc->irx_enable(fwe->fd.fc, fwe->dma_ch);
709}
710
711
712static devclass_t fwe_devclass;
713
714static device_method_t fwe_methods[] = {
715	/* device interface */
716	DEVMETHOD(device_identify,	fwe_identify),
717	DEVMETHOD(device_probe,		fwe_probe),
718	DEVMETHOD(device_attach,	fwe_attach),
719	DEVMETHOD(device_detach,	fwe_detach),
720	{ 0, 0 }
721};
722
723static driver_t fwe_driver = {
724        "fwe",
725	fwe_methods,
726	sizeof(struct fwe_softc),
727};
728
729
730#ifdef __DragonFly__
731DECLARE_DUMMY_MODULE(fwe);
732#endif
733DRIVER_MODULE(fwe, firewire, fwe_driver, fwe_devclass, 0, 0);
734MODULE_VERSION(fwe, 1);
735MODULE_DEPEND(fwe, firewire, 1, 1, 1);
736