No empty .Rs/.Re
[netbsd-mini2440.git] / sys / arch / arm / gemini / if_gpn.c
blob0834956c0e0b4e5c1ea0a1299f59c82f61f89747
1 /* $NetBSD$ */
2 /*-
3 * Copyright (c) 2008 The NetBSD Foundation, Inc.
4 * All rights reserved.
6 * This code is derived from software contributed to The NetBSD Foundation
7 * by Matt Thomas <matt@3am-software.com>
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.
18 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
31 #include <sys/cdefs.h>
33 #include "opt_gemini.h"
34 #include "bpfilter.h"
36 __KERNEL_RCSID(0, "$NetBSD$");
38 #include <sys/param.h>
39 #include <sys/device.h>
40 #include <sys/mbuf.h>
41 #include <sys/ioctl.h>
43 #include <net/if.h>
44 #include <net/if_media.h>
45 #include <net/if_ether.h>
46 #include <net/if_dl.h>
48 #if NBPFILTER > 0
49 #include <net/bpf.h>
50 #endif
52 #include <machine/bus.h>
54 #include <arm/gemini/gemini_var.h>
55 #include <arm/gemini/gemini_ipm.h>
57 #define GPN_MOF 0x00 /* Middle Of Frame */
58 #define GPN_SOF 0x01 /* Start of Frame */
59 #define GPN_EOF 0x02 /* End of Frame */
60 #define GPN_FRAME 0x03 /* Complete Frame */
62 #define GPN_IFUP 0x05 /* partner is up */
63 #define GPN_IFDOWN 0x06 /* partner is down */
65 #define GPN_ACK0 0x10 /* placeholder */
66 #define GPN_ACK1 0x11 /* Ack 1 descriptor */
67 #define GPN_ACK2 0x12 /* Ack 2 descriptors */
68 #define GPN_ACK3 0x13 /* Ack 3 descriptors */
69 #define GPN_ACK4 0x14 /* Ack 4 descriptors */
70 #define GPN_ACK5 0x15 /* Ack 5 descriptors */
71 #define GPN_ACK6 0x16 /* Ack 6 descriptors */
72 #define GPN_ACK7 0x17 /* Ack 7 descriptors */
73 #define GPN_ACK8 0x18 /* Ack 8 descriptors */
74 #define GPN_ACK9 0x19 /* Ack 9 descriptors */
75 #define GPN_ACK10 0x1a /* Ack 10 descriptors */
76 #define GPN_ACK11 0x1b /* Ack 11 descriptors */
77 #define GPN_ACK12 0x1c /* Ack 12 descriptors */
78 #define GPN_ACK13 0x1d /* Ack 13 descriptors */
79 #define GPN_ACK14 0x1e /* Ack 14 descriptors */
81 typedef struct {
82 uint8_t gd_tag;
83 uint8_t gd_subtype;
84 uint8_t gd_txid;
85 uint8_t gd_pktlen64;
86 uint16_t gd_len1;
87 uint16_t gd_len2;
88 uint32_t gd_addr1;
89 uint32_t gd_addr2;
90 } ipm_gpn_desc_t;
92 typedef struct {
93 uint8_t agd_tag;
94 uint8_t agd_subtype;
95 uint8_t agd_txids[14];
96 } ipm_gpn_ack_desc_t;
98 #define MAX_TXACTIVE 60
100 struct gpn_txinfo {
101 struct mbuf *ti_mbuf;
102 bus_dmamap_t ti_map;
105 struct gpn_softc {
106 device_t sc_dev;
107 bus_dma_tag_t sc_dmat;
108 struct ifmedia sc_im;
109 struct ethercom sc_ec;
110 #define sc_if sc_ec.ec_if
111 size_t sc_free;
112 size_t sc_txactive;
113 void *sc_ih;
114 ipm_gpn_ack_desc_t sc_ack_desc;
115 struct mbuf *sc_rxmbuf;
116 struct gpn_txinfo sc_txinfo[MAX_TXACTIVE];
117 uint8_t sc_lastid;
118 bool sc_remoteup; /* remote side up? */
121 CTASSERT((GPN_SOF | GPN_EOF) == GPN_FRAME);
122 CTASSERT((GPN_SOF & GPN_EOF) == 0);
124 extern struct cfdriver gpn_cd;
126 static void gpn_ifstart(struct ifnet *);
128 #ifdef GPNDEBUG
129 static uint32_t
130 m_crc32_le(struct mbuf *m)
132 static const uint32_t crctab[] = {
133 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
134 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
135 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
136 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
138 uint32_t crc;
139 size_t i;
141 crc = 0xffffffffU; /* initial value */
143 for (; m; m = m->m_next) {
144 for (i = 0; i < m->m_len; i++) {
145 crc ^= m->m_data[i];
146 crc = (crc >> 4) ^ crctab[crc & 0xf];
147 crc = (crc >> 4) ^ crctab[crc & 0xf];
151 return (crc);
153 #endif
155 static void
156 gpn_free_dmamaps(struct gpn_softc *sc)
158 struct gpn_txinfo *ti = sc->sc_txinfo;
159 struct gpn_txinfo * const end_ti = ti + __arraycount(sc->sc_txinfo);
161 for (; ti < end_ti; ti++) {
162 if (ti->ti_map == NULL)
163 continue;
164 bus_dmamap_destroy(sc->sc_dmat, ti->ti_map);
165 ti->ti_map = NULL;
169 static int
170 gpn_alloc_dmamaps(struct gpn_softc *sc)
172 struct gpn_txinfo *ti = sc->sc_txinfo;
173 struct gpn_txinfo * const end_ti = ti + __arraycount(sc->sc_txinfo);
174 int error;
176 for (error = 0; ti < end_ti; ti++) {
177 if (ti->ti_map != NULL)
178 continue;
179 error = bus_dmamap_create(sc->sc_dmat,
180 10000, 2, 8192, 0,
181 BUS_DMA_ALLOCNOW|BUS_DMA_WAITOK,
182 &ti->ti_map);
183 if (error)
184 break;
187 if (error)
188 gpn_free_dmamaps(sc);
190 return error;
193 static bool
194 gpn_add_data(struct gpn_softc *sc, bus_addr_t addr, bus_size_t len)
196 struct mbuf *m, *m0;
197 size_t space;
199 m = sc->sc_rxmbuf;
200 KASSERT(m != NULL);
202 m->m_pkthdr.len += len;
204 while (m->m_next != NULL)
205 m = m->m_next;
207 KASSERT(len > 0);
208 space = M_TRAILINGSPACE(m);
209 for (;;) {
210 if (space > 0) {
211 if (len < space)
212 space = len;
213 gemini_ipm_copyin(mtod(m, uint8_t *) + m->m_len, addr,
214 space);
215 len -= space;
216 m->m_len += space;
217 if (len == 0)
218 return true;
219 addr += space;
221 MGET(m0, M_DONTWAIT, MT_DATA);
222 if (m0 == NULL)
223 break;
224 space = MLEN;
225 if (len > space) {
226 MCLGET(m0, M_DONTWAIT);
227 if (m0->m_flags & M_EXT)
228 space = MCLBYTES;
230 m->m_len = 0;
231 m->m_next = m0;
232 m = m0;
234 return false;
237 static void
238 gpn_ack_txid(struct gpn_softc *sc, unsigned int txid)
240 ipm_gpn_ack_desc_t * const agd = &sc->sc_ack_desc;
241 agd->agd_txids[agd->agd_subtype] = txid;
242 if (++agd->agd_subtype == __arraycount(agd->agd_txids)) {
243 agd->agd_subtype += GPN_ACK0;
244 sc->sc_free--;
245 gemini_ipm_produce(agd, 1);
246 agd->agd_subtype = 0;
250 static void
251 gpn_process_data(struct gpn_softc *sc, const ipm_gpn_desc_t *gd)
253 struct ifnet * const ifp = &sc->sc_if;
254 size_t pktlen = gd->gd_pktlen64 * 64;
255 unsigned int subtype = gd->gd_subtype;
256 bool ok;
258 if ((subtype & GPN_SOF) == 0 && sc->sc_rxmbuf == NULL) {
259 ifp->if_ierrors++;
260 goto out;
263 if ((subtype & GPN_SOF) && sc->sc_rxmbuf != NULL) {
264 ifp->if_ierrors++;
265 m_freem(sc->sc_rxmbuf);
266 sc->sc_rxmbuf = NULL;
269 if (sc->sc_rxmbuf == NULL) {
270 struct mbuf *m;
271 MGETHDR(m, M_DONTWAIT, MT_DATA);
272 if (m == NULL) {
273 ifp->if_ierrors++;
274 goto out;
276 if (pktlen > MHLEN - 2) {
277 MCLGET(m, M_DONTWAIT);
278 if ((m->m_flags & M_EXT) == 0) {
279 ifp->if_ierrors++;
280 m_free(m);
281 goto out;
284 m->m_data += 2; /* makes ethernet payload 32bit aligned */
285 m->m_len = 0;
286 m->m_pkthdr.len = 0;
287 sc->sc_rxmbuf = m;
290 ok = gpn_add_data(sc, gd->gd_addr1, gd->gd_len1);
291 if (ok && gd->gd_addr2 && gd->gd_len2)
292 ok = gpn_add_data(sc, gd->gd_addr2, gd->gd_len2);
293 if (!ok) {
294 ifp->if_ierrors++;
295 m_freem(sc->sc_rxmbuf);
296 sc->sc_rxmbuf = NULL;
297 goto out;
300 if (subtype & GPN_EOF) {
301 struct mbuf *m;
302 m = sc->sc_rxmbuf;
303 sc->sc_rxmbuf = NULL;
304 m->m_pkthdr.rcvif = ifp;
305 KASSERT(((m->m_pkthdr.len + 63) >> 6) == gd->gd_pktlen64);
306 ifp->if_ipackets++;
307 ifp->if_ibytes += m->m_pkthdr.len;
308 #if NBPFILTER > 0
309 if (ifp->if_bpf)
310 bpf_mtap(ifp->if_bpf, m);
311 #endif
312 #ifdef GPNDEBUG
313 printf("%s: rx len=%d crc=%#x\n", ifp->if_xname,
314 m->m_pkthdr.len, m_crc32_le(m));
315 #endif
316 (*ifp->if_input)(ifp, m);
319 out:
320 gpn_ack_txid(sc, gd->gd_txid);
323 static void
324 gpn_free_txid(struct gpn_softc *sc, size_t txid)
326 struct gpn_txinfo * const ti = sc->sc_txinfo + txid;
328 KASSERT(txid < MAX_TXACTIVE);
330 if (ti->ti_mbuf == NULL)
331 return;
333 bus_dmamap_sync(sc->sc_dmat, ti->ti_map,
334 0, ti->ti_mbuf->m_len, BUS_DMASYNC_POSTREAD);
335 bus_dmamap_unload(sc->sc_dmat, ti->ti_map);
336 m_freem(ti->ti_mbuf);
337 ti->ti_mbuf = NULL;
338 sc->sc_txactive--;
339 KASSERT(sc->sc_txactive < MAX_TXACTIVE);
340 if (sc->sc_if.if_flags & IFF_OACTIVE) {
341 sc->sc_if.if_flags &= ~IFF_OACTIVE;
342 gpn_ifstart(&sc->sc_if);
347 static void
348 gpn_ipm_rebate(void *arg, size_t count)
350 struct gpn_softc * const sc = arg;
351 int s;
353 s = splnet();
354 sc->sc_free += count;
356 sc->sc_if.if_flags &= ~IFF_OACTIVE;
357 gpn_ifstart(&sc->sc_if);
358 splx(s);
361 static void
362 gpn_ifstart(struct ifnet *ifp)
364 struct gpn_softc * const sc = ifp->if_softc;
366 for (;;) {
367 struct mbuf *m, *m0;
368 ipm_gpn_desc_t gd;
369 ipm_gpn_desc_t *last_gd;
370 size_t count;
372 if (sc->sc_free == 0) {
373 ifp->if_flags |= IFF_OACTIVE;
374 break;
377 IF_DEQUEUE(&ifp->if_snd, m);
378 if (!m)
379 break;
381 if ((ifp->if_flags & IFF_UP) == 0) {
382 m_freem(m);
383 continue;
387 * Make sure to send any pending acks first.
389 if (sc->sc_ack_desc.agd_subtype) {
390 sc->sc_free--;
391 sc->sc_ack_desc.agd_subtype += GPN_ACK0;
392 gemini_ipm_produce(&sc->sc_ack_desc, 1);
393 sc->sc_ack_desc.agd_subtype = 0;
397 * Let's find out how many mbufs we are using.
399 for (m0 = m, count = 0; m0; m0 = m0->m_next) {
400 if (m0->m_len == 0)
401 continue;
402 count++;
406 * Make sure there is always enough room.
408 if (sc->sc_free < count
409 || sc->sc_txactive + count > MAX_TXACTIVE) {
410 IF_PREPEND(&ifp->if_snd, m);
411 ifp->if_flags |= IFF_OACTIVE;
412 return;
415 #if NBPFILTER > 0
416 if (ifp->if_bpf)
417 bpf_mtap(ifp->if_bpf, m);
418 #endif
419 #ifdef GPNDEBUG
420 printf("%s: tx len=%d crc=%#x\n", ifp->if_xname,
421 m->m_pkthdr.len, m_crc32_le(m));
422 #endif
424 last_gd = NULL;
425 gd.gd_tag = IPM_TAG_GPN;
426 gd.gd_subtype = GPN_SOF;
427 gd.gd_pktlen64 = (m->m_pkthdr.len + 63) >> 6;
428 for (; m != NULL; m = m0) {
429 struct gpn_txinfo *ti;
430 bus_dmamap_t map;
431 size_t id;
432 int error;
434 m0 = m->m_next;
435 m->m_next = NULL;
436 if (m->m_len == 0) {
437 m_free(m);
438 continue;
440 if (last_gd) {
441 sc->sc_txactive++;
442 sc->sc_free--;
443 gemini_ipm_produce(last_gd, 1);
444 last_gd = NULL;
445 gd.gd_subtype = GPN_MOF;
447 for (id = sc->sc_lastid;
448 sc->sc_txinfo[id].ti_mbuf != NULL;) {
449 if (++id == __arraycount(sc->sc_txinfo))
450 id = 0;
452 KASSERT(id < MAX_TXACTIVE);
453 ti = sc->sc_txinfo + id;
454 map = ti->ti_map;
455 error = bus_dmamap_load(sc->sc_dmat, map,
456 mtod(m, void *), m->m_len, NULL,
457 BUS_DMA_READ|BUS_DMA_NOWAIT);
458 if (error) {
459 ifp->if_oerrors++;
460 m_freem(m);
461 break;
463 bus_dmamap_sync(sc->sc_dmat, map, 0,
464 m->m_len, BUS_DMASYNC_PREREAD);
465 KASSERT(map->dm_nsegs > 0);
466 KASSERT(map->dm_nsegs <= 2);
467 KASSERT(map->dm_segs[0].ds_addr != 0);
468 gd.gd_len1 = map->dm_segs[0].ds_len;
469 gd.gd_addr1 = map->dm_segs[0].ds_addr;
470 if (map->dm_nsegs == 1) {
471 gd.gd_len2 = 0;
472 gd.gd_addr2 = 0;
473 } else {
474 KASSERT(map->dm_segs[0].ds_addr != 0);
475 gd.gd_len2 = map->dm_segs[1].ds_len;
476 gd.gd_addr2 = map->dm_segs[1].ds_addr;
479 gd.gd_txid = id;
480 ti->ti_mbuf = m;
481 last_gd = &gd;
482 ifp->if_obytes += m->m_len;
484 ifp->if_opackets++;
485 last_gd->gd_subtype |= GPN_EOF;
486 sc->sc_txactive++;
487 sc->sc_free--;
488 gemini_ipm_produce(last_gd, 1);
492 static void
493 gpn_ipm_ifup(struct gpn_softc *sc)
495 sc->sc_remoteup = true;
496 if (sc->sc_if.if_flags & IFF_UP)
497 ifmedia_set(&sc->sc_im, IFM_ETHER|IFM_1000_T|IFM_FDX);
500 static void
501 gpn_ipm_ifdown(struct gpn_softc *sc)
503 struct gpn_txinfo *ti = sc->sc_txinfo;
504 struct gpn_txinfo * const end_ti = ti + __arraycount(sc->sc_txinfo);
506 if (sc->sc_rxmbuf) {
507 m_freem(sc->sc_rxmbuf);
508 sc->sc_rxmbuf = NULL;
511 IF_PURGE(&sc->sc_if.if_snd);
513 for (; ti < end_ti; ti++) {
514 if (ti->ti_mbuf == NULL)
515 continue;
516 bus_dmamap_sync(sc->sc_dmat, ti->ti_map,
517 0, ti->ti_mbuf->m_len, BUS_DMASYNC_POSTREAD);
518 bus_dmamap_unload(sc->sc_dmat, ti->ti_map);
519 m_freem(ti->ti_mbuf);
520 ti->ti_mbuf = NULL;
522 sc->sc_lastid = 0;
523 ifmedia_set(&sc->sc_im, IFM_ETHER|IFM_NONE);
524 sc->sc_remoteup = false;
527 static void
528 gpn_ipm_handler(void *arg, const void *desc)
530 struct gpn_softc * const sc = arg;
531 const ipm_gpn_desc_t * const gd = desc;
532 const ipm_gpn_ack_desc_t * const agd = desc;
533 int s;
535 s = splnet();
537 switch (gd->gd_subtype) {
538 case GPN_ACK14: gpn_free_txid(sc, agd->agd_txids[13]); /* FALLTHROUGH */
539 case GPN_ACK13: gpn_free_txid(sc, agd->agd_txids[12]); /* FALLTHROUGH */
540 case GPN_ACK12: gpn_free_txid(sc, agd->agd_txids[11]); /* FALLTHROUGH */
541 case GPN_ACK11: gpn_free_txid(sc, agd->agd_txids[10]); /* FALLTHROUGH */
542 case GPN_ACK10: gpn_free_txid(sc, agd->agd_txids[9]); /* FALLTHROUGH */
543 case GPN_ACK9: gpn_free_txid(sc, agd->agd_txids[8]); /* FALLTHROUGH */
544 case GPN_ACK8: gpn_free_txid(sc, agd->agd_txids[7]); /* FALLTHROUGH */
545 case GPN_ACK7: gpn_free_txid(sc, agd->agd_txids[6]); /* FALLTHROUGH */
546 case GPN_ACK6: gpn_free_txid(sc, agd->agd_txids[5]); /* FALLTHROUGH */
547 case GPN_ACK5: gpn_free_txid(sc, agd->agd_txids[4]); /* FALLTHROUGH */
548 case GPN_ACK4: gpn_free_txid(sc, agd->agd_txids[3]); /* FALLTHROUGH */
549 case GPN_ACK3: gpn_free_txid(sc, agd->agd_txids[2]); /* FALLTHROUGH */
550 case GPN_ACK2: gpn_free_txid(sc, agd->agd_txids[1]); /* FALLTHROUGH */
551 case GPN_ACK1: gpn_free_txid(sc, agd->agd_txids[0]); break;
552 case GPN_MOF:
553 case GPN_SOF:
554 case GPN_FRAME:
555 case GPN_EOF:
556 gpn_process_data(sc, gd);
557 break;
558 case GPN_IFUP:
559 gpn_ipm_ifup(sc);
560 break;
561 case GPN_IFDOWN:
562 gpn_ipm_ifdown(sc);
563 break;
564 default:
565 KASSERT(0);
568 splx(s);
571 static int
572 gpn_ifinit(struct ifnet *ifp)
574 struct gpn_softc * const sc = ifp->if_softc;
575 ipm_gpn_desc_t gd;
576 int error;
578 error = gpn_alloc_dmamaps(sc);
579 if (error)
580 return error;
582 memset(&gd, 0, sizeof(gd));
583 gd.gd_tag = IPM_TAG_GPN;
584 gd.gd_subtype = GPN_IFUP;
585 KASSERT(sc->sc_free > 0);
586 sc->sc_free--;
587 gemini_ipm_produce(&gd, 1);
589 if (sc->sc_remoteup)
590 ifmedia_set(&sc->sc_im, IFM_ETHER|IFM_1000_T|IFM_FDX);
592 ifp->if_flags |= IFF_RUNNING;
594 return error;
597 static void
598 gpn_ifstop(struct ifnet *ifp, int disable)
600 struct gpn_softc * const sc = ifp->if_softc;
601 ipm_gpn_desc_t gd;
603 memset(&gd, 0, sizeof(gd));
604 gd.gd_tag = IPM_TAG_GPN;
605 gd.gd_subtype = GPN_IFDOWN;
606 KASSERT(sc->sc_free > 0);
607 sc->sc_free--;
608 gemini_ipm_produce(&gd, 1);
609 ifp->if_flags &= ~IFF_RUNNING;
610 gpn_ipm_ifdown(sc);
612 if (disable) {
613 gpn_free_dmamaps(sc);
617 static int
618 gpn_ifioctl(struct ifnet *ifp, u_long cmd, void *data)
620 struct gpn_softc * const sc = ifp->if_softc;
621 struct ifreq * const ifr = data;
622 struct ifaliasreq * const ifra = data;
623 int s, error;
625 s = splnet();
627 switch (cmd) {
628 case SIOCSIFMEDIA:
629 case SIOCGIFMEDIA:
630 error = ifmedia_ioctl(ifp, ifr, &sc->sc_im, cmd);
631 break;
632 case SIOCSIFPHYADDR: {
633 const struct sockaddr_dl *sdl = satosdl(&ifra->ifra_addr);
635 if (sdl->sdl_family != AF_LINK) {
636 error = EINVAL;
637 break;
640 if_set_sadl(ifp, CLLADDR(sdl), ETHER_ADDR_LEN, false);
641 error = 0;
642 break;
644 default:
645 error = ether_ioctl(ifp, cmd, data);
646 if (error == ENETRESET)
647 error = 0;
648 break;
651 splx(s);
652 return error;
655 static int
656 gpn_mediachange(struct ifnet *ifp)
658 return 0;
661 static void
662 gpn_mediastatus(struct ifnet *ifp, struct ifmediareq *imr)
664 struct gpn_softc * const sc = ifp->if_softc;
665 imr->ifm_active = sc->sc_im.ifm_cur->ifm_media;
668 static int
669 gpn_match(device_t parent, cfdata_t cf, void *aux)
671 return strcmp(gpn_cd.cd_name, aux) == 0;
674 static void
675 gpn_attach(device_t parent, device_t self, void *aux)
677 struct gpn_softc * const sc = device_private(self);
678 struct ifnet * const ifp = &sc->sc_if;
679 char enaddr[6];
681 enaddr[0] = 2;
682 enaddr[1] = 0;
683 enaddr[2] = 0;
684 enaddr[3] = 0;
685 enaddr[4] = 0;
686 #ifdef GEMINI_MASTER
687 enaddr[5] = 0;
688 #elif defined(GEMINI_SLAVE)
689 enaddr[5] = 1;
690 #else
691 #error not master nor slave
692 #endif
694 aprint_normal("\n");
695 aprint_naive("\n");
696 sc->sc_dev = self;
697 sc->sc_dmat = &gemini_bus_dma_tag;
700 * Pretend we are full-duplex gigabit ethernet.
702 ifmedia_init(&sc->sc_im, 0, gpn_mediachange, gpn_mediastatus);
703 ifmedia_add(&sc->sc_im, IFM_ETHER|IFM_1000_T|IFM_FDX, 0, NULL);
704 ifmedia_add(&sc->sc_im, IFM_ETHER|IFM_NONE, 0, NULL);
705 ifmedia_set(&sc->sc_im, IFM_ETHER|IFM_NONE);
707 strlcpy(ifp->if_xname, device_xname(self), sizeof(ifp->if_xname));
708 ifp->if_softc = sc;
709 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
710 ifp->if_ioctl = gpn_ifioctl;
711 ifp->if_start = gpn_ifstart;
712 ifp->if_init = gpn_ifinit;
713 ifp->if_stop = gpn_ifstop;
715 IFQ_SET_READY(&ifp->if_snd);
717 sc->sc_ec.ec_capabilities = ETHERCAP_VLAN_MTU | ETHERCAP_JUMBO_MTU;
719 if_attach(ifp);
720 ether_ifattach(ifp, enaddr);
722 sc->sc_free = MAX_TXACTIVE*2;
723 sc->sc_ih = gemini_ipm_register(IPM_TAG_GPN, IPL_SOFTNET, sc->sc_free,
724 gpn_ipm_handler, gpn_ipm_rebate, sc);
725 KASSERT(sc->sc_ih);
727 sc->sc_ack_desc.agd_tag = IPM_TAG_GPN;
730 void gpn_print_gd(ipm_gpn_desc_t *);
731 void
732 gpn_print_gd(ipm_gpn_desc_t *gd)
734 printf("%s: %p\n", __FUNCTION__, gd);
735 printf("\ttag %d, subtype %d, id %d, pktlen64 %d\n",
736 gd->gd_tag, gd->gd_subtype, gd->gd_txid, gd->gd_pktlen64);
737 printf("\tlen1 %d, len2 %d, addr1 %#x, addr2 %#x\n",
738 gd->gd_len1, gd->gd_len2, gd->gd_addr1, gd->gd_addr2);
741 CFATTACH_DECL_NEW(gpn, sizeof(struct gpn_softc),
742 gpn_match, gpn_attach, NULL, NULL);