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