1 /* $NetBSD: if_ep_isa.c,v 1.8 1996/10/21 22:40:56 thorpej Exp $ */ 2 3 /* 4 * Copyright (c) 1996 Jason R. Thorpe <thorpej@beer.org> 5 * Copyright (c) 1994 Herb Peyerl <hpeyerl@beer.org> 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by Herb Peyerl. 19 * 4. The name of Herb Peyerl may not be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include "bpfilter.h" 35 36 #include <sys/param.h> 37 #include <sys/systm.h> 38 #include <sys/mbuf.h> 39 #include <sys/socket.h> 40 #include <sys/ioctl.h> 41 #include <sys/errno.h> 42 #include <sys/syslog.h> 43 #include <sys/select.h> 44 #include <sys/device.h> 45 #include <sys/queue.h> 46 47 #include <net/if.h> 48 #include <net/if_dl.h> 49 #include <net/if_types.h> 50 #include <net/netisr.h> 51 52 #ifdef INET 53 #include <netinet/in.h> 54 #include <netinet/in_systm.h> 55 #include <netinet/in_var.h> 56 #include <netinet/ip.h> 57 #include <netinet/if_ether.h> 58 #endif 59 60 #ifdef NS 61 #include <netns/ns.h> 62 #include <netns/ns_if.h> 63 #endif 64 65 #if NBPFILTER > 0 66 #include <net/bpf.h> 67 #include <net/bpfdesc.h> 68 #endif 69 70 #include <machine/cpu.h> 71 #include <machine/bus.h> 72 #include <machine/intr.h> 73 74 #include <dev/ic/elink3var.h> 75 #include <dev/ic/elink3reg.h> 76 77 #include <dev/isa/isavar.h> 78 #include <dev/isa/elink.h> 79 80 int ep_isa_probe __P((struct device *, void *, void *)); 81 void ep_isa_attach __P((struct device *, struct device *, void *)); 82 83 struct cfattach ep_isa_ca = { 84 sizeof(struct ep_softc), ep_isa_probe, ep_isa_attach 85 }; 86 87 static void epaddcard __P((int, int, int)); 88 89 /* 90 * This keeps track of which ISAs have been through an ep probe sequence. 91 * A simple static variable isn't enough, since it's conceivable that 92 * a system might have more than one ISA bus. 93 * 94 * The "er_bus" member is the unit number of the parent ISA bus, e.g. "0" 95 * for "isa0". 96 */ 97 struct ep_isa_done_probe { 98 LIST_ENTRY(ep_isa_done_probe) er_link; 99 int er_bus; 100 }; 101 static LIST_HEAD(, ep_isa_done_probe) ep_isa_all_probes; 102 static int ep_isa_probes_initialized; 103 104 #define MAXEPCARDS 20 /* if you have more than 20, you lose */ 105 106 static struct epcard { 107 int bus; 108 int iobase; 109 int irq; 110 char available; 111 } epcards[MAXEPCARDS]; 112 static int nepcards; 113 114 static void 115 epaddcard(bus, iobase, irq) 116 int bus, iobase, irq; 117 { 118 119 if (nepcards >= MAXEPCARDS) 120 return; 121 epcards[nepcards].bus = bus; 122 epcards[nepcards].iobase = iobase; 123 epcards[nepcards].irq = (irq == 2) ? 9 : irq; 124 epcards[nepcards].available = 1; 125 nepcards++; 126 } 127 128 /* 129 * 3c509 cards on the ISA bus are probed in ethernet address order. 130 * The probe sequence requires careful orchestration, and we'd like 131 * like to allow the irq and base address to be wildcarded. So, we 132 * probe all the cards the first time epprobe() is called. On subsequent 133 * calls we look for matching cards. 134 */ 135 int 136 ep_isa_probe(parent, match, aux) 137 struct device *parent; 138 void *match, *aux; 139 { 140 struct isa_attach_args *ia = aux; 141 bus_space_tag_t iot = ia->ia_iot; 142 bus_space_handle_t ioh; 143 int slot, iobase, irq, i; 144 u_int16_t vendor, model; 145 struct ep_isa_done_probe *er; 146 int bus = parent->dv_unit; 147 148 if (ep_isa_probes_initialized == 0) { 149 LIST_INIT(&ep_isa_all_probes); 150 ep_isa_probes_initialized = 1; 151 } 152 153 /* 154 * Probe this bus if we haven't done so already. 155 */ 156 for (er = ep_isa_all_probes.lh_first; er != NULL; 157 er = er->er_link.le_next) 158 if (er->er_bus == parent->dv_unit) 159 goto bus_probed; 160 161 /* 162 * Mark this bus so we don't probe it again. 163 */ 164 er = (struct ep_isa_done_probe *) 165 malloc(sizeof(struct ep_isa_done_probe), M_DEVBUF, M_NOWAIT); 166 if (er == NULL) 167 panic("ep_isa_probe: can't allocate state storage"); 168 169 er->er_bus = bus; 170 LIST_INSERT_HEAD(&ep_isa_all_probes, er, er_link); 171 172 /* 173 * Map the Etherlink ID port for the probe sequence. 174 */ 175 if (bus_space_map(iot, ELINK_ID_PORT, 1, 0, &ioh)) { 176 printf("ep_isa_probe: can't map Etherlink ID port\n"); 177 return 0; 178 } 179 180 for (slot = 0; slot < MAXEPCARDS; slot++) { 181 elink_reset(iot, ioh, parent->dv_unit); 182 elink_idseq(iot, ioh, ELINK_509_POLY); 183 184 /* Untag all the adapters so they will talk to us. */ 185 if (slot == 0) 186 bus_space_write_1(iot, ioh, 0, TAG_ADAPTER + 0); 187 188 vendor = htons(epreadeeprom(iot, ioh, EEPROM_MFG_ID)); 189 if (vendor != MFG_ID) 190 continue; 191 192 model = htons(epreadeeprom(iot, ioh, EEPROM_PROD_ID)); 193 if ((model & 0xfff0) != PROD_ID) { 194 #ifndef trusted 195 printf( 196 "ep_isa_probe: ignoring model %04x\n", model); 197 #endif 198 continue; 199 } 200 201 iobase = epreadeeprom(iot, ioh, EEPROM_ADDR_CFG); 202 iobase = (iobase & 0x1f) * 0x10 + 0x200; 203 204 irq = epreadeeprom(iot, ioh, EEPROM_RESOURCE_CFG); 205 irq >>= 12; 206 epaddcard(bus, iobase, irq); 207 208 /* so card will not respond to contention again */ 209 bus_space_write_1(iot, ioh, 0, TAG_ADAPTER + 1); 210 211 /* 212 * XXX: this should probably not be done here 213 * because it enables the drq/irq lines from 214 * the board. Perhaps it should be done after 215 * we have checked for irq/drq collisions? 216 */ 217 bus_space_write_1(iot, ioh, 0, ACTIVATE_ADAPTER_TO_CONFIG); 218 } 219 /* XXX should we sort by ethernet address? */ 220 221 bus_space_unmap(iot, ioh, 1); 222 223 bus_probed: 224 225 for (i = 0; i < nepcards; i++) { 226 if (epcards[i].bus != bus) 227 continue; 228 if (epcards[i].available == 0) 229 continue; 230 if (ia->ia_iobase != IOBASEUNK && 231 ia->ia_iobase != epcards[i].iobase) 232 continue; 233 if (ia->ia_irq != IRQUNK && 234 ia->ia_irq != epcards[i].irq) 235 continue; 236 goto good; 237 } 238 return 0; 239 240 good: 241 epcards[i].available = 0; 242 ia->ia_iobase = epcards[i].iobase; 243 ia->ia_irq = epcards[i].irq; 244 ia->ia_iosize = 0x10; 245 ia->ia_msize = 0; 246 return 1; 247 } 248 249 void 250 ep_isa_attach(parent, self, aux) 251 struct device *parent, *self; 252 void *aux; 253 { 254 struct ep_softc *sc = (void *)self; 255 struct isa_attach_args *ia = aux; 256 bus_space_tag_t iot = ia->ia_iot; 257 bus_space_handle_t ioh; 258 u_short conn = 0; 259 260 /* Map i/o space. */ 261 if (bus_space_map(iot, ia->ia_iobase, ia->ia_iosize, 0, &ioh)) 262 panic("ep_isa_attach: can't map i/o space"); 263 264 sc->sc_iot = iot; 265 sc->sc_ioh = ioh; 266 sc->bustype = EP_BUS_ISA; 267 268 GO_WINDOW(0); 269 conn = bus_space_read_2(iot, ioh, EP_W0_CONFIG_CTRL); 270 271 printf(": 3Com 3C509 Ethernet\n"); 272 273 epconfig(sc, conn); 274 275 sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, 276 IPL_NET, epintr, sc); 277 } 278