if_lc_isa.c revision 1.1
1/* $NetBSD: if_lc_isa.c,v 1.1 1997/07/31 21:58:19 matt Exp $ */ 2 3/*- 4 * Copyright (c) 1994, 1995, 1997 Matt Thomas <matt@3am-software.com> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. The name of the author may not be used to endorse or promote products 13 * derived from this software withough specific prior written permission 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27/* 28 * DEC EtherWORKS 3 Ethernet Controllers 29 * 30 * Written by Matt Thomas 31 * 32 * This driver supports the LEMAC (DE203, DE204, and DE205) cards. 33 */ 34 35#include "bpfilter.h" 36 37#include <sys/param.h> 38#include <sys/systm.h> 39#include <sys/mbuf.h> 40#include <sys/socket.h> 41#include <sys/ioctl.h> 42#include <sys/errno.h> 43#include <sys/syslog.h> 44#include <sys/select.h> 45#include <sys/device.h> 46#include <sys/queue.h> 47 48#include <net/if.h> 49#include <net/if_dl.h> 50#include <net/if_ether.h> 51#include <net/if_media.h> 52 53 54#ifdef INET 55#include <netinet/in.h> 56#include <netinet/in_systm.h> 57#include <netinet/in_var.h> 58#include <netinet/ip.h> 59#include <netinet/if_inarp.h> 60#endif 61 62#ifdef NS 63#include <netns/ns.h> 64#include <netns/ns_if.h> 65#endif 66 67#if NBPFILTER > 0 68#include <net/bpf.h> 69#include <net/bpfdesc.h> 70#endif 71 72#include <machine/cpu.h> 73#include <machine/bus.h> 74#include <machine/intr.h> 75 76#include <dev/ic/lemacreg.h> 77#include <dev/ic/lemacvar.h> 78 79#include <dev/isa/isavar.h> 80 81/* 82 * This keeps track of which ISAs have been through a lc probe sequence. 83 * A simple static variable isn't enough, since it's conceivable that 84 * a system might have more than one ISA bus. 85 * 86 * The "isa_bus" member is a pointer to the parent ISA bus device struct 87 * which will unique per ISA bus. 88 */ 89 90#define MAXCARDS_PER_ISABUS 4 /* if you have more than 4, you lose */ 91#define MAXSLOTS_PER_BUS 16 /* 0x200-0x3FF in 0x20 incr. */ 92 93struct lemac_isabus { 94 LIST_ENTRY(lemac_isabus) isa_link; 95 struct device *isa_bus; 96 struct lemac_card { 97 bus_addr_t iobase; 98 bus_addr_t maddr; 99 bus_size_t msize; 100 int irq; 101 int available; 102 } isa_cards[MAXCARDS_PER_ISABUS]; 103}; 104 105static LIST_HEAD(, lemac_isabus) lemac_isa_buses; 106static int lemac_isa_buses_inited; 107 108static void 109lemac_isa_card_add( 110 struct lemac_isabus *bus, 111 bus_addr_t iobase, 112 bus_addr_t maddr, 113 bus_size_t msize, 114 int irq) 115{ 116 int idx; 117 118 for (idx = 0; idx < MAXCARDS_PER_ISABUS; idx++) { 119 if (bus->isa_cards[idx].available == 0) { 120 bus->isa_cards[idx].iobase = iobase; 121 bus->isa_cards[idx].maddr = maddr; 122 bus->isa_cards[idx].msize = msize; 123 bus->isa_cards[idx].irq = irq; 124 bus->isa_cards[idx].available = 1; 125 break; 126 } 127 } 128} 129 130/* 131 * We'd like like to allow the irq, maddr, and iobase addresses to be 132 * wildcarded. So, we probe all the cards the first time lemac_isa_probe() 133 * is called. On subsequent calls we look for matching cards. 134 */ 135static int 136lemac_isa_probe( 137 struct device *parent, 138#ifdef __BROKEN_INDIRECT_CONFIG 139 void *match, 140#else 141 struct cfdata *match, 142#endif 143 void *aux) 144{ 145 struct isa_attach_args * const ia = aux; 146 struct lemac_isabus *bus; 147 int idx; 148 149 if (lemac_isa_buses_inited == 0) { 150 LIST_INIT(&lemac_isa_buses); 151 lemac_isa_buses_inited = 1; 152 } 153 154 /* 155 * Probe this bus if we haven't done so already. 156 */ 157 for (bus = lemac_isa_buses.lh_first; bus != NULL; 158 bus = bus->isa_link.le_next) { 159 if (bus->isa_bus == parent) 160 break; 161 } 162 163 if (bus == NULL) { 164 bus_addr_t iobase; 165 /* 166 * Mark this bus so we don't probe it again. 167 */ 168 bus = (struct lemac_isabus *) 169 malloc(sizeof(struct lemac_isabus), M_DEVBUF, M_NOWAIT); 170 if (bus == NULL) 171 panic("lemac_isa_probe: can't allocate state storage for %s", 172 parent->dv_xname); 173 174 bus->isa_bus = parent; 175 LIST_INSERT_HEAD(&lemac_isa_buses, bus, isa_link); 176 177 for (iobase = LEMAC_IOBASE_LOW; iobase < LEMAC_IOBASE_HIGH; 178 iobase += LEMAC_IOSIZE) { 179 bus_space_handle_t ioh; 180 /* 181 * Map the LEMACs port-space for the probe sequence. 182 */ 183 if (bus_space_map(ia->ia_iot, iobase, LEMAC_IOSIZE, 0, &ioh)) 184 continue; 185 186 /* 187 * Read the Ethernet address from the EEPROM. 188 * It must start with on the DEC OUIs and pass the 189 * DEC ethernet checksum test. 190 */ 191 192 if (lemac_port_check(ia->ia_iot, ioh)) { 193 int irq; 194 bus_addr_t maddr; 195 bus_addr_t msize; 196 bus_space_handle_t memh; 197 198 lemac_info_get(ia->ia_iot, ioh, &maddr, &msize, &irq); 199 if (!bus_space_map(ia->ia_memt, maddr, msize, 0, &memh)) { 200 lemac_isa_card_add(bus, iobase, maddr, msize, irq); 201 bus_space_unmap(ia->ia_memt, memh, msize); 202 } 203 } 204 205 bus_space_unmap(ia->ia_iot, ioh, LEMAC_IOSIZE); 206 } 207 } 208 209 for (idx = 0; idx < MAXCARDS_PER_ISABUS; idx++) { 210 if (bus->isa_cards[idx].available != 1) 211 continue; 212 if (ia->ia_iobase != IOBASEUNK 213 && ia->ia_iobase != bus->isa_cards[idx].iobase) 214 continue; 215 if (ia->ia_maddr != MADDRUNK 216 && ia->ia_maddr != bus->isa_cards[idx].maddr) 217 continue; 218 if (ia->ia_irq != IRQUNK && ia->ia_irq != bus->isa_cards[idx].irq) 219 continue; 220 break; 221 } 222 if (idx == MAXCARDS_PER_ISABUS) 223 return 0; 224 225 bus->isa_cards[idx].available++; 226 ia->ia_iobase = bus->isa_cards[idx].iobase; 227 ia->ia_irq = bus->isa_cards[idx].irq; 228 ia->ia_iosize = LEMAC_IOSIZE; 229 ia->ia_maddr = bus->isa_cards[idx].maddr; 230 ia->ia_msize = bus->isa_cards[idx].msize; 231 return 1; 232} 233 234static void 235lemac_isa_attach( 236 struct device *parent, 237 struct device *self, 238 void *aux) 239{ 240 lemac_softc_t *sc = (void *)self; 241 struct isa_attach_args *ia = aux; 242 243 244 /* Map i/o space. */ 245 sc->sc_iot = ia->ia_iot; 246 if (bus_space_map(sc->sc_iot, ia->ia_iobase, ia->ia_iosize, 0, &sc->sc_ioh)) 247 panic("\n%s: can't map i/o space 0x%x-0x%x\n", 248 sc->sc_dv.dv_xname, 249 ia->ia_iobase, ia->ia_iobase + ia->ia_iosize - 1); 250 251 if (ia->ia_msize && ia->ia_maddr) { 252 sc->sc_memt = ia->ia_memt; 253 /* Map memory space. */ 254 if (bus_space_map(sc->sc_memt, ia->ia_maddr, ia->ia_msize, 0, &sc->sc_memh)) 255 panic("\n%s: can't map iomem space 0x%x-0x%x\n", 256 sc->sc_dv.dv_xname, 257 ia->ia_maddr, ia->ia_maddr + ia->ia_msize - 1); 258 } 259 260 sc->sc_ats = shutdownhook_establish(lemac_shutdown, sc); 261 if (sc->sc_ats == NULL) 262 printf("\n%s: warning: couldn't establish shutdown hook\n", 263 sc->sc_dv.dv_xname); 264 265 lemac_ifattach(sc); 266 267 sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, 268 IPL_NET, lemac_intr, sc); 269} 270 271struct cfattach lc_isa_ca = { 272 sizeof(lemac_softc_t), lemac_isa_probe, lemac_isa_attach 273}; 274