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