if_nf10bmac.c revision 267919
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: head/sys/dev/netfpga10g/nf10bmac/if_nf10bmac.c 267919 2014-06-26 17:03:08Z 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#define	NF10BMAC_DATA_STRB		0x0000000f
121
122
123static inline void
124nf10bmac_write(struct resource *res, uint32_t reg, uint32_t val,
125    const char *f __unused, const int l __unused)
126{
127
128	bus_write_4(res, reg, htole32(val));
129}
130
131static inline uint32_t
132nf10bmac_read(struct resource *res, uint32_t reg,
133    const char *f __unused, const int l __unused)
134{
135
136	return (le32toh(bus_read_4(res, reg)));
137}
138
139static inline void
140nf10bmac_write_be(struct resource *res, uint32_t reg, uint32_t val,
141    const char *f __unused, const int l __unused)
142{
143
144	bus_write_4(res, reg, htobe32(val));
145}
146
147
148static inline uint32_t
149nf10bmac_read_be(struct resource *res, uint32_t reg,
150    const char *f __unused, const int l __unused)
151{
152
153	return (be32toh(bus_read_4(res, reg)));
154}
155
156#define	NF10BMAC_WRITE_CTRL(sc, reg, val)				\
157	nf10bmac_write((sc)->nf10bmac_ctrl_res, (reg), (val),		\
158	    __func__, __LINE__)
159#define	NF10BMAC_WRITE(sc, reg, val)					\
160	nf10bmac_write((sc)->nf10bmac_tx_mem_res, (reg), (val),		\
161	    __func__, __LINE__)
162#define	NF10BMAC_READ(sc, reg)						\
163	nf10bmac_read((sc)->nf10bmac_rx_mem_res, (reg),			\
164	    __func__, __LINE__)
165#define	NF10BMAC_WRITE_BE(sc, reg, val)					\
166	nf10bmac_write_be((sc)->nf10bmac_tx_mem_res, (reg), (val),	\
167	    __func__, __LINE__)
168#define	NF10BMAC_READ_BE(sc, reg)					\
169	nf10bmac_read_be((sc)->nf10bmac_rx_mem_res, (reg),		\
170	    __func__, __LINE__)
171
172#define	NF10BMAC_WRITE_INTR(sc, reg, val, _f, _l)			\
173	nf10bmac_write((sc)->nf10bmac_intr_res, (reg), (val),		\
174	    (_f), (_l))
175
176#define	NF10BMAC_RX_INTR_CLEAR_DIS(sc)					\
177	NF10BMAC_WRITE_INTR((sc), NF10BMAC_INTR_CLEAR_DIS, 1,		\
178	__func__, __LINE__)
179#define	NF10BMAC_RX_INTR_ENABLE(sc)					\
180	NF10BMAC_WRITE_INTR((sc), NF10BMAC_INTR_CTRL, 1,		\
181	__func__, __LINE__)
182#define	NF10BMAC_RX_INTR_DISABLE(sc)					\
183	NF10BMAC_WRITE_INTR((sc), NF10BMAC_INTR_CTRL, 0,		\
184	__func__, __LINE__)
185
186
187#ifdef ENABLE_WATCHDOG
188static void nf10bmac_tick(void *);
189#endif
190static int nf10bmac_detach(device_t);
191
192devclass_t nf10bmac_devclass;
193
194
195static int
196nf10bmac_tx_locked(struct nf10bmac_softc *sc, struct mbuf *m)
197{
198	int32_t len, l, ml;
199	uint32_t md, val;
200
201	NF10BMAC_LOCK_ASSERT(sc);
202
203	KASSERT(m != NULL, ("%s: m is null: sc=%p", __func__, sc));
204	KASSERT(m->m_flags & M_PKTHDR, ("%s: not a pkthdr: m=%p", __func__, m));
205	/*
206	 * Copy to buffer to minimize our pain as we can only store
207	 * double words which, after the first mbuf gets out of alignment
208	 * quite quickly.
209	 */
210	m_copydata(m, 0, m->m_pkthdr.len, sc->nf10bmac_tx_buf);
211	len = m->m_pkthdr.len;
212
213	/* Write the length at start of packet. */
214	NF10BMAC_WRITE(sc, NF10BMAC_TX_LEN, len);
215
216	/* Write the meta data and data. */
217	ml = len / sizeof(val);
218	len -= (ml * sizeof(val));
219	for (l = 0; l <= ml; l++) {
220		int32_t cl;
221
222		cl = sizeof(val);
223		md = (NF10BMAC_TUSER_CPU0 << NF10BMAC_DATA_SPORT_SHIFT);
224		if (l == ml || (len == 0 && l == (ml - 1))) {
225			if (l == ml && len == 0) {
226				break;
227			} else {
228				uint8_t s;
229				int sl;
230
231				if (l == (ml - 1))
232					len = sizeof(val);
233				cl = len;
234
235				for (s = 0, sl = len; sl > 0; sl--)
236					s |= (1 << (sl - 1));
237				md |= (s & NF10BMAC_DATA_STRB);
238				md |= NF10BMAC_DATA_LAST;
239			}
240		} else {
241			md |= NF10BMAC_DATA_STRB;
242		}
243		NF10BMAC_WRITE(sc, NF10BMAC_TX_META, md);
244		bcopy(&sc->nf10bmac_tx_buf[l*sizeof(val)], &val, cl);
245		NF10BMAC_WRITE_BE(sc, NF10BMAC_TX_DATA, val);
246	}
247
248	/* If anyone is interested give them a copy. */
249	BPF_MTAP(sc->nf10bmac_ifp, m);
250
251	m_freem(m);
252
253	return (0);
254}
255
256static void
257nf10bmac_start_locked(struct ifnet *ifp)
258{
259	struct nf10bmac_softc *sc;
260	int count, error;
261
262	sc = ifp->if_softc;
263	NF10BMAC_LOCK_ASSERT(sc);
264
265	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
266	    IFF_DRV_RUNNING || (sc->nf10bmac_flags & NF10BMAC_FLAGS_LINK) == 0)
267		return;
268
269#ifdef ENABLE_WATCHDOG
270	/*
271	 * Disable the watchdog while sending, we are batching packets.
272	 * Though we should never reach 5 seconds, and are holding the lock,
273	 * but who knows.
274	 */
275	sc->nf10bmac_watchdog_timer = 0;
276#endif
277
278	/* Send up to MAX_PKTS_PER_TX_LOOP packets. */
279	for (count = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd) &&
280	    count < NF10BMAC_MAX_PKTS; count++) {
281		struct mbuf *m;
282
283		IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
284		if (m == NULL)
285			break;
286		error = nf10bmac_tx_locked(sc, m);
287		if (error != 0)
288			break;
289	}
290
291#ifdef ENABLE_WATCHDOG
292done:
293	/* If the IP core walks into Nekromanteion try to bail out. */
294	/* XXX-BZ useless until we have direct FIFO fill status feedback. */
295	if (count > 0)
296		sc->nf10bmac_watchdog_timer = NF10BMAC_WATCHDOG_TIME;
297#endif
298}
299
300static void
301nf10bmac_start(struct ifnet *ifp)
302{
303	struct nf10bmac_softc *sc;
304
305	sc = ifp->if_softc;
306	NF10BMAC_LOCK(sc);
307	nf10bmac_start_locked(ifp);
308	NF10BMAC_UNLOCK(sc);
309}
310
311static void
312nf10bmac_eat_packet_munch_munch(struct nf10bmac_softc *sc)
313{
314	uint32_t md, val;
315
316	do {
317		md = NF10BMAC_READ_BE(sc, NF10BMAC_RX_META);
318		if ((md & NF10BMAC_DATA_STRB) != 0)
319			val = NF10BMAC_READ_BE(sc, NF10BMAC_RX_DATA);
320	} while ((md & NF10BMAC_DATA_STRB) != 0 &&
321	    (md & NF10BMAC_DATA_LAST) == 0);
322}
323
324static int
325nf10bmac_rx_locked(struct nf10bmac_softc *sc)
326{
327	struct ifnet *ifp;
328	struct mbuf *m;
329	uint32_t md, val;
330	int32_t len, l;
331
332	/*
333	 * General problem here in case we need to sync ourselves to the
334	 * beginning of a packet.  Length will only be set for the first
335	 * read, and together with strb we can detect the begining (or
336	 * skip to tlast).
337	 */
338
339	len = NF10BMAC_READ(sc, NF10BMAC_RX_LEN) & NF10BMAC_DATA_LEN_MASK;
340	if (len > (MCLBYTES - ETHER_ALIGN)) {
341		nf10bmac_eat_packet_munch_munch(sc);
342		return (0);
343	}
344
345	md = NF10BMAC_READ(sc, NF10BMAC_RX_META);
346	if (len == 0 && (md & NF10BMAC_DATA_STRB) == 0) {
347		/* No packet data available. */
348		return (0);
349	} else if (len == 0 && (md & NF10BMAC_DATA_STRB) != 0) {
350		/* We are in the middle of a packet. */
351		nf10bmac_eat_packet_munch_munch(sc);
352		return (0);
353	} else if ((md & NF10BMAC_DATA_STRB) == 0) {
354		/* Invalid length "hint". */
355		device_printf(sc->nf10bmac_dev,
356		    "Unexpected length %d on zero strb\n", len);
357		return (0);
358	}
359
360	/* Assume at this point that we have data and a full packet. */
361	if ((len + ETHER_ALIGN) >= MINCLSIZE) {
362		/* Get a cluster. */
363		m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
364		if (m == NULL)
365			return (0);
366		m->m_len = m->m_pkthdr.len = MCLBYTES;
367	} else {
368		/* Hey this still fits into the mbuf+pkthdr. */
369		m = m_gethdr(M_NOWAIT, MT_DATA);
370		if (m == NULL)
371			return (0);
372		m->m_len = m->m_pkthdr.len = MHLEN;
373	}
374	/* Make sure upper layers will be aligned. */
375	m_adj(m, ETHER_ALIGN);
376
377	ifp = sc->nf10bmac_ifp;
378	l = 0;
379/*
380	while ((md & NF10BMAC_DATA_STRB) != 0 && l < len) {
381*/
382	while (l < len) {
383		size_t cl;
384
385		if ((md & NF10BMAC_DATA_LAST) == 0 &&
386		    (len - l) < sizeof(val)) {
387			/*
388			 * Our length and LAST disagree. We have a valid STRB.
389			 * We could continue until we fill the mbuf and just
390			 * log the invlid length "hint".  For now drop the
391			 * packet on the floor and count the error.
392			 */
393			nf10bmac_eat_packet_munch_munch(sc);
394			ifp->if_ierrors++;
395			m_freem(m);
396			return (0);
397		} else if ((len - l) <= sizeof(val)) {
398			cl = len - l;
399		} else {
400			cl = sizeof(val);
401		}
402
403		/* Read the first bytes of data as well. */
404		val = NF10BMAC_READ_BE(sc, NF10BMAC_RX_DATA);
405		bcopy(&val, (uint8_t *)(m->m_data + l), cl);
406		l += cl;
407
408		if ((md & NF10BMAC_DATA_LAST) != 0 || l >= len)
409			break;
410		else {
411			DELAY(50);
412			md = NF10BMAC_READ(sc, NF10BMAC_RX_META);
413		}
414
415		cl = 10;
416		while ((md & NF10BMAC_DATA_STRB) == 0 && cl-- > 0) {
417			DELAY(10);
418			md = NF10BMAC_READ(sc, NF10BMAC_RX_META);
419		}
420	}
421	/* We should get out of this loop with tlast and tsrb. */
422	if ((md & NF10BMAC_DATA_LAST) == 0 || (md & NF10BMAC_DATA_STRB) == 0) {
423		device_printf(sc->nf10bmac_dev, "Unexpected rx loop end state: "
424		    "md=0x%08x len=%d l=%d\n", md, len, l);
425		ifp->if_ierrors++;
426		m_freem(m);
427		return (0);
428	}
429
430	m->m_pkthdr.len = m->m_len = len;
431	m->m_pkthdr.rcvif = ifp;
432	ifp->if_ipackets++;
433
434	NF10BMAC_UNLOCK(sc);
435	(*ifp->if_input)(ifp, m);
436	NF10BMAC_LOCK(sc);
437
438	return (1);
439}
440
441
442static int
443nf10bmac_stop_locked(struct nf10bmac_softc *sc)
444{
445	struct ifnet *ifp;
446
447	NF10BMAC_LOCK_ASSERT(sc);
448
449#ifdef ENABLE_WATCHDOG
450	sc->nf10bmac_watchdog_timer = 0;
451	callout_stop(&sc->nf10bmac_tick);
452#endif
453
454	ifp = sc->nf10bmac_ifp;
455	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
456	NF10BMAC_RX_INTR_CLEAR_DIS(sc);
457
458	sc->nf10bmac_flags &= ~NF10BMAC_FLAGS_LINK;
459	if_link_state_change(ifp, LINK_STATE_DOWN);
460
461	return (0);
462}
463
464static int
465nf10bmac_reset(struct nf10bmac_softc *sc)
466{
467
468	/*
469	 * If we do not have an ether address set, initialize to the same
470	 * OUI as NetFPGA-10G Linux driver does (which luckily seems
471	 * unallocated).  We just change the NIC specific part from
472	 * the slightly long "\0NF10C0" to "\0NFBSD".
473	 * Oh and we keep the way of setting it from a string as they do.
474	 * It's an amazing way to hide it.
475	 * XXX-BZ If NetFPGA gets their own OUI we should fix this.
476	 */
477	if (sc->nf10bmac_eth_addr[0] == 0x00 &&
478	    sc->nf10bmac_eth_addr[1] == 0x00 &&
479	    sc->nf10bmac_eth_addr[2] == 0x00 &&
480	    sc->nf10bmac_eth_addr[3] == 0x00 &&
481	    sc->nf10bmac_eth_addr[4] == 0x00 &&
482	    sc->nf10bmac_eth_addr[5] == 0x00) {
483		memcpy(&sc->nf10bmac_eth_addr, "\0NFBSD", ETHER_ADDR_LEN);
484		sc->nf10bmac_eth_addr[5] += sc->nf10bmac_unit;
485	}
486
487	return (0);
488}
489
490static void
491nf10bmac_init_locked(struct nf10bmac_softc *sc)
492{
493	struct ifnet *ifp;
494	uint8_t *eaddr;
495
496	NF10BMAC_LOCK_ASSERT(sc);
497	ifp = sc->nf10bmac_ifp;
498
499	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
500		return;
501
502	/*
503	 * Must update the ether address if changed.  Given we do not handle
504	 * in nf10bmac_ioctl() but it's in the general framework, just always
505	 * do it here before nf10bmac_reset().
506	 */
507	eaddr = IF_LLADDR(sc->nf10bmac_ifp);
508	bcopy(eaddr, &sc->nf10bmac_eth_addr, ETHER_ADDR_LEN);
509	/* XXX-BZ we do not have any way to tell the NIC our ether address. */
510
511	/* Make things frind to halt, cleanup, ... */
512	nf10bmac_stop_locked(sc);
513	/* ... reset, ... */
514	nf10bmac_reset(sc);
515
516	/* Memory rings?  DMA engine? MC filter?  MII? */
517	/* Instead drain the FIFO; or at least a possible first packet.. */
518	nf10bmac_eat_packet_munch_munch(sc);
519
520#ifdef DEVICE_POLLING
521	/* Only enable interrupts if we are not polling. */
522	if (ifp->if_capenable & IFCAP_POLLING) {
523		NF10BMAC_RX_INTR_CLEAR_DIS(sc);
524	} else
525#endif
526	{
527		NF10BMAC_RX_INTR_ENABLE(sc);
528	}
529
530	ifp->if_drv_flags |= IFF_DRV_RUNNING;
531	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
532
533	/* We have no underlying media, fake link state. */
534	sc->nf10bmac_flags = NF10BMAC_FLAGS_LINK;	/* Always up. */
535	if_link_state_change(sc->nf10bmac_ifp, LINK_STATE_UP);
536
537#ifdef ENABLE_WATCHDOG
538	callout_reset(&sc->nf10bmac_tick, hz, nf10bmac_tick, sc);
539#endif
540}
541
542static void
543nf10bmac_init(void *xsc)
544{
545	struct nf10bmac_softc *sc;
546
547	sc = (struct nf10bmac_softc *)xsc;
548	NF10BMAC_LOCK(sc);
549	nf10bmac_init_locked(sc);
550	NF10BMAC_UNLOCK(sc);
551}
552
553#ifdef ENABLE_WATCHDOG
554static void
555nf10bmac_watchdog(struct nf10bmac_softc *sc)
556{
557
558	NF10BMAC_LOCK_ASSERT(sc);
559
560	if (sc->nf10bmac_watchdog_timer == 0 || --sc->nf10bmac_watchdog_timer > 0)
561		return;
562
563	device_printf(sc->nf10bmac_dev, "watchdog timeout\n");
564	sc->nf10bmac_ifp->if_oerrors++;
565
566	sc->nf10bmac_ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
567	nf10bmac_init_locked(sc);
568
569	if (!IFQ_DRV_IS_EMPTY(&sc->nf10bmac_ifp->if_snd))
570		nf10bmac_start_locked(sc->nf10bmac_ifp);
571}
572
573static void
574nf10bmac_tick(void *xsc)
575{
576	struct nf10bmac_softc *sc;
577	struct ifnet *ifp;
578
579	sc = (struct nf10bmac_softc *)xsc;
580	NF10BMAC_LOCK_ASSERT(sc);
581	ifp = sc->nf10bmac_ifp;
582
583	nf10bmac_watchdog(sc);
584	callout_reset(&sc->nf10bmac_tick, hz, nf10bmac_tick, sc);
585}
586#endif
587
588static void
589nf10bmac_intr(void *arg)
590{
591	struct nf10bmac_softc *sc;
592	struct ifnet *ifp;
593	int rx_npkts;
594
595	sc = (struct nf10bmac_softc *)arg;
596	ifp = sc->nf10bmac_ifp;
597
598	NF10BMAC_LOCK(sc);
599#ifdef DEVICE_POLLING
600	if (ifp->if_capenable & IFCAP_POLLING) {
601		NF10BMAC_UNLOCK(sc);
602		return;
603	}
604#endif
605
606	/* NF10BMAC_RX_INTR_DISABLE(sc); */
607	NF10BMAC_RX_INTR_CLEAR_DIS(sc);
608
609	/* We only have an RX interrupt and no status information. */
610	rx_npkts = 0;
611	while (rx_npkts < NF10BMAC_MAX_PKTS) {
612		int c;
613
614		c = nf10bmac_rx_locked(sc);
615		rx_npkts += c;
616		if (c == 0)
617			break;
618	}
619
620	if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
621		/* Re-enable interrupts. */
622		NF10BMAC_RX_INTR_ENABLE(sc);
623
624		if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
625			nf10bmac_start_locked(ifp);
626	}
627	NF10BMAC_UNLOCK(sc);
628}
629
630
631#ifdef DEVICE_POLLING
632static int
633nf10bmac_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
634{
635	struct nf10bmac_softc *sc;
636	int rx_npkts = 0;
637
638	sc = ifp->if_softc;
639	NF10BMAC_LOCK(sc);
640	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
641		NF10BMAC_UNLOCK(sc);
642		return (rx_npkts);
643	}
644
645	while (rx_npkts < count) {
646		int c;
647
648		c = nf10bmac_rx_locked(sc);
649		rx_npkts += c;
650		if (c == 0)
651			break;
652	}
653	nf10bmac_start_locked(ifp);
654
655	if (rx_npkts > 0 || cmd == POLL_AND_CHECK_STATUS) {
656		/* We currently cannot do much. */
657		;
658	}
659
660        NF10BMAC_UNLOCK(sc);
661        return (rx_npkts);
662}
663#else
664#error We only support polling mode
665#endif /* DEVICE_POLLING */
666
667static int
668nf10bmac_media_change(struct ifnet *ifp __unused)
669{
670
671	/* Do nothing. */
672	return (0);
673}
674
675static void
676nf10bmac_media_status(struct ifnet *ifp __unused, struct ifmediareq *imr)
677{
678
679	imr->ifm_status = IFM_AVALID | IFM_ACTIVE;
680	imr->ifm_active = IFM_ETHER | IFM_10G_T | IFM_FDX;
681}
682
683static int
684nf10bmac_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
685{
686	struct nf10bmac_softc *sc;
687	struct ifreq *ifr;
688	int error, mask;
689
690	error = 0;
691	sc = ifp->if_softc;
692	ifr = (struct ifreq *)data;
693
694	switch (command) {
695	case SIOCSIFFLAGS:
696		NF10BMAC_LOCK(sc);
697		if (ifp->if_flags & IFF_UP) {
698			if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0 &&
699			    ((ifp->if_flags ^ sc->nf10bmac_if_flags) &
700			    (IFF_PROMISC | IFF_ALLMULTI)) != 0)
701				/* Nothing we can do. */ ;
702			else
703				nf10bmac_init_locked(sc);
704		} else if (ifp->if_drv_flags & IFF_DRV_RUNNING)
705			nf10bmac_stop_locked(sc);
706		sc->nf10bmac_if_flags = ifp->if_flags;
707		NF10BMAC_UNLOCK(sc);
708		break;
709	case SIOCSIFCAP:
710		NF10BMAC_LOCK(sc);
711		mask = ifr->ifr_reqcap ^ ifp->if_capenable;
712#ifdef DEVICE_POLLING
713		if ((mask & IFCAP_POLLING) != 0 &&
714		    (IFCAP_POLLING & ifp->if_capabilities) != 0) {
715			ifp->if_capenable ^= IFCAP_POLLING;
716			if ((IFCAP_POLLING & ifp->if_capenable) != 0) {
717
718				error = ether_poll_register(nf10bmac_poll, ifp);
719				if (error != 0) {
720					NF10BMAC_UNLOCK(sc);
721					break;
722				}
723
724				NF10BMAC_RX_INTR_CLEAR_DIS(sc);
725
726			/*
727			 * Do not allow disabling of polling if we do
728			 * not have interrupts.
729			 */
730			} else if (sc->nf10bmac_rx_irq_res != NULL) {
731				error = ether_poll_deregister(ifp);
732				/* Enable interrupts. */
733				NF10BMAC_RX_INTR_ENABLE(sc);
734			} else {
735				ifp->if_capenable ^= IFCAP_POLLING;
736				error = EINVAL;
737			}
738		}
739#endif /* DEVICE_POLLING */
740                NF10BMAC_UNLOCK(sc);
741                break;
742	case SIOCGIFMEDIA:
743	case SIOCSIFMEDIA:
744                error = ifmedia_ioctl(ifp, ifr, &sc->nf10bmac_media, command);
745		break;
746	default:
747		error = ether_ioctl(ifp, command, data);
748		break;
749	}
750
751	return (error);
752}
753
754/*
755 * Generic device handling routines.
756 */
757int
758nf10bmac_attach(device_t dev)
759{
760	struct nf10bmac_softc *sc;
761	struct ifnet *ifp;
762	int error;
763
764	sc = device_get_softc(dev);
765
766	mtx_init(&sc->nf10bmac_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
767	    MTX_DEF);
768
769#ifdef	ENABLE_WATCHDOG
770	callout_init_mtx(&sc->nf10bmac_tick, &sc->nf10bmac_mtx, 0);
771#endif
772
773	sc->nf10bmac_tx_buf = malloc(ETHER_MAX_LEN_JUMBO, M_DEVBUF, M_WAITOK);
774
775	/* Reset the adapter. */
776	nf10bmac_reset(sc);
777
778	/* Setup interface. */
779	ifp = sc->nf10bmac_ifp = if_alloc(IFT_ETHER);
780	if (ifp == NULL) {
781		device_printf(dev, "if_alloc() failed\n");
782		error = ENOSPC;
783		goto err;
784	}
785	ifp->if_softc = sc;
786	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
787	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; /* | IFF_MULTICAST; */
788	ifp->if_ioctl = nf10bmac_ioctl;
789	ifp->if_start = nf10bmac_start;
790	ifp->if_init = nf10bmac_init;
791	IFQ_SET_MAXLEN(&ifp->if_snd, NF10BMAC_MAX_PKTS - 1);
792	ifp->if_snd.ifq_drv_maxlen = NF10BMAC_MAX_PKTS - 1;
793	IFQ_SET_READY(&ifp->if_snd);
794
795	/* Call media-indepedent attach routine. */
796	ether_ifattach(ifp, sc->nf10bmac_eth_addr);
797
798	/* Tell the upper layer(s) about vlan mtu support. */
799	ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header);
800	ifp->if_capabilities |= IFCAP_VLAN_MTU;
801	ifp->if_capenable = ifp->if_capabilities;
802#ifdef DEVICE_POLLING
803	/* We will enable polling by default if no irqs available. See below. */
804	ifp->if_capabilities |= IFCAP_POLLING;
805#endif
806
807	/* We need more media attention.  Fake it! */
808        ifmedia_init(&sc->nf10bmac_media, 0, nf10bmac_media_change,
809	    nf10bmac_media_status);
810        ifmedia_add(&sc->nf10bmac_media, IFM_ETHER | IFM_10G_T, 0, NULL);
811        ifmedia_set(&sc->nf10bmac_media, IFM_ETHER | IFM_10G_T);
812
813	/* Initialise. */
814	error = 0;
815
816	/* Hook up interrupts. Well the one. */
817	if (sc->nf10bmac_rx_irq_res != NULL) {
818		error = bus_setup_intr(dev, sc->nf10bmac_rx_irq_res,
819		    INTR_TYPE_NET | INTR_MPSAFE, NULL, nf10bmac_intr,
820		    sc, &sc->nf10bmac_rx_intrhand);
821		if (error != 0) {
822			device_printf(dev, "enabling RX IRQ failed\n");
823			ether_ifdetach(ifp);
824			goto err;
825		}
826	}
827
828	if ((ifp->if_capenable & IFCAP_POLLING) != 0 ||
829	    sc->nf10bmac_rx_irq_res == NULL) {
830#ifdef DEVICE_POLLING
831		/* If not on and no IRQs force it on. */
832		if (sc->nf10bmac_rx_irq_res == NULL) {
833			ifp->if_capenable |= IFCAP_POLLING;
834			device_printf(dev,
835			    "forcing to polling due to no interrupts\n");
836		}
837		error = ether_poll_register(nf10bmac_poll, ifp);
838		if (error != 0)
839			goto err;
840#else
841		device_printf(dev, "no DEVICE_POLLING in kernel and no IRQs\n");
842		error = ENXIO;
843#endif
844	} else {
845		NF10BMAC_RX_INTR_ENABLE(sc);
846	}
847
848err:
849	if (error != 0)
850		nf10bmac_detach(dev);
851
852	return (error);
853}
854
855static int
856nf10bmac_detach(device_t dev)
857{
858	struct nf10bmac_softc *sc;
859	struct ifnet *ifp;
860
861	sc = device_get_softc(dev);
862	KASSERT(mtx_initialized(&sc->nf10bmac_mtx),
863	    ("%s: mutex not initialized", device_get_nameunit(dev)));
864	ifp = sc->nf10bmac_ifp;
865
866#ifdef DEVICE_POLLING
867	if (ifp->if_capenable & IFCAP_POLLING)
868		ether_poll_deregister(ifp);
869#endif
870
871	/* Only cleanup if attach succeeded. */
872	if (device_is_attached(dev)) {
873		NF10BMAC_LOCK(sc);
874		nf10bmac_stop_locked(sc);
875		NF10BMAC_UNLOCK(sc);
876#ifdef ENABLE_WATCHDOG
877		callout_drain(&sc->nf10bmac_tick);
878#endif
879		ether_ifdetach(ifp);
880	}
881
882	if (sc->nf10bmac_rx_intrhand)
883		bus_teardown_intr(dev, sc->nf10bmac_rx_irq_res,
884		    sc->nf10bmac_rx_intrhand);
885
886	if (ifp != NULL)
887		if_free(ifp);
888	ifmedia_removeall(&sc->nf10bmac_media);
889
890	mtx_destroy(&sc->nf10bmac_mtx);
891
892	return (0);
893}
894
895/* Shared with the attachment specific (e.g., fdt) implementation. */
896void
897nf10bmac_detach_resources(device_t dev)
898{
899	struct nf10bmac_softc *sc;
900
901	sc = device_get_softc(dev);
902
903	if (sc->nf10bmac_rx_irq_res != NULL) {
904		bus_release_resource(dev, SYS_RES_IRQ, sc->nf10bmac_rx_irq_rid,
905		    sc->nf10bmac_rx_irq_res);
906		sc->nf10bmac_rx_irq_res = NULL;
907	}
908	if (sc->nf10bmac_intr_res != NULL) {
909		bus_release_resource(dev, SYS_RES_MEMORY,
910		    sc->nf10bmac_intr_rid, sc->nf10bmac_intr_res);
911		sc->nf10bmac_intr_res = NULL;
912	}
913	if (sc->nf10bmac_rx_mem_res != NULL) {
914		bus_release_resource(dev, SYS_RES_MEMORY,
915		    sc->nf10bmac_rx_mem_rid, sc->nf10bmac_rx_mem_res);
916		sc->nf10bmac_rx_mem_res = NULL;
917	}
918	if (sc->nf10bmac_tx_mem_res != NULL) {
919		bus_release_resource(dev, SYS_RES_MEMORY,
920		    sc->nf10bmac_tx_mem_rid, sc->nf10bmac_tx_mem_res);
921		sc->nf10bmac_tx_mem_res = NULL;
922	}
923	if (sc->nf10bmac_ctrl_res != NULL) {
924		bus_release_resource(dev, SYS_RES_MEMORY,
925		    sc->nf10bmac_ctrl_rid, sc->nf10bmac_ctrl_res);
926		sc->nf10bmac_ctrl_res = NULL;
927	}
928}
929
930int
931nf10bmac_detach_dev(device_t dev)
932{
933	int error;
934
935	error = nf10bmac_detach(dev);
936	if (error) {
937		/* We are basically in undefined state now. */
938		device_printf(dev, "nf10bmac_detach() failed: %d\n", error);
939		return (error);
940	}
941
942	nf10bmac_detach_resources(dev);
943
944	return (0);
945}
946
947/* end */
948