xref: /netbsd-src/sys/arch/arm/gemini/if_gpn.c (revision 3816d47b2c42fcd6e549e3407f842a5b1a1d23ad)
1 /* $NetBSD: if_gpn.c,v 1.1 2008/12/06 05:22:39 cliff Exp $ */
2 /*-
3  * Copyright (c) 2008 The NetBSD Foundation, Inc.
4  * All rights reserved.
5  *
6  * This code is derived from software contributed to The NetBSD Foundation
7  * by Matt Thomas <matt@3am-software.com>
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 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.
29  */
30 
31 #include <sys/cdefs.h>
32 
33 #include "opt_gemini.h"
34 #include "bpfilter.h"
35 
36 __KERNEL_RCSID(0, "$NetBSD: if_gpn.c,v 1.1 2008/12/06 05:22:39 cliff Exp $");
37 
38 #include <sys/param.h>
39 #include <sys/device.h>
40 #include <sys/mbuf.h>
41 #include <sys/ioctl.h>
42 
43 #include <net/if.h>
44 #include <net/if_media.h>
45 #include <net/if_ether.h>
46 #include <net/if_dl.h>
47 
48 #if NBPFILTER > 0
49 #include <net/bpf.h>
50 #endif
51 
52 #include <machine/bus.h>
53 
54 #include <arm/gemini/gemini_var.h>
55 #include <arm/gemini/gemini_ipm.h>
56 
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 */
61 
62 #define	GPN_IFUP	0x05	/* partner is up */
63 #define	GPN_IFDOWN	0x06	/* partner is down */
64 
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 */
80 
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;
91 
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;
97 
98 #define	MAX_TXACTIVE	60
99 
100 struct gpn_txinfo {
101 	struct mbuf *ti_mbuf;
102 	bus_dmamap_t ti_map;
103 };
104 
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? */
119 };
120 
121 CTASSERT((GPN_SOF | GPN_EOF) == GPN_FRAME);
122 CTASSERT((GPN_SOF & GPN_EOF) == 0);
123 
124 extern struct cfdriver gpn_cd;
125 
126 static void gpn_ifstart(struct ifnet *);
127 
128 #ifdef GPNDEBUG
129 static uint32_t
130 m_crc32_le(struct mbuf *m)
131 {
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
137 	};
138 	uint32_t crc;
139 	size_t i;
140 
141 	crc = 0xffffffffU;	/* initial value */
142 
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];
148 		}
149 	}
150 
151 	return (crc);
152 }
153 #endif
154 
155 static void
156 gpn_free_dmamaps(struct gpn_softc *sc)
157 {
158 	struct gpn_txinfo *ti = sc->sc_txinfo;
159 	struct gpn_txinfo * const end_ti = ti + __arraycount(sc->sc_txinfo);
160 
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;
166 	}
167 }
168 
169 static int
170 gpn_alloc_dmamaps(struct gpn_softc *sc)
171 {
172 	struct gpn_txinfo *ti = sc->sc_txinfo;
173 	struct gpn_txinfo * const end_ti = ti + __arraycount(sc->sc_txinfo);
174 	int error;
175 
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;
185 	}
186 
187 	if (error)
188 		gpn_free_dmamaps(sc);
189 
190 	return error;
191 }
192 
193 static bool
194 gpn_add_data(struct gpn_softc *sc, bus_addr_t addr, bus_size_t len)
195 {
196 	struct mbuf *m, *m0;
197 	size_t space;
198 
199 	m = sc->sc_rxmbuf;
200 	KASSERT(m != NULL);
201 
202 	m->m_pkthdr.len += len;
203 
204 	while (m->m_next != NULL)
205 		m = m->m_next;
206 
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;
220 		}
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;
229 		}
230 		m->m_len = 0;
231 		m->m_next = m0;
232 		m = m0;
233 	}
234 	return false;
235 }
236 
237 static void
238 gpn_ack_txid(struct gpn_softc *sc, unsigned int txid)
239 {
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;
247 	}
248 }
249 
250 static void
251 gpn_process_data(struct gpn_softc *sc, const ipm_gpn_desc_t *gd)
252 {
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;
257 
258 	if ((subtype & GPN_SOF) == 0 && sc->sc_rxmbuf == NULL) {
259 		ifp->if_ierrors++;
260 		goto out;
261 	}
262 
263 	if ((subtype & GPN_SOF) && sc->sc_rxmbuf != NULL) {
264 		ifp->if_ierrors++;
265 		m_freem(sc->sc_rxmbuf);
266 		sc->sc_rxmbuf = NULL;
267 	}
268 
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;
275 		}
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;
282 			}
283 		}
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;
288 	}
289 
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;
298 	}
299 
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);
317 	}
318 
319 out:
320 	gpn_ack_txid(sc, gd->gd_txid);
321 }
322 
323 static void
324 gpn_free_txid(struct gpn_softc *sc, size_t txid)
325 {
326 	struct gpn_txinfo * const ti = sc->sc_txinfo + txid;
327 
328 	KASSERT(txid < MAX_TXACTIVE);
329 
330 	if (ti->ti_mbuf == NULL)
331 		return;
332 
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);
343 	}
344 
345 }
346 
347 static void
348 gpn_ipm_rebate(void *arg, size_t count)
349 {
350 	struct gpn_softc * const sc = arg;
351 	int s;
352 
353 	s = splnet();
354 	sc->sc_free += count;
355 
356 	sc->sc_if.if_flags &= ~IFF_OACTIVE;
357 	gpn_ifstart(&sc->sc_if);
358 	splx(s);
359 }
360 
361 static void
362 gpn_ifstart(struct ifnet *ifp)
363 {
364 	struct gpn_softc * const sc = ifp->if_softc;
365 
366 	for (;;) {
367 		struct mbuf *m, *m0;
368 		ipm_gpn_desc_t gd;
369 		ipm_gpn_desc_t *last_gd;
370 		size_t count;
371 
372 		if (sc->sc_free == 0) {
373 			ifp->if_flags |= IFF_OACTIVE;
374 			break;
375 		}
376 
377 		IF_DEQUEUE(&ifp->if_snd, m);
378 		if (!m)
379 			break;
380 
381 		if ((ifp->if_flags & IFF_UP) == 0) {
382 			m_freem(m);
383 			continue;
384 		}
385 
386 		/*
387 		 * Make sure to send any pending acks first.
388 		 */
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;
394 		}
395 
396 		/*
397 		 * Let's find out how many mbufs we are using.
398 		 */
399 		for (m0 = m, count = 0; m0; m0 = m0->m_next) {
400 			if (m0->m_len == 0)
401 				continue;
402 			count++;
403 		}
404 
405 		/*
406 		 * Make sure there is always enough room.
407 		 */
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;
413 		}
414 
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
423 
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;
433 
434 			m0 = m->m_next;
435 			m->m_next = NULL;
436 			if (m->m_len == 0) {
437 				m_free(m);
438 				continue;
439 			}
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;
446 			}
447 			for (id = sc->sc_lastid;
448 			     sc->sc_txinfo[id].ti_mbuf != NULL;) {
449 				if (++id == __arraycount(sc->sc_txinfo))
450 					id = 0;
451 			}
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;
462 			}
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;
477 			}
478 
479 			gd.gd_txid = id;
480 			ti->ti_mbuf = m;
481 			last_gd = &gd;
482 			ifp->if_obytes += m->m_len;
483 		}
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);
489 	}
490 }
491 
492 static void
493 gpn_ipm_ifup(struct gpn_softc *sc)
494 {
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);
498 }
499 
500 static void
501 gpn_ipm_ifdown(struct gpn_softc *sc)
502 {
503 	struct gpn_txinfo *ti = sc->sc_txinfo;
504 	struct gpn_txinfo * const end_ti = ti + __arraycount(sc->sc_txinfo);
505 
506 	if (sc->sc_rxmbuf) {
507 		m_freem(sc->sc_rxmbuf);
508 		sc->sc_rxmbuf = NULL;
509 	}
510 
511 	IF_PURGE(&sc->sc_if.if_snd);
512 
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;
521 	}
522 	sc->sc_lastid = 0;
523 	ifmedia_set(&sc->sc_im, IFM_ETHER|IFM_NONE);
524 	sc->sc_remoteup = false;
525 }
526 
527 static void
528 gpn_ipm_handler(void *arg, const void *desc)
529 {
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;
534 
535 	s = splnet();
536 
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);
566 	}
567 
568 	splx(s);
569 }
570 
571 static int
572 gpn_ifinit(struct ifnet *ifp)
573 {
574 	struct gpn_softc * const sc = ifp->if_softc;
575 	ipm_gpn_desc_t gd;
576 	int error;
577 
578 	error = gpn_alloc_dmamaps(sc);
579 	if (error)
580 		return error;
581 
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);
588 
589 	if (sc->sc_remoteup)
590 		ifmedia_set(&sc->sc_im, IFM_ETHER|IFM_1000_T|IFM_FDX);
591 
592 	ifp->if_flags |= IFF_RUNNING;
593 
594 	return error;
595 }
596 
597 static void
598 gpn_ifstop(struct ifnet *ifp, int disable)
599 {
600 	struct gpn_softc * const sc = ifp->if_softc;
601 	ipm_gpn_desc_t gd;
602 
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);
611 
612 	if (disable) {
613 		gpn_free_dmamaps(sc);
614 	}
615 }
616 
617 static int
618 gpn_ifioctl(struct ifnet *ifp, u_long cmd, void *data)
619 {
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;
624 
625 	s = splnet();
626 
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);
634 
635 		if (sdl->sdl_family != AF_LINK) {
636 			error = EINVAL;
637 			break;
638 		}
639 
640 		if_set_sadl(ifp, CLLADDR(sdl), ETHER_ADDR_LEN, false);
641 		error = 0;
642 		break;
643 	}
644 	default:
645 		error = ether_ioctl(ifp, cmd, data);
646 		if (error == ENETRESET)
647 			error = 0;
648 		break;
649 	}
650 
651 	splx(s);
652 	return error;
653 }
654 
655 static int
656 gpn_mediachange(struct ifnet *ifp)
657 {
658 	return 0;
659 }
660 
661 static void
662 gpn_mediastatus(struct ifnet *ifp, struct ifmediareq *imr)
663 {
664 	struct gpn_softc * const sc = ifp->if_softc;
665 	imr->ifm_active = sc->sc_im.ifm_cur->ifm_media;
666 }
667 
668 static int
669 gpn_match(device_t parent, cfdata_t cf, void *aux)
670 {
671 	return strcmp(gpn_cd.cd_name, aux) == 0;
672 }
673 
674 static void
675 gpn_attach(device_t parent, device_t self, void *aux)
676 {
677 	struct gpn_softc * const sc = device_private(self);
678 	struct ifnet * const ifp = &sc->sc_if;
679 	char enaddr[6];
680 
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
693 
694 	aprint_normal("\n");
695 	aprint_naive("\n");
696 	sc->sc_dev = self;
697 	sc->sc_dmat = &gemini_bus_dma_tag;
698 
699 	/*
700 	 * Pretend we are full-duplex gigabit ethernet.
701 	 */
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);
706 
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;
714 
715 	IFQ_SET_READY(&ifp->if_snd);
716 
717 	sc->sc_ec.ec_capabilities = ETHERCAP_VLAN_MTU | ETHERCAP_JUMBO_MTU;
718 
719 	if_attach(ifp);
720 	ether_ifattach(ifp, enaddr);
721 
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);
726 
727 	sc->sc_ack_desc.agd_tag = IPM_TAG_GPN;
728 }
729 
730 void gpn_print_gd(ipm_gpn_desc_t *);
731 void
732 gpn_print_gd(ipm_gpn_desc_t *gd)
733 {
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);
739 }
740 
741 CFATTACH_DECL_NEW(gpn, sizeof(struct gpn_softc),
742     gpn_match, gpn_attach, NULL, NULL);
743