if_ex.c revision 57989
1189499Srnoland/* 2189499Srnoland * Copyright (c) 1996, Javier Mart�n Rueda (jmrueda@diatel.upm.es) 3189499Srnoland * All rights reserved. 4189499Srnoland * 5189499Srnoland * Redistribution and use in source and binary forms, with or without 6189499Srnoland * modification, are permitted provided that the following conditions 7189499Srnoland * are met: 8189499Srnoland * 1. Redistributions of source code must retain the above copyright 9189499Srnoland * notice unmodified, this list of conditions, and the following 10189499Srnoland * disclaimer. 11189499Srnoland * 2. Redistributions in binary form must reproduce the above copyright 12189499Srnoland * notice, this list of conditions and the following disclaimer in the 13189499Srnoland * documentation and/or other materials provided with the distribution. 14189499Srnoland * 15189499Srnoland * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16189499Srnoland * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17189499Srnoland * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18189499Srnoland * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19189499Srnoland * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20189499Srnoland * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21189499Srnoland * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22189499Srnoland * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23189499Srnoland * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24189499Srnoland * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25189499Srnoland * SUCH DAMAGE. 26189499Srnoland * 27189499Srnoland * $FreeBSD: head/sys/dev/ex/if_ex.c 57989 2000-03-13 12:27:21Z mdodd $ 28189499Srnoland * 29189499Srnoland * MAINTAINER: Matthew N. Dodd <winter@jurai.net> 30189499Srnoland * <mdodd@FreeBSD.org> 31189499Srnoland */ 32189499Srnoland 33189499Srnoland/* 34189499Srnoland * Intel EtherExpress Pro/10, Pro/10+ Ethernet driver 35189499Srnoland * 36189499Srnoland * Revision history: 37189499Srnoland * 38189499Srnoland * 30-Oct-1996: first beta version. Inet and BPF supported, but no multicast. 39189499Srnoland */ 40189499Srnoland 41189499Srnoland#include "ex.h" 42189499Srnoland 43189499Srnoland#include <sys/param.h> 44189499Srnoland#include <sys/systm.h> 45189499Srnoland#include <sys/kernel.h> 46189499Srnoland#include <sys/conf.h> 47189499Srnoland#include <sys/sockio.h> 48189499Srnoland#include <sys/mbuf.h> 49189499Srnoland#include <sys/socket.h> 50189499Srnoland 51189499Srnoland#include <sys/module.h> 52189499Srnoland#include <sys/bus.h> 53189499Srnoland 54189499Srnoland#include <machine/bus.h> 55189499Srnoland#include <machine/resource.h> 56189499Srnoland#include <sys/rman.h> 57189499Srnoland 58189499Srnoland#include <net/if.h> 59189499Srnoland#include <net/if_arp.h> 60189499Srnoland#include <net/if_media.h> 61189499Srnoland#include <net/ethernet.h> 62189499Srnoland#include <net/bpf.h> 63189499Srnoland 64189499Srnoland#include <netinet/in.h> 65189499Srnoland#include <netinet/if_ether.h> 66189499Srnoland 67189499Srnoland#include <machine/clock.h> 68189499Srnoland 69189499Srnoland#include <isa/isavar.h> 70189499Srnoland#include <isa/pnpvar.h> 71189499Srnoland 72189499Srnoland#include <dev/ex/if_exreg.h> 73189499Srnoland 74189499Srnoland#ifdef EXDEBUG 75189499Srnoland# define Start_End 1 76189499Srnoland# define Rcvd_Pkts 2 77189499Srnoland# define Sent_Pkts 4 78189499Srnoland# define Status 8 79189499Srnolandstatic int debug_mask = 0; 80189499Srnolandstatic int exintr_count = 0; 81189499Srnoland# define DODEBUG(level, action) if (level & debug_mask) action 82189499Srnoland#else 83189499Srnoland# define DODEBUG(level, action) 84189499Srnoland#endif 85189499Srnoland 86189499Srnoland#define CARD_TYPE_EX_10 1 87189499Srnoland#define CARD_TYPE_EX_10_PLUS 2 88189499Srnoland 89189499Srnolandstruct ex_softc { 90189499Srnoland struct arpcom arpcom; /* Ethernet common data */ 91189499Srnoland struct ifmedia ifmedia; 92189499Srnoland 93189499Srnoland device_t dev; 94189499Srnoland struct resource *ioport; 95189499Srnoland struct resource *irq; 96189499Srnoland 97189499Srnoland u_int iobase; /* I/O base address. */ 98189499Srnoland u_short irq_no; /* IRQ number. */ 99189499Srnoland 100189499Srnoland char * irq2ee; /* irq <-> internal */ 101189499Srnoland u_char * ee2irq; /* representation conversion */ 102189499Srnoland 103189499Srnoland u_int mem_size; /* Total memory size, in bytes. */ 104189499Srnoland u_int rx_mem_size; /* Rx memory size (by default, */ 105189499Srnoland /* first 3/4 of total memory). */ 106189499Srnoland 107189499Srnoland u_int rx_lower_limit; /* Lower and upper limits of */ 108189499Srnoland u_int rx_upper_limit; /* receive buffer. */ 109189499Srnoland 110189499Srnoland u_int rx_head; /* Head of receive ring buffer. */ 111189499Srnoland u_int tx_mem_size; /* Tx memory size (by default, */ 112189499Srnoland /* last quarter of total memory).*/ 113189499Srnoland 114189499Srnoland u_int tx_lower_limit; /* Lower and upper limits of */ 115189499Srnoland u_int tx_upper_limit; /* transmit buffer. */ 116189499Srnoland 117189499Srnoland u_int tx_head; /* Head and tail of */ 118189499Srnoland u_int tx_tail; /* transmit ring buffer. */ 119189499Srnoland 120189499Srnoland u_int tx_last; /* Pointer to beginning of last */ 121189499Srnoland /* frame in the chain. */ 122189499Srnoland}; 123189499Srnoland 124189499Srnolandstatic char irq2eemap[] = 125189499Srnoland { -1, -1, 0, 1, -1, 2, -1, -1, -1, 0, 3, 4, -1, -1, -1, -1 }; 126189499Srnolandstatic u_char ee2irqmap[] = 127189499Srnoland { 9, 3, 5, 10, 11, 0, 0, 0 }; 128189499Srnoland 129189499Srnolandstatic char plus_irq2eemap[] = 130189499Srnoland { -1, -1, -1, 0, 1, 2, -1, 3, -1, 4, 5, 6, 7, -1, -1, -1 }; 131189499Srnolandstatic u_char plus_ee2irqmap[] = 132189499Srnoland { 3, 4, 5, 7, 9, 10, 11, 12 }; 133189499Srnoland 134189499Srnoland/* Bus Front End Functions */ 135189499Srnolandstatic void ex_isa_identify __P((driver_t *, device_t)); 136189499Srnolandstatic int ex_isa_probe __P((device_t)); 137189499Srnolandstatic int ex_isa_attach __P((device_t)); 138189499Srnoland 139189499Srnoland/* Network Interface Functions */ 140189499Srnolandstatic void ex_init __P((void *)); 141189499Srnolandstatic void ex_start __P((struct ifnet *)); 142189499Srnolandstatic int ex_ioctl __P((struct ifnet *, u_long, caddr_t)); 143189499Srnolandstatic void ex_watchdog __P((struct ifnet *)); 144189499Srnoland 145189499Srnoland/* ifmedia Functions */ 146189499Srnolandstatic int ex_ifmedia_upd __P((struct ifnet *)); 147189499Srnolandstatic void ex_ifmedia_sts __P((struct ifnet *, struct ifmediareq *)); 148189499Srnoland 149189499Srnolandstatic void ex_stop __P((struct ex_softc *)); 150189499Srnolandstatic void ex_reset __P((struct ex_softc *)); 151189499Srnoland 152189499Srnolandstatic driver_intr_t ex_intr; 153189499Srnolandstatic void ex_tx_intr __P((struct ex_softc *)); 154189499Srnolandstatic void ex_rx_intr __P((struct ex_softc *)); 155189499Srnoland 156189499Srnolandstatic u_short eeprom_read __P((int, int)); 157189499Srnoland 158189499Srnolandstatic device_method_t ex_methods[] = { 159189499Srnoland /* Device interface */ 160189499Srnoland DEVMETHOD(device_identify, ex_isa_identify), 161189499Srnoland DEVMETHOD(device_probe, ex_isa_probe), 162189499Srnoland DEVMETHOD(device_attach, ex_isa_attach), 163189499Srnoland 164189499Srnoland { 0, 0 } 165189499Srnoland}; 166189499Srnoland 167189499Srnolandstatic driver_t ex_driver = { 168189499Srnoland "ex", 169189499Srnoland ex_methods, 170189499Srnoland sizeof(struct ex_softc), 171189499Srnoland}; 172189499Srnoland 173189499Srnolandstatic devclass_t ex_devclass; 174189499Srnoland 175189499SrnolandDRIVER_MODULE(ex, isa, ex_driver, ex_devclass, 0, 0); 176189499Srnoland 177189499Srnolandstatic struct isa_pnp_id ex_ids[] = { 178189499Srnoland { 0x3110d425, NULL }, /* INT1031 */ 179189499Srnoland { 0x3010d425, NULL }, /* INT1030 */ 180189499Srnoland { 0, NULL }, 181189499Srnoland}; 182189499Srnoland 183189499Srnolandstatic int 184189499Srnolandlook_for_card (u_int iobase) 185189499Srnoland{ 186189499Srnoland int count1, count2; 187189499Srnoland 188189499Srnoland /* 189189499Srnoland * Check for the i82595 signature, and check that the round robin 190189499Srnoland * counter actually advances. 191189499Srnoland */ 192189499Srnoland if (((count1 = inb(iobase + ID_REG)) & Id_Mask) != Id_Sig) 193189499Srnoland return(0); 194189499Srnoland count2 = inb(iobase + ID_REG); 195189909Srnoland count2 = inb(iobase + ID_REG); 196189499Srnoland count2 = inb(iobase + ID_REG); 197189499Srnoland 198189499Srnoland return((count2 & Counter_bits) == ((count1 + 0xc0) & Counter_bits)); 199189499Srnoland} 200189499Srnoland 201189499Srnolandstatic int 202189499Srnolandex_get_media (u_int32_t iobase) 203189499Srnoland{ 204189499Srnoland int tmp; 205189499Srnoland 206189499Srnoland outb(iobase + CMD_REG, Bank2_Sel); 207189499Srnoland tmp = inb(iobase + REG3); 208189499Srnoland outb(iobase + CMD_REG, Bank0_Sel); 209189499Srnoland 210189499Srnoland if (tmp & TPE_bit) 211189499Srnoland return(IFM_ETHER|IFM_10_T); 212189499Srnoland if (tmp & BNC_bit) 213189499Srnoland return(IFM_ETHER|IFM_10_2); 214189499Srnoland 215189499Srnoland return (IFM_ETHER|IFM_10_5); 216189499Srnoland} 217189499Srnoland 218189499Srnolandstatic void 219189499Srnolandex_get_address (u_int32_t iobase, u_char *enaddr) 220189499Srnoland{ 221189499Srnoland u_int16_t eaddr_tmp; 222189499Srnoland 223189499Srnoland eaddr_tmp = eeprom_read(iobase, EE_Eth_Addr_Lo); 224189499Srnoland enaddr[5] = eaddr_tmp & 0xff; 225189499Srnoland enaddr[4] = eaddr_tmp >> 8; 226189499Srnoland eaddr_tmp = eeprom_read(iobase, EE_Eth_Addr_Mid); 227189499Srnoland enaddr[3] = eaddr_tmp & 0xff; 228189499Srnoland enaddr[2] = eaddr_tmp >> 8; 229189499Srnoland eaddr_tmp = eeprom_read(iobase, EE_Eth_Addr_Hi); 230189499Srnoland enaddr[1] = eaddr_tmp & 0xff; 231189499Srnoland enaddr[0] = eaddr_tmp >> 8; 232189499Srnoland 233189499Srnoland return; 234189499Srnoland} 235189499Srnoland 236189499Srnolandstatic int 237189499Srnolandex_card_type (u_char *enaddr) 238189499Srnoland{ 239189499Srnoland if ((enaddr[0] == 0x00) && (enaddr[1] == 0xA0) && (enaddr[2] == 0xC9)) 240189499Srnoland return (CARD_TYPE_EX_10_PLUS); 241189499Srnoland 242189499Srnoland return (CARD_TYPE_EX_10); 243189499Srnoland} 244189499Srnoland 245189499Srnoland/* 246189499Srnoland * Non-destructive identify. 247189499Srnoland */ 248189499Srnolandstatic void 249189499Srnolandex_isa_identify (driver_t *driver, device_t parent) 250189499Srnoland{ 251189499Srnoland device_t child; 252189499Srnoland u_int32_t ioport; 253189499Srnoland u_char enaddr[6]; 254189499Srnoland u_int irq; 255189499Srnoland int tmp; 256189499Srnoland const char * desc; 257189499Srnoland 258189499Srnoland if (bootverbose) 259189499Srnoland printf("ex_isa_identify()\n"); 260189499Srnoland 261189499Srnoland for (ioport = 0x200; ioport < 0x3a0; ioport += 0x10) { 262189499Srnoland 263189499Srnoland /* No board found at address */ 264189499Srnoland if (!look_for_card(ioport)) { 265189499Srnoland continue; 266189499Srnoland } 267189499Srnoland 268189499Srnoland if (bootverbose) 269189499Srnoland printf("ex: Found card at 0x%03x!\n", ioport); 270189499Srnoland 271189499Srnoland /* Board in PnP mode */ 272189499Srnoland if (eeprom_read(ioport, EE_W0) & EE_W0_PNP) { 273189499Srnoland /* Reset the card. */ 274189499Srnoland outb(ioport + CMD_REG, Reset_CMD); 275189499Srnoland DELAY(500); 276189499Srnoland if (bootverbose) 277189499Srnoland printf("ex: card at 0x%03x in PnP mode!\n", ioport); 278189499Srnoland continue; 279189499Srnoland } 280189499Srnoland 281189499Srnoland bzero(enaddr, sizeof(enaddr)); 282189499Srnoland 283189499Srnoland /* Reset the card. */ 284189499Srnoland outb(ioport + CMD_REG, Reset_CMD); 285190595Srnoland DELAY(400); 286190595Srnoland 287189499Srnoland ex_get_address(ioport, enaddr); 288189499Srnoland tmp = eeprom_read(ioport, EE_W1) & EE_W1_INT_SEL; 289190595Srnoland 290190595Srnoland /* work out which set of irq <-> internal tables to use */ 291190595Srnoland if (ex_card_type(enaddr) == CARD_TYPE_EX_10_PLUS) { 292190595Srnoland irq = plus_ee2irqmap[tmp]; 293190595Srnoland desc = "Intel Pro/10+"; 294190595Srnoland } else { 295190595Srnoland irq = ee2irqmap[tmp]; 296190595Srnoland desc = "Intel Pro/10"; 297190595Srnoland } 298190595Srnoland 299190595Srnoland child = BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, "ex", -1); 300190595Srnoland device_set_desc_copy(child, desc); 301190595Srnoland device_set_driver(child, driver); 302190595Srnoland bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1); 303190595Srnoland bus_set_resource(child, SYS_RES_IOPORT, 0, ioport, EX_IOSIZE); 304190595Srnoland 305190595Srnoland if (bootverbose) 306190595Srnoland printf("ex: Adding board at 0x%03x, irq %d\n", ioport, irq); 307190595Srnoland } 308190595Srnoland 309190595Srnoland return; 310190595Srnoland} 311190595Srnoland 312190595Srnolandstatic int 313190595Srnolandex_isa_probe(device_t dev) 314190595Srnoland{ 315190595Srnoland u_int iobase; 316190595Srnoland u_int irq; 317190595Srnoland char * irq2ee; 318190595Srnoland u_char * ee2irq; 319190595Srnoland u_char enaddr[6]; 320190595Srnoland int tmp; 321190595Srnoland int error; 322190595Srnoland 323190595Srnoland DODEBUG(Start_End, printf("ex_probe: start\n");); 324190595Srnoland 325190595Srnoland /* Check isapnp ids */ 326190674Srnoland error = ISA_PNP_PROBE(device_get_parent(dev), dev, ex_ids); 327190595Srnoland 328189499Srnoland /* If the card had a PnP ID that didn't match any we know about */ 329190674Srnoland if (error == ENXIO) { 330190674Srnoland return(error); 331190674Srnoland } 332190674Srnoland 333190674Srnoland /* If we had some other problem. */ 334190674Srnoland if (!(error == 0 || error == ENOENT)) { 335190674Srnoland return(error); 336190674Srnoland } 337190674Srnoland 338190674Srnoland iobase = bus_get_resource_start(dev, SYS_RES_IOPORT, 0); 339190674Srnoland if (!iobase) { 340190674Srnoland printf("ex: no iobase?\n"); 341190674Srnoland return(ENXIO); 342190674Srnoland } 343190674Srnoland 344190595Srnoland if (!look_for_card(iobase)) { 345190595Srnoland printf("ex: no card found at 0x%03x\n", iobase); 346190595Srnoland return(ENXIO); 347190595Srnoland } 348189499Srnoland 349190595Srnoland if (bootverbose) 350190674Srnoland printf("ex: ex_isa_probe() found card at 0x%03x\n", iobase); 351190595Srnoland 352189499Srnoland /* 353189499Srnoland * Reset the card. 354189499Srnoland */ 355189499Srnoland outb(iobase + CMD_REG, Reset_CMD); 356189499Srnoland DELAY(800); 357189499Srnoland 358189499Srnoland ex_get_address(iobase, enaddr); 359189499Srnoland 360189499Srnoland /* work out which set of irq <-> internal tables to use */ 361189499Srnoland if (ex_card_type(enaddr) == CARD_TYPE_EX_10_PLUS) { 362189499Srnoland irq2ee = plus_irq2eemap; 363189499Srnoland ee2irq = plus_ee2irqmap; 364189499Srnoland } else { 365189499Srnoland irq2ee = irq2eemap; 366189499Srnoland ee2irq = ee2irqmap; 367189499Srnoland } 368189499Srnoland 369189499Srnoland tmp = eeprom_read(iobase, EE_W1) & EE_W1_INT_SEL; 370189499Srnoland irq = bus_get_resource_start(dev, SYS_RES_IRQ, 0); 371189499Srnoland 372189499Srnoland if (irq > 0) { 373189499Srnoland /* This will happen if board is in PnP mode. */ 374189499Srnoland if (ee2irq[tmp] != irq) { 375189499Srnoland printf("ex: WARNING: board's EEPROM is configured" 376189499Srnoland " for IRQ %d, using %d\n", 377189499Srnoland ee2irq[tmp], irq); 378189499Srnoland } 379189499Srnoland } else { 380189499Srnoland irq = ee2irq[tmp]; 381189499Srnoland bus_set_resource(dev, SYS_RES_IRQ, 0, irq, 1); 382189499Srnoland } 383189499Srnoland 384189499Srnoland if (irq == 0) { 385189499Srnoland printf("ex: invalid IRQ.\n"); 386189499Srnoland return(ENXIO); 387189499Srnoland } 388189499Srnoland 389189499Srnoland DODEBUG(Start_End, printf("ex_probe: finish\n");); 390189499Srnoland 391189499Srnoland return(0); 392189499Srnoland} 393189499Srnoland 394189499Srnolandstatic int 395189499Srnolandex_isa_attach(device_t dev) 396189499Srnoland{ 397189499Srnoland struct ex_softc * sc = device_get_softc(dev); 398189499Srnoland struct ifnet * ifp = &sc->arpcom.ac_if; 399189499Srnoland struct ifmedia * ifm; 400189499Srnoland int unit = device_get_unit(dev); 401189499Srnoland int error; 402189499Srnoland int rid; 403189499Srnoland void * ih; 404189499Srnoland u_int16_t temp; 405189499Srnoland 406189499Srnoland DODEBUG(Start_End, device_printf(dev, "start\n");); 407189499Srnoland 408189499Srnoland rid = 0; 409189499Srnoland sc->ioport = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 410189499Srnoland 0, ~0, 1, RF_ACTIVE); 411189499Srnoland 412189499Srnoland if (!sc->ioport) { 413190595Srnoland device_printf(dev, "No I/O space?!\n"); 414190595Srnoland goto bad; 415189499Srnoland } 416189499Srnoland 417190595Srnoland rid = 0; 418190595Srnoland sc->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 419190674Srnoland 0, ~0, 1, RF_ACTIVE); 420190595Srnoland 421190595Srnoland if (!sc->irq) { 422190595Srnoland device_printf(dev, "No IRQ?!\n"); 423190595Srnoland goto bad; 424195501Srnoland } 425195501Srnoland 426190595Srnoland error = bus_setup_intr(dev, sc->irq, INTR_TYPE_NET, 427190595Srnoland ex_intr, (void *)sc, &ih); 428190595Srnoland 429190595Srnoland if (error) { 430190595Srnoland device_printf(dev, "bus_setup_intr() failed!\n"); 431190595Srnoland goto bad; 432190595Srnoland } 433190595Srnoland 434190595Srnoland /* 435190674Srnoland * Fill in several fields of the softc structure: 436190595Srnoland * - I/O base address. 437189499Srnoland * - Hardware Ethernet address. 438190674Srnoland * - IRQ number (if not supplied in config file, read it from EEPROM). 439190674Srnoland * - Connector type. 440190674Srnoland */ 441190674Srnoland sc->dev = dev; 442190674Srnoland sc->iobase = rman_get_start(sc->ioport); 443190674Srnoland sc->irq_no = rman_get_start(sc->irq); 444190674Srnoland 445190674Srnoland ex_get_address(sc->iobase, sc->arpcom.ac_enaddr); 446190674Srnoland 447190674Srnoland /* work out which set of irq <-> internal tables to use */ 448190674Srnoland if (ex_card_type(sc->arpcom.ac_enaddr) == CARD_TYPE_EX_10_PLUS) { 449190674Srnoland sc->irq2ee = plus_irq2eemap; 450190595Srnoland sc->ee2irq = plus_ee2irqmap; 451190674Srnoland } else { 452190595Srnoland sc->irq2ee = irq2eemap; 453190595Srnoland sc->ee2irq = ee2irqmap; 454189499Srnoland } 455190595Srnoland 456190674Srnoland sc->mem_size = CARD_RAM_SIZE; /* XXX This should be read from the card itself. */ 457190595Srnoland 458190595Srnoland /* 459189499Srnoland * Initialize the ifnet structure. 460189499Srnoland */ 461189499Srnoland ifp->if_softc = sc; 462189499Srnoland ifp->if_unit = unit; 463189499Srnoland ifp->if_name = "ex"; 464189499Srnoland ifp->if_mtu = ETHERMTU; 465189499Srnoland ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST /* XXX not done yet. | IFF_MULTICAST */; 466189499Srnoland ifp->if_output = ether_output; 467189499Srnoland ifp->if_start = ex_start; 468189499Srnoland ifp->if_ioctl = ex_ioctl; 469189499Srnoland ifp->if_watchdog = ex_watchdog; 470189499Srnoland ifp->if_init = ex_init; 471189499Srnoland ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; 472189499Srnoland 473189499Srnoland ifmedia_init(&sc->ifmedia, 0, ex_ifmedia_upd, ex_ifmedia_sts); 474189499Srnoland 475189499Srnoland temp = eeprom_read(sc->iobase, EE_W5); 476189499Srnoland if (temp & EE_W5_PORT_TPE) 477189499Srnoland ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T, 0, NULL); 478189499Srnoland if (temp & EE_W5_PORT_BNC) 479189499Srnoland ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_2, 0, NULL); 480189499Srnoland if (temp & EE_W5_PORT_AUI) 481189499Srnoland ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_5, 0, NULL); 482189499Srnoland 483189499Srnoland ifmedia_set(&sc->ifmedia, ex_get_media(sc->iobase)); 484189499Srnoland 485189499Srnoland ifm = &sc->ifmedia; 486189499Srnoland ifm->ifm_media = ifm->ifm_cur->ifm_media; 487189499Srnoland ex_ifmedia_upd(ifp); 488189499Srnoland 489189499Srnoland /* 490189499Srnoland * Attach the interface. 491189499Srnoland */ 492189499Srnoland if_attach(ifp); 493189499Srnoland ether_ifattach(ifp); 494189499Srnoland 495189499Srnoland temp = eeprom_read(sc->iobase, EE_W0); 496189499Srnoland device_printf(sc->dev, "%s config, %s bus, ", 497189499Srnoland (temp & EE_W0_PNP) ? "PnP" : "Manual", 498189499Srnoland (temp & EE_W0_BUS16) ? "16-bit" : "8-bit"); 499189499Srnoland 500189499Srnoland temp = eeprom_read(sc->iobase, EE_W6); 501189499Srnoland printf("board id 0x%03x, stepping 0x%01x\n", 502189499Srnoland (temp & EE_W6_BOARD_MASK) >> EE_W6_BOARD_SHIFT, 503189499Srnoland temp & EE_W6_STEP_MASK); 504189499Srnoland 505189499Srnoland device_printf(sc->dev, "Ethernet address %6D\n", 506189499Srnoland sc->arpcom.ac_enaddr, ":"); 507189499Srnoland /* 508189499Srnoland * If BPF is in the kernel, call the attach for it 509189499Srnoland */ 510189499Srnoland bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header)); 511189499Srnoland DODEBUG(Start_End, printf("ex_isa_attach%d: finish\n", unit);); 512189499Srnoland 513189499Srnoland return(0); 514189499Srnolandbad: 515189499Srnoland 516189499Srnoland if (sc->ioport) 517189499Srnoland bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->ioport); 518189499Srnoland if (sc->irq) 519189499Srnoland bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq); 520189499Srnoland 521189499Srnoland return (-1); 522189499Srnoland} 523189499Srnoland 524189499Srnoland 525189499Srnolandstatic void 526189499Srnolandex_init(void *xsc) 527189499Srnoland{ 528189499Srnoland struct ex_softc * sc = (struct ex_softc *) xsc; 529189499Srnoland struct ifnet * ifp = &sc->arpcom.ac_if; 530189499Srnoland int s; 531189499Srnoland int i; 532189499Srnoland register int iobase = sc->iobase; 533189499Srnoland unsigned short temp_reg; 534189499Srnoland 535189499Srnoland DODEBUG(Start_End, printf("ex_init%d: start\n", ifp->if_unit);); 536189499Srnoland 537189499Srnoland if (ifp->if_addrhead.tqh_first == NULL) { 538189499Srnoland return; 539189499Srnoland } 540189499Srnoland s = splimp(); 541189499Srnoland sc->arpcom.ac_if.if_timer = 0; 542189499Srnoland 543189499Srnoland /* 544189499Srnoland * Load the ethernet address into the card. 545189499Srnoland */ 546189499Srnoland outb(iobase + CMD_REG, Bank2_Sel); 547189499Srnoland temp_reg = inb(iobase + EEPROM_REG); 548189499Srnoland if (temp_reg & Trnoff_Enable) { 549189499Srnoland outb(iobase + EEPROM_REG, temp_reg & ~Trnoff_Enable); 550189499Srnoland } 551189499Srnoland for (i = 0; i < ETHER_ADDR_LEN; i++) { 552189499Srnoland outb(iobase + I_ADDR_REG0 + i, sc->arpcom.ac_enaddr[i]); 553189499Srnoland } 554189499Srnoland /* 555189499Srnoland * - Setup transmit chaining and discard bad received frames. 556189499Srnoland * - Match broadcast. 557189499Srnoland * - Clear test mode. 558189499Srnoland * - Set receiving mode. 559189499Srnoland * - Set IRQ number. 560189499Srnoland */ 561189499Srnoland outb(iobase + REG1, inb(iobase + REG1) | Tx_Chn_Int_Md | Tx_Chn_ErStp | Disc_Bad_Fr); 562189499Srnoland outb(iobase + REG2, inb(iobase + REG2) | No_SA_Ins | RX_CRC_InMem); 563189499Srnoland outb(iobase + REG3, inb(iobase + REG3) & 0x3f /* XXX constants. */ ); 564189499Srnoland outb(iobase + CMD_REG, Bank1_Sel); 565189499Srnoland outb(iobase + INT_NO_REG, (inb(iobase + INT_NO_REG) & 0xf8) | sc->irq2ee[sc->irq_no]); 566189499Srnoland 567189499Srnoland /* 568189499Srnoland * Divide the available memory in the card into rcv and xmt buffers. 569189499Srnoland * By default, I use the first 3/4 of the memory for the rcv buffer, 570189499Srnoland * and the remaining 1/4 of the memory for the xmt buffer. 571189499Srnoland */ 572189499Srnoland sc->rx_mem_size = sc->mem_size * 3 / 4; 573189499Srnoland sc->tx_mem_size = sc->mem_size - sc->rx_mem_size; 574189499Srnoland sc->rx_lower_limit = 0x0000; 575189499Srnoland sc->rx_upper_limit = sc->rx_mem_size - 2; 576189499Srnoland sc->tx_lower_limit = sc->rx_mem_size; 577189499Srnoland sc->tx_upper_limit = sc->mem_size - 2; 578189499Srnoland outb(iobase + RCV_LOWER_LIMIT_REG, sc->rx_lower_limit >> 8); 579189499Srnoland outb(iobase + RCV_UPPER_LIMIT_REG, sc->rx_upper_limit >> 8); 580189499Srnoland outb(iobase + XMT_LOWER_LIMIT_REG, sc->tx_lower_limit >> 8); 581189499Srnoland outb(iobase + XMT_UPPER_LIMIT_REG, sc->tx_upper_limit >> 8); 582189499Srnoland 583189499Srnoland /* 584189499Srnoland * Enable receive and transmit interrupts, and clear any pending int. 585189499Srnoland */ 586189499Srnoland outb(iobase + REG1, inb(iobase + REG1) | TriST_INT); 587189499Srnoland outb(iobase + CMD_REG, Bank0_Sel); 588189499Srnoland outb(iobase + MASK_REG, All_Int & ~(Rx_Int | Tx_Int)); 589189499Srnoland outb(iobase + STATUS_REG, All_Int); 590189499Srnoland 591189499Srnoland /* 592189499Srnoland * Initialize receive and transmit ring buffers. 593189499Srnoland */ 594189499Srnoland outw(iobase + RCV_BAR, sc->rx_lower_limit); 595189499Srnoland sc->rx_head = sc->rx_lower_limit; 596189499Srnoland outw(iobase + RCV_STOP_REG, sc->rx_upper_limit | 0xfe); 597189499Srnoland outw(iobase + XMT_BAR, sc->tx_lower_limit); 598189499Srnoland sc->tx_head = sc->tx_tail = sc->tx_lower_limit; 599189499Srnoland 600189499Srnoland ifp->if_flags |= IFF_RUNNING; 601189499Srnoland ifp->if_flags &= ~IFF_OACTIVE; 602189499Srnoland DODEBUG(Status, printf("OIDLE init\n");); 603189499Srnoland 604189499Srnoland /* 605189499Srnoland * Final reset of the board, and enable operation. 606189499Srnoland */ 607189499Srnoland outb(iobase + CMD_REG, Sel_Reset_CMD); 608189499Srnoland DELAY(2); 609189499Srnoland outb(iobase + CMD_REG, Rcv_Enable_CMD); 610189499Srnoland 611189499Srnoland ex_start(ifp); 612189499Srnoland splx(s); 613189499Srnoland 614189499Srnoland DODEBUG(Start_End, printf("ex_init%d: finish\n", ifp->if_unit);); 615189499Srnoland} 616189499Srnoland 617189499Srnoland 618189499Srnolandstatic void 619189499Srnolandex_start(struct ifnet *ifp) 620189499Srnoland{ 621189499Srnoland struct ex_softc * sc = ifp->if_softc; 622189499Srnoland int iobase = sc->iobase; 623189499Srnoland int i, s, len, data_len, avail, dest, next; 624189499Srnoland unsigned char tmp16[2]; 625189499Srnoland struct mbuf * opkt; 626189499Srnoland struct mbuf * m; 627189499Srnoland 628189499Srnoland DODEBUG(Start_End, printf("ex_start%d: start\n", unit);); 629189499Srnoland 630189499Srnoland s = splimp(); 631189499Srnoland 632189499Srnoland /* 633189499Srnoland * Main loop: send outgoing packets to network card until there are no 634189499Srnoland * more packets left, or the card cannot accept any more yet. 635189499Srnoland */ 636189499Srnoland while (((opkt = ifp->if_snd.ifq_head) != NULL) && 637189499Srnoland !(ifp->if_flags & IFF_OACTIVE)) { 638189499Srnoland 639189499Srnoland /* 640189499Srnoland * Ensure there is enough free transmit buffer space for 641189499Srnoland * this packet, including its header. Note: the header 642189499Srnoland * cannot wrap around the end of the transmit buffer and 643189499Srnoland * must be kept together, so we allow space for twice the 644189499Srnoland * length of the header, just in case. 645189499Srnoland */ 646189499Srnoland 647189499Srnoland for (len = 0, m = opkt; m != NULL; m = m->m_next) { 648189499Srnoland len += m->m_len; 649189499Srnoland } 650189499Srnoland 651189499Srnoland data_len = len; 652189499Srnoland 653189499Srnoland DODEBUG(Sent_Pkts, printf("1. Sending packet with %d data bytes. ", data_len);); 654189499Srnoland 655189499Srnoland if (len & 1) { 656189499Srnoland len += XMT_HEADER_LEN + 1; 657189499Srnoland } else { 658189499Srnoland len += XMT_HEADER_LEN; 659189499Srnoland } 660189499Srnoland 661189499Srnoland if ((i = sc->tx_tail - sc->tx_head) >= 0) { 662189499Srnoland avail = sc->tx_mem_size - i; 663189499Srnoland } else { 664189499Srnoland avail = -i; 665189499Srnoland } 666189499Srnoland 667189499Srnoland DODEBUG(Sent_Pkts, printf("i=%d, avail=%d\n", i, avail);); 668189499Srnoland 669189499Srnoland if (avail >= len + XMT_HEADER_LEN) { 670189499Srnoland IF_DEQUEUE(&ifp->if_snd, opkt); 671189499Srnoland 672189499Srnoland#ifdef EX_PSA_INTR 673189499Srnoland /* 674189499Srnoland * Disable rx and tx interrupts, to avoid corruption 675189499Srnoland * of the host address register by interrupt service 676189499Srnoland * routines. 677189499Srnoland * XXX Is this necessary with splimp() enabled? 678189499Srnoland */ 679189499Srnoland outb(iobase + MASK_REG, All_Int); 680189499Srnoland#endif 681189499Srnoland 682189499Srnoland /* 683189499Srnoland * Compute the start and end addresses of this 684189499Srnoland * frame in the tx buffer. 685189499Srnoland */ 686189499Srnoland dest = sc->tx_tail; 687189499Srnoland next = dest + len; 688189499Srnoland 689189499Srnoland if (next > sc->tx_upper_limit) { 690189499Srnoland if ((sc->tx_upper_limit + 2 - sc->tx_tail) <= 691189499Srnoland XMT_HEADER_LEN) { 692189499Srnoland dest = sc->tx_lower_limit; 693189499Srnoland next = dest + len; 694189499Srnoland } else { 695189499Srnoland next = sc->tx_lower_limit + 696189499Srnoland next - sc->tx_upper_limit - 2; 697189499Srnoland } 698189499Srnoland } 699189499Srnoland 700189499Srnoland /* 701189499Srnoland * Build the packet frame in the card's ring buffer. 702189499Srnoland */ 703189499Srnoland DODEBUG(Sent_Pkts, printf("2. dest=%d, next=%d. ", dest, next);); 704189499Srnoland 705189499Srnoland outw(iobase + HOST_ADDR_REG, dest); 706189499Srnoland outw(iobase + IO_PORT_REG, Transmit_CMD); 707189499Srnoland outw(iobase + IO_PORT_REG, 0); 708189499Srnoland outw(iobase + IO_PORT_REG, next); 709189499Srnoland outw(iobase + IO_PORT_REG, data_len); 710189499Srnoland 711189499Srnoland /* 712189499Srnoland * Output the packet data to the card. Ensure all 713189499Srnoland * transfers are 16-bit wide, even if individual 714189499Srnoland * mbufs have odd length. 715189499Srnoland */ 716189499Srnoland 717189499Srnoland for (m = opkt, i = 0; m != NULL; m = m->m_next) { 718189499Srnoland DODEBUG(Sent_Pkts, printf("[%d]", m->m_len);); 719189499Srnoland if (i) { 720189499Srnoland tmp16[1] = *(mtod(m, caddr_t)); 721189499Srnoland outsw(iobase + IO_PORT_REG, tmp16, 1); 722189499Srnoland } 723189499Srnoland outsw(iobase + IO_PORT_REG, 724189499Srnoland mtod(m, caddr_t) + i, (m->m_len - i) / 2); 725189499Srnoland 726189499Srnoland if ((i = (m->m_len - i) & 1) != 0) { 727189499Srnoland tmp16[0] = *(mtod(m, caddr_t) + 728189499Srnoland m->m_len - 1); 729189499Srnoland } 730189499Srnoland } 731189499Srnoland if (i) { 732189499Srnoland outsw(iobase + IO_PORT_REG, tmp16, 1); 733189499Srnoland } 734189499Srnoland 735189499Srnoland /* 736189499Srnoland * If there were other frames chained, update the 737189499Srnoland * chain in the last one. 738189499Srnoland */ 739189499Srnoland if (sc->tx_head != sc->tx_tail) { 740189499Srnoland if (sc->tx_tail != dest) { 741189499Srnoland outw(iobase + HOST_ADDR_REG, 742189499Srnoland sc->tx_last + XMT_Chain_Point); 743189499Srnoland outw(iobase + IO_PORT_REG, dest); 744189499Srnoland } 745189499Srnoland outw(iobase + HOST_ADDR_REG, 746189499Srnoland sc->tx_last + XMT_Byte_Count); 747189499Srnoland i = inw(iobase + IO_PORT_REG); 748189499Srnoland outw(iobase + HOST_ADDR_REG, 749189499Srnoland sc->tx_last + XMT_Byte_Count); 750189499Srnoland outw(iobase + IO_PORT_REG, i | Ch_bit); 751189499Srnoland } 752189499Srnoland 753189499Srnoland /* 754189499Srnoland * Resume normal operation of the card: 755189499Srnoland * - Make a dummy read to flush the DRAM write 756189499Srnoland * pipeline. 757189499Srnoland * - Enable receive and transmit interrupts. 758189499Srnoland * - Send Transmit or Resume_XMT command, as 759189499Srnoland * appropriate. 760189499Srnoland */ 761189499Srnoland inw(iobase + IO_PORT_REG); 762189499Srnoland#ifdef EX_PSA_INTR 763189499Srnoland outb(iobase + MASK_REG, All_Int & ~(Rx_Int | Tx_Int)); 764189499Srnoland#endif 765189499Srnoland if (sc->tx_head == sc->tx_tail) { 766189499Srnoland outw(iobase + XMT_BAR, dest); 767189499Srnoland outb(iobase + CMD_REG, Transmit_CMD); 768189499Srnoland sc->tx_head = dest; 769189499Srnoland DODEBUG(Sent_Pkts, printf("Transmit\n");); 770189499Srnoland } else { 771189499Srnoland outb(iobase + CMD_REG, Resume_XMT_List_CMD); 772189499Srnoland DODEBUG(Sent_Pkts, printf("Resume\n");); 773189499Srnoland } 774189499Srnoland 775189499Srnoland sc->tx_last = dest; 776189499Srnoland sc->tx_tail = next; 777189499Srnoland 778189499Srnoland if (ifp->if_bpf != NULL) { 779189499Srnoland bpf_mtap(ifp, opkt); 780189499Srnoland } 781189499Srnoland 782189499Srnoland ifp->if_timer = 2; 783189499Srnoland ifp->if_opackets++; 784189499Srnoland m_freem(opkt); 785189499Srnoland } else { 786189499Srnoland ifp->if_flags |= IFF_OACTIVE; 787189499Srnoland DODEBUG(Status, printf("OACTIVE start\n");); 788189499Srnoland } 789189499Srnoland } 790189499Srnoland 791189499Srnoland splx(s); 792189499Srnoland 793189499Srnoland DODEBUG(Start_End, printf("ex_start%d: finish\n", unit);); 794189499Srnoland} 795189499Srnoland 796189499Srnolandstatic void 797189499Srnolandex_stop(struct ex_softc *sc) 798189499Srnoland{ 799189499Srnoland int iobase = sc->iobase; 800189499Srnoland 801189499Srnoland DODEBUG(Start_End, printf("ex_stop%d: start\n", unit);); 802189499Srnoland 803189499Srnoland /* 804189499Srnoland * Disable card operation: 805189499Srnoland * - Disable the interrupt line. 806189499Srnoland * - Flush transmission and disable reception. 807189499Srnoland * - Mask and clear all interrupts. 808189499Srnoland * - Reset the 82595. 809189499Srnoland */ 810189499Srnoland outb(iobase + CMD_REG, Bank1_Sel); 811189499Srnoland outb(iobase + REG1, inb(iobase + REG1) & ~TriST_INT); 812189499Srnoland outb(iobase + CMD_REG, Bank0_Sel); 813189499Srnoland outb(iobase + CMD_REG, Rcv_Stop); 814189499Srnoland sc->tx_head = sc->tx_tail = sc->tx_lower_limit; 815189499Srnoland 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. */ 816189499Srnoland outb(iobase + MASK_REG, All_Int); 817189499Srnoland outb(iobase + STATUS_REG, All_Int); 818189499Srnoland outb(iobase + CMD_REG, Reset_CMD); 819189499Srnoland DELAY(200); 820189499Srnoland 821189499Srnoland DODEBUG(Start_End, printf("ex_stop%d: finish\n", unit);); 822189499Srnoland 823189499Srnoland return; 824189499Srnoland} 825189499Srnoland 826189499Srnoland 827189499Srnolandstatic void 828189499Srnolandex_intr(void *arg) 829189499Srnoland{ 830189499Srnoland struct ex_softc * sc = (struct ex_softc *)arg; 831189499Srnoland struct ifnet * ifp = &sc->arpcom.ac_if; 832189499Srnoland int iobase = sc->iobase; 833189499Srnoland int int_status, send_pkts; 834189499Srnoland 835189499Srnoland DODEBUG(Start_End, printf("ex_intr%d: start\n", unit);); 836189499Srnoland 837189499Srnoland#ifdef EXDEBUG 838189499Srnoland if (++exintr_count != 1) 839189499Srnoland printf("WARNING: nested interrupt (%d). Mail the author.\n", exintr_count); 840189499Srnoland#endif 841189499Srnoland 842189499Srnoland send_pkts = 0; 843189499Srnoland while ((int_status = inb(iobase + STATUS_REG)) & (Tx_Int | Rx_Int)) { 844189499Srnoland if (int_status & Rx_Int) { 845189499Srnoland outb(iobase + STATUS_REG, Rx_Int); 846189499Srnoland 847189499Srnoland ex_rx_intr(sc); 848189499Srnoland } else if (int_status & Tx_Int) { 849189499Srnoland outb(iobase + STATUS_REG, Tx_Int); 850189499Srnoland 851189499Srnoland ex_tx_intr(sc); 852189499Srnoland send_pkts = 1; 853189499Srnoland } 854189499Srnoland } 855189499Srnoland 856189499Srnoland /* 857189499Srnoland * If any packet has been transmitted, and there are queued packets to 858189499Srnoland * be sent, attempt to send more packets to the network card. 859189499Srnoland */ 860189499Srnoland 861189499Srnoland if (send_pkts && (ifp->if_snd.ifq_head != NULL)) { 862189499Srnoland ex_start(ifp); 863189499Srnoland } 864189499Srnoland 865189499Srnoland#ifdef EXDEBUG 866189499Srnoland exintr_count--; 867189499Srnoland#endif 868189499Srnoland 869189499Srnoland DODEBUG(Start_End, printf("ex_intr%d: finish\n", unit);); 870189499Srnoland 871189499Srnoland return; 872189499Srnoland} 873189499Srnoland 874189499Srnolandstatic void 875189499Srnolandex_tx_intr(struct ex_softc *sc) 876189499Srnoland{ 877189499Srnoland struct ifnet * ifp = &sc->arpcom.ac_if; 878189499Srnoland int iobase = sc->iobase; 879189499Srnoland int tx_status; 880189499Srnoland 881189499Srnoland DODEBUG(Start_End, printf("ex_tx_intr%d: start\n", unit);); 882189499Srnoland 883189499Srnoland /* 884189499Srnoland * - Cancel the watchdog. 885189499Srnoland * For all packets transmitted since last transmit interrupt: 886189499Srnoland * - Advance chain pointer to next queued packet. 887189499Srnoland * - Update statistics. 888189499Srnoland */ 889189499Srnoland 890189499Srnoland ifp->if_timer = 0; 891189499Srnoland 892189499Srnoland while (sc->tx_head != sc->tx_tail) { 893189499Srnoland outw(iobase + HOST_ADDR_REG, sc->tx_head); 894189499Srnoland 895189499Srnoland if (! inw(iobase + IO_PORT_REG) & Done_bit) 896189499Srnoland break; 897189499Srnoland 898189499Srnoland tx_status = inw(iobase + IO_PORT_REG); 899189499Srnoland sc->tx_head = inw(iobase + IO_PORT_REG); 900189499Srnoland 901189499Srnoland if (tx_status & TX_OK_bit) { 902189499Srnoland ifp->if_opackets++; 903189499Srnoland } else { 904189499Srnoland ifp->if_oerrors++; 905189499Srnoland } 906189499Srnoland 907189499Srnoland ifp->if_collisions += tx_status & No_Collisions_bits; 908189499Srnoland } 909189499Srnoland 910189499Srnoland /* 911189499Srnoland * The card should be ready to accept more packets now. 912189499Srnoland */ 913189499Srnoland 914189499Srnoland ifp->if_flags &= ~IFF_OACTIVE; 915189499Srnoland 916189499Srnoland DODEBUG(Status, printf("OIDLE tx_intr\n");); 917189499Srnoland DODEBUG(Start_End, printf("ex_tx_intr%d: finish\n", unit);); 918189499Srnoland 919189499Srnoland return; 920189499Srnoland} 921189499Srnoland 922189499Srnolandstatic void 923189499Srnolandex_rx_intr(struct ex_softc *sc) 924189499Srnoland{ 925189499Srnoland struct ifnet * ifp = &sc->arpcom.ac_if; 926189499Srnoland int iobase = sc->iobase; 927189499Srnoland int rx_status; 928189499Srnoland int pkt_len; 929189499Srnoland int QQQ; 930189499Srnoland struct mbuf * m; 931189499Srnoland struct mbuf * ipkt; 932189499Srnoland struct ether_header * eh; 933189499Srnoland 934189499Srnoland DODEBUG(Start_End, printf("ex_rx_intr%d: start\n", unit);); 935189499Srnoland 936189499Srnoland /* 937189499Srnoland * For all packets received since last receive interrupt: 938189499Srnoland * - If packet ok, read it into a new mbuf and queue it to interface, 939189499Srnoland * updating statistics. 940189499Srnoland * - If packet bad, just discard it, and update statistics. 941189499Srnoland * Finally, advance receive stop limit in card's memory to new location. 942189499Srnoland */ 943189499Srnoland 944189499Srnoland outw(iobase + HOST_ADDR_REG, sc->rx_head); 945189499Srnoland 946189499Srnoland while (inw(iobase + IO_PORT_REG) == RCV_Done) { 947189499Srnoland 948189499Srnoland rx_status = inw(iobase + IO_PORT_REG); 949189499Srnoland sc->rx_head = inw(iobase + IO_PORT_REG); 950189499Srnoland QQQ = pkt_len = inw(iobase + IO_PORT_REG); 951189499Srnoland 952189499Srnoland if (rx_status & RCV_OK_bit) { 953189499Srnoland MGETHDR(m, M_DONTWAIT, MT_DATA); 954189499Srnoland ipkt = m; 955189499Srnoland if (ipkt == NULL) { 956189499Srnoland ifp->if_iqdrops++; 957189499Srnoland } else { 958189499Srnoland ipkt->m_pkthdr.rcvif = ifp; 959189499Srnoland ipkt->m_pkthdr.len = pkt_len; 960189499Srnoland ipkt->m_len = MHLEN; 961189499Srnoland 962189499Srnoland while (pkt_len > 0) { 963189499Srnoland if (pkt_len > MINCLSIZE) { 964189499Srnoland MCLGET(m, M_DONTWAIT); 965189499Srnoland if (m->m_flags & M_EXT) { 966189499Srnoland m->m_len = MCLBYTES; 967189499Srnoland } else { 968189499Srnoland m_freem(ipkt); 969189499Srnoland ifp->if_iqdrops++; 970189499Srnoland goto rx_another; 971189499Srnoland } 972189499Srnoland } 973189499Srnoland m->m_len = min(m->m_len, pkt_len); 974189499Srnoland 975189499Srnoland /* 976189499Srnoland * NOTE: I'm assuming that all mbufs allocated are of even length, 977189499Srnoland * except for the last one in an odd-length packet. 978189499Srnoland */ 979189499Srnoland 980189499Srnoland insw(iobase + IO_PORT_REG, 981189499Srnoland mtod(m, caddr_t), m->m_len / 2); 982189499Srnoland 983189499Srnoland if (m->m_len & 1) { 984189499Srnoland *(mtod(m, caddr_t) + m->m_len - 1) = inb(iobase + IO_PORT_REG); 985189499Srnoland } 986189499Srnoland pkt_len -= m->m_len; 987189499Srnoland 988189499Srnoland if (pkt_len > 0) { 989189499Srnoland MGET(m->m_next, M_DONTWAIT, MT_DATA); 990189499Srnoland if (m->m_next == NULL) { 991189499Srnoland m_freem(ipkt); 992189499Srnoland ifp->if_iqdrops++; 993189499Srnoland goto rx_another; 994189499Srnoland } 995189499Srnoland m = m->m_next; 996189499Srnoland m->m_len = MLEN; 997189499Srnoland } 998189499Srnoland } 999189499Srnoland eh = mtod(ipkt, struct ether_header *); 1000189499Srnoland#ifdef EXDEBUG 1001189499Srnoland if (debug_mask & Rcvd_Pkts) { 1002189499Srnoland if ((eh->ether_dhost[5] != 0xff) || (eh->ether_dhost[0] != 0xff)) { 1003189499Srnoland printf("Receive packet with %d data bytes: %6D -> ", QQQ, eh->ether_shost, ":"); 1004189499Srnoland printf("%6D\n", eh->ether_dhost, ":"); 1005189499Srnoland } /* QQQ */ 1006189499Srnoland } 1007189499Srnoland#endif 1008189499Srnoland if (ifp->if_bpf != NULL) { 1009189499Srnoland bpf_mtap(ifp, ipkt); 1010189499Srnoland 1011189499Srnoland /* 1012189499Srnoland * Note that the interface cannot be in promiscuous mode 1013189499Srnoland * if there are no BPF listeners. And if we are in 1014189499Srnoland * promiscuous mode, we have to check if this packet is 1015189499Srnoland * really ours. 1016189499Srnoland */ 1017189499Srnoland if ((ifp->if_flags & IFF_PROMISC) && 1018189499Srnoland (eh->ether_dhost[0] & 1) == 0 && 1019189499Srnoland bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr, sizeof(eh->ether_dhost)) != 0 && 1020189499Srnoland bcmp(eh->ether_dhost, etherbroadcastaddr, sizeof(eh->ether_dhost)) != 0) { 1021189499Srnoland m_freem(ipkt); 1022189499Srnoland goto rx_another; 1023189499Srnoland } 1024189499Srnoland } 1025189499Srnoland m_adj(ipkt, sizeof(struct ether_header)); 1026189499Srnoland ether_input(ifp, eh, ipkt); 1027189499Srnoland ifp->if_ipackets++; 1028189499Srnoland } 1029189499Srnoland } else { 1030189499Srnoland ifp->if_ierrors++; 1031189499Srnoland } 1032189499Srnoland outw(iobase + HOST_ADDR_REG, sc->rx_head); 1033189499Srnolandrx_another: ; 1034189499Srnoland } 1035189499Srnoland 1036189499Srnoland if (sc->rx_head < sc->rx_lower_limit + 2) 1037189499Srnoland outw(iobase + RCV_STOP_REG, sc->rx_upper_limit); 1038189499Srnoland else 1039189499Srnoland outw(iobase + RCV_STOP_REG, sc->rx_head - 2); 1040189499Srnoland 1041189499Srnoland DODEBUG(Start_End, printf("ex_rx_intr%d: finish\n", unit);); 1042189499Srnoland 1043189499Srnoland return; 1044189499Srnoland} 1045189499Srnoland 1046189499Srnoland 1047189499Srnolandstatic int 1048189499Srnolandex_ioctl(register struct ifnet *ifp, u_long cmd, caddr_t data) 1049189499Srnoland{ 1050189499Srnoland struct ex_softc * sc = ifp->if_softc; 1051189499Srnoland struct ifreq * ifr = (struct ifreq *)data; 1052189499Srnoland int s; 1053189499Srnoland int error = 0; 1054189499Srnoland 1055189499Srnoland DODEBUG(Start_End, printf("ex_ioctl%d: start ", ifp->if_unit);); 1056189499Srnoland 1057189499Srnoland s = splimp(); 1058189499Srnoland 1059189499Srnoland switch(cmd) { 1060189499Srnoland case SIOCSIFADDR: 1061189499Srnoland case SIOCGIFADDR: 1062189499Srnoland case SIOCSIFMTU: 1063189499Srnoland error = ether_ioctl(ifp, cmd, data); 1064189499Srnoland break; 1065189499Srnoland 1066189499Srnoland case SIOCSIFFLAGS: 1067189499Srnoland DODEBUG(Start_End, printf("SIOCSIFFLAGS");); 1068189499Srnoland if ((ifp->if_flags & IFF_UP) == 0 && 1069189499Srnoland (ifp->if_flags & IFF_RUNNING)) { 1070189499Srnoland 1071189499Srnoland ifp->if_flags &= ~IFF_RUNNING; 1072189499Srnoland ex_stop(sc); 1073189499Srnoland } else { 1074189499Srnoland ex_init(sc); 1075189499Srnoland } 1076189499Srnoland break; 1077189499Srnoland#ifdef NODEF 1078189499Srnoland case SIOCGHWADDR: 1079189499Srnoland DODEBUG(Start_End, printf("SIOCGHWADDR");); 1080189499Srnoland bcopy((caddr_t)sc->sc_addr, (caddr_t)&ifr->ifr_data, 1081189499Srnoland sizeof(sc->sc_addr)); 1082189499Srnoland break; 1083189499Srnoland#endif 1084189499Srnoland case SIOCADDMULTI: 1085189499Srnoland DODEBUG(Start_End, printf("SIOCADDMULTI");); 1086189499Srnoland case SIOCDELMULTI: 1087189499Srnoland DODEBUG(Start_End, printf("SIOCDELMULTI");); 1088189499Srnoland /* XXX Support not done yet. */ 1089189499Srnoland error = EINVAL; 1090189499Srnoland break; 1091189499Srnoland case SIOCSIFMEDIA: 1092189499Srnoland case SIOCGIFMEDIA: 1093189499Srnoland error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, cmd); 1094189499Srnoland break; 1095189499Srnoland default: 1096189499Srnoland DODEBUG(Start_End, printf("unknown");); 1097189499Srnoland error = EINVAL; 1098189499Srnoland } 1099189499Srnoland 1100189499Srnoland splx(s); 1101189499Srnoland 1102189499Srnoland DODEBUG(Start_End, printf("\nex_ioctl%d: finish\n", ifp->if_unit);); 1103189499Srnoland 1104189499Srnoland return(error); 1105189499Srnoland} 1106189499Srnoland 1107189499Srnoland 1108189499Srnolandstatic void 1109189499Srnolandex_reset(struct ex_softc *sc) 1110189499Srnoland{ 1111189499Srnoland int s; 1112189499Srnoland 1113189499Srnoland DODEBUG(Start_End, printf("ex_reset%d: start\n", unit);); 1114189499Srnoland 1115189499Srnoland s = splimp(); 1116189499Srnoland 1117189499Srnoland ex_stop(sc); 1118189499Srnoland ex_init(sc); 1119189499Srnoland 1120189499Srnoland splx(s); 1121189499Srnoland 1122189499Srnoland DODEBUG(Start_End, printf("ex_reset%d: finish\n", unit);); 1123189499Srnoland 1124189499Srnoland return; 1125189499Srnoland} 1126189499Srnoland 1127189499Srnolandstatic void 1128189499Srnolandex_watchdog(struct ifnet *ifp) 1129189499Srnoland{ 1130189499Srnoland struct ex_softc * sc = ifp->if_softc; 1131189499Srnoland 1132189499Srnoland DODEBUG(Start_End, printf("ex_watchdog%d: start\n", ifp->if_unit);); 1133189499Srnoland 1134189499Srnoland ifp->if_flags &= ~IFF_OACTIVE; 1135189499Srnoland 1136189499Srnoland DODEBUG(Status, printf("OIDLE watchdog\n");); 1137189499Srnoland 1138189499Srnoland ifp->if_oerrors++; 1139189499Srnoland ex_reset(sc); 1140189499Srnoland ex_start(ifp); 1141189499Srnoland 1142189499Srnoland DODEBUG(Start_End, printf("ex_watchdog%d: finish\n", ifp->if_unit);); 1143189499Srnoland 1144189499Srnoland return; 1145189499Srnoland} 1146189499Srnoland 1147189499Srnolandstatic int 1148189499Srnolandex_ifmedia_upd (ifp) 1149189499Srnoland struct ifnet * ifp; 1150189499Srnoland{ 1151189499Srnoland struct ex_softc * sc = ifp->if_softc; 1152189499Srnoland 1153189499Srnoland return (0); 1154189499Srnoland} 1155189499Srnoland 1156189499Srnolandstatic void 1157189499Srnolandex_ifmedia_sts(ifp, ifmr) 1158189499Srnoland struct ifnet * ifp; 1159189499Srnoland struct ifmediareq * ifmr; 1160189499Srnoland{ 1161189499Srnoland struct ex_softc * sc = ifp->if_softc; 1162189499Srnoland 1163189499Srnoland ifmr->ifm_active = ex_get_media(sc->iobase); 1164189499Srnoland 1165189499Srnoland return; 1166189499Srnoland} 1167189499Srnoland 1168189499Srnolandstatic u_short 1169189499Srnolandeeprom_read(int iobase, int location) 1170189499Srnoland{ 1171189499Srnoland int i; 1172189499Srnoland u_short data = 0; 1173189499Srnoland int ee_addr; 1174189499Srnoland int read_cmd = location | EE_READ_CMD; 1175189499Srnoland short ctrl_val = EECS; 1176189499Srnoland 1177189499Srnoland ee_addr = iobase + EEPROM_REG; 1178189499Srnoland outb(iobase + CMD_REG, Bank2_Sel); 1179189499Srnoland outb(ee_addr, EECS); 1180189499Srnoland for (i = 8; i >= 0; i--) { 1181189499Srnoland short outval = (read_cmd & (1 << i)) ? ctrl_val | EEDI : ctrl_val; 1182189499Srnoland outb(ee_addr, outval); 1183189499Srnoland outb(ee_addr, outval | EESK); 1184189499Srnoland DELAY(3); 1185189499Srnoland outb(ee_addr, outval); 1186189499Srnoland DELAY(2); 1187189499Srnoland } 1188189499Srnoland outb(ee_addr, ctrl_val); 1189189499Srnoland 1190189499Srnoland for (i = 16; i > 0; i--) { 1191189499Srnoland outb(ee_addr, ctrl_val | EESK); 1192189499Srnoland DELAY(3); 1193189499Srnoland data = (data << 1) | ((inb(ee_addr) & EEDO) ? 1 : 0); 1194189499Srnoland outb(ee_addr, ctrl_val); 1195189499Srnoland DELAY(2); 1196189499Srnoland } 1197189499Srnoland 1198189499Srnoland ctrl_val &= ~EECS; 1199189499Srnoland outb(ee_addr, ctrl_val | EESK); 1200189499Srnoland DELAY(3); 1201189499Srnoland outb(ee_addr, ctrl_val); 1202189499Srnoland DELAY(2); 1203189499Srnoland outb(iobase + CMD_REG, Bank0_Sel); 1204189499Srnoland return(data); 1205189499Srnoland} 1206189499Srnoland