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