1 /* $NetBSD: if_le.c,v 1.36 2002/01/28 09:56:58 aymeric 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 83 #include <sys/cdefs.h> 84 __KERNEL_RCSID(0, "$NetBSD: if_le.c,v 1.36 2002/01/28 09:56:58 aymeric Exp $"); 85 86 #include "bpfilter.h" 87 88 #include <sys/param.h> 89 #include <sys/systm.h> 90 #include <sys/mbuf.h> 91 #include <sys/syslog.h> 92 #include <sys/socket.h> 93 #include <sys/device.h> 94 95 #include <net/if.h> 96 #include <net/if_ether.h> 97 #include <net/if_media.h> 98 99 #ifdef INET 100 #include <netinet/in.h> 101 #include <netinet/if_inarp.h> 102 #endif 103 104 #include <machine/cpu.h> 105 #include <machine/mtpr.h> 106 107 #include <amiga/amiga/device.h> 108 #include <amiga/amiga/isr.h> 109 110 #include <dev/ic/lancereg.h> 111 #include <dev/ic/lancevar.h> 112 #include <dev/ic/am7990reg.h> 113 #include <dev/ic/am7990var.h> 114 115 #include <amiga/dev/zbusvar.h> 116 #include <amiga/dev/if_levar.h> 117 118 int le_zbus_match(struct device *, struct cfdata *, void *); 119 void le_zbus_attach(struct device *, struct device *, void *); 120 121 struct cfattach le_zbus_ca = { 122 sizeof(struct le_softc), le_zbus_match, le_zbus_attach 123 }; 124 125 #if defined(_KERNEL_OPT) 126 #include "opt_ddb.h" 127 #endif 128 129 #ifdef DDB 130 #define integrate 131 #define hide 132 #else 133 #define integrate static __inline 134 #define hide static 135 #endif 136 137 hide void lepcnet_reset(struct lance_softc *); 138 hide void lewrcsr(struct lance_softc *, u_int16_t, u_int16_t); 139 hide u_int16_t lerdcsr(struct lance_softc *, u_int16_t); 140 141 hide u_int16_t ariadne_swapreg(u_int16_t); 142 hide void ariadne_wrcsr(struct lance_softc *, u_int16_t, u_int16_t); 143 hide u_int16_t ariadne_rdcsr(struct lance_softc *, u_int16_t); 144 hide void ariadne_wribcr(struct lance_softc *, u_int16_t, u_int16_t); 145 integrate void ariadne_copytodesc_word(struct lance_softc *, void *, int, int); 146 integrate void ariadne_copyfromdesc_word(struct lance_softc *, void *, 147 int, int); 148 integrate void ariadne_copytobuf_word(struct lance_softc *, void *, int, int); 149 integrate void ariadne_copyfrombuf_word(struct lance_softc *, void *, int, int); 150 integrate void ariadne_zerobuf_word(struct lance_softc *, int, int); 151 void ariadne_autoselect(struct lance_softc *, int); 152 int ariadne_mediachange(struct lance_softc *); 153 void ariadne_hwinit(struct lance_softc *); 154 155 /* 156 * Media types supported by the Ariadne. 157 */ 158 int lemedia_ariadne[] = { 159 IFM_ETHER | IFM_10_T, 160 IFM_ETHER | IFM_10_2, 161 IFM_ETHER | IFM_AUTO, 162 }; 163 #define NLEMEDIA_ARIADNE (sizeof(lemedia_ariadne) / sizeof(lemedia_ariadne[0])) 164 165 166 hide u_int16_t 167 ariadne_swapreg(u_int16_t val) 168 { 169 170 return (((val & 0xff) << 8 ) | (( val >> 8) & 0xff)); 171 } 172 173 hide void 174 ariadne_wrcsr(struct lance_softc *sc, u_int16_t port, u_int16_t val) 175 { 176 struct lereg1 *ler1 = ((struct le_softc *)sc)->sc_r1; 177 178 ler1->ler1_rap = ariadne_swapreg(port); 179 ler1->ler1_rdp = ariadne_swapreg(val); 180 } 181 182 hide u_int16_t 183 ariadne_rdcsr(struct lance_softc *sc, 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(struct lance_softc *sc, u_int16_t port, u_int16_t val) 195 { 196 struct lereg1 *ler1 = ((struct le_softc *)sc)->sc_r1; 197 198 ler1->ler1_rap = ariadne_swapreg(port); 199 ler1->ler1_idp = ariadne_swapreg(val); 200 } 201 202 hide void 203 lewrcsr(struct lance_softc *sc, u_int16_t port, u_int16_t val) 204 { 205 struct lereg1 *ler1 = ((struct le_softc *)sc)->sc_r1; 206 207 ler1->ler1_rap = port; 208 ler1->ler1_rdp = val; 209 } 210 211 hide u_int16_t 212 lerdcsr(struct lance_softc *sc, u_int16_t port) 213 { 214 struct lereg1 *ler1 = ((struct le_softc *)sc)->sc_r1; 215 u_int16_t val; 216 217 ler1->ler1_rap = port; 218 val = ler1->ler1_rdp; 219 return (val); 220 } 221 222 hide void 223 lepcnet_reset(struct lance_softc *sc) 224 { 225 struct lereg1 *ler1 = ((struct le_softc *)sc)->sc_r1; 226 volatile int dummy; 227 228 dummy = ler1->ler1_reset; /* Reset PCNet-ISA */ 229 } 230 231 void 232 ariadne_autoselect(struct lance_softc *sc, int on) 233 { 234 235 /* 236 * on = 0: autoselect disabled 237 * on = 1: autoselect enabled 238 */ 239 if (on == 0) 240 ariadne_wribcr(sc, LE_BCR_MC, 0x0000); 241 else 242 ariadne_wribcr(sc, LE_BCR_MC, LE_MC_ASEL); 243 } 244 245 int 246 ariadne_mediachange(struct lance_softc *sc) 247 { 248 struct ifmedia *ifm = &sc->sc_media; 249 250 if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) 251 return (EINVAL); 252 253 /* 254 * Switch to the selected media. If autoselect is 255 * set, switch it on otherwise disable it. We'll 256 * switch to the other media when we detect loss of 257 * carrier. 258 */ 259 switch (IFM_SUBTYPE(ifm->ifm_media)) { 260 case IFM_10_T: 261 sc->sc_initmodemedia = 1; 262 lance_init(&sc->sc_ethercom.ec_if); 263 break; 264 265 case IFM_10_2: 266 sc->sc_initmodemedia = 0; 267 lance_init(&sc->sc_ethercom.ec_if); 268 break; 269 270 case IFM_AUTO: 271 sc->sc_initmodemedia = 2; 272 ariadne_hwinit(sc); 273 break; 274 275 default: 276 return (EINVAL); 277 } 278 279 return (0); 280 } 281 282 void 283 ariadne_hwinit(struct lance_softc *sc) 284 { 285 286 /* 287 * Re-program LEDs to match meaning used on the Ariadne board. 288 */ 289 ariadne_wribcr(sc, LE_BCR_LED1, 0x0090); 290 ariadne_wribcr(sc, LE_BCR_LED2, 0x0081); 291 ariadne_wribcr(sc, LE_BCR_LED3, 0x0084); 292 293 /* 294 * Enabel/Disable auto selection 295 */ 296 if (sc->sc_initmodemedia == 2) 297 ariadne_autoselect(sc, 1); 298 else 299 ariadne_autoselect(sc, 0); 300 } 301 302 int 303 le_zbus_match(struct device *parent, struct cfdata *cfp, void *aux) 304 { 305 struct zbus_args *zap = aux; 306 307 /* Commodore ethernet card */ 308 if (zap->manid == 514 && zap->prodid == 112) 309 return (1); 310 311 /* Ameristar ethernet card */ 312 if (zap->manid == 1053 && zap->prodid == 1) 313 return (1); 314 315 /* Ariadne ethernet card */ 316 if (zap->manid == 2167 && zap->prodid == 201) 317 return (1); 318 319 return (0); 320 } 321 322 void 323 le_zbus_attach(struct device *parent, struct device *self, void *aux) 324 { 325 struct le_softc *lesc = (struct le_softc *)self; 326 struct lance_softc *sc = &lesc->sc_am7990.lsc; 327 struct zbus_args *zap = aux; 328 u_long ser; 329 330 /* This has no effect on PCnet-ISA LANCE chips */ 331 sc->sc_conf3 = LE_C3_BSWP; 332 333 /* 334 * Manufacturer decides the 3 first bytes, i.e. ethernet vendor ID. 335 */ 336 switch (zap->manid) { 337 case 514: 338 /* Commodore */ 339 sc->sc_memsize = 32768; 340 sc->sc_enaddr[0] = 0x00; 341 sc->sc_enaddr[1] = 0x80; 342 sc->sc_enaddr[2] = 0x10; 343 lesc->sc_r1 = (struct lereg1 *)(0x4000 + (int)zap->va); 344 sc->sc_mem = (void *)(0x8000 + (int)zap->va); 345 sc->sc_addr = 0x8000; 346 sc->sc_copytodesc = lance_copytobuf_contig; 347 sc->sc_copyfromdesc = lance_copyfrombuf_contig; 348 sc->sc_copytobuf = lance_copytobuf_contig; 349 sc->sc_copyfrombuf = lance_copyfrombuf_contig; 350 sc->sc_zerobuf = lance_zerobuf_contig; 351 sc->sc_rdcsr = lerdcsr; 352 sc->sc_wrcsr = lewrcsr; 353 sc->sc_hwreset = NULL; 354 sc->sc_hwinit = NULL; 355 break; 356 357 case 1053: 358 /* Ameristar */ 359 sc->sc_memsize = 32768; 360 sc->sc_enaddr[0] = 0x00; 361 sc->sc_enaddr[1] = 0x00; 362 sc->sc_enaddr[2] = 0x9f; 363 lesc->sc_r1 = (struct lereg1 *)(0x4000 + (int)zap->va); 364 sc->sc_mem = (void *)(0x8000 + (int)zap->va); 365 sc->sc_addr = 0x8000; 366 sc->sc_copytodesc = lance_copytobuf_contig; 367 sc->sc_copyfromdesc = lance_copyfrombuf_contig; 368 sc->sc_copytobuf = lance_copytobuf_contig; 369 sc->sc_copyfrombuf = lance_copyfrombuf_contig; 370 sc->sc_zerobuf = lance_zerobuf_contig; 371 sc->sc_rdcsr = lerdcsr; 372 sc->sc_wrcsr = lewrcsr; 373 sc->sc_hwreset = NULL; 374 sc->sc_hwinit = NULL; 375 break; 376 377 case 2167: 378 /* Village Tronic */ 379 sc->sc_memsize = 32768; 380 sc->sc_enaddr[0] = 0x00; 381 sc->sc_enaddr[1] = 0x60; 382 sc->sc_enaddr[2] = 0x30; 383 lesc->sc_r1 = (struct lereg1 *)(0x0370 + (int)zap->va); 384 sc->sc_mem = (void *)(0x8000 + (int)zap->va); 385 sc->sc_addr = 0x8000; 386 sc->sc_copytodesc = ariadne_copytodesc_word; 387 sc->sc_copyfromdesc = ariadne_copyfromdesc_word; 388 sc->sc_copytobuf = ariadne_copytobuf_word; 389 sc->sc_copyfrombuf = ariadne_copyfrombuf_word; 390 sc->sc_zerobuf = ariadne_zerobuf_word; 391 sc->sc_rdcsr = ariadne_rdcsr; 392 sc->sc_wrcsr = ariadne_wrcsr; 393 sc->sc_hwreset = lepcnet_reset; 394 sc->sc_hwinit = ariadne_hwinit; 395 sc->sc_mediachange = ariadne_mediachange; 396 sc->sc_supmedia = lemedia_ariadne; 397 sc->sc_nsupmedia = NLEMEDIA_ARIADNE; 398 sc->sc_defaultmedia = IFM_ETHER | IFM_AUTO; 399 sc->sc_initmodemedia = 2; 400 break; 401 402 default: 403 panic("le_zbus_attach: bad manid"); 404 } 405 406 /* 407 * Serial number for board is used as host ID. 408 */ 409 ser = (u_long)zap->serno; 410 sc->sc_enaddr[3] = (ser >> 16) & 0xff; 411 sc->sc_enaddr[4] = (ser >> 8) & 0xff; 412 sc->sc_enaddr[5] = (ser ) & 0xff; 413 414 am7990_config(&lesc->sc_am7990); 415 416 lesc->sc_isr.isr_intr = am7990_intr; 417 lesc->sc_isr.isr_arg = sc; 418 lesc->sc_isr.isr_ipl = 2; 419 add_isr(&lesc->sc_isr); 420 } 421 422 423 integrate void 424 ariadne_copytodesc_word(struct lance_softc *sc, void *from, int boff, int len) 425 { 426 u_short *b1 = from; 427 volatile u_short *b2 = (u_short *)((u_char *)sc->sc_mem + boff); 428 429 for (len >>= 1; len > 0; len--) 430 *b2++ = ariadne_swapreg(*b1++); 431 } 432 433 integrate void 434 ariadne_copyfromdesc_word(struct lance_softc *sc, void *to, int boff, int len) 435 { 436 volatile u_short *b1 = (u_short *)((u_char *)sc->sc_mem + boff); 437 u_short *b2 = to; 438 439 for (len >>= 1; len > 0; len--) 440 *b2++ = ariadne_swapreg(*b1++); 441 } 442 443 #define isodd(n) ((n) & 1) 444 445 integrate void 446 ariadne_copytobuf_word(struct lance_softc *sc, void *from, int boff, int len) 447 { 448 u_char *a1 = from; 449 volatile u_char *a2 = (u_char *)sc->sc_mem + boff; 450 u_short *b1; 451 volatile u_short *b2; 452 int i; 453 454 if (len > 0 && isodd(boff)) { 455 /* adjust source pointer */ 456 b1 = (u_short *)(a1 + 1); 457 /* compute aligned destination pointer */ 458 b2 = (u_short *)(a2 + 1); 459 /* copy first unaligned byte to buf */ 460 b2[-1] = (b2[-1] & 0xff00) | *a1; 461 --len; 462 } else { 463 /* destination is aligned or length is zero */ 464 b1 = (u_short *)a1; 465 b2 = (u_short *)a2; 466 } 467 468 /* copy full words with aligned destination */ 469 for (i = len >> 1; i > 0; i--) 470 *b2++ = *b1++; 471 472 /* copy remaining byte */ 473 if (isodd(len)) 474 *b2 = (*b2 & 0x00ff) | (*(u_char *)b1) << 8; 475 } 476 477 integrate void 478 ariadne_copyfrombuf_word(struct lance_softc *sc, void *to, int boff, int len) 479 { 480 volatile u_char *a1 = (u_char *)sc->sc_mem + boff; 481 u_char *a2 = to; 482 volatile u_short *b1; 483 u_short *b2; 484 int i; 485 486 if (len > 0 && isodd(boff)) { 487 /* compute aligned source pointer */ 488 b1 = (u_short *)(a1 + 1); 489 /* adjust destination pointer (possibly unaligned) */ 490 b2 = (u_short *)(a2 + 1); 491 /* copy first unaligned byte from buf */ 492 *a2 = b1[-1]; 493 --len; 494 } else { 495 /* source is aligned or length is zero */ 496 b1 = (u_short *)a1; 497 b2 = (u_short *)a2; 498 } 499 500 /* copy full words with aligned source */ 501 for (i = len >> 1; i > 0; i--) 502 *b2++ = *b1++; 503 504 /* copy remaining byte */ 505 if (isodd(len)) 506 *(u_char *)b2 = *b1 >> 8; 507 } 508 509 integrate void 510 ariadne_zerobuf_word(struct lance_softc *sc, int boff, int len) 511 { 512 volatile u_char *a1 = (u_char *)sc->sc_mem + boff; 513 volatile u_short *b1; 514 int i; 515 516 if (len > 0 && isodd(boff)) { 517 b1 = (u_short *)(a1 + 1); 518 b1[-1] &= 0xff00; 519 --len; 520 } else { 521 b1 = (u_short *)a1; 522 } 523 524 for (i = len >> 1; i > 0; i--) 525 *b1++ = 0; 526 527 if (isodd(len)) 528 *b1 &= 0x00ff; 529 } 530