1 /* $NetBSD: if_smap.c,v 1.9 2007/03/04 06:00:30 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 2001 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by UCHIYAMA Yasushi. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 #include <sys/cdefs.h> 40 __KERNEL_RCSID(0, "$NetBSD: if_smap.c,v 1.9 2007/03/04 06:00:30 christos Exp $"); 41 42 #include "debug_playstation2.h" 43 44 #include "bpfilter.h" 45 #include "rnd.h" 46 47 #include <sys/param.h> 48 #include <sys/systm.h> 49 50 #include <sys/syslog.h> 51 #include <sys/mbuf.h> 52 #include <sys/ioctl.h> 53 #include <sys/socket.h> 54 55 #include <playstation2/ee/eevar.h> 56 57 #if NRND > 0 58 #include <sys/rnd.h> 59 #endif 60 61 #include <net/if.h> 62 #include <net/if_dl.h> 63 #include <net/if_types.h> 64 65 #include <net/if_ether.h> 66 #include <net/if_media.h> 67 68 #include <dev/mii/mii.h> 69 #include <dev/mii/miivar.h> 70 71 #include <netinet/in.h> 72 #include <netinet/in_systm.h> 73 #include <netinet/in_var.h> 74 #include <netinet/ip.h> 75 #include <netinet/if_inarp.h> 76 77 #if NBPFILTER > 0 78 #include <net/bpf.h> 79 #include <net/bpfdesc.h> 80 #endif 81 82 #include <playstation2/dev/spdvar.h> 83 #include <playstation2/dev/spdreg.h> 84 #include <playstation2/dev/emac3var.h> 85 #include <playstation2/dev/if_smapreg.h> 86 87 #ifdef SMAP_DEBUG 88 #include <playstation2/ee/gsvar.h> 89 int smap_debug = 0; 90 #define DPRINTF(fmt, args...) \ 91 if (smap_debug) \ 92 printf("%s: " fmt, __FUNCTION__ , ##args) 93 #define DPRINTFN(n, arg) \ 94 if (smap_debug > (n)) \ 95 printf("%s: " fmt, __FUNCTION__ , ##args) 96 #define STATIC 97 struct smap_softc *__sc; 98 void __smap_status(int); 99 void __smap_lock_check(const char *, int); 100 #define FUNC_ENTER() __smap_lock_check(__FUNCTION__, 1) 101 #define FUNC_EXIT() __smap_lock_check(__FUNCTION__, 0) 102 #else 103 #define DPRINTF(arg...) ((void)0) 104 #define DPRINTFN(n, arg...) ((void)0) 105 #define STATIC static 106 #define FUNC_ENTER() ((void)0) 107 #define FUNC_EXIT() ((void)0) 108 #endif 109 110 struct smap_softc { 111 struct emac3_softc emac3; 112 struct ethercom ethercom; 113 114 u_int32_t *tx_buf; 115 u_int32_t *rx_buf; 116 struct smap_desc *tx_desc; 117 struct smap_desc *rx_desc; 118 119 #define SMAP_FIFO_ALIGN 4 120 int tx_buf_freesize; /* buffer usage */ 121 int tx_desc_cnt; /* descriptor usage */ 122 u_int16_t tx_fifo_ptr; 123 int tx_done_index, tx_start_index; 124 int rx_done_index; 125 126 #if NRND > 0 127 rndsource_element_t rnd_source; 128 #endif 129 }; 130 131 #define DEVNAME (sc->emac3.dev.dv_xname) 132 #define ROUND4(x) (((x) + 3) & ~3) 133 #define ROUND16(x) (((x) + 15) & ~15) 134 135 STATIC int smap_match(struct device *, struct cfdata *, void *); 136 STATIC void smap_attach(struct device *, struct device *, void *); 137 138 CFATTACH_DECL(smap, sizeof (struct smap_softc), 139 smap_match, smap_attach, NULL, NULL); 140 141 STATIC int smap_intr(void *); 142 STATIC void smap_rxeof(void *); 143 STATIC void smap_txeof(void *); 144 STATIC void smap_start(struct ifnet *); 145 STATIC void smap_watchdog(struct ifnet *); 146 STATIC int smap_ioctl(struct ifnet *, u_long, void *); 147 STATIC int smap_init(struct ifnet *); 148 STATIC void smap_stop(struct ifnet *, int); 149 150 STATIC int smap_get_eaddr(struct smap_softc *, u_int8_t *); 151 STATIC int smap_fifo_init(struct smap_softc *); 152 STATIC int smap_fifo_reset(bus_addr_t); 153 STATIC void smap_desc_init(struct smap_softc *); 154 155 int 156 smap_match(struct device *parent, struct cfdata *cf, void *aux) 157 { 158 struct spd_attach_args *spa = aux; 159 160 if (spa->spa_slot != SPD_NIC) 161 return (0); 162 163 return (1); 164 } 165 166 void 167 smap_attach(struct device *parent, struct device *self, void *aux) 168 { 169 struct spd_attach_args *spa = aux; 170 struct smap_softc *sc = (void *)self; 171 struct emac3_softc *emac3 = &sc->emac3; 172 struct ifnet *ifp = &sc->ethercom.ec_if; 173 struct mii_data *mii = &emac3->mii; 174 void *txbuf, *rxbuf; 175 u_int16_t r; 176 177 #ifdef SMAP_DEBUG 178 __sc = sc; 179 #endif 180 181 printf(": %s\n", spa->spa_product_name); 182 183 /* SPD EEPROM */ 184 if (smap_get_eaddr(sc, emac3->eaddr) != 0) 185 return; 186 187 printf("%s: Ethernet address %s\n", DEVNAME, 188 ether_sprintf(emac3->eaddr)); 189 190 /* disable interrupts */ 191 r = _reg_read_2(SPD_INTR_ENABLE_REG16); 192 r &= ~(SPD_INTR_RXEND | SPD_INTR_TXEND | SPD_INTR_RXDNV | 193 SPD_INTR_EMAC3); 194 _reg_write_2(SPD_INTR_ENABLE_REG16, r); 195 emac3_intr_disable(); 196 197 /* clear pending interrupts */ 198 _reg_write_2(SPD_INTR_CLEAR_REG16, SPD_INTR_RXEND | SPD_INTR_TXEND | 199 SPD_INTR_RXDNV); 200 emac3_intr_clear(); 201 202 /* buffer descriptor mode */ 203 _reg_write_1(SMAP_DESC_MODE_REG8, 0); 204 205 if (smap_fifo_init(sc) != 0) 206 return; 207 208 if (emac3_init(&sc->emac3) != 0) 209 return; 210 emac3_intr_disable(); 211 emac3_disable(); 212 213 smap_desc_init(sc); 214 215 /* allocate temporary buffer */ 216 txbuf = malloc(ETHER_MAX_LEN - ETHER_CRC_LEN + SMAP_FIFO_ALIGN + 16, 217 M_DEVBUF, M_NOWAIT); 218 if (txbuf == NULL) { 219 printf("%s: no memory.\n", DEVNAME); 220 return; 221 } 222 223 rxbuf = malloc(ETHER_MAX_LEN + SMAP_FIFO_ALIGN + 16, 224 M_DEVBUF, M_NOWAIT); 225 if (rxbuf == NULL) { 226 printf("%s: no memory.\n", DEVNAME); 227 free(txbuf, M_DEVBUF); 228 return; 229 } 230 231 sc->tx_buf = (u_int32_t *)ROUND16((vaddr_t)txbuf); 232 sc->rx_buf = (u_int32_t *)ROUND16((vaddr_t)rxbuf); 233 234 /* 235 * setup MI layer 236 */ 237 strcpy(ifp->if_xname, DEVNAME); 238 ifp->if_softc = sc; 239 ifp->if_start = smap_start; 240 ifp->if_ioctl = smap_ioctl; 241 ifp->if_init = smap_init; 242 ifp->if_stop = smap_stop; 243 ifp->if_watchdog= smap_watchdog; 244 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | 245 IFF_MULTICAST; 246 IFQ_SET_READY(&ifp->if_snd); 247 248 /* ifmedia setup. */ 249 mii->mii_ifp = ifp; 250 mii->mii_readreg = emac3_phy_readreg; 251 mii->mii_writereg = emac3_phy_writereg; 252 mii->mii_statchg = emac3_phy_statchg; 253 ifmedia_init(&mii->mii_media, 0, emac3_ifmedia_upd, emac3_ifmedia_sts); 254 mii_attach(&emac3->dev, mii, 0xffffffff, MII_PHY_ANY, 255 MII_OFFSET_ANY, 0); 256 257 /* Choose a default media. */ 258 if (LIST_FIRST(&mii->mii_phys) == NULL) { 259 ifmedia_add(&mii->mii_media, IFM_ETHER|IFM_NONE, 0, NULL); 260 ifmedia_set(&mii->mii_media, IFM_ETHER|IFM_NONE); 261 } else { 262 ifmedia_set(&mii->mii_media, IFM_ETHER|IFM_AUTO); 263 } 264 265 if_attach(ifp); 266 ether_ifattach(ifp, emac3->eaddr); 267 268 spd_intr_establish(SPD_NIC, smap_intr, sc); 269 270 #if NRND > 0 271 rnd_attach_source(&sc->rnd_source, DEVNAME, 272 RND_TYPE_NET, 0); 273 #endif 274 } 275 276 int 277 smap_ioctl(struct ifnet *ifp, u_long command, void *data) 278 { 279 struct smap_softc *sc = ifp->if_softc; 280 struct ifreq *ifr = (struct ifreq *) data; 281 int error, s; 282 283 s = splnet(); 284 285 switch (command) { 286 case SIOCGIFMEDIA: 287 case SIOCSIFMEDIA: 288 error = ifmedia_ioctl(ifp, ifr, &sc->emac3.mii.mii_media, 289 command); 290 break; 291 292 default: 293 error = ether_ioctl(ifp, command, data); 294 295 if (error == ENETRESET) { 296 if (ifp->if_flags & IFF_RUNNING) 297 emac3_setmulti(&sc->emac3, &sc->ethercom); 298 error = 0; 299 } 300 break; 301 } 302 303 splx(s); 304 305 return (error); 306 } 307 308 int 309 smap_intr(void *arg) 310 { 311 struct smap_softc *sc = arg; 312 struct ifnet *ifp; 313 u_int16_t cause, disable, r; 314 315 cause = _reg_read_2(SPD_INTR_STATUS_REG16) & 316 _reg_read_2(SPD_INTR_ENABLE_REG16); 317 318 disable = cause & (SPD_INTR_RXDNV | SPD_INTR_TXDNV); 319 if (disable) { 320 r = _reg_read_2(SPD_INTR_ENABLE_REG16); 321 r &= ~disable; 322 _reg_write_2(SPD_INTR_ENABLE_REG16, r); 323 324 printf("%s: invalid descriptor. (%c%c)\n", DEVNAME, 325 disable & SPD_INTR_RXDNV ? 'R' : '_', 326 disable & SPD_INTR_TXDNV ? 'T' : '_'); 327 328 if (disable & SPD_INTR_RXDNV) 329 smap_rxeof(arg); 330 331 _reg_write_2(SPD_INTR_CLEAR_REG16, disable); 332 } 333 334 if (cause & SPD_INTR_TXEND) { 335 _reg_write_2(SPD_INTR_CLEAR_REG16, SPD_INTR_TXEND); 336 if (_reg_read_1(SMAP_RXFIFO_FRAME_REG8) > 0) 337 cause |= SPD_INTR_RXEND; 338 smap_txeof(arg); 339 } 340 341 if (cause & SPD_INTR_RXEND) { 342 _reg_write_2(SPD_INTR_CLEAR_REG16, SPD_INTR_RXEND); 343 smap_rxeof(arg); 344 if (sc->tx_desc_cnt > 0 && 345 sc->tx_desc_cnt > _reg_read_1(SMAP_TXFIFO_FRAME_REG8)) 346 smap_txeof(arg); 347 } 348 349 if (cause & SPD_INTR_EMAC3) 350 emac3_intr(arg); 351 352 /* if transmission is pending, start here */ 353 ifp = &sc->ethercom.ec_if; 354 if (IFQ_IS_EMPTY(&ifp->if_snd) == 0) 355 smap_start(ifp); 356 #if NRND > 0 357 rnd_add_uint32(&sc->rnd_source, cause | sc->tx_fifo_ptr << 16); 358 #endif 359 360 return (1); 361 } 362 363 void 364 smap_rxeof(void *arg) 365 { 366 struct smap_softc *sc = arg; 367 struct smap_desc *d; 368 struct ifnet *ifp = &sc->ethercom.ec_if; 369 struct mbuf *m; 370 u_int16_t r16, stat; 371 u_int32_t *p; 372 int i, j, sz, rxsz, cnt; 373 374 FUNC_ENTER(); 375 376 i = sc->rx_done_index; 377 378 for (cnt = 0;; cnt++, i = (i + 1) & 0x3f) { 379 m = NULL; 380 d = &sc->rx_desc[i]; 381 stat = d->stat; 382 383 if ((stat & SMAP_RXDESC_EMPTY) != 0) { 384 break; 385 } else if (stat & 0x7fff) { 386 ifp->if_ierrors++; 387 goto next_packet; 388 } 389 390 sz = d->sz; 391 rxsz = ROUND4(sz); 392 393 KDASSERT(sz >= ETHER_ADDR_LEN * 2 + ETHER_TYPE_LEN); 394 KDASSERT(sz <= ETHER_MAX_LEN); 395 396 /* load data from FIFO */ 397 _reg_write_2(SMAP_RXFIFO_PTR_REG16, d->ptr & 0x3ffc); 398 p = sc->rx_buf; 399 for (j = 0; j < rxsz; j += sizeof(u_int32_t)) { 400 *p++ = _reg_read_4(SMAP_RXFIFO_DATA_REG); 401 } 402 403 /* put to mbuf */ 404 MGETHDR(m, M_DONTWAIT, MT_DATA); 405 if (m == NULL) { 406 printf("%s: unable to allocate Rx mbuf\n", DEVNAME); 407 ifp->if_ierrors++; 408 goto next_packet; 409 } 410 411 if (sz > (MHLEN - 2)) { 412 MCLGET(m, M_DONTWAIT); 413 if ((m->m_flags & M_EXT) == 0) { 414 printf("%s: unable to allocate Rx cluster\n", 415 DEVNAME); 416 m_freem(m); 417 m = NULL; 418 ifp->if_ierrors++; 419 goto next_packet; 420 } 421 } 422 423 m->m_data += 2; /* for alignment */ 424 m->m_pkthdr.rcvif = ifp; 425 m->m_pkthdr.len = m->m_len = sz; 426 memcpy(mtod(m, void *), (void *)sc->rx_buf, sz); 427 428 next_packet: 429 ifp->if_ipackets++; 430 431 _reg_write_1(SMAP_RXFIFO_FRAME_DEC_REG8, 1); 432 433 /* free descriptor */ 434 d->sz = 0; 435 d->ptr = 0; 436 d->stat = SMAP_RXDESC_EMPTY; 437 _wbflush(); 438 439 if (m != NULL) { 440 #if NBPFILTER > 0 441 if (ifp->if_bpf) 442 bpf_mtap(ifp->if_bpf, m); 443 #endif 444 (*ifp->if_input)(ifp, m); 445 } 446 } 447 sc->rx_done_index = i; 448 449 r16 = _reg_read_2(SPD_INTR_ENABLE_REG16); 450 if (((r16 & SPD_INTR_RXDNV) == 0) && cnt > 0) { 451 r16 |= SPD_INTR_RXDNV; 452 _reg_write_2(SPD_INTR_ENABLE_REG16, r16); 453 } 454 455 FUNC_EXIT(); 456 } 457 458 void 459 smap_txeof(void *arg) 460 { 461 struct smap_softc *sc = arg; 462 struct ifnet *ifp = &sc->ethercom.ec_if; 463 struct smap_desc *d; 464 int i; 465 466 FUNC_ENTER(); 467 468 /* clear the timeout timer. */ 469 ifp->if_timer = 0; 470 471 /* garbage collect */ 472 for (i = sc->tx_done_index;; i = (i + 1) & 0x3f) { 473 u_int16_t stat; 474 475 d = &sc->tx_desc[i]; 476 stat = d->stat; 477 if (stat & SMAP_TXDESC_READY) { 478 /* all descriptor processed. */ 479 break; 480 } else if (stat & 0x7fff) { 481 if (stat & (SMAP_TXDESC_ECOLL | SMAP_TXDESC_LCOLL | 482 SMAP_TXDESC_MCOLL | SMAP_TXDESC_SCOLL)) 483 ifp->if_collisions++; 484 else 485 ifp->if_oerrors++; 486 } else { 487 ifp->if_opackets++; 488 } 489 490 if (sc->tx_desc_cnt == 0) 491 break; 492 493 sc->tx_buf_freesize += ROUND4(d->sz); 494 sc->tx_desc_cnt--; 495 496 d->sz = 0; 497 d->ptr = 0; 498 d->stat = 0; 499 _wbflush(); 500 } 501 sc->tx_done_index = i; 502 503 /* OK to start transmit */ 504 ifp->if_flags &= ~IFF_OACTIVE; 505 506 FUNC_EXIT(); 507 } 508 509 void 510 smap_start(struct ifnet *ifp) 511 { 512 struct smap_softc *sc = ifp->if_softc; 513 struct smap_desc *d; 514 struct mbuf *m0, *m; 515 u_int8_t *p, *q; 516 u_int32_t *r; 517 int i, sz, pktsz; 518 u_int16_t fifop; 519 u_int16_t r16; 520 521 KDASSERT(ifp->if_flags & IFF_RUNNING); 522 FUNC_ENTER(); 523 524 while (1) { 525 IFQ_POLL(&ifp->if_snd, m0); 526 if (m0 == NULL) 527 goto end; 528 529 pktsz = m0->m_pkthdr.len; 530 KDASSERT(pktsz <= ETHER_MAX_LEN - ETHER_CRC_LEN); 531 sz = ROUND4(pktsz); 532 533 if (sz > sc->tx_buf_freesize || 534 sc->tx_desc_cnt >= SMAP_DESC_MAX || 535 emac3_tx_done() != 0) { 536 ifp->if_flags |= IFF_OACTIVE; 537 goto end; 538 } 539 540 IFQ_DEQUEUE(&ifp->if_snd, m0); 541 KDASSERT(m0 != NULL); 542 #if NBPFILTER > 0 543 if (ifp->if_bpf) 544 bpf_mtap(ifp->if_bpf, m0); 545 #endif 546 547 p = (u_int8_t *)sc->tx_buf; 548 q = p + sz; 549 /* copy to temporary buffer area */ 550 for (m = m0; m != 0; m = m->m_next) { 551 memcpy(p, mtod(m, void *), m->m_len); 552 p += m->m_len; 553 } 554 m_freem(m0); 555 556 /* zero padding area */ 557 for (; p < q; p++) 558 *p = 0; 559 560 /* put to FIFO */ 561 fifop = sc->tx_fifo_ptr; 562 KDASSERT((fifop & 3) == 0); 563 _reg_write_2(SMAP_TXFIFO_PTR_REG16, fifop); 564 sc->tx_fifo_ptr = (fifop + sz) & 0xfff; 565 566 r = sc->tx_buf; 567 for (i = 0; i < sz; i += sizeof(u_int32_t)) 568 *(volatile u_int32_t *)SMAP_TXFIFO_DATA_REG = *r++; 569 _wbflush(); 570 571 /* put FIFO to EMAC3 */ 572 d = &sc->tx_desc[sc->tx_start_index]; 573 KDASSERT((d->stat & SMAP_TXDESC_READY) == 0); 574 575 d->sz = pktsz; 576 d->ptr = fifop + SMAP_TXBUF_BASE; 577 d->stat = SMAP_TXDESC_READY | SMAP_TXDESC_GENFCS | 578 SMAP_TXDESC_GENPAD; 579 _wbflush(); 580 581 sc->tx_buf_freesize -= sz; 582 sc->tx_desc_cnt++; 583 sc->tx_start_index = (sc->tx_start_index + 1) & 0x3f; 584 _reg_write_1(SMAP_TXFIFO_FRAME_INC_REG8, 1); 585 586 emac3_tx_kick(); 587 r16 = _reg_read_2(SPD_INTR_ENABLE_REG16); 588 if ((r16 & SPD_INTR_TXDNV) == 0) { 589 r16 |= SPD_INTR_TXDNV; 590 _reg_write_2(SPD_INTR_ENABLE_REG16, r16); 591 } 592 } 593 end: 594 /* set watchdog timer */ 595 ifp->if_timer = 5; 596 597 FUNC_EXIT(); 598 } 599 600 void 601 smap_watchdog(struct ifnet *ifp) 602 { 603 struct smap_softc *sc = ifp->if_softc; 604 605 printf("%s: watchdog timeout\n",DEVNAME); 606 sc->ethercom.ec_if.if_oerrors++; 607 608 smap_fifo_init(sc); 609 smap_desc_init(sc); 610 emac3_reset(&sc->emac3); 611 } 612 613 int 614 smap_init(struct ifnet *ifp) 615 { 616 struct smap_softc *sc = ifp->if_softc; 617 u_int16_t r16; 618 619 smap_fifo_init(sc); 620 emac3_reset(&sc->emac3); 621 smap_desc_init(sc); 622 623 _reg_write_2(SPD_INTR_CLEAR_REG16, SPD_INTR_RXEND | SPD_INTR_TXEND | 624 SPD_INTR_RXDNV); 625 emac3_intr_clear(); 626 627 r16 = _reg_read_2(SPD_INTR_ENABLE_REG16); 628 r16 |= SPD_INTR_EMAC3 | SPD_INTR_RXEND | SPD_INTR_TXEND | 629 SPD_INTR_RXDNV; 630 _reg_write_2(SPD_INTR_ENABLE_REG16, r16); 631 emac3_intr_enable(); 632 633 emac3_enable(); 634 635 /* Program the multicast filter, if necessary. */ 636 emac3_setmulti(&sc->emac3, &sc->ethercom); 637 638 /* Set current media. */ 639 mii_mediachg(&sc->emac3.mii); 640 641 ifp->if_flags |= IFF_RUNNING; 642 643 return (0); 644 } 645 646 void 647 smap_stop(struct ifnet *ifp, int disable) 648 { 649 struct smap_softc *sc = ifp->if_softc; 650 651 mii_down(&sc->emac3.mii); 652 653 if (disable) 654 emac3_disable(); 655 656 ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); 657 } 658 659 /* 660 * FIFO 661 */ 662 int 663 smap_fifo_init(struct smap_softc *sc) 664 { 665 666 if (smap_fifo_reset(SMAP_TXFIFO_CTRL_REG8) != 0) 667 goto error; 668 669 if (smap_fifo_reset(SMAP_RXFIFO_CTRL_REG8) != 0) 670 goto error; 671 672 return (0); 673 error: 674 printf("%s: FIFO reset not complete.\n", DEVNAME); 675 676 return (1); 677 } 678 679 int 680 smap_fifo_reset(bus_addr_t a) 681 { 682 int retry = 10000; 683 684 _reg_write_1(a, SMAP_FIFO_RESET); 685 686 while ((_reg_read_1(a) & SMAP_FIFO_RESET) && --retry > 0) 687 ; 688 689 return (retry == 0); 690 } 691 692 /* 693 * Buffer descriptor 694 */ 695 void 696 smap_desc_init(struct smap_softc *sc) 697 { 698 struct smap_desc *d; 699 int i; 700 701 sc->tx_desc = (void *)SMAP_TXDESC_BASE; 702 sc->rx_desc = (void *)SMAP_RXDESC_BASE; 703 704 sc->tx_buf_freesize = SMAP_TXBUF_SIZE; 705 sc->tx_fifo_ptr = 0; 706 sc->tx_start_index = 0; 707 sc->tx_done_index = 0; 708 sc->rx_done_index = 0; 709 710 /* intialize entry */ 711 d = sc->tx_desc; 712 for (i = 0; i < SMAP_DESC_MAX; i++, d++) { 713 d->stat = 0; 714 d->__reserved = 0; 715 d->sz = 0; 716 d->ptr = 0; 717 } 718 719 d = sc->rx_desc; 720 for (i = 0; i < SMAP_DESC_MAX; i++, d++) { 721 d->stat = SMAP_RXDESC_EMPTY; 722 d->__reserved = 0; 723 d->sz = 0; 724 d->ptr = 0; 725 } 726 _wbflush(); 727 } 728 729 730 /* 731 * EEPROM 732 */ 733 int 734 smap_get_eaddr(struct smap_softc *sc, u_int8_t *eaddr) 735 { 736 u_int16_t checksum, *p = (u_int16_t *)eaddr; 737 738 spd_eeprom_read(0, p, 3); 739 spd_eeprom_read(3, &checksum, 1); 740 741 if (checksum != (u_int16_t)(p[0] + p[1] + p[2])) { 742 printf("%s: Ethernet address checksum error.(%s)\n", 743 DEVNAME, ether_sprintf(eaddr)); 744 return (1); 745 } 746 747 return (0); 748 } 749 750 #ifdef SMAP_DEBUG 751 #include <mips/locore.h> 752 void 753 __smap_lock_check(const char *func, int enter) 754 { 755 static int cnt; 756 static const char *last; 757 758 cnt += enter ? 1 : -1; 759 760 if (cnt < 0 || cnt > 1) 761 panic("%s cnt=%d last=%s", func, cnt, last); 762 763 last = func; 764 } 765 766 void 767 __smap_status(int msg) 768 { 769 static int cnt; 770 __gsfb_print(1, "%d: tx=%d rx=%d txcnt=%d free=%d cnt=%d\n", msg, 771 _reg_read_1(SMAP_TXFIFO_FRAME_REG8), 772 _reg_read_1(SMAP_RXFIFO_FRAME_REG8), __sc->tx_desc_cnt, 773 __sc->tx_buf_freesize, cnt++); 774 } 775 #endif /* SMAP_DEBUG */ 776