1 /* $NetBSD: if_gpn.c,v 1.7 2016/12/15 09:28:02 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@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.7 2016/12/15 09:28:02 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