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