]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - sys/dev/netfpga10g/nf10bmac/if_nf10bmac.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / sys / dev / netfpga10g / nf10bmac / if_nf10bmac.c
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
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
87 static poll_handler_t nf10bmac_poll;
88 #endif
89
90 #define NF10BMAC_LOCK(_sc)              mtx_lock(&(_sc)->nf10bmac_mtx)
91 #define NF10BMAC_UNLOCK(_sc)            mtx_unlock(&(_sc)->nf10bmac_mtx)
92 #define NF10BMAC_LOCK_ASSERT(_sc)       \
93         mtx_assert(&(_sc)->nf10bmac_mtx, MA_OWNED)
94
95 #define NF10BMAC_CTRL0                  0x00
96 #define NF10BMAC_TX_DATA                0x00
97 #define NF10BMAC_TX_META                0x08
98 #define NF10BMAC_TX_LEN                 0x10
99 #define NF10BMAC_RX_DATA                0x00
100 #define NF10BMAC_RX_META                0x08
101 #define NF10BMAC_RX_LEN                 0x10
102 #define NF10BMAC_INTR_CLEAR_DIS         0x00
103 #define NF10BMAC_INTR_CTRL              0x08
104
105 #define NF10BMAC_TUSER_MAC0             (1 << 0)
106 #define NF10BMAC_TUSER_CPU0             (1 << 1)
107 #define NF10BMAC_TUSER_MAC1             (1 << 2)
108 #define NF10BMAC_TUSER_CPU1             (1 << 3)
109 #define NF10BMAC_TUSER_MAC2             (1 << 4)
110 #define NF10BMAC_TUSER_CPU2             (1 << 5)
111 #define NF10BMAC_TUSER_MAC3             (1 << 6)
112 #define NF10BMAC_TUSER_CPU3             (1 << 7)
113
114 #define NF10BMAC_DATA_LEN_MASK          0x0000ffff
115 #define NF10BMAC_DATA_DPORT_MASK        0xff000000
116 #define NF10BMAC_DATA_DPORT_SHIFT       24
117 #define NF10BMAC_DATA_SPORT_MASK        0x00ff0000
118 #define NF10BMAC_DATA_SPORT_SHIFT       16
119 #define NF10BMAC_DATA_LAST              0x00008000
120 #ifdef NF10BMAC_64BIT
121 #define NF10BMAC_DATA_STRB              0x000000ff
122 #define REGWTYPE                        uint64_t
123 #else
124 #define NF10BMAC_DATA_STRB              0x0000000f
125 #define REGWTYPE                        uint32_t
126 #endif
127
128
129 static inline void
130 nf10bmac_write(struct resource *res, REGWTYPE reg, REGWTYPE val,
131     const char *f __unused, const int l __unused)
132 {
133
134 #ifdef NF10BMAC_64BIT
135         bus_write_8(res, reg, htole64(val));
136 #else
137         bus_write_4(res, reg, htole32(val));
138 #endif
139 }
140
141 static inline REGWTYPE
142 nf10bmac_read(struct resource *res, REGWTYPE reg,
143     const char *f __unused, const int l __unused)
144 {
145
146 #ifdef NF10BMAC_64BIT
147         return (le64toh(bus_read_8(res, reg)));
148 #else
149         return (le32toh(bus_read_4(res, reg)));
150 #endif
151 }
152
153 static inline void
154 nf10bmac_write_be(struct resource *res, REGWTYPE reg, REGWTYPE val,
155     const char *f __unused, const int l __unused)
156 {
157
158 #ifdef NF10BMAC_64BIT
159         bus_write_8(res, reg, htobe64(val));
160 #else
161         bus_write_4(res, reg, htobe32(val));
162 #endif
163 }
164
165
166 static inline REGWTYPE
167 nf10bmac_read_be(struct resource *res, REGWTYPE reg,
168     const char *f __unused, const int l __unused)
169 {
170
171 #ifdef NF10BMAC_64BIT
172         return (be64toh(bus_read_8(res, reg)));
173 #else
174         return (be32toh(bus_read_4(res, reg)));
175 #endif
176 }
177
178 #define NF10BMAC_WRITE_CTRL(sc, reg, val)                               \
179         nf10bmac_write((sc)->nf10bmac_ctrl_res, (reg), (val),           \
180             __func__, __LINE__)
181 #define NF10BMAC_WRITE(sc, reg, val)                                    \
182         nf10bmac_write((sc)->nf10bmac_tx_mem_res, (reg), (val),         \
183             __func__, __LINE__)
184 #define NF10BMAC_READ(sc, reg)                                          \
185         nf10bmac_read((sc)->nf10bmac_rx_mem_res, (reg),                 \
186             __func__, __LINE__)
187 #define NF10BMAC_WRITE_BE(sc, reg, val)                                 \
188         nf10bmac_write_be((sc)->nf10bmac_tx_mem_res, (reg), (val),      \
189             __func__, __LINE__)
190 #define NF10BMAC_READ_BE(sc, reg)                                       \
191         nf10bmac_read_be((sc)->nf10bmac_rx_mem_res, (reg),              \
192             __func__, __LINE__)
193
194 #define NF10BMAC_WRITE_INTR(sc, reg, val, _f, _l)                       \
195         nf10bmac_write((sc)->nf10bmac_intr_res, (reg), (val),           \
196             (_f), (_l))
197
198 #define NF10BMAC_RX_INTR_CLEAR_DIS(sc)                                  \
199         NF10BMAC_WRITE_INTR((sc), NF10BMAC_INTR_CLEAR_DIS, 1,           \
200         __func__, __LINE__)
201 #define NF10BMAC_RX_INTR_ENABLE(sc)                                     \
202         NF10BMAC_WRITE_INTR((sc), NF10BMAC_INTR_CTRL, 1,                \
203         __func__, __LINE__)
204 #define NF10BMAC_RX_INTR_DISABLE(sc)                                    \
205         NF10BMAC_WRITE_INTR((sc), NF10BMAC_INTR_CTRL, 0,                \
206         __func__, __LINE__)
207
208
209 #ifdef ENABLE_WATCHDOG
210 static void nf10bmac_tick(void *);
211 #endif
212 static int nf10bmac_detach(device_t);
213
214 devclass_t nf10bmac_devclass;
215
216
217 static int
218 nf10bmac_tx_locked(struct nf10bmac_softc *sc, struct mbuf *m)
219 {
220         int32_t len, l, ml;
221         REGWTYPE md, val;
222
223         NF10BMAC_LOCK_ASSERT(sc);
224
225         KASSERT(m != NULL, ("%s: m is null: sc=%p", __func__, sc));
226         KASSERT(m->m_flags & M_PKTHDR, ("%s: not a pkthdr: m=%p", __func__, m));
227         /*
228          * Copy to buffer to minimize our pain as we can only store
229          * double words which, after the first mbuf gets out of alignment
230          * quite quickly.
231          */
232         m_copydata(m, 0, m->m_pkthdr.len, sc->nf10bmac_tx_buf);
233         len = m->m_pkthdr.len;
234
235         /* Write the length at start of packet. */
236         NF10BMAC_WRITE(sc, NF10BMAC_TX_LEN, len);
237
238         /* Write the meta data and data. */
239         ml = len / sizeof(val);
240         len -= (ml * sizeof(val));
241         for (l = 0; l <= ml; l++) {
242                 int32_t cl;
243
244                 cl = sizeof(val);
245                 md = (NF10BMAC_TUSER_CPU0 << NF10BMAC_DATA_SPORT_SHIFT);
246                 if (l == ml || (len == 0 && l == (ml - 1))) {
247                         if (l == ml && len == 0) {
248                                 break;
249                         } else {
250                                 uint8_t s;
251                                 int sl;
252
253                                 if (l == (ml - 1))
254                                         len = sizeof(val);
255                                 cl = len;
256
257                                 for (s = 0, sl = len; sl > 0; sl--)
258                                         s |= (1 << (sl - 1));
259                                 md |= (s & NF10BMAC_DATA_STRB);
260                                 md |= NF10BMAC_DATA_LAST;
261                         }
262                 } else {
263                         md |= NF10BMAC_DATA_STRB;
264                 }
265                 NF10BMAC_WRITE(sc, NF10BMAC_TX_META, md);
266                 bcopy(&sc->nf10bmac_tx_buf[l*sizeof(val)], &val, cl);
267                 NF10BMAC_WRITE_BE(sc, NF10BMAC_TX_DATA, val);   
268         }
269
270         /* If anyone is interested give them a copy. */
271         BPF_MTAP(sc->nf10bmac_ifp, m);
272
273         m_freem(m);
274
275         return (0);
276 }
277
278 static void
279 nf10bmac_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
314 done:
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
322 static void
323 nf10bmac_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
333 static void
334 nf10bmac_eat_packet_munch_munch(struct nf10bmac_softc *sc)
335 {
336         REGWTYPE md, val;
337
338         do {
339                 md = NF10BMAC_READ_BE(sc, NF10BMAC_RX_META);
340                 if ((md & NF10BMAC_DATA_STRB) != 0)
341                         val = NF10BMAC_READ_BE(sc, NF10BMAC_RX_DATA);
342         } while ((md & NF10BMAC_DATA_STRB) != 0 &&
343             (md & NF10BMAC_DATA_LAST) == 0);
344 }
345
346 static int
347 nf10bmac_rx_locked(struct nf10bmac_softc *sc)
348 {
349         struct ifnet *ifp;
350         struct mbuf *m;
351         REGWTYPE md, val;
352         int32_t len, l;
353
354         /*
355          * General problem here in case we need to sync ourselves to the
356          * beginning of a packet.  Length will only be set for the first
357          * read, and together with strb we can detect the begining (or
358          * skip to tlast).
359          */
360
361         len = NF10BMAC_READ(sc, NF10BMAC_RX_LEN) & NF10BMAC_DATA_LEN_MASK;
362         if (len > (MCLBYTES - ETHER_ALIGN)) {
363                 nf10bmac_eat_packet_munch_munch(sc);
364                 return (0);
365         }
366
367         md = NF10BMAC_READ(sc, NF10BMAC_RX_META);
368         if (len == 0 && (md & NF10BMAC_DATA_STRB) == 0) {
369                 /* No packet data available. */
370                 return (0);
371         } else if (len == 0 && (md & NF10BMAC_DATA_STRB) != 0) {
372                 /* We are in the middle of a packet. */
373                 nf10bmac_eat_packet_munch_munch(sc);
374                 return (0);
375         } else if ((md & NF10BMAC_DATA_STRB) == 0) {
376                 /* Invalid length "hint". */
377                 device_printf(sc->nf10bmac_dev,
378                     "Unexpected length %d on zero strb\n", len);
379                 return (0);
380         }
381
382         /* Assume at this point that we have data and a full packet. */
383         if ((len + ETHER_ALIGN) >= MINCLSIZE) {
384                 /* Get a cluster. */
385                 m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
386                 if (m == NULL)
387                         return (0);
388                 m->m_len = m->m_pkthdr.len = MCLBYTES;
389         } else {
390                 /* Hey this still fits into the mbuf+pkthdr. */
391                 m = m_gethdr(M_NOWAIT, MT_DATA);
392                 if (m == NULL)
393                         return (0);
394                 m->m_len = m->m_pkthdr.len = MHLEN;
395         }
396         /* Make sure upper layers will be aligned. */
397         m_adj(m, ETHER_ALIGN);
398
399         ifp = sc->nf10bmac_ifp;
400         l = 0;
401 /*
402         while ((md & NF10BMAC_DATA_STRB) != 0 && l < len) {
403 */
404         while (l < len) {
405                 size_t cl;
406
407                 if ((md & NF10BMAC_DATA_LAST) == 0 &&
408                     (len - l) < sizeof(val)) {
409                         /*
410                          * Our length and LAST disagree. We have a valid STRB.
411                          * We could continue until we fill the mbuf and just
412                          * log the invlid length "hint".  For now drop the
413                          * packet on the floor and count the error.
414                          */
415                         nf10bmac_eat_packet_munch_munch(sc);            
416                         ifp->if_ierrors++;
417                         m_freem(m);
418                         return (0);
419                 } else if ((len - l) <= sizeof(val)) {
420                         cl = len - l;
421                 } else {
422                         cl = sizeof(val);
423                 }
424
425                 /* Read the first bytes of data as well. */
426                 val = NF10BMAC_READ_BE(sc, NF10BMAC_RX_DATA);
427                 bcopy(&val, (uint8_t *)(m->m_data + l), cl);
428                 l += cl;
429
430                 if ((md & NF10BMAC_DATA_LAST) != 0 || l >= len)
431                         break;
432                 else {
433                         DELAY(50);
434                         md = NF10BMAC_READ(sc, NF10BMAC_RX_META);
435                 }
436
437                 cl = 10;
438                 while ((md & NF10BMAC_DATA_STRB) == 0 && cl-- > 0) {
439                         DELAY(10);
440                         md = NF10BMAC_READ(sc, NF10BMAC_RX_META);
441                 }
442         }
443         /* We should get out of this loop with tlast and tsrb. */
444         if ((md & NF10BMAC_DATA_LAST) == 0 || (md & NF10BMAC_DATA_STRB) == 0) {
445                 device_printf(sc->nf10bmac_dev, "Unexpected rx loop end state: "
446                     "md=0x%08jx len=%d l=%d\n", (uintmax_t)md, len, l);
447                 ifp->if_ierrors++;
448                 m_freem(m);
449                 return (0);
450         }
451
452         m->m_pkthdr.len = m->m_len = len;
453         m->m_pkthdr.rcvif = ifp;
454         ifp->if_ipackets++;
455
456         NF10BMAC_UNLOCK(sc);
457         (*ifp->if_input)(ifp, m);
458         NF10BMAC_LOCK(sc);
459
460         return (1);
461 }
462
463
464 static int
465 nf10bmac_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
486 static int
487 nf10bmac_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
512 static void
513 nf10bmac_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
564 static void
565 nf10bmac_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
576 static void
577 nf10bmac_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
595 static void
596 nf10bmac_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
610 static void
611 nf10bmac_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
654 static int
655 nf10bmac_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
689 static int
690 nf10bmac_media_change(struct ifnet *ifp __unused)
691 {
692
693         /* Do nothing. */
694         return (0);
695 }
696
697 static void
698 nf10bmac_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
705 static int
706 nf10bmac_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  */
779 int
780 nf10bmac_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
870 err:
871         if (error != 0)
872                 nf10bmac_detach(dev);
873
874         return (error);                                                                                                                                                                      
875 }
876
877 static int
878 nf10bmac_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. */
918 void
919 nf10bmac_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
952 int
953 nf10bmac_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 */