if_sn.c revision 147256
1139749Simp/*- 254773Simp * Copyright (c) 1996 Gardner Buchanan <gbuchanan@shl.com> 354773Simp * All rights reserved. 454773Simp * 554773Simp * Redistribution and use in source and binary forms, with or without 654773Simp * modification, are permitted provided that the following conditions 754773Simp * are met: 854773Simp * 1. Redistributions of source code must retain the above copyright 954773Simp * notice, this list of conditions and the following disclaimer. 1054773Simp * 2. Redistributions in binary form must reproduce the above copyright 1154773Simp * notice, this list of conditions and the following disclaimer in the 1254773Simp * documentation and/or other materials provided with the distribution. 1354773Simp * 3. All advertising materials mentioning features or use of this software 1454773Simp * must display the following acknowledgement: 1554773Simp * This product includes software developed by Gardner Buchanan. 1654773Simp * 4. The name of Gardner Buchanan may not be used to endorse or promote 1754773Simp * products derived from this software without specific prior written 1854773Simp * permission. 1954773Simp * 2054773Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 2154773Simp * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2254773Simp * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2354773Simp * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2454773Simp * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2554773Simp * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2654773Simp * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2754773Simp * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2854773Simp * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2954773Simp * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3054773Simp */ 3154773Simp 32119419Sobrien#include <sys/cdefs.h> 33119419Sobrien__FBSDID("$FreeBSD: head/sys/dev/sn/if_sn.c 147256 2005-06-10 16:49:24Z brooks $"); 34119419Sobrien 3554773Simp/* 3654773Simp * This is a driver for SMC's 9000 series of Ethernet adapters. 3754773Simp * 3854773Simp * This FreeBSD driver is derived from the smc9194 Linux driver by 3954773Simp * Erik Stahlman and is Copyright (C) 1996 by Erik Stahlman. 4054773Simp * This driver also shamelessly borrows from the FreeBSD ep driver 4154773Simp * which is Copyright (C) 1994 Herb Peyerl <hpeyerl@novatel.ca> 4254773Simp * All rights reserved. 4354773Simp * 4454773Simp * It is set up for my SMC91C92 equipped Ampro LittleBoard embedded 4554773Simp * PC. It is adapted from Erik Stahlman's Linux driver which worked 4654773Simp * with his EFA Info*Express SVC VLB adaptor. According to SMC's databook, 4754773Simp * it will work for the entire SMC 9xxx series. (Ha Ha) 4854773Simp * 4954773Simp * "Features" of the SMC chip: 5054773Simp * 4608 byte packet memory. (for the 91C92. Others have more) 5154773Simp * EEPROM for configuration 5254773Simp * AUI/TP selection 5354773Simp * 5454773Simp * Authors: 5554773Simp * Erik Stahlman erik@vt.edu 5654773Simp * Herb Peyerl hpeyerl@novatel.ca 5754773Simp * Andres Vega Garcia avega@sophia.inria.fr 5854773Simp * Serge Babkin babkin@hq.icb.chel.su 5954773Simp * Gardner Buchanan gbuchanan@shl.com 6054773Simp * 6154773Simp * Sources: 6254773Simp * o SMC databook 6354773Simp * o "smc9194.c:v0.10(FIXED) 02/15/96 by Erik Stahlman (erik@vt.edu)" 6454773Simp * o "if_ep.c,v 1.19 1995/01/24 20:53:45 davidg Exp" 6554773Simp * 6654773Simp * Known Bugs: 6754773Simp * o Setting of the hardware address isn't supported. 6854773Simp * o Hardware padding isn't used. 6954773Simp */ 7054773Simp 7154773Simp/* 7254773Simp * Modifications for Megahertz X-Jack Ethernet Card (XJ-10BT) 7354773Simp * 7454773Simp * Copyright (c) 1996 by Tatsumi Hosokawa <hosokawa@jp.FreeBSD.org> 7554773Simp * BSD-nomads, Tokyo, Japan. 7654773Simp */ 7754773Simp/* 7854773Simp * Multicast support by Kei TANAKA <kei@pal.xerox.com> 7954773Simp * Special thanks to itojun@itojun.org 8054773Simp */ 8154773Simp 8254773Simp#include <sys/param.h> 8354773Simp#include <sys/systm.h> 8454773Simp#include <sys/errno.h> 8554773Simp#include <sys/sockio.h> 8654773Simp#include <sys/mbuf.h> 8754773Simp#include <sys/socket.h> 8854773Simp#include <sys/syslog.h> 8954773Simp 9054994Simp#include <sys/module.h> 9154994Simp#include <sys/bus.h> 9254994Simp 9354994Simp#include <machine/bus.h> 9454994Simp#include <machine/resource.h> 9554994Simp#include <sys/rman.h> 9654994Simp 9754773Simp#include <net/ethernet.h> 9854773Simp#include <net/if.h> 9954773Simp#include <net/if_arp.h> 10054773Simp#include <net/if_dl.h> 10154773Simp#include <net/if_types.h> 10254773Simp#include <net/if_mib.h> 10354773Simp 10454773Simp#ifdef INET 10554773Simp#include <netinet/in.h> 10654773Simp#include <netinet/in_systm.h> 10754773Simp#include <netinet/in_var.h> 10854773Simp#include <netinet/ip.h> 10954773Simp#endif 11054773Simp 11154773Simp#include <net/bpf.h> 11254773Simp#include <net/bpfdesc.h> 11354773Simp 11454773Simp 11554773Simp#include <dev/sn/if_snreg.h> 11654994Simp#include <dev/sn/if_snvar.h> 11754773Simp 11854994Simp/* Exported variables */ 11954994Simpdevclass_t sn_devclass; 12054773Simp 12154994Simpstatic int snioctl(struct ifnet * ifp, u_long, caddr_t); 12254773Simp 12354994Simpstatic void snresume(struct ifnet *); 12454773Simp 125121589Simpstatic void sninit_locked(void *); 126121589Simpstatic void snstart_locked(struct ifnet *); 12754773Simp 128121589Simpstatic void sninit(void *); 129121589Simpstatic void snread(struct ifnet *); 130121589Simpstatic void snstart(struct ifnet *); 131121589Simpstatic void snstop(struct sn_softc *); 132121589Simpstatic void snwatchdog(struct ifnet *); 133121589Simp 13454773Simpstatic void sn_setmcast(struct sn_softc *); 135147256Sbrooksstatic int sn_getmcf(struct ifnet *ifp, u_char *mcf); 13654773Simp 13754773Simp/* I (GB) have been unlucky getting the hardware padding 13854773Simp * to work properly. 13954773Simp */ 14054773Simp#define SW_PAD 14154773Simp 14254994Simpstatic const char *chip_ids[15] = { 14354994Simp NULL, NULL, NULL, 14454994Simp /* 3 */ "SMC91C90/91C92", 14554994Simp /* 4 */ "SMC91C94", 14654994Simp /* 5 */ "SMC91C95", 14754994Simp NULL, 14854994Simp /* 7 */ "SMC91C100", 14971060Stoshi /* 8 */ "SMC91C100FD", 15071060Stoshi NULL, NULL, NULL, 15154994Simp NULL, NULL, NULL 15254773Simp}; 15354773Simp 15454773Simpint 15554994Simpsn_attach(device_t dev) 15654773Simp{ 15754994Simp struct sn_softc *sc = device_get_softc(dev); 158147256Sbrooks struct ifnet *ifp; 159121589Simp uint16_t i, w; 160121589Simp uint8_t *p; 16154773Simp int rev; 162121589Simp uint16_t address; 16356366Shosokawa int j; 164122427Simp int err; 165147256Sbrooks u_char eaddr[6]; 16654773Simp 167147256Sbrooks ifp = sc->ifp = if_alloc(IFT_ETHER); 168147256Sbrooks if (ifp == NULL) { 169147256Sbrooks device_printf(dev, "can not if_alloc()\n"); 170147256Sbrooks return (ENOSPC); 171147256Sbrooks } 172147256Sbrooks 173121589Simp sc->dev = dev; 17454994Simp sn_activate(dev); 175121589Simp SN_LOCK_INIT(sc); 17654994Simp snstop(sc); 17754773Simp sc->pages_wanted = -1; 17854773Simp 179121514Simp SMC_SELECT_BANK(sc, 3); 180121514Simp rev = (CSR_READ_2(sc, REVISION_REG_W) >> 4) & 0xf; 181121514Simp if (chip_ids[rev]) 182121514Simp device_printf(dev, " %s ", chip_ids[rev]); 183121514Simp else 184121589Simp device_printf(dev, " unsupported chip"); 18554773Simp 186121514Simp SMC_SELECT_BANK(sc, 1); 187121514Simp i = CSR_READ_2(sc, CONFIG_REG_W); 18854773Simp printf(i & CR_AUI_SELECT ? "AUI" : "UTP"); 18954773Simp 19056397Shosokawa if (sc->pccard_enaddr) 19156397Shosokawa for (j = 0; j < 3; j++) { 192147256Sbrooks w = (uint16_t)eaddr[j * 2] | 193147256Sbrooks (((uint16_t)eaddr[j * 2 + 1]) << 8); 194121514Simp CSR_WRITE_2(sc, IAR_ADDR0_REG_W + j * 2, w); 19556397Shosokawa } 19654773Simp 19754773Simp /* 19854773Simp * Read the station address from the chip. The MAC address is bank 1, 19954773Simp * regs 4 - 9 20054773Simp */ 201121514Simp SMC_SELECT_BANK(sc, 1); 202147256Sbrooks p = (uint8_t *) eaddr; 20354773Simp for (i = 0; i < 6; i += 2) { 204121514Simp address = CSR_READ_2(sc, IAR_ADDR0_REG_W + i); 20554773Simp p[i + 1] = address >> 8; 20654773Simp p[i] = address & 0xFF; 20754773Simp } 20854773Simp ifp->if_softc = sc; 209121816Sbrooks if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 21054773Simp ifp->if_mtu = ETHERMTU; 21154773Simp ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 21254773Simp ifp->if_start = snstart; 21354773Simp ifp->if_ioctl = snioctl; 21454773Simp ifp->if_watchdog = snwatchdog; 21554773Simp ifp->if_init = sninit; 21655161Simp ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; 21754773Simp ifp->if_timer = 0; 21854773Simp 219147256Sbrooks ether_ifattach(ifp, eaddr); 22054994Simp 22154773Simp /* 222122427Simp * Activate the interrupt so we can get card interrupts. This 223122427Simp * needs to be done last so that we don't have/hold the lock 224122427Simp * during startup to avoid LORs in the network layer. 225122427Simp */ 226122427Simp if ((err = bus_setup_intr(dev, sc->irq_res, 227122427Simp INTR_TYPE_NET | INTR_MPSAFE, sn_intr, sc, &sc->intrhand)) != 0) { 228122427Simp sn_detach(dev); 229122427Simp return err; 230122427Simp } 23154994Simp return 0; 23254773Simp} 23354773Simp 23454773Simp 23569955Simpint 23669955Simpsn_detach(device_t dev) 23769955Simp{ 238147256Sbrooks struct sn_softc *sc = device_get_softc(dev); 239147256Sbrooks struct ifnet *ifp = sc->ifp; 24069955Simp 241121589Simp snstop(sc); 242147256Sbrooks ifp->if_flags &= ~IFF_RUNNING; 243147256Sbrooks ether_ifdetach(ifp); 244147256Sbrooks if_free(ifp); 24569955Simp sn_deactivate(dev); 246121589Simp SN_LOCK_DESTORY(sc); 24769955Simp return 0; 24869955Simp} 24969955Simp 250121589Simpstatic void 251121589Simpsninit(void *xsc) 252121589Simp{ 253121589Simp struct sn_softc *sc = xsc; 254121589Simp SN_LOCK(sc); 255121589Simp sninit_locked(sc); 256121589Simp SN_UNLOCK(sc); 257121589Simp} 258121589Simp 25954773Simp/* 26054773Simp * Reset and initialize the chip 26154773Simp */ 262121589Simpstatic void 263121589Simpsninit_locked(void *xsc) 26454773Simp{ 265121553Simp struct sn_softc *sc = xsc; 266147256Sbrooks struct ifnet *ifp = sc->ifp; 26754773Simp int flags; 26854773Simp int mask; 26954773Simp 270121589Simp SN_ASSERT_LOCKED(sc); 27154773Simp 27254773Simp /* 27354773Simp * This resets the registers mostly to defaults, but doesn't affect 27454773Simp * EEPROM. After the reset cycle, we pause briefly for the chip to 27554773Simp * be happy. 27654773Simp */ 277121514Simp SMC_SELECT_BANK(sc, 0); 278121514Simp CSR_WRITE_2(sc, RECV_CONTROL_REG_W, RCR_SOFTRESET); 279121514Simp SMC_DELAY(sc); 280121514Simp CSR_WRITE_2(sc, RECV_CONTROL_REG_W, 0x0000); 281121514Simp SMC_DELAY(sc); 282121514Simp SMC_DELAY(sc); 28354773Simp 284121514Simp CSR_WRITE_2(sc, TXMIT_CONTROL_REG_W, 0x0000); 28554773Simp 28654773Simp /* 28754773Simp * Set the control register to automatically release succesfully 28854773Simp * transmitted packets (making the best use out of our limited 28954773Simp * memory) and to enable the EPH interrupt on certain TX errors. 29054773Simp */ 291121514Simp SMC_SELECT_BANK(sc, 1); 292121514Simp CSR_WRITE_2(sc, CONTROL_REG_W, (CTR_AUTO_RELEASE | CTR_TE_ENABLE | 29354773Simp CTR_CR_ENABLE | CTR_LE_ENABLE)); 29454773Simp 29554773Simp /* Set squelch level to 240mV (default 480mV) */ 296121514Simp flags = CSR_READ_2(sc, CONFIG_REG_W); 29754773Simp flags |= CR_SET_SQLCH; 298121514Simp CSR_WRITE_2(sc, CONFIG_REG_W, flags); 29954773Simp 30054773Simp /* 30154773Simp * Reset the MMU and wait for it to be un-busy. 30254773Simp */ 303121514Simp SMC_SELECT_BANK(sc, 2); 304121514Simp CSR_WRITE_2(sc, MMU_CMD_REG_W, MMUCR_RESET); 305121514Simp while (CSR_READ_2(sc, MMU_CMD_REG_W) & MMUCR_BUSY) /* NOTHING */ 30654773Simp ; 30754773Simp 30854773Simp /* 30954773Simp * Disable all interrupts 31054773Simp */ 311121514Simp CSR_WRITE_1(sc, INTR_MASK_REG_B, 0x00); 31254773Simp 31354773Simp sn_setmcast(sc); 31454773Simp 31554773Simp /* 31654773Simp * Set the transmitter control. We want it enabled. 31754773Simp */ 31854773Simp flags = TCR_ENABLE; 31954773Simp 32054773Simp#ifndef SW_PAD 32154773Simp /* 32254773Simp * I (GB) have been unlucky getting this to work. 32354773Simp */ 32454773Simp flags |= TCR_PAD_ENABLE; 32554773Simp#endif /* SW_PAD */ 32654773Simp 327121514Simp CSR_WRITE_2(sc, TXMIT_CONTROL_REG_W, flags); 32854773Simp 32954773Simp 33054773Simp /* 33154773Simp * Now, enable interrupts 33254773Simp */ 333121514Simp SMC_SELECT_BANK(sc, 2); 33454773Simp 33554773Simp mask = IM_EPH_INT | 33654773Simp IM_RX_OVRN_INT | 33754773Simp IM_RCV_INT | 33854773Simp IM_TX_INT; 33954773Simp 340121514Simp CSR_WRITE_1(sc, INTR_MASK_REG_B, mask); 34154773Simp sc->intr_mask = mask; 34254773Simp sc->pages_wanted = -1; 34354773Simp 34454773Simp 34554773Simp /* 34654773Simp * Mark the interface running but not active. 34754773Simp */ 34854773Simp ifp->if_flags |= IFF_RUNNING; 34954773Simp ifp->if_flags &= ~IFF_OACTIVE; 35054773Simp 35154773Simp /* 35254773Simp * Attempt to push out any waiting packets. 35354773Simp */ 354121589Simp snstart_locked(ifp); 355121589Simp} 35654773Simp 357121589Simpstatic void 358121589Simpsnstart(struct ifnet *ifp) 359121589Simp{ 360121589Simp struct sn_softc *sc = ifp->if_softc; 361121589Simp SN_LOCK(sc); 362121589Simp snstart_locked(ifp); 363121589Simp SN_UNLOCK(sc); 36454773Simp} 36554773Simp 36654773Simp 367121589Simpstatic void 368121589Simpsnstart_locked(struct ifnet *ifp) 36954773Simp{ 370121553Simp struct sn_softc *sc = ifp->if_softc; 371121589Simp u_int len; 372121589Simp struct mbuf *m; 373121589Simp struct mbuf *top; 374121589Simp int pad; 37554773Simp int mask; 376121589Simp uint16_t length; 377121589Simp uint16_t numPages; 378121589Simp uint8_t packet_no; 37954773Simp int time_out; 38066058Simp int junk = 0; 38154773Simp 382121589Simp SN_ASSERT_LOCKED(sc); 38354773Simp 384147256Sbrooks if (sc->ifp->if_flags & IFF_OACTIVE) 38554773Simp return; 38654773Simp if (sc->pages_wanted != -1) { 387104257Sbrooks if_printf(ifp, "snstart() while memory allocation pending\n"); 38854773Simp return; 38954773Simp } 39054773Simpstartagain: 39154773Simp 39254773Simp /* 39354773Simp * Sneak a peek at the next packet 39454773Simp */ 395147256Sbrooks m = sc->ifp->if_snd.ifq_head; 396121589Simp if (m == 0) 39754773Simp return; 39854773Simp /* 39954773Simp * Compute the frame length and set pad to give an overall even 40054773Simp * number of bytes. Below we assume that the packet length is even. 40154773Simp */ 40254773Simp for (len = 0, top = m; m; m = m->m_next) 40354773Simp len += m->m_len; 40454773Simp 40554773Simp pad = (len & 1); 40654773Simp 40754773Simp /* 40854773Simp * We drop packets that are too large. Perhaps we should truncate 40954773Simp * them instead? 41054773Simp */ 41154773Simp if (len + pad > ETHER_MAX_LEN - ETHER_CRC_LEN) { 412104257Sbrooks if_printf(ifp, "large packet discarded (A)\n"); 413147256Sbrooks ++sc->ifp->if_oerrors; 414147256Sbrooks IF_DEQUEUE(&sc->ifp->if_snd, m); 41554773Simp m_freem(m); 41654773Simp goto readcheck; 41754773Simp } 41854773Simp#ifdef SW_PAD 41954773Simp 42054773Simp /* 42154773Simp * If HW padding is not turned on, then pad to ETHER_MIN_LEN. 42254773Simp */ 42354773Simp if (len < ETHER_MIN_LEN - ETHER_CRC_LEN) 42454773Simp pad = ETHER_MIN_LEN - ETHER_CRC_LEN - len; 42554773Simp 42654773Simp#endif /* SW_PAD */ 42754773Simp 42854773Simp length = pad + len; 42954773Simp 43054773Simp /* 43154773Simp * The MMU wants the number of pages to be the number of 256 byte 43254773Simp * 'pages', minus 1 (A packet can't ever have 0 pages. We also 43354773Simp * include space for the status word, byte count and control bytes in 43454773Simp * the allocation request. 43554773Simp */ 43654773Simp numPages = (length + 6) >> 8; 43754773Simp 43854773Simp 43954773Simp /* 44054773Simp * Now, try to allocate the memory 44154773Simp */ 442121514Simp SMC_SELECT_BANK(sc, 2); 443121514Simp CSR_WRITE_2(sc, MMU_CMD_REG_W, MMUCR_ALLOC | numPages); 44454773Simp 44554773Simp /* 44654773Simp * Wait a short amount of time to see if the allocation request 44754773Simp * completes. Otherwise, I enable the interrupt and wait for 44854773Simp * completion asyncronously. 44954773Simp */ 45054773Simp 45154773Simp time_out = MEMORY_WAIT_TIME; 45254773Simp do { 453121514Simp if (CSR_READ_1(sc, INTR_STAT_REG_B) & IM_ALLOC_INT) 45454773Simp break; 45554773Simp } while (--time_out); 45654773Simp 45766058Simp if (!time_out || junk > 10) { 45854773Simp 45954773Simp /* 46054773Simp * No memory now. Oh well, wait until the chip finds memory 46154773Simp * later. Remember how many pages we were asking for and 46254773Simp * enable the allocation completion interrupt. Also set a 46354773Simp * watchdog in case we miss the interrupt. We mark the 46454773Simp * interface active since there is no point in attempting an 46554773Simp * snstart() until after the memory is available. 46654773Simp */ 467121514Simp mask = CSR_READ_1(sc, INTR_MASK_REG_B) | IM_ALLOC_INT; 468121514Simp CSR_WRITE_1(sc, INTR_MASK_REG_B, mask); 46954773Simp sc->intr_mask = mask; 47054773Simp 471147256Sbrooks sc->ifp->if_timer = 1; 472147256Sbrooks sc->ifp->if_flags |= IFF_OACTIVE; 47354773Simp sc->pages_wanted = numPages; 47454773Simp return; 47554773Simp } 47654773Simp /* 47754773Simp * The memory allocation completed. Check the results. 47854773Simp */ 479121514Simp packet_no = CSR_READ_1(sc, ALLOC_RESULT_REG_B); 48054773Simp if (packet_no & ARR_FAILED) { 48166058Simp if (junk++ > 10) 482104257Sbrooks if_printf(ifp, "Memory allocation failed\n"); 48354773Simp goto startagain; 48454773Simp } 48554773Simp /* 48654773Simp * We have a packet number, so tell the card to use it. 48754773Simp */ 488121514Simp CSR_WRITE_1(sc, PACKET_NUM_REG_B, packet_no); 48954773Simp 49054773Simp /* 49154773Simp * Point to the beginning of the packet 49254773Simp */ 493121514Simp CSR_WRITE_2(sc, POINTER_REG_W, PTR_AUTOINC | 0x0000); 49454773Simp 49554773Simp /* 49654773Simp * Send the packet length (+6 for status, length and control byte) 49754773Simp * and the status word (set to zeros) 49854773Simp */ 499121514Simp CSR_WRITE_2(sc, DATA_REG_W, 0); 500121514Simp CSR_WRITE_1(sc, DATA_REG_B, (length + 6) & 0xFF); 501121514Simp CSR_WRITE_1(sc, DATA_REG_B, (length + 6) >> 8); 50254773Simp 50354773Simp /* 50454773Simp * Get the packet from the kernel. This will include the Ethernet 50554773Simp * frame header, MAC Addresses etc. 50654773Simp */ 507147256Sbrooks IF_DEQUEUE(&sc->ifp->if_snd, m); 50854773Simp 50954773Simp /* 51054773Simp * Push out the data to the card. 51154773Simp */ 51254773Simp for (top = m; m != 0; m = m->m_next) { 51354773Simp 51454773Simp /* 51554773Simp * Push out words. 51654773Simp */ 517121514Simp CSR_WRITE_MULTI_2(sc, DATA_REG_W, mtod(m, uint16_t *), 518121514Simp m->m_len / 2); 51954773Simp 52054773Simp /* 52154773Simp * Push out remaining byte. 52254773Simp */ 52354773Simp if (m->m_len & 1) 524121514Simp CSR_WRITE_1(sc, DATA_REG_B, 525121514Simp *(mtod(m, caddr_t) + m->m_len - 1)); 52654773Simp } 52754773Simp 52854773Simp /* 52954773Simp * Push out padding. 53054773Simp */ 53154773Simp while (pad > 1) { 532121514Simp CSR_WRITE_2(sc, DATA_REG_W, 0); 53354773Simp pad -= 2; 53454773Simp } 53554773Simp if (pad) 536121514Simp CSR_WRITE_1(sc, DATA_REG_B, 0); 53754773Simp 53854773Simp /* 53954773Simp * Push out control byte and unused packet byte The control byte is 0 54054773Simp * meaning the packet is even lengthed and no special CRC handling is 54154773Simp * desired. 54254773Simp */ 543121514Simp CSR_WRITE_2(sc, DATA_REG_W, 0); 54454773Simp 54554773Simp /* 54654773Simp * Enable the interrupts and let the chipset deal with it Also set a 54754773Simp * watchdog in case we miss the interrupt. 54854773Simp */ 549121514Simp mask = CSR_READ_1(sc, INTR_MASK_REG_B) | (IM_TX_INT | IM_TX_EMPTY_INT); 550121514Simp CSR_WRITE_1(sc, INTR_MASK_REG_B, mask); 55154773Simp sc->intr_mask = mask; 55254773Simp 553121514Simp CSR_WRITE_2(sc, MMU_CMD_REG_W, MMUCR_ENQUEUE); 55454773Simp 555147256Sbrooks sc->ifp->if_flags |= IFF_OACTIVE; 556147256Sbrooks sc->ifp->if_timer = 1; 55754773Simp 558106937Ssam BPF_MTAP(ifp, top); 55954773Simp 560147256Sbrooks sc->ifp->if_opackets++; 56154773Simp m_freem(top); 56254773Simp 56354773Simp 56454773Simpreadcheck: 56554773Simp 56654773Simp /* 56754773Simp * Is another packet coming in? We don't want to overflow the tiny 56854773Simp * RX FIFO. If nothing has arrived then attempt to queue another 56954773Simp * transmit packet. 57054773Simp */ 571121514Simp if (CSR_READ_2(sc, FIFO_PORTS_REG_W) & FIFO_REMPTY) 57254773Simp goto startagain; 57354773Simp return; 57454773Simp} 57554773Simp 57654773Simp 57754773Simp 57854773Simp/* Resume a packet transmit operation after a memory allocation 57954773Simp * has completed. 58054773Simp * 58154773Simp * This is basically a hacked up copy of snstart() which handles 58254773Simp * a completed memory allocation the same way snstart() does. 58354773Simp * It then passes control to snstart to handle any other queued 58454773Simp * packets. 58554773Simp */ 58654773Simpstatic void 58754773Simpsnresume(struct ifnet *ifp) 58854773Simp{ 589121553Simp struct sn_softc *sc = ifp->if_softc; 590121589Simp u_int len; 591121589Simp struct mbuf *m; 59254773Simp struct mbuf *top; 59354773Simp int pad; 59454773Simp int mask; 595121589Simp uint16_t length; 596121589Simp uint16_t numPages; 597121589Simp uint16_t pages_wanted; 598121589Simp uint8_t packet_no; 59954773Simp 60054773Simp if (sc->pages_wanted < 0) 60154773Simp return; 60254773Simp 60354773Simp pages_wanted = sc->pages_wanted; 60454773Simp sc->pages_wanted = -1; 60554773Simp 60654773Simp /* 60754773Simp * Sneak a peek at the next packet 60854773Simp */ 609147256Sbrooks m = sc->ifp->if_snd.ifq_head; 61054773Simp if (m == 0) { 611104257Sbrooks if_printf(ifp, "snresume() with nothing to send\n"); 61254773Simp return; 61354773Simp } 61454773Simp /* 61554773Simp * Compute the frame length and set pad to give an overall even 61654773Simp * number of bytes. Below we assume that the packet length is even. 61754773Simp */ 61854773Simp for (len = 0, top = m; m; m = m->m_next) 61954773Simp len += m->m_len; 62054773Simp 62154773Simp pad = (len & 1); 62254773Simp 62354773Simp /* 62454773Simp * We drop packets that are too large. Perhaps we should truncate 62554773Simp * them instead? 62654773Simp */ 62754773Simp if (len + pad > ETHER_MAX_LEN - ETHER_CRC_LEN) { 628104257Sbrooks if_printf(ifp, "large packet discarded (B)\n"); 629147256Sbrooks ++sc->ifp->if_oerrors; 630147256Sbrooks IF_DEQUEUE(&sc->ifp->if_snd, m); 63154773Simp m_freem(m); 63254773Simp return; 63354773Simp } 63454773Simp#ifdef SW_PAD 63554773Simp 63654773Simp /* 63754773Simp * If HW padding is not turned on, then pad to ETHER_MIN_LEN. 63854773Simp */ 63954773Simp if (len < ETHER_MIN_LEN - ETHER_CRC_LEN) 64054773Simp pad = ETHER_MIN_LEN - ETHER_CRC_LEN - len; 64154773Simp 64254773Simp#endif /* SW_PAD */ 64354773Simp 64454773Simp length = pad + len; 64554773Simp 64654773Simp 64754773Simp /* 64854773Simp * The MMU wants the number of pages to be the number of 256 byte 64954773Simp * 'pages', minus 1 (A packet can't ever have 0 pages. We also 65054773Simp * include space for the status word, byte count and control bytes in 65154773Simp * the allocation request. 65254773Simp */ 65354773Simp numPages = (length + 6) >> 8; 65454773Simp 65554773Simp 656121514Simp SMC_SELECT_BANK(sc, 2); 65754773Simp 65854773Simp /* 65954773Simp * The memory allocation completed. Check the results. If it failed, 66054773Simp * we simply set a watchdog timer and hope for the best. 66154773Simp */ 662121514Simp packet_no = CSR_READ_1(sc, ALLOC_RESULT_REG_B); 66354773Simp if (packet_no & ARR_FAILED) { 664104257Sbrooks if_printf(ifp, "Memory allocation failed. Weird.\n"); 665147256Sbrooks sc->ifp->if_timer = 1; 66654773Simp goto try_start; 66754773Simp } 66854773Simp /* 66954773Simp * We have a packet number, so tell the card to use it. 67054773Simp */ 671121514Simp CSR_WRITE_1(sc, PACKET_NUM_REG_B, packet_no); 67254773Simp 67354773Simp /* 67454773Simp * Now, numPages should match the pages_wanted recorded when the 67554773Simp * memory allocation was initiated. 67654773Simp */ 67754773Simp if (pages_wanted != numPages) { 678104257Sbrooks if_printf(ifp, "memory allocation wrong size. Weird.\n"); 67954773Simp /* 68054773Simp * If the allocation was the wrong size we simply release the 68154773Simp * memory once it is granted. Wait for the MMU to be un-busy. 68254773Simp */ 683121514Simp while (CSR_READ_2(sc, MMU_CMD_REG_W) & MMUCR_BUSY) /* NOTHING */ 68454773Simp ; 685121514Simp CSR_WRITE_2(sc, MMU_CMD_REG_W, MMUCR_FREEPKT); 68654773Simp 68754773Simp return; 68854773Simp } 68954773Simp /* 69054773Simp * Point to the beginning of the packet 69154773Simp */ 692121514Simp CSR_WRITE_2(sc, POINTER_REG_W, PTR_AUTOINC | 0x0000); 69354773Simp 69454773Simp /* 69554773Simp * Send the packet length (+6 for status, length and control byte) 69654773Simp * and the status word (set to zeros) 69754773Simp */ 698121514Simp CSR_WRITE_2(sc, DATA_REG_W, 0); 699121514Simp CSR_WRITE_1(sc, DATA_REG_B, (length + 6) & 0xFF); 700121514Simp CSR_WRITE_1(sc, DATA_REG_B, (length + 6) >> 8); 70154773Simp 70254773Simp /* 70354773Simp * Get the packet from the kernel. This will include the Ethernet 70454773Simp * frame header, MAC Addresses etc. 70554773Simp */ 706147256Sbrooks IF_DEQUEUE(&sc->ifp->if_snd, m); 70754773Simp 70854773Simp /* 70954773Simp * Push out the data to the card. 71054773Simp */ 71154773Simp for (top = m; m != 0; m = m->m_next) { 71254773Simp 71354773Simp /* 71454773Simp * Push out words. 71554773Simp */ 716121514Simp CSR_WRITE_MULTI_2(sc, DATA_REG_W, mtod(m, uint16_t *), 717121514Simp m->m_len / 2); 71854773Simp /* 71954773Simp * Push out remaining byte. 72054773Simp */ 72154773Simp if (m->m_len & 1) 722121514Simp CSR_WRITE_1(sc, DATA_REG_B, 723121514Simp *(mtod(m, caddr_t) + m->m_len - 1)); 72454773Simp } 72554773Simp 72654773Simp /* 72754773Simp * Push out padding. 72854773Simp */ 72954773Simp while (pad > 1) { 730121514Simp CSR_WRITE_2(sc, DATA_REG_W, 0); 73154773Simp pad -= 2; 73254773Simp } 73354773Simp if (pad) 734121514Simp CSR_WRITE_1(sc, DATA_REG_B, 0); 73554773Simp 73654773Simp /* 73754773Simp * Push out control byte and unused packet byte The control byte is 0 73854773Simp * meaning the packet is even lengthed and no special CRC handling is 73954773Simp * desired. 74054773Simp */ 741121514Simp CSR_WRITE_2(sc, DATA_REG_W, 0); 74254773Simp 74354773Simp /* 74454773Simp * Enable the interrupts and let the chipset deal with it Also set a 74554773Simp * watchdog in case we miss the interrupt. 74654773Simp */ 747121514Simp mask = CSR_READ_1(sc, INTR_MASK_REG_B) | (IM_TX_INT | IM_TX_EMPTY_INT); 748121514Simp CSR_WRITE_1(sc, INTR_MASK_REG_B, mask); 74954773Simp sc->intr_mask = mask; 750121514Simp CSR_WRITE_2(sc, MMU_CMD_REG_W, MMUCR_ENQUEUE); 75154773Simp 752106937Ssam BPF_MTAP(ifp, top); 75354773Simp 754147256Sbrooks sc->ifp->if_opackets++; 75554773Simp m_freem(top); 75654773Simp 75754773Simptry_start: 75854773Simp 75954773Simp /* 76054773Simp * Now pass control to snstart() to queue any additional packets 76154773Simp */ 762147256Sbrooks sc->ifp->if_flags &= ~IFF_OACTIVE; 76354773Simp snstart(ifp); 76454773Simp 76554773Simp /* 76654773Simp * We've sent something, so we're active. Set a watchdog in case the 76754773Simp * TX_EMPTY interrupt is lost. 76854773Simp */ 769147256Sbrooks sc->ifp->if_flags |= IFF_OACTIVE; 770147256Sbrooks sc->ifp->if_timer = 1; 77154773Simp 77254773Simp return; 77354773Simp} 77454773Simp 77554773Simp 77654773Simpvoid 77754994Simpsn_intr(void *arg) 77854773Simp{ 77954773Simp int status, interrupts; 780121553Simp struct sn_softc *sc = (struct sn_softc *) arg; 781147256Sbrooks struct ifnet *ifp = sc->ifp; 78254773Simp 78354773Simp /* 78454773Simp * Chip state registers 78554773Simp */ 786121589Simp uint8_t mask; 787121589Simp uint8_t packet_no; 788121589Simp uint16_t tx_status; 789121589Simp uint16_t card_stats; 79054773Simp 791121589Simp SN_LOCK(sc); 79254773Simp 79354773Simp /* 79454773Simp * Clear the watchdog. 79554773Simp */ 79654773Simp ifp->if_timer = 0; 79754773Simp 798121514Simp SMC_SELECT_BANK(sc, 2); 79954773Simp 80054773Simp /* 80154773Simp * Obtain the current interrupt mask and clear the hardware mask 80254773Simp * while servicing interrupts. 80354773Simp */ 804121514Simp mask = CSR_READ_1(sc, INTR_MASK_REG_B); 805121514Simp CSR_WRITE_1(sc, INTR_MASK_REG_B, 0x00); 80654773Simp 80754773Simp /* 80854773Simp * Get the set of interrupts which occurred and eliminate any which 80954773Simp * are masked. 81054773Simp */ 811121514Simp interrupts = CSR_READ_1(sc, INTR_STAT_REG_B); 81254773Simp status = interrupts & mask; 81354773Simp 81454773Simp /* 81554773Simp * Now, process each of the interrupt types. 81654773Simp */ 81754773Simp 81854773Simp /* 81954773Simp * Receive Overrun. 82054773Simp */ 82154773Simp if (status & IM_RX_OVRN_INT) { 82254773Simp /* 82354773Simp * Acknowlege Interrupt 82454773Simp */ 825121514Simp SMC_SELECT_BANK(sc, 2); 826121514Simp CSR_WRITE_1(sc, INTR_ACK_REG_B, IM_RX_OVRN_INT); 82754773Simp 828147256Sbrooks ++sc->ifp->if_ierrors; 82954773Simp } 83054773Simp /* 83154773Simp * Got a packet. 83254773Simp */ 83354773Simp if (status & IM_RCV_INT) { 83454773Simp int packet_number; 83554773Simp 836121514Simp SMC_SELECT_BANK(sc, 2); 837121514Simp packet_number = CSR_READ_2(sc, FIFO_PORTS_REG_W); 83854773Simp 83954773Simp if (packet_number & FIFO_REMPTY) { 84054773Simp /* 84154773Simp * we got called , but nothing was on the FIFO 84254773Simp */ 84354773Simp printf("sn: Receive interrupt with nothing on FIFO\n"); 84454773Simp goto out; 84554773Simp } 84654773Simp snread(ifp); 84754773Simp } 84854773Simp /* 84954773Simp * An on-card memory allocation came through. 85054773Simp */ 85154773Simp if (status & IM_ALLOC_INT) { 85254773Simp /* 85354773Simp * Disable this interrupt. 85454773Simp */ 85554773Simp mask &= ~IM_ALLOC_INT; 856147256Sbrooks sc->ifp->if_flags &= ~IFF_OACTIVE; 857147256Sbrooks snresume(sc->ifp); 85854773Simp } 85954773Simp /* 86054773Simp * TX Completion. Handle a transmit error message. This will only be 86154773Simp * called when there is an error, because of the AUTO_RELEASE mode. 86254773Simp */ 86354773Simp if (status & IM_TX_INT) { 86454773Simp /* 86554773Simp * Acknowlege Interrupt 86654773Simp */ 867121514Simp SMC_SELECT_BANK(sc, 2); 868121514Simp CSR_WRITE_1(sc, INTR_ACK_REG_B, IM_TX_INT); 86954773Simp 870121514Simp packet_no = CSR_READ_2(sc, FIFO_PORTS_REG_W); 87154773Simp packet_no &= FIFO_TX_MASK; 87254773Simp 87354773Simp /* 87454773Simp * select this as the packet to read from 87554773Simp */ 876121514Simp CSR_WRITE_1(sc, PACKET_NUM_REG_B, packet_no); 87754773Simp 87854773Simp /* 87954773Simp * Position the pointer to the first word from this packet 88054773Simp */ 881121514Simp CSR_WRITE_2(sc, POINTER_REG_W, PTR_AUTOINC | PTR_READ | 0x0000); 88254773Simp 88354773Simp /* 88454773Simp * Fetch the TX status word. The value found here will be a 88554773Simp * copy of the EPH_STATUS_REG_W at the time the transmit 88654773Simp * failed. 88754773Simp */ 888121514Simp tx_status = CSR_READ_2(sc, DATA_REG_W); 88954773Simp 89054773Simp if (tx_status & EPHSR_TX_SUC) { 89154994Simp device_printf(sc->dev, 89254994Simp "Successful packet caused interrupt\n"); 89354773Simp } else { 894147256Sbrooks ++sc->ifp->if_oerrors; 89554773Simp } 89654773Simp 89754773Simp if (tx_status & EPHSR_LATCOL) 898147256Sbrooks ++sc->ifp->if_collisions; 89954773Simp 90054773Simp /* 90154773Simp * Some of these errors will have disabled transmit. 90254773Simp * Re-enable transmit now. 90354773Simp */ 904121514Simp SMC_SELECT_BANK(sc, 0); 90554773Simp 90654773Simp#ifdef SW_PAD 907121514Simp CSR_WRITE_2(sc, TXMIT_CONTROL_REG_W, TCR_ENABLE); 90854773Simp#else 909121514Simp CSR_WRITE_2(sc, TXMIT_CONTROL_REG_W, TCR_ENABLE | TCR_PAD_ENABLE); 91054773Simp#endif /* SW_PAD */ 91154773Simp 91254773Simp /* 91354773Simp * kill the failed packet. Wait for the MMU to be un-busy. 91454773Simp */ 915121514Simp SMC_SELECT_BANK(sc, 2); 916121514Simp while (CSR_READ_2(sc, MMU_CMD_REG_W) & MMUCR_BUSY) /* NOTHING */ 91754773Simp ; 918121514Simp CSR_WRITE_2(sc, MMU_CMD_REG_W, MMUCR_FREEPKT); 91954773Simp 92054773Simp /* 92154773Simp * Attempt to queue more transmits. 92254773Simp */ 923147256Sbrooks sc->ifp->if_flags &= ~IFF_OACTIVE; 924147256Sbrooks snstart_locked(sc->ifp); 92554773Simp } 92654773Simp /* 92754773Simp * Transmit underrun. We use this opportunity to update transmit 92854773Simp * statistics from the card. 92954773Simp */ 93054773Simp if (status & IM_TX_EMPTY_INT) { 93154773Simp 93254773Simp /* 93354773Simp * Acknowlege Interrupt 93454773Simp */ 935121514Simp SMC_SELECT_BANK(sc, 2); 936121514Simp CSR_WRITE_1(sc, INTR_ACK_REG_B, IM_TX_EMPTY_INT); 93754773Simp 93854773Simp /* 93954773Simp * Disable this interrupt. 94054773Simp */ 94154773Simp mask &= ~IM_TX_EMPTY_INT; 94254773Simp 943121514Simp SMC_SELECT_BANK(sc, 0); 944121514Simp card_stats = CSR_READ_2(sc, COUNTER_REG_W); 94554773Simp 94654773Simp /* 94754773Simp * Single collisions 94854773Simp */ 949147256Sbrooks sc->ifp->if_collisions += card_stats & ECR_COLN_MASK; 95054773Simp 95154773Simp /* 95254773Simp * Multiple collisions 95354773Simp */ 954147256Sbrooks sc->ifp->if_collisions += (card_stats & ECR_MCOLN_MASK) >> 4; 95554773Simp 956121514Simp SMC_SELECT_BANK(sc, 2); 95754773Simp 95854773Simp /* 95954773Simp * Attempt to enqueue some more stuff. 96054773Simp */ 961147256Sbrooks sc->ifp->if_flags &= ~IFF_OACTIVE; 962147256Sbrooks snstart_locked(sc->ifp); 96354773Simp } 96454773Simp /* 96554773Simp * Some other error. Try to fix it by resetting the adapter. 96654773Simp */ 96754773Simp if (status & IM_EPH_INT) { 96854994Simp snstop(sc); 969121589Simp sninit_locked(sc); 97054773Simp } 97154773Simp 97254773Simpout: 97354773Simp /* 97454773Simp * Handled all interrupt sources. 97554773Simp */ 97654773Simp 977121514Simp SMC_SELECT_BANK(sc, 2); 97854773Simp 97954773Simp /* 98054773Simp * Reestablish interrupts from mask which have not been deselected 98154773Simp * during this interrupt. Note that the hardware mask, which was set 98254773Simp * to 0x00 at the start of this service routine, may have been 98354773Simp * updated by one or more of the interrupt handers and we must let 98454773Simp * those new interrupts stay enabled here. 98554773Simp */ 986121514Simp mask |= CSR_READ_1(sc, INTR_MASK_REG_B); 987121514Simp CSR_WRITE_1(sc, INTR_MASK_REG_B, mask); 98854773Simp sc->intr_mask = mask; 989121589Simp SN_UNLOCK(sc); 99054773Simp} 99154773Simp 992121589Simpstatic void 993121553Simpsnread(struct ifnet *ifp) 99454773Simp{ 99554994Simp struct sn_softc *sc = ifp->if_softc; 99654773Simp struct ether_header *eh; 99754773Simp struct mbuf *m; 99854773Simp short status; 99954773Simp int packet_number; 1000121589Simp uint16_t packet_length; 1001121589Simp uint8_t *data; 100254773Simp 1003121514Simp SMC_SELECT_BANK(sc, 2); 100454773Simp#if 0 1005121514Simp packet_number = CSR_READ_2(sc, FIFO_PORTS_REG_W); 100654773Simp 100754773Simp if (packet_number & FIFO_REMPTY) { 100854773Simp 100954773Simp /* 101054773Simp * we got called , but nothing was on the FIFO 101154773Simp */ 101254773Simp printf("sn: Receive interrupt with nothing on FIFO\n"); 101354773Simp return; 101454773Simp } 101554773Simp#endif 101654773Simpread_another: 101754773Simp 101854773Simp /* 101954773Simp * Start reading from the start of the packet. Since PTR_RCV is set, 102054773Simp * packet number is found in FIFO_PORTS_REG_W, FIFO_RX_MASK. 102154773Simp */ 1022121514Simp CSR_WRITE_2(sc, POINTER_REG_W, PTR_READ | PTR_RCV | PTR_AUTOINC | 0x0000); 102354773Simp 102454773Simp /* 102554773Simp * First two words are status and packet_length 102654773Simp */ 1027121514Simp status = CSR_READ_2(sc, DATA_REG_W); 1028121514Simp packet_length = CSR_READ_2(sc, DATA_REG_W) & RLEN_MASK; 102954773Simp 103054773Simp /* 103154773Simp * The packet length contains 3 extra words: status, length, and a 103254773Simp * extra word with the control byte. 103354773Simp */ 103454773Simp packet_length -= 6; 103554773Simp 103654773Simp /* 103754773Simp * Account for receive errors and discard. 103854773Simp */ 103954773Simp if (status & RS_ERRORS) { 1040147256Sbrooks ++sc->ifp->if_ierrors; 104154773Simp goto out; 104254773Simp } 104354773Simp /* 104454773Simp * A packet is received. 104554773Simp */ 104654773Simp 104754773Simp /* 104854773Simp * Adjust for odd-length packet. 104954773Simp */ 105054773Simp if (status & RS_ODDFRAME) 105154773Simp packet_length++; 105254773Simp 105354773Simp /* 105454773Simp * Allocate a header mbuf from the kernel. 105554773Simp */ 1056111119Simp MGETHDR(m, M_DONTWAIT, MT_DATA); 105754773Simp if (m == NULL) 105854773Simp goto out; 105954773Simp 1060147256Sbrooks m->m_pkthdr.rcvif = sc->ifp; 106154773Simp m->m_pkthdr.len = m->m_len = packet_length; 106254773Simp 106354773Simp /* 106454773Simp * Attach an mbuf cluster 106554773Simp */ 1066111119Simp MCLGET(m, M_DONTWAIT); 106754773Simp 106854773Simp /* 106954773Simp * Insist on getting a cluster 107054773Simp */ 107154773Simp if ((m->m_flags & M_EXT) == 0) { 107254773Simp m_freem(m); 1073147256Sbrooks ++sc->ifp->if_ierrors; 107454773Simp printf("sn: snread() kernel memory allocation problem\n"); 107554773Simp goto out; 107654773Simp } 107754773Simp eh = mtod(m, struct ether_header *); 107854773Simp 107954773Simp /* 108054773Simp * Get packet, including link layer address, from interface. 108154773Simp */ 1082121589Simp data = (uint8_t *) eh; 1083121514Simp CSR_READ_MULTI_2(sc, DATA_REG_W, (uint16_t *) data, packet_length >> 1); 108454773Simp if (packet_length & 1) { 108554773Simp data += packet_length & ~1; 1086121514Simp *data = CSR_READ_1(sc, DATA_REG_B); 108754773Simp } 1088147256Sbrooks ++sc->ifp->if_ipackets; 108954773Simp 109054773Simp /* 109154773Simp * Remove link layer addresses and whatnot. 109254773Simp */ 1093106937Ssam m->m_pkthdr.len = m->m_len = packet_length; 109454773Simp 1095121589Simp /* 1096121589Simp * Drop locks before calling if_input() since it may re-enter 1097121589Simp * snstart() in the netisr case. This would result in a 1098121589Simp * lock reversal. Better performance might be obtained by 1099121589Simp * chaining all packets received, dropping the lock, and then 1100121589Simp * calling if_input() on each one. 1101121589Simp */ 1102121589Simp SN_UNLOCK(sc); 1103106937Ssam (*ifp->if_input)(ifp, m); 1104121589Simp SN_LOCK(sc); 110554773Simp 110654773Simpout: 110754773Simp 110854773Simp /* 110954773Simp * Error or good, tell the card to get rid of this packet Wait for 111054773Simp * the MMU to be un-busy. 111154773Simp */ 1112121514Simp SMC_SELECT_BANK(sc, 2); 1113121514Simp while (CSR_READ_2(sc, MMU_CMD_REG_W) & MMUCR_BUSY) /* NOTHING */ 111454773Simp ; 1115121514Simp CSR_WRITE_2(sc, MMU_CMD_REG_W, MMUCR_RELEASE); 111654773Simp 111754773Simp /* 111854773Simp * Check whether another packet is ready 111954773Simp */ 1120121514Simp packet_number = CSR_READ_2(sc, FIFO_PORTS_REG_W); 112154773Simp if (packet_number & FIFO_REMPTY) { 112254773Simp return; 112354773Simp } 112454773Simp goto read_another; 112554773Simp} 112654773Simp 112754773Simp 112854773Simp/* 112954773Simp * Handle IOCTLS. This function is completely stolen from if_ep.c 113054773Simp * As with its progenitor, it does not handle hardware address 113154773Simp * changes. 113254773Simp */ 113354773Simpstatic int 1134121553Simpsnioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 113554773Simp{ 113654994Simp struct sn_softc *sc = ifp->if_softc; 1137121589Simp int error = 0; 113854773Simp 113954773Simp switch (cmd) { 114054773Simp case SIOCSIFFLAGS: 1141121589Simp SN_LOCK(sc); 114254773Simp if ((ifp->if_flags & IFF_UP) == 0 && ifp->if_flags & IFF_RUNNING) { 114354773Simp ifp->if_flags &= ~IFF_RUNNING; 114454994Simp snstop(sc); 114554773Simp } else { 114654773Simp /* reinitialize card on any parameter change */ 1147121589Simp sninit_locked(sc); 114854773Simp } 1149121589Simp SN_UNLOCK(sc); 115054773Simp break; 115154773Simp 115254773Simp#ifdef notdef 115354773Simp case SIOCGHWADDR: 115454773Simp bcopy((caddr_t) sc->sc_addr, (caddr_t) & ifr->ifr_data, 115554773Simp sizeof(sc->sc_addr)); 115654773Simp break; 115754773Simp#endif 115854773Simp 115954773Simp case SIOCADDMULTI: 1160121589Simp /* update multicast filter list. */ 1161121589Simp SN_LOCK(sc); 1162121589Simp sn_setmcast(sc); 1163121589Simp error = 0; 1164121589Simp SN_UNLOCK(sc); 1165121589Simp break; 116654773Simp case SIOCDELMULTI: 1167121589Simp /* update multicast filter list. */ 1168121589Simp SN_LOCK(sc); 1169121589Simp sn_setmcast(sc); 1170121589Simp error = 0; 1171121589Simp SN_UNLOCK(sc); 1172121589Simp break; 117354773Simp default: 117454773Simp error = EINVAL; 1175106937Ssam error = ether_ioctl(ifp, cmd, data); 1176106937Ssam break; 117754773Simp } 117854773Simp return (error); 117954773Simp} 118054773Simp 1181121589Simpstatic void 118254773Simpsnwatchdog(struct ifnet *ifp) 118354773Simp{ 118454994Simp sn_intr(ifp->if_softc); 118554773Simp} 118654773Simp 118754773Simp 118854773Simp/* 1. zero the interrupt mask 118954773Simp * 2. clear the enable receive flag 119054773Simp * 3. clear the enable xmit flags 119154773Simp */ 1192121589Simpstatic void 119354994Simpsnstop(struct sn_softc *sc) 119454773Simp{ 119554994Simp 1196147256Sbrooks struct ifnet *ifp = sc->ifp; 119754773Simp 119854773Simp /* 119954773Simp * Clear interrupt mask; disable all interrupts. 120054773Simp */ 1201121514Simp SMC_SELECT_BANK(sc, 2); 1202121514Simp CSR_WRITE_1(sc, INTR_MASK_REG_B, 0x00); 120354773Simp 120454773Simp /* 120554773Simp * Disable transmitter and Receiver 120654773Simp */ 1207121514Simp SMC_SELECT_BANK(sc, 0); 1208121514Simp CSR_WRITE_2(sc, RECV_CONTROL_REG_W, 0x0000); 1209121514Simp CSR_WRITE_2(sc, TXMIT_CONTROL_REG_W, 0x0000); 121054773Simp 121154773Simp /* 121254773Simp * Cancel watchdog. 121354773Simp */ 121454773Simp ifp->if_timer = 0; 121554773Simp} 121654773Simp 121754773Simp 121854994Simpint 121954994Simpsn_activate(device_t dev) 122054994Simp{ 122154994Simp struct sn_softc *sc = device_get_softc(dev); 122254773Simp 122354994Simp sc->port_rid = 0; 122454994Simp sc->port_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->port_rid, 122554994Simp 0, ~0, SMC_IO_EXTENT, RF_ACTIVE); 122654994Simp if (!sc->port_res) { 122766058Simp if (bootverbose) 122866058Simp device_printf(dev, "Cannot allocate ioport\n"); 122954994Simp return ENOMEM; 123054994Simp } 123154994Simp 123254994Simp sc->irq_rid = 0; 1233127135Snjl sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid, 1234127135Snjl RF_ACTIVE); 123554994Simp if (!sc->irq_res) { 123666058Simp if (bootverbose) 123766058Simp device_printf(dev, "Cannot allocate irq\n"); 123854994Simp sn_deactivate(dev); 123954994Simp return ENOMEM; 124054994Simp } 1241121514Simp sc->bst = rman_get_bustag(sc->port_res); 1242121514Simp sc->bsh = rman_get_bushandle(sc->port_res); 124354994Simp return (0); 124454994Simp} 124554994Simp 124654994Simpvoid 124754994Simpsn_deactivate(device_t dev) 124854994Simp{ 124954994Simp struct sn_softc *sc = device_get_softc(dev); 125054994Simp 125154994Simp if (sc->intrhand) 125254994Simp bus_teardown_intr(dev, sc->irq_res, sc->intrhand); 125354994Simp sc->intrhand = 0; 125454994Simp if (sc->port_res) 125554994Simp bus_release_resource(dev, SYS_RES_IOPORT, sc->port_rid, 125654994Simp sc->port_res); 125754994Simp sc->port_res = 0; 125854994Simp if (sc->irq_res) 125954994Simp bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, 126054994Simp sc->irq_res); 126154994Simp sc->irq_res = 0; 126254994Simp return; 126354994Simp} 126454994Simp 126554773Simp/* 126654994Simp * Function: sn_probe( device_t dev, int pccard ) 126754773Simp * 126854773Simp * Purpose: 126954773Simp * Tests to see if a given ioaddr points to an SMC9xxx chip. 127054773Simp * Tries to cause as little damage as possible if it's not a SMC chip. 127154773Simp * Returns a 0 on success 127254773Simp * 127354773Simp * Algorithm: 127454773Simp * (1) see if the high byte of BANK_SELECT is 0x33 127554773Simp * (2) compare the ioaddr with the base register's address 127654773Simp * (3) see if I recognize the chip ID in the appropriate register 127754773Simp * 127854773Simp * 127954773Simp */ 128054994Simpint 128154994Simpsn_probe(device_t dev, int pccard) 128254773Simp{ 128354994Simp struct sn_softc *sc = device_get_softc(dev); 1284121589Simp uint16_t bank; 1285121589Simp uint16_t revision_register; 1286121589Simp uint16_t base_address_register; 128754994Simp int err; 128854773Simp 128954994Simp if ((err = sn_activate(dev)) != 0) 129054994Simp return err; 129154994Simp 129254773Simp /* 129354773Simp * First, see if the high byte is 0x33 129454773Simp */ 1295121514Simp bank = CSR_READ_2(sc, BANK_SELECT_REG_W); 129654773Simp if ((bank & BSR_DETECT_MASK) != BSR_DETECT_VALUE) { 129754773Simp#ifdef SN_DEBUG 129854994Simp device_printf(dev, "test1 failed\n"); 129954773Simp#endif 130054994Simp goto error; 130154773Simp } 130254773Simp /* 130354773Simp * The above MIGHT indicate a device, but I need to write to further 130454773Simp * test this. Go to bank 0, then test that the register still 130554773Simp * reports the high byte is 0x33. 130654773Simp */ 1307121514Simp CSR_WRITE_2(sc, BANK_SELECT_REG_W, 0x0000); 1308121514Simp bank = CSR_READ_2(sc, BANK_SELECT_REG_W); 130954773Simp if ((bank & BSR_DETECT_MASK) != BSR_DETECT_VALUE) { 131054773Simp#ifdef SN_DEBUG 131154994Simp device_printf(dev, "test2 failed\n"); 131254773Simp#endif 131354994Simp goto error; 131454773Simp } 131554773Simp /* 131654773Simp * well, we've already written once, so hopefully another time won't 131754773Simp * hurt. This time, I need to switch the bank register to bank 1, so 131854773Simp * I can access the base address register. The contents of the 131954773Simp * BASE_ADDR_REG_W register, after some jiggery pokery, is expected 132054773Simp * to match the I/O port address where the adapter is being probed. 132154773Simp */ 1322121514Simp CSR_WRITE_2(sc, BANK_SELECT_REG_W, 0x0001); 1323121514Simp base_address_register = (CSR_READ_2(sc, BASE_ADDR_REG_W) >> 3) & 0x3e0; 132454773Simp 132554773Simp /* 132654773Simp * This test is nonsence on PC-card architecture, so if 132754773Simp * pccard == 1, skip this test. (hosokawa) 132854773Simp */ 1329121514Simp if (!pccard && rman_get_start(sc->port_res) != base_address_register) { 133054773Simp 133154773Simp /* 133254773Simp * Well, the base address register didn't match. Must not 133354773Simp * have been a SMC chip after all. 133454773Simp */ 133554773Simp#ifdef SN_DEBUG 133654994Simp device_printf(dev, "test3 failed ioaddr = 0x%x, " 1337121514Simp "base_address_register = 0x%x\n", 1338121514Simp rman_get_start(sc->port_res), base_address_register); 133954773Simp#endif 134054994Simp goto error; 134154773Simp } 134266058Simp 134354773Simp /* 134454773Simp * Check if the revision register is something that I recognize. 134554773Simp * These might need to be added to later, as future revisions could 134654773Simp * be added. 134754773Simp */ 1348121514Simp CSR_WRITE_2(sc, BANK_SELECT_REG_W, 0x3); 1349121514Simp revision_register = CSR_READ_2(sc, REVISION_REG_W); 135054773Simp if (!chip_ids[(revision_register >> 4) & 0xF]) { 135154773Simp 135254773Simp /* 135354773Simp * I don't regonize this chip, so... 135454773Simp */ 135554773Simp#ifdef SN_DEBUG 135654994Simp device_printf(dev, "test4 failed\n"); 135754773Simp#endif 135854994Simp goto error; 135954773Simp } 136066058Simp 136154773Simp /* 136254773Simp * at this point I'll assume that the chip is an SMC9xxx. It might be 136354773Simp * prudent to check a listing of MAC addresses against the hardware 136454773Simp * address, or do some other tests. 136554773Simp */ 136654994Simp sn_deactivate(dev); 136754773Simp return 0; 136854994Simp error: 136954994Simp sn_deactivate(dev); 137054994Simp return ENXIO; 137154773Simp} 137254773Simp 137354773Simp#define MCFSZ 8 137454773Simp 137554773Simpstatic void 137654773Simpsn_setmcast(struct sn_softc *sc) 137754773Simp{ 1378147256Sbrooks struct ifnet *ifp = sc->ifp; 137954773Simp int flags; 1380121589Simp uint8_t mcf[MCFSZ]; 138154773Simp 1382121589Simp SN_ASSERT_LOCKED(sc); 1383121589Simp 138454773Simp /* 138554773Simp * Set the receiver filter. We want receive enabled and auto strip 138654773Simp * of CRC from received packet. If we are promiscuous then set that 138754773Simp * bit too. 138854773Simp */ 138954773Simp flags = RCR_ENABLE | RCR_STRIP_CRC; 139054773Simp 139154773Simp if (ifp->if_flags & IFF_PROMISC) { 139254773Simp flags |= RCR_PROMISC | RCR_ALMUL; 139354773Simp } else if (ifp->if_flags & IFF_ALLMULTI) { 139454773Simp flags |= RCR_ALMUL; 139554773Simp } else { 1396147256Sbrooks if (sn_getmcf(ifp, mcf)) { 139754773Simp /* set filter */ 1398121514Simp SMC_SELECT_BANK(sc, 3); 1399121514Simp CSR_WRITE_2(sc, MULTICAST1_REG_W, 1400121589Simp ((uint16_t)mcf[1] << 8) | mcf[0]); 1401121514Simp CSR_WRITE_2(sc, MULTICAST2_REG_W, 1402121589Simp ((uint16_t)mcf[3] << 8) | mcf[2]); 1403121514Simp CSR_WRITE_2(sc, MULTICAST3_REG_W, 1404121589Simp ((uint16_t)mcf[5] << 8) | mcf[4]); 1405121514Simp CSR_WRITE_2(sc, MULTICAST4_REG_W, 1406121589Simp ((uint16_t)mcf[7] << 8) | mcf[6]); 140754773Simp } else { 140854773Simp flags |= RCR_ALMUL; 140954773Simp } 141054773Simp } 1411121514Simp SMC_SELECT_BANK(sc, 0); 1412121514Simp CSR_WRITE_2(sc, RECV_CONTROL_REG_W, flags); 141354773Simp} 141454773Simp 141554773Simpstatic int 1416147256Sbrookssn_getmcf(struct ifnet *ifp, uint8_t *mcf) 141754773Simp{ 141854773Simp int i; 1419121589Simp uint32_t index, index2; 1420121589Simp uint8_t *af = mcf; 142154773Simp struct ifmultiaddr *ifma; 142254773Simp 142354773Simp bzero(mcf, MCFSZ); 142454773Simp 1425147256Sbrooks TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 142654773Simp if (ifma->ifma_addr->sa_family != AF_LINK) 142754773Simp return 0; 1428130270Snaddy index = ether_crc32_le(LLADDR((struct sockaddr_dl *) 1429130270Snaddy ifma->ifma_addr), ETHER_ADDR_LEN) & 0x3f; 143054773Simp index2 = 0; 143154773Simp for (i = 0; i < 6; i++) { 143254773Simp index2 <<= 1; 143354773Simp index2 |= (index & 0x01); 143454773Simp index >>= 1; 143554773Simp } 143654773Simp af[index2 >> 3] |= 1 << (index2 & 7); 143754773Simp } 143854773Simp return 1; /* use multicast filter */ 143954773Simp} 1440