if_netdock_nubus.c revision 1.16.16.2
11.16.16.1Smjf/* $NetBSD: if_netdock_nubus.c,v 1.16.16.2 2008/06/02 13:22:22 mjf Exp $ */ 21.1Sitojun 31.1Sitojun/* 41.1Sitojun * Copyright (C) 2000,2002 Daishi Kato <daishi@axlight.com> 51.1Sitojun * All rights reserved. 61.1Sitojun * 71.1Sitojun * Redistribution and use in source and binary forms, with or without 81.1Sitojun * modification, are permitted provided that the following conditions 91.1Sitojun * are met: 101.1Sitojun * 1. Redistributions of source code must retain the above copyright 111.1Sitojun * notice, this list of conditions and the following disclaimer. 121.1Sitojun * 2. Redistributions in binary form must reproduce the above copyright 131.1Sitojun * notice, this list of conditions and the following disclaimer in the 141.1Sitojun * documentation and/or other materials provided with the distribution. 151.1Sitojun * 3. All advertising materials mentioning features or use of this software 161.1Sitojun * must display the following acknowledgement: 171.1Sitojun * This product includes software developed by Daishi Kato 181.1Sitojun * 4. The name of the author may not be used to endorse or promote products 191.1Sitojun * derived from this software without specific prior written permission. 201.1Sitojun * 211.1Sitojun * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 221.1Sitojun * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 231.1Sitojun * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 241.1Sitojun * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 251.1Sitojun * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 261.1Sitojun * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 271.1Sitojun * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 281.1Sitojun * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 291.1Sitojun * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 301.1Sitojun * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 311.1Sitojun */ 321.1Sitojun 331.1Sitojun/* 341.1Sitojun * Asante NetDock (for Duo series) driver 351.1Sitojun * the chip inside is not known 361.1Sitojun */ 371.1Sitojun 381.1Sitojun/* 391.1Sitojun * The author would like to thank Takeo Kuwata <tkuwata@mac.com> for 401.1Sitojun * his help in stabilizing this driver. 411.1Sitojun */ 421.1Sitojun 431.1Sitojun/***********************/ 441.4Slukem 451.4Slukem#include <sys/cdefs.h> 461.16.16.1Smjf__KERNEL_RCSID(0, "$NetBSD: if_netdock_nubus.c,v 1.16.16.2 2008/06/02 13:22:22 mjf Exp $"); 471.1Sitojun 481.1Sitojun#include <sys/param.h> 491.1Sitojun#include <sys/device.h> 501.1Sitojun#include <sys/socket.h> 511.1Sitojun#include <sys/systm.h> 521.1Sitojun#include <sys/mbuf.h> 531.1Sitojun#include <sys/ioctl.h> 541.1Sitojun 551.1Sitojun#include <net/if.h> 561.1Sitojun#include <net/if_dl.h> 571.1Sitojun#include <net/if_ether.h> 581.1Sitojun 591.1Sitojun#include "opt_inet.h" 601.1Sitojun#ifdef INET 611.1Sitojun#include <netinet/in.h> 621.1Sitojun#include <netinet/if_inarp.h> 631.1Sitojun#endif 641.1Sitojun 651.1Sitojun#include "bpfilter.h" 661.1Sitojun#if NBPFILTER > 0 671.1Sitojun#include <net/bpf.h> 681.1Sitojun#endif 691.1Sitojun 701.1Sitojun#include <machine/bus.h> 711.1Sitojun#include <machine/viareg.h> 721.1Sitojun#include <mac68k/nubus/nubus.h> 731.1Sitojun 741.1Sitojun/***********************/ 751.1Sitojun 761.1Sitojun#define NETDOCK_DEBUG 771.1Sitojun 781.1Sitojun#define NETDOCK_NUBUS_CATEGORY 0x0020 791.1Sitojun#define NETDOCK_NUBUS_TYPE 0x0003 801.1Sitojun#define NETDOCK_NUBUS_DRSW 0x0103 811.1Sitojun#define NETDOCK_NUBUS_DRHW 0x0100 821.1Sitojun 831.1Sitojun#define ETHERMICRODOCK_NUBUS_CATEGORY 0x0020 841.1Sitojun#define ETHERMICRODOCK_NUBUS_TYPE 0x0003 851.1Sitojun#define ETHERMICRODOCK_NUBUS_DRSW 0x0102 861.1Sitojun#define ETHERMICRODOCK_NUBUS_DRHW 0x0100 871.1Sitojun 881.1Sitojun#define REG_ISR 0x000c 891.1Sitojun#define REG_000E 0x000e 901.1Sitojun#define REG_0000 0x0000 911.1Sitojun#define REG_0002 0x0002 921.1Sitojun#define REG_0004 0x0004 931.1Sitojun#define REG_0006 0x0006 941.1Sitojun#define REG_DATA 0x0008 951.1Sitojun#define REG_EFD00 0xefd00 961.1Sitojun 971.1Sitojun#define ISR_ALL 0x3300 981.1Sitojun#define ISR_TX 0x0200 991.1Sitojun#define ISR_RX 0x0100 1001.1Sitojun#define ISR_READY 0x0800 1011.1Sitojun#define ISR_BIT_0C 0x1000 1021.1Sitojun#define ISR_BIT_0D 0x2000 1031.1Sitojun#define ISR_MASK 0x0033 1041.1Sitojun#define ISR_BIT_03 0x0008 1051.1Sitojun 1061.1Sitojun#define REG_0002_BIT_04 0x0010 1071.1Sitojun#define REG_0000_BIT_08 0x0100 1081.1Sitojun#define REG_0004_BIT_0F 0x8000 1091.1Sitojun#define REG_0004_BIT_07 0x0080 1101.1Sitojun#define REG_DATA_BIT_02 0x0004 1111.1Sitojun#define REG_DATA_BIT_03 0x0008 1121.1Sitojun#define REG_DATA_BIT_04 0x0010 1131.1Sitojun#define REG_DATA_BIT_05 0x0020 1141.1Sitojun#define REG_DATA_BIT_08 0x0100 1151.1Sitojun#define REG_DATA_BIT_07 0x0080 1161.1Sitojun#define REG_DATA_BIT_0F 0x8000 1171.1Sitojun 1181.1Sitojun/***********************/ 1191.1Sitojun 1201.1Sitojuntypedef struct netdock_softc { 1211.16.16.2Smjf device_t sc_dev; 1221.1Sitojun struct ethercom sc_ethercom; 1231.1Sitojun#define sc_if sc_ethercom.ec_if 1241.1Sitojun 1251.1Sitojun bus_space_tag_t sc_regt; 1261.1Sitojun bus_space_handle_t sc_regh; 1271.1Sitojun 1281.1Sitojun u_int8_t sc_enaddr[ETHER_ADDR_LEN]; 1291.1Sitojun 1301.1Sitojun} netdock_softc_t; 1311.1Sitojun 1321.1Sitojun/***********************/ 1331.1Sitojun 1341.6Schsstatic int netdock_nubus_match(struct device *, struct cfdata *, void *); 1351.6Schsstatic void netdock_nubus_attach(struct device *, struct device *, void *); 1361.6Schsstatic int netdock_nb_get_enaddr(bus_space_tag_t, bus_space_handle_t, 1371.6Schs struct nubus_attach_args *, u_int8_t *); 1381.1Sitojun#ifdef NETDOCK_DEBUG_DRIVER 1391.6Schsstatic void netdock_print_driver(bus_space_tag_t, bus_space_handle_t, 1401.6Schs struct nubus_attach_args *); 1411.1Sitojun#endif 1421.1Sitojun 1431.6Schsint netdock_setup(struct netdock_softc *, u_int8_t *); 1441.6Schsvoid netdock_intr(void *); 1451.1Sitojun 1461.6Schsstatic void netdock_watchdog(struct ifnet *); 1471.6Schsstatic int netdock_init(struct netdock_softc *); 1481.6Schsstatic int netdock_stop(struct netdock_softc *); 1491.12Schristosstatic int netdock_ioctl(struct ifnet *, u_long, void *); 1501.6Schsstatic void netdock_start(struct ifnet *); 1511.6Schsstatic void netdock_reset(struct netdock_softc *); 1521.6Schsstatic void netdock_txint(struct netdock_softc *); 1531.6Schsstatic void netdock_rxint(struct netdock_softc *); 1541.6Schs 1551.6Schsstatic u_int netdock_put(struct netdock_softc *, struct mbuf *); 1561.6Schsstatic int netdock_read(struct netdock_softc *, int); 1571.6Schsstatic struct mbuf *netdock_get(struct netdock_softc *, int); 1581.1Sitojun 1591.1Sitojun/***********************/ 1601.1Sitojun 1611.1Sitojun#define NIC_GET_1(sc, o) (bus_space_read_1((sc)->sc_regt, \ 1621.1Sitojun (sc)->sc_regh, (o))) 1631.1Sitojun#define NIC_PUT_1(sc, o, val) (bus_space_write_1((sc)->sc_regt, \ 1641.1Sitojun (sc)->sc_regh, (o), (val))) 1651.1Sitojun#define NIC_GET_2(sc, o) (bus_space_read_2((sc)->sc_regt, \ 1661.1Sitojun (sc)->sc_regh, (o))) 1671.1Sitojun#define NIC_PUT_2(sc, o, val) (bus_space_write_2((sc)->sc_regt, \ 1681.1Sitojun (sc)->sc_regh, (o), (val))) 1691.1Sitojun#define NIC_GET_4(sc, o) (bus_space_read_4((sc)->sc_regt, \ 1701.1Sitojun (sc)->sc_regh, (o))) 1711.1Sitojun#define NIC_PUT_4(sc, o, val) (bus_space_write_4((sc)->sc_regt, \ 1721.1Sitojun (sc)->sc_regh, (o), (val))) 1731.1Sitojun 1741.1Sitojun#define NIC_BSET(sc, o, b) \ 1751.11Sperry __asm volatile("bset %0,%1" : : "di" ((u_short)(b)), \ 1761.1Sitojun "g" (*(u_int8_t *)((sc)->sc_regh.base + (o)))) 1771.1Sitojun#define NIC_BCLR(sc, o, b) \ 1781.11Sperry __asm volatile("bclr %0,%1" : : "di" ((u_short)(b)), \ 1791.1Sitojun "g" (*(u_int8_t *)((sc)->sc_regh.base + (o)))) 1801.1Sitojun#define NIC_ANDW(sc, o, b) \ 1811.11Sperry __asm volatile("andw %0,%1" : : "di" ((u_short)(b)), \ 1821.1Sitojun "g" (*(u_int8_t *)((sc)->sc_regh.base + (o)))) 1831.1Sitojun#define NIC_ORW(sc, o, b) \ 1841.11Sperry __asm volatile("orw %0,%1" : : "di" ((u_short)(b)), \ 1851.1Sitojun "g" (*(u_int8_t *)((sc)->sc_regh.base + (o)))) 1861.1Sitojun 1871.1Sitojun 1881.1Sitojun/***********************/ 1891.1Sitojun 1901.3SthorpejCFATTACH_DECL(netdock_nubus, sizeof(struct netdock_softc), 1911.3Sthorpej netdock_nubus_match, netdock_nubus_attach, NULL, NULL); 1921.1Sitojun 1931.1Sitojun/***********************/ 1941.1Sitojun 1951.1Sitojunstatic int 1961.6Schsnetdock_nubus_match(struct device *parent, struct cfdata *cf, void *aux) 1971.1Sitojun{ 1981.1Sitojun struct nubus_attach_args *na = (struct nubus_attach_args *)aux; 1991.1Sitojun bus_space_handle_t bsh; 2001.1Sitojun int rv; 2011.1Sitojun 2021.1Sitojun if (bus_space_map(na->na_tag, NUBUS_SLOT2PA(na->slot), 2031.1Sitojun NBMEMSIZE, 0, &bsh)) 2041.1Sitojun return (0); 2051.1Sitojun 2061.1Sitojun rv = 0; 2071.1Sitojun 2081.1Sitojun if (na->category == NETDOCK_NUBUS_CATEGORY && 2091.1Sitojun na->type == NETDOCK_NUBUS_TYPE && 2101.1Sitojun na->drsw == NETDOCK_NUBUS_DRSW) { 2111.1Sitojun /* assuming this IS Asante NetDock */ 2121.1Sitojun rv = 1; 2131.1Sitojun } 2141.1Sitojun 2151.1Sitojun if (na->category == ETHERMICRODOCK_NUBUS_CATEGORY && 2161.1Sitojun na->type == ETHERMICRODOCK_NUBUS_TYPE && 2171.1Sitojun na->drsw == ETHERMICRODOCK_NUBUS_DRSW) { 2181.1Sitojun /* assuming this IS Newer EtherMicroDock */ 2191.1Sitojun rv = 1; 2201.1Sitojun } 2211.1Sitojun 2221.1Sitojun bus_space_unmap(na->na_tag, bsh, NBMEMSIZE); 2231.1Sitojun 2241.1Sitojun return rv; 2251.1Sitojun} 2261.1Sitojun 2271.1Sitojunstatic void 2281.6Schsnetdock_nubus_attach(struct device *parent, struct device *self, void *aux) 2291.1Sitojun{ 2301.1Sitojun struct netdock_softc *sc = (struct netdock_softc *)self; 2311.1Sitojun struct nubus_attach_args *na = (struct nubus_attach_args *)aux; 2321.1Sitojun bus_space_tag_t bst; 2331.1Sitojun bus_space_handle_t bsh; 2341.1Sitojun u_int8_t enaddr[ETHER_ADDR_LEN]; 2351.8Srjs const char *cardtype; 2361.1Sitojun 2371.1Sitojun bst = na->na_tag; 2381.1Sitojun if (bus_space_map(bst, NUBUS_SLOT2PA(na->slot), NBMEMSIZE, 0, &bsh)) { 2391.1Sitojun printf(": failed to map memory space.\n"); 2401.1Sitojun return; 2411.1Sitojun } 2421.1Sitojun 2431.1Sitojun sc->sc_regt = bst; 2441.1Sitojun cardtype = nubus_get_card_name(bst, bsh, na->fmt); 2451.1Sitojun 2461.1Sitojun#ifdef NETDOCK_DEBUG_DRIVER 2471.1Sitojun netdock_print_driver(bst, bsh, na); 2481.1Sitojun#endif 2491.1Sitojun 2501.1Sitojun if (netdock_nb_get_enaddr(bst, bsh, na, enaddr)) { 2511.1Sitojun printf(": can't find MAC address.\n"); 2521.1Sitojun bus_space_unmap(bst, bsh, NBMEMSIZE); 2531.1Sitojun return; 2541.1Sitojun } 2551.1Sitojun 2561.1Sitojun if (bus_space_subregion(bst, bsh, 0xe00300, 0xf0000, &sc->sc_regh)) { 2571.1Sitojun printf(": failed to map register space.\n"); 2581.1Sitojun bus_space_unmap(bst, bsh, NBMEMSIZE); 2591.1Sitojun return; 2601.1Sitojun } 2611.1Sitojun 2621.1Sitojun printf(": %s\n", cardtype); 2631.1Sitojun 2641.1Sitojun if (netdock_setup(sc, enaddr)) { 2651.1Sitojun bus_space_unmap(bst, bsh, NBMEMSIZE); 2661.1Sitojun return; 2671.1Sitojun } 2681.1Sitojun 2691.1Sitojun add_nubus_intr(na->slot, netdock_intr, (void *)sc); 2701.1Sitojun 2711.1Sitojun return; 2721.1Sitojun} 2731.1Sitojun 2741.1Sitojunstatic int 2751.6Schsnetdock_nb_get_enaddr(bus_space_tag_t bst, bus_space_handle_t bsh, 2761.6Schs struct nubus_attach_args *na, u_int8_t *ep) 2771.1Sitojun{ 2781.1Sitojun nubus_dir dir; 2791.1Sitojun nubus_dirent dirent; 2801.1Sitojun 2811.1Sitojun /* 2821.1Sitojun * these hardwired resource IDs are only for NetDock 2831.1Sitojun */ 2841.1Sitojun nubus_get_main_dir(na->fmt, &dir); 2851.1Sitojun if (nubus_find_rsrc(bst, bsh, na->fmt, &dir, 0x81, &dirent) <= 0) 2861.1Sitojun return 1; 2871.1Sitojun nubus_get_dir_from_rsrc(na->fmt, &dirent, &dir); 2881.1Sitojun if (nubus_find_rsrc(bst, bsh, na->fmt, &dir, 0x80, &dirent) <= 0) 2891.1Sitojun return 1; 2901.1Sitojun if (nubus_get_ind_data(bst, bsh, na->fmt, &dirent, 2911.1Sitojun ep, ETHER_ADDR_LEN) <= 0) 2921.1Sitojun return 1; 2931.1Sitojun 2941.1Sitojun return 0; 2951.1Sitojun} 2961.1Sitojun 2971.1Sitojun#ifdef NETDOCK_DEBUG_DRIVER 2981.1Sitojunstatic void 2991.6Schsnetdock_print_driver(bus_space_tag_t bst, bus_space_handle_t bsh, 3001.6Schs struct nubus_attach_args *na) 3011.1Sitojun{ 3021.1Sitojun#define HEADSIZE (8+4) 3031.1Sitojun#define CODESIZE (6759-4) 3041.1Sitojun unsigned char mydata[HEADSIZE + CODESIZE]; 3051.1Sitojun nubus_dir dir; 3061.1Sitojun nubus_dirent dirent; 3071.1Sitojun int i, rv; 3081.1Sitojun 3091.1Sitojun nubus_get_main_dir(na->fmt, &dir); 3101.1Sitojun rv = nubus_find_rsrc(bst, bsh, na->fmt, &dir, 0x81, &dirent); 3111.1Sitojun if (rv <= 0) { 3121.1Sitojun printf(": can't find sResource.\n"); 3131.1Sitojun return; 3141.1Sitojun } 3151.1Sitojun nubus_get_dir_from_rsrc(na->fmt, &dirent, &dir); 3161.1Sitojun if (nubus_find_rsrc(bst, bsh, na->fmt, &dir, NUBUS_RSRC_DRVRDIR, 3171.1Sitojun &dirent) <= 0) { 3181.1Sitojun printf(": can't find sResource.\n"); 3191.1Sitojun return; 3201.1Sitojun } 3211.1Sitojun if (nubus_get_ind_data(bst, bsh, na->fmt, 3221.1Sitojun &dirent, mydata, HEADSIZE+CODESIZE) <= 0) { 3231.1Sitojun printf(": can't find indirect data.\n"); 3241.1Sitojun return; 3251.1Sitojun } 3261.1Sitojun printf("\n########## begin driver dir"); 3271.1Sitojun for (i = 0; i < HEADSIZE; i++) { 3281.1Sitojun if (i % 16 == 0) 3291.1Sitojun printf("\n%02x:",i); 3301.1Sitojun printf(" %02x", mydata[i]); 3311.1Sitojun } 3321.1Sitojun printf("\n########## begin driver code"); 3331.1Sitojun for (i = 0; i < CODESIZE; i++) { 3341.1Sitojun if (i % 16 == 0) 3351.1Sitojun printf("\n%02x:",i); 3361.1Sitojun printf(" %02x", mydata[i + HEADSIZE]); 3371.1Sitojun } 3381.1Sitojun#if 0 3391.1Sitojun printf("\n########## begin driver code (partial)\n"); 3401.1Sitojun#define PARTSIZE 256 3411.1Sitojun#define OFFSET 0x1568 3421.1Sitojun for (i = OFFSET; i < OFFSET + PARTSIZE; i++) { 3431.1Sitojun if ((i - OFFSET) % 16 == 0) 3441.1Sitojun printf("\n%02x:",i); 3451.1Sitojun printf(" %02x", mydata[i + HEADSIZE]); 3461.1Sitojun } 3471.1Sitojun#endif 3481.1Sitojun printf("\n########## end\n"); 3491.1Sitojun} 3501.1Sitojun#endif 3511.1Sitojun 3521.1Sitojun 3531.1Sitojunint 3541.6Schsnetdock_setup(struct netdock_softc *sc, u_int8_t *lladdr) 3551.1Sitojun{ 3561.1Sitojun struct ifnet *ifp = &sc->sc_if; 3571.1Sitojun 3581.6Schs memcpy(sc->sc_enaddr, lladdr, ETHER_ADDR_LEN); 3591.1Sitojun printf("%s: Ethernet address %s\n", 3601.16.16.1Smjf sc->sc_dev->dv_xname, ether_sprintf(lladdr)); 3611.1Sitojun 3621.16.16.2Smjf memcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ); 3631.1Sitojun ifp->if_softc = sc; 3641.1Sitojun ifp->if_ioctl = netdock_ioctl; 3651.1Sitojun ifp->if_start = netdock_start; 3661.1Sitojun ifp->if_flags = 3671.1Sitojun IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST; 3681.1Sitojun ifp->if_watchdog = netdock_watchdog; 3691.1Sitojun 3701.1Sitojun if_attach(ifp); 3711.1Sitojun ether_ifattach(ifp, lladdr); 3721.1Sitojun 3731.1Sitojun return (0); 3741.1Sitojun} 3751.1Sitojun 3761.1Sitojunstatic int 3771.12Schristosnetdock_ioctl(struct ifnet *ifp, u_long cmd, void *data) 3781.1Sitojun{ 3791.1Sitojun struct ifaddr *ifa; 3801.1Sitojun struct netdock_softc *sc = ifp->if_softc; 3811.1Sitojun int s = splnet(); 3821.1Sitojun int err = 0; 3831.1Sitojun int temp; 3841.1Sitojun 3851.1Sitojun switch (cmd) { 3861.1Sitojun case SIOCSIFADDR: 3871.1Sitojun ifa = (struct ifaddr *)data; 3881.1Sitojun ifp->if_flags |= IFF_UP; 3891.1Sitojun switch (ifa->ifa_addr->sa_family) { 3901.1Sitojun#ifdef INET 3911.1Sitojun case AF_INET: 3921.1Sitojun (void)netdock_init(sc); 3931.1Sitojun arp_ifinit(ifp, ifa); 3941.1Sitojun break; 3951.1Sitojun#endif 3961.1Sitojun default: 3971.1Sitojun (void)netdock_init(sc); 3981.1Sitojun break; 3991.1Sitojun } 4001.1Sitojun break; 4011.1Sitojun 4021.1Sitojun case SIOCSIFFLAGS: 4031.1Sitojun if ((ifp->if_flags & IFF_UP) == 0 && 4041.1Sitojun (ifp->if_flags & IFF_RUNNING) != 0) { 4051.1Sitojun netdock_stop(sc); 4061.1Sitojun ifp->if_flags &= ~IFF_RUNNING; 4071.1Sitojun } else if ((ifp->if_flags & IFF_UP) != 0 && 4081.1Sitojun (ifp->if_flags & IFF_RUNNING) == 0) { 4091.1Sitojun (void)netdock_init(sc); 4101.1Sitojun } else { 4111.1Sitojun temp = ifp->if_flags & IFF_UP; 4121.1Sitojun netdock_reset(sc); 4131.1Sitojun ifp->if_flags |= temp; 4141.1Sitojun netdock_start(ifp); 4151.1Sitojun } 4161.1Sitojun break; 4171.1Sitojun 4181.1Sitojun case SIOCADDMULTI: 4191.1Sitojun case SIOCDELMULTI: 4201.15Sjmmv if ((err = ether_ioctl(ifp, cmd, data)) == ENETRESET) { 4211.5Sthorpej if (ifp->if_flags & IFF_RUNNING) { 4221.5Sthorpej temp = ifp->if_flags & IFF_UP; 4231.5Sthorpej netdock_reset(sc); 4241.5Sthorpej ifp->if_flags |= temp; 4251.5Sthorpej } 4261.1Sitojun err = 0; 4271.1Sitojun } 4281.1Sitojun break; 4291.1Sitojun default: 4301.1Sitojun err = EINVAL; 4311.1Sitojun break; 4321.1Sitojun } 4331.1Sitojun splx(s); 4341.1Sitojun return (err); 4351.1Sitojun} 4361.1Sitojun 4371.1Sitojunstatic void 4381.6Schsnetdock_start(struct ifnet *ifp) 4391.1Sitojun{ 4401.1Sitojun struct netdock_softc *sc = ifp->if_softc; 4411.1Sitojun struct mbuf *m; 4421.1Sitojun 4431.1Sitojun if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) 4441.1Sitojun return; 4451.1Sitojun 4461.1Sitojun while (1) { 4471.1Sitojun IF_DEQUEUE(&ifp->if_snd, m); 4481.1Sitojun if (m == 0) 4491.1Sitojun return; 4501.1Sitojun 4511.1Sitojun if ((m->m_flags & M_PKTHDR) == 0) 4521.1Sitojun panic("%s: netdock_start: no header mbuf", 4531.16.16.2Smjf device_xname(sc->sc_dev)); 4541.1Sitojun 4551.1Sitojun#if NBPFILTER > 0 4561.1Sitojun if (ifp->if_bpf) 4571.1Sitojun bpf_mtap(ifp->if_bpf, m); 4581.1Sitojun#endif 4591.1Sitojun 4601.1Sitojun if ((netdock_put(sc, m)) == 0) { 4611.1Sitojun IF_PREPEND(&ifp->if_snd, m); 4621.1Sitojun return; 4631.1Sitojun } 4641.1Sitojun 4651.1Sitojun ifp->if_opackets++; 4661.1Sitojun } 4671.1Sitojun 4681.1Sitojun} 4691.1Sitojun 4701.1Sitojunstatic void 4711.6Schsnetdock_reset(struct netdock_softc *sc) 4721.1Sitojun{ 4731.1Sitojun 4741.1Sitojun netdock_stop(sc); 4751.1Sitojun netdock_init(sc); 4761.1Sitojun} 4771.1Sitojun 4781.1Sitojunstatic int 4791.6Schsnetdock_init(struct netdock_softc *sc) 4801.1Sitojun{ 4811.1Sitojun int s; 4821.1Sitojun int saveisr; 4831.1Sitojun int savetmp; 4841.1Sitojun 4851.1Sitojun if (sc->sc_if.if_flags & IFF_RUNNING) 4861.1Sitojun return (0); 4871.1Sitojun 4881.1Sitojun s = splnet(); 4891.1Sitojun 4901.1Sitojun /* 0606 */ 4911.1Sitojun NIC_PUT_2(sc, REG_000E, 0x0200); 4921.1Sitojun NIC_PUT_2(sc, REG_ISR , 0); 4931.1Sitojun NIC_PUT_2(sc, REG_000E, 0); 4941.1Sitojun 4951.1Sitojun NIC_PUT_2(sc, REG_0000, 0x8104); 4961.1Sitojun NIC_PUT_2(sc, REG_0004, 0x0043); 4971.1Sitojun NIC_PUT_2(sc, REG_000E, 0x0100); 4981.1Sitojun NIC_PUT_2(sc, REG_0002, 0x6618); 4991.1Sitojun NIC_PUT_2(sc, REG_0000, 0x8010); 5001.1Sitojun 5011.1Sitojun NIC_PUT_1(sc, REG_0004 + 0, sc->sc_enaddr[0]); 5021.1Sitojun NIC_PUT_1(sc, REG_0004 + 1, sc->sc_enaddr[1]); 5031.1Sitojun NIC_PUT_1(sc, REG_0004 + 2, sc->sc_enaddr[2]); 5041.1Sitojun NIC_PUT_1(sc, REG_0004 + 3, sc->sc_enaddr[3]); 5051.1Sitojun NIC_PUT_1(sc, REG_0004 + 4, sc->sc_enaddr[4]); 5061.1Sitojun NIC_PUT_1(sc, REG_0004 + 5, sc->sc_enaddr[5]); 5071.1Sitojun 5081.1Sitojun NIC_PUT_2(sc, REG_ISR , 0x2008); 5091.1Sitojun NIC_PUT_2(sc, REG_000E, 0x0200); 5101.1Sitojun NIC_PUT_2(sc, REG_0000, 0x4000); 5111.1Sitojun NIC_PUT_2(sc, REG_ISR, ISR_MASK); 5121.1Sitojun 5131.1Sitojun 5141.1Sitojun /* 1320 */ 5151.1Sitojun saveisr = NIC_GET_2(sc, REG_ISR); 5161.1Sitojun NIC_PUT_2(sc, REG_ISR , 0); 5171.1Sitojun savetmp = NIC_GET_2(sc, REG_000E); 5181.1Sitojun NIC_PUT_2(sc, REG_000E, 0x0100); 5191.1Sitojun NIC_ANDW(sc, REG_ISR, ~ISR_BIT_03); 5201.1Sitojun NIC_PUT_2(sc, REG_000E, savetmp); 5211.1Sitojun 5221.1Sitojun /* 1382 */ 5231.1Sitojun savetmp = NIC_GET_2(sc, REG_000E); 5241.1Sitojun NIC_PUT_2(sc, REG_000E, 0x0100); 5251.1Sitojun NIC_ORW(sc, REG_ISR, ISR_BIT_03); 5261.1Sitojun NIC_PUT_2(sc, REG_000E, savetmp); 5271.1Sitojun NIC_PUT_2(sc, REG_ISR , saveisr); 5281.1Sitojun 5291.1Sitojun 5301.1Sitojun sc->sc_if.if_flags |= IFF_RUNNING; 5311.1Sitojun sc->sc_if.if_flags &= ~IFF_OACTIVE; 5321.1Sitojun 5331.1Sitojun splx(s); 5341.1Sitojun return (0); 5351.1Sitojun} 5361.1Sitojun 5371.1Sitojunstatic int 5381.6Schsnetdock_stop(struct netdock_softc *sc) 5391.1Sitojun{ 5401.1Sitojun int s = splnet(); 5411.1Sitojun 5421.1Sitojun sc->sc_if.if_timer = 0; 5431.1Sitojun sc->sc_if.if_flags &= ~(IFF_RUNNING | IFF_UP); 5441.1Sitojun 5451.1Sitojun splx(s); 5461.1Sitojun return (0); 5471.1Sitojun} 5481.1Sitojun 5491.1Sitojunstatic void 5501.6Schsnetdock_watchdog(struct ifnet *ifp) 5511.1Sitojun{ 5521.1Sitojun struct netdock_softc *sc = ifp->if_softc; 5531.1Sitojun int tmp; 5541.1Sitojun 5551.1Sitojun printf("netdock_watchdog: resetting chip\n"); 5561.1Sitojun tmp = ifp->if_flags & IFF_UP; 5571.1Sitojun netdock_reset(sc); 5581.1Sitojun ifp->if_flags |= tmp; 5591.1Sitojun} 5601.1Sitojun 5611.1Sitojunstatic u_int 5621.6Schsnetdock_put(struct netdock_softc *sc, struct mbuf *m0) 5631.1Sitojun{ 5641.1Sitojun struct mbuf *m; 5651.1Sitojun u_int totlen = 0; 5661.1Sitojun u_int tmplen; 5671.1Sitojun int isr; 5681.1Sitojun int timeout; 5691.1Sitojun int tmp; 5701.1Sitojun u_int i; 5711.1Sitojun 5721.1Sitojun for (m = m0; m; m = m->m_next) 5731.1Sitojun totlen += m->m_len; 5741.1Sitojun 5751.1Sitojun if (totlen >= ETHER_MAX_LEN) 5761.16.16.1Smjf panic("%s: netdock_put: packet overflow", 5771.16.16.2Smjf device_xname(sc->sc_dev)); 5781.1Sitojun 5791.1Sitojun totlen += 6; 5801.1Sitojun tmplen = totlen; 5811.1Sitojun tmplen &= 0xff00; 5821.1Sitojun tmplen |= 0x2000; 5831.1Sitojun NIC_PUT_2(sc, REG_0000, tmplen); 5841.1Sitojun 5851.1Sitojun timeout = 0x3000; 5861.1Sitojun while ((((isr = NIC_GET_2(sc, REG_ISR)) & ISR_READY) == 0) && 5871.1Sitojun timeout--) { 5881.1Sitojun if (isr & ISR_TX) 5891.1Sitojun netdock_txint(sc); 5901.1Sitojun } 5911.1Sitojun if (timeout == 0) 5921.1Sitojun return (0); 5931.1Sitojun 5941.1Sitojun tmp = NIC_GET_2(sc, REG_0002); 5951.1Sitojun tmp <<= 8; 5961.1Sitojun NIC_PUT_2(sc, REG_0002, tmp); 5971.1Sitojun NIC_PUT_2(sc, REG_0006, 0x240); 5981.1Sitojun NIC_GET_2(sc, REG_ISR); 5991.1Sitojun tmplen = ((totlen << 8) & 0xfe00) | ((totlen >> 8) & 0x00ff); 6001.1Sitojun NIC_PUT_2(sc, REG_DATA, tmplen); 6011.1Sitojun 6021.1Sitojun for (m = m0; m; m = m->m_next) { 6031.1Sitojun u_char *data = mtod(m, u_char *); 6041.1Sitojun int len = m->m_len; 6051.1Sitojun int len4 = len >> 2; 6061.1Sitojun u_int32_t *data4 = (u_int32_t *)data; 6071.1Sitojun for (i = 0; i < len4; i++) 6081.1Sitojun NIC_PUT_4(sc, REG_DATA, data4[i]); 6091.1Sitojun for (i = len4 << 2; i < len; i++) 6101.1Sitojun NIC_PUT_1(sc, REG_DATA, data[i]); 6111.1Sitojun } 6121.1Sitojun 6131.1Sitojun if (totlen & 0x01) 6141.1Sitojun NIC_PUT_2(sc, REG_DATA, 0x2020); 6151.1Sitojun else 6161.1Sitojun NIC_PUT_2(sc, REG_DATA, 0); 6171.1Sitojun 6181.1Sitojun NIC_PUT_2(sc, REG_0000, 0xc000); 6191.1Sitojun 6201.1Sitojun m_freem(m0); 6211.1Sitojun /* sc->sc_if.if_timer = 5; */ 6221.1Sitojun return (totlen); 6231.1Sitojun} 6241.1Sitojun 6251.1Sitojunvoid 6261.6Schsnetdock_intr(void *arg) 6271.1Sitojun{ 6281.1Sitojun struct netdock_softc *sc = (struct netdock_softc *)arg; 6291.1Sitojun int isr; 6301.1Sitojun int tmp; 6311.1Sitojun 6321.1Sitojun NIC_PUT_2(sc, REG_ISR, 0); 6331.1Sitojun while ((isr = (NIC_GET_2(sc, REG_ISR) & ISR_ALL)) != 0) { 6341.1Sitojun if (isr & ISR_TX) 6351.1Sitojun netdock_txint(sc); 6361.1Sitojun 6371.1Sitojun if (isr & ISR_RX) 6381.1Sitojun netdock_rxint(sc); 6391.1Sitojun 6401.1Sitojun if (isr & (ISR_BIT_0C | ISR_BIT_0D)) { 6411.1Sitojun if (isr & ISR_BIT_0C) { 6421.1Sitojun NIC_PUT_2(sc, REG_000E, 0); 6431.1Sitojun NIC_BSET(sc, REG_0004, 0x08); 6441.1Sitojun NIC_PUT_2(sc, REG_000E, 0x0200); 6451.1Sitojun } 6461.1Sitojun if (isr & ISR_BIT_0D) { 6471.1Sitojun NIC_PUT_2(sc, REG_000E, 0); 6481.1Sitojun tmp = NIC_GET_2(sc, REG_0002); 6491.1Sitojun if (tmp & REG_0002_BIT_04) 6501.1Sitojun NIC_GET_2(sc, REG_0006); 6511.1Sitojun tmp = NIC_GET_2(sc, REG_0000); 6521.1Sitojun if (tmp & REG_0000_BIT_08) 6531.1Sitojun NIC_BSET(sc, REG_0000, 0x08); 6541.1Sitojun NIC_PUT_2(sc, REG_000E, 0x0200); 6551.1Sitojun } 6561.1Sitojun NIC_PUT_2(sc, REG_ISR, isr); 6571.1Sitojun } 6581.1Sitojun } 6591.1Sitojun NIC_PUT_2(sc, REG_ISR, ISR_MASK); 6601.1Sitojun} 6611.1Sitojun 6621.1Sitojunstatic void 6631.6Schsnetdock_txint(struct netdock_softc *sc) 6641.1Sitojun{ 6651.1Sitojun struct ifnet *ifp = &sc->sc_if; 6661.1Sitojun int savereg0002; 6671.1Sitojun int reg0004; 6681.1Sitojun int regdata; 6691.1Sitojun 6701.1Sitojun ifp->if_flags &= ~IFF_OACTIVE; 6711.1Sitojun ifp->if_timer = 0; 6721.1Sitojun 6731.1Sitojun savereg0002 = NIC_GET_2(sc, REG_0002); 6741.1Sitojun 6751.1Sitojun while (((reg0004 = NIC_GET_2(sc, REG_0004)) & REG_0004_BIT_0F) == 0) { 6761.1Sitojun NIC_PUT_2(sc, REG_0002, reg0004); 6771.1Sitojun NIC_PUT_2(sc, REG_0006, 0x0060); 6781.1Sitojun NIC_GET_2(sc, REG_ISR); 6791.1Sitojun regdata = NIC_GET_2(sc, REG_DATA); 6801.1Sitojun if ((regdata & REG_DATA_BIT_08) == 0) { 6811.1Sitojun /* ifp->if_collisions++; */ 6821.1Sitojun if (regdata & REG_DATA_BIT_07) 6831.1Sitojun /* ifp->if_oerrors++; */ 6841.1Sitojun NIC_PUT_2(sc, REG_000E, 0); 6851.1Sitojun NIC_ORW(sc, REG_0000, 0x0100); 6861.1Sitojun NIC_PUT_2(sc, REG_000E, 0x0200); 6871.1Sitojun } 6881.1Sitojun NIC_GET_2(sc ,REG_DATA); 6891.1Sitojun 6901.1Sitojun if (regdata & REG_DATA_BIT_0F) 6911.1Sitojun NIC_GET_4(sc, REG_EFD00); 6921.1Sitojun NIC_PUT_2(sc, REG_0000, 0xa000); 6931.1Sitojun NIC_PUT_2(sc, REG_ISR, ISR_TX); 6941.1Sitojun } 6951.1Sitojun 6961.1Sitojun NIC_PUT_2(sc, REG_0002, savereg0002); 6971.1Sitojun NIC_PUT_2(sc, REG_000E, 0); 6981.1Sitojun NIC_GET_2(sc, REG_0006); 6991.1Sitojun NIC_PUT_2(sc, REG_000E, 0x0200); 7001.1Sitojun NIC_PUT_2(sc, REG_0006, 0); 7011.1Sitojun} 7021.1Sitojun 7031.1Sitojunstatic void 7041.6Schsnetdock_rxint(struct netdock_softc *sc) 7051.1Sitojun{ 7061.1Sitojun struct ifnet *ifp = &sc->sc_if; 7071.1Sitojun int regdata1; 7081.1Sitojun int regdata2; 7091.1Sitojun u_int len; 7101.1Sitojun int timeout; 7111.1Sitojun 7121.1Sitojun while ((NIC_GET_2(sc, REG_0004) & REG_0004_BIT_07) == 0) { 7131.1Sitojun NIC_GET_2(sc, REG_ISR); 7141.1Sitojun NIC_PUT_2(sc, REG_0006, 0x00e0); 7151.1Sitojun NIC_GET_2(sc, REG_ISR); 7161.1Sitojun regdata1 = NIC_GET_2(sc, REG_DATA); 7171.1Sitojun regdata2 = NIC_GET_2(sc, REG_DATA); 7181.1Sitojun len = ((regdata2 << 8) & 0x0700) | ((regdata2 >> 8) & 0x00ff); 7191.1Sitojun 7201.1Sitojun#if 0 7211.1Sitojun printf("netdock_rxint: r1=0x%04x, r2=0x%04x, len=%d\n", 7221.1Sitojun regdata1, regdata2, len); 7231.1Sitojun#endif 7241.1Sitojun 7251.1Sitojun if ((regdata1 & REG_DATA_BIT_04) == 0) 7261.1Sitojun len -= 2; 7271.1Sitojun 7281.7Sthorpej /* CRC is included with the packet; trim it off. */ 7291.7Sthorpej len -= ETHER_CRC_LEN; 7301.7Sthorpej 7311.1Sitojun if ((regdata1 & 0x00ac) == 0) { 7321.1Sitojun if (netdock_read(sc, len)) 7331.1Sitojun ifp->if_ipackets++; 7341.1Sitojun else 7351.1Sitojun ifp->if_ierrors++; 7361.1Sitojun } else { 7371.1Sitojun ifp->if_ierrors++; 7381.1Sitojun 7391.1Sitojun if (regdata1 & REG_DATA_BIT_02) 7401.1Sitojun NIC_GET_4(sc, REG_EFD00); 7411.1Sitojun if (regdata1 & REG_DATA_BIT_03) 7421.1Sitojun ; 7431.1Sitojun if (regdata1 & REG_DATA_BIT_05) 7441.1Sitojun NIC_GET_4(sc, REG_EFD00); 7451.1Sitojun if (regdata1 & REG_DATA_BIT_07) 7461.1Sitojun ; 7471.1Sitojun } 7481.1Sitojun 7491.1Sitojun timeout = 0x14; 7501.1Sitojun while ((NIC_GET_2(sc, REG_0000) & REG_0000_BIT_08) && timeout--) 7511.1Sitojun ; 7521.1Sitojun if (timeout == 0) 7531.1Sitojun ; 7541.1Sitojun 7551.1Sitojun NIC_PUT_2(sc, REG_0000, 0x8000); 7561.1Sitojun } 7571.1Sitojun NIC_PUT_2(sc, REG_0006, 0); 7581.1Sitojun} 7591.1Sitojun 7601.1Sitojunstatic int 7611.6Schsnetdock_read(struct netdock_softc *sc, int len) 7621.1Sitojun{ 7631.1Sitojun struct ifnet *ifp = &sc->sc_if; 7641.1Sitojun struct mbuf *m; 7651.1Sitojun 7661.1Sitojun m = netdock_get(sc, len); 7671.1Sitojun if (m == 0) 7681.1Sitojun return (0); 7691.1Sitojun 7701.1Sitojun#if NBPFILTER > 0 7711.1Sitojun if (ifp->if_bpf) 7721.1Sitojun bpf_mtap(ifp->if_bpf, m); 7731.1Sitojun#endif 7741.1Sitojun 7751.1Sitojun (*ifp->if_input)(ifp, m); 7761.1Sitojun 7771.1Sitojun return (1); 7781.1Sitojun} 7791.1Sitojun 7801.1Sitojunstatic struct mbuf * 7811.6Schsnetdock_get(struct netdock_softc *sc, int datalen) 7821.1Sitojun{ 7831.1Sitojun struct mbuf *m, *top, **mp; 7841.1Sitojun u_char *data; 7851.1Sitojun int i; 7861.1Sitojun int len; 7871.1Sitojun int len4; 7881.1Sitojun u_int32_t *data4; 7891.1Sitojun 7901.1Sitojun MGETHDR(m, M_DONTWAIT, MT_DATA); 7911.1Sitojun if (m == NULL) 7921.1Sitojun return (NULL); 7931.1Sitojun m->m_pkthdr.rcvif = &sc->sc_if; 7941.1Sitojun m->m_pkthdr.len = datalen; 7951.1Sitojun len = MHLEN; 7961.1Sitojun top = NULL; 7971.1Sitojun mp = ⊤ 7981.1Sitojun 7991.1Sitojun while (datalen > 0) { 8001.1Sitojun if (top) { 8011.1Sitojun MGET(m, M_DONTWAIT, MT_DATA); 8021.1Sitojun if (m == 0) { 8031.1Sitojun m_freem(top); 8041.1Sitojun return (NULL); 8051.1Sitojun } 8061.1Sitojun len = MLEN; 8071.1Sitojun } 8081.1Sitojun if (datalen >= MINCLSIZE) { 8091.1Sitojun MCLGET(m, M_DONTWAIT); 8101.1Sitojun if ((m->m_flags & M_EXT) == 0) { 8111.1Sitojun if (top) 8121.1Sitojun m_freem(top); 8131.1Sitojun return (NULL); 8141.1Sitojun } 8151.1Sitojun len = MCLBYTES; 8161.1Sitojun } 8171.1Sitojun 8181.1Sitojun if (mp == &top) { 8191.13She char *newdata = (char *) 8201.1Sitojun ALIGN(m->m_data + sizeof(struct ether_header)) - 8211.1Sitojun sizeof(struct ether_header); 8221.1Sitojun len -= newdata - m->m_data; 8231.1Sitojun m->m_data = newdata; 8241.1Sitojun } 8251.1Sitojun 8261.1Sitojun m->m_len = len = min(datalen, len); 8271.1Sitojun 8281.1Sitojun data = mtod(m, u_char *); 8291.1Sitojun len4 = len >> 2; 8301.1Sitojun data4 = (u_int32_t *)data; 8311.1Sitojun for (i = 0; i < len4; i++) 8321.1Sitojun data4[i] = NIC_GET_4(sc, REG_DATA); 8331.1Sitojun for (i = len4 << 2; i < len; i++) 8341.1Sitojun data[i] = NIC_GET_1(sc, REG_DATA); 8351.1Sitojun 8361.1Sitojun datalen -= len; 8371.1Sitojun *mp = m; 8381.1Sitojun mp = &m->m_next; 8391.1Sitojun } 8401.1Sitojun 8411.1Sitojun return (top); 8421.1Sitojun} 843