xref: /netbsd-src/sys/arch/arm/gemini/if_gpn.c (revision f3cfa6f6ce31685c6c4a758bc430e69eb99f50a4)
1 /* $NetBSD: if_gpn.c,v 1.12 2019/05/29 10:07:28 msaitoh 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 
35 __KERNEL_RCSID(0, "$NetBSD: if_gpn.c,v 1.12 2019/05/29 10:07:28 msaitoh Exp $");
36 
37 #include <sys/param.h>
38 #include <sys/device.h>
39 #include <sys/mbuf.h>
40 #include <sys/ioctl.h>
41 
42 #include <net/if.h>
43 #include <net/if_media.h>
44 #include <net/if_ether.h>
45 #include <net/if_dl.h>
46 #include <net/bpf.h>
47 
48 #include <sys/bus.h>
49 
50 #include <arm/gemini/gemini_var.h>
51 #include <arm/gemini/gemini_ipm.h>
52 
53 #define	GPN_MOF		0x00	/* Middle Of Frame */
54 #define	GPN_SOF		0x01	/* Start of Frame */
55 #define	GPN_EOF		0x02	/* End of Frame */
56 #define	GPN_FRAME	0x03	/* Complete Frame */
57 
58 #define	GPN_IFUP	0x05	/* partner is up */
59 #define	GPN_IFDOWN	0x06	/* partner is down */
60 
61 #define	GPN_ACK0	0x10	/* placeholder */
62 #define	GPN_ACK1	0x11	/* Ack 1 descriptor */
63 #define	GPN_ACK2	0x12	/* Ack 2 descriptors */
64 #define	GPN_ACK3	0x13	/* Ack 3 descriptors */
65 #define	GPN_ACK4	0x14	/* Ack 4 descriptors */
66 #define	GPN_ACK5	0x15	/* Ack 5 descriptors */
67 #define	GPN_ACK6	0x16	/* Ack 6 descriptors */
68 #define	GPN_ACK7	0x17	/* Ack 7 descriptors */
69 #define	GPN_ACK8	0x18	/* Ack 8 descriptors */
70 #define	GPN_ACK9	0x19	/* Ack 9 descriptors */
71 #define	GPN_ACK10	0x1a	/* Ack 10 descriptors */
72 #define	GPN_ACK11	0x1b	/* Ack 11 descriptors */
73 #define	GPN_ACK12	0x1c	/* Ack 12 descriptors */
74 #define	GPN_ACK13	0x1d	/* Ack 13 descriptors */
75 #define	GPN_ACK14	0x1e	/* Ack 14 descriptors */
76 
77 typedef struct {
78 	uint8_t gd_tag;
79 	uint8_t gd_subtype;
80 	uint8_t gd_txid;
81 	uint8_t gd_pktlen64;
82 	uint16_t gd_len1;
83 	uint16_t gd_len2;
84 	uint32_t gd_addr1;
85 	uint32_t gd_addr2;
86 } ipm_gpn_desc_t;
87 
88 typedef struct {
89 	uint8_t agd_tag;
90 	uint8_t agd_subtype;
91 	uint8_t agd_txids[14];
92 } ipm_gpn_ack_desc_t;
93 
94 #define	MAX_TXACTIVE	60
95 
96 struct gpn_txinfo {
97 	struct mbuf *ti_mbuf;
98 	bus_dmamap_t ti_map;
99 };
100 
101 struct gpn_softc {
102 	device_t sc_dev;
103 	bus_dma_tag_t sc_dmat;
104 	struct ifmedia sc_im;
105 	struct ethercom sc_ec;
106 #define	sc_if sc_ec.ec_if
107 	size_t sc_free;
108 	size_t sc_txactive;
109 	void *sc_ih;
110 	ipm_gpn_ack_desc_t sc_ack_desc;
111 	struct mbuf *sc_rxmbuf;
112 	struct gpn_txinfo sc_txinfo[MAX_TXACTIVE];
113 	uint8_t sc_lastid;
114 	bool sc_remoteup;		/* remote side up? */
115 };
116 
117 CTASSERT((GPN_SOF | GPN_EOF) == GPN_FRAME);
118 CTASSERT((GPN_SOF & GPN_EOF) == 0);
119 
120 extern struct cfdriver gpn_cd;
121 
122 static void gpn_ifstart(struct ifnet *);
123 
124 #ifdef GPNDEBUG
125 static uint32_t
126 m_crc32_le(struct mbuf *m)
127 {
128 	static const uint32_t crctab[] = {
129 		0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
130 		0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
131 		0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
132 		0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
133 	};
134 	uint32_t crc;
135 	size_t i;
136 
137 	crc = 0xffffffffU;	/* initial value */
138 
139 	for (; m; m = m->m_next) {
140 		for (i = 0; i < m->m_len; i++) {
141 			crc ^= m->m_data[i];
142 			crc = (crc >> 4) ^ crctab[crc & 0xf];
143 			crc = (crc >> 4) ^ crctab[crc & 0xf];
144 		}
145 	}
146 
147 	return crc;
148 }
149 #endif
150 
151 static void
152 gpn_free_dmamaps(struct gpn_softc *sc)
153 {
154 	struct gpn_txinfo *ti = sc->sc_txinfo;
155 	struct gpn_txinfo * const end_ti = ti + __arraycount(sc->sc_txinfo);
156 
157 	for (; ti < end_ti; ti++) {
158 		if (ti->ti_map == NULL)
159 			continue;
160 		bus_dmamap_destroy(sc->sc_dmat, ti->ti_map);
161 		ti->ti_map = NULL;
162 	}
163 }
164 
165 static int
166 gpn_alloc_dmamaps(struct gpn_softc *sc)
167 {
168 	struct gpn_txinfo *ti = sc->sc_txinfo;
169 	struct gpn_txinfo * const end_ti = ti + __arraycount(sc->sc_txinfo);
170 	int error;
171 
172 	for (error = 0; ti < end_ti; ti++) {
173 		if (ti->ti_map != NULL)
174 			continue;
175 		error = bus_dmamap_create(sc->sc_dmat,
176 		    10000, 2, 8192, 0,
177 		    BUS_DMA_ALLOCNOW | BUS_DMA_WAITOK,
178 		    &ti->ti_map);
179 		if (error)
180 			break;
181 	}
182 
183 	if (error)
184 		gpn_free_dmamaps(sc);
185 
186 	return error;
187 }
188 
189 static bool
190 gpn_add_data(struct gpn_softc *sc, bus_addr_t addr, bus_size_t len)
191 {
192 	struct mbuf *m, *m0;
193 	size_t space;
194 
195 	m = sc->sc_rxmbuf;
196 	KASSERT(m != NULL);
197 
198 	m->m_pkthdr.len += len;
199 
200 	while (m->m_next != NULL)
201 		m = m->m_next;
202 
203 	KASSERT(len > 0);
204 	space = M_TRAILINGSPACE(m);
205 	for (;;) {
206 		if (space > 0) {
207 			if (len < space)
208 				space = len;
209 			gemini_ipm_copyin(mtod(m, uint8_t *) + m->m_len, addr,
210 			    space);
211 			len -= space;
212 			m->m_len += space;
213 			if (len == 0)
214 				return true;
215 			addr += space;
216 		}
217 		MGET(m0, M_DONTWAIT, MT_DATA);
218 		if (m0 == NULL)
219 			break;
220 		space = MLEN;
221 		if (len > space) {
222 			MCLGET(m0, M_DONTWAIT);
223 			if (m0->m_flags & M_EXT)
224 				space = MCLBYTES;
225 		}
226 		m->m_len = 0;
227 		m->m_next = m0;
228 		m = m0;
229 	}
230 	return false;
231 }
232 
233 static void
234 gpn_ack_txid(struct gpn_softc *sc, unsigned int txid)
235 {
236 	ipm_gpn_ack_desc_t * const agd = &sc->sc_ack_desc;
237 	agd->agd_txids[agd->agd_subtype] = txid;
238 	if (++agd->agd_subtype == __arraycount(agd->agd_txids)) {
239 		agd->agd_subtype += GPN_ACK0;
240 		sc->sc_free--;
241 		gemini_ipm_produce(agd, 1);
242 		agd->agd_subtype = 0;
243 	}
244 }
245 
246 static void
247 gpn_process_data(struct gpn_softc *sc, const ipm_gpn_desc_t *gd)
248 {
249 	struct ifnet * const ifp = &sc->sc_if;
250 	size_t pktlen = gd->gd_pktlen64 * 64;
251 	unsigned int subtype = gd->gd_subtype;
252 	bool ok;
253 
254 	if ((subtype & GPN_SOF) == 0 && sc->sc_rxmbuf == NULL) {
255 		ifp->if_ierrors++;
256 		goto out;
257 	}
258 
259 	if ((subtype & GPN_SOF) && sc->sc_rxmbuf != NULL) {
260 		ifp->if_ierrors++;
261 		m_freem(sc->sc_rxmbuf);
262 		sc->sc_rxmbuf = NULL;
263 	}
264 
265 	if (sc->sc_rxmbuf == NULL) {
266 		struct mbuf *m;
267 		MGETHDR(m, M_DONTWAIT, MT_DATA);
268 		if (m == NULL) {
269 			ifp->if_ierrors++;
270 			goto out;
271 		}
272 		if (pktlen > MHLEN - 2) {
273 			MCLGET(m, M_DONTWAIT);
274 			if ((m->m_flags & M_EXT) == 0) {
275 				ifp->if_ierrors++;
276 				m_free(m);
277 				goto out;
278 			}
279 		}
280 		m->m_data += 2;	/* makes ethernet payload 32bit aligned */
281 		m->m_len = 0;
282 		m->m_pkthdr.len = 0;
283 		sc->sc_rxmbuf = m;
284 	}
285 
286 	ok = gpn_add_data(sc, gd->gd_addr1, gd->gd_len1);
287 	if (ok && gd->gd_addr2 && gd->gd_len2)
288 		ok = gpn_add_data(sc, gd->gd_addr2, gd->gd_len2);
289 	if (!ok) {
290 		ifp->if_ierrors++;
291 		m_freem(sc->sc_rxmbuf);
292 		sc->sc_rxmbuf = NULL;
293 		goto out;
294 	}
295 
296 	if (subtype & GPN_EOF) {
297 		struct mbuf *m;
298 		m = sc->sc_rxmbuf;
299 		sc->sc_rxmbuf = NULL;
300 		m_set_rcvif(m, ifp);
301 		KASSERT(((m->m_pkthdr.len + 63) >> 6) == gd->gd_pktlen64);
302 		ifp->if_ibytes += m->m_pkthdr.len;
303 #ifdef GPNDEBUG
304 		printf("%s: rx len=%d crc=%#x\n", ifp->if_xname,
305 		    m->m_pkthdr.len, m_crc32_le(m));
306 #endif
307 		if_percpuq_enqueue(ifp->if_percpuq, m);
308 	}
309 
310 out:
311 	gpn_ack_txid(sc, gd->gd_txid);
312 }
313 
314 static void
315 gpn_free_txid(struct gpn_softc *sc, size_t txid)
316 {
317 	struct gpn_txinfo * const ti = sc->sc_txinfo + txid;
318 
319 	KASSERT(txid < MAX_TXACTIVE);
320 
321 	if (ti->ti_mbuf == NULL)
322 		return;
323 
324 	bus_dmamap_sync(sc->sc_dmat, ti->ti_map,
325 	    0, ti->ti_mbuf->m_len, BUS_DMASYNC_POSTREAD);
326 	bus_dmamap_unload(sc->sc_dmat, ti->ti_map);
327 	m_freem(ti->ti_mbuf);
328 	ti->ti_mbuf = NULL;
329 	sc->sc_txactive--;
330 	KASSERT(sc->sc_txactive < MAX_TXACTIVE);
331 	if (sc->sc_if.if_flags & IFF_OACTIVE) {
332 		sc->sc_if.if_flags &= ~IFF_OACTIVE;
333 		gpn_ifstart(&sc->sc_if);
334 	}
335 }
336 
337 static void
338 gpn_ipm_rebate(void *arg, size_t count)
339 {
340 	struct gpn_softc * const sc = arg;
341 	int s;
342 
343 	s = splnet();
344 	sc->sc_free += count;
345 
346 	sc->sc_if.if_flags &= ~IFF_OACTIVE;
347 	gpn_ifstart(&sc->sc_if);
348 	splx(s);
349 }
350 
351 static void
352 gpn_ifstart(struct ifnet *ifp)
353 {
354 	struct gpn_softc * const sc = ifp->if_softc;
355 
356 	for (;;) {
357 		struct mbuf *m, *m0;
358 		ipm_gpn_desc_t gd;
359 		ipm_gpn_desc_t *last_gd;
360 		size_t count;
361 
362 		if (sc->sc_free == 0) {
363 			ifp->if_flags |= IFF_OACTIVE;
364 			break;
365 		}
366 
367 		IF_DEQUEUE(&ifp->if_snd, m);
368 		if (!m)
369 			break;
370 
371 		if ((ifp->if_flags & IFF_UP) == 0) {
372 			m_freem(m);
373 			continue;
374 		}
375 
376 		/*
377 		 * Make sure to send any pending acks first.
378 		 */
379 		if (sc->sc_ack_desc.agd_subtype) {
380 			sc->sc_free--;
381 			sc->sc_ack_desc.agd_subtype += GPN_ACK0;
382 			gemini_ipm_produce(&sc->sc_ack_desc, 1);
383 			sc->sc_ack_desc.agd_subtype = 0;
384 		}
385 
386 		/*
387 		 * Let's find out how many mbufs we are using.
388 		 */
389 		for (m0 = m, count = 0; m0; m0 = m0->m_next) {
390 			if (m0->m_len == 0)
391 				continue;
392 			count++;
393 		}
394 
395 		/*
396 		 * Make sure there is always enough room.
397 		 */
398 		if (sc->sc_free < count
399 		    || sc->sc_txactive + count > MAX_TXACTIVE) {
400 			IF_PREPEND(&ifp->if_snd, m);
401 			ifp->if_flags |= IFF_OACTIVE;
402 			return;
403 		}
404 
405 		bpf_mtap(ifp, m, BPF_D_OUT);
406 #ifdef GPNDEBUG
407 		printf("%s: tx len=%d crc=%#x\n", ifp->if_xname,
408 		    m->m_pkthdr.len, m_crc32_le(m));
409 #endif
410 
411 		last_gd = NULL;
412 		gd.gd_tag = IPM_TAG_GPN;
413 		gd.gd_subtype = GPN_SOF;
414 		gd.gd_pktlen64 = (m->m_pkthdr.len + 63) >> 6;
415 		for (; m != NULL; m = m0) {
416 			struct gpn_txinfo *ti;
417 			bus_dmamap_t map;
418 			size_t id;
419 			int error;
420 
421 			m0 = m->m_next;
422 			m->m_next = NULL;
423 			if (m->m_len == 0) {
424 				m_free(m);
425 				continue;
426 			}
427 			if (last_gd) {
428 				sc->sc_txactive++;
429 				sc->sc_free--;
430 				gemini_ipm_produce(last_gd, 1);
431 				last_gd = NULL;
432 				gd.gd_subtype = GPN_MOF;
433 			}
434 			for (id = sc->sc_lastid;
435 			     sc->sc_txinfo[id].ti_mbuf != NULL;) {
436 				if (++id == __arraycount(sc->sc_txinfo))
437 					id = 0;
438 			}
439 			KASSERT(id < MAX_TXACTIVE);
440 			ti = sc->sc_txinfo + id;
441 			map = ti->ti_map;
442 			error = bus_dmamap_load(sc->sc_dmat, map,
443 			    mtod(m, void *), m->m_len, NULL,
444 			    BUS_DMA_READ | BUS_DMA_NOWAIT);
445 			if (error) {
446 				ifp->if_oerrors++;
447 				m_freem(m);
448 				break;
449 			}
450 			bus_dmamap_sync(sc->sc_dmat, map, 0,
451 			    m->m_len, BUS_DMASYNC_PREREAD);
452 			KASSERT(map->dm_nsegs > 0);
453 			KASSERT(map->dm_nsegs <= 2);
454 			KASSERT(map->dm_segs[0].ds_addr != 0);
455 			gd.gd_len1 = map->dm_segs[0].ds_len;
456 			gd.gd_addr1 = map->dm_segs[0].ds_addr;
457 			if (map->dm_nsegs == 1) {
458 				gd.gd_len2 = 0;
459 				gd.gd_addr2 = 0;
460 			} else {
461 				KASSERT(map->dm_segs[0].ds_addr != 0);
462 				gd.gd_len2 = map->dm_segs[1].ds_len;
463 				gd.gd_addr2 = map->dm_segs[1].ds_addr;
464 			}
465 
466 			gd.gd_txid = id;
467 			ti->ti_mbuf = m;
468 			last_gd = &gd;
469 			ifp->if_obytes += m->m_len;
470 		}
471 		ifp->if_opackets++;
472 
473 		/*
474 		 * XXX XXX 'last_gd' could be NULL
475 		 */
476 		last_gd->gd_subtype |= GPN_EOF;
477 
478 		sc->sc_txactive++;
479 		sc->sc_free--;
480 		gemini_ipm_produce(last_gd, 1);
481 	}
482 }
483 
484 static void
485 gpn_ipm_ifup(struct gpn_softc *sc)
486 {
487 	sc->sc_remoteup = true;
488 	if (sc->sc_if.if_flags & IFF_UP)
489 		ifmedia_set(&sc->sc_im, IFM_ETHER | IFM_1000_T | IFM_FDX);
490 }
491 
492 static void
493 gpn_ipm_ifdown(struct gpn_softc *sc)
494 {
495 	struct gpn_txinfo *ti = sc->sc_txinfo;
496 	struct gpn_txinfo * const end_ti = ti + __arraycount(sc->sc_txinfo);
497 
498 	if (sc->sc_rxmbuf) {
499 		m_freem(sc->sc_rxmbuf);
500 		sc->sc_rxmbuf = NULL;
501 	}
502 
503 	IF_PURGE(&sc->sc_if.if_snd);
504 
505 	for (; ti < end_ti; ti++) {
506 		if (ti->ti_mbuf == NULL)
507 			continue;
508 		bus_dmamap_sync(sc->sc_dmat, ti->ti_map,
509 		    0, ti->ti_mbuf->m_len, BUS_DMASYNC_POSTREAD);
510 		bus_dmamap_unload(sc->sc_dmat, ti->ti_map);
511 		m_freem(ti->ti_mbuf);
512 		ti->ti_mbuf = NULL;
513 	}
514 	sc->sc_lastid = 0;
515 	ifmedia_set(&sc->sc_im, IFM_ETHER | IFM_NONE);
516 	sc->sc_remoteup = false;
517 }
518 
519 static void
520 gpn_ipm_handler(void *arg, const void *desc)
521 {
522 	struct gpn_softc * const sc = arg;
523 	const ipm_gpn_desc_t * const gd = desc;
524 	const ipm_gpn_ack_desc_t * const agd = desc;
525 	int s;
526 
527 	s = splnet();
528 
529 	switch (gd->gd_subtype) {
530 	case GPN_ACK14: gpn_free_txid(sc, agd->agd_txids[13]); /* FALLTHROUGH */
531 	case GPN_ACK13: gpn_free_txid(sc, agd->agd_txids[12]); /* FALLTHROUGH */
532 	case GPN_ACK12: gpn_free_txid(sc, agd->agd_txids[11]); /* FALLTHROUGH */
533 	case GPN_ACK11: gpn_free_txid(sc, agd->agd_txids[10]); /* FALLTHROUGH */
534 	case GPN_ACK10: gpn_free_txid(sc, agd->agd_txids[9]); /* FALLTHROUGH */
535 	case GPN_ACK9: gpn_free_txid(sc, agd->agd_txids[8]); /* FALLTHROUGH */
536 	case GPN_ACK8: gpn_free_txid(sc, agd->agd_txids[7]); /* FALLTHROUGH */
537 	case GPN_ACK7: gpn_free_txid(sc, agd->agd_txids[6]); /* FALLTHROUGH */
538 	case GPN_ACK6: gpn_free_txid(sc, agd->agd_txids[5]); /* FALLTHROUGH */
539 	case GPN_ACK5: gpn_free_txid(sc, agd->agd_txids[4]); /* FALLTHROUGH */
540 	case GPN_ACK4: gpn_free_txid(sc, agd->agd_txids[3]); /* FALLTHROUGH */
541 	case GPN_ACK3: gpn_free_txid(sc, agd->agd_txids[2]); /* FALLTHROUGH */
542 	case GPN_ACK2: gpn_free_txid(sc, agd->agd_txids[1]); /* FALLTHROUGH */
543 	case GPN_ACK1: gpn_free_txid(sc, agd->agd_txids[0]); break;
544 	case GPN_MOF:
545 	case GPN_SOF:
546 	case GPN_FRAME:
547 	case GPN_EOF:
548 		gpn_process_data(sc, gd);
549 		break;
550 	case GPN_IFUP:
551 		gpn_ipm_ifup(sc);
552 		break;
553 	case GPN_IFDOWN:
554 		gpn_ipm_ifdown(sc);
555 		break;
556 	default:
557 		KASSERT(0);
558 	}
559 
560 	splx(s);
561 }
562 
563 static int
564 gpn_ifinit(struct ifnet *ifp)
565 {
566 	struct gpn_softc * const sc = ifp->if_softc;
567 	ipm_gpn_desc_t gd;
568 	int error;
569 
570 	error = gpn_alloc_dmamaps(sc);
571 	if (error)
572 		return error;
573 
574 	memset(&gd, 0, sizeof(gd));
575 	gd.gd_tag = IPM_TAG_GPN;
576 	gd.gd_subtype = GPN_IFUP;
577 	KASSERT(sc->sc_free > 0);
578 	sc->sc_free--;
579 	gemini_ipm_produce(&gd, 1);
580 
581 	if (sc->sc_remoteup)
582 		ifmedia_set(&sc->sc_im, IFM_ETHER | IFM_1000_T | IFM_FDX);
583 
584 	ifp->if_flags |= IFF_RUNNING;
585 
586 	return error;
587 }
588 
589 static void
590 gpn_ifstop(struct ifnet *ifp, int disable)
591 {
592 	struct gpn_softc * const sc = ifp->if_softc;
593 	ipm_gpn_desc_t gd;
594 
595 	memset(&gd, 0, sizeof(gd));
596 	gd.gd_tag = IPM_TAG_GPN;
597 	gd.gd_subtype = GPN_IFDOWN;
598 	KASSERT(sc->sc_free > 0);
599 	sc->sc_free--;
600 	gemini_ipm_produce(&gd, 1);
601 	ifp->if_flags &= ~IFF_RUNNING;
602 	gpn_ipm_ifdown(sc);
603 
604 	if (disable) {
605 		gpn_free_dmamaps(sc);
606 	}
607 }
608 
609 static int
610 gpn_ifioctl(struct ifnet *ifp, u_long cmd, void *data)
611 {
612 	struct gpn_softc * const sc = ifp->if_softc;
613 	struct ifreq * const ifr = data;
614 	struct ifaliasreq * const ifra = data;
615 	int s, error;
616 
617 	s = splnet();
618 
619 	switch (cmd) {
620 	case SIOCSIFPHYADDR: {
621 		const struct sockaddr_dl *sdl = satosdl(&ifra->ifra_addr);
622 
623 		if (sdl->sdl_family != AF_LINK) {
624 			error = EINVAL;
625 			break;
626 		}
627 
628 		if_set_sadl(ifp, CLLADDR(sdl), ETHER_ADDR_LEN, false);
629 		error = 0;
630 		break;
631 	}
632 	default:
633 		error = ether_ioctl(ifp, cmd, data);
634 		if (error == ENETRESET)
635 			error = 0;
636 		break;
637 	}
638 
639 	splx(s);
640 	return error;
641 }
642 
643 static int
644 gpn_mediachange(struct ifnet *ifp)
645 {
646 	return 0;
647 }
648 
649 static void
650 gpn_mediastatus(struct ifnet *ifp, struct ifmediareq *imr)
651 {
652 	struct gpn_softc * const sc = ifp->if_softc;
653 	imr->ifm_active = sc->sc_im.ifm_cur->ifm_media;
654 }
655 
656 static int
657 gpn_match(device_t parent, cfdata_t cf, void *aux)
658 {
659 	return strcmp(gpn_cd.cd_name, aux) == 0;
660 }
661 
662 static void
663 gpn_attach(device_t parent, device_t self, void *aux)
664 {
665 	struct gpn_softc * const sc = device_private(self);
666 	struct ifnet * const ifp = &sc->sc_if;
667 	char enaddr[6];
668 
669 	enaddr[0] = 2;
670 	enaddr[1] = 0;
671 	enaddr[2] = 0;
672 	enaddr[3] = 0;
673 	enaddr[4] = 0;
674 #ifdef GEMINI_MASTER
675 	enaddr[5] = 0;
676 #elif defined(GEMINI_SLAVE)
677 	enaddr[5] = 1;
678 #else
679 #error not master nor slave
680 #endif
681 
682 	aprint_normal("\n");
683 	aprint_naive("\n");
684 	sc->sc_dev = self;
685 	sc->sc_dmat = &gemini_bus_dma_tag;
686 
687 	/* Setup ifmedia interface */
688 	sc->sc_ec.ec_ifmedia = &sc->sc_im;
689 	ifmedia_init(&sc->sc_im, 0, gpn_mediachange, gpn_mediastatus);
690 	/* Pretend we are full-duplex gigabit ethernet. */
691 	ifmedia_add(&sc->sc_im, IFM_ETHER | IFM_1000_T | IFM_FDX, 0, NULL);
692 	ifmedia_add(&sc->sc_im, IFM_ETHER | IFM_NONE, 0, NULL);
693 	ifmedia_set(&sc->sc_im, IFM_ETHER | IFM_NONE);
694 
695 	strlcpy(ifp->if_xname, device_xname(self), sizeof(ifp->if_xname));
696 	ifp->if_softc = sc;
697 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
698 	ifp->if_ioctl = gpn_ifioctl;
699 	ifp->if_start = gpn_ifstart;
700 	ifp->if_init  = gpn_ifinit;
701 	ifp->if_stop  = gpn_ifstop;
702 
703 	IFQ_SET_READY(&ifp->if_snd);
704 
705 	sc->sc_ec.ec_capabilities = ETHERCAP_VLAN_MTU | ETHERCAP_JUMBO_MTU;
706 
707 	if_attach(ifp);
708 	ether_ifattach(ifp, enaddr);
709 
710 	sc->sc_free = MAX_TXACTIVE*2;
711 	sc->sc_ih = gemini_ipm_register(IPM_TAG_GPN, IPL_SOFTNET, sc->sc_free,
712 	    gpn_ipm_handler, gpn_ipm_rebate, sc);
713 	KASSERT(sc->sc_ih);
714 
715 	sc->sc_ack_desc.agd_tag = IPM_TAG_GPN;
716 }
717 
718 void gpn_print_gd(ipm_gpn_desc_t *);
719 void
720 gpn_print_gd(ipm_gpn_desc_t *gd)
721 {
722 	printf("%s: %p\n", __FUNCTION__, gd);
723 	printf("\ttag %d, subtype %d, id %d, pktlen64 %d\n",
724 		gd->gd_tag, gd->gd_subtype, gd->gd_txid, gd->gd_pktlen64);
725 	printf("\tlen1 %d, len2 %d, addr1 %#x, addr2 %#x\n",
726 		gd->gd_len1, gd->gd_len2, gd->gd_addr1, gd->gd_addr2);
727 }
728 
729 CFATTACH_DECL_NEW(gpn, sizeof(struct gpn_softc),
730     gpn_match, gpn_attach, NULL, NULL);
731