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