1 /* $NetBSD: if_gpn.c,v 1.18 2024/06/29 12:11:10 riastradh 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.18 2024/06/29 12:11:10 riastradh 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 bool sc_txbusy;
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
m_crc32_le(struct mbuf * m)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
gpn_free_dmamaps(struct gpn_softc * sc)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
gpn_alloc_dmamaps(struct gpn_softc * sc)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
gpn_add_data(struct gpn_softc * sc,bus_addr_t addr,bus_size_t len)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
gpn_ack_txid(struct gpn_softc * sc,unsigned int txid)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
gpn_process_data(struct gpn_softc * sc,const ipm_gpn_desc_t * gd)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 if_statinc(ifp, if_ierrors);
257 goto out;
258 }
259
260 if ((subtype & GPN_SOF) && sc->sc_rxmbuf != NULL) {
261 if_statinc(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 if_statinc(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 if_statinc(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 if_statinc(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 #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
gpn_free_txid(struct gpn_softc * sc,size_t txid)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_txbusy) {
332 sc->sc_txbusy = false;
333 gpn_ifstart(&sc->sc_if);
334 }
335 }
336
337 static void
gpn_ipm_rebate(void * arg,size_t count)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_txbusy = false;
347 gpn_ifstart(&sc->sc_if);
348 splx(s);
349 }
350
351 static void
gpn_ifstart(struct ifnet * ifp)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 sc->sc_txbusy = true;
364 break;
365 }
366
367 IF_POLL(&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 sc->sc_txbusy = true;
401 return;
402 }
403 IF_DEQUEUE(&ifp->if_snd, m);
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 net_stat_ref_t nsr = IF_STAT_GETREF(ifp);
416 for (; m != NULL; m = m0) {
417 struct gpn_txinfo *ti;
418 bus_dmamap_t map;
419 size_t id;
420 int error;
421
422 m0 = m->m_next;
423 m->m_next = NULL;
424 if (m->m_len == 0) {
425 m_free(m);
426 continue;
427 }
428 if (last_gd) {
429 sc->sc_txactive++;
430 sc->sc_free--;
431 gemini_ipm_produce(last_gd, 1);
432 last_gd = NULL;
433 gd.gd_subtype = GPN_MOF;
434 }
435 for (id = sc->sc_lastid;
436 sc->sc_txinfo[id].ti_mbuf != NULL;) {
437 if (++id == __arraycount(sc->sc_txinfo))
438 id = 0;
439 }
440 KASSERT(id < MAX_TXACTIVE);
441 ti = sc->sc_txinfo + id;
442 map = ti->ti_map;
443 error = bus_dmamap_load(sc->sc_dmat, map,
444 mtod(m, void *), m->m_len, NULL,
445 BUS_DMA_READ | BUS_DMA_NOWAIT);
446 if (error) {
447 if_statinc_ref(ifp, nsr, if_oerrors);
448 m_freem(m);
449 break;
450 }
451 bus_dmamap_sync(sc->sc_dmat, map, 0,
452 m->m_len, BUS_DMASYNC_PREREAD);
453 KASSERT(map->dm_nsegs > 0);
454 KASSERT(map->dm_nsegs <= 2);
455 KASSERT(map->dm_segs[0].ds_addr != 0);
456 gd.gd_len1 = map->dm_segs[0].ds_len;
457 gd.gd_addr1 = map->dm_segs[0].ds_addr;
458 if (map->dm_nsegs == 1) {
459 gd.gd_len2 = 0;
460 gd.gd_addr2 = 0;
461 } else {
462 KASSERT(map->dm_segs[0].ds_addr != 0);
463 gd.gd_len2 = map->dm_segs[1].ds_len;
464 gd.gd_addr2 = map->dm_segs[1].ds_addr;
465 }
466
467 gd.gd_txid = id;
468 ti->ti_mbuf = m;
469 last_gd = &gd;
470 if_statadd_ref(ifp, nsr, if_obytes, m->m_len);
471 }
472 if_statinc_ref(ifp, nsr, if_opackets);
473 IF_STAT_PUTREF(ifp);
474
475 if (last_gd != NULL) {
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
485 static void
gpn_ipm_ifup(struct gpn_softc * sc)486 gpn_ipm_ifup(struct gpn_softc *sc)
487 {
488 sc->sc_remoteup = true;
489 if (sc->sc_if.if_flags & IFF_UP)
490 ifmedia_set(&sc->sc_im, IFM_ETHER | IFM_1000_T | IFM_FDX);
491 }
492
493 static void
gpn_ipm_ifdown(struct gpn_softc * sc)494 gpn_ipm_ifdown(struct gpn_softc *sc)
495 {
496 struct gpn_txinfo *ti = sc->sc_txinfo;
497 struct gpn_txinfo * const end_ti = ti + __arraycount(sc->sc_txinfo);
498
499 if (sc->sc_rxmbuf) {
500 m_freem(sc->sc_rxmbuf);
501 sc->sc_rxmbuf = NULL;
502 }
503
504 IF_PURGE(&sc->sc_if.if_snd);
505
506 for (; ti < end_ti; ti++) {
507 if (ti->ti_mbuf == NULL)
508 continue;
509 bus_dmamap_sync(sc->sc_dmat, ti->ti_map,
510 0, ti->ti_mbuf->m_len, BUS_DMASYNC_POSTREAD);
511 bus_dmamap_unload(sc->sc_dmat, ti->ti_map);
512 m_freem(ti->ti_mbuf);
513 ti->ti_mbuf = NULL;
514 }
515 sc->sc_lastid = 0;
516 ifmedia_set(&sc->sc_im, IFM_ETHER | IFM_NONE);
517 sc->sc_remoteup = false;
518 }
519
520 static void
gpn_ipm_handler(void * arg,const void * desc)521 gpn_ipm_handler(void *arg, const void *desc)
522 {
523 struct gpn_softc * const sc = arg;
524 const ipm_gpn_desc_t * const gd = desc;
525 const ipm_gpn_ack_desc_t * const agd = desc;
526 int s;
527
528 s = splnet();
529
530 switch (gd->gd_subtype) {
531 case GPN_ACK14: gpn_free_txid(sc, agd->agd_txids[13]); /* FALLTHROUGH */
532 case GPN_ACK13: gpn_free_txid(sc, agd->agd_txids[12]); /* FALLTHROUGH */
533 case GPN_ACK12: gpn_free_txid(sc, agd->agd_txids[11]); /* FALLTHROUGH */
534 case GPN_ACK11: gpn_free_txid(sc, agd->agd_txids[10]); /* FALLTHROUGH */
535 case GPN_ACK10: gpn_free_txid(sc, agd->agd_txids[9]); /* FALLTHROUGH */
536 case GPN_ACK9: gpn_free_txid(sc, agd->agd_txids[8]); /* FALLTHROUGH */
537 case GPN_ACK8: gpn_free_txid(sc, agd->agd_txids[7]); /* FALLTHROUGH */
538 case GPN_ACK7: gpn_free_txid(sc, agd->agd_txids[6]); /* FALLTHROUGH */
539 case GPN_ACK6: gpn_free_txid(sc, agd->agd_txids[5]); /* FALLTHROUGH */
540 case GPN_ACK5: gpn_free_txid(sc, agd->agd_txids[4]); /* FALLTHROUGH */
541 case GPN_ACK4: gpn_free_txid(sc, agd->agd_txids[3]); /* FALLTHROUGH */
542 case GPN_ACK3: gpn_free_txid(sc, agd->agd_txids[2]); /* FALLTHROUGH */
543 case GPN_ACK2: gpn_free_txid(sc, agd->agd_txids[1]); /* FALLTHROUGH */
544 case GPN_ACK1: gpn_free_txid(sc, agd->agd_txids[0]); break;
545 case GPN_MOF:
546 case GPN_SOF:
547 case GPN_FRAME:
548 case GPN_EOF:
549 gpn_process_data(sc, gd);
550 break;
551 case GPN_IFUP:
552 gpn_ipm_ifup(sc);
553 break;
554 case GPN_IFDOWN:
555 gpn_ipm_ifdown(sc);
556 break;
557 default:
558 KASSERT(0);
559 }
560
561 splx(s);
562 }
563
564 static int
gpn_ifinit(struct ifnet * ifp)565 gpn_ifinit(struct ifnet *ifp)
566 {
567 struct gpn_softc * const sc = ifp->if_softc;
568 ipm_gpn_desc_t gd;
569 int error;
570
571 error = gpn_alloc_dmamaps(sc);
572 if (error)
573 return error;
574
575 memset(&gd, 0, sizeof(gd));
576 gd.gd_tag = IPM_TAG_GPN;
577 gd.gd_subtype = GPN_IFUP;
578 KASSERT(sc->sc_free > 0);
579 sc->sc_free--;
580 gemini_ipm_produce(&gd, 1);
581
582 if (sc->sc_remoteup)
583 ifmedia_set(&sc->sc_im, IFM_ETHER | IFM_1000_T | IFM_FDX);
584
585 ifp->if_flags |= IFF_RUNNING;
586
587 return error;
588 }
589
590 static void
gpn_ifstop(struct ifnet * ifp,int disable)591 gpn_ifstop(struct ifnet *ifp, int disable)
592 {
593 struct gpn_softc * const sc = ifp->if_softc;
594 ipm_gpn_desc_t gd;
595
596 memset(&gd, 0, sizeof(gd));
597 gd.gd_tag = IPM_TAG_GPN;
598 gd.gd_subtype = GPN_IFDOWN;
599 KASSERT(sc->sc_free > 0);
600 sc->sc_free--;
601 gemini_ipm_produce(&gd, 1);
602 ifp->if_flags &= ~IFF_RUNNING;
603 gpn_ipm_ifdown(sc);
604
605 if (disable) {
606 gpn_free_dmamaps(sc);
607 }
608 }
609
610 static int
gpn_ifioctl(struct ifnet * ifp,u_long cmd,void * data)611 gpn_ifioctl(struct ifnet *ifp, u_long cmd, void *data)
612 {
613 struct ifaliasreq * const ifra = data;
614 int s, error;
615
616 s = splnet();
617
618 switch (cmd) {
619 case SIOCSIFPHYADDR: {
620 const struct sockaddr_dl *sdl = satosdl(&ifra->ifra_addr);
621
622 if (sdl->sdl_family != AF_LINK) {
623 error = EINVAL;
624 break;
625 }
626
627 if_set_sadl(ifp, CLLADDR(sdl), ETHER_ADDR_LEN, false);
628 error = 0;
629 break;
630 }
631 default:
632 error = ether_ioctl(ifp, cmd, data);
633 if (error == ENETRESET)
634 error = 0;
635 break;
636 }
637
638 splx(s);
639 return error;
640 }
641
642 static int
gpn_mediachange(struct ifnet * ifp)643 gpn_mediachange(struct ifnet *ifp)
644 {
645 return 0;
646 }
647
648 static void
gpn_mediastatus(struct ifnet * ifp,struct ifmediareq * imr)649 gpn_mediastatus(struct ifnet *ifp, struct ifmediareq *imr)
650 {
651 struct gpn_softc * const sc = ifp->if_softc;
652 imr->ifm_active = sc->sc_im.ifm_cur->ifm_media;
653 }
654
655 static int
gpn_match(device_t parent,cfdata_t cf,void * aux)656 gpn_match(device_t parent, cfdata_t cf, void *aux)
657 {
658 return strcmp(gpn_cd.cd_name, aux) == 0;
659 }
660
661 static void
gpn_attach(device_t parent,device_t self,void * aux)662 gpn_attach(device_t parent, device_t self, void *aux)
663 {
664 struct gpn_softc * const sc = device_private(self);
665 struct ifnet * const ifp = &sc->sc_if;
666 char enaddr[6];
667
668 enaddr[0] = 2;
669 enaddr[1] = 0;
670 enaddr[2] = 0;
671 enaddr[3] = 0;
672 enaddr[4] = 0;
673 #ifdef GEMINI_MASTER
674 enaddr[5] = 0;
675 #elif defined(GEMINI_SLAVE)
676 enaddr[5] = 1;
677 #else
678 #error not master nor slave
679 #endif
680
681 aprint_normal("\n");
682 aprint_naive("\n");
683 sc->sc_dev = self;
684 sc->sc_dmat = &gemini_bus_dma_tag;
685
686 /* Setup ifmedia interface */
687 sc->sc_ec.ec_ifmedia = &sc->sc_im;
688 ifmedia_init(&sc->sc_im, 0, gpn_mediachange, gpn_mediastatus);
689 /* Pretend we are full-duplex gigabit ethernet. */
690 ifmedia_add(&sc->sc_im, IFM_ETHER | IFM_1000_T | IFM_FDX, 0, NULL);
691 ifmedia_add(&sc->sc_im, IFM_ETHER | IFM_NONE, 0, NULL);
692 ifmedia_set(&sc->sc_im, IFM_ETHER | IFM_NONE);
693
694 strlcpy(ifp->if_xname, device_xname(self), sizeof(ifp->if_xname));
695 ifp->if_softc = sc;
696 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
697 ifp->if_ioctl = gpn_ifioctl;
698 ifp->if_start = gpn_ifstart;
699 ifp->if_init = gpn_ifinit;
700 ifp->if_stop = gpn_ifstop;
701
702 IFQ_SET_READY(&ifp->if_snd);
703
704 sc->sc_ec.ec_capabilities = ETHERCAP_VLAN_MTU | ETHERCAP_JUMBO_MTU;
705
706 if_attach(ifp);
707 ether_ifattach(ifp, enaddr);
708
709 sc->sc_free = MAX_TXACTIVE*2;
710 sc->sc_ih = gemini_ipm_register(IPM_TAG_GPN, IPL_SOFTNET, sc->sc_free,
711 gpn_ipm_handler, gpn_ipm_rebate, sc);
712 KASSERT(sc->sc_ih);
713
714 sc->sc_ack_desc.agd_tag = IPM_TAG_GPN;
715 }
716
717 void gpn_print_gd(ipm_gpn_desc_t *);
718 void
gpn_print_gd(ipm_gpn_desc_t * gd)719 gpn_print_gd(ipm_gpn_desc_t *gd)
720 {
721 printf("%s: %p\n", __FUNCTION__, gd);
722 printf("\ttag %d, subtype %d, id %d, pktlen64 %d\n",
723 gd->gd_tag, gd->gd_subtype, gd->gd_txid, gd->gd_pktlen64);
724 printf("\tlen1 %d, len2 %d, addr1 %#x, addr2 %#x\n",
725 gd->gd_len1, gd->gd_len2, gd->gd_addr1, gd->gd_addr2);
726 }
727
728 CFATTACH_DECL_NEW(gpn, sizeof(struct gpn_softc),
729 gpn_match, gpn_attach, NULL, NULL);
730