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