Deleted Added
full compact
if_nf10bmac.c (267919) if_nf10bmac.c (267920)
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>
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 $");
40__FBSDID("$FreeBSD: head/sys/dev/netfpga10g/nf10bmac/if_nf10bmac.c 267920 2014-06-26 17:10:07Z 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
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
120#define NF10BMAC_DATA_STRB 0x0000000f
124#define NF10BMAC_DATA_STRB 0x0000000f
125#define REGWTYPE uint32_t
126#endif
121
122
123static inline void
127
128
129static inline void
124nf10bmac_write(struct resource *res, uint32_t reg, uint32_t val,
130nf10bmac_write(struct resource *res, REGWTYPE reg, REGWTYPE val,
125 const char *f __unused, const int l __unused)
126{
127
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
128 bus_write_4(res, reg, htole32(val));
137 bus_write_4(res, reg, htole32(val));
138#endif
129}
130
139}
140
131static inline uint32_t
132nf10bmac_read(struct resource *res, uint32_t reg,
141static inline REGWTYPE
142nf10bmac_read(struct resource *res, REGWTYPE reg,
133 const char *f __unused, const int l __unused)
134{
135
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
136 return (le32toh(bus_read_4(res, reg)));
149 return (le32toh(bus_read_4(res, reg)));
150#endif
137}
138
139static inline void
151}
152
153static inline void
140nf10bmac_write_be(struct resource *res, uint32_t reg, uint32_t val,
154nf10bmac_write_be(struct resource *res, REGWTYPE reg, REGWTYPE val,
141 const char *f __unused, const int l __unused)
142{
143
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
144 bus_write_4(res, reg, htobe32(val));
161 bus_write_4(res, reg, htobe32(val));
162#endif
145}
146
147
163}
164
165
148static inline uint32_t
149nf10bmac_read_be(struct resource *res, uint32_t reg,
166static inline REGWTYPE
167nf10bmac_read_be(struct resource *res, REGWTYPE reg,
150 const char *f __unused, const int l __unused)
151{
152
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
153 return (be32toh(bus_read_4(res, reg)));
174 return (be32toh(bus_read_4(res, reg)));
175#endif
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;
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;
199 uint32_t md, val;
221 REGWTYPE 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{
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{
314 uint32_t md, val;
336 REGWTYPE 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;
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;
329 uint32_t md, val;
351 REGWTYPE 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: "
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: "
424 "md=0x%08x len=%d l=%d\n", md, len, l);
446 "md=0x%08jx len=%d l=%d\n", (uintmax_t)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 */
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 */