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