1098ca2bdSWarner Losh /*-
2df57947fSPedro F. Giffuni * SPDX-License-Identifier: BSD-4-Clause
3df57947fSPedro F. Giffuni *
4b8b33234SDoug Rabson * Copyright (c) 2004
5b8b33234SDoug Rabson * Doug Rabson
6b8b33234SDoug Rabson * Copyright (c) 2002-2003
7b8b33234SDoug Rabson * Hidetoshi Shimokawa. All rights reserved.
8b8b33234SDoug Rabson *
9b8b33234SDoug Rabson * Redistribution and use in source and binary forms, with or without
10b8b33234SDoug Rabson * modification, are permitted provided that the following conditions
11b8b33234SDoug Rabson * are met:
12b8b33234SDoug Rabson * 1. Redistributions of source code must retain the above copyright
13b8b33234SDoug Rabson * notice, this list of conditions and the following disclaimer.
14b8b33234SDoug Rabson * 2. Redistributions in binary form must reproduce the above copyright
15b8b33234SDoug Rabson * notice, this list of conditions and the following disclaimer in the
16b8b33234SDoug Rabson * documentation and/or other materials provided with the distribution.
17b8b33234SDoug Rabson * 3. All advertising materials mentioning features or use of this software
18b8b33234SDoug Rabson * must display the following acknowledgement:
19b8b33234SDoug Rabson *
20b8b33234SDoug Rabson * This product includes software developed by Hidetoshi Shimokawa.
21b8b33234SDoug Rabson *
22b8b33234SDoug Rabson * 4. Neither the name of the author nor the names of its contributors
23b8b33234SDoug Rabson * may be used to endorse or promote products derived from this software
24b8b33234SDoug Rabson * without specific prior written permission.
25b8b33234SDoug Rabson *
26b8b33234SDoug Rabson * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27b8b33234SDoug Rabson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28b8b33234SDoug Rabson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29b8b33234SDoug Rabson * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30b8b33234SDoug Rabson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31b8b33234SDoug Rabson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32b8b33234SDoug Rabson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33b8b33234SDoug Rabson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34b8b33234SDoug Rabson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35b8b33234SDoug Rabson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36b8b33234SDoug Rabson * SUCH DAMAGE.
37b8b33234SDoug Rabson *
38b8b33234SDoug Rabson */
39b8b33234SDoug Rabson
40f0796cd2SGleb Smirnoff #ifdef HAVE_KERNEL_OPTION_HEADERS
41f0796cd2SGleb Smirnoff #include "opt_device_polling.h"
42b8b33234SDoug Rabson #include "opt_inet.h"
43f0796cd2SGleb Smirnoff #endif
44b8b33234SDoug Rabson
45b8b33234SDoug Rabson #include <sys/param.h>
46b8b33234SDoug Rabson #include <sys/kernel.h>
47b8b33234SDoug Rabson #include <sys/malloc.h>
48b8b33234SDoug Rabson #include <sys/mbuf.h>
49b8b33234SDoug Rabson #include <sys/socket.h>
50b8b33234SDoug Rabson #include <sys/sockio.h>
51b8b33234SDoug Rabson #include <sys/sysctl.h>
52b8b33234SDoug Rabson #include <sys/systm.h>
53b8b33234SDoug Rabson #include <sys/taskqueue.h>
54b8b33234SDoug Rabson #include <sys/module.h>
55b8b33234SDoug Rabson #include <sys/bus.h>
56b8b33234SDoug Rabson #include <machine/bus.h>
57b8b33234SDoug Rabson
58b8b33234SDoug Rabson #include <net/bpf.h>
59b8b33234SDoug Rabson #include <net/if.h>
6076039bc8SGleb Smirnoff #include <net/if_var.h>
61b8b33234SDoug Rabson #include <net/firewire.h>
62b8b33234SDoug Rabson #include <net/if_arp.h>
63fc74a9f9SBrooks Davis #include <net/if_types.h>
64b8b33234SDoug Rabson #include <dev/firewire/firewire.h>
65b8b33234SDoug Rabson #include <dev/firewire/firewirereg.h>
6604fa3b29SDoug Rabson #include <dev/firewire/iec13213.h>
67b8b33234SDoug Rabson #include <dev/firewire/if_fwipvar.h>
68b8b33234SDoug Rabson
69b8b33234SDoug Rabson /*
70b8b33234SDoug Rabson * We really need a mechanism for allocating regions in the FIFO
71b8b33234SDoug Rabson * address space. We pick a address in the OHCI controller's 'middle'
72b8b33234SDoug Rabson * address space. This means that the controller will automatically
73b8b33234SDoug Rabson * send responses for us, which is fine since we don't have any
74b8b33234SDoug Rabson * important information to put in the response anyway.
75b8b33234SDoug Rabson */
76b8b33234SDoug Rabson #define INET_FIFO 0xfffe00000000LL
77b8b33234SDoug Rabson
78b8b33234SDoug Rabson #define FWIPDEBUG if (fwipdebug) if_printf
79b8b33234SDoug Rabson #define TX_MAX_QUEUE (FWMAXQUEUE - 1)
80b8b33234SDoug Rabson
81b8b33234SDoug Rabson /* network interface */
8261c05f13SJustin Hibbits static void fwip_start (if_t);
8361c05f13SJustin Hibbits static int fwip_ioctl (if_t, u_long, caddr_t);
84b8b33234SDoug Rabson static void fwip_init (void *);
85b8b33234SDoug Rabson
86b8b33234SDoug Rabson static void fwip_post_busreset (void *);
87b8b33234SDoug Rabson static void fwip_output_callback (struct fw_xfer *);
8861c05f13SJustin Hibbits static void fwip_async_output (struct fwip_softc *, if_t);
89b8b33234SDoug Rabson static void fwip_start_send (void *, int);
90b8b33234SDoug Rabson static void fwip_stream_input (struct fw_xferq *);
91b8b33234SDoug Rabson static void fwip_unicast_input(struct fw_xfer *);
92b8b33234SDoug Rabson
93b8b33234SDoug Rabson static int fwipdebug = 0;
942f8e2ebbSDoug Rabson static int broadcast_channel = 0xc0 | 0x1f; /* tag | channel(XXX) */
95b8b33234SDoug Rabson static int tx_speed = 2;
96b8b33234SDoug Rabson static int rx_queue_len = FWMAXQUEUE;
97b8b33234SDoug Rabson
98d745c852SEd Schouten static MALLOC_DEFINE(M_FWIP, "if_fwip", "IP over FireWire interface");
99b8b33234SDoug Rabson SYSCTL_INT(_debug, OID_AUTO, if_fwip_debug, CTLFLAG_RW, &fwipdebug, 0, "");
100b8b33234SDoug Rabson SYSCTL_DECL(_hw_firewire);
1017029da5cSPawel Biernacki static SYSCTL_NODE(_hw_firewire, OID_AUTO, fwip, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
102b8b33234SDoug Rabson "Firewire ip subsystem");
103af3b2549SHans Petter Selasky SYSCTL_INT(_hw_firewire_fwip, OID_AUTO, rx_queue_len, CTLFLAG_RWTUN, &rx_queue_len,
104b8b33234SDoug Rabson 0, "Length of the receive queue");
105b8b33234SDoug Rabson
106b8b33234SDoug Rabson #ifdef DEVICE_POLLING
107b8b33234SDoug Rabson static poll_handler_t fwip_poll;
108b8b33234SDoug Rabson
1091abcdbd1SAttilio Rao static int
fwip_poll(if_t ifp,enum poll_cmd cmd,int count)11061c05f13SJustin Hibbits fwip_poll(if_t ifp, enum poll_cmd cmd, int count)
111b8b33234SDoug Rabson {
112b8b33234SDoug Rabson struct fwip_softc *fwip;
113b8b33234SDoug Rabson struct firewire_comm *fc;
114b8b33234SDoug Rabson
11561c05f13SJustin Hibbits if (!(if_getdrvflags(ifp) & IFF_DRV_RUNNING))
1161abcdbd1SAttilio Rao return (0);
11740929967SGleb Smirnoff
11861c05f13SJustin Hibbits fwip = ((struct fwip_eth_softc *)if_getsoftc(ifp))->fwip;
119b8b33234SDoug Rabson fc = fwip->fd.fc;
120b8b33234SDoug Rabson fc->poll(fc, (cmd == POLL_AND_CHECK_STATUS)?0:1, count);
1211abcdbd1SAttilio Rao return (0);
122b8b33234SDoug Rabson }
12340929967SGleb Smirnoff #endif /* DEVICE_POLLING */
12440929967SGleb Smirnoff
125b8b33234SDoug Rabson static void
fwip_identify(driver_t * driver,device_t parent)126b8b33234SDoug Rabson fwip_identify(driver_t *driver, device_t parent)
127b8b33234SDoug Rabson {
128b8b33234SDoug Rabson BUS_ADD_CHILD(parent, 0, "fwip", device_get_unit(parent));
129b8b33234SDoug Rabson }
130b8b33234SDoug Rabson
131b8b33234SDoug Rabson static int
fwip_probe(device_t dev)132b8b33234SDoug Rabson fwip_probe(device_t dev)
133b8b33234SDoug Rabson {
134b8b33234SDoug Rabson device_t pa;
135b8b33234SDoug Rabson
136b8b33234SDoug Rabson pa = device_get_parent(dev);
137b8b33234SDoug Rabson if (device_get_unit(dev) != device_get_unit(pa)) {
138b8b33234SDoug Rabson return (ENXIO);
139b8b33234SDoug Rabson }
140b8b33234SDoug Rabson
141b8b33234SDoug Rabson device_set_desc(dev, "IP over FireWire");
142b8b33234SDoug Rabson return (0);
143b8b33234SDoug Rabson }
144b8b33234SDoug Rabson
145b8b33234SDoug Rabson static int
fwip_attach(device_t dev)146b8b33234SDoug Rabson fwip_attach(device_t dev)
147b8b33234SDoug Rabson {
148b8b33234SDoug Rabson struct fwip_softc *fwip;
14961c05f13SJustin Hibbits if_t ifp;
150b8b33234SDoug Rabson int unit, s;
151b8b33234SDoug Rabson struct fw_hwaddr *hwaddr;
152b8b33234SDoug Rabson
153b8b33234SDoug Rabson fwip = ((struct fwip_softc *)device_get_softc(dev));
154b8b33234SDoug Rabson unit = device_get_unit(dev);
155fc74a9f9SBrooks Davis ifp = fwip->fw_softc.fwip_ifp = if_alloc(IFT_IEEE1394);
156b8b33234SDoug Rabson
1579950b741SHidetoshi Shimokawa mtx_init(&fwip->mtx, "fwip", NULL, MTX_DEF);
158b8b33234SDoug Rabson /* XXX */
159b8b33234SDoug Rabson fwip->dma_ch = -1;
160b8b33234SDoug Rabson
161b8b33234SDoug Rabson fwip->fd.fc = device_get_ivars(dev);
162b8b33234SDoug Rabson if (tx_speed < 0)
163b8b33234SDoug Rabson tx_speed = fwip->fd.fc->speed;
164b8b33234SDoug Rabson
165b8b33234SDoug Rabson fwip->fd.dev = dev;
166b8b33234SDoug Rabson fwip->fd.post_explore = NULL;
167b8b33234SDoug Rabson fwip->fd.post_busreset = fwip_post_busreset;
168b8b33234SDoug Rabson fwip->fw_softc.fwip = fwip;
169b8b33234SDoug Rabson TASK_INIT(&fwip->start_send, 0, fwip_start_send, fwip);
170b8b33234SDoug Rabson
171b8b33234SDoug Rabson /*
172b8b33234SDoug Rabson * Encode our hardware the way that arp likes it.
173b8b33234SDoug Rabson */
174fc74a9f9SBrooks Davis hwaddr = &IFP2FWC(fwip->fw_softc.fwip_ifp)->fc_hwaddr;
175b8b33234SDoug Rabson hwaddr->sender_unique_ID_hi = htonl(fwip->fd.fc->eui.hi);
176b8b33234SDoug Rabson hwaddr->sender_unique_ID_lo = htonl(fwip->fd.fc->eui.lo);
177b8b33234SDoug Rabson hwaddr->sender_max_rec = fwip->fd.fc->maxrec;
178b8b33234SDoug Rabson hwaddr->sspd = fwip->fd.fc->speed;
179b8b33234SDoug Rabson hwaddr->sender_unicast_FIFO_hi = htons((uint16_t)(INET_FIFO >> 32));
180b8b33234SDoug Rabson hwaddr->sender_unicast_FIFO_lo = htonl((uint32_t)INET_FIFO);
181b8b33234SDoug Rabson
182b8b33234SDoug Rabson /* fill the rest and attach interface */
18361c05f13SJustin Hibbits if_setsoftc(ifp, &fwip->fw_softc);
184b8b33234SDoug Rabson
185b8b33234SDoug Rabson if_initname(ifp, device_get_name(dev), unit);
18661c05f13SJustin Hibbits if_setinitfn(ifp, fwip_init);
18761c05f13SJustin Hibbits if_setstartfn(ifp, fwip_start);
18861c05f13SJustin Hibbits if_setioctlfn(ifp, fwip_ioctl);
18961c05f13SJustin Hibbits if_setflags(ifp, (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST));
19061c05f13SJustin Hibbits if_setsendqlen(ifp, TX_MAX_QUEUE);
19140929967SGleb Smirnoff #ifdef DEVICE_POLLING
19261c05f13SJustin Hibbits if_setcapabilitiesbit(ifp, IFCAP_POLLING, 0);
19340929967SGleb Smirnoff #endif
194b8b33234SDoug Rabson
195b8b33234SDoug Rabson s = splimp();
196b8b33234SDoug Rabson firewire_ifattach(ifp, hwaddr);
197b8b33234SDoug Rabson splx(s);
198b8b33234SDoug Rabson
199b8b33234SDoug Rabson FWIPDEBUG(ifp, "interface created\n");
200aa386085SZhenlei Huang return (0);
201b8b33234SDoug Rabson }
202b8b33234SDoug Rabson
203b8b33234SDoug Rabson static void
fwip_stop(struct fwip_softc * fwip)204b8b33234SDoug Rabson fwip_stop(struct fwip_softc *fwip)
205b8b33234SDoug Rabson {
206b8b33234SDoug Rabson struct firewire_comm *fc;
207b8b33234SDoug Rabson struct fw_xferq *xferq;
20861c05f13SJustin Hibbits if_t ifp = fwip->fw_softc.fwip_ifp;
209b8b33234SDoug Rabson struct fw_xfer *xfer, *next;
210b8b33234SDoug Rabson int i;
211b8b33234SDoug Rabson
212b8b33234SDoug Rabson fc = fwip->fd.fc;
213b8b33234SDoug Rabson
214b8b33234SDoug Rabson if (fwip->dma_ch >= 0) {
215b8b33234SDoug Rabson xferq = fc->ir[fwip->dma_ch];
216b8b33234SDoug Rabson
217b8b33234SDoug Rabson if (xferq->flag & FWXFERQ_RUNNING)
218b8b33234SDoug Rabson fc->irx_disable(fc, fwip->dma_ch);
219b8b33234SDoug Rabson xferq->flag &=
220b8b33234SDoug Rabson ~(FWXFERQ_MODEMASK | FWXFERQ_OPEN | FWXFERQ_STREAM |
221b8b33234SDoug Rabson FWXFERQ_EXTBUF | FWXFERQ_HANDLER | FWXFERQ_CHTAGMASK);
222b8b33234SDoug Rabson xferq->hand = NULL;
223b8b33234SDoug Rabson
224b8b33234SDoug Rabson for (i = 0; i < xferq->bnchunk; i++)
225b8b33234SDoug Rabson m_freem(xferq->bulkxfer[i].mbuf);
226b8b33234SDoug Rabson free(xferq->bulkxfer, M_FWIP);
227b8b33234SDoug Rabson
228b8b33234SDoug Rabson fw_bindremove(fc, &fwip->fwb);
229b8b33234SDoug Rabson for (xfer = STAILQ_FIRST(&fwip->fwb.xferlist); xfer != NULL;
230b8b33234SDoug Rabson xfer = next) {
231b8b33234SDoug Rabson next = STAILQ_NEXT(xfer, link);
232b8b33234SDoug Rabson fw_xfer_free(xfer);
233b8b33234SDoug Rabson }
234b8b33234SDoug Rabson
235b8b33234SDoug Rabson for (xfer = STAILQ_FIRST(&fwip->xferlist); xfer != NULL;
236b8b33234SDoug Rabson xfer = next) {
237b8b33234SDoug Rabson next = STAILQ_NEXT(xfer, link);
238b8b33234SDoug Rabson fw_xfer_free(xfer);
239b8b33234SDoug Rabson }
240b8b33234SDoug Rabson STAILQ_INIT(&fwip->xferlist);
241b8b33234SDoug Rabson
242b8b33234SDoug Rabson xferq->bulkxfer = NULL;
243b8b33234SDoug Rabson fwip->dma_ch = -1;
244b8b33234SDoug Rabson }
245b8b33234SDoug Rabson
24661c05f13SJustin Hibbits if_setdrvflagbits(ifp, 0, (IFF_DRV_RUNNING | IFF_DRV_OACTIVE));
247b8b33234SDoug Rabson }
248b8b33234SDoug Rabson
249b8b33234SDoug Rabson static int
fwip_detach(device_t dev)250b8b33234SDoug Rabson fwip_detach(device_t dev)
251b8b33234SDoug Rabson {
252b8b33234SDoug Rabson struct fwip_softc *fwip;
25361c05f13SJustin Hibbits if_t ifp;
254b8b33234SDoug Rabson int s;
255b8b33234SDoug Rabson
256b8b33234SDoug Rabson fwip = (struct fwip_softc *)device_get_softc(dev);
25740929967SGleb Smirnoff ifp = fwip->fw_softc.fwip_ifp;
25840929967SGleb Smirnoff
25940929967SGleb Smirnoff #ifdef DEVICE_POLLING
26061c05f13SJustin Hibbits if (if_getcapenable(ifp) & IFCAP_POLLING)
26140929967SGleb Smirnoff ether_poll_deregister(ifp);
26240929967SGleb Smirnoff #endif
26340929967SGleb Smirnoff
264b8b33234SDoug Rabson s = splimp();
265b8b33234SDoug Rabson
266b8b33234SDoug Rabson fwip_stop(fwip);
26740929967SGleb Smirnoff firewire_ifdetach(ifp);
26840929967SGleb Smirnoff if_free(ifp);
2699950b741SHidetoshi Shimokawa mtx_destroy(&fwip->mtx);
270b8b33234SDoug Rabson
271b8b33234SDoug Rabson splx(s);
272b8b33234SDoug Rabson return 0;
273b8b33234SDoug Rabson }
274b8b33234SDoug Rabson
275b8b33234SDoug Rabson static void
fwip_init(void * arg)276b8b33234SDoug Rabson fwip_init(void *arg)
277b8b33234SDoug Rabson {
278b8b33234SDoug Rabson struct fwip_softc *fwip = ((struct fwip_eth_softc *)arg)->fwip;
279b8b33234SDoug Rabson struct firewire_comm *fc;
28061c05f13SJustin Hibbits if_t ifp = fwip->fw_softc.fwip_ifp;
281b8b33234SDoug Rabson struct fw_xferq *xferq;
282b8b33234SDoug Rabson struct fw_xfer *xfer;
283b8b33234SDoug Rabson struct mbuf *m;
284b8b33234SDoug Rabson int i;
285b8b33234SDoug Rabson
286b8b33234SDoug Rabson FWIPDEBUG(ifp, "initializing\n");
287b8b33234SDoug Rabson
288b8b33234SDoug Rabson fc = fwip->fd.fc;
289b8b33234SDoug Rabson #define START 0
290b8b33234SDoug Rabson if (fwip->dma_ch < 0) {
2919950b741SHidetoshi Shimokawa fwip->dma_ch = fw_open_isodma(fc, /* tx */0);
2929950b741SHidetoshi Shimokawa if (fwip->dma_ch < 0)
293b8b33234SDoug Rabson return;
2949950b741SHidetoshi Shimokawa xferq = fc->ir[fwip->dma_ch];
2959950b741SHidetoshi Shimokawa xferq->flag |= FWXFERQ_EXTBUF |
296b8b33234SDoug Rabson FWXFERQ_HANDLER | FWXFERQ_STREAM;
297b8b33234SDoug Rabson xferq->flag &= ~0xff;
298b8b33234SDoug Rabson xferq->flag |= broadcast_channel & 0xff;
299b8b33234SDoug Rabson /* register fwip_input handler */
300b8b33234SDoug Rabson xferq->sc = (caddr_t) fwip;
301b8b33234SDoug Rabson xferq->hand = fwip_stream_input;
302b8b33234SDoug Rabson xferq->bnchunk = rx_queue_len;
303b8b33234SDoug Rabson xferq->bnpacket = 1;
304b8b33234SDoug Rabson xferq->psize = MCLBYTES;
305b8b33234SDoug Rabson xferq->queued = 0;
306b8b33234SDoug Rabson xferq->buf = NULL;
307*4d47c7caSZhenlei Huang xferq->bulkxfer = malloc(
308b8b33234SDoug Rabson sizeof(struct fw_bulkxfer) * xferq->bnchunk,
309b8b33234SDoug Rabson M_FWIP, M_WAITOK);
310b8b33234SDoug Rabson STAILQ_INIT(&xferq->stvalid);
311b8b33234SDoug Rabson STAILQ_INIT(&xferq->stfree);
312b8b33234SDoug Rabson STAILQ_INIT(&xferq->stdma);
313b8b33234SDoug Rabson xferq->stproc = NULL;
314b8b33234SDoug Rabson for (i = 0; i < xferq->bnchunk; i++) {
315c6499eccSGleb Smirnoff m = m_getcl(M_WAITOK, MT_DATA, M_PKTHDR);
316b8b33234SDoug Rabson xferq->bulkxfer[i].mbuf = m;
317b8b33234SDoug Rabson m->m_len = m->m_pkthdr.len = m->m_ext.ext_size;
318b8b33234SDoug Rabson STAILQ_INSERT_TAIL(&xferq->stfree,
319b8b33234SDoug Rabson &xferq->bulkxfer[i], link);
320b8b33234SDoug Rabson }
321b8b33234SDoug Rabson
322b8b33234SDoug Rabson fwip->fwb.start = INET_FIFO;
323b8b33234SDoug Rabson fwip->fwb.end = INET_FIFO + 16384; /* S3200 packet size */
324b8b33234SDoug Rabson
325b8b33234SDoug Rabson /* pre-allocate xfer */
326b8b33234SDoug Rabson STAILQ_INIT(&fwip->fwb.xferlist);
327b8b33234SDoug Rabson for (i = 0; i < rx_queue_len; i++) {
328b8b33234SDoug Rabson xfer = fw_xfer_alloc(M_FWIP);
329b8b33234SDoug Rabson if (xfer == NULL)
330b8b33234SDoug Rabson break;
331c6499eccSGleb Smirnoff m = m_getcl(M_WAITOK, MT_DATA, M_PKTHDR);
332b8b33234SDoug Rabson xfer->recv.payload = mtod(m, uint32_t *);
333b8b33234SDoug Rabson xfer->recv.pay_len = MCLBYTES;
334801167a8SHidetoshi Shimokawa xfer->hand = fwip_unicast_input;
335b8b33234SDoug Rabson xfer->fc = fc;
336b8b33234SDoug Rabson xfer->sc = (caddr_t)fwip;
337b8b33234SDoug Rabson xfer->mbuf = m;
338b8b33234SDoug Rabson STAILQ_INSERT_TAIL(&fwip->fwb.xferlist, xfer, link);
339b8b33234SDoug Rabson }
340b8b33234SDoug Rabson fw_bindadd(fc, &fwip->fwb);
341b8b33234SDoug Rabson
342b8b33234SDoug Rabson STAILQ_INIT(&fwip->xferlist);
343b8b33234SDoug Rabson for (i = 0; i < TX_MAX_QUEUE; i++) {
344b8b33234SDoug Rabson xfer = fw_xfer_alloc(M_FWIP);
345b8b33234SDoug Rabson if (xfer == NULL)
346b8b33234SDoug Rabson break;
347b8b33234SDoug Rabson xfer->send.spd = tx_speed;
348b8b33234SDoug Rabson xfer->fc = fwip->fd.fc;
349b8b33234SDoug Rabson xfer->sc = (caddr_t)fwip;
350801167a8SHidetoshi Shimokawa xfer->hand = fwip_output_callback;
351b8b33234SDoug Rabson STAILQ_INSERT_TAIL(&fwip->xferlist, xfer, link);
352b8b33234SDoug Rabson }
353b8b33234SDoug Rabson } else
354b8b33234SDoug Rabson xferq = fc->ir[fwip->dma_ch];
355b8b33234SDoug Rabson
356b8b33234SDoug Rabson fwip->last_dest.hi = 0;
357b8b33234SDoug Rabson fwip->last_dest.lo = 0;
358b8b33234SDoug Rabson
359b8b33234SDoug Rabson /* start dma */
360b8b33234SDoug Rabson if ((xferq->flag & FWXFERQ_RUNNING) == 0)
361b8b33234SDoug Rabson fc->irx_enable(fc, fwip->dma_ch);
362b8b33234SDoug Rabson
36361c05f13SJustin Hibbits if_setdrvflagbits(ifp, IFF_DRV_RUNNING, 0);
36461c05f13SJustin Hibbits if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE);
365b8b33234SDoug Rabson
366b8b33234SDoug Rabson #if 0
367b8b33234SDoug Rabson /* attempt to start output */
368b8b33234SDoug Rabson fwip_start(ifp);
369b8b33234SDoug Rabson #endif
370b8b33234SDoug Rabson }
371b8b33234SDoug Rabson
372b8b33234SDoug Rabson static int
fwip_ioctl(if_t ifp,u_long cmd,caddr_t data)37361c05f13SJustin Hibbits fwip_ioctl(if_t ifp, u_long cmd, caddr_t data)
374b8b33234SDoug Rabson {
37561c05f13SJustin Hibbits struct fwip_softc *fwip = ((struct fwip_eth_softc *)if_getsoftc(ifp))->fwip;
376b8b33234SDoug Rabson int s, error;
377b8b33234SDoug Rabson
378b8b33234SDoug Rabson switch (cmd) {
379b8b33234SDoug Rabson case SIOCSIFFLAGS:
380b8b33234SDoug Rabson s = splimp();
38161c05f13SJustin Hibbits if (if_getflags(ifp) & IFF_UP) {
38261c05f13SJustin Hibbits if (!(if_getdrvflags(ifp) & IFF_DRV_RUNNING))
383b8b33234SDoug Rabson fwip_init(&fwip->fw_softc);
384b8b33234SDoug Rabson } else {
38561c05f13SJustin Hibbits if (if_getdrvflags(ifp) & IFF_DRV_RUNNING)
386b8b33234SDoug Rabson fwip_stop(fwip);
387b8b33234SDoug Rabson }
388b8b33234SDoug Rabson splx(s);
389b8b33234SDoug Rabson break;
390b8b33234SDoug Rabson case SIOCADDMULTI:
391b8b33234SDoug Rabson case SIOCDELMULTI:
392b8b33234SDoug Rabson break;
39340929967SGleb Smirnoff case SIOCSIFCAP:
39440929967SGleb Smirnoff #ifdef DEVICE_POLLING
39540929967SGleb Smirnoff {
39640929967SGleb Smirnoff struct ifreq *ifr = (struct ifreq *) data;
3970a5eaa9dSMax Khon struct firewire_comm *fc = fwip->fd.fc;
398b8b33234SDoug Rabson
39940929967SGleb Smirnoff if (ifr->ifr_reqcap & IFCAP_POLLING &&
40061c05f13SJustin Hibbits !(if_getcapenable(ifp) & IFCAP_POLLING)) {
40140929967SGleb Smirnoff error = ether_poll_register(fwip_poll, ifp);
40240929967SGleb Smirnoff if (error)
40340929967SGleb Smirnoff return (error);
40440929967SGleb Smirnoff /* Disable interrupts */
40540929967SGleb Smirnoff fc->set_intr(fc, 0);
40661c05f13SJustin Hibbits if_setcapenablebit(ifp, IFCAP_POLLING, 0);
40740929967SGleb Smirnoff return (error);
40840929967SGleb Smirnoff }
40940929967SGleb Smirnoff if (!(ifr->ifr_reqcap & IFCAP_POLLING) &&
41061c05f13SJustin Hibbits if_getcapenable(ifp) & IFCAP_POLLING) {
41140929967SGleb Smirnoff error = ether_poll_deregister(ifp);
41240929967SGleb Smirnoff /* Enable interrupts. */
41340929967SGleb Smirnoff fc->set_intr(fc, 1);
41461c05f13SJustin Hibbits if_setcapenablebit(ifp, 0, IFCAP_POLLING);
41540929967SGleb Smirnoff return (error);
41640929967SGleb Smirnoff }
41740929967SGleb Smirnoff }
41840929967SGleb Smirnoff #endif /* DEVICE_POLLING */
41940929967SGleb Smirnoff break;
420b8b33234SDoug Rabson default:
421b8b33234SDoug Rabson s = splimp();
422b8b33234SDoug Rabson error = firewire_ioctl(ifp, cmd, data);
423b8b33234SDoug Rabson splx(s);
424b8b33234SDoug Rabson return (error);
425b8b33234SDoug Rabson }
426b8b33234SDoug Rabson
427b8b33234SDoug Rabson return (0);
428b8b33234SDoug Rabson }
429b8b33234SDoug Rabson
430b8b33234SDoug Rabson static void
fwip_post_busreset(void * arg)431b8b33234SDoug Rabson fwip_post_busreset(void *arg)
432b8b33234SDoug Rabson {
433b8b33234SDoug Rabson struct fwip_softc *fwip = arg;
43404fa3b29SDoug Rabson struct crom_src *src;
43504fa3b29SDoug Rabson struct crom_chunk *root;
43604fa3b29SDoug Rabson
43704fa3b29SDoug Rabson src = fwip->fd.fc->crom_src;
43804fa3b29SDoug Rabson root = fwip->fd.fc->crom_root;
43904fa3b29SDoug Rabson
44004fa3b29SDoug Rabson /* RFC2734 IPv4 over IEEE1394 */
44104fa3b29SDoug Rabson bzero(&fwip->unit4, sizeof(struct crom_chunk));
44204fa3b29SDoug Rabson crom_add_chunk(src, root, &fwip->unit4, CROM_UDIR);
44304fa3b29SDoug Rabson crom_add_entry(&fwip->unit4, CSRKEY_SPEC, CSRVAL_IETF);
44404fa3b29SDoug Rabson crom_add_simple_text(src, &fwip->unit4, &fwip->spec4, "IANA");
44504fa3b29SDoug Rabson crom_add_entry(&fwip->unit4, CSRKEY_VER, 1);
44604fa3b29SDoug Rabson crom_add_simple_text(src, &fwip->unit4, &fwip->ver4, "IPv4");
44704fa3b29SDoug Rabson
44804fa3b29SDoug Rabson /* RFC3146 IPv6 over IEEE1394 */
44904fa3b29SDoug Rabson bzero(&fwip->unit6, sizeof(struct crom_chunk));
45004fa3b29SDoug Rabson crom_add_chunk(src, root, &fwip->unit6, CROM_UDIR);
45104fa3b29SDoug Rabson crom_add_entry(&fwip->unit6, CSRKEY_SPEC, CSRVAL_IETF);
45204fa3b29SDoug Rabson crom_add_simple_text(src, &fwip->unit6, &fwip->spec6, "IANA");
45304fa3b29SDoug Rabson crom_add_entry(&fwip->unit6, CSRKEY_VER, 2);
45404fa3b29SDoug Rabson crom_add_simple_text(src, &fwip->unit6, &fwip->ver6, "IPv6");
455b8b33234SDoug Rabson
456b8b33234SDoug Rabson fwip->last_dest.hi = 0;
457b8b33234SDoug Rabson fwip->last_dest.lo = 0;
458fc74a9f9SBrooks Davis firewire_busreset(fwip->fw_softc.fwip_ifp);
459b8b33234SDoug Rabson }
460b8b33234SDoug Rabson
461b8b33234SDoug Rabson static void
fwip_output_callback(struct fw_xfer * xfer)462b8b33234SDoug Rabson fwip_output_callback(struct fw_xfer *xfer)
463b8b33234SDoug Rabson {
464b8b33234SDoug Rabson struct fwip_softc *fwip;
46561c05f13SJustin Hibbits if_t ifp;
466b8b33234SDoug Rabson int s;
467b8b33234SDoug Rabson
468b8b33234SDoug Rabson fwip = (struct fwip_softc *)xfer->sc;
469fc74a9f9SBrooks Davis ifp = fwip->fw_softc.fwip_ifp;
470b8b33234SDoug Rabson /* XXX error check */
471b8b33234SDoug Rabson FWIPDEBUG(ifp, "resp = %d\n", xfer->resp);
472b8b33234SDoug Rabson if (xfer->resp != 0)
473c8dfaf38SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
474b8b33234SDoug Rabson m_freem(xfer->mbuf);
475b8b33234SDoug Rabson fw_xfer_unload(xfer);
476b8b33234SDoug Rabson
477b8b33234SDoug Rabson s = splimp();
4789950b741SHidetoshi Shimokawa FWIP_LOCK(fwip);
479b8b33234SDoug Rabson STAILQ_INSERT_TAIL(&fwip->xferlist, xfer, link);
4809950b741SHidetoshi Shimokawa FWIP_UNLOCK(fwip);
481b8b33234SDoug Rabson splx(s);
482b8b33234SDoug Rabson
483b8b33234SDoug Rabson /* for queue full */
48461c05f13SJustin Hibbits if (!if_sendq_empty(ifp)) {
485b8b33234SDoug Rabson fwip_start(ifp);
486b8b33234SDoug Rabson }
4879950b741SHidetoshi Shimokawa }
488b8b33234SDoug Rabson
489b8b33234SDoug Rabson static void
fwip_start(if_t ifp)49061c05f13SJustin Hibbits fwip_start(if_t ifp)
491b8b33234SDoug Rabson {
49261c05f13SJustin Hibbits struct fwip_softc *fwip = ((struct fwip_eth_softc *)if_getsoftc(ifp))->fwip;
493b8b33234SDoug Rabson int s;
494b8b33234SDoug Rabson
495b8b33234SDoug Rabson FWIPDEBUG(ifp, "starting\n");
496b8b33234SDoug Rabson
497b8b33234SDoug Rabson if (fwip->dma_ch < 0) {
498b8b33234SDoug Rabson struct mbuf *m = NULL;
499b8b33234SDoug Rabson
500b8b33234SDoug Rabson FWIPDEBUG(ifp, "not ready\n");
501b8b33234SDoug Rabson
502b8b33234SDoug Rabson s = splimp();
503b8b33234SDoug Rabson do {
50461c05f13SJustin Hibbits m = if_dequeue(ifp);
505b8b33234SDoug Rabson if (m != NULL)
506b8b33234SDoug Rabson m_freem(m);
507c8dfaf38SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
508b8b33234SDoug Rabson } while (m != NULL);
509b8b33234SDoug Rabson splx(s);
510b8b33234SDoug Rabson
511b8b33234SDoug Rabson return;
512b8b33234SDoug Rabson }
513b8b33234SDoug Rabson
514b8b33234SDoug Rabson s = splimp();
51561c05f13SJustin Hibbits if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0);
516b8b33234SDoug Rabson
51761c05f13SJustin Hibbits if (!if_sendq_empty(ifp))
518b8b33234SDoug Rabson fwip_async_output(fwip, ifp);
519b8b33234SDoug Rabson
52061c05f13SJustin Hibbits if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE);
521b8b33234SDoug Rabson splx(s);
522b8b33234SDoug Rabson }
523b8b33234SDoug Rabson
524b8b33234SDoug Rabson /* Async. stream output */
525b8b33234SDoug Rabson static void
fwip_async_output(struct fwip_softc * fwip,if_t ifp)52661c05f13SJustin Hibbits fwip_async_output(struct fwip_softc *fwip, if_t ifp)
527b8b33234SDoug Rabson {
528b8b33234SDoug Rabson struct firewire_comm *fc = fwip->fd.fc;
529b8b33234SDoug Rabson struct mbuf *m;
530b8b33234SDoug Rabson struct m_tag *mtag;
531b8b33234SDoug Rabson struct fw_hwaddr *destfw;
532b8b33234SDoug Rabson struct fw_xfer *xfer;
533b8b33234SDoug Rabson struct fw_xferq *xferq;
534b8b33234SDoug Rabson struct fw_pkt *fp;
535b8b33234SDoug Rabson uint16_t nodeid;
536ee2f2cccSDoug Rabson int error;
537b8b33234SDoug Rabson int i = 0;
538b8b33234SDoug Rabson
539b8b33234SDoug Rabson xfer = NULL;
5409950b741SHidetoshi Shimokawa xferq = fc->atq;
5419950b741SHidetoshi Shimokawa while ((xferq->queued < xferq->maxq - 1) &&
54261c05f13SJustin Hibbits !if_sendq_empty(ifp)) {
5439950b741SHidetoshi Shimokawa FWIP_LOCK(fwip);
544b8b33234SDoug Rabson xfer = STAILQ_FIRST(&fwip->xferlist);
545b8b33234SDoug Rabson if (xfer == NULL) {
5469950b741SHidetoshi Shimokawa FWIP_UNLOCK(fwip);
5479950b741SHidetoshi Shimokawa #if 0
548b8b33234SDoug Rabson printf("if_fwip: lack of xfer\n");
5499950b741SHidetoshi Shimokawa #endif
550b8b33234SDoug Rabson break;
5519950b741SHidetoshi Shimokawa }
5529950b741SHidetoshi Shimokawa STAILQ_REMOVE_HEAD(&fwip->xferlist, link);
5539950b741SHidetoshi Shimokawa FWIP_UNLOCK(fwip);
5549950b741SHidetoshi Shimokawa
55561c05f13SJustin Hibbits m = if_dequeue(ifp);
5569950b741SHidetoshi Shimokawa if (m == NULL) {
5579950b741SHidetoshi Shimokawa FWIP_LOCK(fwip);
5589950b741SHidetoshi Shimokawa STAILQ_INSERT_HEAD(&fwip->xferlist, xfer, link);
5599950b741SHidetoshi Shimokawa FWIP_UNLOCK(fwip);
5609950b741SHidetoshi Shimokawa break;
5619950b741SHidetoshi Shimokawa }
562b8b33234SDoug Rabson
563b8b33234SDoug Rabson /*
564b8b33234SDoug Rabson * Dig out the link-level address which
565b8b33234SDoug Rabson * firewire_output got via arp or neighbour
566b8b33234SDoug Rabson * discovery. If we don't have a link-level address,
567b8b33234SDoug Rabson * just stick the thing on the broadcast channel.
568b8b33234SDoug Rabson */
569b8b33234SDoug Rabson mtag = m_tag_locate(m, MTAG_FIREWIRE, MTAG_FIREWIRE_HWADDR, 0);
570b8b33234SDoug Rabson if (mtag == NULL)
5714d24901aSPedro F. Giffuni destfw = NULL;
572b8b33234SDoug Rabson else
573b8b33234SDoug Rabson destfw = (struct fw_hwaddr *) (mtag + 1);
574b8b33234SDoug Rabson
575b8b33234SDoug Rabson
576b8b33234SDoug Rabson /*
577b8b33234SDoug Rabson * We don't do any bpf stuff here - the generic code
578b8b33234SDoug Rabson * in firewire_output gives the packet to bpf before
579b8b33234SDoug Rabson * it adds the link-level encapsulation.
580b8b33234SDoug Rabson */
581b8b33234SDoug Rabson
582b8b33234SDoug Rabson /*
583b8b33234SDoug Rabson * Put the mbuf in the xfer early in case we hit an
584b8b33234SDoug Rabson * error case below - fwip_output_callback will free
585b8b33234SDoug Rabson * the mbuf.
586b8b33234SDoug Rabson */
587b8b33234SDoug Rabson xfer->mbuf = m;
588b8b33234SDoug Rabson
589b8b33234SDoug Rabson /*
590b8b33234SDoug Rabson * We use the arp result (if any) to add a suitable firewire
591b8b33234SDoug Rabson * packet header before handing off to the bus.
592b8b33234SDoug Rabson */
593b8b33234SDoug Rabson fp = &xfer->send.hdr;
594b8b33234SDoug Rabson nodeid = FWLOCALBUS | fc->nodeid;
595b8b33234SDoug Rabson if ((m->m_flags & M_BCAST) || !destfw) {
596b8b33234SDoug Rabson /*
597b8b33234SDoug Rabson * Broadcast packets are sent as GASP packets with
598b8b33234SDoug Rabson * specifier ID 0x00005e, version 1 on the broadcast
599b8b33234SDoug Rabson * channel. To be conservative, we send at the
600b8b33234SDoug Rabson * slowest possible speed.
601b8b33234SDoug Rabson */
602b8b33234SDoug Rabson uint32_t *p;
603b8b33234SDoug Rabson
604c6499eccSGleb Smirnoff M_PREPEND(m, 2*sizeof(uint32_t), M_NOWAIT);
605b8b33234SDoug Rabson p = mtod(m, uint32_t *);
606b8b33234SDoug Rabson fp->mode.stream.len = m->m_pkthdr.len;
607b8b33234SDoug Rabson fp->mode.stream.chtag = broadcast_channel;
608b8b33234SDoug Rabson fp->mode.stream.tcode = FWTCODE_STREAM;
609b8b33234SDoug Rabson fp->mode.stream.sy = 0;
610b8b33234SDoug Rabson xfer->send.spd = 0;
611b8b33234SDoug Rabson p[0] = htonl(nodeid << 16);
612b8b33234SDoug Rabson p[1] = htonl((0x5e << 24) | 1);
613b8b33234SDoug Rabson } else {
614b8b33234SDoug Rabson /*
615b8b33234SDoug Rabson * Unicast packets are sent as block writes to the
616b8b33234SDoug Rabson * target's unicast fifo address. If we can't
617b8b33234SDoug Rabson * find the node address, we just give up. We
618b8b33234SDoug Rabson * could broadcast it but that might overflow
619b8b33234SDoug Rabson * the packet size limitations due to the
620b8b33234SDoug Rabson * extra GASP header. Note: the hardware
621b8b33234SDoug Rabson * address is stored in network byte order to
622b8b33234SDoug Rabson * make life easier for ARP.
623b8b33234SDoug Rabson */
624b8b33234SDoug Rabson struct fw_device *fd;
625b8b33234SDoug Rabson struct fw_eui64 eui;
626b8b33234SDoug Rabson
627b8b33234SDoug Rabson eui.hi = ntohl(destfw->sender_unique_ID_hi);
628b8b33234SDoug Rabson eui.lo = ntohl(destfw->sender_unique_ID_lo);
629b8b33234SDoug Rabson if (fwip->last_dest.hi != eui.hi ||
630b8b33234SDoug Rabson fwip->last_dest.lo != eui.lo) {
631b8b33234SDoug Rabson fd = fw_noderesolve_eui64(fc, &eui);
632b8b33234SDoug Rabson if (!fd) {
633b8b33234SDoug Rabson /* error */
634c8dfaf38SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
635b8b33234SDoug Rabson /* XXX set error code */
636b8b33234SDoug Rabson fwip_output_callback(xfer);
637b8b33234SDoug Rabson continue;
638b8b33234SDoug Rabson
639b8b33234SDoug Rabson }
640b8b33234SDoug Rabson fwip->last_hdr.mode.wreqb.dst = FWLOCALBUS | fd->dst;
641b8b33234SDoug Rabson fwip->last_hdr.mode.wreqb.tlrt = 0;
642b8b33234SDoug Rabson fwip->last_hdr.mode.wreqb.tcode = FWTCODE_WREQB;
643b8b33234SDoug Rabson fwip->last_hdr.mode.wreqb.pri = 0;
644b8b33234SDoug Rabson fwip->last_hdr.mode.wreqb.src = nodeid;
645b8b33234SDoug Rabson fwip->last_hdr.mode.wreqb.dest_hi =
646b8b33234SDoug Rabson ntohs(destfw->sender_unicast_FIFO_hi);
647b8b33234SDoug Rabson fwip->last_hdr.mode.wreqb.dest_lo =
648b8b33234SDoug Rabson ntohl(destfw->sender_unicast_FIFO_lo);
649b8b33234SDoug Rabson fwip->last_hdr.mode.wreqb.extcode = 0;
650b8b33234SDoug Rabson fwip->last_dest = eui;
651b8b33234SDoug Rabson }
652b8b33234SDoug Rabson
653b8b33234SDoug Rabson fp->mode.wreqb = fwip->last_hdr.mode.wreqb;
654b8b33234SDoug Rabson fp->mode.wreqb.len = m->m_pkthdr.len;
655b8b33234SDoug Rabson xfer->send.spd = min(destfw->sspd, fc->speed);
656b8b33234SDoug Rabson }
657b8b33234SDoug Rabson
658b8b33234SDoug Rabson xfer->send.pay_len = m->m_pkthdr.len;
659b8b33234SDoug Rabson
660ee2f2cccSDoug Rabson error = fw_asyreq(fc, -1, xfer);
661ee2f2cccSDoug Rabson if (error == EAGAIN) {
662ee2f2cccSDoug Rabson /*
663ee2f2cccSDoug Rabson * We ran out of tlabels - requeue the packet
664ee2f2cccSDoug Rabson * for later transmission.
665ee2f2cccSDoug Rabson */
666ee2f2cccSDoug Rabson xfer->mbuf = 0;
6679950b741SHidetoshi Shimokawa FWIP_LOCK(fwip);
668ee2f2cccSDoug Rabson STAILQ_INSERT_TAIL(&fwip->xferlist, xfer, link);
6699950b741SHidetoshi Shimokawa FWIP_UNLOCK(fwip);
67061c05f13SJustin Hibbits if_sendq_prepend(ifp, m);
671ee2f2cccSDoug Rabson break;
672ee2f2cccSDoug Rabson }
673ee2f2cccSDoug Rabson if (error) {
674b8b33234SDoug Rabson /* error */
675c8dfaf38SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
676b8b33234SDoug Rabson /* XXX set error code */
677b8b33234SDoug Rabson fwip_output_callback(xfer);
678b8b33234SDoug Rabson continue;
679b8b33234SDoug Rabson } else {
680c8dfaf38SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
681b8b33234SDoug Rabson i++;
682b8b33234SDoug Rabson }
683b8b33234SDoug Rabson }
684b8b33234SDoug Rabson #if 0
685b8b33234SDoug Rabson if (i > 1)
686b8b33234SDoug Rabson printf("%d queued\n", i);
687b8b33234SDoug Rabson #endif
6889950b741SHidetoshi Shimokawa if (i > 0)
689b8b33234SDoug Rabson xferq->start(fc);
690b8b33234SDoug Rabson }
691b8b33234SDoug Rabson
692b8b33234SDoug Rabson static void
fwip_start_send(void * arg,int count)693b8b33234SDoug Rabson fwip_start_send (void *arg, int count)
694b8b33234SDoug Rabson {
695b8b33234SDoug Rabson struct fwip_softc *fwip = arg;
696b8b33234SDoug Rabson
697b8b33234SDoug Rabson fwip->fd.fc->atq->start(fwip->fd.fc);
698b8b33234SDoug Rabson }
699b8b33234SDoug Rabson
700b8b33234SDoug Rabson /* Async. stream output */
701b8b33234SDoug Rabson static void
fwip_stream_input(struct fw_xferq * xferq)702b8b33234SDoug Rabson fwip_stream_input(struct fw_xferq *xferq)
703b8b33234SDoug Rabson {
704b8a6e03fSGleb Smirnoff struct epoch_tracker et;
705b8b33234SDoug Rabson struct mbuf *m, *m0;
706b8b33234SDoug Rabson struct m_tag *mtag;
70761c05f13SJustin Hibbits if_t ifp;
708b8b33234SDoug Rabson struct fwip_softc *fwip;
709b8b33234SDoug Rabson struct fw_bulkxfer *sxfer;
710b8b33234SDoug Rabson struct fw_pkt *fp;
711b8b33234SDoug Rabson uint16_t src;
712b8b33234SDoug Rabson uint32_t *p;
713b8b33234SDoug Rabson
714b8b33234SDoug Rabson fwip = (struct fwip_softc *)xferq->sc;
715fc74a9f9SBrooks Davis ifp = fwip->fw_softc.fwip_ifp;
71640929967SGleb Smirnoff
717b8a6e03fSGleb Smirnoff NET_EPOCH_ENTER(et);
718b8b33234SDoug Rabson while ((sxfer = STAILQ_FIRST(&xferq->stvalid)) != NULL) {
719b8b33234SDoug Rabson STAILQ_REMOVE_HEAD(&xferq->stvalid, link);
720b8b33234SDoug Rabson fp = mtod(sxfer->mbuf, struct fw_pkt *);
721b8b33234SDoug Rabson if (fwip->fd.fc->irx_post != NULL)
722b8b33234SDoug Rabson fwip->fd.fc->irx_post(fwip->fd.fc, fp->mode.ld);
723b8b33234SDoug Rabson m = sxfer->mbuf;
724b8b33234SDoug Rabson
725b8b33234SDoug Rabson /* insert new rbuf */
726c6499eccSGleb Smirnoff sxfer->mbuf = m0 = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
727b8b33234SDoug Rabson if (m0 != NULL) {
728b8b33234SDoug Rabson m0->m_len = m0->m_pkthdr.len = m0->m_ext.ext_size;
729b8b33234SDoug Rabson STAILQ_INSERT_TAIL(&xferq->stfree, sxfer, link);
730b8b33234SDoug Rabson } else
731b8b33234SDoug Rabson printf("fwip_as_input: m_getcl failed\n");
732b8b33234SDoug Rabson
733b8b33234SDoug Rabson /*
734b8b33234SDoug Rabson * We must have a GASP header - leave the
735b8b33234SDoug Rabson * encapsulation sanity checks to the generic
736453130d9SPedro F. Giffuni * code. Remember that we also have the firewire async
737b8b33234SDoug Rabson * stream header even though that isn't accounted for
738b8b33234SDoug Rabson * in mode.stream.len.
739b8b33234SDoug Rabson */
740b8b33234SDoug Rabson if (sxfer->resp != 0 || fp->mode.stream.len <
741b8b33234SDoug Rabson 2*sizeof(uint32_t)) {
742b8b33234SDoug Rabson m_freem(m);
743c8dfaf38SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
744b8b33234SDoug Rabson continue;
745b8b33234SDoug Rabson }
746b8b33234SDoug Rabson m->m_len = m->m_pkthdr.len = fp->mode.stream.len
747b8b33234SDoug Rabson + sizeof(fp->mode.stream);
748b8b33234SDoug Rabson
749b8b33234SDoug Rabson /*
750b8b33234SDoug Rabson * If we received the packet on the broadcast channel,
751b8b33234SDoug Rabson * mark it as broadcast, otherwise we assume it must
752b8b33234SDoug Rabson * be multicast.
753b8b33234SDoug Rabson */
754b8b33234SDoug Rabson if (fp->mode.stream.chtag == broadcast_channel)
755b8b33234SDoug Rabson m->m_flags |= M_BCAST;
756b8b33234SDoug Rabson else
757b8b33234SDoug Rabson m->m_flags |= M_MCAST;
758b8b33234SDoug Rabson
759b8b33234SDoug Rabson /*
760b8b33234SDoug Rabson * Make sure we recognise the GASP specifier and
761b8b33234SDoug Rabson * version.
762b8b33234SDoug Rabson */
763b8b33234SDoug Rabson p = mtod(m, uint32_t *);
764b8b33234SDoug Rabson if ((((ntohl(p[1]) & 0xffff) << 8) | ntohl(p[2]) >> 24) != 0x00005e
765b8b33234SDoug Rabson || (ntohl(p[2]) & 0xffffff) != 1) {
766b8b33234SDoug Rabson FWIPDEBUG(ifp, "Unrecognised GASP header %#08x %#08x\n",
767b8b33234SDoug Rabson ntohl(p[1]), ntohl(p[2]));
768b8b33234SDoug Rabson m_freem(m);
769c8dfaf38SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
770b8b33234SDoug Rabson continue;
771b8b33234SDoug Rabson }
772b8b33234SDoug Rabson
773b8b33234SDoug Rabson /*
774b8b33234SDoug Rabson * Record the sender ID for possible BPF usage.
775b8b33234SDoug Rabson */
776b8b33234SDoug Rabson src = ntohl(p[1]) >> 16;
7778f31b879SJustin Hibbits if (bpf_peers_present_if(ifp)) {
778b8b33234SDoug Rabson mtag = m_tag_alloc(MTAG_FIREWIRE,
779b8b33234SDoug Rabson MTAG_FIREWIRE_SENDER_EUID,
780b8b33234SDoug Rabson 2*sizeof(uint32_t), M_NOWAIT);
781b8b33234SDoug Rabson if (mtag) {
782b8b33234SDoug Rabson /* bpf wants it in network byte order */
783b8b33234SDoug Rabson struct fw_device *fd;
784b8b33234SDoug Rabson uint32_t *p = (uint32_t *) (mtag + 1);
785b8b33234SDoug Rabson fd = fw_noderesolve_nodeid(fwip->fd.fc,
786b8b33234SDoug Rabson src & 0x3f);
787b8b33234SDoug Rabson if (fd) {
788b8b33234SDoug Rabson p[0] = htonl(fd->eui.hi);
789b8b33234SDoug Rabson p[1] = htonl(fd->eui.lo);
790b8b33234SDoug Rabson } else {
791b8b33234SDoug Rabson p[0] = 0;
792b8b33234SDoug Rabson p[1] = 0;
793b8b33234SDoug Rabson }
794b8b33234SDoug Rabson m_tag_prepend(m, mtag);
795b8b33234SDoug Rabson }
796b8b33234SDoug Rabson }
797b8b33234SDoug Rabson
798b8b33234SDoug Rabson /*
799b8b33234SDoug Rabson * Trim off the GASP header
800b8b33234SDoug Rabson */
801b8b33234SDoug Rabson m_adj(m, 3*sizeof(uint32_t));
802b8b33234SDoug Rabson m->m_pkthdr.rcvif = ifp;
803b8b33234SDoug Rabson firewire_input(ifp, m, src);
804c8dfaf38SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
805b8b33234SDoug Rabson }
806b8a6e03fSGleb Smirnoff NET_EPOCH_EXIT(et);
807b8b33234SDoug Rabson if (STAILQ_FIRST(&xferq->stfree) != NULL)
808b8b33234SDoug Rabson fwip->fd.fc->irx_enable(fwip->fd.fc, fwip->dma_ch);
809b8b33234SDoug Rabson }
810b8b33234SDoug Rabson
811b8b33234SDoug Rabson static __inline void
fwip_unicast_input_recycle(struct fwip_softc * fwip,struct fw_xfer * xfer)812b8b33234SDoug Rabson fwip_unicast_input_recycle(struct fwip_softc *fwip, struct fw_xfer *xfer)
813b8b33234SDoug Rabson {
814b8b33234SDoug Rabson struct mbuf *m;
815b8b33234SDoug Rabson
816b8b33234SDoug Rabson /*
817b8b33234SDoug Rabson * We have finished with a unicast xfer. Allocate a new
818b8b33234SDoug Rabson * cluster and stick it on the back of the input queue.
819b8b33234SDoug Rabson */
820c6499eccSGleb Smirnoff m = m_getcl(M_WAITOK, MT_DATA, M_PKTHDR);
821b8b33234SDoug Rabson xfer->mbuf = m;
822b8b33234SDoug Rabson xfer->recv.payload = mtod(m, uint32_t *);
823b8b33234SDoug Rabson xfer->recv.pay_len = MCLBYTES;
824b8b33234SDoug Rabson xfer->mbuf = m;
825b8b33234SDoug Rabson STAILQ_INSERT_TAIL(&fwip->fwb.xferlist, xfer, link);
826b8b33234SDoug Rabson }
827b8b33234SDoug Rabson
828b8b33234SDoug Rabson static void
fwip_unicast_input(struct fw_xfer * xfer)829b8b33234SDoug Rabson fwip_unicast_input(struct fw_xfer *xfer)
830b8b33234SDoug Rabson {
831b8b33234SDoug Rabson uint64_t address;
832b8b33234SDoug Rabson struct mbuf *m;
833b8b33234SDoug Rabson struct m_tag *mtag;
834bdf316e8STai-hwa Liang struct epoch_tracker et;
83561c05f13SJustin Hibbits if_t ifp;
836b8b33234SDoug Rabson struct fwip_softc *fwip;
837b8b33234SDoug Rabson struct fw_pkt *fp;
838b8b33234SDoug Rabson //struct fw_pkt *sfp;
839b8b33234SDoug Rabson int rtcode;
840b8b33234SDoug Rabson
841b8b33234SDoug Rabson fwip = (struct fwip_softc *)xfer->sc;
842fc74a9f9SBrooks Davis ifp = fwip->fw_softc.fwip_ifp;
843b8b33234SDoug Rabson m = xfer->mbuf;
844b8b33234SDoug Rabson xfer->mbuf = 0;
845b8b33234SDoug Rabson fp = &xfer->recv.hdr;
846b8b33234SDoug Rabson
847b8b33234SDoug Rabson /*
848b8b33234SDoug Rabson * Check the fifo address - we only accept addresses of
849b8b33234SDoug Rabson * exactly INET_FIFO.
850b8b33234SDoug Rabson */
851b8b33234SDoug Rabson address = ((uint64_t)fp->mode.wreqb.dest_hi << 32)
852b8b33234SDoug Rabson | fp->mode.wreqb.dest_lo;
853b8b33234SDoug Rabson if (fp->mode.wreqb.tcode != FWTCODE_WREQB) {
854b8b33234SDoug Rabson rtcode = FWRCODE_ER_TYPE;
855b8b33234SDoug Rabson } else if (address != INET_FIFO) {
856b8b33234SDoug Rabson rtcode = FWRCODE_ER_ADDR;
857b8b33234SDoug Rabson } else {
858b8b33234SDoug Rabson rtcode = FWRCODE_COMPLETE;
859b8b33234SDoug Rabson }
860bdf316e8STai-hwa Liang NET_EPOCH_ENTER(et);
861b8b33234SDoug Rabson
862b8b33234SDoug Rabson /*
863b8b33234SDoug Rabson * Pick up a new mbuf and stick it on the back of the receive
864b8b33234SDoug Rabson * queue.
865b8b33234SDoug Rabson */
866b8b33234SDoug Rabson fwip_unicast_input_recycle(fwip, xfer);
867b8b33234SDoug Rabson
868b8b33234SDoug Rabson /*
869b8b33234SDoug Rabson * If we've already rejected the packet, give up now.
870b8b33234SDoug Rabson */
871b8b33234SDoug Rabson if (rtcode != FWRCODE_COMPLETE) {
872b8b33234SDoug Rabson m_freem(m);
873c8dfaf38SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
874bdf316e8STai-hwa Liang goto done;
875b8b33234SDoug Rabson }
876b8b33234SDoug Rabson
8778f31b879SJustin Hibbits if (bpf_peers_present_if(ifp)) {
878b8b33234SDoug Rabson /*
879b8b33234SDoug Rabson * Record the sender ID for possible BPF usage.
880b8b33234SDoug Rabson */
881b8b33234SDoug Rabson mtag = m_tag_alloc(MTAG_FIREWIRE, MTAG_FIREWIRE_SENDER_EUID,
882b8b33234SDoug Rabson 2*sizeof(uint32_t), M_NOWAIT);
883b8b33234SDoug Rabson if (mtag) {
884b8b33234SDoug Rabson /* bpf wants it in network byte order */
885b8b33234SDoug Rabson struct fw_device *fd;
886b8b33234SDoug Rabson uint32_t *p = (uint32_t *) (mtag + 1);
887b8b33234SDoug Rabson fd = fw_noderesolve_nodeid(fwip->fd.fc,
888b8b33234SDoug Rabson fp->mode.wreqb.src & 0x3f);
889b8b33234SDoug Rabson if (fd) {
890b8b33234SDoug Rabson p[0] = htonl(fd->eui.hi);
891b8b33234SDoug Rabson p[1] = htonl(fd->eui.lo);
892b8b33234SDoug Rabson } else {
893b8b33234SDoug Rabson p[0] = 0;
894b8b33234SDoug Rabson p[1] = 0;
895b8b33234SDoug Rabson }
896b8b33234SDoug Rabson m_tag_prepend(m, mtag);
897b8b33234SDoug Rabson }
898b8b33234SDoug Rabson }
899b8b33234SDoug Rabson
900b8b33234SDoug Rabson /*
901b8b33234SDoug Rabson * Hand off to the generic encapsulation code. We don't use
902b8b33234SDoug Rabson * ifp->if_input so that we can pass the source nodeid as an
903b8b33234SDoug Rabson * argument to facilitate link-level fragment reassembly.
904b8b33234SDoug Rabson */
905b8b33234SDoug Rabson m->m_len = m->m_pkthdr.len = fp->mode.wreqb.len;
906b8b33234SDoug Rabson m->m_pkthdr.rcvif = ifp;
907b8b33234SDoug Rabson firewire_input(ifp, m, fp->mode.wreqb.src);
908c8dfaf38SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
909bdf316e8STai-hwa Liang done:
910bdf316e8STai-hwa Liang NET_EPOCH_EXIT(et);
911b8b33234SDoug Rabson }
912b8b33234SDoug Rabson
913b8b33234SDoug Rabson static device_method_t fwip_methods[] = {
914b8b33234SDoug Rabson /* device interface */
915b8b33234SDoug Rabson DEVMETHOD(device_identify, fwip_identify),
916b8b33234SDoug Rabson DEVMETHOD(device_probe, fwip_probe),
917b8b33234SDoug Rabson DEVMETHOD(device_attach, fwip_attach),
918b8b33234SDoug Rabson DEVMETHOD(device_detach, fwip_detach),
919b8b33234SDoug Rabson { 0, 0 }
920b8b33234SDoug Rabson };
921b8b33234SDoug Rabson
922b8b33234SDoug Rabson static driver_t fwip_driver = {
923b8b33234SDoug Rabson "fwip",
924b8b33234SDoug Rabson fwip_methods,
925b8b33234SDoug Rabson sizeof(struct fwip_softc),
926b8b33234SDoug Rabson };
927b8b33234SDoug Rabson
928b8b33234SDoug Rabson
9298984411bSJohn Baldwin DRIVER_MODULE(fwip, firewire, fwip_driver, 0, 0);
930b8b33234SDoug Rabson MODULE_VERSION(fwip, 1);
931b8b33234SDoug Rabson MODULE_DEPEND(fwip, firewire, 1, 1, 1);
932