if_nf10bmac.c revision 264601
1251875Speter/*-
2251875Speter * Copyright (c) 2012-2014 Bjoern A. Zeeb
3251875Speter * All rights reserved.
4251875Speter *
5251875Speter * This software was developed by SRI International and the University of
6251875Speter * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249
7251875Speter * ("MRC2"), as part of the DARPA MRC research programme.
8251875Speter *
9251875Speter * Redistribution and use in source and binary forms, with or without
10251875Speter * modification, are permitted provided that the following conditions
11251875Speter * are met:
12251875Speter * 1. Redistributions of source code must retain the above copyright
13251875Speter *    notice, this list of conditions and the following disclaimer.
14251875Speter * 2. Redistributions in binary form must reproduce the above copyright
15251875Speter *    notice, this list of conditions and the following disclaimer in the
16251875Speter *    documentation and/or other materials provided with the distribution.
17251875Speter *
18251875Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19251875Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20251875Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21251875Speter * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22251875Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23251875Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24251875Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25251875Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26251875Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27251875Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28251875Speter * SUCH DAMAGE.
29251875Speter *
30251875Speter * This driver is modelled after atse(4).  We need to seriously reduce the
31251875Speter * per-driver code we have to write^wcopy & paste.
32251875Speter *
33251875Speter * TODO:
34251875Speter * - figure out on the HW side why some data is LE and some is BE.
35251875Speter * - general set of improvements possible (e.g., reduce times of copying,
36251875Speter *   do on-the-copy checksum calculations)
37251875Speter */
38251875Speter
39251875Speter#include <sys/cdefs.h>
40251875Speter__FBSDID("$FreeBSD: head/sys/dev/netfpga10g/nf10bmac/if_nf10bmac.c 264601 2014-04-17 12:33:26Z bz $");
41251875Speter
42251875Speter#include "opt_device_polling.h"
43251875Speter
44251875Speter#include <sys/param.h>
45251875Speter#include <sys/systm.h>
46251875Speter#include <sys/kernel.h>
47251875Speter#include <sys/bus.h>
48251875Speter#include <sys/endian.h>
49251875Speter#include <sys/lock.h>
50251875Speter#include <sys/module.h>
51251875Speter#include <sys/mutex.h>
52251875Speter#include <sys/proc.h>
53251875Speter#include <sys/socket.h>
54251875Speter#include <sys/sockio.h>
55251875Speter#include <sys/types.h>
56251875Speter
57251875Speter#include <net/ethernet.h>
58251875Speter#include <net/if.h>
59251875Speter#include <net/if_var.h>
60251875Speter#include <net/if_dl.h>
61251875Speter#include <net/if_media.h>
62251875Speter#include <net/if_types.h>
63251875Speter#include <net/if_vlan_var.h>
64251875Speter
65251875Speter#include <net/bpf.h>
66251875Speter
67251875Speter#include <machine/bus.h>
68251875Speter#include <machine/resource.h>
69251875Speter#include <sys/rman.h>
70251875Speter
71251875Speter#include "if_nf10bmacreg.h"
72251875Speter
73251875Speter#ifndef	NF10BMAC_MAX_PKTS
74251875Speter/*
75251875Speter * We have a 4k buffer in HW, so do not try to send more than 3 packets.
76251875Speter * At the time of writing HW is orders of magnitude faster than we can
77251875Speter * enqueue so it would not matter but need an escape.
78251875Speter */
79251875Speter#define	NF10BMAC_MAX_PKTS		3
80251875Speter#endif
81251875Speter
82251875Speter#ifndef NF10BMAC_WATCHDOG_TIME
83251875Speter#define	NF10BMAC_WATCHDOG_TIME		5	/* seconds */
84251875Speter#endif
85251875Speter
86251875Speter#ifdef DEVICE_POLLING
87251875Speterstatic poll_handler_t nf10bmac_poll;
88251875Speter#endif
89251875Speter
90251875Speter#define	NF10BMAC_LOCK(_sc)		mtx_lock(&(_sc)->nf10bmac_mtx)
91251875Speter#define	NF10BMAC_UNLOCK(_sc)		mtx_unlock(&(_sc)->nf10bmac_mtx)
92251875Speter#define	NF10BMAC_LOCK_ASSERT(_sc)	\
93251875Speter	mtx_assert(&(_sc)->nf10bmac_mtx, MA_OWNED)
94251875Speter
95251875Speter#define	NF10BMAC_TX_LEN			0x08
96251875Speter#define	NF10BMAC_TX_META		0x04
97251875Speter#define	NF10BMAC_TX_DATA		0x00
98251875Speter#define	NF10BMAC_RX_LEN			0x08
99251875Speter#define	NF10BMAC_RX_META		0x04
100251875Speter#define	NF10BMAC_RX_DATA		0x00
101251875Speter#define	NF10BMAC_CTRL0			0x00
102251875Speter
103251875Speter#define NF10BMAC_TUSER_MAC0		(1 << 0)
104251875Speter#define NF10BMAC_TUSER_CPU0		(1 << 1)
105251875Speter#define NF10BMAC_TUSER_MAC1		(1 << 2)
106251875Speter#define NF10BMAC_TUSER_CPU1		(1 << 3)
107251875Speter#define NF10BMAC_TUSER_MAC2		(1 << 4)
108251875Speter#define NF10BMAC_TUSER_CPU2		(1 << 5)
109251875Speter#define NF10BMAC_TUSER_MAC3		(1 << 6)
110251875Speter#define NF10BMAC_TUSER_CPU3		(1 << 7)
111251875Speter
112251875Speter#define	NF10BMAC_DATA_DPORT_MASK	0xff000000
113251875Speter#define	NF10BMAC_DATA_DPORT_SHIFT	24
114251875Speter#define	NF10BMAC_DATA_SPORT_MASK	0x00ff0000
115251875Speter#define	NF10BMAC_DATA_SPORT_SHIFT	16
116251875Speter#define	NF10BMAC_DATA_LAST		0x00000080
117251875Speter#define	NF10BMAC_DATA_STRB		0x0000000f
118251875Speter
119251875Speter
120251875Speterstatic inline void
121251875Speternf10bmac_write_4(struct resource *res, uint32_t reg, uint32_t val4,
122251875Speter    const char *f __unused, const int l __unused)
123251875Speter{
124251875Speter
125251875Speter	bus_write_4(res, reg, htole32(val4));
126251875Speter}
127251875Speter
128251875Speterstatic inline uint32_t
129251875Speternf10bmac_read_4(struct resource *res, uint32_t reg,
130251875Speter    const char *f __unused, const int l __unused)
131251875Speter{
132251875Speter
133251875Speter	return (le32toh(bus_read_4(res, reg)));
134251875Speter}
135251875Speter
136251875Speterstatic inline void
137251875Speternf10bmac_write_4_be(struct resource *res, uint32_t reg, uint32_t val4,
138251875Speter    const char *f __unused, const int l __unused)
139251875Speter{
140251875Speter
141251875Speter	bus_write_4(res, reg, htobe32(val4));
142251875Speter}
143251875Speter
144251875Speter
145251875Speterstatic inline uint32_t
146251875Speternf10bmac_read_4_be(struct resource *res, uint32_t reg,
147251875Speter    const char *f __unused, const int l __unused)
148251875Speter{
149251875Speter
150251875Speter	return (be32toh(bus_read_4(res, reg)));
151251875Speter}
152251875Speter
153251875Speter#define	NF10BMAC_WRITE_CTRL_4(sc, reg, val)				\
154251875Speter	nf10bmac_write_4((sc)->nf10bmac_mem_res, (reg), (val),		\
155251875Speter	    __func__, __LINE__)
156251875Speter#define	NF10BMAC_WRITE_4(sc, reg, val)					\
157251875Speter	nf10bmac_write_4((sc)->nf10bmac_tx_mem_res, (reg), (val),	\
158251875Speter	    __func__, __LINE__)
159251875Speter#define	NF10BMAC_READ_4(sc, reg)					\
160251875Speter	nf10bmac_read_4((sc)->nf10bmac_rx_mem_res, (reg),		\
161251875Speter	    __func__, __LINE__)
162251875Speter#define	NF10BMAC_WRITE_4_BE(sc, reg, val)				\
163251875Speter	nf10bmac_write_4_be((sc)->nf10bmac_tx_mem_res, (reg), (val),	\
164251875Speter	    __func__, __LINE__)
165251875Speter#define	NF10BMAC_READ_4_BE(sc, reg)					\
166251875Speter	nf10bmac_read_4_be((sc)->nf10bmac_rx_mem_res, (reg),		\
167251875Speter	    __func__, __LINE__)
168251875Speter
169251875Speter#ifdef ENABLE_WATCHDOG
170251875Speterstatic void nf10bmac_tick(void *);
171251875Speter#endif
172251875Speterstatic int nf10bmac_detach(device_t);
173251875Speter
174251875Speterdevclass_t nf10bmac_devclass;
175251875Speter
176251875Speter
177251875Speterstatic int
178251875Speternf10bmac_tx_locked(struct nf10bmac_softc *sc, struct mbuf *m)
179251875Speter{
180251875Speter	int32_t len, l, ml;
181251875Speter	uint32_t m4, val4;
182251875Speter
183251875Speter	NF10BMAC_LOCK_ASSERT(sc);
184251875Speter
185251875Speter	KASSERT(m != NULL, ("%s: m is null: sc=%p", __func__, sc));
186251875Speter	KASSERT(m->m_flags & M_PKTHDR, ("%s: not a pkthdr: m=%p", __func__, m));
187251875Speter	/*
188251875Speter	 * Copy to buffer to minimize our pain as we can only store
189251875Speter	 * double words which, after the first mbuf gets out of alignment
190251875Speter	 * quite quickly.
191251875Speter	 */
192251875Speter	m_copydata(m, 0, m->m_pkthdr.len, sc->nf10bmac_tx_buf);
193251875Speter	len = m->m_pkthdr.len;
194251875Speter
195251875Speter	/* Write the length at start of packet. */
196251875Speter	NF10BMAC_WRITE_4(sc, NF10BMAC_TX_LEN, len);
197251875Speter
198251875Speter	/* Write the meta data and data. */
199251875Speter	ml = len / sizeof(val4);
200251875Speter	len -= (ml * sizeof(val4));
201251875Speter	for (l = 0; l <= ml; l++) {
202251875Speter		int32_t cl;
203251875Speter
204251875Speter		cl = sizeof(val4);
205251875Speter		m4 = (NF10BMAC_TUSER_CPU0 << NF10BMAC_DATA_SPORT_SHIFT);
206251875Speter		if (l == ml || (len == 0 && l == (ml - 1))) {
207251875Speter			if (l == ml && len == 0) {
208251875Speter				break;
209251875Speter			} else {
210251875Speter				uint8_t s;
211251875Speter				int sl;
212251875Speter
213251875Speter				if (l == (ml - 1))
214251875Speter					len = 4;
215251875Speter				cl = len;
216251875Speter
217251875Speter				for (s = 0, sl = len; sl > 0; sl--)
218251875Speter					s |= (1 << (sl - 1));
219251875Speter				m4 |= (s & NF10BMAC_DATA_STRB);
220251875Speter				m4 |= NF10BMAC_DATA_LAST;
221251875Speter			}
222251875Speter		} else {
223251875Speter			m4 |= NF10BMAC_DATA_STRB;
224251875Speter		}
225251875Speter		NF10BMAC_WRITE_4(sc, NF10BMAC_TX_META, m4);
226251875Speter		bcopy(&sc->nf10bmac_tx_buf[l*sizeof(val4)], &val4, cl);
227251875Speter		NF10BMAC_WRITE_4_BE(sc, NF10BMAC_TX_DATA, val4);
228251875Speter	}
229251875Speter
230251875Speter	/* If anyone is interested give them a copy. */
231251875Speter	BPF_MTAP(sc->nf10bmac_ifp, m);
232251875Speter
233251875Speter	m_freem(m);
234251875Speter
235251875Speter	return (0);
236251875Speter}
237251875Speter
238251875Speterstatic void
239251875Speternf10bmac_start_locked(struct ifnet *ifp)
240251875Speter{
241251875Speter	struct nf10bmac_softc *sc;
242251875Speter	int count, error;
243251875Speter
244	sc = ifp->if_softc;
245	NF10BMAC_LOCK_ASSERT(sc);
246
247	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
248	    IFF_DRV_RUNNING || (sc->nf10bmac_flags & NF10BMAC_FLAGS_LINK) == 0)
249		return;
250
251#ifdef ENABLE_WATCHDOG
252	/*
253	 * Disable the watchdog while sending, we are batching packets.
254	 * Though we should never reach 5 seconds, and are holding the lock,
255	 * but who knows.
256	 */
257	sc->nf10bmac_watchdog_timer = 0;
258#endif
259
260	/* Send up to MAX_PKTS_PER_TX_LOOP packets. */
261	for (count = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd) &&
262	    count < NF10BMAC_MAX_PKTS; count++) {
263		struct mbuf *m;
264
265		IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
266		if (m == NULL)
267			break;
268		error = nf10bmac_tx_locked(sc, m);
269		if (error != 0)
270			break;
271	}
272
273#ifdef ENABLE_WATCHDOG
274done:
275	/* If the IP core walks into Nekromanteion try to bail out. */
276	/* XXX-BZ useless until we have direct FIFO fill status feedback. */
277	if (count > 0)
278		sc->nf10bmac_watchdog_timer = NF10BMAC_WATCHDOG_TIME;
279#endif
280}
281
282static void
283nf10bmac_start(struct ifnet *ifp)
284{
285	struct nf10bmac_softc *sc;
286
287	sc = ifp->if_softc;
288	NF10BMAC_LOCK(sc);
289	nf10bmac_start_locked(ifp);
290	NF10BMAC_UNLOCK(sc);
291}
292
293static void
294nf10bmac_eat_packet_munch_munch(struct nf10bmac_softc *sc)
295{
296	uint32_t m4, val4;
297
298	do {
299		m4 = NF10BMAC_READ_4_BE(sc, NF10BMAC_RX_META);
300		if ((m4 & NF10BMAC_DATA_STRB) != 0)
301			val4 = NF10BMAC_READ_4_BE(sc, NF10BMAC_RX_DATA);
302	} while ((m4 & NF10BMAC_DATA_STRB) != 0 &&
303	    (m4 & NF10BMAC_DATA_LAST) == 0);
304}
305
306static int
307nf10bmac_rx_locked(struct nf10bmac_softc *sc)
308{
309	struct ifnet *ifp;
310	struct mbuf *m;
311	uint32_t m4, val4;
312	int32_t len, l;
313
314	/*
315	 * General problem here in case we need to sync ourselves to the
316	 * beginning of a packet.  Length will only be set for the first
317	 * read, and together with strb we can detect the begining (or
318	 * skip to tlast).
319	 */
320
321	len = NF10BMAC_READ_4(sc, NF10BMAC_RX_LEN);
322	if (len > (MCLBYTES - ETHER_ALIGN)) {
323		nf10bmac_eat_packet_munch_munch(sc);
324		return (0);
325	}
326
327	m4 = NF10BMAC_READ_4(sc, NF10BMAC_RX_META);
328	if (len == 0 && (m4 & NF10BMAC_DATA_STRB) == 0) {
329		/* No packet data available. */
330		return (0);
331	} else if (len == 0 && (m4 & NF10BMAC_DATA_STRB) != 0) {
332		/* We are in the middle of a packet. */
333		nf10bmac_eat_packet_munch_munch(sc);
334		return (0);
335	} else if ((m4 & NF10BMAC_DATA_STRB) == 0) {
336		/* Invalid length "hint". */
337		device_printf(sc->nf10bmac_dev,
338		    "Unexpected length %d on zero strb\n", len);
339		return (0);
340	}
341
342	/* Assume at this point that we have data and a full packet. */
343	if ((len + ETHER_ALIGN) >= MINCLSIZE) {
344		/* Get a cluster. */
345		m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
346		if (m == NULL)
347			return (0);
348		m->m_len = m->m_pkthdr.len = MCLBYTES;
349	} else {
350		/* Hey this still fits into the mbuf+pkthdr. */
351		m = m_gethdr(M_NOWAIT, MT_DATA);
352		if (m == NULL)
353			return (0);
354		m->m_len = m->m_pkthdr.len = MHLEN;
355	}
356	/* Make sure upper layers will be aligned. */
357	m_adj(m, ETHER_ALIGN);
358
359	ifp = sc->nf10bmac_ifp;
360	l = 0;
361/*
362	while ((m4 & NF10BMAC_DATA_STRB) != 0 && l < len) {
363*/
364	while (l < len) {
365		size_t cl;
366
367		if ((m4 & NF10BMAC_DATA_LAST) == 0 &&
368		    (len - l) < sizeof(val4)) {
369			/*
370			 * Our length and LAST disagree. We have a valid STRB.
371			 * We could continue until we fill the mbuf and just
372			 * log the invlid length "hint".  For now drop the
373			 * packet on the floor and count the error.
374			 */
375			nf10bmac_eat_packet_munch_munch(sc);
376			ifp->if_ierrors++;
377			m_freem(m);
378			return (0);
379		} else if ((len - l) <= sizeof(val4)) {
380			cl = len - l;
381		} else {
382			cl = sizeof(val4);
383		}
384
385		/* Read the first bytes of data as well. */
386		val4 = NF10BMAC_READ_4_BE(sc, NF10BMAC_RX_DATA);
387		bcopy(&val4, (uint8_t *)(m->m_data + l), cl);
388		l += cl;
389
390		if ((m4 & NF10BMAC_DATA_LAST) != 0 || l >= len)
391			break;
392		else {
393			DELAY(50);
394			m4 = NF10BMAC_READ_4(sc, NF10BMAC_RX_META);
395		}
396
397		cl = 10;
398		while ((m4 & NF10BMAC_DATA_STRB) == 0 && cl-- > 0) {
399			DELAY(10);
400			m4 = NF10BMAC_READ_4(sc, NF10BMAC_RX_META);
401		}
402	}
403	/* We should get out of this loop with tlast and tsrb. */
404	if ((m4 & NF10BMAC_DATA_LAST) == 0 || (m4 & NF10BMAC_DATA_STRB) == 0) {
405		device_printf(sc->nf10bmac_dev, "Unexpected rx loop end state: "
406		    "m4=0x%08x len=%d l=%d\n", m4, len, l);
407		ifp->if_ierrors++;
408		m_freem(m);
409		return (0);
410	}
411
412	m->m_pkthdr.len = m->m_len = len;
413	m->m_pkthdr.rcvif = ifp;
414	ifp->if_ipackets++;
415
416	NF10BMAC_UNLOCK(sc);
417	(*ifp->if_input)(ifp, m);
418	NF10BMAC_LOCK(sc);
419
420	return (1);
421}
422
423
424static int
425nf10bmac_stop_locked(struct nf10bmac_softc *sc)
426{
427	struct ifnet *ifp;
428
429	NF10BMAC_LOCK_ASSERT(sc);
430
431#ifdef ENABLE_WATCHDOG
432	sc->nf10bmac_watchdog_timer = 0;
433	callout_stop(&sc->nf10bmac_tick);
434#endif
435
436	ifp = sc->nf10bmac_ifp;
437	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
438
439	sc->nf10bmac_flags &= ~NF10BMAC_FLAGS_LINK;
440	if_link_state_change(ifp, LINK_STATE_DOWN);
441
442	return (0);
443}
444
445static int
446nf10bmac_reset(struct nf10bmac_softc *sc)
447{
448
449	/* Currently we cannot do anything. */
450	return (0);
451}
452
453static void
454nf10bmac_init_locked(struct nf10bmac_softc *sc)
455{
456	struct ifnet *ifp;
457	uint8_t *eaddr;
458
459	NF10BMAC_LOCK_ASSERT(sc);
460	ifp = sc->nf10bmac_ifp;
461
462	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
463		return;
464
465	/*
466	 * Must update the ether address if changed.  Given we do not handle
467	 * in nf10bmac_ioctl() but it's in the general framework, just always
468	 * do it here before nf10bmac_reset().
469	 */
470	eaddr = IF_LLADDR(sc->nf10bmac_ifp);
471	bcopy(eaddr, &sc->nf10bmac_eth_addr, ETHER_ADDR_LEN);
472	/* XXX-BZ we do not have any way to tell the NIC our ether address. */
473
474	/* Make things frind to halt, cleanup, ... */
475	nf10bmac_stop_locked(sc);
476	/* ... reset, ... */
477	nf10bmac_reset(sc);
478
479	/* Memory rings?  DMA engine? MC filter?  MII? */
480	/* Instead drain the FIFO; or at least a possible first packet.. */
481	nf10bmac_eat_packet_munch_munch(sc);
482
483	ifp->if_drv_flags |= IFF_DRV_RUNNING;
484	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
485
486	/* We have no underlying media, fake link state. */
487	sc->nf10bmac_flags = NF10BMAC_FLAGS_LINK;	/* Always up. */
488	if_link_state_change(sc->nf10bmac_ifp, LINK_STATE_UP);
489
490#ifdef ENABLE_WATCHDOG
491	callout_reset(&sc->nf10bmac_tick, hz, nf10bmac_tick, sc);
492#endif
493}
494
495static void
496nf10bmac_init(void *xsc)
497{
498	struct nf10bmac_softc *sc;
499
500	sc = (struct nf10bmac_softc *)xsc;
501	NF10BMAC_LOCK(sc);
502	nf10bmac_init_locked(sc);
503	NF10BMAC_UNLOCK(sc);
504}
505
506#ifdef ENABLE_WATCHDOG
507static void
508nf10bmac_watchdog(struct nf10bmac_softc *sc)
509{
510
511	NF10BMAC_LOCK_ASSERT(sc);
512
513	if (sc->nf10bmac_watchdog_timer == 0 || --sc->nf10bmac_watchdog_timer > 0)
514		return;
515
516	device_printf(sc->nf10bmac_dev, "watchdog timeout\n");
517	sc->nf10bmac_ifp->if_oerrors++;
518
519	sc->nf10bmac_ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
520	nf10bmac_init_locked(sc);
521
522	if (!IFQ_DRV_IS_EMPTY(&sc->nf10bmac_ifp->if_snd))
523		nf10bmac_start_locked(sc->nf10bmac_ifp);
524}
525
526static void
527nf10bmac_tick(void *xsc)
528{
529	struct nf10bmac_softc *sc;
530	struct ifnet *ifp;
531
532	sc = (struct nf10bmac_softc *)xsc;
533	NF10BMAC_LOCK_ASSERT(sc);
534	ifp = sc->nf10bmac_ifp;
535
536	nf10bmac_watchdog(sc);
537	callout_reset(&sc->nf10bmac_tick, hz, nf10bmac_tick, sc);
538}
539#endif
540
541#ifdef DEVICE_POLLING
542static int
543nf10bmac_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
544{
545	struct nf10bmac_softc *sc;
546	int rx_npkts = 0;
547
548	sc = ifp->if_softc;
549	NF10BMAC_LOCK(sc);
550	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
551		NF10BMAC_UNLOCK(sc);
552		return (rx_npkts);
553	}
554
555	while (rx_npkts < count) {
556		int c;
557
558		c = nf10bmac_rx_locked(sc);
559		rx_npkts += c;
560		if (c == 0)
561			break;
562	}
563	nf10bmac_start_locked(ifp);
564
565	if (rx_npkts > 0 || cmd == POLL_AND_CHECK_STATUS) {
566		/* We currently cannot do much. */
567		;
568	}
569
570        NF10BMAC_UNLOCK(sc);
571        return (rx_npkts);
572}
573#else
574#error We only support polling mode
575#endif /* DEVICE_POLLING */
576
577static int
578nf10bmac_media_change(struct ifnet *ifp __unused)
579{
580
581	/* Do nothing. */
582	return (0);
583}
584
585static void
586nf10bmac_media_status(struct ifnet *ifp __unused, struct ifmediareq *imr)
587{
588
589	imr->ifm_status = IFM_AVALID | IFM_ACTIVE;
590	imr->ifm_active = IFM_ETHER | IFM_10G_T | IFM_FDX;
591}
592
593static int
594nf10bmac_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
595{
596	struct nf10bmac_softc *sc;
597	struct ifreq *ifr;
598	int error, mask;
599
600	error = 0;
601	sc = ifp->if_softc;
602	ifr = (struct ifreq *)data;
603
604	switch (command) {
605	case SIOCSIFFLAGS:
606		NF10BMAC_LOCK(sc);
607		if (ifp->if_flags & IFF_UP) {
608			if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0 &&
609			    ((ifp->if_flags ^ sc->nf10bmac_if_flags) &
610			    (IFF_PROMISC | IFF_ALLMULTI)) != 0)
611				/* Nothing we can do. */ ;
612			else
613				nf10bmac_init_locked(sc);
614		} else if (ifp->if_drv_flags & IFF_DRV_RUNNING)
615			nf10bmac_stop_locked(sc);
616		sc->nf10bmac_if_flags = ifp->if_flags;
617		NF10BMAC_UNLOCK(sc);
618		break;
619	case SIOCSIFCAP:
620		NF10BMAC_LOCK(sc);
621		mask = ifr->ifr_reqcap ^ ifp->if_capenable;
622#ifdef DEVICE_POLLING
623		if ((mask & IFCAP_POLLING) != 0 &&
624		    (IFCAP_POLLING & ifp->if_capabilities) != 0) {
625			ifp->if_capenable ^= IFCAP_POLLING;
626			if ((IFCAP_POLLING & ifp->if_capenable) != 0) {
627
628				error = ether_poll_register(nf10bmac_poll, ifp);
629				if (error != 0) {
630					NF10BMAC_UNLOCK(sc);
631					break;
632				}
633
634			/*
635			 * Do not allow disabling of polling if we do
636			 * not have interrupts.
637			 */
638			} else {
639				ifp->if_capenable ^= IFCAP_POLLING;
640				error = EINVAL;
641			}
642		}
643#endif /* DEVICE_POLLING */
644                NF10BMAC_UNLOCK(sc);
645                break;
646	case SIOCGIFMEDIA:
647	case SIOCSIFMEDIA:
648                error = ifmedia_ioctl(ifp, ifr, &sc->nf10bmac_media, command);
649		break;
650	default:
651		error = ether_ioctl(ifp, command, data);
652		break;
653	}
654
655	return (error);
656}
657
658
659/*
660 * Generic device handling routines.
661 */
662int
663nf10bmac_attach(device_t dev)
664{
665	struct nf10bmac_softc *sc;
666	struct ifnet *ifp;
667	int error;
668
669	sc = device_get_softc(dev);
670
671	mtx_init(&sc->nf10bmac_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
672	    MTX_DEF);
673
674#ifdef	ENABLE_WATCHDOG
675	callout_init_mtx(&sc->nf10bmac_tick, &sc->nf10bmac_mtx, 0);
676#endif
677
678	sc->nf10bmac_tx_buf = malloc(ETHER_MAX_LEN_JUMBO, M_DEVBUF, M_WAITOK);
679
680	/* Reset the adapter. */
681	nf10bmac_reset(sc);
682
683	/* Setup interface. */
684	ifp = sc->nf10bmac_ifp = if_alloc(IFT_ETHER);
685	if (ifp == NULL) {
686		device_printf(dev, "if_alloc() failed\n");
687		error = ENOSPC;
688		goto err;
689	}
690	ifp->if_softc = sc;
691	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
692	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; /* | IFF_MULTICAST; */
693	ifp->if_ioctl = nf10bmac_ioctl;
694	ifp->if_start = nf10bmac_start;
695	ifp->if_init = nf10bmac_init;
696	IFQ_SET_MAXLEN(&ifp->if_snd, NF10BMAC_MAX_PKTS - 1);
697	ifp->if_snd.ifq_drv_maxlen = NF10BMAC_MAX_PKTS - 1;
698	IFQ_SET_READY(&ifp->if_snd);
699
700	/* Call media-indepedent attach routine. */
701	ether_ifattach(ifp, sc->nf10bmac_eth_addr);
702
703	/* Tell the upper layer(s) about vlan mtu support. */
704	ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header);
705	ifp->if_capabilities |= IFCAP_VLAN_MTU;
706	ifp->if_capenable = ifp->if_capabilities;
707#ifdef DEVICE_POLLING
708	/* We will enable polling by default if no irqs available. See below. */
709	ifp->if_capabilities |= IFCAP_POLLING;
710#endif
711
712	/* We need more media attention.  Fake it! */
713        ifmedia_init(&sc->nf10bmac_media, 0, nf10bmac_media_change,
714	    nf10bmac_media_status);
715        ifmedia_add(&sc->nf10bmac_media, IFM_ETHER | IFM_10G_T, 0, NULL);
716        ifmedia_set(&sc->nf10bmac_media, IFM_ETHER | IFM_10G_T);
717
718	/* Interrupts would go here. */
719
720#ifdef DEVICE_POLLING
721	ifp->if_capenable |= IFCAP_POLLING;
722	device_printf(dev, "forcing to polling due to no interrupts\n");
723	error = ether_poll_register(nf10bmac_poll, ifp);
724	if (error != 0)
725		goto err;
726#else
727	device_printf(dev, "no DEVICE_POLLING in kernel and no IRQs\n");
728	error = ENXIO;
729#endif
730
731err:
732	if (error != 0)
733		nf10bmac_detach(dev);
734
735	return (error);
736}
737
738static int
739nf10bmac_detach(device_t dev)
740{
741	struct nf10bmac_softc *sc;
742	struct ifnet *ifp;
743
744	sc = device_get_softc(dev);
745	KASSERT(mtx_initialized(&sc->nf10bmac_mtx),
746	    ("%s: mutex not initialized", device_get_nameunit(dev)));
747	ifp = sc->nf10bmac_ifp;
748
749#ifdef DEVICE_POLLING
750	if (ifp->if_capenable & IFCAP_POLLING)
751		ether_poll_deregister(ifp);
752#endif
753
754	/* Only cleanup if attach succeeded. */
755	if (device_is_attached(dev)) {
756		NF10BMAC_LOCK(sc);
757		nf10bmac_stop_locked(sc);
758		NF10BMAC_UNLOCK(sc);
759#ifdef ENABLE_WATCHDOG
760		callout_drain(&sc->nf10bmac_tick);
761#endif
762		ether_ifdetach(ifp);
763	}
764
765	if (ifp != NULL)
766		if_free(ifp);
767	ifmedia_removeall(&sc->nf10bmac_media);
768
769	mtx_destroy(&sc->nf10bmac_mtx);
770
771	return (0);
772}
773
774/* Shared with the attachment specific (e.g., fdt) implementation. */
775void
776nf10bmac_detach_resources(device_t dev)
777{
778	struct nf10bmac_softc *sc;
779
780	sc = device_get_softc(dev);
781
782	if (sc->nf10bmac_mem_res != NULL) {
783		bus_release_resource(dev, SYS_RES_MEMORY,
784		    sc->nf10bmac_mem_rid, sc->nf10bmac_mem_res);
785		sc->nf10bmac_mem_res = NULL;
786	}
787	if (sc->nf10bmac_rx_mem_res != NULL) {
788		bus_release_resource(dev, SYS_RES_MEMORY,
789		    sc->nf10bmac_rx_mem_rid, sc->nf10bmac_rx_mem_res);
790		sc->nf10bmac_rx_mem_res = NULL;
791	}
792	if (sc->nf10bmac_tx_mem_res != NULL) {
793		bus_release_resource(dev, SYS_RES_MEMORY,
794		    sc->nf10bmac_tx_mem_rid, sc->nf10bmac_tx_mem_res);
795		sc->nf10bmac_tx_mem_res = NULL;
796	}
797}
798
799int
800nf10bmac_detach_dev(device_t dev)
801{
802	int error;
803
804	error = nf10bmac_detach(dev);
805	if (error) {
806		/* We are basically in undefined state now. */
807		device_printf(dev, "nf10bmac_detach() failed: %d\n", error);
808		return (error);
809	}
810
811	nf10bmac_detach_resources(dev);
812
813	return (0);
814}
815
816/* end */
817