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