if_sq.c revision 1.8
1/* $NetBSD: if_sq.c,v 1.8 2001/11/18 08:16:16 thorpej Exp $ */ 2 3/* 4 * Copyright (c) 2001 Rafal K. Boni 5 * Copyright (c) 1998, 1999, 2000 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * Portions of this code are derived from software contributed to The 9 * NetBSD Foundation by Jason R. Thorpe of the Numerical Aerospace 10 * Simulation Facility, NASA Ames Research Center. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. The name of the author may not be used to endorse or promote products 21 * derived from this software without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35#include "bpfilter.h" 36 37#include <sys/param.h> 38#include <sys/systm.h> 39#include <sys/device.h> 40#include <sys/callout.h> 41#include <sys/mbuf.h> 42#include <sys/malloc.h> 43#include <sys/kernel.h> 44#include <sys/socket.h> 45#include <sys/ioctl.h> 46#include <sys/errno.h> 47#include <sys/syslog.h> 48 49#include <uvm/uvm_extern.h> 50 51#include <machine/endian.h> 52 53#include <net/if.h> 54#include <net/if_dl.h> 55#include <net/if_media.h> 56#include <net/if_ether.h> 57 58#if NBPFILTER > 0 59#include <net/bpf.h> 60#endif 61 62/* XXXrkb: cheap hack until parents pass in DMA tags */ 63#define _SGIMIPS_BUS_DMA_PRIVATE 64 65#include <machine/bus.h> 66#include <machine/intr.h> 67 68#include <dev/ic/seeq8003reg.h> 69 70#include <sgimips/hpc/sqvar.h> 71#include <sgimips/hpc/hpcvar.h> 72#include <sgimips/hpc/hpcreg.h> 73 74#include <dev/arcbios/arcbios.h> 75#include <dev/arcbios/arcbiosvar.h> 76 77#define static 78 79/* 80 * Short TODO list: 81 * (1) Do counters for bad-RX packets. 82 * (2) Inherit DMA tag via config machinery, don't hard-code it. 83 * (3) Allow multi-segment transmits, instead of copying to a single, 84 * contiguous mbuf. 85 * (4) Verify sq_stop() turns off enough stuff; I was still getting 86 * seeq interrupts after sq_stop(). 87 * (5) Fix up printfs in driver (most should only fire ifdef SQ_DEBUG 88 * or something similar. 89 * (6) Implement EDLC modes: especially packet auto-pad and simplex 90 * mode. 91 * (7) Should the driver filter out its own transmissions in non-EDLC 92 * mode? 93 * (8) Multicast support -- multicast filter, address management, ... 94 * (9) Deal with RB0 (recv buffer overflow) on reception. Will need 95 * to figure out if RB0 is read-only as stated in one spot in the 96 * HPC spec or read-write (ie, is the 'write a one to clear it') 97 * the correct thing? 98 */ 99 100static int sq_match(struct device *, struct cfdata *, void *); 101static void sq_attach(struct device *, struct device *, void *); 102static int sq_init(struct ifnet *); 103static void sq_start(struct ifnet *); 104static void sq_stop(struct ifnet *, int); 105static void sq_watchdog(struct ifnet *); 106static int sq_ioctl(struct ifnet *, u_long, caddr_t); 107 108static void sq_set_filter(struct sq_softc *); 109static int sq_intr(void *); 110static int sq_rxintr(struct sq_softc *); 111static int sq_txintr(struct sq_softc *); 112static void sq_reset(struct sq_softc *); 113static int sq_add_rxbuf(struct sq_softc *, int); 114static void sq_dump_buffer(u_int32_t addr, u_int32_t len); 115 116static void enaddr_aton(const char*, u_int8_t*); 117 118/* Actions */ 119#define SQ_RESET 1 120#define SQ_ADD_TO_DMA 2 121#define SQ_START_DMA 3 122#define SQ_DONE_DMA 4 123#define SQ_RESTART_DMA 5 124#define SQ_TXINTR_ENTER 6 125#define SQ_TXINTR_EXIT 7 126#define SQ_TXINTR_BUSY 8 127 128struct sq_action_trace { 129 int action; 130 int bufno; 131 int status; 132 int freebuf; 133}; 134 135#define SQ_TRACEBUF_SIZE 100 136int sq_trace_idx = 0; 137struct sq_action_trace sq_trace[SQ_TRACEBUF_SIZE]; 138 139void sq_trace_dump(struct sq_softc* sc); 140 141#define SQ_TRACE(act, buf, stat, free) do { \ 142 sq_trace[sq_trace_idx].action = (act); \ 143 sq_trace[sq_trace_idx].bufno = (buf); \ 144 sq_trace[sq_trace_idx].status = (stat); \ 145 sq_trace[sq_trace_idx].freebuf = (free); \ 146 if (++sq_trace_idx == SQ_TRACEBUF_SIZE) { \ 147 memset(&sq_trace, 0, sizeof(sq_trace)); \ 148 sq_trace_idx = 0; \ 149 } \ 150} while (0) 151 152struct cfattach sq_ca = { 153 sizeof(struct sq_softc), sq_match, sq_attach 154}; 155 156static int 157sq_match(struct device *parent, struct cfdata *cf, void *aux) 158{ 159 struct hpc_attach_args *ha = aux; 160 161 if (strcmp(ha->ha_name, cf->cf_driver->cd_name) == 0) 162 return (1); 163 164 return (0); 165} 166 167static void 168sq_attach(struct device *parent, struct device *self, void *aux) 169{ 170 int i, err; 171 char* macaddr; 172 struct sq_softc *sc = (void *)self; 173 struct hpc_attach_args *haa = aux; 174 struct ifnet *ifp = &sc->sc_ethercom.ec_if; 175 176 sc->sc_hpct = haa->ha_st; 177 if ((err = bus_space_subregion(haa->ha_st, haa->ha_sh, 178 haa->ha_dmaoff, 179 HPC_ENET_REGS_SIZE, 180 &sc->sc_hpch)) != 0) { 181 printf(": unable to map HPC DMA registers, error = %d\n", err); 182 goto fail_0; 183 } 184 185 sc->sc_regt = haa->ha_st; 186 if ((err = bus_space_subregion(haa->ha_st, haa->ha_sh, 187 haa->ha_devoff, 188 HPC_ENET_DEVREGS_SIZE, 189 &sc->sc_regh)) != 0) { 190 printf(": unable to map Seeq registers, error = %d\n", err); 191 goto fail_0; 192 } 193 194 sc->sc_dmat = haa->ha_dmat; 195 196 if ((err = bus_dmamem_alloc(sc->sc_dmat, sizeof(struct sq_control), 197 PAGE_SIZE, PAGE_SIZE, &sc->sc_cdseg, 198 1, &sc->sc_ncdseg, BUS_DMA_NOWAIT)) != 0) { 199 printf(": unable to allocate control data, error = %d\n", err); 200 goto fail_0; 201 } 202 203 if ((err = bus_dmamem_map(sc->sc_dmat, &sc->sc_cdseg, sc->sc_ncdseg, 204 sizeof(struct sq_control), 205 (caddr_t *)&sc->sc_control, 206 BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) { 207 printf(": unable to map control data, error = %d\n", err); 208 goto fail_1; 209 } 210 211 if ((err = bus_dmamap_create(sc->sc_dmat, sizeof(struct sq_control), 212 1, sizeof(struct sq_control), PAGE_SIZE, 213 BUS_DMA_NOWAIT, &sc->sc_cdmap)) != 0) { 214 printf(": unable to create DMA map for control data, error " 215 "= %d\n", err); 216 goto fail_2; 217 } 218 219 if ((err = bus_dmamap_load(sc->sc_dmat, sc->sc_cdmap, sc->sc_control, 220 sizeof(struct sq_control), 221 NULL, BUS_DMA_NOWAIT)) != 0) { 222 printf(": unable to load DMA map for control data, error " 223 "= %d\n", err); 224 goto fail_3; 225 } 226 227 memset(sc->sc_control, 0, sizeof(struct sq_control)); 228 229 /* Create transmit buffer DMA maps */ 230 for (i = 0; i < SQ_NTXDESC; i++) { 231 if ((err = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, MCLBYTES, 232 0, BUS_DMA_NOWAIT, 233 &sc->sc_txmap[i])) != 0) { 234 printf(": unable to create tx DMA map %d, error = %d\n", 235 i, err); 236 goto fail_4; 237 } 238 } 239 240 /* Create transmit buffer DMA maps */ 241 for (i = 0; i < SQ_NRXDESC; i++) { 242 if ((err = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, MCLBYTES, 243 0, BUS_DMA_NOWAIT, 244 &sc->sc_rxmap[i])) != 0) { 245 printf(": unable to create rx DMA map %d, error = %d\n", 246 i, err); 247 goto fail_5; 248 } 249 } 250 251 /* Pre-allocate the receive buffers. */ 252 for (i = 0; i < SQ_NRXDESC; i++) { 253 if ((err = sq_add_rxbuf(sc, i)) != 0) { 254 printf(": unable to allocate or map rx buffer %d\n," 255 " error = %d\n", i, err); 256 goto fail_6; 257 } 258 } 259 260 if ((macaddr = ARCBIOS->GetEnvironmentVariable("eaddr")) == NULL) { 261 printf(": unable to get MAC address!\n"); 262 goto fail_6; 263 } 264 265 if ((cpu_intr_establish(haa->ha_irq, IPL_NET, sq_intr, sc)) == NULL) { 266 printf(": unable to establish interrupt!\n"); 267 goto fail_6; 268 } 269 270 /* Reset the chip to a known state. */ 271 sq_reset(sc); 272 273 /* 274 * Determine if we're an 8003 or 80c03 by setting the first 275 * MAC address register to non-zero, and then reading it back. 276 * If it's zero, we have an 80c03, because we will have read 277 * the TxCollLSB register. 278 */ 279 bus_space_write_1(sc->sc_regt, sc->sc_regh, SEEQ_TXCOLLS0, 0xa5); 280 if (bus_space_read_1(sc->sc_regt, sc->sc_regh, SEEQ_TXCOLLS0) == 0) 281 sc->sc_type = SQ_TYPE_80C03; 282 else 283 sc->sc_type = SQ_TYPE_8003; 284 bus_space_write_1(sc->sc_regt, sc->sc_regh, SEEQ_TXCOLLS0, 0x00); 285 286 printf(": SGI Seeq %s\n", 287 sc->sc_type == SQ_TYPE_80C03 ? "80c03" : "8003"); 288 289 enaddr_aton(macaddr, sc->sc_enaddr); 290 291 printf("%s: Ethernet address %s\n", sc->sc_dev.dv_xname, 292 ether_sprintf(sc->sc_enaddr)); 293 294 strcpy(ifp->if_xname, sc->sc_dev.dv_xname); 295 ifp->if_softc = sc; 296 ifp->if_mtu = ETHERMTU; 297 ifp->if_init = sq_init; 298 ifp->if_stop = sq_stop; 299 ifp->if_start = sq_start; 300 ifp->if_ioctl = sq_ioctl; 301 ifp->if_watchdog = sq_watchdog; 302 ifp->if_flags = IFF_BROADCAST | IFF_NOTRAILERS | IFF_MULTICAST; 303 IFQ_SET_READY(&ifp->if_snd); 304 305 if_attach(ifp); 306 ether_ifattach(ifp, sc->sc_enaddr); 307 308 memset(&sq_trace, 0, sizeof(sq_trace)); 309 /* Done! */ 310 return; 311 312 /* 313 * Free any resources we've allocated during the failed attach 314 * attempt. Do this in reverse order and fall through. 315 */ 316fail_6: 317 for (i = 0; i < SQ_NRXDESC; i++) { 318 if (sc->sc_rxmbuf[i] != NULL) { 319 bus_dmamap_unload(sc->sc_dmat, sc->sc_rxmap[i]); 320 m_freem(sc->sc_rxmbuf[i]); 321 } 322 } 323fail_5: 324 for (i = 0; i < SQ_NRXDESC; i++) { 325 if (sc->sc_rxmap[i] != NULL) 326 bus_dmamap_destroy(sc->sc_dmat, sc->sc_rxmap[i]); 327 } 328fail_4: 329 for (i = 0; i < SQ_NTXDESC; i++) { 330 if (sc->sc_txmap[i] != NULL) 331 bus_dmamap_destroy(sc->sc_dmat, sc->sc_txmap[i]); 332 } 333 bus_dmamap_unload(sc->sc_dmat, sc->sc_cdmap); 334fail_3: 335 bus_dmamap_destroy(sc->sc_dmat, sc->sc_cdmap); 336fail_2: 337 bus_dmamem_unmap(sc->sc_dmat, (caddr_t) sc->sc_control, 338 sizeof(struct sq_control)); 339fail_1: 340 bus_dmamem_free(sc->sc_dmat, &sc->sc_cdseg, sc->sc_ncdseg); 341fail_0: 342 return; 343} 344 345/* Set up data to get the interface up and running. */ 346int 347sq_init(struct ifnet *ifp) 348{ 349 int i; 350 u_int32_t reg; 351 struct sq_softc *sc = ifp->if_softc; 352 353 /* Cancel any in-progress I/O */ 354 sq_stop(ifp, 0); 355 356 sc->sc_nextrx = 0; 357 358 sc->sc_nfreetx = SQ_NTXDESC; 359 sc->sc_nexttx = sc->sc_prevtx = 0; 360 361 SQ_TRACE(SQ_RESET, 0, 0, sc->sc_nfreetx); 362 363 /* Set into 8003 mode, bank 0 to program ethernet address */ 364 bus_space_write_1(sc->sc_regt, sc->sc_regh, SEEQ_TXCMD, TXCMD_BANK0); 365 366 /* Now write the address */ 367 for (i = 0; i < ETHER_ADDR_LEN; i++) 368 bus_space_write_1(sc->sc_regt, sc->sc_regh, i, 369 sc->sc_enaddr[i]); 370 371 sc->sc_rxcmd = RXCMD_IE_CRC | 372 RXCMD_IE_DRIB | 373 RXCMD_IE_SHORT | 374 RXCMD_IE_END | 375 RXCMD_IE_GOOD; 376 377 /* 378 * Set the receive filter -- this will add some bits to the 379 * prototype RXCMD register. Do this before setting the 380 * transmit config register, since we might need to switch 381 * banks. 382 */ 383 sq_set_filter(sc); 384 385 /* Set up Seeq transmit command register */ 386 bus_space_write_1(sc->sc_regt, sc->sc_regh, SEEQ_TXCMD, 387 TXCMD_IE_UFLOW | 388 TXCMD_IE_COLL | 389 TXCMD_IE_16COLL | 390 TXCMD_IE_GOOD); 391 392 /* Now write the receive command register. */ 393 bus_space_write_1(sc->sc_regt, sc->sc_regh, SEEQ_RXCMD, sc->sc_rxcmd); 394 395 /* Set up HPC ethernet DMA config */ 396 reg = bus_space_read_4(sc->sc_hpct, sc->sc_hpch, HPC_ENETR_DMACFG); 397 bus_space_write_4(sc->sc_hpct, sc->sc_hpch, HPC_ENETR_DMACFG, 398 reg | ENETR_DMACFG_FIX_RXDC | 399 ENETR_DMACFG_FIX_INTR | 400 ENETR_DMACFG_FIX_EOP); 401 402 /* Pass the start of the receive ring to the HPC */ 403 bus_space_write_4(sc->sc_hpct, sc->sc_hpch, HPC_ENETR_NDBP, 404 SQ_CDRXADDR(sc, 0)); 405 406 /* And turn on the HPC ethernet receive channel */ 407 bus_space_write_4(sc->sc_hpct, sc->sc_hpch, HPC_ENETR_CTL, 408 ENETR_CTL_ACTIVE); 409 410 ifp->if_flags |= IFF_RUNNING; 411 ifp->if_flags &= ~IFF_OACTIVE; 412 413 return 0; 414} 415 416static void 417sq_set_filter(struct sq_softc *sc) 418{ 419 struct ethercom *ec = &sc->sc_ethercom; 420 struct ifnet *ifp = &sc->sc_ethercom.ec_if; 421 struct ether_multi *enm; 422 struct ether_multistep step; 423 424 /* 425 * Check for promiscuous mode. Also implies 426 * all-multicast. 427 */ 428 if (ifp->if_flags & IFF_PROMISC) { 429 sc->sc_rxcmd |= RXCMD_REC_ALL; 430 ifp->if_flags |= IFF_ALLMULTI; 431 return; 432 } 433 434 /* 435 * The 8003 has no hash table. If we have any multicast 436 * addresses on the list, enable reception of all multicast 437 * frames. 438 * 439 * XXX The 80c03 has a hash table. We should use it. 440 */ 441 442 ETHER_FIRST_MULTI(step, ec, enm); 443 444 if (enm == NULL) { 445 sc->sc_rxcmd |= RXCMD_REC_BROAD; 446 return; 447 } 448 449 sc->sc_rxcmd |= RXCMD_REC_MULTI; 450 ifp->if_flags |= IFF_ALLMULTI; 451} 452 453int 454sq_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 455{ 456 int s, error = 0; 457 458 s = splnet(); 459 460 error = ether_ioctl(ifp, cmd, data); 461 if (error == ENETRESET) { 462 /* 463 * Multicast list has changed; set the hardware filter 464 * accordingly. 465 */ 466 error = sq_init(ifp); 467 } 468 469 splx(s); 470 return (error); 471} 472 473void 474sq_start(struct ifnet *ifp) 475{ 476 struct sq_softc *sc = ifp->if_softc; 477 u_int32_t status; 478 struct mbuf *m0, *m; 479 bus_dmamap_t dmamap; 480 int err, totlen, nexttx, firsttx, lasttx, ofree, seg; 481 482 if ((ifp->if_flags & (IFF_RUNNING|IFF_OACTIVE)) != IFF_RUNNING) 483 return; 484 485 /* 486 * Remember the previous number of free descriptors and 487 * the first descriptor we'll use. 488 */ 489 ofree = sc->sc_nfreetx; 490 firsttx = sc->sc_nexttx; 491 492 /* 493 * Loop through the send queue, setting up transmit descriptors 494 * until we drain the queue, or use up all available transmit 495 * descriptors. 496 */ 497 while (sc->sc_nfreetx != 0) { 498 /* 499 * Grab a packet off the queue. 500 */ 501 IFQ_POLL(&ifp->if_snd, m0); 502 if (m0 == NULL) 503 break; 504 m = NULL; 505 506 dmamap = sc->sc_txmap[sc->sc_nexttx]; 507 508 /* 509 * Load the DMA map. If this fails, the packet either 510 * didn't fit in the alloted number of segments, or we were 511 * short on resources. In this case, we'll copy and try 512 * again. 513 */ 514 if (bus_dmamap_load_mbuf(sc->sc_dmat, dmamap, m0, 515 BUS_DMA_NOWAIT) != 0) { 516 MGETHDR(m, M_DONTWAIT, MT_DATA); 517 if (m == NULL) { 518 printf("%s: unable to allocate Tx mbuf\n", 519 sc->sc_dev.dv_xname); 520 break; 521 } 522 if (m0->m_pkthdr.len > MHLEN) { 523 MCLGET(m, M_DONTWAIT); 524 if ((m->m_flags & M_EXT) == 0) { 525 printf("%s: unable to allocate Tx " 526 "cluster\n", sc->sc_dev.dv_xname); 527 m_freem(m); 528 break; 529 } 530 } 531 532 m_copydata(m0, 0, m0->m_pkthdr.len, mtod(m, caddr_t)); 533 m->m_pkthdr.len = m->m_len = m0->m_pkthdr.len; 534 535 if ((err = bus_dmamap_load_mbuf(sc->sc_dmat, dmamap, 536 m, BUS_DMA_NOWAIT)) != 0) { 537 printf("%s: unable to load Tx buffer, " 538 "error = %d\n", sc->sc_dev.dv_xname, err); 539 break; 540 } 541 } 542 543 /* 544 * Ensure we have enough descriptors free to describe 545 * the packet. 546 */ 547 if (dmamap->dm_nsegs > sc->sc_nfreetx) { 548 /* 549 * Not enough free descriptors to transmit this 550 * packet. We haven't committed to anything yet, 551 * so just unload the DMA map, put the packet 552 * back on the queue, and punt. Notify the upper 553 * layer that there are no more slots left. 554 * 555 * XXX We could allocate an mbuf and copy, but 556 * XXX it is worth it? 557 */ 558 ifp->if_flags |= IFF_OACTIVE; 559 bus_dmamap_unload(sc->sc_dmat, dmamap); 560 if (m != NULL) 561 m_freem(m); 562 break; 563 } 564 565 IFQ_DEQUEUE(&ifp->if_snd, m0); 566 if (m != NULL) { 567 m_freem(m0); 568 m0 = m; 569 } 570 571 /* 572 * WE ARE NOW COMMITTED TO TRANSMITTING THE PACKET. 573 */ 574 575 /* Sync the DMA map. */ 576 bus_dmamap_sync(sc->sc_dmat, dmamap, 0, dmamap->dm_mapsize, 577 BUS_DMASYNC_PREWRITE); 578 579 /* 580 * Initialize the transmit descriptors. 581 */ 582 for (nexttx = sc->sc_nexttx, seg = 0, totlen = 0; 583 seg < dmamap->dm_nsegs; 584 seg++, nexttx = SQ_NEXTTX(nexttx)) { 585 sc->sc_txdesc[nexttx].hdd_bufptr = 586 dmamap->dm_segs[seg].ds_addr; 587 sc->sc_txdesc[nexttx].hdd_ctl = 588 dmamap->dm_segs[seg].ds_len; 589 sc->sc_txdesc[nexttx].hdd_descptr= 590 SQ_CDTXADDR(sc, SQ_NEXTTX(nexttx)); 591 lasttx = nexttx; 592 totlen += dmamap->dm_segs[seg].ds_len; 593 } 594 595 /* Last descriptor gets end-of-packet */ 596 sc->sc_txdesc[lasttx].hdd_ctl |= HDD_CTL_EOPACKET; 597 598 /* XXXrkb: if not EDLC, pad to min len manually */ 599 if (totlen < ETHER_MIN_LEN) { 600 sc->sc_txdesc[lasttx].hdd_ctl += (ETHER_MIN_LEN - totlen); 601 totlen = ETHER_MIN_LEN; 602 } 603 604#if 0 605 printf("%s: transmit %d-%d, len %d\n", sc->sc_dev.dv_xname, 606 sc->sc_nexttx, lasttx, 607 totlen); 608#endif 609 610 if (ifp->if_flags & IFF_DEBUG) { 611 printf(" transmit chain:\n"); 612 for (seg = sc->sc_nexttx;; seg = SQ_NEXTTX(seg)) { 613 printf(" descriptor %d:\n", seg); 614 printf(" hdd_bufptr: 0x%08x\n", 615 sc->sc_txdesc[seg].hdd_bufptr); 616 printf(" hdd_ctl: 0x%08x\n", 617 sc->sc_txdesc[seg].hdd_ctl); 618 printf(" hdd_descptr: 0x%08x\n", 619 sc->sc_txdesc[seg].hdd_descptr); 620 621 if (seg == lasttx) 622 break; 623 } 624 } 625 626 /* Sync the descriptors we're using. */ 627 SQ_CDTXSYNC(sc, sc->sc_nexttx, dmamap->dm_nsegs, 628 BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 629 630 /* Store a pointer to the packet so we can free it later */ 631 sc->sc_txmbuf[sc->sc_nexttx] = m0; 632 633 /* Advance the tx pointer. */ 634 sc->sc_nfreetx -= dmamap->dm_nsegs; 635 sc->sc_nexttx = nexttx; 636 637#if NBPFILTER > 0 638 /* 639 * Pass the packet to any BPF listeners. 640 */ 641 if (ifp->if_bpf) 642 bpf_mtap(ifp->if_bpf, m0); 643#endif /* NBPFILTER > 0 */ 644 } 645 646 /* All transmit descriptors used up, let upper layers know */ 647 if (sc->sc_nfreetx == 0) 648 ifp->if_flags |= IFF_OACTIVE; 649 650 if (sc->sc_nfreetx != ofree) { 651#if 0 652 printf("%s: %d packets enqueued, first %d, INTR on %d\n", 653 sc->sc_dev.dv_xname, lasttx - firsttx + 1, 654 firsttx, lasttx); 655#endif 656 657 /* 658 * Cause a transmit interrupt to happen on the 659 * last packet we enqueued, mark it as the last 660 * descriptor. 661 */ 662 sc->sc_txdesc[lasttx].hdd_ctl |= (HDD_CTL_INTR | 663 HDD_CTL_EOCHAIN); 664 SQ_CDTXSYNC(sc, lasttx, 1, 665 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 666 667 /* 668 * There is a potential race condition here if the HPC 669 * DMA channel is active and we try and either update 670 * the 'next descriptor' pointer in the HPC PIO space 671 * or the 'next descriptor' pointer in a previous desc- 672 * riptor. 673 * 674 * To avoid this, if the channel is active, we rely on 675 * the transmit interrupt routine noticing that there 676 * are more packets to send and restarting the HPC DMA 677 * engine, rather than mucking with the DMA state here. 678 */ 679 status = bus_space_read_4(sc->sc_hpct, sc->sc_hpch, 680 HPC_ENETX_CTL); 681 682 if ((status & ENETX_CTL_ACTIVE) != 0) { 683 SQ_TRACE(SQ_ADD_TO_DMA, firsttx, status, 684 sc->sc_nfreetx); 685 sc->sc_txdesc[SQ_PREVTX(firsttx)].hdd_ctl &= 686 ~HDD_CTL_EOCHAIN; 687 SQ_CDTXSYNC(sc, SQ_PREVTX(firsttx), 1, 688 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 689 } else { 690 SQ_TRACE(SQ_START_DMA, firsttx, status, sc->sc_nfreetx); 691 692 bus_space_write_4(sc->sc_hpct, sc->sc_hpch, 693 HPC_ENETX_NDBP, SQ_CDTXADDR(sc, firsttx)); 694 695 /* Kick DMA channel into life */ 696 bus_space_write_4(sc->sc_hpct, sc->sc_hpch, 697 HPC_ENETX_CTL, ENETX_CTL_ACTIVE); 698 } 699 700 /* Set a watchdog timer in case the chip flakes out. */ 701 ifp->if_timer = 5; 702 } 703} 704 705void 706sq_stop(struct ifnet *ifp, int disable) 707{ 708 int i; 709 struct sq_softc *sc = ifp->if_softc; 710 711 for (i =0; i < SQ_NTXDESC; i++) { 712 if (sc->sc_txmbuf[i] != NULL) { 713 bus_dmamap_unload(sc->sc_dmat, sc->sc_txmap[i]); 714 m_freem(sc->sc_txmbuf[i]); 715 sc->sc_txmbuf[i] = NULL; 716 } 717 } 718 719 /* Clear Seeq transmit/receive command registers */ 720 bus_space_write_1(sc->sc_regt, sc->sc_regh, SEEQ_TXCMD, 0); 721 bus_space_write_1(sc->sc_regt, sc->sc_regh, SEEQ_RXCMD, 0); 722 723 sq_reset(sc); 724 725 ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); 726 ifp->if_timer = 0; 727} 728 729/* Device timeout/watchdog routine. */ 730void 731sq_watchdog(struct ifnet *ifp) 732{ 733 u_int32_t status; 734 struct sq_softc *sc = ifp->if_softc; 735 736 status = bus_space_read_4(sc->sc_hpct, sc->sc_hpch, HPC_ENETX_CTL); 737 log(LOG_ERR, "%s: device timeout (prev %d, next %d, free %d, " 738 "status %08x)\n", sc->sc_dev.dv_xname, sc->sc_prevtx, 739 sc->sc_nexttx, sc->sc_nfreetx, status); 740 741 sq_trace_dump(sc); 742 743 memset(&sq_trace, 0, sizeof(sq_trace)); 744 sq_trace_idx = 0; 745 746 ++ifp->if_oerrors; 747 748 sq_init(ifp); 749} 750 751void sq_trace_dump(struct sq_softc* sc) 752{ 753 int i; 754 755 for(i = 0; i < sq_trace_idx; i++) { 756 printf("%s: [%d] action %d, buf %d, free %d, status %08x\n", 757 sc->sc_dev.dv_xname, i, sq_trace[i].action, 758 sq_trace[i].bufno, sq_trace[i].freebuf, 759 sq_trace[i].status); 760 } 761} 762 763static int 764sq_intr(void * arg) 765{ 766 struct sq_softc *sc = arg; 767 struct ifnet *ifp = &sc->sc_ethercom.ec_if; 768 int handled = 0; 769 u_int32_t stat; 770 771 stat = bus_space_read_4(sc->sc_hpct, sc->sc_hpch, HPC_ENETR_RESET); 772 773 if ((stat & 2) == 0) { 774 printf("%s: Unexpected interrupt!\n", sc->sc_dev.dv_xname); 775 return 0; 776 } 777 778 bus_space_write_4(sc->sc_hpct, sc->sc_hpch, HPC_ENETR_RESET, 2); 779 780 /* 781 * If the interface isn't running, the interrupt couldn't 782 * possibly have come from us. 783 */ 784 if ((ifp->if_flags & IFF_RUNNING) == 0) 785 return 0; 786 787 /* Always check for received packets */ 788 if (sq_rxintr(sc) != 0) 789 handled++; 790 791 /* Only handle transmit interrupts if we actually sent something */ 792 if (sc->sc_nfreetx < SQ_NTXDESC) { 793 sq_txintr(sc); 794 handled++; 795 } 796 797#if NRND > 0 798 if (handled) 799 rnd_add_uint32(&sc->rnd_source, stat); 800#endif 801 return (handled); 802} 803 804static int 805sq_rxintr(struct sq_softc *sc) 806{ 807 int count = 0; 808 struct mbuf* m; 809 int i, framelen; 810 u_int8_t pktstat; 811 u_int32_t status; 812 int new_end, orig_end; 813 struct ifnet *ifp = &sc->sc_ethercom.ec_if; 814 815 for(i = sc->sc_nextrx;; i = SQ_NEXTRX(i)) { 816 SQ_CDRXSYNC(sc, i, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 817 818 /* If this is a CPU-owned buffer, we're at the end of the list */ 819 if (sc->sc_rxdesc[i].hdd_ctl & HDD_CTL_OWN) { 820#if 0 821 u_int32_t reg; 822 823 reg = bus_space_read_4(sc->sc_hpct, sc->sc_hpch, HPC_ENETR_CTL); 824 printf("%s: rxintr: done at %d (ctl %08x)\n", 825 sc->sc_dev.dv_xname, i, reg); 826#endif 827 break; 828 } 829 830 count++; 831 832 m = sc->sc_rxmbuf[i]; 833 framelen = m->m_ext.ext_size - 834 HDD_CTL_BYTECNT(sc->sc_rxdesc[i].hdd_ctl) - 3; 835 836 /* Now sync the actual packet data */ 837 bus_dmamap_sync(sc->sc_dmat, sc->sc_rxmap[i], 0, 838 sc->sc_rxmap[i]->dm_mapsize, BUS_DMASYNC_POSTREAD); 839 840 pktstat = *((u_int8_t*)m->m_data + framelen + 2); 841 842 if ((pktstat & RXSTAT_GOOD) == 0) { 843 ifp->if_ierrors++; 844 845 if (pktstat & RXSTAT_OFLOW) 846 printf("%s: receive FIFO overflow\n", sc->sc_dev.dv_xname); 847 848 bus_dmamap_sync(sc->sc_dmat, sc->sc_rxmap[i], 0, 849 sc->sc_rxmap[i]->dm_mapsize, 850 BUS_DMASYNC_PREREAD); 851 SQ_INIT_RXDESC(sc, i); 852 continue; 853 } 854 855 if (sq_add_rxbuf(sc, i) != 0) { 856 ifp->if_ierrors++; 857 bus_dmamap_sync(sc->sc_dmat, sc->sc_rxmap[i], 0, 858 sc->sc_rxmap[i]->dm_mapsize, 859 BUS_DMASYNC_PREREAD); 860 SQ_INIT_RXDESC(sc, i); 861 continue; 862 } 863 864 865 m->m_data += 2; 866 m->m_pkthdr.rcvif = ifp; 867 m->m_pkthdr.len = m->m_len = framelen; 868 869 ifp->if_ipackets++; 870 871#if 0 872 printf("%s: sq_rxintr: buf %d len %d\n", sc->sc_dev.dv_xname, 873 i, framelen); 874#endif 875 876#if NBPFILTER > 0 877 if (ifp->if_bpf) 878 bpf_mtap(ifp->if_bpf, m); 879#endif 880 (*ifp->if_input)(ifp, m); 881 } 882 883 884 /* If anything happened, move ring start/end pointers to new spot */ 885 if (i != sc->sc_nextrx) { 886 new_end = SQ_PREVRX(i); 887 sc->sc_rxdesc[new_end].hdd_ctl |= HDD_CTL_EOCHAIN; 888 SQ_CDRXSYNC(sc, new_end, BUS_DMASYNC_PREREAD | 889 BUS_DMASYNC_PREWRITE); 890 891 orig_end = SQ_PREVRX(sc->sc_nextrx); 892 sc->sc_rxdesc[orig_end].hdd_ctl &= ~HDD_CTL_EOCHAIN; 893 SQ_CDRXSYNC(sc, orig_end, BUS_DMASYNC_PREREAD | 894 BUS_DMASYNC_PREWRITE); 895 896 sc->sc_nextrx = i; 897 } 898 899 status = bus_space_read_4(sc->sc_hpct, sc->sc_hpch, 900 HPC_ENETR_CTL); 901 902 /* If receive channel is stopped, restart it... */ 903 if ((status & ENETR_CTL_ACTIVE) == 0) { 904 /* Pass the start of the receive ring to the HPC */ 905 bus_space_write_4(sc->sc_hpct, sc->sc_hpch, 906 HPC_ENETR_NDBP, SQ_CDRXADDR(sc, sc->sc_nextrx)); 907 908 /* And turn on the HPC ethernet receive channel */ 909 bus_space_write_4(sc->sc_hpct, sc->sc_hpch, HPC_ENETR_CTL, 910 ENETR_CTL_ACTIVE); 911 } 912 913 return count; 914} 915 916static int 917sq_txintr(struct sq_softc *sc) 918{ 919 int i; 920 u_int32_t status; 921 struct ifnet *ifp = &sc->sc_ethercom.ec_if; 922 923 status = bus_space_read_4(sc->sc_hpct, sc->sc_hpch, HPC_ENETX_CTL); 924 925 SQ_TRACE(SQ_TXINTR_ENTER, sc->sc_prevtx, status, sc->sc_nfreetx); 926 927 if ((status & (ENETX_CTL_ACTIVE | TXSTAT_GOOD)) == 0) { 928 if (status & TXSTAT_COLL) 929 ifp->if_collisions++; 930 931 if (status & TXSTAT_UFLOW) { 932 printf("%s: transmit underflow\n", sc->sc_dev.dv_xname); 933 ifp->if_oerrors++; 934 } 935 936 if (status & TXSTAT_16COLL) { 937 printf("%s: max collisions reached\n", sc->sc_dev.dv_xname); 938 ifp->if_oerrors++; 939 ifp->if_collisions += 16; 940 } 941 } 942 943 i = sc->sc_prevtx; 944 while (sc->sc_nfreetx < SQ_NTXDESC) { 945 /* 946 * Check status first so we don't end up with a case of 947 * the buffer not being finished while the DMA channel 948 * has gone idle. 949 */ 950 status = bus_space_read_4(sc->sc_hpct, sc->sc_hpch, 951 HPC_ENETX_CTL); 952 953 SQ_CDTXSYNC(sc, i, sc->sc_txmap[i]->dm_nsegs, 954 BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); 955 956 /* If not yet transmitted, try and start DMA engine again */ 957 if ((sc->sc_txdesc[i].hdd_ctl & HDD_CTL_XMITDONE) == 0) { 958 if ((status & ENETX_CTL_ACTIVE) == 0) { 959 SQ_TRACE(SQ_RESTART_DMA, i, status, sc->sc_nfreetx); 960 961 bus_space_write_4(sc->sc_hpct, sc->sc_hpch, 962 HPC_ENETX_NDBP, SQ_CDTXADDR(sc, i)); 963 964 /* Kick DMA channel into life */ 965 bus_space_write_4(sc->sc_hpct, sc->sc_hpch, 966 HPC_ENETX_CTL, ENETX_CTL_ACTIVE); 967 968 /* Set a watchdog timer in case the chip flakes out. */ 969 ifp->if_timer = 5; 970 } else { 971 SQ_TRACE(SQ_TXINTR_BUSY, i, status, sc->sc_nfreetx); 972 } 973 break; 974 } 975 976 /* Sync the packet data, unload DMA map, free mbuf */ 977 bus_dmamap_sync(sc->sc_dmat, sc->sc_txmap[i], 0, 978 sc->sc_txmap[i]->dm_mapsize, 979 BUS_DMASYNC_POSTWRITE); 980 bus_dmamap_unload(sc->sc_dmat, sc->sc_txmap[i]); 981 m_freem(sc->sc_txmbuf[i]); 982 sc->sc_txmbuf[i] = NULL; 983 984 ifp->if_opackets++; 985 sc->sc_nfreetx++; 986 987 SQ_TRACE(SQ_DONE_DMA, i, status, sc->sc_nfreetx); 988 i = SQ_NEXTTX(i); 989 } 990 991 /* prevtx now points to next xmit packet not yet finished */ 992 sc->sc_prevtx = i; 993 994 /* If we have buffers free, let upper layers know */ 995 if (sc->sc_nfreetx > 0) 996 ifp->if_flags &= ~IFF_OACTIVE; 997 998 /* If all packets have left the coop, cancel watchdog */ 999 if (sc->sc_nfreetx == SQ_NTXDESC) 1000 ifp->if_timer = 0; 1001 1002 SQ_TRACE(SQ_TXINTR_EXIT, sc->sc_prevtx, status, sc->sc_nfreetx); 1003 sq_start(ifp); 1004 1005 return 1; 1006} 1007 1008 1009void 1010sq_reset(struct sq_softc *sc) 1011{ 1012 /* Stop HPC dma channels */ 1013 bus_space_write_4(sc->sc_hpct, sc->sc_hpch, HPC_ENETR_CTL, 0); 1014 bus_space_write_4(sc->sc_hpct, sc->sc_hpch, HPC_ENETX_CTL, 0); 1015 1016 bus_space_write_4(sc->sc_hpct, sc->sc_hpch, HPC_ENETR_RESET, 3); 1017 delay(20); 1018 bus_space_write_4(sc->sc_hpct, sc->sc_hpch, HPC_ENETR_RESET, 0); 1019} 1020 1021/* sq_add_rxbuf: Add a receive buffer to the indicated descriptor. */ 1022int 1023sq_add_rxbuf(struct sq_softc *sc, int idx) 1024{ 1025 int err; 1026 struct mbuf *m; 1027 1028 MGETHDR(m, M_DONTWAIT, MT_DATA); 1029 if (m == NULL) 1030 return (ENOBUFS); 1031 1032 MCLGET(m, M_DONTWAIT); 1033 if ((m->m_flags & M_EXT) == 0) { 1034 m_freem(m); 1035 return (ENOBUFS); 1036 } 1037 1038 if (sc->sc_rxmbuf[idx] != NULL) 1039 bus_dmamap_unload(sc->sc_dmat, sc->sc_rxmap[idx]); 1040 1041 sc->sc_rxmbuf[idx] = m; 1042 1043 if ((err = bus_dmamap_load(sc->sc_dmat, sc->sc_rxmap[idx], 1044 m->m_ext.ext_buf, m->m_ext.ext_size, 1045 NULL, BUS_DMA_NOWAIT)) != 0) { 1046 printf("%s: can't load rx DMA map %d, error = %d\n", 1047 sc->sc_dev.dv_xname, idx, err); 1048 panic("sq_add_rxbuf"); /* XXX */ 1049 } 1050 1051 bus_dmamap_sync(sc->sc_dmat, sc->sc_rxmap[idx], 0, 1052 sc->sc_rxmap[idx]->dm_mapsize, BUS_DMASYNC_PREREAD); 1053 1054 SQ_INIT_RXDESC(sc, idx); 1055 1056 return 0; 1057} 1058 1059void 1060sq_dump_buffer(u_int32_t addr, u_int32_t len) 1061{ 1062 int i; 1063 u_char* physaddr = (char*) MIPS_PHYS_TO_KSEG1((caddr_t)addr); 1064 1065 if (len == 0) 1066 return; 1067 1068 printf("%p: ", physaddr); 1069 1070 for(i = 0; i < len; i++) { 1071 printf("%02x ", *(physaddr + i) & 0xff); 1072 if ((i % 16) == 15 && i != len - 1) 1073 printf("\n%p: ", physaddr + i); 1074 } 1075 1076 printf("\n"); 1077} 1078 1079 1080void 1081enaddr_aton(const char* str, u_int8_t* eaddr) 1082{ 1083 int i; 1084 char c; 1085 1086 for(i = 0; i < ETHER_ADDR_LEN; i++) { 1087 if (*str == ':') 1088 str++; 1089 1090 c = *str++; 1091 if (isdigit(c)) { 1092 eaddr[i] = (c - '0'); 1093 } else if (isxdigit(c)) { 1094 eaddr[i] = (toupper(c) + 10 - 'A'); 1095 } 1096 1097 c = *str++; 1098 if (isdigit(c)) { 1099 eaddr[i] = (eaddr[i] << 4) | (c - '0'); 1100 } else if (isxdigit(c)) { 1101 eaddr[i] = (eaddr[i] << 4) | (toupper(c) + 10 - 'A'); 1102 } 1103 } 1104} 1105