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