1 /* $NetBSD: if_tlp_eisa.c,v 1.29 2021/07/24 18:50:07 thorpej Exp $ */ 2 3 /*- 4 * Copyright (c) 1999, 2000 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 9 * NASA Ames Research Center. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* 34 * EISA bus front-end for the Digital Semiconductor ``Tulip'' (21x4x) 35 * Ethernet controller family driver. 36 */ 37 38 #include <sys/cdefs.h> 39 __KERNEL_RCSID(0, "$NetBSD: if_tlp_eisa.c,v 1.29 2021/07/24 18:50:07 thorpej Exp $"); 40 41 #include "opt_inet.h" 42 43 #include <sys/param.h> 44 #include <sys/systm.h> 45 #include <sys/mbuf.h> 46 #include <sys/malloc.h> 47 #include <sys/kernel.h> 48 #include <sys/socket.h> 49 #include <sys/ioctl.h> 50 #include <sys/errno.h> 51 #include <sys/device.h> 52 53 #include <machine/endian.h> 54 55 #include <net/if.h> 56 #include <net/if_dl.h> 57 #include <net/if_media.h> 58 #include <net/if_ether.h> 59 60 #ifdef INET 61 #include <netinet/in.h> 62 #include <netinet/if_inarp.h> 63 #endif 64 65 66 #include <sys/bus.h> 67 #include <sys/intr.h> 68 69 #include <dev/mii/miivar.h> 70 #include <dev/mii/mii_bitbang.h> 71 72 #include <dev/ic/tulipreg.h> 73 #include <dev/ic/tulipvar.h> 74 75 #include <dev/eisa/eisareg.h> 76 #include <dev/eisa/eisavar.h> 77 #include <dev/eisa/eisadevs.h> 78 79 #include <dev/pci/pcireg.h> 80 81 /* 82 * DE425 configuration registers; literal offsets from CSR base. 83 * This is effectively the 21040 PCI configuration space interleaved 84 * into the CSR space (CSRs are space 16 bytes on the DE425). 85 * 86 * What a cool address decoder hack they must have on that board... 87 */ 88 #define DE425_CFID 0x08 /* Configuration ID */ 89 #define DE425_CFCS 0x0c /* Configuration Command-Status */ 90 #define DE425_CFRV 0x18 /* Configuration Revision */ 91 #define DE425_CFLT 0x1c /* Configuration Latency Timer */ 92 #define DE425_CBIO 0x28 /* Configuration Base I/O Address */ 93 #define DE425_CFDA 0x2c /* Configuration Driver Area */ 94 #define DE425_ENETROM 0xc90 /* Offset in I/O space for ENETROM */ 95 #define DE425_CFG0 0xc88 /* IRQ Configuration Register */ 96 97 struct tulip_eisa_softc { 98 struct tulip_softc sc_tulip; /* real Tulip softc */ 99 100 /* EISA-specific goo. */ 101 void *sc_ih; /* interrupt handle */ 102 }; 103 104 static int tlp_eisa_match(device_t, cfdata_t, void *); 105 static void tlp_eisa_attach(device_t, device_t, void *); 106 107 CFATTACH_DECL_NEW(tlp_eisa, sizeof(struct tulip_eisa_softc), 108 tlp_eisa_match, tlp_eisa_attach, NULL, NULL); 109 110 static const int tlp_eisa_irqs[] = { 5, 9, 10, 11 }; 111 112 struct tulip_eisa_product { 113 const char *name; /* device name */ 114 tulip_chip_t chip; /* base Tulip chip type */ 115 }; 116 117 static const struct tulip_eisa_product dec4250 = { 118 .name = "DEC DE425", 119 .chip = TULIP_CHIP_DE425, 120 }; 121 122 static const struct device_compatible_entry compat_data[] = { 123 { .compat = "DEC4250", .data = &dec4250 }, 124 DEVICE_COMPAT_EOL 125 }; 126 127 static int 128 tlp_eisa_match(device_t parent, cfdata_t match, 129 void *aux) 130 { 131 struct eisa_attach_args *ea = aux; 132 133 return (eisa_compatible_match(ea, compat_data)); 134 } 135 136 static void 137 tlp_eisa_attach(device_t parent, device_t self, void *aux) 138 { 139 static const u_int8_t testpat[] = 140 { 0xff, 0, 0x55, 0xaa, 0xff, 0, 0x55, 0xaa }; 141 struct tulip_eisa_softc *esc = device_private(self); 142 struct tulip_softc *sc = &esc->sc_tulip; 143 struct eisa_attach_args *ea = aux; 144 const struct device_compatible_entry *dce; 145 eisa_chipset_tag_t ec = ea->ea_ec; 146 eisa_intr_handle_t ih; 147 bus_space_tag_t iot = ea->ea_iot; 148 bus_space_handle_t ioh; 149 const char *intrstr; 150 const struct tulip_eisa_product *tep; 151 u_int8_t enaddr[ETHER_ADDR_LEN], tmpbuf[sizeof(testpat)]; 152 u_int32_t val; 153 int irq, ist, i, cnt; 154 char intrbuf[EISA_INTRSTR_LEN]; 155 156 /* 157 * Map the device. 158 */ 159 if (bus_space_map(iot, EISA_SLOT_ADDR(ea->ea_slot), 160 EISA_SLOT_SIZE, 0, &ioh)) { 161 aprint_error(": unable to map I/O space\n"); 162 return; 163 } 164 165 sc->sc_dev = self; 166 sc->sc_st = iot; 167 sc->sc_sh = ioh; 168 169 dce = eisa_compatible_lookup(ea, compat_data); 170 KASSERT(dce != NULL); 171 tep = dce->data; 172 173 sc->sc_chip = tep->chip; 174 175 /* 176 * DE425's registers are 16 bytes long; the PCI configuration 177 * space registers are interleaved in the I/O space. 178 */ 179 sc->sc_regshift = 4; 180 181 /* 182 * No power management hooks. 183 */ 184 sc->sc_flags |= TULIPF_ENABLED; 185 186 /* 187 * CBIO must map the EISA slot, and I/O access and Bus Mastering 188 * must be enabled. 189 */ 190 bus_space_write_4(iot, ioh, DE425_CBIO, EISA_SLOT_ADDR(ea->ea_slot)); 191 bus_space_write_4(iot, ioh, DE425_CFCS, 192 bus_space_read_4(iot, ioh, DE425_CFCS) | 193 PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MASTER_ENABLE); 194 195 /* 196 * Get revision info. 197 */ 198 sc->sc_rev = bus_space_read_4(iot, ioh, DE425_CFRV) & 0xff; 199 200 aprint_normal(": %s Ethernet, pass %d.%d\n", 201 tep->name, (sc->sc_rev >> 4) & 0xf, sc->sc_rev & 0xf); 202 203 sc->sc_dmat = ea->ea_dmat; 204 205 /* 206 * EISA doesn't have a cache line register. 207 */ 208 sc->sc_cacheline = 0; 209 210 /* 211 * Find the beginning of the Ethernet Address ROM. 212 */ 213 for (i = 0, cnt = 0; i < sizeof(testpat) && cnt < 32; cnt++) { 214 tmpbuf[i] = bus_space_read_1(iot, ioh, DE425_ENETROM); 215 if (tmpbuf[i] == testpat[i]) 216 i++; 217 else 218 i = 0; 219 } 220 221 /* 222 * ...and now read the contents of the Ethernet Address ROM. 223 */ 224 sc->sc_srom = malloc(32, M_DEVBUF, M_WAITOK|M_ZERO); 225 for (i = 0; i < 32; i++) 226 sc->sc_srom[i] = bus_space_read_1(iot, ioh, DE425_ENETROM); 227 228 /* 229 * None of the DE425 boards have the new-style SROMs. 230 */ 231 if (tlp_parse_old_srom(sc, enaddr) == 0) { 232 aprint_error_dev(self, "unable to decode old-style SROM\n"); 233 return; 234 } 235 236 /* 237 * All DE425 boards use the 21040 media switch. 238 */ 239 sc->sc_mediasw = &tlp_21040_mediasw; 240 241 /* 242 * Figure out which IRQ we want to use, and determine if it's 243 * edge- or level-triggered. 244 */ 245 val = bus_space_read_4(iot, ioh, DE425_CFG0); 246 irq = tlp_eisa_irqs[(val >> 1) & 0x03]; 247 ist = (val & 0x01) ? IST_EDGE : IST_LEVEL; 248 249 /* 250 * Map and establish our interrupt. 251 */ 252 if (eisa_intr_map(ec, irq, &ih)) { 253 aprint_error_dev(self, "unable to map interrupt (%u)\n", irq); 254 return; 255 } 256 intrstr = eisa_intr_string(ec, ih, intrbuf, sizeof(intrbuf)); 257 esc->sc_ih = eisa_intr_establish(ec, ih, ist, IPL_NET, tlp_intr, sc); 258 if (esc->sc_ih == NULL) { 259 aprint_error_dev(self, "unable to establish interrupt"); 260 if (intrstr != NULL) 261 aprint_error(" at %s", intrstr); 262 aprint_error("\n"); 263 return; 264 } 265 if (intrstr != NULL) { 266 aprint_normal_dev(self, "interrupting at %s (%s trigger)\n", 267 ist == IST_EDGE ? "edge" : "level", intrstr); 268 } 269 270 /* 271 * Finish off the attach. 272 */ 273 tlp_attach(sc, enaddr); 274 } 275