if_ex.c revision 106937
1113836Simp/* 2113836Simp * Copyright (c) 1996, Javier Mart�n Rueda (jmrueda@diatel.upm.es) 3113836Simp * All rights reserved. 4113836Simp * 5113836Simp * Redistribution and use in source and binary forms, with or without 6113836Simp * modification, are permitted provided that the following conditions 7113836Simp * are met: 8113836Simp * 1. Redistributions of source code must retain the above copyright 9113836Simp * notice unmodified, this list of conditions, and the following 10113836Simp * disclaimer. 11113836Simp * 2. Redistributions in binary form must reproduce the above copyright 12113836Simp * notice, this list of conditions and the following disclaimer in the 13113836Simp * documentation and/or other materials provided with the distribution. 14113836Simp * 15113836Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16113836Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17113836Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18113836Simp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19113836Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20113836Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21113836Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22113836Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23113836Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24113836Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25113836Simp * SUCH DAMAGE. 26113836Simp * 27113836Simp * $FreeBSD: head/sys/dev/ex/if_ex.c 106937 2002-11-14 23:54:55Z sam $ 28113836Simp * 29113836Simp * MAINTAINER: Matthew N. Dodd <winter@jurai.net> 30113836Simp * <mdodd@FreeBSD.org> 31113836Simp */ 32113836Simp 33113836Simp/* 34113836Simp * Intel EtherExpress Pro/10, Pro/10+ Ethernet driver 35113836Simp * 36115418Sru * Revision history: 37113836Simp * 38113836Simp * 30-Oct-1996: first beta version. Inet and BPF supported, but no multicast. 39113836Simp */ 40113836Simp 41113836Simp#include <sys/param.h> 42113836Simp#include <sys/systm.h> 43113836Simp#include <sys/kernel.h> 44113836Simp#include <sys/sockio.h> 45113836Simp#include <sys/mbuf.h> 46113836Simp#include <sys/socket.h> 47113836Simp 48166611Sbrueffer#include <sys/module.h> 49113836Simp#include <sys/bus.h> 50113836Simp 51113836Simp#include <machine/bus.h> 52121414Shmp#include <machine/resource.h> 53113836Simp#include <sys/rman.h> 54 55#include <net/if.h> 56#include <net/if_arp.h> 57#include <net/if_media.h> 58#include <net/ethernet.h> 59#include <net/bpf.h> 60 61#include <netinet/in.h> 62#include <netinet/if_ether.h> 63 64 65#include <isa/isavar.h> 66#include <isa/pnpvar.h> 67 68#include <dev/ex/if_exreg.h> 69#include <dev/ex/if_exvar.h> 70 71#ifdef EXDEBUG 72# define Start_End 1 73# define Rcvd_Pkts 2 74# define Sent_Pkts 4 75# define Status 8 76static int debug_mask = 0; 77static int exintr_count = 0; 78# define DODEBUG(level, action) if (level & debug_mask) action 79#else 80# define DODEBUG(level, action) 81#endif 82 83char irq2eemap[] = 84 { -1, -1, 0, 1, -1, 2, -1, -1, -1, 0, 3, 4, -1, -1, -1, -1 }; 85u_char ee2irqmap[] = 86 { 9, 3, 5, 10, 11, 0, 0, 0 }; 87 88char plus_irq2eemap[] = 89 { -1, -1, -1, 0, 1, 2, -1, 3, -1, 4, 5, 6, 7, -1, -1, -1 }; 90u_char plus_ee2irqmap[] = 91 { 3, 4, 5, 7, 9, 10, 11, 12 }; 92 93/* Network Interface Functions */ 94static void ex_init (void *); 95static void ex_start (struct ifnet *); 96static int ex_ioctl (struct ifnet *, u_long, caddr_t); 97static void ex_watchdog (struct ifnet *); 98 99/* ifmedia Functions */ 100static int ex_ifmedia_upd (struct ifnet *); 101static void ex_ifmedia_sts (struct ifnet *, struct ifmediareq *); 102 103static int ex_get_media (u_int32_t iobase); 104 105static void ex_reset (struct ex_softc *); 106 107static void ex_tx_intr (struct ex_softc *); 108static void ex_rx_intr (struct ex_softc *); 109 110int 111look_for_card (u_int32_t iobase) 112{ 113 int count1, count2; 114 115 /* 116 * Check for the i82595 signature, and check that the round robin 117 * counter actually advances. 118 */ 119 if (((count1 = inb(iobase + ID_REG)) & Id_Mask) != Id_Sig) 120 return(0); 121 count2 = inb(iobase + ID_REG); 122 count2 = inb(iobase + ID_REG); 123 count2 = inb(iobase + ID_REG); 124 125 return((count2 & Counter_bits) == ((count1 + 0xc0) & Counter_bits)); 126} 127 128void 129ex_get_address (u_int32_t iobase, u_char *enaddr) 130{ 131 u_int16_t eaddr_tmp; 132 133 eaddr_tmp = eeprom_read(iobase, EE_Eth_Addr_Lo); 134 enaddr[5] = eaddr_tmp & 0xff; 135 enaddr[4] = eaddr_tmp >> 8; 136 eaddr_tmp = eeprom_read(iobase, EE_Eth_Addr_Mid); 137 enaddr[3] = eaddr_tmp & 0xff; 138 enaddr[2] = eaddr_tmp >> 8; 139 eaddr_tmp = eeprom_read(iobase, EE_Eth_Addr_Hi); 140 enaddr[1] = eaddr_tmp & 0xff; 141 enaddr[0] = eaddr_tmp >> 8; 142 143 return; 144} 145 146int 147ex_card_type (u_char *enaddr) 148{ 149 if ((enaddr[0] == 0x00) && (enaddr[1] == 0xA0) && (enaddr[2] == 0xC9)) 150 return (CARD_TYPE_EX_10_PLUS); 151 152 return (CARD_TYPE_EX_10); 153} 154 155/* 156 * Caller is responsible for eventually calling 157 * ex_release_resources() on failure. 158 */ 159int 160ex_alloc_resources (device_t dev) 161{ 162 struct ex_softc * sc = device_get_softc(dev); 163 int error = 0; 164 165 sc->ioport = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->ioport_rid, 166 0, ~0, 1, RF_ACTIVE); 167 if (!sc->ioport) { 168 device_printf(dev, "No I/O space?!\n"); 169 error = ENOMEM; 170 goto bad; 171 } 172 173 sc->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->irq_rid, 174 0, ~0, 1, RF_ACTIVE); 175 176 if (!sc->irq) { 177 device_printf(dev, "No IRQ?!\n"); 178 error = ENOMEM; 179 goto bad; 180 } 181 182bad: 183 return (error); 184} 185 186void 187ex_release_resources (device_t dev) 188{ 189 struct ex_softc * sc = device_get_softc(dev); 190 191 if (sc->ih) { 192 bus_teardown_intr(dev, sc->irq, sc->ih); 193 sc->ih = NULL; 194 } 195 196 if (sc->ioport) { 197 bus_release_resource(dev, SYS_RES_IOPORT, 198 sc->ioport_rid, sc->ioport); 199 sc->ioport = NULL; 200 } 201 202 if (sc->irq) { 203 bus_release_resource(dev, SYS_RES_IRQ, 204 sc->irq_rid, sc->irq); 205 sc->irq = NULL; 206 } 207 208 return; 209} 210 211int 212ex_attach(device_t dev) 213{ 214 struct ex_softc * sc = device_get_softc(dev); 215 struct ifnet * ifp = &sc->arpcom.ac_if; 216 struct ifmedia * ifm; 217 int unit = device_get_unit(dev); 218 u_int16_t temp; 219 220 /* work out which set of irq <-> internal tables to use */ 221 if (ex_card_type(sc->arpcom.ac_enaddr) == CARD_TYPE_EX_10_PLUS) { 222 sc->irq2ee = plus_irq2eemap; 223 sc->ee2irq = plus_ee2irqmap; 224 } else { 225 sc->irq2ee = irq2eemap; 226 sc->ee2irq = ee2irqmap; 227 } 228 229 sc->mem_size = CARD_RAM_SIZE; /* XXX This should be read from the card itself. */ 230 231 /* 232 * Initialize the ifnet structure. 233 */ 234 ifp->if_softc = sc; 235 ifp->if_unit = unit; 236 ifp->if_name = "ex"; 237 ifp->if_mtu = ETHERMTU; 238 ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST /* XXX not done yet. | IFF_MULTICAST */; 239 ifp->if_output = ether_output; 240 ifp->if_start = ex_start; 241 ifp->if_ioctl = ex_ioctl; 242 ifp->if_watchdog = ex_watchdog; 243 ifp->if_init = ex_init; 244 ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; 245 246 ifmedia_init(&sc->ifmedia, 0, ex_ifmedia_upd, ex_ifmedia_sts); 247 248 temp = eeprom_read(sc->iobase, EE_W5); 249 if (temp & EE_W5_PORT_TPE) 250 ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T, 0, NULL); 251 if (temp & EE_W5_PORT_BNC) 252 ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_2, 0, NULL); 253 if (temp & EE_W5_PORT_AUI) 254 ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_5, 0, NULL); 255 256 ifmedia_set(&sc->ifmedia, ex_get_media(sc->iobase)); 257 258 ifm = &sc->ifmedia; 259 ifm->ifm_media = ifm->ifm_cur->ifm_media; 260 ex_ifmedia_upd(ifp); 261 262 /* 263 * Attach the interface. 264 */ 265 ether_ifattach(ifp, sc->arpcom.ac_enaddr); 266 267 device_printf(sc->dev, "Ethernet address %6D\n", 268 sc->arpcom.ac_enaddr, ":"); 269 270 return(0); 271} 272 273static void 274ex_init(void *xsc) 275{ 276 struct ex_softc * sc = (struct ex_softc *) xsc; 277 struct ifnet * ifp = &sc->arpcom.ac_if; 278 int s; 279 int i; 280 register int iobase = sc->iobase; 281 unsigned short temp_reg; 282 283 DODEBUG(Start_End, printf("ex_init%d: start\n", ifp->if_unit);); 284 285 if (TAILQ_FIRST(&ifp->if_addrhead) == NULL) { 286 return; 287 } 288 s = splimp(); 289 ifp->if_timer = 0; 290 291 /* 292 * Load the ethernet address into the card. 293 */ 294 outb(iobase + CMD_REG, Bank2_Sel); 295 temp_reg = inb(iobase + EEPROM_REG); 296 if (temp_reg & Trnoff_Enable) { 297 outb(iobase + EEPROM_REG, temp_reg & ~Trnoff_Enable); 298 } 299 for (i = 0; i < ETHER_ADDR_LEN; i++) { 300 outb(iobase + I_ADDR_REG0 + i, sc->arpcom.ac_enaddr[i]); 301 } 302 /* 303 * - Setup transmit chaining and discard bad received frames. 304 * - Match broadcast. 305 * - Clear test mode. 306 * - Set receiving mode. 307 * - Set IRQ number. 308 */ 309 outb(iobase + REG1, inb(iobase + REG1) | Tx_Chn_Int_Md | Tx_Chn_ErStp | Disc_Bad_Fr); 310 outb(iobase + REG2, inb(iobase + REG2) | No_SA_Ins | RX_CRC_InMem); 311 outb(iobase + REG3, inb(iobase + REG3) & 0x3f /* XXX constants. */ ); 312 outb(iobase + CMD_REG, Bank1_Sel); 313 outb(iobase + INT_NO_REG, (inb(iobase + INT_NO_REG) & 0xf8) | sc->irq2ee[sc->irq_no]); 314 315 /* 316 * Divide the available memory in the card into rcv and xmt buffers. 317 * By default, I use the first 3/4 of the memory for the rcv buffer, 318 * and the remaining 1/4 of the memory for the xmt buffer. 319 */ 320 sc->rx_mem_size = sc->mem_size * 3 / 4; 321 sc->tx_mem_size = sc->mem_size - sc->rx_mem_size; 322 sc->rx_lower_limit = 0x0000; 323 sc->rx_upper_limit = sc->rx_mem_size - 2; 324 sc->tx_lower_limit = sc->rx_mem_size; 325 sc->tx_upper_limit = sc->mem_size - 2; 326 outb(iobase + RCV_LOWER_LIMIT_REG, sc->rx_lower_limit >> 8); 327 outb(iobase + RCV_UPPER_LIMIT_REG, sc->rx_upper_limit >> 8); 328 outb(iobase + XMT_LOWER_LIMIT_REG, sc->tx_lower_limit >> 8); 329 outb(iobase + XMT_UPPER_LIMIT_REG, sc->tx_upper_limit >> 8); 330 331 /* 332 * Enable receive and transmit interrupts, and clear any pending int. 333 */ 334 outb(iobase + REG1, inb(iobase + REG1) | TriST_INT); 335 outb(iobase + CMD_REG, Bank0_Sel); 336 outb(iobase + MASK_REG, All_Int & ~(Rx_Int | Tx_Int)); 337 outb(iobase + STATUS_REG, All_Int); 338 339 /* 340 * Initialize receive and transmit ring buffers. 341 */ 342 outw(iobase + RCV_BAR, sc->rx_lower_limit); 343 sc->rx_head = sc->rx_lower_limit; 344 outw(iobase + RCV_STOP_REG, sc->rx_upper_limit | 0xfe); 345 outw(iobase + XMT_BAR, sc->tx_lower_limit); 346 sc->tx_head = sc->tx_tail = sc->tx_lower_limit; 347 348 ifp->if_flags |= IFF_RUNNING; 349 ifp->if_flags &= ~IFF_OACTIVE; 350 DODEBUG(Status, printf("OIDLE init\n");); 351 352 /* 353 * Final reset of the board, and enable operation. 354 */ 355 outb(iobase + CMD_REG, Sel_Reset_CMD); 356 DELAY(2); 357 outb(iobase + CMD_REG, Rcv_Enable_CMD); 358 359 ex_start(ifp); 360 splx(s); 361 362 DODEBUG(Start_End, printf("ex_init%d: finish\n", ifp->if_unit);); 363} 364 365 366static void 367ex_start(struct ifnet *ifp) 368{ 369 struct ex_softc * sc = ifp->if_softc; 370 int iobase = sc->iobase; 371 int i, s, len, data_len, avail, dest, next; 372 unsigned char tmp16[2]; 373 struct mbuf * opkt; 374 struct mbuf * m; 375 376 DODEBUG(Start_End, printf("ex_start%d: start\n", unit);); 377 378 s = splimp(); 379 380 /* 381 * Main loop: send outgoing packets to network card until there are no 382 * more packets left, or the card cannot accept any more yet. 383 */ 384 while (((opkt = ifp->if_snd.ifq_head) != NULL) && 385 !(ifp->if_flags & IFF_OACTIVE)) { 386 387 /* 388 * Ensure there is enough free transmit buffer space for 389 * this packet, including its header. Note: the header 390 * cannot wrap around the end of the transmit buffer and 391 * must be kept together, so we allow space for twice the 392 * length of the header, just in case. 393 */ 394 395 for (len = 0, m = opkt; m != NULL; m = m->m_next) { 396 len += m->m_len; 397 } 398 399 data_len = len; 400 401 DODEBUG(Sent_Pkts, printf("1. Sending packet with %d data bytes. ", data_len);); 402 403 if (len & 1) { 404 len += XMT_HEADER_LEN + 1; 405 } else { 406 len += XMT_HEADER_LEN; 407 } 408 409 if ((i = sc->tx_tail - sc->tx_head) >= 0) { 410 avail = sc->tx_mem_size - i; 411 } else { 412 avail = -i; 413 } 414 415 DODEBUG(Sent_Pkts, printf("i=%d, avail=%d\n", i, avail);); 416 417 if (avail >= len + XMT_HEADER_LEN) { 418 IF_DEQUEUE(&ifp->if_snd, opkt); 419 420#ifdef EX_PSA_INTR 421 /* 422 * Disable rx and tx interrupts, to avoid corruption 423 * of the host address register by interrupt service 424 * routines. 425 * XXX Is this necessary with splimp() enabled? 426 */ 427 outb(iobase + MASK_REG, All_Int); 428#endif 429 430 /* 431 * Compute the start and end addresses of this 432 * frame in the tx buffer. 433 */ 434 dest = sc->tx_tail; 435 next = dest + len; 436 437 if (next > sc->tx_upper_limit) { 438 if ((sc->tx_upper_limit + 2 - sc->tx_tail) <= 439 XMT_HEADER_LEN) { 440 dest = sc->tx_lower_limit; 441 next = dest + len; 442 } else { 443 next = sc->tx_lower_limit + 444 next - sc->tx_upper_limit - 2; 445 } 446 } 447 448 /* 449 * Build the packet frame in the card's ring buffer. 450 */ 451 DODEBUG(Sent_Pkts, printf("2. dest=%d, next=%d. ", dest, next);); 452 453 outw(iobase + HOST_ADDR_REG, dest); 454 outw(iobase + IO_PORT_REG, Transmit_CMD); 455 outw(iobase + IO_PORT_REG, 0); 456 outw(iobase + IO_PORT_REG, next); 457 outw(iobase + IO_PORT_REG, data_len); 458 459 /* 460 * Output the packet data to the card. Ensure all 461 * transfers are 16-bit wide, even if individual 462 * mbufs have odd length. 463 */ 464 465 for (m = opkt, i = 0; m != NULL; m = m->m_next) { 466 DODEBUG(Sent_Pkts, printf("[%d]", m->m_len);); 467 if (i) { 468 tmp16[1] = *(mtod(m, caddr_t)); 469 outsw(iobase + IO_PORT_REG, tmp16, 1); 470 } 471 outsw(iobase + IO_PORT_REG, 472 mtod(m, caddr_t) + i, (m->m_len - i) / 2); 473 474 if ((i = (m->m_len - i) & 1) != 0) { 475 tmp16[0] = *(mtod(m, caddr_t) + 476 m->m_len - 1); 477 } 478 } 479 if (i) { 480 outsw(iobase + IO_PORT_REG, tmp16, 1); 481 } 482 483 /* 484 * If there were other frames chained, update the 485 * chain in the last one. 486 */ 487 if (sc->tx_head != sc->tx_tail) { 488 if (sc->tx_tail != dest) { 489 outw(iobase + HOST_ADDR_REG, 490 sc->tx_last + XMT_Chain_Point); 491 outw(iobase + IO_PORT_REG, dest); 492 } 493 outw(iobase + HOST_ADDR_REG, 494 sc->tx_last + XMT_Byte_Count); 495 i = inw(iobase + IO_PORT_REG); 496 outw(iobase + HOST_ADDR_REG, 497 sc->tx_last + XMT_Byte_Count); 498 outw(iobase + IO_PORT_REG, i | Ch_bit); 499 } 500 501 /* 502 * Resume normal operation of the card: 503 * - Make a dummy read to flush the DRAM write 504 * pipeline. 505 * - Enable receive and transmit interrupts. 506 * - Send Transmit or Resume_XMT command, as 507 * appropriate. 508 */ 509 inw(iobase + IO_PORT_REG); 510#ifdef EX_PSA_INTR 511 outb(iobase + MASK_REG, All_Int & ~(Rx_Int | Tx_Int)); 512#endif 513 if (sc->tx_head == sc->tx_tail) { 514 outw(iobase + XMT_BAR, dest); 515 outb(iobase + CMD_REG, Transmit_CMD); 516 sc->tx_head = dest; 517 DODEBUG(Sent_Pkts, printf("Transmit\n");); 518 } else { 519 outb(iobase + CMD_REG, Resume_XMT_List_CMD); 520 DODEBUG(Sent_Pkts, printf("Resume\n");); 521 } 522 523 sc->tx_last = dest; 524 sc->tx_tail = next; 525 526 BPF_MTAP(ifp, opkt); 527 528 ifp->if_timer = 2; 529 ifp->if_opackets++; 530 m_freem(opkt); 531 } else { 532 ifp->if_flags |= IFF_OACTIVE; 533 DODEBUG(Status, printf("OACTIVE start\n");); 534 } 535 } 536 537 splx(s); 538 539 DODEBUG(Start_End, printf("ex_start%d: finish\n", unit);); 540} 541 542void 543ex_stop(struct ex_softc *sc) 544{ 545 int iobase = sc->iobase; 546 547 DODEBUG(Start_End, printf("ex_stop%d: start\n", unit);); 548 549 /* 550 * Disable card operation: 551 * - Disable the interrupt line. 552 * - Flush transmission and disable reception. 553 * - Mask and clear all interrupts. 554 * - Reset the 82595. 555 */ 556 outb(iobase + CMD_REG, Bank1_Sel); 557 outb(iobase + REG1, inb(iobase + REG1) & ~TriST_INT); 558 outb(iobase + CMD_REG, Bank0_Sel); 559 outb(iobase + CMD_REG, Rcv_Stop); 560 sc->tx_head = sc->tx_tail = sc->tx_lower_limit; 561 sc->tx_last = 0; /* XXX I think these two lines are not necessary, because ex_init will always be called again to reinit the interface. */ 562 outb(iobase + MASK_REG, All_Int); 563 outb(iobase + STATUS_REG, All_Int); 564 outb(iobase + CMD_REG, Reset_CMD); 565 DELAY(200); 566 567 DODEBUG(Start_End, printf("ex_stop%d: finish\n", unit);); 568 569 return; 570} 571 572void 573ex_intr(void *arg) 574{ 575 struct ex_softc * sc = (struct ex_softc *)arg; 576 struct ifnet * ifp = &sc->arpcom.ac_if; 577 int iobase = sc->iobase; 578 int int_status, send_pkts; 579 580 DODEBUG(Start_End, printf("ex_intr%d: start\n", unit);); 581 582#ifdef EXDEBUG 583 if (++exintr_count != 1) 584 printf("WARNING: nested interrupt (%d). Mail the author.\n", exintr_count); 585#endif 586 587 send_pkts = 0; 588 while ((int_status = inb(iobase + STATUS_REG)) & (Tx_Int | Rx_Int)) { 589 if (int_status & Rx_Int) { 590 outb(iobase + STATUS_REG, Rx_Int); 591 592 ex_rx_intr(sc); 593 } else if (int_status & Tx_Int) { 594 outb(iobase + STATUS_REG, Tx_Int); 595 596 ex_tx_intr(sc); 597 send_pkts = 1; 598 } 599 } 600 601 /* 602 * If any packet has been transmitted, and there are queued packets to 603 * be sent, attempt to send more packets to the network card. 604 */ 605 606 if (send_pkts && (ifp->if_snd.ifq_head != NULL)) { 607 ex_start(ifp); 608 } 609 610#ifdef EXDEBUG 611 exintr_count--; 612#endif 613 614 DODEBUG(Start_End, printf("ex_intr%d: finish\n", unit);); 615 616 return; 617} 618 619static void 620ex_tx_intr(struct ex_softc *sc) 621{ 622 struct ifnet * ifp = &sc->arpcom.ac_if; 623 int iobase = sc->iobase; 624 int tx_status; 625 626 DODEBUG(Start_End, printf("ex_tx_intr%d: start\n", unit);); 627 628 /* 629 * - Cancel the watchdog. 630 * For all packets transmitted since last transmit interrupt: 631 * - Advance chain pointer to next queued packet. 632 * - Update statistics. 633 */ 634 635 ifp->if_timer = 0; 636 637 while (sc->tx_head != sc->tx_tail) { 638 outw(iobase + HOST_ADDR_REG, sc->tx_head); 639 640 if (! inw(iobase + IO_PORT_REG) & Done_bit) 641 break; 642 643 tx_status = inw(iobase + IO_PORT_REG); 644 sc->tx_head = inw(iobase + IO_PORT_REG); 645 646 if (tx_status & TX_OK_bit) { 647 ifp->if_opackets++; 648 } else { 649 ifp->if_oerrors++; 650 } 651 652 ifp->if_collisions += tx_status & No_Collisions_bits; 653 } 654 655 /* 656 * The card should be ready to accept more packets now. 657 */ 658 659 ifp->if_flags &= ~IFF_OACTIVE; 660 661 DODEBUG(Status, printf("OIDLE tx_intr\n");); 662 DODEBUG(Start_End, printf("ex_tx_intr%d: finish\n", unit);); 663 664 return; 665} 666 667static void 668ex_rx_intr(struct ex_softc *sc) 669{ 670 struct ifnet * ifp = &sc->arpcom.ac_if; 671 int iobase = sc->iobase; 672 int rx_status; 673 int pkt_len; 674 int QQQ; 675 struct mbuf * m; 676 struct mbuf * ipkt; 677 struct ether_header * eh; 678 679 DODEBUG(Start_End, printf("ex_rx_intr%d: start\n", unit);); 680 681 /* 682 * For all packets received since last receive interrupt: 683 * - If packet ok, read it into a new mbuf and queue it to interface, 684 * updating statistics. 685 * - If packet bad, just discard it, and update statistics. 686 * Finally, advance receive stop limit in card's memory to new location. 687 */ 688 689 outw(iobase + HOST_ADDR_REG, sc->rx_head); 690 691 while (inw(iobase + IO_PORT_REG) == RCV_Done) { 692 693 rx_status = inw(iobase + IO_PORT_REG); 694 sc->rx_head = inw(iobase + IO_PORT_REG); 695 QQQ = pkt_len = inw(iobase + IO_PORT_REG); 696 697 if (rx_status & RCV_OK_bit) { 698 MGETHDR(m, M_DONTWAIT, MT_DATA); 699 ipkt = m; 700 if (ipkt == NULL) { 701 ifp->if_iqdrops++; 702 } else { 703 ipkt->m_pkthdr.rcvif = ifp; 704 ipkt->m_pkthdr.len = pkt_len; 705 ipkt->m_len = MHLEN; 706 707 while (pkt_len > 0) { 708 if (pkt_len > MINCLSIZE) { 709 MCLGET(m, M_DONTWAIT); 710 if (m->m_flags & M_EXT) { 711 m->m_len = MCLBYTES; 712 } else { 713 m_freem(ipkt); 714 ifp->if_iqdrops++; 715 goto rx_another; 716 } 717 } 718 m->m_len = min(m->m_len, pkt_len); 719 720 /* 721 * NOTE: I'm assuming that all mbufs allocated are of even length, 722 * except for the last one in an odd-length packet. 723 */ 724 725 insw(iobase + IO_PORT_REG, 726 mtod(m, caddr_t), m->m_len / 2); 727 728 if (m->m_len & 1) { 729 *(mtod(m, caddr_t) + m->m_len - 1) = inb(iobase + IO_PORT_REG); 730 } 731 pkt_len -= m->m_len; 732 733 if (pkt_len > 0) { 734 MGET(m->m_next, M_DONTWAIT, MT_DATA); 735 if (m->m_next == NULL) { 736 m_freem(ipkt); 737 ifp->if_iqdrops++; 738 goto rx_another; 739 } 740 m = m->m_next; 741 m->m_len = MLEN; 742 } 743 } 744 eh = mtod(ipkt, struct ether_header *); 745#ifdef EXDEBUG 746 if (debug_mask & Rcvd_Pkts) { 747 if ((eh->ether_dhost[5] != 0xff) || (eh->ether_dhost[0] != 0xff)) { 748 printf("Receive packet with %d data bytes: %6D -> ", QQQ, eh->ether_shost, ":"); 749 printf("%6D\n", eh->ether_dhost, ":"); 750 } /* QQQ */ 751 } 752#endif 753 (*ifp->if_input)(ifp, ipkt); 754 ifp->if_ipackets++; 755 } 756 } else { 757 ifp->if_ierrors++; 758 } 759 outw(iobase + HOST_ADDR_REG, sc->rx_head); 760rx_another: ; 761 } 762 763 if (sc->rx_head < sc->rx_lower_limit + 2) 764 outw(iobase + RCV_STOP_REG, sc->rx_upper_limit); 765 else 766 outw(iobase + RCV_STOP_REG, sc->rx_head - 2); 767 768 DODEBUG(Start_End, printf("ex_rx_intr%d: finish\n", unit);); 769 770 return; 771} 772 773 774static int 775ex_ioctl(register struct ifnet *ifp, u_long cmd, caddr_t data) 776{ 777 struct ex_softc * sc = ifp->if_softc; 778 struct ifreq * ifr = (struct ifreq *)data; 779 int s; 780 int error = 0; 781 782 DODEBUG(Start_End, printf("ex_ioctl%d: start ", ifp->if_unit);); 783 784 s = splimp(); 785 786 switch(cmd) { 787 case SIOCSIFADDR: 788 case SIOCGIFADDR: 789 case SIOCSIFMTU: 790 error = ether_ioctl(ifp, cmd, data); 791 break; 792 793 case SIOCSIFFLAGS: 794 DODEBUG(Start_End, printf("SIOCSIFFLAGS");); 795 if ((ifp->if_flags & IFF_UP) == 0 && 796 (ifp->if_flags & IFF_RUNNING)) { 797 798 ifp->if_flags &= ~IFF_RUNNING; 799 ex_stop(sc); 800 } else { 801 ex_init(sc); 802 } 803 break; 804#ifdef NODEF 805 case SIOCGHWADDR: 806 DODEBUG(Start_End, printf("SIOCGHWADDR");); 807 bcopy((caddr_t)sc->sc_addr, (caddr_t)&ifr->ifr_data, 808 sizeof(sc->sc_addr)); 809 break; 810#endif 811 case SIOCADDMULTI: 812 DODEBUG(Start_End, printf("SIOCADDMULTI");); 813 case SIOCDELMULTI: 814 DODEBUG(Start_End, printf("SIOCDELMULTI");); 815 /* XXX Support not done yet. */ 816 error = EINVAL; 817 break; 818 case SIOCSIFMEDIA: 819 case SIOCGIFMEDIA: 820 error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, cmd); 821 break; 822 default: 823 DODEBUG(Start_End, printf("unknown");); 824 error = EINVAL; 825 } 826 827 splx(s); 828 829 DODEBUG(Start_End, printf("\nex_ioctl%d: finish\n", ifp->if_unit);); 830 831 return(error); 832} 833 834 835static void 836ex_reset(struct ex_softc *sc) 837{ 838 int s; 839 840 DODEBUG(Start_End, printf("ex_reset%d: start\n", unit);); 841 842 s = splimp(); 843 844 ex_stop(sc); 845 ex_init(sc); 846 847 splx(s); 848 849 DODEBUG(Start_End, printf("ex_reset%d: finish\n", unit);); 850 851 return; 852} 853 854static void 855ex_watchdog(struct ifnet *ifp) 856{ 857 struct ex_softc * sc = ifp->if_softc; 858 859 DODEBUG(Start_End, printf("ex_watchdog%d: start\n", ifp->if_unit);); 860 861 ifp->if_flags &= ~IFF_OACTIVE; 862 863 DODEBUG(Status, printf("OIDLE watchdog\n");); 864 865 ifp->if_oerrors++; 866 ex_reset(sc); 867 ex_start(ifp); 868 869 DODEBUG(Start_End, printf("ex_watchdog%d: finish\n", ifp->if_unit);); 870 871 return; 872} 873 874static int 875ex_get_media (u_int32_t iobase) 876{ 877 int tmp; 878 879 outb(iobase + CMD_REG, Bank2_Sel); 880 tmp = inb(iobase + REG3); 881 outb(iobase + CMD_REG, Bank0_Sel); 882 883 if (tmp & TPE_bit) 884 return(IFM_ETHER|IFM_10_T); 885 if (tmp & BNC_bit) 886 return(IFM_ETHER|IFM_10_2); 887 888 return (IFM_ETHER|IFM_10_5); 889} 890 891static int 892ex_ifmedia_upd (ifp) 893 struct ifnet * ifp; 894{ 895 896 return (0); 897} 898 899static void 900ex_ifmedia_sts(ifp, ifmr) 901 struct ifnet * ifp; 902 struct ifmediareq * ifmr; 903{ 904 struct ex_softc * sc = ifp->if_softc; 905 906 ifmr->ifm_active = ex_get_media(sc->iobase); 907 908 return; 909} 910 911u_short 912eeprom_read(u_int32_t iobase, int location) 913{ 914 int i; 915 u_short data = 0; 916 int ee_addr; 917 int read_cmd = location | EE_READ_CMD; 918 short ctrl_val = EECS; 919 920 ee_addr = iobase + EEPROM_REG; 921 outb(iobase + CMD_REG, Bank2_Sel); 922 outb(ee_addr, EECS); 923 for (i = 8; i >= 0; i--) { 924 short outval = (read_cmd & (1 << i)) ? ctrl_val | EEDI : ctrl_val; 925 outb(ee_addr, outval); 926 outb(ee_addr, outval | EESK); 927 DELAY(3); 928 outb(ee_addr, outval); 929 DELAY(2); 930 } 931 outb(ee_addr, ctrl_val); 932 933 for (i = 16; i > 0; i--) { 934 outb(ee_addr, ctrl_val | EESK); 935 DELAY(3); 936 data = (data << 1) | ((inb(ee_addr) & EEDO) ? 1 : 0); 937 outb(ee_addr, ctrl_val); 938 DELAY(2); 939 } 940 941 ctrl_val &= ~EECS; 942 outb(ee_addr, ctrl_val | EESK); 943 DELAY(3); 944 outb(ee_addr, ctrl_val); 945 DELAY(2); 946 outb(iobase + CMD_REG, Bank0_Sel); 947 return(data); 948} 949