1 /* $NetBSD: if_ie_vme.c,v 1.24 2024/12/20 23:52:00 tsutsui Exp $ */ 2 3 /*- 4 * Copyright (c) 1996 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Gordon W. Ross. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * Machine-dependent glue for the Intel Ethernet (ie) driver. 34 */ 35 36 #include <sys/cdefs.h> 37 __KERNEL_RCSID(0, "$NetBSD: if_ie_vme.c,v 1.24 2024/12/20 23:52:00 tsutsui Exp $"); 38 39 #include "opt_inet.h" 40 41 #include <sys/param.h> 42 #include <sys/systm.h> 43 #include <sys/device.h> 44 #include <sys/protosw.h> 45 #include <sys/socket.h> 46 #include <net/if.h> 47 #include <net/if_ether.h> 48 49 #ifdef INET 50 #include <netinet/in.h> 51 #include <netinet/in_systm.h> 52 #include <netinet/in_var.h> 53 #include <netinet/ip.h> 54 #include <netinet/if_inarp.h> 55 #endif 56 57 #include <machine/autoconf.h> 58 #include <machine/cpu.h> 59 #include <machine/dvma.h> 60 #include <machine/idprom.h> 61 #include <machine/vmparam.h> 62 63 #include "i82586.h" 64 #include "if_iereg.h" 65 #include "if_ievar.h" 66 67 static void ie_vmereset(struct ie_softc *); 68 static void ie_vmeattend(struct ie_softc *); 69 static void ie_vmerun(struct ie_softc *); 70 71 /* 72 * zero/copy functions: OBIO can use the normal functions, but VME 73 * must do only byte or half-word (16 bit) accesses... 74 */ 75 static void *wmemcpy(void *, const void *, size_t); 76 static void *wmemset(void *, int, size_t); 77 78 79 /* 80 * New-style autoconfig attachment 81 */ 82 83 static int ie_vme_match(device_t, cfdata_t, void *); 84 static void ie_vme_attach(device_t, device_t, void *); 85 86 CFATTACH_DECL_NEW(ie_vme, sizeof(struct ie_softc), 87 ie_vme_match, ie_vme_attach, NULL, NULL); 88 89 static int 90 ie_vme_match(device_t parent, cfdata_t cf, void *args) 91 { 92 struct confargs *ca = args; 93 94 /* No default VME address. */ 95 if (ca->ca_paddr == -1) 96 return 0; 97 98 /* Make sure something is there... */ 99 if (bus_peek(ca->ca_bustype, ca->ca_paddr, 2) == -1) 100 return 0; 101 102 /* Default interrupt priority. */ 103 if (ca->ca_intpri == -1) 104 ca->ca_intpri = 3; 105 106 return 1; 107 } 108 109 /* 110 * *note*: we don't detect the difference between a VME3E and 111 * a multibus/vme card. if you want to use a 3E you'll have 112 * to fix this. 113 */ 114 void 115 ie_vme_attach(device_t parent, device_t self, void *args) 116 { 117 struct ie_softc *sc = device_private(self); 118 struct confargs *ca = args; 119 volatile struct ievme *iev; 120 u_long rampaddr; 121 int lcv, off; 122 123 sc->sc_dev = self; 124 sc->hard_type = IE_VME; 125 sc->reset_586 = ie_vmereset; 126 sc->chan_attn = ie_vmeattend; 127 sc->run_586 = ie_vmerun; 128 sc->sc_memcpy = wmemcpy; 129 sc->sc_memset = wmemset; 130 131 /* 132 * There is 64K of memory on the VME board. 133 * (determined by hardware - NOT configurable!) 134 */ 135 sc->sc_msize = 0x10000; /* MEMSIZE 64K */ 136 137 /* Map in the board control regs. */ 138 sc->sc_reg = bus_mapin(ca->ca_bustype, ca->ca_paddr, 139 sizeof(struct ievme)); 140 iev = (volatile struct ievme *) sc->sc_reg; 141 142 /* 143 * Find and map in the board memory. 144 */ 145 /* top 12 bits */ 146 rampaddr = ca->ca_paddr & 0xfff00000; 147 /* 4 more */ 148 rampaddr |= ((iev->status & IEVME_HADDR) << 16); 149 sc->sc_maddr = bus_mapin(ca->ca_bustype, rampaddr, sc->sc_msize); 150 151 /* 152 * On this hardware, the i82586 address is just 153 * masked to 16 bits, so sc_iobase == sc_maddr 154 */ 155 sc->sc_iobase = sc->sc_maddr; 156 157 /* 158 * Set up on-board mapping registers for linear map. 159 */ 160 iev->pectrl |= IEVME_PARACK; /* clear to start */ 161 for (lcv = 0; lcv < IEVME_MAPSZ; lcv++) 162 iev->pgmap[lcv] = IEVME_SBORDR | IEVME_OBMEM | lcv; 163 (sc->sc_memset)(sc->sc_maddr, 0, sc->sc_msize); 164 165 /* 166 * Set the System Configuration Pointer (SCP). 167 * Its location is system-dependent because the 168 * i82586 reads it from a fixed physical address. 169 * On this hardware, the i82586 address is just 170 * masked down to 16 bits, so the SCP is found 171 * at the end of the RAM on the VME board. 172 */ 173 off = IE_SCP_ADDR & 0xFFFF; 174 sc->scp = (volatile void *)((char *)sc->sc_maddr + off); 175 176 /* 177 * The rest of ram is used for buffers, etc. 178 */ 179 sc->buf_area = sc->sc_maddr; 180 sc->buf_area_sz = off; 181 182 /* Set the ethernet address. */ 183 idprom_etheraddr(sc->sc_addr); 184 185 /* Do machine-independent parts of attach. */ 186 ie_attach(sc); 187 188 /* Install interrupt handler. */ 189 isr_add_vectored(ie_intr, sc, ca->ca_intpri, ca->ca_intvec); 190 } 191 192 193 /* 194 * MULTIBUS/VME support 195 */ 196 197 void 198 ie_vmeattend(struct ie_softc *sc) 199 { 200 volatile struct ievme *iev = (struct ievme *)sc->sc_reg; 201 202 iev->status |= IEVME_ATTEN; /* flag! */ 203 iev->status &= ~IEVME_ATTEN; /* down. */ 204 } 205 206 void 207 ie_vmereset(struct ie_softc *sc) 208 { 209 volatile struct ievme *iev = (struct ievme *)sc->sc_reg; 210 211 iev->status = IEVME_RESET; 212 delay(20); 213 iev->status = (IEVME_ONAIR | IEVME_IENAB | IEVME_PEINT); 214 } 215 216 void 217 ie_vmerun(struct ie_softc *sc) 218 { 219 220 /* do it all in reset */ 221 } 222 223 /* 224 * wmemcpy/wmemset - like memcpy/memset but largest access is 16-bits, 225 * and also does byte swaps... 226 * XXX - Would be nice to have asm versions in some library... 227 */ 228 229 static void * 230 wmemset(void *vb, int val, size_t l) 231 { 232 uint8_t *b = vb; 233 uint8_t *be = b + l; 234 uint16_t *sp; 235 236 if (l == 0) 237 return vb; 238 239 /* front, */ 240 if ((uint32_t)b & 1) 241 *b++ = val; 242 243 /* back, */ 244 if (b != be && ((uint32_t)be & 1) != 0) { 245 be--; 246 *be = val; 247 } 248 249 /* and middle. */ 250 sp = (uint16_t *)b; 251 while (sp != (uint16_t *)be) 252 *sp++ = val; 253 254 return vb; 255 } 256 257 static void * 258 wmemcpy(void *dst, const void *src, size_t l) 259 { 260 const uint8_t *b1e, *b1 = src; 261 uint8_t *b2 = dst; 262 const uint16_t *sp; 263 int bstore = 0; 264 265 if (l == 0) 266 return dst; 267 268 /* front, */ 269 if ((uint32_t)b1 & 1) { 270 *b2++ = *b1++; 271 l--; 272 } 273 274 /* middle, */ 275 sp = (const uint16_t *)b1; 276 b1e = b1 + l; 277 if (l & 1) 278 b1e--; 279 bstore = (uint32_t)b2 & 1; 280 281 while (sp < (const uint16_t *)b1e) { 282 if (bstore) { 283 b2[1] = *sp & 0xff; 284 b2[0] = *sp >> 8; 285 } else 286 *((uint16_t *)b2) = *sp; 287 sp++; 288 b2 += 2; 289 } 290 291 /* and back. */ 292 if (l & 1) 293 *b2 = *b1e; 294 295 return dst; 296 } 297