1 1.47 msaitoh /* $NetBSD: if_ep_isa.c,v 1.47 2019/12/27 04:50:41 msaitoh Exp $ */ 2 1.16 thorpej 3 1.16 thorpej /*- 4 1.16 thorpej * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc. 5 1.16 thorpej * All rights reserved. 6 1.16 thorpej * 7 1.16 thorpej * This code is derived from software contributed to The NetBSD Foundation 8 1.16 thorpej * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 9 1.16 thorpej * NASA Ames Research Center. 10 1.16 thorpej * 11 1.16 thorpej * Redistribution and use in source and binary forms, with or without 12 1.16 thorpej * modification, are permitted provided that the following conditions 13 1.16 thorpej * are met: 14 1.16 thorpej * 1. Redistributions of source code must retain the above copyright 15 1.16 thorpej * notice, this list of conditions and the following disclaimer. 16 1.16 thorpej * 2. Redistributions in binary form must reproduce the above copyright 17 1.16 thorpej * notice, this list of conditions and the following disclaimer in the 18 1.16 thorpej * documentation and/or other materials provided with the distribution. 19 1.16 thorpej * 20 1.16 thorpej * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 1.16 thorpej * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 1.16 thorpej * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 1.16 thorpej * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 1.16 thorpej * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 1.16 thorpej * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 1.16 thorpej * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 1.16 thorpej * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 1.16 thorpej * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 1.16 thorpej * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 1.16 thorpej * POSSIBILITY OF SUCH DAMAGE. 31 1.16 thorpej */ 32 1.1 thorpej 33 1.1 thorpej /* 34 1.11 jonathan * Copyright (c) 1997 Jonathan Stone <jonathan (at) NetBSD.org> 35 1.4 thorpej * Copyright (c) 1994 Herb Peyerl <hpeyerl (at) beer.org> 36 1.1 thorpej * All rights reserved. 37 1.1 thorpej * 38 1.1 thorpej * Redistribution and use in source and binary forms, with or without 39 1.1 thorpej * modification, are permitted provided that the following conditions 40 1.1 thorpej * are met: 41 1.1 thorpej * 1. Redistributions of source code must retain the above copyright 42 1.1 thorpej * notice, this list of conditions and the following disclaimer. 43 1.1 thorpej * 2. Redistributions in binary form must reproduce the above copyright 44 1.1 thorpej * notice, this list of conditions and the following disclaimer in the 45 1.1 thorpej * documentation and/or other materials provided with the distribution. 46 1.1 thorpej * 3. All advertising materials mentioning features or use of this software 47 1.1 thorpej * must display the following acknowledgement: 48 1.1 thorpej * This product includes software developed by Herb Peyerl. 49 1.1 thorpej * 4. The name of Herb Peyerl may not be used to endorse or promote products 50 1.1 thorpej * derived from this software without specific prior written permission. 51 1.1 thorpej * 52 1.1 thorpej * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 53 1.1 thorpej * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 54 1.1 thorpej * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 55 1.1 thorpej * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 56 1.1 thorpej * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 57 1.1 thorpej * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 58 1.1 thorpej * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 59 1.1 thorpej * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 60 1.1 thorpej * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 61 1.1 thorpej * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 62 1.1 thorpej */ 63 1.29 lukem 64 1.29 lukem #include <sys/cdefs.h> 65 1.47 msaitoh __KERNEL_RCSID(0, "$NetBSD: if_ep_isa.c,v 1.47 2019/12/27 04:50:41 msaitoh Exp $"); 66 1.1 thorpej 67 1.1 thorpej #include <sys/param.h> 68 1.3 christos #include <sys/systm.h> 69 1.1 thorpej #include <sys/mbuf.h> 70 1.1 thorpej #include <sys/socket.h> 71 1.1 thorpej #include <sys/ioctl.h> 72 1.1 thorpej #include <sys/errno.h> 73 1.1 thorpej #include <sys/syslog.h> 74 1.1 thorpej #include <sys/select.h> 75 1.1 thorpej #include <sys/device.h> 76 1.2 thorpej #include <sys/queue.h> 77 1.1 thorpej 78 1.1 thorpej #include <net/if.h> 79 1.1 thorpej #include <net/if_dl.h> 80 1.11 jonathan #include <net/if_ether.h> 81 1.11 jonathan #include <net/if_media.h> 82 1.1 thorpej 83 1.41 ad #include <sys/cpu.h> 84 1.41 ad #include <sys/bus.h> 85 1.41 ad #include <sys/intr.h> 86 1.1 thorpej 87 1.23 thorpej #include <dev/mii/miivar.h> 88 1.23 thorpej 89 1.1 thorpej #include <dev/ic/elink3var.h> 90 1.1 thorpej #include <dev/ic/elink3reg.h> 91 1.1 thorpej 92 1.1 thorpej #include <dev/isa/isavar.h> 93 1.1 thorpej #include <dev/isa/elink.h> 94 1.1 thorpej 95 1.43 christos int ep_isa_probe(device_t , cfdata_t , void *); 96 1.43 christos void ep_isa_attach(device_t , device_t , void *); 97 1.1 thorpej 98 1.43 christos CFATTACH_DECL_NEW(ep_isa, sizeof(struct ep_softc), 99 1.33 thorpej ep_isa_probe, ep_isa_attach, NULL, NULL); 100 1.1 thorpej 101 1.35 perry static void epaddcard(int, int, int, int); 102 1.1 thorpej 103 1.2 thorpej /* 104 1.2 thorpej * This keeps track of which ISAs have been through an ep probe sequence. 105 1.2 thorpej * A simple static variable isn't enough, since it's conceivable that 106 1.2 thorpej * a system might have more than one ISA bus. 107 1.2 thorpej * 108 1.2 thorpej * The "er_bus" member is the unit number of the parent ISA bus, e.g. "0" 109 1.2 thorpej * for "isa0". 110 1.2 thorpej */ 111 1.2 thorpej struct ep_isa_done_probe { 112 1.2 thorpej LIST_ENTRY(ep_isa_done_probe) er_link; 113 1.2 thorpej int er_bus; 114 1.2 thorpej }; 115 1.2 thorpej static LIST_HEAD(, ep_isa_done_probe) ep_isa_all_probes; 116 1.2 thorpej static int ep_isa_probes_initialized; 117 1.2 thorpej 118 1.2 thorpej #define MAXEPCARDS 20 /* if you have more than 20, you lose */ 119 1.1 thorpej 120 1.1 thorpej static struct epcard { 121 1.2 thorpej int bus; 122 1.1 thorpej int iobase; 123 1.1 thorpej int irq; 124 1.1 thorpej char available; 125 1.14 mjacob long model; 126 1.1 thorpej } epcards[MAXEPCARDS]; 127 1.1 thorpej static int nepcards; 128 1.1 thorpej 129 1.1 thorpej static void 130 1.44 dsl epaddcard(int bus, int iobase, int irq, int model) 131 1.1 thorpej { 132 1.1 thorpej 133 1.1 thorpej if (nepcards >= MAXEPCARDS) 134 1.1 thorpej return; 135 1.2 thorpej epcards[nepcards].bus = bus; 136 1.1 thorpej epcards[nepcards].iobase = iobase; 137 1.1 thorpej epcards[nepcards].irq = (irq == 2) ? 9 : irq; 138 1.13 veego epcards[nepcards].model = model; 139 1.1 thorpej epcards[nepcards].available = 1; 140 1.1 thorpej nepcards++; 141 1.1 thorpej } 142 1.1 thorpej 143 1.1 thorpej /* 144 1.1 thorpej * 3c509 cards on the ISA bus are probed in ethernet address order. 145 1.1 thorpej * The probe sequence requires careful orchestration, and we'd like 146 1.47 msaitoh * to allow the irq and base address to be wildcarded. So, we 147 1.1 thorpej * probe all the cards the first time epprobe() is called. On subsequent 148 1.1 thorpej * calls we look for matching cards. 149 1.1 thorpej */ 150 1.1 thorpej int 151 1.43 christos ep_isa_probe(device_t parent, cfdata_t match, void *aux) 152 1.1 thorpej { 153 1.1 thorpej struct isa_attach_args *ia = aux; 154 1.8 thorpej bus_space_tag_t iot = ia->ia_iot; 155 1.26 jonathan bus_space_handle_t ioh; 156 1.1 thorpej int slot, iobase, irq, i; 157 1.36 christos u_int16_t vendor, model, eeprom_addr_cfg; 158 1.2 thorpej struct ep_isa_done_probe *er; 159 1.38 thorpej int bus = device_unit(parent); 160 1.2 thorpej 161 1.30 thorpej if (ISA_DIRECT_CONFIG(ia)) 162 1.30 thorpej return (0); 163 1.30 thorpej 164 1.2 thorpej if (ep_isa_probes_initialized == 0) { 165 1.2 thorpej LIST_INIT(&ep_isa_all_probes); 166 1.2 thorpej ep_isa_probes_initialized = 1; 167 1.2 thorpej } 168 1.2 thorpej 169 1.2 thorpej /* 170 1.2 thorpej * Probe this bus if we haven't done so already. 171 1.2 thorpej */ 172 1.2 thorpej for (er = ep_isa_all_probes.lh_first; er != NULL; 173 1.2 thorpej er = er->er_link.le_next) 174 1.38 thorpej if (er->er_bus == device_unit(parent)) 175 1.2 thorpej goto bus_probed; 176 1.2 thorpej 177 1.2 thorpej /* 178 1.2 thorpej * Mark this bus so we don't probe it again. 179 1.2 thorpej */ 180 1.46 chs er = malloc(sizeof(struct ep_isa_done_probe), M_DEVBUF, M_WAITOK); 181 1.2 thorpej er->er_bus = bus; 182 1.2 thorpej LIST_INSERT_HEAD(&ep_isa_all_probes, er, er_link); 183 1.2 thorpej 184 1.2 thorpej /* 185 1.2 thorpej * Map the Etherlink ID port for the probe sequence. 186 1.2 thorpej */ 187 1.8 thorpej if (bus_space_map(iot, ELINK_ID_PORT, 1, 0, &ioh)) { 188 1.7 christos printf("ep_isa_probe: can't map Etherlink ID port\n"); 189 1.3 christos return 0; 190 1.2 thorpej } 191 1.2 thorpej 192 1.2 thorpej for (slot = 0; slot < MAXEPCARDS; slot++) { 193 1.38 thorpej elink_reset(iot, ioh, device_unit(parent)); 194 1.8 thorpej elink_idseq(iot, ioh, ELINK_509_POLY); 195 1.2 thorpej 196 1.2 thorpej /* Untag all the adapters so they will talk to us. */ 197 1.2 thorpej if (slot == 0) 198 1.8 thorpej bus_space_write_1(iot, ioh, 0, TAG_ADAPTER + 0); 199 1.1 thorpej 200 1.28 tsutsui vendor = bswap16(epreadeeprom(iot, ioh, EEPROM_MFG_ID)); 201 1.2 thorpej if (vendor != MFG_ID) 202 1.2 thorpej continue; 203 1.1 thorpej 204 1.28 tsutsui model = bswap16(epreadeeprom(iot, ioh, EEPROM_PROD_ID)); 205 1.13 veego /* 206 1.13 veego * XXX: Add a new product id to check for other cards 207 1.13 veego * (3c515?) and fix the check in ep_isa_attach. 208 1.13 veego */ 209 1.13 veego if ((model & 0xfff0) != PROD_ID_3C509) { 210 1.1 thorpej #ifndef trusted 211 1.7 christos printf( 212 1.2 thorpej "ep_isa_probe: ignoring model %04x\n", model); 213 1.1 thorpej #endif 214 1.2 thorpej continue; 215 1.1 thorpej } 216 1.1 thorpej 217 1.36 christos eeprom_addr_cfg = epreadeeprom(iot, ioh, EEPROM_ADDR_CFG); 218 1.36 christos iobase = (eeprom_addr_cfg & 0x1f) * 0x10 + 0x200; 219 1.1 thorpej 220 1.8 thorpej irq = epreadeeprom(iot, ioh, EEPROM_RESOURCE_CFG); 221 1.2 thorpej irq >>= 12; 222 1.2 thorpej 223 1.26 jonathan /* XXX Should ignore card if non-ISA(EISA) io address? -chb */ 224 1.2 thorpej 225 1.2 thorpej /* 226 1.13 veego * Don't attach a 3c509 in PnP mode. 227 1.26 jonathan * PnP mode was added with the 3C509B. 228 1.26 jonathan * Check some EEPROM registers to make sure this is really 229 1.26 jonathan * a 3C509B and test whether it is in PnP mode. 230 1.13 veego */ 231 1.13 veego if ((model & 0xfff0) == PROD_ID_3C509) { 232 1.26 jonathan u_int16_t cksum, eepromrev, eeprom_cap, eeprom_hi; 233 1.26 jonathan 234 1.26 jonathan 235 1.26 jonathan /* 236 1.26 jonathan * Fetch all the info we need to ascertain whether 237 1.26 jonathan * the card is PnP capable and in PnP mode. 238 1.26 jonathan * Skip over PnP cards. 239 1.26 jonathan */ 240 1.26 jonathan 241 1.26 jonathan /* secondary configurable data checksum */ 242 1.26 jonathan cksum = epreadeeprom(iot, ioh, EEPROM_CHECKSUM_EL3) 243 1.26 jonathan & 0xFF; 244 1.26 jonathan for (i = EEPROM_CONFIG_HIGH; 245 1.26 jonathan i < EEPROM_CHECKSUM_EL3; i++) { 246 1.26 jonathan cksum ^= epreadeeprom(iot, ioh, i); 247 1.26 jonathan } 248 1.26 jonathan cksum = (cksum & 0xFF) ^ ((cksum >> 8) & 0xFF); 249 1.26 jonathan 250 1.26 jonathan eepromrev = epreadeeprom(iot, ioh, EEPROM_SSI); 251 1.26 jonathan eeprom_hi = epreadeeprom(iot, ioh, EEPROM_CONFIG_HIGH); 252 1.26 jonathan eeprom_cap = epreadeeprom(iot, ioh, EEPROM_CAP); 253 1.26 jonathan 254 1.26 jonathan /* 255 1.26 jonathan * Stop card responding to contention in future. 256 1.26 jonathan * (NB: stops rsponse to all reads from ID port.) 257 1.26 jonathan */ 258 1.26 jonathan bus_space_write_1(iot, ioh, 0, TAG_ADAPTER + 1); 259 1.26 jonathan 260 1.26 jonathan if (cksum != 0) { 261 1.26 jonathan #if 0 262 1.26 jonathan printf("ep_isa_probe: cksum mismatch 0x%02x\n", 263 1.26 jonathan (int)cksum); 264 1.26 jonathan #endif 265 1.26 jonathan } 266 1.26 jonathan else if ((eepromrev & 0xF) < 1) { 267 1.26 jonathan /* 3C509B is adapter revision level 1. */ 268 1.26 jonathan #if 0 269 1.36 christos printf("ep_isa_probe: revision level 0\n"); 270 1.26 jonathan #endif 271 1.26 jonathan } 272 1.26 jonathan else if (eeprom_cap != 0x2083) { 273 1.26 jonathan #if 0 274 1.26 jonathan printf("ep_isa_probe: capabilities word mismatch0x%03x\n", 275 1.26 jonathan (int)epreadeeprom(iot, ioh, EEPROM_CAP)); 276 1.26 jonathan #endif 277 1.25 jonathan } 278 1.26 jonathan else 279 1.26 jonathan /* 280 1.26 jonathan * we have a 3c509B with PnP capabilities. 281 1.36 christos * Test partly documented bits which toggle when 282 1.36 christos * in PnP mode. 283 1.26 jonathan */ 284 1.36 christos if ((eeprom_hi & 0x8) != 0 || ((eeprom_hi & 0xc) == 0 && 285 1.36 christos (eeprom_addr_cfg & 0x80) != 0)) { 286 1.26 jonathan printf("3COM 3C509B Ethernet card in PnP mode\n"); 287 1.13 veego continue; 288 1.13 veego } 289 1.13 veego } 290 1.25 jonathan 291 1.25 jonathan /* 292 1.25 jonathan * XXX: this should probably not be done here 293 1.25 jonathan * because it enables the drq/irq lines from 294 1.25 jonathan * the board. Perhaps it should be done after 295 1.25 jonathan * we have checked for irq/drq collisions? 296 1.26 jonathan * 297 1.26 jonathan * According to the 3COM docs, this does not enable 298 1.26 jonathan * the irq lines. -chb 299 1.25 jonathan */ 300 1.25 jonathan bus_space_write_1(iot, ioh, 0, ACTIVATE_ADAPTER_TO_CONFIG); 301 1.25 jonathan 302 1.13 veego epaddcard(bus, iobase, irq, model); 303 1.1 thorpej } 304 1.2 thorpej /* XXX should we sort by ethernet address? */ 305 1.2 thorpej 306 1.8 thorpej bus_space_unmap(iot, ioh, 1); 307 1.2 thorpej 308 1.13 veego bus_probed: 309 1.1 thorpej 310 1.30 thorpej if (ia->ia_nio < 1) 311 1.30 thorpej return (0); 312 1.30 thorpej if (ia->ia_nirq < 1) 313 1.30 thorpej return (0); 314 1.30 thorpej 315 1.1 thorpej for (i = 0; i < nepcards; i++) { 316 1.2 thorpej if (epcards[i].bus != bus) 317 1.2 thorpej continue; 318 1.1 thorpej if (epcards[i].available == 0) 319 1.1 thorpej continue; 320 1.30 thorpej 321 1.34 drochner if (ia->ia_io[0].ir_addr != ISA_UNKNOWN_PORT && 322 1.30 thorpej ia->ia_io[0].ir_addr != epcards[i].iobase) 323 1.1 thorpej continue; 324 1.30 thorpej 325 1.34 drochner if (ia->ia_irq[0].ir_irq != ISA_UNKNOWN_IRQ && 326 1.30 thorpej ia->ia_irq[0].ir_irq != epcards[i].irq) 327 1.1 thorpej continue; 328 1.30 thorpej 329 1.1 thorpej goto good; 330 1.1 thorpej } 331 1.1 thorpej return 0; 332 1.1 thorpej 333 1.1 thorpej good: 334 1.1 thorpej epcards[i].available = 0; 335 1.30 thorpej 336 1.30 thorpej ia->ia_nio = 1; 337 1.30 thorpej ia->ia_io[0].ir_addr = epcards[i].iobase; 338 1.30 thorpej ia->ia_io[0].ir_size = 0x10; 339 1.30 thorpej 340 1.30 thorpej ia->ia_nirq = 1; 341 1.30 thorpej ia->ia_irq[0].ir_irq = epcards[i].irq; 342 1.30 thorpej 343 1.30 thorpej ia->ia_niomem = 0; 344 1.30 thorpej ia->ia_ndrq = 0; 345 1.30 thorpej 346 1.13 veego ia->ia_aux = (void *)epcards[i].model; 347 1.1 thorpej return 1; 348 1.1 thorpej } 349 1.1 thorpej 350 1.1 thorpej void 351 1.43 christos ep_isa_attach(device_t parent, device_t self, void *aux) 352 1.1 thorpej { 353 1.43 christos struct ep_softc *sc = device_private(self); 354 1.1 thorpej struct isa_attach_args *ia = aux; 355 1.8 thorpej bus_space_tag_t iot = ia->ia_iot; 356 1.8 thorpej bus_space_handle_t ioh; 357 1.13 veego int chipset; 358 1.1 thorpej 359 1.2 thorpej /* Map i/o space. */ 360 1.30 thorpej if (bus_space_map(iot, ia->ia_io[0].ir_addr, 0x10, 0, &ioh)) { 361 1.45 msaitoh aprint_error(": can't map i/o space\n"); 362 1.19 thorpej return; 363 1.19 thorpej } 364 1.2 thorpej 365 1.43 christos sc->sc_dev = self; 366 1.8 thorpej sc->sc_iot = iot; 367 1.2 thorpej sc->sc_ioh = ioh; 368 1.24 fvdl sc->bustype = ELINK_BUS_ISA; 369 1.1 thorpej 370 1.17 thorpej sc->enable = NULL; 371 1.17 thorpej sc->disable = NULL; 372 1.17 thorpej sc->enabled = 1; 373 1.17 thorpej 374 1.14 mjacob chipset = (int)(long)ia->ia_aux; 375 1.13 veego if ((chipset & 0xfff0) == PROD_ID_3C509) { 376 1.45 msaitoh aprint_normal(": 3Com 3C509 Ethernet\n"); 377 1.24 fvdl epconfig(sc, ELINK_CHIPSET_3C509, NULL); 378 1.13 veego } else { 379 1.13 veego /* 380 1.13 veego * XXX: Maybe a 3c515, but the check in ep_isa_probe looks 381 1.13 veego * at the moment only for a 3c509. 382 1.13 veego */ 383 1.45 msaitoh aprint_error(": unknown 3Com Ethernet card: %04x\n", chipset); 384 1.23 thorpej return; 385 1.13 veego } 386 1.1 thorpej 387 1.30 thorpej sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq[0].ir_irq, 388 1.30 thorpej IST_EDGE, IPL_NET, epintr, sc); 389 1.1 thorpej } 390