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$"); 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> 85199559Sjhb#include <sys/kernel.h> 8654773Simp#include <sys/sockio.h> 8754773Simp#include <sys/mbuf.h> 8854773Simp#include <sys/socket.h> 8954773Simp#include <sys/syslog.h> 9054773Simp 9154994Simp#include <sys/module.h> 9254994Simp#include <sys/bus.h> 9354994Simp 9454994Simp#include <machine/bus.h> 9554994Simp#include <machine/resource.h> 9654994Simp#include <sys/rman.h> 9754994Simp 9854773Simp#include <net/ethernet.h> 9954773Simp#include <net/if.h> 10054773Simp#include <net/if_arp.h> 10154773Simp#include <net/if_dl.h> 10254773Simp#include <net/if_types.h> 10354773Simp#include <net/if_mib.h> 10454773Simp 10554773Simp#ifdef INET 10654773Simp#include <netinet/in.h> 10754773Simp#include <netinet/in_systm.h> 10854773Simp#include <netinet/in_var.h> 10954773Simp#include <netinet/ip.h> 11054773Simp#endif 11154773Simp 11254773Simp#include <net/bpf.h> 11354773Simp#include <net/bpfdesc.h> 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 125199559Sjhbstatic void snintr_locked(struct sn_softc *); 126121589Simpstatic void sninit_locked(void *); 127121589Simpstatic void snstart_locked(struct ifnet *); 12854773Simp 129121589Simpstatic void sninit(void *); 130121589Simpstatic void snread(struct ifnet *); 131121589Simpstatic void snstart(struct ifnet *); 132121589Simpstatic void snstop(struct sn_softc *); 133199559Sjhbstatic void snwatchdog(void *); 134121589Simp 13554773Simpstatic void sn_setmcast(struct sn_softc *); 136147256Sbrooksstatic int sn_getmcf(struct ifnet *ifp, u_char *mcf); 13754773Simp 13854773Simp/* I (GB) have been unlucky getting the hardware padding 13954773Simp * to work properly. 14054773Simp */ 14154773Simp#define SW_PAD 14254773Simp 14354994Simpstatic const char *chip_ids[15] = { 14454994Simp NULL, NULL, NULL, 14554994Simp /* 3 */ "SMC91C90/91C92", 146148144Simp /* 4 */ "SMC91C94/91C96", 14754994Simp /* 5 */ "SMC91C95", 14854994Simp NULL, 14954994Simp /* 7 */ "SMC91C100", 15071060Stoshi /* 8 */ "SMC91C100FD", 151147872Simp /* 9 */ "SMC91C110", 152147872Simp NULL, NULL, 15354994Simp NULL, NULL, NULL 15454773Simp}; 15554773Simp 15654773Simpint 15754994Simpsn_attach(device_t dev) 15854773Simp{ 15954994Simp struct sn_softc *sc = device_get_softc(dev); 160147256Sbrooks struct ifnet *ifp; 161147797Simp uint16_t i; 162121589Simp uint8_t *p; 16354773Simp int rev; 164121589Simp uint16_t address; 165122427Simp int err; 166147256Sbrooks u_char eaddr[6]; 16754773Simp 168147256Sbrooks ifp = sc->ifp = if_alloc(IFT_ETHER); 169147256Sbrooks if (ifp == NULL) { 170147256Sbrooks device_printf(dev, "can not if_alloc()\n"); 171147256Sbrooks return (ENOSPC); 172147256Sbrooks } 173147256Sbrooks 174121589Simp SN_LOCK_INIT(sc); 175199559Sjhb callout_init_mtx(&sc->watchdog, &sc->sc_mtx, 0); 17654994Simp snstop(sc); 17754773Simp sc->pages_wanted = -1; 17854773Simp 179147797Simp if (bootverbose || 1) { 180147797Simp SMC_SELECT_BANK(sc, 3); 181147797Simp rev = (CSR_READ_2(sc, REVISION_REG_W) >> 4) & 0xf; 182147797Simp if (chip_ids[rev]) 183147797Simp device_printf(dev, " %s ", chip_ids[rev]); 184147797Simp else 185149095Simp device_printf(dev, " unsupported chip: rev %d ", rev); 186147797Simp SMC_SELECT_BANK(sc, 1); 187147797Simp i = CSR_READ_2(sc, CONFIG_REG_W); 188147797Simp printf("%s\n", i & CR_AUI_SELECT ? "AUI" : "UTP"); 189147797Simp } 19054773Simp 19154773Simp /* 19254773Simp * Read the station address from the chip. The MAC address is bank 1, 19354773Simp * regs 4 - 9 19454773Simp */ 195121514Simp SMC_SELECT_BANK(sc, 1); 196147256Sbrooks p = (uint8_t *) eaddr; 19754773Simp for (i = 0; i < 6; i += 2) { 198121514Simp address = CSR_READ_2(sc, IAR_ADDR0_REG_W + i); 19954773Simp p[i + 1] = address >> 8; 20054773Simp p[i] = address & 0xFF; 20154773Simp } 20254773Simp ifp->if_softc = sc; 203121816Sbrooks if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 20454773Simp ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 20554773Simp ifp->if_start = snstart; 20654773Simp ifp->if_ioctl = snioctl; 20754773Simp ifp->if_init = sninit; 208155280Simp ifp->if_baudrate = 10000000; 209207554Ssobomax IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); 210207554Ssobomax ifp->if_snd.ifq_maxlen = ifqmaxlen; 211155280Simp IFQ_SET_READY(&ifp->if_snd); 21254773Simp 213147256Sbrooks ether_ifattach(ifp, eaddr); 21454994Simp 21554773Simp /* 216122427Simp * Activate the interrupt so we can get card interrupts. This 217122427Simp * needs to be done last so that we don't have/hold the lock 218122427Simp * during startup to avoid LORs in the network layer. 219122427Simp */ 220122427Simp if ((err = bus_setup_intr(dev, sc->irq_res, 221166901Spiso INTR_TYPE_NET | INTR_MPSAFE, NULL, sn_intr, sc, 222166901Spiso &sc->intrhand)) != 0) { 223122427Simp sn_detach(dev); 224122427Simp return err; 225122427Simp } 22654994Simp return 0; 22754773Simp} 22854773Simp 22954773Simp 23069955Simpint 23169955Simpsn_detach(device_t dev) 23269955Simp{ 233147256Sbrooks struct sn_softc *sc = device_get_softc(dev); 234147256Sbrooks struct ifnet *ifp = sc->ifp; 23569955Simp 236199559Sjhb ether_ifdetach(ifp); 237199559Sjhb SN_LOCK(sc); 238121589Simp snstop(sc); 239199559Sjhb SN_UNLOCK(sc); 240199559Sjhb callout_drain(&sc->watchdog); 241150306Simp sn_deactivate(dev); 242147256Sbrooks if_free(ifp); 243150183Sru SN_LOCK_DESTROY(sc); 24469955Simp return 0; 24569955Simp} 24669955Simp 247121589Simpstatic void 248121589Simpsninit(void *xsc) 249121589Simp{ 250121589Simp struct sn_softc *sc = xsc; 251121589Simp SN_LOCK(sc); 252121589Simp sninit_locked(sc); 253121589Simp SN_UNLOCK(sc); 254121589Simp} 255121589Simp 25654773Simp/* 25754773Simp * Reset and initialize the chip 25854773Simp */ 259121589Simpstatic void 260121589Simpsninit_locked(void *xsc) 26154773Simp{ 262121553Simp struct sn_softc *sc = xsc; 263147256Sbrooks struct ifnet *ifp = sc->ifp; 26454773Simp int flags; 26554773Simp int mask; 26654773Simp 267121589Simp SN_ASSERT_LOCKED(sc); 26854773Simp 26954773Simp /* 27054773Simp * This resets the registers mostly to defaults, but doesn't affect 27154773Simp * EEPROM. After the reset cycle, we pause briefly for the chip to 27254773Simp * be happy. 27354773Simp */ 274121514Simp SMC_SELECT_BANK(sc, 0); 275121514Simp CSR_WRITE_2(sc, RECV_CONTROL_REG_W, RCR_SOFTRESET); 276121514Simp SMC_DELAY(sc); 277121514Simp CSR_WRITE_2(sc, RECV_CONTROL_REG_W, 0x0000); 278121514Simp SMC_DELAY(sc); 279121514Simp SMC_DELAY(sc); 28054773Simp 281121514Simp CSR_WRITE_2(sc, TXMIT_CONTROL_REG_W, 0x0000); 28254773Simp 28354773Simp /* 28454773Simp * Set the control register to automatically release succesfully 28554773Simp * transmitted packets (making the best use out of our limited 28654773Simp * memory) and to enable the EPH interrupt on certain TX errors. 28754773Simp */ 288121514Simp SMC_SELECT_BANK(sc, 1); 289121514Simp CSR_WRITE_2(sc, CONTROL_REG_W, (CTR_AUTO_RELEASE | CTR_TE_ENABLE | 29054773Simp CTR_CR_ENABLE | CTR_LE_ENABLE)); 29154773Simp 29254773Simp /* Set squelch level to 240mV (default 480mV) */ 293121514Simp flags = CSR_READ_2(sc, CONFIG_REG_W); 29454773Simp flags |= CR_SET_SQLCH; 295121514Simp CSR_WRITE_2(sc, CONFIG_REG_W, flags); 29654773Simp 29754773Simp /* 29854773Simp * Reset the MMU and wait for it to be un-busy. 29954773Simp */ 300121514Simp SMC_SELECT_BANK(sc, 2); 301121514Simp CSR_WRITE_2(sc, MMU_CMD_REG_W, MMUCR_RESET); 302121514Simp while (CSR_READ_2(sc, MMU_CMD_REG_W) & MMUCR_BUSY) /* NOTHING */ 30354773Simp ; 30454773Simp 30554773Simp /* 30654773Simp * Disable all interrupts 30754773Simp */ 308121514Simp CSR_WRITE_1(sc, INTR_MASK_REG_B, 0x00); 30954773Simp 31054773Simp sn_setmcast(sc); 31154773Simp 31254773Simp /* 31354773Simp * Set the transmitter control. We want it enabled. 31454773Simp */ 31554773Simp flags = TCR_ENABLE; 31654773Simp 31754773Simp#ifndef SW_PAD 31854773Simp /* 31954773Simp * I (GB) have been unlucky getting this to work. 32054773Simp */ 32154773Simp flags |= TCR_PAD_ENABLE; 32254773Simp#endif /* SW_PAD */ 32354773Simp 324121514Simp CSR_WRITE_2(sc, TXMIT_CONTROL_REG_W, flags); 32554773Simp 32654773Simp 32754773Simp /* 32854773Simp * Now, enable interrupts 32954773Simp */ 330121514Simp SMC_SELECT_BANK(sc, 2); 33154773Simp 33254773Simp mask = IM_EPH_INT | 33354773Simp IM_RX_OVRN_INT | 33454773Simp IM_RCV_INT | 33554773Simp IM_TX_INT; 33654773Simp 337121514Simp CSR_WRITE_1(sc, INTR_MASK_REG_B, mask); 33854773Simp sc->intr_mask = mask; 33954773Simp sc->pages_wanted = -1; 34054773Simp 34154773Simp 34254773Simp /* 34354773Simp * Mark the interface running but not active. 34454773Simp */ 345148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 346148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 347199559Sjhb callout_reset(&sc->watchdog, hz, snwatchdog, sc); 34854773Simp 34954773Simp /* 35054773Simp * Attempt to push out any waiting packets. 35154773Simp */ 352121589Simp snstart_locked(ifp); 353121589Simp} 35454773Simp 355121589Simpstatic void 356121589Simpsnstart(struct ifnet *ifp) 357121589Simp{ 358121589Simp struct sn_softc *sc = ifp->if_softc; 359121589Simp SN_LOCK(sc); 360121589Simp snstart_locked(ifp); 361121589Simp SN_UNLOCK(sc); 36254773Simp} 36354773Simp 36454773Simp 365121589Simpstatic void 366121589Simpsnstart_locked(struct ifnet *ifp) 36754773Simp{ 368121553Simp struct sn_softc *sc = ifp->if_softc; 369121589Simp u_int len; 370121589Simp struct mbuf *m; 371121589Simp struct mbuf *top; 372121589Simp int pad; 37354773Simp int mask; 374121589Simp uint16_t length; 375121589Simp uint16_t numPages; 376121589Simp uint8_t packet_no; 37754773Simp int time_out; 37866058Simp int junk = 0; 37954773Simp 380121589Simp SN_ASSERT_LOCKED(sc); 38154773Simp 382154100Simp if (ifp->if_drv_flags & IFF_DRV_OACTIVE) 38354773Simp return; 38454773Simp if (sc->pages_wanted != -1) { 385104257Sbrooks if_printf(ifp, "snstart() while memory allocation pending\n"); 38654773Simp return; 38754773Simp } 38854773Simpstartagain: 38954773Simp 39054773Simp /* 39154773Simp * Sneak a peek at the next packet 39254773Simp */ 393154100Simp m = ifp->if_snd.ifq_head; 394121589Simp if (m == 0) 39554773Simp return; 39654773Simp /* 39754773Simp * Compute the frame length and set pad to give an overall even 39854773Simp * number of bytes. Below we assume that the packet length is even. 39954773Simp */ 40054773Simp for (len = 0, top = m; m; m = m->m_next) 40154773Simp len += m->m_len; 40254773Simp 40354773Simp pad = (len & 1); 40454773Simp 40554773Simp /* 40654773Simp * We drop packets that are too large. Perhaps we should truncate 40754773Simp * them instead? 40854773Simp */ 40954773Simp if (len + pad > ETHER_MAX_LEN - ETHER_CRC_LEN) { 410104257Sbrooks if_printf(ifp, "large packet discarded (A)\n"); 411154100Simp ++ifp->if_oerrors; 412155283Simp IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 41354773Simp m_freem(m); 41454773Simp goto readcheck; 41554773Simp } 41654773Simp#ifdef SW_PAD 41754773Simp 41854773Simp /* 41954773Simp * If HW padding is not turned on, then pad to ETHER_MIN_LEN. 42054773Simp */ 42154773Simp if (len < ETHER_MIN_LEN - ETHER_CRC_LEN) 42254773Simp pad = ETHER_MIN_LEN - ETHER_CRC_LEN - len; 42354773Simp 42454773Simp#endif /* SW_PAD */ 42554773Simp 42654773Simp length = pad + len; 42754773Simp 42854773Simp /* 42954773Simp * The MMU wants the number of pages to be the number of 256 byte 43054773Simp * 'pages', minus 1 (A packet can't ever have 0 pages. We also 43154773Simp * include space for the status word, byte count and control bytes in 43254773Simp * the allocation request. 43354773Simp */ 43454773Simp numPages = (length + 6) >> 8; 43554773Simp 43654773Simp 43754773Simp /* 43854773Simp * Now, try to allocate the memory 43954773Simp */ 440121514Simp SMC_SELECT_BANK(sc, 2); 441121514Simp CSR_WRITE_2(sc, MMU_CMD_REG_W, MMUCR_ALLOC | numPages); 44254773Simp 44354773Simp /* 44454773Simp * Wait a short amount of time to see if the allocation request 44554773Simp * completes. Otherwise, I enable the interrupt and wait for 446250460Seadler * completion asynchronously. 44754773Simp */ 44854773Simp 44954773Simp time_out = MEMORY_WAIT_TIME; 45054773Simp do { 451121514Simp if (CSR_READ_1(sc, INTR_STAT_REG_B) & IM_ALLOC_INT) 45254773Simp break; 45354773Simp } while (--time_out); 45454773Simp 45566058Simp if (!time_out || junk > 10) { 45654773Simp 45754773Simp /* 45854773Simp * No memory now. Oh well, wait until the chip finds memory 45954773Simp * later. Remember how many pages we were asking for and 46054773Simp * enable the allocation completion interrupt. Also set a 46154773Simp * watchdog in case we miss the interrupt. We mark the 46254773Simp * interface active since there is no point in attempting an 46354773Simp * snstart() until after the memory is available. 46454773Simp */ 465121514Simp mask = CSR_READ_1(sc, INTR_MASK_REG_B) | IM_ALLOC_INT; 466121514Simp CSR_WRITE_1(sc, INTR_MASK_REG_B, mask); 46754773Simp sc->intr_mask = mask; 46854773Simp 469199559Sjhb sc->timer = 1; 470154100Simp ifp->if_drv_flags |= IFF_DRV_OACTIVE; 47154773Simp sc->pages_wanted = numPages; 47254773Simp return; 47354773Simp } 47454773Simp /* 47554773Simp * The memory allocation completed. Check the results. 47654773Simp */ 477121514Simp packet_no = CSR_READ_1(sc, ALLOC_RESULT_REG_B); 47854773Simp if (packet_no & ARR_FAILED) { 47966058Simp if (junk++ > 10) 480104257Sbrooks if_printf(ifp, "Memory allocation failed\n"); 48154773Simp goto startagain; 48254773Simp } 48354773Simp /* 48454773Simp * We have a packet number, so tell the card to use it. 48554773Simp */ 486121514Simp CSR_WRITE_1(sc, PACKET_NUM_REG_B, packet_no); 48754773Simp 48854773Simp /* 48954773Simp * Point to the beginning of the packet 49054773Simp */ 491121514Simp CSR_WRITE_2(sc, POINTER_REG_W, PTR_AUTOINC | 0x0000); 49254773Simp 49354773Simp /* 49454773Simp * Send the packet length (+6 for status, length and control byte) 49554773Simp * and the status word (set to zeros) 49654773Simp */ 497121514Simp CSR_WRITE_2(sc, DATA_REG_W, 0); 498121514Simp CSR_WRITE_1(sc, DATA_REG_B, (length + 6) & 0xFF); 499121514Simp CSR_WRITE_1(sc, DATA_REG_B, (length + 6) >> 8); 50054773Simp 50154773Simp /* 50254773Simp * Get the packet from the kernel. This will include the Ethernet 50354773Simp * frame header, MAC Addresses etc. 50454773Simp */ 505155283Simp IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 50654773Simp 50754773Simp /* 50854773Simp * Push out the data to the card. 50954773Simp */ 51054773Simp for (top = m; m != 0; m = m->m_next) { 51154773Simp 51254773Simp /* 51354773Simp * Push out words. 51454773Simp */ 515121514Simp CSR_WRITE_MULTI_2(sc, DATA_REG_W, mtod(m, uint16_t *), 516121514Simp m->m_len / 2); 51754773Simp 51854773Simp /* 51954773Simp * Push out remaining byte. 52054773Simp */ 52154773Simp if (m->m_len & 1) 522121514Simp CSR_WRITE_1(sc, DATA_REG_B, 523121514Simp *(mtod(m, caddr_t) + m->m_len - 1)); 52454773Simp } 52554773Simp 52654773Simp /* 52754773Simp * Push out padding. 52854773Simp */ 52954773Simp while (pad > 1) { 530121514Simp CSR_WRITE_2(sc, DATA_REG_W, 0); 53154773Simp pad -= 2; 53254773Simp } 53354773Simp if (pad) 534121514Simp CSR_WRITE_1(sc, DATA_REG_B, 0); 53554773Simp 53654773Simp /* 53754773Simp * Push out control byte and unused packet byte The control byte is 0 53854773Simp * meaning the packet is even lengthed and no special CRC handling is 53954773Simp * desired. 54054773Simp */ 541121514Simp CSR_WRITE_2(sc, DATA_REG_W, 0); 54254773Simp 54354773Simp /* 54454773Simp * Enable the interrupts and let the chipset deal with it Also set a 54554773Simp * watchdog in case we miss the interrupt. 54654773Simp */ 547121514Simp mask = CSR_READ_1(sc, INTR_MASK_REG_B) | (IM_TX_INT | IM_TX_EMPTY_INT); 548121514Simp CSR_WRITE_1(sc, INTR_MASK_REG_B, mask); 54954773Simp sc->intr_mask = mask; 55054773Simp 551121514Simp CSR_WRITE_2(sc, MMU_CMD_REG_W, MMUCR_ENQUEUE); 55254773Simp 553154100Simp ifp->if_drv_flags |= IFF_DRV_OACTIVE; 554199559Sjhb sc->timer = 1; 55554773Simp 556106937Ssam BPF_MTAP(ifp, top); 55754773Simp 558154100Simp ifp->if_opackets++; 55954773Simp m_freem(top); 56054773Simp 56154773Simp 56254773Simpreadcheck: 56354773Simp 56454773Simp /* 56554773Simp * Is another packet coming in? We don't want to overflow the tiny 56654773Simp * RX FIFO. If nothing has arrived then attempt to queue another 56754773Simp * transmit packet. 56854773Simp */ 569121514Simp if (CSR_READ_2(sc, FIFO_PORTS_REG_W) & FIFO_REMPTY) 57054773Simp goto startagain; 57154773Simp return; 57254773Simp} 57354773Simp 57454773Simp 57554773Simp 57654773Simp/* Resume a packet transmit operation after a memory allocation 57754773Simp * has completed. 57854773Simp * 57954773Simp * This is basically a hacked up copy of snstart() which handles 58054773Simp * a completed memory allocation the same way snstart() does. 58154773Simp * It then passes control to snstart to handle any other queued 58254773Simp * packets. 58354773Simp */ 58454773Simpstatic void 58554773Simpsnresume(struct ifnet *ifp) 58654773Simp{ 587121553Simp struct sn_softc *sc = ifp->if_softc; 588121589Simp u_int len; 589121589Simp struct mbuf *m; 59054773Simp struct mbuf *top; 59154773Simp int pad; 59254773Simp int mask; 593121589Simp uint16_t length; 594121589Simp uint16_t numPages; 595121589Simp uint16_t pages_wanted; 596121589Simp uint8_t packet_no; 59754773Simp 59854773Simp if (sc->pages_wanted < 0) 59954773Simp return; 60054773Simp 60154773Simp pages_wanted = sc->pages_wanted; 60254773Simp sc->pages_wanted = -1; 60354773Simp 60454773Simp /* 60554773Simp * Sneak a peek at the next packet 60654773Simp */ 607154100Simp m = ifp->if_snd.ifq_head; 60854773Simp if (m == 0) { 609104257Sbrooks if_printf(ifp, "snresume() with nothing to send\n"); 61054773Simp return; 61154773Simp } 61254773Simp /* 61354773Simp * Compute the frame length and set pad to give an overall even 61454773Simp * number of bytes. Below we assume that the packet length is even. 61554773Simp */ 61654773Simp for (len = 0, top = m; m; m = m->m_next) 61754773Simp len += m->m_len; 61854773Simp 61954773Simp pad = (len & 1); 62054773Simp 62154773Simp /* 62254773Simp * We drop packets that are too large. Perhaps we should truncate 62354773Simp * them instead? 62454773Simp */ 62554773Simp if (len + pad > ETHER_MAX_LEN - ETHER_CRC_LEN) { 626104257Sbrooks if_printf(ifp, "large packet discarded (B)\n"); 627154100Simp ++ifp->if_oerrors; 628155283Simp IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 62954773Simp m_freem(m); 63054773Simp return; 63154773Simp } 63254773Simp#ifdef SW_PAD 63354773Simp 63454773Simp /* 63554773Simp * If HW padding is not turned on, then pad to ETHER_MIN_LEN. 63654773Simp */ 63754773Simp if (len < ETHER_MIN_LEN - ETHER_CRC_LEN) 63854773Simp pad = ETHER_MIN_LEN - ETHER_CRC_LEN - len; 63954773Simp 64054773Simp#endif /* SW_PAD */ 64154773Simp 64254773Simp length = pad + len; 64354773Simp 64454773Simp 64554773Simp /* 64654773Simp * The MMU wants the number of pages to be the number of 256 byte 64754773Simp * 'pages', minus 1 (A packet can't ever have 0 pages. We also 64854773Simp * include space for the status word, byte count and control bytes in 64954773Simp * the allocation request. 65054773Simp */ 65154773Simp numPages = (length + 6) >> 8; 65254773Simp 65354773Simp 654121514Simp SMC_SELECT_BANK(sc, 2); 65554773Simp 65654773Simp /* 65754773Simp * The memory allocation completed. Check the results. If it failed, 65854773Simp * we simply set a watchdog timer and hope for the best. 65954773Simp */ 660121514Simp packet_no = CSR_READ_1(sc, ALLOC_RESULT_REG_B); 66154773Simp if (packet_no & ARR_FAILED) { 662104257Sbrooks if_printf(ifp, "Memory allocation failed. Weird.\n"); 663199559Sjhb sc->timer = 1; 66454773Simp goto try_start; 66554773Simp } 66654773Simp /* 66754773Simp * We have a packet number, so tell the card to use it. 66854773Simp */ 669121514Simp CSR_WRITE_1(sc, PACKET_NUM_REG_B, packet_no); 67054773Simp 67154773Simp /* 67254773Simp * Now, numPages should match the pages_wanted recorded when the 67354773Simp * memory allocation was initiated. 67454773Simp */ 67554773Simp if (pages_wanted != numPages) { 676104257Sbrooks if_printf(ifp, "memory allocation wrong size. Weird.\n"); 67754773Simp /* 67854773Simp * If the allocation was the wrong size we simply release the 67954773Simp * memory once it is granted. Wait for the MMU to be un-busy. 68054773Simp */ 681121514Simp while (CSR_READ_2(sc, MMU_CMD_REG_W) & MMUCR_BUSY) /* NOTHING */ 68254773Simp ; 683121514Simp CSR_WRITE_2(sc, MMU_CMD_REG_W, MMUCR_FREEPKT); 68454773Simp 68554773Simp return; 68654773Simp } 68754773Simp /* 68854773Simp * Point to the beginning of the packet 68954773Simp */ 690121514Simp CSR_WRITE_2(sc, POINTER_REG_W, PTR_AUTOINC | 0x0000); 69154773Simp 69254773Simp /* 69354773Simp * Send the packet length (+6 for status, length and control byte) 69454773Simp * and the status word (set to zeros) 69554773Simp */ 696121514Simp CSR_WRITE_2(sc, DATA_REG_W, 0); 697121514Simp CSR_WRITE_1(sc, DATA_REG_B, (length + 6) & 0xFF); 698121514Simp CSR_WRITE_1(sc, DATA_REG_B, (length + 6) >> 8); 69954773Simp 70054773Simp /* 70154773Simp * Get the packet from the kernel. This will include the Ethernet 70254773Simp * frame header, MAC Addresses etc. 70354773Simp */ 704155283Simp IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 70554773Simp 70654773Simp /* 70754773Simp * Push out the data to the card. 70854773Simp */ 70954773Simp for (top = m; m != 0; m = m->m_next) { 71054773Simp 71154773Simp /* 71254773Simp * Push out words. 71354773Simp */ 714121514Simp CSR_WRITE_MULTI_2(sc, DATA_REG_W, mtod(m, uint16_t *), 715121514Simp m->m_len / 2); 71654773Simp /* 71754773Simp * Push out remaining byte. 71854773Simp */ 71954773Simp if (m->m_len & 1) 720121514Simp CSR_WRITE_1(sc, DATA_REG_B, 721121514Simp *(mtod(m, caddr_t) + m->m_len - 1)); 72254773Simp } 72354773Simp 72454773Simp /* 72554773Simp * Push out padding. 72654773Simp */ 72754773Simp while (pad > 1) { 728121514Simp CSR_WRITE_2(sc, DATA_REG_W, 0); 72954773Simp pad -= 2; 73054773Simp } 73154773Simp if (pad) 732121514Simp CSR_WRITE_1(sc, DATA_REG_B, 0); 73354773Simp 73454773Simp /* 73554773Simp * Push out control byte and unused packet byte The control byte is 0 73654773Simp * meaning the packet is even lengthed and no special CRC handling is 73754773Simp * desired. 73854773Simp */ 739121514Simp CSR_WRITE_2(sc, DATA_REG_W, 0); 74054773Simp 74154773Simp /* 74254773Simp * Enable the interrupts and let the chipset deal with it Also set a 74354773Simp * watchdog in case we miss the interrupt. 74454773Simp */ 745121514Simp mask = CSR_READ_1(sc, INTR_MASK_REG_B) | (IM_TX_INT | IM_TX_EMPTY_INT); 746121514Simp CSR_WRITE_1(sc, INTR_MASK_REG_B, mask); 74754773Simp sc->intr_mask = mask; 748121514Simp CSR_WRITE_2(sc, MMU_CMD_REG_W, MMUCR_ENQUEUE); 74954773Simp 750106937Ssam BPF_MTAP(ifp, top); 75154773Simp 752154100Simp ifp->if_opackets++; 75354773Simp m_freem(top); 75454773Simp 75554773Simptry_start: 75654773Simp 75754773Simp /* 75854773Simp * Now pass control to snstart() to queue any additional packets 75954773Simp */ 760154100Simp ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 761199559Sjhb snstart_locked(ifp); 76254773Simp 76354773Simp /* 76454773Simp * We've sent something, so we're active. Set a watchdog in case the 76554773Simp * TX_EMPTY interrupt is lost. 76654773Simp */ 767154100Simp ifp->if_drv_flags |= IFF_DRV_OACTIVE; 768199559Sjhb sc->timer = 1; 76954773Simp 77054773Simp return; 77154773Simp} 77254773Simp 77354773Simpvoid 77454994Simpsn_intr(void *arg) 77554773Simp{ 776199559Sjhb struct sn_softc *sc = (struct sn_softc *) arg; 777199559Sjhb 778199559Sjhb SN_LOCK(sc); 779199559Sjhb snintr_locked(sc); 780199559Sjhb SN_UNLOCK(sc); 781199559Sjhb} 782199559Sjhb 783199559Sjhbstatic void 784199559Sjhbsnintr_locked(struct sn_softc *sc) 785199559Sjhb{ 78654773Simp int status, interrupts; 787147256Sbrooks struct ifnet *ifp = sc->ifp; 78854773Simp 78954773Simp /* 79054773Simp * Chip state registers 79154773Simp */ 792121589Simp uint8_t mask; 793121589Simp uint8_t packet_no; 794121589Simp uint16_t tx_status; 795121589Simp uint16_t card_stats; 79654773Simp 79754773Simp /* 79854773Simp * Clear the watchdog. 79954773Simp */ 800199559Sjhb sc->timer = 0; 80154773Simp 802121514Simp SMC_SELECT_BANK(sc, 2); 80354773Simp 80454773Simp /* 80554773Simp * Obtain the current interrupt mask and clear the hardware mask 80654773Simp * while servicing interrupts. 80754773Simp */ 808121514Simp mask = CSR_READ_1(sc, INTR_MASK_REG_B); 809121514Simp CSR_WRITE_1(sc, INTR_MASK_REG_B, 0x00); 81054773Simp 81154773Simp /* 81254773Simp * Get the set of interrupts which occurred and eliminate any which 81354773Simp * are masked. 81454773Simp */ 815121514Simp interrupts = CSR_READ_1(sc, INTR_STAT_REG_B); 81654773Simp status = interrupts & mask; 81754773Simp 81854773Simp /* 81954773Simp * Now, process each of the interrupt types. 82054773Simp */ 82154773Simp 82254773Simp /* 82354773Simp * Receive Overrun. 82454773Simp */ 82554773Simp if (status & IM_RX_OVRN_INT) { 82654773Simp /* 82754773Simp * Acknowlege Interrupt 82854773Simp */ 829121514Simp SMC_SELECT_BANK(sc, 2); 830121514Simp CSR_WRITE_1(sc, INTR_ACK_REG_B, IM_RX_OVRN_INT); 83154773Simp 832154100Simp ++ifp->if_ierrors; 83354773Simp } 83454773Simp /* 83554773Simp * Got a packet. 83654773Simp */ 83754773Simp if (status & IM_RCV_INT) { 83854773Simp int packet_number; 83954773Simp 840121514Simp SMC_SELECT_BANK(sc, 2); 841121514Simp packet_number = CSR_READ_2(sc, FIFO_PORTS_REG_W); 84254773Simp 84354773Simp if (packet_number & FIFO_REMPTY) { 84454773Simp /* 84554773Simp * we got called , but nothing was on the FIFO 84654773Simp */ 84754773Simp printf("sn: Receive interrupt with nothing on FIFO\n"); 84854773Simp goto out; 84954773Simp } 85054773Simp snread(ifp); 85154773Simp } 85254773Simp /* 85354773Simp * An on-card memory allocation came through. 85454773Simp */ 85554773Simp if (status & IM_ALLOC_INT) { 85654773Simp /* 85754773Simp * Disable this interrupt. 85854773Simp */ 85954773Simp mask &= ~IM_ALLOC_INT; 860154100Simp ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 861154100Simp snresume(ifp); 86254773Simp } 86354773Simp /* 86454773Simp * TX Completion. Handle a transmit error message. This will only be 86554773Simp * called when there is an error, because of the AUTO_RELEASE mode. 86654773Simp */ 86754773Simp if (status & IM_TX_INT) { 86854773Simp /* 86954773Simp * Acknowlege Interrupt 87054773Simp */ 871121514Simp SMC_SELECT_BANK(sc, 2); 872121514Simp CSR_WRITE_1(sc, INTR_ACK_REG_B, IM_TX_INT); 87354773Simp 874121514Simp packet_no = CSR_READ_2(sc, FIFO_PORTS_REG_W); 87554773Simp packet_no &= FIFO_TX_MASK; 87654773Simp 87754773Simp /* 87854773Simp * select this as the packet to read from 87954773Simp */ 880121514Simp CSR_WRITE_1(sc, PACKET_NUM_REG_B, packet_no); 88154773Simp 88254773Simp /* 88354773Simp * Position the pointer to the first word from this packet 88454773Simp */ 885121514Simp CSR_WRITE_2(sc, POINTER_REG_W, PTR_AUTOINC | PTR_READ | 0x0000); 88654773Simp 88754773Simp /* 88854773Simp * Fetch the TX status word. The value found here will be a 88954773Simp * copy of the EPH_STATUS_REG_W at the time the transmit 89054773Simp * failed. 89154773Simp */ 892121514Simp tx_status = CSR_READ_2(sc, DATA_REG_W); 89354773Simp 89454773Simp if (tx_status & EPHSR_TX_SUC) { 89554994Simp device_printf(sc->dev, 89654994Simp "Successful packet caused interrupt\n"); 89754773Simp } else { 898154100Simp ++ifp->if_oerrors; 89954773Simp } 90054773Simp 90154773Simp if (tx_status & EPHSR_LATCOL) 902154100Simp ++ifp->if_collisions; 90354773Simp 90454773Simp /* 90554773Simp * Some of these errors will have disabled transmit. 90654773Simp * Re-enable transmit now. 90754773Simp */ 908121514Simp SMC_SELECT_BANK(sc, 0); 90954773Simp 91054773Simp#ifdef SW_PAD 911121514Simp CSR_WRITE_2(sc, TXMIT_CONTROL_REG_W, TCR_ENABLE); 91254773Simp#else 913121514Simp CSR_WRITE_2(sc, TXMIT_CONTROL_REG_W, TCR_ENABLE | TCR_PAD_ENABLE); 91454773Simp#endif /* SW_PAD */ 91554773Simp 91654773Simp /* 91754773Simp * kill the failed packet. Wait for the MMU to be un-busy. 91854773Simp */ 919121514Simp SMC_SELECT_BANK(sc, 2); 920121514Simp while (CSR_READ_2(sc, MMU_CMD_REG_W) & MMUCR_BUSY) /* NOTHING */ 92154773Simp ; 922121514Simp CSR_WRITE_2(sc, MMU_CMD_REG_W, MMUCR_FREEPKT); 92354773Simp 92454773Simp /* 92554773Simp * Attempt to queue more transmits. 92654773Simp */ 927154100Simp ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 928154100Simp snstart_locked(ifp); 92954773Simp } 93054773Simp /* 93154773Simp * Transmit underrun. We use this opportunity to update transmit 93254773Simp * statistics from the card. 93354773Simp */ 93454773Simp if (status & IM_TX_EMPTY_INT) { 93554773Simp 93654773Simp /* 93754773Simp * Acknowlege Interrupt 93854773Simp */ 939121514Simp SMC_SELECT_BANK(sc, 2); 940121514Simp CSR_WRITE_1(sc, INTR_ACK_REG_B, IM_TX_EMPTY_INT); 94154773Simp 94254773Simp /* 94354773Simp * Disable this interrupt. 94454773Simp */ 94554773Simp mask &= ~IM_TX_EMPTY_INT; 94654773Simp 947121514Simp SMC_SELECT_BANK(sc, 0); 948121514Simp card_stats = CSR_READ_2(sc, COUNTER_REG_W); 94954773Simp 95054773Simp /* 95154773Simp * Single collisions 95254773Simp */ 953154100Simp ifp->if_collisions += card_stats & ECR_COLN_MASK; 95454773Simp 95554773Simp /* 95654773Simp * Multiple collisions 95754773Simp */ 958154100Simp ifp->if_collisions += (card_stats & ECR_MCOLN_MASK) >> 4; 95954773Simp 960121514Simp SMC_SELECT_BANK(sc, 2); 96154773Simp 96254773Simp /* 96354773Simp * Attempt to enqueue some more stuff. 96454773Simp */ 965154100Simp ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 966154100Simp snstart_locked(ifp); 96754773Simp } 96854773Simp /* 96954773Simp * Some other error. Try to fix it by resetting the adapter. 97054773Simp */ 97154773Simp if (status & IM_EPH_INT) { 97254994Simp snstop(sc); 973121589Simp sninit_locked(sc); 97454773Simp } 97554773Simp 97654773Simpout: 97754773Simp /* 97854773Simp * Handled all interrupt sources. 97954773Simp */ 98054773Simp 981121514Simp SMC_SELECT_BANK(sc, 2); 98254773Simp 98354773Simp /* 98454773Simp * Reestablish interrupts from mask which have not been deselected 98554773Simp * during this interrupt. Note that the hardware mask, which was set 98654773Simp * to 0x00 at the start of this service routine, may have been 98754773Simp * updated by one or more of the interrupt handers and we must let 98854773Simp * those new interrupts stay enabled here. 98954773Simp */ 990121514Simp mask |= CSR_READ_1(sc, INTR_MASK_REG_B); 991121514Simp CSR_WRITE_1(sc, INTR_MASK_REG_B, mask); 99254773Simp sc->intr_mask = mask; 99354773Simp} 99454773Simp 995121589Simpstatic void 996121553Simpsnread(struct ifnet *ifp) 99754773Simp{ 99854994Simp struct sn_softc *sc = ifp->if_softc; 99954773Simp struct ether_header *eh; 100054773Simp struct mbuf *m; 100154773Simp short status; 100254773Simp int packet_number; 1003121589Simp uint16_t packet_length; 1004121589Simp uint8_t *data; 100554773Simp 1006121514Simp SMC_SELECT_BANK(sc, 2); 100754773Simp#if 0 1008121514Simp packet_number = CSR_READ_2(sc, FIFO_PORTS_REG_W); 100954773Simp 101054773Simp if (packet_number & FIFO_REMPTY) { 101154773Simp 101254773Simp /* 101354773Simp * we got called , but nothing was on the FIFO 101454773Simp */ 101554773Simp printf("sn: Receive interrupt with nothing on FIFO\n"); 101654773Simp return; 101754773Simp } 101854773Simp#endif 101954773Simpread_another: 102054773Simp 102154773Simp /* 102254773Simp * Start reading from the start of the packet. Since PTR_RCV is set, 102354773Simp * packet number is found in FIFO_PORTS_REG_W, FIFO_RX_MASK. 102454773Simp */ 1025121514Simp CSR_WRITE_2(sc, POINTER_REG_W, PTR_READ | PTR_RCV | PTR_AUTOINC | 0x0000); 102654773Simp 102754773Simp /* 102854773Simp * First two words are status and packet_length 102954773Simp */ 1030121514Simp status = CSR_READ_2(sc, DATA_REG_W); 1031121514Simp packet_length = CSR_READ_2(sc, DATA_REG_W) & RLEN_MASK; 103254773Simp 103354773Simp /* 103454773Simp * The packet length contains 3 extra words: status, length, and a 103554773Simp * extra word with the control byte. 103654773Simp */ 103754773Simp packet_length -= 6; 103854773Simp 103954773Simp /* 104054773Simp * Account for receive errors and discard. 104154773Simp */ 104254773Simp if (status & RS_ERRORS) { 1043154100Simp ++ifp->if_ierrors; 104454773Simp goto out; 104554773Simp } 104654773Simp /* 104754773Simp * A packet is received. 104854773Simp */ 104954773Simp 105054773Simp /* 105154773Simp * Adjust for odd-length packet. 105254773Simp */ 105354773Simp if (status & RS_ODDFRAME) 105454773Simp packet_length++; 105554773Simp 105654773Simp /* 105754773Simp * Allocate a header mbuf from the kernel. 105854773Simp */ 1059243857Sglebius MGETHDR(m, M_NOWAIT, MT_DATA); 106054773Simp if (m == NULL) 106154773Simp goto out; 106254773Simp 1063154100Simp m->m_pkthdr.rcvif = ifp; 106454773Simp m->m_pkthdr.len = m->m_len = packet_length; 106554773Simp 106654773Simp /* 106754773Simp * Attach an mbuf cluster 106854773Simp */ 1069243857Sglebius MCLGET(m, M_NOWAIT); 107054773Simp 107154773Simp /* 107254773Simp * Insist on getting a cluster 107354773Simp */ 107454773Simp if ((m->m_flags & M_EXT) == 0) { 107554773Simp m_freem(m); 1076154100Simp ++ifp->if_ierrors; 107754773Simp printf("sn: snread() kernel memory allocation problem\n"); 107854773Simp goto out; 107954773Simp } 108054773Simp eh = mtod(m, struct ether_header *); 108154773Simp 108254773Simp /* 108354773Simp * Get packet, including link layer address, from interface. 108454773Simp */ 1085121589Simp data = (uint8_t *) eh; 1086121514Simp CSR_READ_MULTI_2(sc, DATA_REG_W, (uint16_t *) data, packet_length >> 1); 108754773Simp if (packet_length & 1) { 108854773Simp data += packet_length & ~1; 1089121514Simp *data = CSR_READ_1(sc, DATA_REG_B); 109054773Simp } 1091154100Simp ++ifp->if_ipackets; 109254773Simp 109354773Simp /* 109454773Simp * Remove link layer addresses and whatnot. 109554773Simp */ 1096106937Ssam m->m_pkthdr.len = m->m_len = packet_length; 109754773Simp 1098121589Simp /* 1099121589Simp * Drop locks before calling if_input() since it may re-enter 1100121589Simp * snstart() in the netisr case. This would result in a 1101121589Simp * lock reversal. Better performance might be obtained by 1102121589Simp * chaining all packets received, dropping the lock, and then 1103121589Simp * calling if_input() on each one. 1104121589Simp */ 1105121589Simp SN_UNLOCK(sc); 1106106937Ssam (*ifp->if_input)(ifp, m); 1107121589Simp SN_LOCK(sc); 110854773Simp 110954773Simpout: 111054773Simp 111154773Simp /* 111254773Simp * Error or good, tell the card to get rid of this packet Wait for 111354773Simp * the MMU to be un-busy. 111454773Simp */ 1115121514Simp SMC_SELECT_BANK(sc, 2); 1116121514Simp while (CSR_READ_2(sc, MMU_CMD_REG_W) & MMUCR_BUSY) /* NOTHING */ 111754773Simp ; 1118121514Simp CSR_WRITE_2(sc, MMU_CMD_REG_W, MMUCR_RELEASE); 111954773Simp 112054773Simp /* 112154773Simp * Check whether another packet is ready 112254773Simp */ 1123121514Simp packet_number = CSR_READ_2(sc, FIFO_PORTS_REG_W); 112454773Simp if (packet_number & FIFO_REMPTY) { 112554773Simp return; 112654773Simp } 112754773Simp goto read_another; 112854773Simp} 112954773Simp 113054773Simp 113154773Simp/* 113254773Simp * Handle IOCTLS. This function is completely stolen from if_ep.c 113354773Simp * As with its progenitor, it does not handle hardware address 113454773Simp * changes. 113554773Simp */ 113654773Simpstatic int 1137121553Simpsnioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 113854773Simp{ 113954994Simp struct sn_softc *sc = ifp->if_softc; 1140121589Simp int error = 0; 114154773Simp 114254773Simp switch (cmd) { 114354773Simp case SIOCSIFFLAGS: 1144121589Simp SN_LOCK(sc); 1145148887Srwatson if ((ifp->if_flags & IFF_UP) == 0 && 1146148887Srwatson ifp->if_drv_flags & IFF_DRV_RUNNING) { 114754994Simp snstop(sc); 114854773Simp } else { 114954773Simp /* reinitialize card on any parameter change */ 1150121589Simp sninit_locked(sc); 115154773Simp } 1152121589Simp SN_UNLOCK(sc); 115354773Simp break; 115454773Simp 115554773Simp case SIOCADDMULTI: 115654773Simp case SIOCDELMULTI: 1157121589Simp /* update multicast filter list. */ 1158121589Simp SN_LOCK(sc); 1159121589Simp sn_setmcast(sc); 1160121589Simp error = 0; 1161121589Simp SN_UNLOCK(sc); 1162121589Simp break; 116354773Simp default: 1164106937Ssam error = ether_ioctl(ifp, cmd, data); 1165106937Ssam break; 116654773Simp } 116754773Simp return (error); 116854773Simp} 116954773Simp 1170121589Simpstatic void 1171199559Sjhbsnwatchdog(void *arg) 117254773Simp{ 1173199559Sjhb struct sn_softc *sc; 1174199559Sjhb 1175199559Sjhb sc = arg; 1176199559Sjhb SN_ASSERT_LOCKED(sc); 1177199559Sjhb callout_reset(&sc->watchdog, hz, snwatchdog, sc); 1178199559Sjhb if (sc->timer == 0 || --sc->timer > 0) 1179199559Sjhb return; 1180199559Sjhb snintr_locked(sc); 118154773Simp} 118254773Simp 118354773Simp 118454773Simp/* 1. zero the interrupt mask 118554773Simp * 2. clear the enable receive flag 118654773Simp * 3. clear the enable xmit flags 118754773Simp */ 1188121589Simpstatic void 118954994Simpsnstop(struct sn_softc *sc) 119054773Simp{ 119154994Simp 1192147256Sbrooks struct ifnet *ifp = sc->ifp; 119354773Simp 119454773Simp /* 119554773Simp * Clear interrupt mask; disable all interrupts. 119654773Simp */ 1197121514Simp SMC_SELECT_BANK(sc, 2); 1198121514Simp CSR_WRITE_1(sc, INTR_MASK_REG_B, 0x00); 119954773Simp 120054773Simp /* 120154773Simp * Disable transmitter and Receiver 120254773Simp */ 1203121514Simp SMC_SELECT_BANK(sc, 0); 1204121514Simp CSR_WRITE_2(sc, RECV_CONTROL_REG_W, 0x0000); 1205121514Simp CSR_WRITE_2(sc, TXMIT_CONTROL_REG_W, 0x0000); 120654773Simp 120754773Simp /* 120854773Simp * Cancel watchdog. 120954773Simp */ 1210199559Sjhb sc->timer = 0; 1211199559Sjhb callout_stop(&sc->watchdog); 1212199559Sjhb ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 121354773Simp} 121454773Simp 121554773Simp 121654994Simpint 121754994Simpsn_activate(device_t dev) 121854994Simp{ 121954994Simp struct sn_softc *sc = device_get_softc(dev); 122054773Simp 122154994Simp sc->port_rid = 0; 122254994Simp sc->port_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->port_rid, 122354994Simp 0, ~0, SMC_IO_EXTENT, RF_ACTIVE); 122454994Simp if (!sc->port_res) { 122566058Simp if (bootverbose) 122666058Simp device_printf(dev, "Cannot allocate ioport\n"); 122754994Simp return ENOMEM; 122854994Simp } 122954994Simp 123054994Simp sc->irq_rid = 0; 1231127135Snjl sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid, 1232127135Snjl RF_ACTIVE); 123354994Simp if (!sc->irq_res) { 123466058Simp if (bootverbose) 123566058Simp device_printf(dev, "Cannot allocate irq\n"); 123654994Simp sn_deactivate(dev); 123754994Simp return ENOMEM; 123854994Simp } 123954994Simp return (0); 124054994Simp} 124154994Simp 124254994Simpvoid 124354994Simpsn_deactivate(device_t dev) 124454994Simp{ 124554994Simp struct sn_softc *sc = device_get_softc(dev); 124654994Simp 124754994Simp if (sc->intrhand) 124854994Simp bus_teardown_intr(dev, sc->irq_res, sc->intrhand); 124954994Simp sc->intrhand = 0; 125054994Simp if (sc->port_res) 125154994Simp bus_release_resource(dev, SYS_RES_IOPORT, sc->port_rid, 125254994Simp sc->port_res); 125354994Simp sc->port_res = 0; 1254149095Simp if (sc->modem_res) 1255149095Simp bus_release_resource(dev, SYS_RES_IOPORT, sc->modem_rid, 1256149095Simp sc->modem_res); 1257149095Simp sc->modem_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/* 1266149095Simp * Function: sn_probe(device_t dev) 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 1281147797Simpsn_probe(device_t dev) 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 1325147797Simp if (rman_get_start(sc->port_res) != base_address_register) { 132654773Simp 132754773Simp /* 132854773Simp * Well, the base address register didn't match. Must not 132954773Simp * have been a SMC chip after all. 133054773Simp */ 133154773Simp#ifdef SN_DEBUG 133254994Simp device_printf(dev, "test3 failed ioaddr = 0x%x, " 1333121514Simp "base_address_register = 0x%x\n", 1334121514Simp rman_get_start(sc->port_res), base_address_register); 133554773Simp#endif 133654994Simp goto error; 133754773Simp } 133866058Simp 133954773Simp /* 134054773Simp * Check if the revision register is something that I recognize. 134154773Simp * These might need to be added to later, as future revisions could 134254773Simp * be added. 134354773Simp */ 1344121514Simp CSR_WRITE_2(sc, BANK_SELECT_REG_W, 0x3); 1345121514Simp revision_register = CSR_READ_2(sc, REVISION_REG_W); 134654773Simp if (!chip_ids[(revision_register >> 4) & 0xF]) { 134754773Simp 134854773Simp /* 134954773Simp * I don't regonize this chip, so... 135054773Simp */ 135154773Simp#ifdef SN_DEBUG 135254994Simp device_printf(dev, "test4 failed\n"); 135354773Simp#endif 135454994Simp goto error; 135554773Simp } 135666058Simp 135754773Simp /* 135854773Simp * at this point I'll assume that the chip is an SMC9xxx. It might be 135954773Simp * prudent to check a listing of MAC addresses against the hardware 136054773Simp * address, or do some other tests. 136154773Simp */ 136254994Simp sn_deactivate(dev); 136354773Simp return 0; 136454994Simp error: 136554994Simp sn_deactivate(dev); 136654994Simp return ENXIO; 136754773Simp} 136854773Simp 136954773Simp#define MCFSZ 8 137054773Simp 137154773Simpstatic void 137254773Simpsn_setmcast(struct sn_softc *sc) 137354773Simp{ 1374147256Sbrooks struct ifnet *ifp = sc->ifp; 137554773Simp int flags; 1376121589Simp uint8_t mcf[MCFSZ]; 137754773Simp 1378121589Simp SN_ASSERT_LOCKED(sc); 1379121589Simp 138054773Simp /* 138154773Simp * Set the receiver filter. We want receive enabled and auto strip 138254773Simp * of CRC from received packet. If we are promiscuous then set that 138354773Simp * bit too. 138454773Simp */ 138554773Simp flags = RCR_ENABLE | RCR_STRIP_CRC; 138654773Simp 138754773Simp if (ifp->if_flags & IFF_PROMISC) { 138854773Simp flags |= RCR_PROMISC | RCR_ALMUL; 138954773Simp } else if (ifp->if_flags & IFF_ALLMULTI) { 139054773Simp flags |= RCR_ALMUL; 139154773Simp } else { 1392147256Sbrooks if (sn_getmcf(ifp, mcf)) { 139354773Simp /* set filter */ 1394121514Simp SMC_SELECT_BANK(sc, 3); 1395121514Simp CSR_WRITE_2(sc, MULTICAST1_REG_W, 1396121589Simp ((uint16_t)mcf[1] << 8) | mcf[0]); 1397121514Simp CSR_WRITE_2(sc, MULTICAST2_REG_W, 1398121589Simp ((uint16_t)mcf[3] << 8) | mcf[2]); 1399121514Simp CSR_WRITE_2(sc, MULTICAST3_REG_W, 1400121589Simp ((uint16_t)mcf[5] << 8) | mcf[4]); 1401121514Simp CSR_WRITE_2(sc, MULTICAST4_REG_W, 1402121589Simp ((uint16_t)mcf[7] << 8) | mcf[6]); 140354773Simp } else { 140454773Simp flags |= RCR_ALMUL; 140554773Simp } 140654773Simp } 1407121514Simp SMC_SELECT_BANK(sc, 0); 1408121514Simp CSR_WRITE_2(sc, RECV_CONTROL_REG_W, flags); 140954773Simp} 141054773Simp 141154773Simpstatic int 1412147256Sbrookssn_getmcf(struct ifnet *ifp, uint8_t *mcf) 141354773Simp{ 141454773Simp int i; 1415121589Simp uint32_t index, index2; 1416121589Simp uint8_t *af = mcf; 141754773Simp struct ifmultiaddr *ifma; 141854773Simp 141954773Simp bzero(mcf, MCFSZ); 142054773Simp 1421195049Srwatson if_maddr_rlock(ifp); 1422147256Sbrooks TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 1423148654Srwatson if (ifma->ifma_addr->sa_family != AF_LINK) { 1424195049Srwatson if_maddr_runlock(ifp); 142554773Simp return 0; 1426148654Srwatson } 1427130270Snaddy index = ether_crc32_le(LLADDR((struct sockaddr_dl *) 1428130270Snaddy ifma->ifma_addr), ETHER_ADDR_LEN) & 0x3f; 142954773Simp index2 = 0; 143054773Simp for (i = 0; i < 6; i++) { 143154773Simp index2 <<= 1; 143254773Simp index2 |= (index & 0x01); 143354773Simp index >>= 1; 143454773Simp } 143554773Simp af[index2 >> 3] |= 1 << (index2 & 7); 143654773Simp } 1437195049Srwatson if_maddr_runlock(ifp); 143854773Simp return 1; /* use multicast filter */ 143954773Simp} 1440