1 /* $NetBSD: if_le.c,v 1.26 1997/03/27 21:15:13 veego Exp $ */ 2 3 /*- 4 * Copyright (c) 1997 Jason R. Thorpe and Bernd Ernesti. All rights reserved. 5 * Copyright (c) 1995 Charles M. Hannum. All rights reserved. 6 * Copyright (c) 1992, 1993 7 * The Regents of the University of California. All rights reserved. 8 * 9 * This code is derived from software contributed to Berkeley by 10 * Ralph Campbell and Rick Macklem. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. All advertising materials mentioning features or use of this software 21 * must display the following acknowledgement: 22 * This product includes software developed for the NetBSD Project 23 * by Bernd Ernesti and Jason R. Thorpe. 24 * This product includes software developed by the University of 25 * California, Berkeley and its contributors. 26 * 4. Neither the name of the University nor the names of its contributors 27 * may be used to endorse or promote products derived from this software 28 * without specific prior written permission. 29 * 30 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 31 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 32 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 33 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 34 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 35 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 36 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 37 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 38 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 39 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 40 * SUCH DAMAGE. 41 * 42 * @(#)if_le.c 8.2 (Berkeley) 11/16/93 43 */ 44 45 #include "bpfilter.h" 46 47 #include <sys/param.h> 48 #include <sys/systm.h> 49 #include <sys/mbuf.h> 50 #include <sys/syslog.h> 51 #include <sys/socket.h> 52 #include <sys/device.h> 53 54 #include <net/if.h> 55 #include <net/if_ether.h> 56 #include <net/if_media.h> 57 58 #ifdef INET 59 #include <netinet/in.h> 60 #include <netinet/if_inarp.h> 61 #endif 62 63 #include <machine/cpu.h> 64 #include <machine/mtpr.h> 65 66 #include <amiga/amiga/device.h> 67 #include <amiga/amiga/isr.h> 68 69 #include <dev/ic/am7990reg.h> 70 #include <dev/ic/am7990var.h> 71 72 #include <amiga/dev/zbusvar.h> 73 #include <amiga/dev/if_levar.h> 74 75 int le_zbus_match __P((struct device *, struct cfdata *, void *)); 76 void le_zbus_attach __P((struct device *, struct device *, void *)); 77 78 struct cfattach le_zbus_ca = { 79 sizeof(struct le_softc), le_zbus_match, le_zbus_attach 80 }; 81 82 hide void lepcnet_reset __P((struct am7990_softc *)); 83 hide void lewrcsr __P((struct am7990_softc *, u_int16_t, u_int16_t)); 84 hide u_int16_t lerdcsr __P((struct am7990_softc *, u_int16_t)); 85 86 hide u_int16_t ariadne_swapreg __P((u_int16_t)); 87 hide void ariadne_wrcsr __P((struct am7990_softc *, u_int16_t, u_int16_t)); 88 hide u_int16_t ariadne_rdcsr __P((struct am7990_softc *, u_int16_t)); 89 hide void ariadne_wribcr __P((struct am7990_softc *, u_int16_t, u_int16_t)); 90 integrate void ariadne_copytodesc_word __P((struct am7990_softc *, void *, int, int)); 91 integrate void ariadne_copyfromdesc_word __P((struct am7990_softc *, void *, int, int)); 92 integrate void ariadne_copytobuf_word __P((struct am7990_softc *, void *, int, int)); 93 integrate void ariadne_copyfrombuf_word __P((struct am7990_softc *, void *, int, int)); 94 integrate void ariadne_zerobuf_word __P((struct am7990_softc *, int, int)); 95 void ariadne_autoselect __P((struct am7990_softc *, int)); 96 int ariadne_mediachange __P((struct am7990_softc *)); 97 void ariadne_hwinit __P((struct am7990_softc *)); 98 99 /* 100 * Media types supported by the Ariadne. 101 */ 102 int lemedia_ariadne[] = { 103 IFM_ETHER | IFM_10_T, 104 IFM_ETHER | IFM_10_2, 105 IFM_ETHER | IFM_AUTO, 106 }; 107 #define NLEMEDIA_ARIADNE (sizeof(lemedia_ariadne) / sizeof(lemedia_ariadne[0])) 108 109 110 hide u_int16_t 111 ariadne_swapreg(val) 112 u_int16_t val; 113 { 114 115 return (((val & 0xff) << 8 ) | (( val >> 8) & 0xff)); 116 } 117 118 hide void 119 ariadne_wrcsr(sc, port, val) 120 struct am7990_softc *sc; 121 u_int16_t port, val; 122 { 123 struct lereg1 *ler1 = ((struct le_softc *)sc)->sc_r1; 124 125 ler1->ler1_rap = ariadne_swapreg(port); 126 ler1->ler1_rdp = ariadne_swapreg(val); 127 } 128 129 hide u_int16_t 130 ariadne_rdcsr(sc, port) 131 struct am7990_softc *sc; 132 u_int16_t port; 133 { 134 struct lereg1 *ler1 = ((struct le_softc *)sc)->sc_r1; 135 u_int16_t val; 136 137 ler1->ler1_rap = ariadne_swapreg(port); 138 val = ariadne_swapreg(ler1->ler1_rdp); 139 return (val); 140 } 141 142 hide void 143 ariadne_wribcr(sc, port, val) 144 struct am7990_softc *sc; 145 u_int16_t port, val; 146 { 147 struct lereg1 *ler1 = ((struct le_softc *)sc)->sc_r1; 148 149 ler1->ler1_rap = ariadne_swapreg(port); 150 ler1->ler1_idp = ariadne_swapreg(val); 151 } 152 153 hide void 154 lewrcsr(sc, port, val) 155 struct am7990_softc *sc; 156 u_int16_t port, val; 157 { 158 struct lereg1 *ler1 = ((struct le_softc *)sc)->sc_r1; 159 160 ler1->ler1_rap = port; 161 ler1->ler1_rdp = val; 162 } 163 164 hide u_int16_t 165 lerdcsr(sc, port) 166 struct am7990_softc *sc; 167 u_int16_t port; 168 { 169 struct lereg1 *ler1 = ((struct le_softc *)sc)->sc_r1; 170 u_int16_t val; 171 172 ler1->ler1_rap = port; 173 val = ler1->ler1_rdp; 174 return (val); 175 } 176 177 hide void 178 lepcnet_reset(sc) 179 struct am7990_softc *sc; 180 { 181 struct lereg1 *ler1 = ((struct le_softc *)sc)->sc_r1; 182 volatile int dummy; 183 184 dummy = ler1->ler1_reset; /* Reset PCNet-ISA */ 185 } 186 187 void 188 ariadne_autoselect(sc, on) 189 struct am7990_softc *sc; 190 int on; 191 { 192 193 /* 194 * on = 0: autoselect disabled 195 * on = 1: autoselect enabled 196 */ 197 if (on == 0) 198 ariadne_wribcr(sc, LE_BCR_MC, 0x0000); 199 else 200 ariadne_wribcr(sc, LE_BCR_MC, LE_MC_ASEL); 201 } 202 203 int 204 ariadne_mediachange(sc) 205 struct am7990_softc *sc; 206 { 207 struct ifmedia *ifm = &sc->sc_media; 208 209 if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) 210 return (EINVAL); 211 212 /* 213 * Switch to the selected media. If autoselect is 214 * set, switch it on otherwise disable it. We'll 215 * switch to the other media when we detect loss of 216 * carrier. 217 */ 218 switch (IFM_SUBTYPE(ifm->ifm_media)) { 219 case IFM_10_T: 220 sc->sc_initmodemedia = 1; 221 am7990_init(sc); 222 break; 223 224 case IFM_10_2: 225 sc->sc_initmodemedia = 0; 226 am7990_init(sc); 227 break; 228 229 case IFM_AUTO: 230 sc->sc_initmodemedia = 2; 231 ariadne_hwinit(sc); 232 break; 233 234 default: 235 return (EINVAL); 236 } 237 238 return (0); 239 } 240 241 void 242 ariadne_hwinit(sc) 243 struct am7990_softc *sc; 244 { 245 246 /* 247 * Re-program LEDs to match meaning used on the Ariadne board. 248 */ 249 ariadne_wribcr(sc, LE_BCR_LED1, 0x0090); 250 ariadne_wribcr(sc, LE_BCR_LED2, 0x0081); 251 ariadne_wribcr(sc, LE_BCR_LED3, 0x0084); 252 253 /* 254 * Enabel/Disable auto selection 255 */ 256 if (sc->sc_initmodemedia == 2) 257 ariadne_autoselect(sc, 1); 258 else 259 ariadne_autoselect(sc, 0); 260 } 261 262 int 263 le_zbus_match(parent, cfp, aux) 264 struct device *parent; 265 struct cfdata *cfp; 266 void *aux; 267 { 268 struct zbus_args *zap = aux; 269 270 /* Commodore ethernet card */ 271 if (zap->manid == 514 && zap->prodid == 112) 272 return (1); 273 274 /* Ameristar ethernet card */ 275 if (zap->manid == 1053 && zap->prodid == 1) 276 return (1); 277 278 /* Ariadne ethernet card */ 279 if (zap->manid == 2167 && zap->prodid == 201) 280 return (1); 281 282 return (0); 283 } 284 285 void 286 le_zbus_attach(parent, self, aux) 287 struct device *parent, *self; 288 void *aux; 289 { 290 struct le_softc *lesc = (struct le_softc *)self; 291 struct am7990_softc *sc = &lesc->sc_am7990; 292 struct zbus_args *zap = aux; 293 u_long ser; 294 295 /* This has no effect on PCnet-ISA LANCE chips */ 296 sc->sc_conf3 = LE_C3_BSWP; 297 298 /* 299 * Manufacturer decides the 3 first bytes, i.e. ethernet vendor ID. 300 */ 301 switch (zap->manid) { 302 case 514: 303 /* Commodore */ 304 sc->sc_memsize = 32768; 305 sc->sc_enaddr[0] = 0x00; 306 sc->sc_enaddr[1] = 0x80; 307 sc->sc_enaddr[2] = 0x10; 308 lesc->sc_r1 = (struct lereg1 *)(0x4000 + (int)zap->va); 309 sc->sc_mem = (void *)(0x8000 + (int)zap->va); 310 sc->sc_addr = 0x8000; 311 sc->sc_copytodesc = am7990_copytobuf_contig; 312 sc->sc_copyfromdesc = am7990_copyfrombuf_contig; 313 sc->sc_copytobuf = am7990_copytobuf_contig; 314 sc->sc_copyfrombuf = am7990_copyfrombuf_contig; 315 sc->sc_zerobuf = am7990_zerobuf_contig; 316 sc->sc_rdcsr = lerdcsr; 317 sc->sc_wrcsr = lewrcsr; 318 sc->sc_hwreset = NULL; 319 sc->sc_hwinit = NULL; 320 break; 321 322 case 1053: 323 /* Ameristar */ 324 sc->sc_memsize = 32768; 325 sc->sc_enaddr[0] = 0x00; 326 sc->sc_enaddr[1] = 0x00; 327 sc->sc_enaddr[2] = 0x9f; 328 lesc->sc_r1 = (struct lereg1 *)(0x4000 + (int)zap->va); 329 sc->sc_mem = (void *)(0x8000 + (int)zap->va); 330 sc->sc_addr = 0x8000; 331 sc->sc_copytodesc = am7990_copytobuf_contig; 332 sc->sc_copyfromdesc = am7990_copyfrombuf_contig; 333 sc->sc_copytobuf = am7990_copytobuf_contig; 334 sc->sc_copyfrombuf = am7990_copyfrombuf_contig; 335 sc->sc_zerobuf = am7990_zerobuf_contig; 336 sc->sc_rdcsr = lerdcsr; 337 sc->sc_wrcsr = lewrcsr; 338 sc->sc_hwreset = NULL; 339 sc->sc_hwinit = NULL; 340 break; 341 342 case 2167: 343 /* Village Tronic */ 344 sc->sc_memsize = 32768; 345 sc->sc_enaddr[0] = 0x00; 346 sc->sc_enaddr[1] = 0x60; 347 sc->sc_enaddr[2] = 0x30; 348 lesc->sc_r1 = (struct lereg1 *)(0x0370 + (int)zap->va); 349 sc->sc_mem = (void *)(0x8000 + (int)zap->va); 350 sc->sc_addr = 0x8000; 351 sc->sc_copytodesc = ariadne_copytodesc_word; 352 sc->sc_copyfromdesc = ariadne_copyfromdesc_word; 353 sc->sc_copytobuf = ariadne_copytobuf_word; 354 sc->sc_copyfrombuf = ariadne_copyfrombuf_word; 355 sc->sc_zerobuf = ariadne_zerobuf_word; 356 sc->sc_rdcsr = ariadne_rdcsr; 357 sc->sc_wrcsr = ariadne_wrcsr; 358 sc->sc_hwreset = lepcnet_reset; 359 sc->sc_hwinit = ariadne_hwinit; 360 sc->sc_mediachange = ariadne_mediachange; 361 sc->sc_supmedia = lemedia_ariadne; 362 sc->sc_nsupmedia = NLEMEDIA_ARIADNE; 363 sc->sc_defaultmedia = IFM_ETHER | IFM_AUTO; 364 sc->sc_initmodemedia = 2; 365 break; 366 367 default: 368 panic("le_zbus_attach: bad manid"); 369 } 370 371 /* 372 * Serial number for board is used as host ID. 373 */ 374 ser = (u_long)zap->serno; 375 sc->sc_enaddr[3] = (ser >> 16) & 0xff; 376 sc->sc_enaddr[4] = (ser >> 8) & 0xff; 377 sc->sc_enaddr[5] = (ser ) & 0xff; 378 379 am7990_config(sc); 380 381 lesc->sc_isr.isr_intr = am7990_intr; 382 lesc->sc_isr.isr_arg = sc; 383 lesc->sc_isr.isr_ipl = 2; 384 add_isr(&lesc->sc_isr); 385 } 386 387 388 integrate void 389 ariadne_copytodesc_word(sc, from, boff, len) 390 struct am7990_softc *sc; 391 void *from; 392 int boff, len; 393 { 394 u_short *b1 = from; 395 volatile u_short *b2 = sc->sc_mem + boff; 396 397 for (len >>= 1; len > 0; len--) 398 *b2++ = ariadne_swapreg(*b1++); 399 } 400 401 integrate void 402 ariadne_copyfromdesc_word(sc, to, boff, len) 403 struct am7990_softc *sc; 404 void *to; 405 int boff, len; 406 { 407 volatile u_short *b1 = sc->sc_mem + boff; 408 u_short *b2 = to; 409 410 for (len >>= 1; len > 0; len--) 411 *b2++ = ariadne_swapreg(*b1++); 412 } 413 414 #define isodd(n) ((n) & 1) 415 416 integrate void 417 ariadne_copytobuf_word(sc, from, boff, len) 418 struct am7990_softc *sc; 419 void *from; 420 int boff, len; 421 { 422 u_char *a1 = from; 423 volatile u_char *a2 = sc->sc_mem + boff; 424 u_short *b1; 425 volatile u_short *b2; 426 int i; 427 428 if (len > 0 && isodd(boff)) { 429 b1 = (u_short *)(a1 + 1); 430 b2 = (u_short *)(a2 + 1); 431 b2[-1] = (b2[-1] & 0xff00) | (b1[-1] & 0x00ff); 432 --len; 433 } else { 434 b1 = (u_short *)a1; 435 b2 = (u_short *)a2; 436 } 437 438 for (i = len >> 1; i > 0; i--) 439 *b2++ = *b1++; 440 441 if (isodd(len)) 442 *b2 = (*b2 & 0x00ff) | (*b1 & 0xff00); 443 } 444 445 integrate void 446 ariadne_copyfrombuf_word(sc, to, boff, len) 447 struct am7990_softc *sc; 448 void *to; 449 int boff, len; 450 { 451 volatile u_char *a1 = sc->sc_mem + boff; 452 u_char *a2 = to; 453 volatile u_short *b1; 454 u_short *b2; 455 int i; 456 457 if (len > 0 && isodd(boff)) { 458 b1 = (u_short *)(a1 + 1); 459 b2 = (u_short *)(a2 + 1); 460 b2[-1] = (b2[-1] & 0xff00) | (b1[-1] & 0x00ff); 461 --len; 462 } else { 463 b1 = (u_short *)a1; 464 b2 = (u_short *)a2; 465 } 466 467 for (i = len >> 1; i > 0; i--) 468 *b2++ = *b1++; 469 470 if (isodd(len)) 471 *b2 = (*b2 & 0x00ff) | (*b1 & 0xff00); 472 } 473 474 integrate void 475 ariadne_zerobuf_word(sc, boff, len) 476 struct am7990_softc *sc; 477 int boff, len; 478 { 479 volatile u_char *a1 = sc->sc_mem + boff; 480 volatile u_short *b1; 481 int i; 482 483 if (len > 0 && isodd(boff)) { 484 b1 = (u_short *)(a1 + 1); 485 b1[-1] &= 0xff00; 486 --len; 487 } else { 488 b1 = (u_short *)a1; 489 } 490 491 for (i = len >> 1; i > 0; i--) 492 *b1++ = 0; 493 494 if (isodd(len)) 495 *b1 &= 0x00ff; 496 } 497