if_nf10bmac.c revision 270061
1/*-
2 * Copyright (c) 2012-2014 Bjoern A. Zeeb
3 * All rights reserved.
4 *
5 * This software was developed by SRI International and the University of
6 * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249
7 * ("MRC2"), as part of the DARPA MRC research programme.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 *
30 * This driver is modelled after atse(4).  We need to seriously reduce the
31 * per-driver code we have to write^wcopy & paste.
32 *
33 * TODO:
34 * - figure out on the HW side why some data is LE and some is BE.
35 * - general set of improvements possible (e.g., reduce times of copying,
36 *   do on-the-copy checksum calculations)
37 */
38
39#include <sys/cdefs.h>
40__FBSDID("$FreeBSD: stable/10/sys/dev/netfpga10g/nf10bmac/if_nf10bmac.c 270061 2014-08-16 14:30:46Z bz $");
41
42#include "opt_device_polling.h"
43
44#include <sys/param.h>
45#include <sys/systm.h>
46#include <sys/kernel.h>
47#include <sys/bus.h>
48#include <sys/endian.h>
49#include <sys/lock.h>
50#include <sys/module.h>
51#include <sys/mutex.h>
52#include <sys/proc.h>
53#include <sys/socket.h>
54#include <sys/sockio.h>
55#include <sys/types.h>
56
57#include <net/ethernet.h>
58#include <net/if.h>
59#include <net/if_var.h>
60#include <net/if_dl.h>
61#include <net/if_media.h>
62#include <net/if_types.h>
63#include <net/if_vlan_var.h>
64
65#include <net/bpf.h>
66
67#include <machine/bus.h>
68#include <machine/resource.h>
69#include <sys/rman.h>
70
71#include "if_nf10bmacreg.h"
72
73#ifndef	NF10BMAC_MAX_PKTS
74/*
75 * We have a 4k buffer in HW, so do not try to send more than 3 packets.
76 * At the time of writing HW is orders of magnitude faster than we can
77 * enqueue so it would not matter but need an escape.
78 */
79#define	NF10BMAC_MAX_PKTS		3
80#endif
81
82#ifndef NF10BMAC_WATCHDOG_TIME
83#define	NF10BMAC_WATCHDOG_TIME		5	/* seconds */
84#endif
85
86#ifdef DEVICE_POLLING
87static poll_handler_t nf10bmac_poll;
88#endif
89
90#define	NF10BMAC_LOCK(_sc)		mtx_lock(&(_sc)->nf10bmac_mtx)
91#define	NF10BMAC_UNLOCK(_sc)		mtx_unlock(&(_sc)->nf10bmac_mtx)
92#define	NF10BMAC_LOCK_ASSERT(_sc)	\
93	mtx_assert(&(_sc)->nf10bmac_mtx, MA_OWNED)
94
95#define	NF10BMAC_CTRL0			0x00
96#define	NF10BMAC_TX_DATA		0x00
97#define	NF10BMAC_TX_META		0x08
98#define	NF10BMAC_TX_LEN			0x10
99#define	NF10BMAC_RX_DATA		0x00
100#define	NF10BMAC_RX_META		0x08
101#define	NF10BMAC_RX_LEN			0x10
102#define	NF10BMAC_INTR_CLEAR_DIS		0x00
103#define	NF10BMAC_INTR_CTRL		0x08
104
105#define NF10BMAC_TUSER_MAC0		(1 << 0)
106#define NF10BMAC_TUSER_CPU0		(1 << 1)
107#define NF10BMAC_TUSER_MAC1		(1 << 2)
108#define NF10BMAC_TUSER_CPU1		(1 << 3)
109#define NF10BMAC_TUSER_MAC2		(1 << 4)
110#define NF10BMAC_TUSER_CPU2		(1 << 5)
111#define NF10BMAC_TUSER_MAC3		(1 << 6)
112#define NF10BMAC_TUSER_CPU3		(1 << 7)
113
114#define	NF10BMAC_DATA_LEN_MASK		0x0000ffff
115#define	NF10BMAC_DATA_DPORT_MASK	0xff000000
116#define	NF10BMAC_DATA_DPORT_SHIFT	24
117#define	NF10BMAC_DATA_SPORT_MASK	0x00ff0000
118#define	NF10BMAC_DATA_SPORT_SHIFT	16
119#define	NF10BMAC_DATA_LAST		0x00008000
120#ifdef NF10BMAC_64BIT
121#define	NF10BMAC_DATA_STRB		0x000000ff
122#define	REGWTYPE			uint64_t
123#else
124#define	NF10BMAC_DATA_STRB		0x0000000f
125#define	REGWTYPE			uint32_t
126#endif
127
128
129static inline void
130nf10bmac_write(struct resource *res, REGWTYPE reg, REGWTYPE val,
131    const char *f __unused, const int l __unused)
132{
133
134#ifdef NF10BMAC_64BIT
135	bus_write_8(res, reg, htole64(val));
136#else
137	bus_write_4(res, reg, htole32(val));
138#endif
139}
140
141static inline REGWTYPE
142nf10bmac_read(struct resource *res, REGWTYPE reg,
143    const char *f __unused, const int l __unused)
144{
145
146#ifdef NF10BMAC_64BIT
147	return (le64toh(bus_read_8(res, reg)));
148#else
149	return (le32toh(bus_read_4(res, reg)));
150#endif
151}
152
153static inline void
154nf10bmac_write_be(struct resource *res, REGWTYPE reg, REGWTYPE val,
155    const char *f __unused, const int l __unused)
156{
157
158#ifdef NF10BMAC_64BIT
159	bus_write_8(res, reg, htobe64(val));
160#else
161	bus_write_4(res, reg, htobe32(val));
162#endif
163}
164
165
166static inline REGWTYPE
167nf10bmac_read_be(struct resource *res, REGWTYPE reg,
168    const char *f __unused, const int l __unused)
169{
170
171#ifdef NF10BMAC_64BIT
172	return (be64toh(bus_read_8(res, reg)));
173#else
174	return (be32toh(bus_read_4(res, reg)));
175#endif
176}
177
178#define	NF10BMAC_WRITE_CTRL(sc, reg, val)				\
179	nf10bmac_write((sc)->nf10bmac_ctrl_res, (reg), (val),		\
180	    __func__, __LINE__)
181#define	NF10BMAC_WRITE(sc, reg, val)					\
182	nf10bmac_write((sc)->nf10bmac_tx_mem_res, (reg), (val),		\
183	    __func__, __LINE__)
184#define	NF10BMAC_READ(sc, reg)						\
185	nf10bmac_read((sc)->nf10bmac_rx_mem_res, (reg),			\
186	    __func__, __LINE__)
187#define	NF10BMAC_WRITE_BE(sc, reg, val)					\
188	nf10bmac_write_be((sc)->nf10bmac_tx_mem_res, (reg), (val),	\
189	    __func__, __LINE__)
190#define	NF10BMAC_READ_BE(sc, reg)					\
191	nf10bmac_read_be((sc)->nf10bmac_rx_mem_res, (reg),		\
192	    __func__, __LINE__)
193
194#define	NF10BMAC_WRITE_INTR(sc, reg, val, _f, _l)			\
195	nf10bmac_write((sc)->nf10bmac_intr_res, (reg), (val),		\
196	    (_f), (_l))
197
198#define	NF10BMAC_RX_INTR_CLEAR_DIS(sc)					\
199	NF10BMAC_WRITE_INTR((sc), NF10BMAC_INTR_CLEAR_DIS, 1,		\
200	__func__, __LINE__)
201#define	NF10BMAC_RX_INTR_ENABLE(sc)					\
202	NF10BMAC_WRITE_INTR((sc), NF10BMAC_INTR_CTRL, 1,		\
203	__func__, __LINE__)
204#define	NF10BMAC_RX_INTR_DISABLE(sc)					\
205	NF10BMAC_WRITE_INTR((sc), NF10BMAC_INTR_CTRL, 0,		\
206	__func__, __LINE__)
207
208
209#ifdef ENABLE_WATCHDOG
210static void nf10bmac_tick(void *);
211#endif
212static int nf10bmac_detach(device_t);
213
214devclass_t nf10bmac_devclass;
215
216
217static int
218nf10bmac_tx_locked(struct nf10bmac_softc *sc, struct mbuf *m)
219{
220	int32_t len, l, ml;
221	REGWTYPE md, val;
222
223	NF10BMAC_LOCK_ASSERT(sc);
224
225	KASSERT(m != NULL, ("%s: m is null: sc=%p", __func__, sc));
226	KASSERT(m->m_flags & M_PKTHDR, ("%s: not a pkthdr: m=%p", __func__, m));
227	/*
228	 * Copy to buffer to minimize our pain as we can only store
229	 * double words which, after the first mbuf gets out of alignment
230	 * quite quickly.
231	 */
232	m_copydata(m, 0, m->m_pkthdr.len, sc->nf10bmac_tx_buf);
233	len = m->m_pkthdr.len;
234
235	/* Write the length at start of packet. */
236	NF10BMAC_WRITE(sc, NF10BMAC_TX_LEN, len);
237
238	/* Write the meta data and data. */
239	ml = len / sizeof(val);
240	len -= (ml * sizeof(val));
241	for (l = 0; l <= ml; l++) {
242		int32_t cl;
243
244		cl = sizeof(val);
245		md = (NF10BMAC_TUSER_CPU0 << NF10BMAC_DATA_SPORT_SHIFT);
246		if (l == ml || (len == 0 && l == (ml - 1))) {
247			if (l == ml && len == 0) {
248				break;
249			} else {
250				uint8_t s;
251				int sl;
252
253				if (l == (ml - 1))
254					len = sizeof(val);
255				cl = len;
256
257				for (s = 0, sl = len; sl > 0; sl--)
258					s |= (1 << (sl - 1));
259				md |= (s & NF10BMAC_DATA_STRB);
260				md |= NF10BMAC_DATA_LAST;
261			}
262		} else {
263			md |= NF10BMAC_DATA_STRB;
264		}
265		NF10BMAC_WRITE(sc, NF10BMAC_TX_META, md);
266		bcopy(&sc->nf10bmac_tx_buf[l*sizeof(val)], &val, cl);
267		NF10BMAC_WRITE_BE(sc, NF10BMAC_TX_DATA, val);
268	}
269
270	/* If anyone is interested give them a copy. */
271	BPF_MTAP(sc->nf10bmac_ifp, m);
272
273	m_freem(m);
274
275	return (0);
276}
277
278static void
279nf10bmac_start_locked(struct ifnet *ifp)
280{
281	struct nf10bmac_softc *sc;
282	int count, error;
283
284	sc = ifp->if_softc;
285	NF10BMAC_LOCK_ASSERT(sc);
286
287	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
288	    IFF_DRV_RUNNING || (sc->nf10bmac_flags & NF10BMAC_FLAGS_LINK) == 0)
289		return;
290
291#ifdef ENABLE_WATCHDOG
292	/*
293	 * Disable the watchdog while sending, we are batching packets.
294	 * Though we should never reach 5 seconds, and are holding the lock,
295	 * but who knows.
296	 */
297	sc->nf10bmac_watchdog_timer = 0;
298#endif
299
300	/* Send up to MAX_PKTS_PER_TX_LOOP packets. */
301	for (count = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd) &&
302	    count < NF10BMAC_MAX_PKTS; count++) {
303		struct mbuf *m;
304
305		IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
306		if (m == NULL)
307			break;
308		error = nf10bmac_tx_locked(sc, m);
309		if (error != 0)
310			break;
311	}
312
313#ifdef ENABLE_WATCHDOG
314done:
315	/* If the IP core walks into Nekromanteion try to bail out. */
316	/* XXX-BZ useless until we have direct FIFO fill status feedback. */
317	if (count > 0)
318		sc->nf10bmac_watchdog_timer = NF10BMAC_WATCHDOG_TIME;
319#endif
320}
321
322static void
323nf10bmac_start(struct ifnet *ifp)
324{
325	struct nf10bmac_softc *sc;
326
327	sc = ifp->if_softc;
328	NF10BMAC_LOCK(sc);
329	nf10bmac_start_locked(ifp);
330	NF10BMAC_UNLOCK(sc);
331}
332
333static void
334nf10bmac_eat_packet_munch_munch(struct nf10bmac_softc *sc)
335{
336	REGWTYPE md, val;
337
338	do {
339		md = NF10BMAC_READ_BE(sc, NF10BMAC_RX_META);
340		if ((md & NF10BMAC_DATA_STRB) != 0)
341			val = NF10BMAC_READ_BE(sc, NF10BMAC_RX_DATA);
342	} while ((md & NF10BMAC_DATA_STRB) != 0 &&
343	    (md & NF10BMAC_DATA_LAST) == 0);
344}
345
346static int
347nf10bmac_rx_locked(struct nf10bmac_softc *sc)
348{
349	struct ifnet *ifp;
350	struct mbuf *m;
351	REGWTYPE md, val;
352	int32_t len, l;
353
354	/*
355	 * General problem here in case we need to sync ourselves to the
356	 * beginning of a packet.  Length will only be set for the first
357	 * read, and together with strb we can detect the begining (or
358	 * skip to tlast).
359	 */
360
361	len = NF10BMAC_READ(sc, NF10BMAC_RX_LEN) & NF10BMAC_DATA_LEN_MASK;
362	if (len > (MCLBYTES - ETHER_ALIGN)) {
363		nf10bmac_eat_packet_munch_munch(sc);
364		return (0);
365	}
366
367	md = NF10BMAC_READ(sc, NF10BMAC_RX_META);
368	if (len == 0 && (md & NF10BMAC_DATA_STRB) == 0) {
369		/* No packet data available. */
370		return (0);
371	} else if (len == 0 && (md & NF10BMAC_DATA_STRB) != 0) {
372		/* We are in the middle of a packet. */
373		nf10bmac_eat_packet_munch_munch(sc);
374		return (0);
375	} else if ((md & NF10BMAC_DATA_STRB) == 0) {
376		/* Invalid length "hint". */
377		device_printf(sc->nf10bmac_dev,
378		    "Unexpected length %d on zero strb\n", len);
379		return (0);
380	}
381
382	/* Assume at this point that we have data and a full packet. */
383	if ((len + ETHER_ALIGN) >= MINCLSIZE) {
384		/* Get a cluster. */
385		m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
386		if (m == NULL)
387			return (0);
388		m->m_len = m->m_pkthdr.len = MCLBYTES;
389	} else {
390		/* Hey this still fits into the mbuf+pkthdr. */
391		m = m_gethdr(M_NOWAIT, MT_DATA);
392		if (m == NULL)
393			return (0);
394		m->m_len = m->m_pkthdr.len = MHLEN;
395	}
396	/* Make sure upper layers will be aligned. */
397	m_adj(m, ETHER_ALIGN);
398
399	ifp = sc->nf10bmac_ifp;
400	l = 0;
401/*
402	while ((md & NF10BMAC_DATA_STRB) != 0 && l < len) {
403*/
404	while (l < len) {
405		size_t cl;
406
407		if ((md & NF10BMAC_DATA_LAST) == 0 &&
408		    (len - l) < sizeof(val)) {
409			/*
410			 * Our length and LAST disagree. We have a valid STRB.
411			 * We could continue until we fill the mbuf and just
412			 * log the invlid length "hint".  For now drop the
413			 * packet on the floor and count the error.
414			 */
415			nf10bmac_eat_packet_munch_munch(sc);
416			ifp->if_ierrors++;
417			m_freem(m);
418			return (0);
419		} else if ((len - l) <= sizeof(val)) {
420			cl = len - l;
421		} else {
422			cl = sizeof(val);
423		}
424
425		/* Read the first bytes of data as well. */
426		val = NF10BMAC_READ_BE(sc, NF10BMAC_RX_DATA);
427		bcopy(&val, (uint8_t *)(m->m_data + l), cl);
428		l += cl;
429
430		if ((md & NF10BMAC_DATA_LAST) != 0 || l >= len)
431			break;
432		else {
433			DELAY(50);
434			md = NF10BMAC_READ(sc, NF10BMAC_RX_META);
435		}
436
437		cl = 10;
438		while ((md & NF10BMAC_DATA_STRB) == 0 && cl-- > 0) {
439			DELAY(10);
440			md = NF10BMAC_READ(sc, NF10BMAC_RX_META);
441		}
442	}
443	/* We should get out of this loop with tlast and tsrb. */
444	if ((md & NF10BMAC_DATA_LAST) == 0 || (md & NF10BMAC_DATA_STRB) == 0) {
445		device_printf(sc->nf10bmac_dev, "Unexpected rx loop end state: "
446		    "md=0x%08jx len=%d l=%d\n", (uintmax_t)md, len, l);
447		ifp->if_ierrors++;
448		m_freem(m);
449		return (0);
450	}
451
452	m->m_pkthdr.len = m->m_len = len;
453	m->m_pkthdr.rcvif = ifp;
454	ifp->if_ipackets++;
455
456	NF10BMAC_UNLOCK(sc);
457	(*ifp->if_input)(ifp, m);
458	NF10BMAC_LOCK(sc);
459
460	return (1);
461}
462
463
464static int
465nf10bmac_stop_locked(struct nf10bmac_softc *sc)
466{
467	struct ifnet *ifp;
468
469	NF10BMAC_LOCK_ASSERT(sc);
470
471#ifdef ENABLE_WATCHDOG
472	sc->nf10bmac_watchdog_timer = 0;
473	callout_stop(&sc->nf10bmac_tick);
474#endif
475
476	ifp = sc->nf10bmac_ifp;
477	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
478	NF10BMAC_RX_INTR_CLEAR_DIS(sc);
479
480	sc->nf10bmac_flags &= ~NF10BMAC_FLAGS_LINK;
481	if_link_state_change(ifp, LINK_STATE_DOWN);
482
483	return (0);
484}
485
486static int
487nf10bmac_reset(struct nf10bmac_softc *sc)
488{
489
490	/*
491	 * If we do not have an ether address set, initialize to the same
492	 * OUI as NetFPGA-10G Linux driver does (which luckily seems
493	 * unallocated).  We just change the NIC specific part from
494	 * the slightly long "\0NF10C0" to "\0NFBSD".
495	 * Oh and we keep the way of setting it from a string as they do.
496	 * It's an amazing way to hide it.
497	 * XXX-BZ If NetFPGA gets their own OUI we should fix this.
498	 */
499	if (sc->nf10bmac_eth_addr[0] == 0x00 &&
500	    sc->nf10bmac_eth_addr[1] == 0x00 &&
501	    sc->nf10bmac_eth_addr[2] == 0x00 &&
502	    sc->nf10bmac_eth_addr[3] == 0x00 &&
503	    sc->nf10bmac_eth_addr[4] == 0x00 &&
504	    sc->nf10bmac_eth_addr[5] == 0x00) {
505		memcpy(&sc->nf10bmac_eth_addr, "\0NFBSD", ETHER_ADDR_LEN);
506		sc->nf10bmac_eth_addr[5] += sc->nf10bmac_unit;
507	}
508
509	return (0);
510}
511
512static void
513nf10bmac_init_locked(struct nf10bmac_softc *sc)
514{
515	struct ifnet *ifp;
516	uint8_t *eaddr;
517
518	NF10BMAC_LOCK_ASSERT(sc);
519	ifp = sc->nf10bmac_ifp;
520
521	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
522		return;
523
524	/*
525	 * Must update the ether address if changed.  Given we do not handle
526	 * in nf10bmac_ioctl() but it's in the general framework, just always
527	 * do it here before nf10bmac_reset().
528	 */
529	eaddr = IF_LLADDR(sc->nf10bmac_ifp);
530	bcopy(eaddr, &sc->nf10bmac_eth_addr, ETHER_ADDR_LEN);
531	/* XXX-BZ we do not have any way to tell the NIC our ether address. */
532
533	/* Make things frind to halt, cleanup, ... */
534	nf10bmac_stop_locked(sc);
535	/* ... reset, ... */
536	nf10bmac_reset(sc);
537
538	/* Memory rings?  DMA engine? MC filter?  MII? */
539	/* Instead drain the FIFO; or at least a possible first packet.. */
540	nf10bmac_eat_packet_munch_munch(sc);
541
542#ifdef DEVICE_POLLING
543	/* Only enable interrupts if we are not polling. */
544	if (ifp->if_capenable & IFCAP_POLLING) {
545		NF10BMAC_RX_INTR_CLEAR_DIS(sc);
546	} else
547#endif
548	{
549		NF10BMAC_RX_INTR_ENABLE(sc);
550	}
551
552	ifp->if_drv_flags |= IFF_DRV_RUNNING;
553	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
554
555	/* We have no underlying media, fake link state. */
556	sc->nf10bmac_flags = NF10BMAC_FLAGS_LINK;	/* Always up. */
557	if_link_state_change(sc->nf10bmac_ifp, LINK_STATE_UP);
558
559#ifdef ENABLE_WATCHDOG
560	callout_reset(&sc->nf10bmac_tick, hz, nf10bmac_tick, sc);
561#endif
562}
563
564static void
565nf10bmac_init(void *xsc)
566{
567	struct nf10bmac_softc *sc;
568
569	sc = (struct nf10bmac_softc *)xsc;
570	NF10BMAC_LOCK(sc);
571	nf10bmac_init_locked(sc);
572	NF10BMAC_UNLOCK(sc);
573}
574
575#ifdef ENABLE_WATCHDOG
576static void
577nf10bmac_watchdog(struct nf10bmac_softc *sc)
578{
579
580	NF10BMAC_LOCK_ASSERT(sc);
581
582	if (sc->nf10bmac_watchdog_timer == 0 || --sc->nf10bmac_watchdog_timer > 0)
583		return;
584
585	device_printf(sc->nf10bmac_dev, "watchdog timeout\n");
586	sc->nf10bmac_ifp->if_oerrors++;
587
588	sc->nf10bmac_ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
589	nf10bmac_init_locked(sc);
590
591	if (!IFQ_DRV_IS_EMPTY(&sc->nf10bmac_ifp->if_snd))
592		nf10bmac_start_locked(sc->nf10bmac_ifp);
593}
594
595static void
596nf10bmac_tick(void *xsc)
597{
598	struct nf10bmac_softc *sc;
599	struct ifnet *ifp;
600
601	sc = (struct nf10bmac_softc *)xsc;
602	NF10BMAC_LOCK_ASSERT(sc);
603	ifp = sc->nf10bmac_ifp;
604
605	nf10bmac_watchdog(sc);
606	callout_reset(&sc->nf10bmac_tick, hz, nf10bmac_tick, sc);
607}
608#endif
609
610static void
611nf10bmac_intr(void *arg)
612{
613	struct nf10bmac_softc *sc;
614	struct ifnet *ifp;
615	int rx_npkts;
616
617	sc = (struct nf10bmac_softc *)arg;
618	ifp = sc->nf10bmac_ifp;
619
620	NF10BMAC_LOCK(sc);
621#ifdef DEVICE_POLLING
622	if (ifp->if_capenable & IFCAP_POLLING) {
623		NF10BMAC_UNLOCK(sc);
624		return;
625	}
626#endif
627
628	/* NF10BMAC_RX_INTR_DISABLE(sc); */
629	NF10BMAC_RX_INTR_CLEAR_DIS(sc);
630
631	/* We only have an RX interrupt and no status information. */
632	rx_npkts = 0;
633	while (rx_npkts < NF10BMAC_MAX_PKTS) {
634		int c;
635
636		c = nf10bmac_rx_locked(sc);
637		rx_npkts += c;
638		if (c == 0)
639			break;
640	}
641
642	if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
643		/* Re-enable interrupts. */
644		NF10BMAC_RX_INTR_ENABLE(sc);
645
646		if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
647			nf10bmac_start_locked(ifp);
648	}
649	NF10BMAC_UNLOCK(sc);
650}
651
652
653#ifdef DEVICE_POLLING
654static int
655nf10bmac_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
656{
657	struct nf10bmac_softc *sc;
658	int rx_npkts = 0;
659
660	sc = ifp->if_softc;
661	NF10BMAC_LOCK(sc);
662	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
663		NF10BMAC_UNLOCK(sc);
664		return (rx_npkts);
665	}
666
667	while (rx_npkts < count) {
668		int c;
669
670		c = nf10bmac_rx_locked(sc);
671		rx_npkts += c;
672		if (c == 0)
673			break;
674	}
675	nf10bmac_start_locked(ifp);
676
677	if (rx_npkts > 0 || cmd == POLL_AND_CHECK_STATUS) {
678		/* We currently cannot do much. */
679		;
680	}
681
682        NF10BMAC_UNLOCK(sc);
683        return (rx_npkts);
684}
685#else
686#error We only support polling mode
687#endif /* DEVICE_POLLING */
688
689static int
690nf10bmac_media_change(struct ifnet *ifp __unused)
691{
692
693	/* Do nothing. */
694	return (0);
695}
696
697static void
698nf10bmac_media_status(struct ifnet *ifp __unused, struct ifmediareq *imr)
699{
700
701	imr->ifm_status = IFM_AVALID | IFM_ACTIVE;
702	imr->ifm_active = IFM_ETHER | IFM_10G_T | IFM_FDX;
703}
704
705static int
706nf10bmac_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
707{
708	struct nf10bmac_softc *sc;
709	struct ifreq *ifr;
710	int error, mask;
711
712	error = 0;
713	sc = ifp->if_softc;
714	ifr = (struct ifreq *)data;
715
716	switch (command) {
717	case SIOCSIFFLAGS:
718		NF10BMAC_LOCK(sc);
719		if (ifp->if_flags & IFF_UP) {
720			if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0 &&
721			    ((ifp->if_flags ^ sc->nf10bmac_if_flags) &
722			    (IFF_PROMISC | IFF_ALLMULTI)) != 0)
723				/* Nothing we can do. */ ;
724			else
725				nf10bmac_init_locked(sc);
726		} else if (ifp->if_drv_flags & IFF_DRV_RUNNING)
727			nf10bmac_stop_locked(sc);
728		sc->nf10bmac_if_flags = ifp->if_flags;
729		NF10BMAC_UNLOCK(sc);
730		break;
731	case SIOCSIFCAP:
732		NF10BMAC_LOCK(sc);
733		mask = ifr->ifr_reqcap ^ ifp->if_capenable;
734#ifdef DEVICE_POLLING
735		if ((mask & IFCAP_POLLING) != 0 &&
736		    (IFCAP_POLLING & ifp->if_capabilities) != 0) {
737			ifp->if_capenable ^= IFCAP_POLLING;
738			if ((IFCAP_POLLING & ifp->if_capenable) != 0) {
739
740				error = ether_poll_register(nf10bmac_poll, ifp);
741				if (error != 0) {
742					NF10BMAC_UNLOCK(sc);
743					break;
744				}
745
746				NF10BMAC_RX_INTR_CLEAR_DIS(sc);
747
748			/*
749			 * Do not allow disabling of polling if we do
750			 * not have interrupts.
751			 */
752			} else if (sc->nf10bmac_rx_irq_res != NULL) {
753				error = ether_poll_deregister(ifp);
754				/* Enable interrupts. */
755				NF10BMAC_RX_INTR_ENABLE(sc);
756			} else {
757				ifp->if_capenable ^= IFCAP_POLLING;
758				error = EINVAL;
759			}
760		}
761#endif /* DEVICE_POLLING */
762                NF10BMAC_UNLOCK(sc);
763                break;
764	case SIOCGIFMEDIA:
765	case SIOCSIFMEDIA:
766                error = ifmedia_ioctl(ifp, ifr, &sc->nf10bmac_media, command);
767		break;
768	default:
769		error = ether_ioctl(ifp, command, data);
770		break;
771	}
772
773	return (error);
774}
775
776/*
777 * Generic device handling routines.
778 */
779int
780nf10bmac_attach(device_t dev)
781{
782	struct nf10bmac_softc *sc;
783	struct ifnet *ifp;
784	int error;
785
786	sc = device_get_softc(dev);
787
788	mtx_init(&sc->nf10bmac_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
789	    MTX_DEF);
790
791#ifdef	ENABLE_WATCHDOG
792	callout_init_mtx(&sc->nf10bmac_tick, &sc->nf10bmac_mtx, 0);
793#endif
794
795	sc->nf10bmac_tx_buf = malloc(ETHER_MAX_LEN_JUMBO, M_DEVBUF, M_WAITOK);
796
797	/* Reset the adapter. */
798	nf10bmac_reset(sc);
799
800	/* Setup interface. */
801	ifp = sc->nf10bmac_ifp = if_alloc(IFT_ETHER);
802	if (ifp == NULL) {
803		device_printf(dev, "if_alloc() failed\n");
804		error = ENOSPC;
805		goto err;
806	}
807	ifp->if_softc = sc;
808	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
809	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; /* | IFF_MULTICAST; */
810	ifp->if_ioctl = nf10bmac_ioctl;
811	ifp->if_start = nf10bmac_start;
812	ifp->if_init = nf10bmac_init;
813	IFQ_SET_MAXLEN(&ifp->if_snd, NF10BMAC_MAX_PKTS - 1);
814	ifp->if_snd.ifq_drv_maxlen = NF10BMAC_MAX_PKTS - 1;
815	IFQ_SET_READY(&ifp->if_snd);
816
817	/* Call media-indepedent attach routine. */
818	ether_ifattach(ifp, sc->nf10bmac_eth_addr);
819
820	/* Tell the upper layer(s) about vlan mtu support. */
821	ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header);
822	ifp->if_capabilities |= IFCAP_VLAN_MTU;
823	ifp->if_capenable = ifp->if_capabilities;
824#ifdef DEVICE_POLLING
825	/* We will enable polling by default if no irqs available. See below. */
826	ifp->if_capabilities |= IFCAP_POLLING;
827#endif
828
829	/* We need more media attention.  Fake it! */
830        ifmedia_init(&sc->nf10bmac_media, 0, nf10bmac_media_change,
831	    nf10bmac_media_status);
832        ifmedia_add(&sc->nf10bmac_media, IFM_ETHER | IFM_10G_T, 0, NULL);
833        ifmedia_set(&sc->nf10bmac_media, IFM_ETHER | IFM_10G_T);
834
835	/* Initialise. */
836	error = 0;
837
838	/* Hook up interrupts. Well the one. */
839	if (sc->nf10bmac_rx_irq_res != NULL) {
840		error = bus_setup_intr(dev, sc->nf10bmac_rx_irq_res,
841		    INTR_TYPE_NET | INTR_MPSAFE, NULL, nf10bmac_intr,
842		    sc, &sc->nf10bmac_rx_intrhand);
843		if (error != 0) {
844			device_printf(dev, "enabling RX IRQ failed\n");
845			ether_ifdetach(ifp);
846			goto err;
847		}
848	}
849
850	if ((ifp->if_capenable & IFCAP_POLLING) != 0 ||
851	    sc->nf10bmac_rx_irq_res == NULL) {
852#ifdef DEVICE_POLLING
853		/* If not on and no IRQs force it on. */
854		if (sc->nf10bmac_rx_irq_res == NULL) {
855			ifp->if_capenable |= IFCAP_POLLING;
856			device_printf(dev,
857			    "forcing to polling due to no interrupts\n");
858		}
859		error = ether_poll_register(nf10bmac_poll, ifp);
860		if (error != 0)
861			goto err;
862#else
863		device_printf(dev, "no DEVICE_POLLING in kernel and no IRQs\n");
864		error = ENXIO;
865#endif
866	} else {
867		NF10BMAC_RX_INTR_ENABLE(sc);
868	}
869
870err:
871	if (error != 0)
872		nf10bmac_detach(dev);
873
874	return (error);
875}
876
877static int
878nf10bmac_detach(device_t dev)
879{
880	struct nf10bmac_softc *sc;
881	struct ifnet *ifp;
882
883	sc = device_get_softc(dev);
884	KASSERT(mtx_initialized(&sc->nf10bmac_mtx),
885	    ("%s: mutex not initialized", device_get_nameunit(dev)));
886	ifp = sc->nf10bmac_ifp;
887
888#ifdef DEVICE_POLLING
889	if (ifp->if_capenable & IFCAP_POLLING)
890		ether_poll_deregister(ifp);
891#endif
892
893	/* Only cleanup if attach succeeded. */
894	if (device_is_attached(dev)) {
895		NF10BMAC_LOCK(sc);
896		nf10bmac_stop_locked(sc);
897		NF10BMAC_UNLOCK(sc);
898#ifdef ENABLE_WATCHDOG
899		callout_drain(&sc->nf10bmac_tick);
900#endif
901		ether_ifdetach(ifp);
902	}
903
904	if (sc->nf10bmac_rx_intrhand)
905		bus_teardown_intr(dev, sc->nf10bmac_rx_irq_res,
906		    sc->nf10bmac_rx_intrhand);
907
908	if (ifp != NULL)
909		if_free(ifp);
910	ifmedia_removeall(&sc->nf10bmac_media);
911
912	mtx_destroy(&sc->nf10bmac_mtx);
913
914	return (0);
915}
916
917/* Shared with the attachment specific (e.g., fdt) implementation. */
918void
919nf10bmac_detach_resources(device_t dev)
920{
921	struct nf10bmac_softc *sc;
922
923	sc = device_get_softc(dev);
924
925	if (sc->nf10bmac_rx_irq_res != NULL) {
926		bus_release_resource(dev, SYS_RES_IRQ, sc->nf10bmac_rx_irq_rid,
927		    sc->nf10bmac_rx_irq_res);
928		sc->nf10bmac_rx_irq_res = NULL;
929	}
930	if (sc->nf10bmac_intr_res != NULL) {
931		bus_release_resource(dev, SYS_RES_MEMORY,
932		    sc->nf10bmac_intr_rid, sc->nf10bmac_intr_res);
933		sc->nf10bmac_intr_res = NULL;
934	}
935	if (sc->nf10bmac_rx_mem_res != NULL) {
936		bus_release_resource(dev, SYS_RES_MEMORY,
937		    sc->nf10bmac_rx_mem_rid, sc->nf10bmac_rx_mem_res);
938		sc->nf10bmac_rx_mem_res = NULL;
939	}
940	if (sc->nf10bmac_tx_mem_res != NULL) {
941		bus_release_resource(dev, SYS_RES_MEMORY,
942		    sc->nf10bmac_tx_mem_rid, sc->nf10bmac_tx_mem_res);
943		sc->nf10bmac_tx_mem_res = NULL;
944	}
945	if (sc->nf10bmac_ctrl_res != NULL) {
946		bus_release_resource(dev, SYS_RES_MEMORY,
947		    sc->nf10bmac_ctrl_rid, sc->nf10bmac_ctrl_res);
948		sc->nf10bmac_ctrl_res = NULL;
949	}
950}
951
952int
953nf10bmac_detach_dev(device_t dev)
954{
955	int error;
956
957	error = nf10bmac_detach(dev);
958	if (error) {
959		/* We are basically in undefined state now. */
960		device_printf(dev, "nf10bmac_detach() failed: %d\n", error);
961		return (error);
962	}
963
964	nf10bmac_detach_resources(dev);
965
966	return (0);
967}
968
969/* end */
970