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