1/* $NetBSD: if_gpn.c,v 1.3 2010/04/05 07:19:29 joerg 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.3 2010/04/05 07:19:29 joerg 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
78typedef 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
89typedef 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
97struct gpn_txinfo {
98	struct mbuf *ti_mbuf;
99	bus_dmamap_t ti_map;
100};
101
102struct 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
118CTASSERT((GPN_SOF | GPN_EOF) == GPN_FRAME);
119CTASSERT((GPN_SOF & GPN_EOF) == 0);
120
121extern struct cfdriver gpn_cd;
122
123static void gpn_ifstart(struct ifnet *);
124
125#ifdef GPNDEBUG
126static uint32_t
127m_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
152static void
153gpn_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
166static int
167gpn_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
190static bool
191gpn_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
234static void
235gpn_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
247static void
248gpn_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->m_pkthdr.rcvif = ifp;
302		KASSERT(((m->m_pkthdr.len + 63) >> 6) == gd->gd_pktlen64);
303		ifp->if_ipackets++;
304		ifp->if_ibytes += m->m_pkthdr.len;
305		bpf_mtap(ifp, m);
306#ifdef GPNDEBUG
307		printf("%s: rx len=%d crc=%#x\n", ifp->if_xname,
308		    m->m_pkthdr.len, m_crc32_le(m));
309#endif
310		(*ifp->if_input)(ifp, m);
311	}
312
313out:
314	gpn_ack_txid(sc, gd->gd_txid);
315}
316
317static void
318gpn_free_txid(struct gpn_softc *sc, size_t txid)
319{
320	struct gpn_txinfo * const ti = sc->sc_txinfo + txid;
321
322	KASSERT(txid < MAX_TXACTIVE);
323
324	if (ti->ti_mbuf == NULL)
325		return;
326
327	bus_dmamap_sync(sc->sc_dmat, ti->ti_map,
328	    0, ti->ti_mbuf->m_len, BUS_DMASYNC_POSTREAD);
329	bus_dmamap_unload(sc->sc_dmat, ti->ti_map);
330	m_freem(ti->ti_mbuf);
331	ti->ti_mbuf = NULL;
332	sc->sc_txactive--;
333	KASSERT(sc->sc_txactive < MAX_TXACTIVE);
334	if (sc->sc_if.if_flags & IFF_OACTIVE) {
335		sc->sc_if.if_flags &= ~IFF_OACTIVE;
336		gpn_ifstart(&sc->sc_if);
337	}
338
339}
340
341static void
342gpn_ipm_rebate(void *arg, size_t count)
343{
344	struct gpn_softc * const sc = arg;
345	int s;
346
347	s = splnet();
348	sc->sc_free += count;
349
350	sc->sc_if.if_flags &= ~IFF_OACTIVE;
351	gpn_ifstart(&sc->sc_if);
352	splx(s);
353}
354
355static void
356gpn_ifstart(struct ifnet *ifp)
357{
358	struct gpn_softc * const sc = ifp->if_softc;
359
360	for (;;) {
361		struct mbuf *m, *m0;
362		ipm_gpn_desc_t gd;
363		ipm_gpn_desc_t *last_gd;
364		size_t count;
365
366		if (sc->sc_free == 0) {
367			ifp->if_flags |= IFF_OACTIVE;
368			break;
369		}
370
371		IF_DEQUEUE(&ifp->if_snd, m);
372		if (!m)
373			break;
374
375		if ((ifp->if_flags & IFF_UP) == 0) {
376			m_freem(m);
377			continue;
378		}
379
380		/*
381		 * Make sure to send any pending acks first.
382		 */
383		if (sc->sc_ack_desc.agd_subtype) {
384			sc->sc_free--;
385			sc->sc_ack_desc.agd_subtype += GPN_ACK0;
386			gemini_ipm_produce(&sc->sc_ack_desc, 1);
387			sc->sc_ack_desc.agd_subtype = 0;
388		}
389
390		/*
391		 * Let's find out how many mbufs we are using.
392		 */
393		for (m0 = m, count = 0; m0; m0 = m0->m_next) {
394			if (m0->m_len == 0)
395				continue;
396			count++;
397		}
398
399		/*
400		 * Make sure there is always enough room.
401		 */
402		if (sc->sc_free < count
403		    || sc->sc_txactive + count > MAX_TXACTIVE) {
404			IF_PREPEND(&ifp->if_snd, m);
405			ifp->if_flags |= IFF_OACTIVE;
406			return;
407		}
408
409		bpf_mtap(ifp, m);
410#ifdef GPNDEBUG
411		printf("%s: tx len=%d crc=%#x\n", ifp->if_xname,
412		    m->m_pkthdr.len, m_crc32_le(m));
413#endif
414
415		last_gd = NULL;
416		gd.gd_tag = IPM_TAG_GPN;
417		gd.gd_subtype = GPN_SOF;
418		gd.gd_pktlen64 = (m->m_pkthdr.len + 63) >> 6;
419		for (; m != NULL; m = m0) {
420			struct gpn_txinfo *ti;
421			bus_dmamap_t map;
422			size_t id;
423			int error;
424
425			m0 = m->m_next;
426			m->m_next = NULL;
427			if (m->m_len == 0) {
428				m_free(m);
429				continue;
430			}
431			if (last_gd) {
432				sc->sc_txactive++;
433				sc->sc_free--;
434				gemini_ipm_produce(last_gd, 1);
435				last_gd = NULL;
436				gd.gd_subtype = GPN_MOF;
437			}
438			for (id = sc->sc_lastid;
439			     sc->sc_txinfo[id].ti_mbuf != NULL;) {
440				if (++id == __arraycount(sc->sc_txinfo))
441					id = 0;
442			}
443			KASSERT(id < MAX_TXACTIVE);
444			ti = sc->sc_txinfo + id;
445			map = ti->ti_map;
446			error = bus_dmamap_load(sc->sc_dmat, map,
447			    mtod(m, void *), m->m_len, NULL,
448			    BUS_DMA_READ|BUS_DMA_NOWAIT);
449			if (error) {
450				ifp->if_oerrors++;
451				m_freem(m);
452				break;
453			}
454			bus_dmamap_sync(sc->sc_dmat, map, 0,
455			    m->m_len, BUS_DMASYNC_PREREAD);
456			KASSERT(map->dm_nsegs > 0);
457			KASSERT(map->dm_nsegs <= 2);
458			KASSERT(map->dm_segs[0].ds_addr != 0);
459			gd.gd_len1 = map->dm_segs[0].ds_len;
460			gd.gd_addr1 = map->dm_segs[0].ds_addr;
461			if (map->dm_nsegs == 1) {
462				gd.gd_len2 = 0;
463				gd.gd_addr2 = 0;
464			} else {
465				KASSERT(map->dm_segs[0].ds_addr != 0);
466				gd.gd_len2 = map->dm_segs[1].ds_len;
467				gd.gd_addr2 = map->dm_segs[1].ds_addr;
468			}
469
470			gd.gd_txid = id;
471			ti->ti_mbuf = m;
472			last_gd = &gd;
473			ifp->if_obytes += m->m_len;
474		}
475		ifp->if_opackets++;
476		last_gd->gd_subtype |= GPN_EOF;
477		sc->sc_txactive++;
478		sc->sc_free--;
479		gemini_ipm_produce(last_gd, 1);
480	}
481}
482
483static void
484gpn_ipm_ifup(struct gpn_softc *sc)
485{
486	sc->sc_remoteup = true;
487	if (sc->sc_if.if_flags & IFF_UP)
488		ifmedia_set(&sc->sc_im, IFM_ETHER|IFM_1000_T|IFM_FDX);
489}
490
491static void
492gpn_ipm_ifdown(struct gpn_softc *sc)
493{
494	struct gpn_txinfo *ti = sc->sc_txinfo;
495	struct gpn_txinfo * const end_ti = ti + __arraycount(sc->sc_txinfo);
496
497	if (sc->sc_rxmbuf) {
498		m_freem(sc->sc_rxmbuf);
499		sc->sc_rxmbuf = NULL;
500	}
501
502	IF_PURGE(&sc->sc_if.if_snd);
503
504	for (; ti < end_ti; ti++) {
505		if (ti->ti_mbuf == NULL)
506			continue;
507		bus_dmamap_sync(sc->sc_dmat, ti->ti_map,
508		    0, ti->ti_mbuf->m_len, BUS_DMASYNC_POSTREAD);
509		bus_dmamap_unload(sc->sc_dmat, ti->ti_map);
510		m_freem(ti->ti_mbuf);
511		ti->ti_mbuf = NULL;
512	}
513	sc->sc_lastid = 0;
514	ifmedia_set(&sc->sc_im, IFM_ETHER|IFM_NONE);
515	sc->sc_remoteup = false;
516}
517
518static void
519gpn_ipm_handler(void *arg, const void *desc)
520{
521	struct gpn_softc * const sc = arg;
522	const ipm_gpn_desc_t * const gd = desc;
523	const ipm_gpn_ack_desc_t * const agd = desc;
524	int s;
525
526	s = splnet();
527
528	switch (gd->gd_subtype) {
529	case GPN_ACK14: gpn_free_txid(sc, agd->agd_txids[13]); /* FALLTHROUGH */
530	case GPN_ACK13: gpn_free_txid(sc, agd->agd_txids[12]); /* FALLTHROUGH */
531	case GPN_ACK12: gpn_free_txid(sc, agd->agd_txids[11]); /* FALLTHROUGH */
532	case GPN_ACK11: gpn_free_txid(sc, agd->agd_txids[10]); /* FALLTHROUGH */
533	case GPN_ACK10: gpn_free_txid(sc, agd->agd_txids[9]); /* FALLTHROUGH */
534	case GPN_ACK9: gpn_free_txid(sc, agd->agd_txids[8]); /* FALLTHROUGH */
535	case GPN_ACK8: gpn_free_txid(sc, agd->agd_txids[7]); /* FALLTHROUGH */
536	case GPN_ACK7: gpn_free_txid(sc, agd->agd_txids[6]); /* FALLTHROUGH */
537	case GPN_ACK6: gpn_free_txid(sc, agd->agd_txids[5]); /* FALLTHROUGH */
538	case GPN_ACK5: gpn_free_txid(sc, agd->agd_txids[4]); /* FALLTHROUGH */
539	case GPN_ACK4: gpn_free_txid(sc, agd->agd_txids[3]); /* FALLTHROUGH */
540	case GPN_ACK3: gpn_free_txid(sc, agd->agd_txids[2]); /* FALLTHROUGH */
541	case GPN_ACK2: gpn_free_txid(sc, agd->agd_txids[1]); /* FALLTHROUGH */
542	case GPN_ACK1: gpn_free_txid(sc, agd->agd_txids[0]); break;
543	case GPN_MOF:
544	case GPN_SOF:
545	case GPN_FRAME:
546	case GPN_EOF:
547		gpn_process_data(sc, gd);
548		break;
549	case GPN_IFUP:
550		gpn_ipm_ifup(sc);
551		break;
552	case GPN_IFDOWN:
553		gpn_ipm_ifdown(sc);
554		break;
555	default:
556		KASSERT(0);
557	}
558
559	splx(s);
560}
561
562static int
563gpn_ifinit(struct ifnet *ifp)
564{
565	struct gpn_softc * const sc = ifp->if_softc;
566	ipm_gpn_desc_t gd;
567	int error;
568
569	error = gpn_alloc_dmamaps(sc);
570	if (error)
571		return error;
572
573	memset(&gd, 0, sizeof(gd));
574	gd.gd_tag = IPM_TAG_GPN;
575	gd.gd_subtype = GPN_IFUP;
576	KASSERT(sc->sc_free > 0);
577	sc->sc_free--;
578	gemini_ipm_produce(&gd, 1);
579
580	if (sc->sc_remoteup)
581		ifmedia_set(&sc->sc_im, IFM_ETHER|IFM_1000_T|IFM_FDX);
582
583	ifp->if_flags |= IFF_RUNNING;
584
585	return error;
586}
587
588static void
589gpn_ifstop(struct ifnet *ifp, int disable)
590{
591	struct gpn_softc * const sc = ifp->if_softc;
592	ipm_gpn_desc_t gd;
593
594	memset(&gd, 0, sizeof(gd));
595	gd.gd_tag = IPM_TAG_GPN;
596	gd.gd_subtype = GPN_IFDOWN;
597	KASSERT(sc->sc_free > 0);
598	sc->sc_free--;
599	gemini_ipm_produce(&gd, 1);
600	ifp->if_flags &= ~IFF_RUNNING;
601	gpn_ipm_ifdown(sc);
602
603	if (disable) {
604		gpn_free_dmamaps(sc);
605	}
606}
607
608static int
609gpn_ifioctl(struct ifnet *ifp, u_long cmd, void *data)
610{
611	struct gpn_softc * const sc = ifp->if_softc;
612	struct ifreq * const ifr = data;
613	struct ifaliasreq * const ifra = data;
614	int s, error;
615
616	s = splnet();
617
618	switch (cmd) {
619	case SIOCSIFMEDIA:
620	case SIOCGIFMEDIA:
621		error = ifmedia_ioctl(ifp, ifr, &sc->sc_im, cmd);
622		break;
623	case SIOCSIFPHYADDR: {
624		const struct sockaddr_dl *sdl = satosdl(&ifra->ifra_addr);
625
626		if (sdl->sdl_family != AF_LINK) {
627			error = EINVAL;
628			break;
629		}
630
631		if_set_sadl(ifp, CLLADDR(sdl), ETHER_ADDR_LEN, false);
632		error = 0;
633		break;
634	}
635	default:
636		error = ether_ioctl(ifp, cmd, data);
637		if (error == ENETRESET)
638			error = 0;
639		break;
640	}
641
642	splx(s);
643	return error;
644}
645
646static int
647gpn_mediachange(struct ifnet *ifp)
648{
649	return 0;
650}
651
652static void
653gpn_mediastatus(struct ifnet *ifp, struct ifmediareq *imr)
654{
655	struct gpn_softc * const sc = ifp->if_softc;
656	imr->ifm_active = sc->sc_im.ifm_cur->ifm_media;
657}
658
659static int
660gpn_match(device_t parent, cfdata_t cf, void *aux)
661{
662	return strcmp(gpn_cd.cd_name, aux) == 0;
663}
664
665static void
666gpn_attach(device_t parent, device_t self, void *aux)
667{
668	struct gpn_softc * const sc = device_private(self);
669	struct ifnet * const ifp = &sc->sc_if;
670	char enaddr[6];
671
672	enaddr[0] = 2;
673	enaddr[1] = 0;
674	enaddr[2] = 0;
675	enaddr[3] = 0;
676	enaddr[4] = 0;
677#ifdef GEMINI_MASTER
678	enaddr[5] = 0;
679#elif defined(GEMINI_SLAVE)
680	enaddr[5] = 1;
681#else
682#error not master nor slave
683#endif
684
685	aprint_normal("\n");
686	aprint_naive("\n");
687	sc->sc_dev = self;
688	sc->sc_dmat = &gemini_bus_dma_tag;
689
690	/*
691	 * Pretend we are full-duplex gigabit ethernet.
692	 */
693	ifmedia_init(&sc->sc_im, 0, gpn_mediachange, gpn_mediastatus);
694	ifmedia_add(&sc->sc_im, IFM_ETHER|IFM_1000_T|IFM_FDX, 0, NULL);
695	ifmedia_add(&sc->sc_im, IFM_ETHER|IFM_NONE, 0, NULL);
696	ifmedia_set(&sc->sc_im, IFM_ETHER|IFM_NONE);
697
698	strlcpy(ifp->if_xname, device_xname(self), sizeof(ifp->if_xname));
699	ifp->if_softc = sc;
700	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
701	ifp->if_ioctl = gpn_ifioctl;
702	ifp->if_start = gpn_ifstart;
703	ifp->if_init  = gpn_ifinit;
704	ifp->if_stop  = gpn_ifstop;
705
706	IFQ_SET_READY(&ifp->if_snd);
707
708	sc->sc_ec.ec_capabilities = ETHERCAP_VLAN_MTU | ETHERCAP_JUMBO_MTU;
709
710	if_attach(ifp);
711	ether_ifattach(ifp, enaddr);
712
713	sc->sc_free = MAX_TXACTIVE*2;
714	sc->sc_ih = gemini_ipm_register(IPM_TAG_GPN, IPL_SOFTNET, sc->sc_free,
715	    gpn_ipm_handler, gpn_ipm_rebate, sc);
716	KASSERT(sc->sc_ih);
717
718	sc->sc_ack_desc.agd_tag = IPM_TAG_GPN;
719}
720
721void gpn_print_gd(ipm_gpn_desc_t *);
722void
723gpn_print_gd(ipm_gpn_desc_t *gd)
724{
725	printf("%s: %p\n", __FUNCTION__, gd);
726	printf("\ttag %d, subtype %d, id %d, pktlen64 %d\n",
727		gd->gd_tag, gd->gd_subtype, gd->gd_txid, gd->gd_pktlen64);
728	printf("\tlen1 %d, len2 %d, addr1 %#x, addr2 %#x\n",
729		gd->gd_len1, gd->gd_len2, gd->gd_addr1, gd->gd_addr2);
730}
731
732CFATTACH_DECL_NEW(gpn, sizeof(struct gpn_softc),
733    gpn_match, gpn_attach, NULL, NULL);
734