xref: /openbsd-src/sys/arch/macppc/dev/if_mc.c (revision 5eec54d30947dc151bb9ec29e24d6c7f6c612ca1)
1*5eec54d3Sjsg /*	$OpenBSD: if_mc.c,v 1.35 2024/09/06 10:54:08 jsg Exp $	*/
295b52b4dSgwk /*	$NetBSD: if_mc.c,v 1.9.16.1 2006/06/21 14:53:13 yamt Exp $	*/
395b52b4dSgwk 
495b52b4dSgwk /*-
595b52b4dSgwk  * Copyright (c) 1997 David Huang <khym@bga.com>
695b52b4dSgwk  * All rights reserved.
795b52b4dSgwk  *
895b52b4dSgwk  * Portions of this code are based on code by Denton Gentry <denny1@home.com>
995b52b4dSgwk  * and Yanagisawa Takeshi <yanagisw@aa.ap.titech.ac.jp>.
1095b52b4dSgwk  *
1195b52b4dSgwk  * Redistribution and use in source and binary forms, with or without
1295b52b4dSgwk  * modification, are permitted provided that the following conditions
1395b52b4dSgwk  * are met:
1495b52b4dSgwk  * 1. Redistributions of source code must retain the above copyright
1595b52b4dSgwk  *    notice, this list of conditions and the following disclaimer.
1695b52b4dSgwk  * 2. The name of the author may not be used to endorse or promote products
1795b52b4dSgwk  *    derived from this software without specific prior written permission
1895b52b4dSgwk  *
1995b52b4dSgwk  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2095b52b4dSgwk  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2195b52b4dSgwk  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2295b52b4dSgwk  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2395b52b4dSgwk  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2495b52b4dSgwk  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2595b52b4dSgwk  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2695b52b4dSgwk  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2795b52b4dSgwk  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2895b52b4dSgwk  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2995b52b4dSgwk  *
3095b52b4dSgwk  */
3195b52b4dSgwk 
3295b52b4dSgwk /*
3395b52b4dSgwk  * AMD AM79C940 (MACE) driver with DBDMA bus attachment and DMA routines
3495b52b4dSgwk  * for onboard ethernet found on most old world macs.
3595b52b4dSgwk  */
3695b52b4dSgwk 
3795b52b4dSgwk #include <sys/param.h>
3895b52b4dSgwk #include <sys/systm.h>
3995b52b4dSgwk #include <sys/mbuf.h>
4095b52b4dSgwk #include <sys/buf.h>
4195b52b4dSgwk #include <sys/socket.h>
4295b52b4dSgwk #include <sys/syslog.h>
4395b52b4dSgwk #include <sys/ioctl.h>
4495b52b4dSgwk #include <sys/errno.h>
4595b52b4dSgwk #include <sys/device.h>
463f1243dcSderaadt #include <sys/timeout.h>
4795b52b4dSgwk 
4895b52b4dSgwk #include <net/if.h>
4995b52b4dSgwk #include <net/if_media.h>
5095b52b4dSgwk 
5195b52b4dSgwk #include <netinet/in.h>
5295b52b4dSgwk #include <netinet/if_ether.h>
5395b52b4dSgwk 
5495b52b4dSgwk #include "bpfilter.h"
5595b52b4dSgwk #if NBPFILTER > 0
5695b52b4dSgwk #include <net/bpf.h>
5795b52b4dSgwk #endif
5895b52b4dSgwk 
5995b52b4dSgwk #include <dev/ofw/openfirm.h>
6095b52b4dSgwk #include <machine/pio.h>
6195b52b4dSgwk #include <machine/bus.h>
6295b52b4dSgwk #include <machine/autoconf.h>
6395b52b4dSgwk 
6495b52b4dSgwk #include <macppc/dev/dbdma.h>
6595b52b4dSgwk 
6695b52b4dSgwk #define MC_REGSPACING   	16
6795b52b4dSgwk #define MC_REGSIZE      	MACE_NREGS * MC_REGSPACING
6895b52b4dSgwk #define MACE_REG(x)     	((x)*MC_REGSPACING)
6995b52b4dSgwk #define MACE_BUFLEN		2048
7095b52b4dSgwk #define MACE_TXBUFS		2
7195b52b4dSgwk #define MACE_RXBUFS		8
7295b52b4dSgwk 
7395b52b4dSgwk #define MC_RXDMABUFS		4
7495b52b4dSgwk 
7595b52b4dSgwk #define MACE_BUFSZ       	((MACE_RXBUFS + MACE_TXBUFS + 2) * MACE_BUFLEN)
7695b52b4dSgwk 
7795b52b4dSgwk #define NIC_GET(sc, reg)	(in8rb(sc->sc_reg + MACE_REG(reg)))
7895b52b4dSgwk 
7995b52b4dSgwk #define NIC_PUT(sc, reg, val)   (out8rb(sc->sc_reg + MACE_REG(reg), (val)))
8095b52b4dSgwk 
8195b52b4dSgwk /*
8295b52b4dSgwk  * AMD MACE (Am79C940) register definitions
8395b52b4dSgwk  */
8495b52b4dSgwk #define	MACE_RCVFIFO		0   /* Receive FIFO [15-00] (read only) */
8595b52b4dSgwk #define	MACE_XMTFIFO		1   /* Transmit FIFO [15-00] (write only) */
8695b52b4dSgwk #define	MACE_XMTFC		2   /* Transmit Frame Control (read/write) */
8795b52b4dSgwk #define	MACE_XMTFS		3   /* Transmit Frame Status (read only) */
8895b52b4dSgwk #define	MACE_XMTRC		4   /* Transmit Retry Count (read only) */
8995b52b4dSgwk #define	MACE_RCVFC		5   /* Receive Frame Control (read/write) */
9095b52b4dSgwk #define	MACE_RCVFS		6   /* Receive Frame Status (4 bytes) (read only) */
9195b52b4dSgwk #define	MACE_FIFOFC		7   /* FIFO Frame Count (read only) */
9295b52b4dSgwk #define	MACE_IR			8   /* Interrupt Register (read only) */
9395b52b4dSgwk #define	MACE_IMR		9   /* Interrupt Mask Register (read/write) */
9495b52b4dSgwk #define	MACE_PR			10  /* Poll Register (read only) */
9595b52b4dSgwk #define	MACE_BIUCC		11  /* BIU Configuration Control (read/write) */
9695b52b4dSgwk #define	MACE_FIFOCC		12  /* FIFO Configuration Control (read/write) */
9795b52b4dSgwk #define	MACE_MACCC		13  /* MAC Configuration Control (read/write) */
9895b52b4dSgwk #define	MACE_PLSCC		14  /* PLS Configuration Control (read/write) */
99*5eec54d3Sjsg #define	MACE_PHYCC		15  /* PHY Configuration Control (read/write) */
10095b52b4dSgwk #define	MACE_CHIPIDL		16  /* Chip ID Register [07-00] (read only) */
10195b52b4dSgwk #define	MACE_CHIPIDH		17  /* Chip ID Register [15-08] (read only) */
10295b52b4dSgwk #define	MACE_IAC		18  /* Internal Address Configuration (read/write) */
10395b52b4dSgwk /*	RESERVED		19     Reserved (read/write as 0) */
10495b52b4dSgwk #define	MACE_LADRF		20  /* Logical Address Filter (8 bytes) (read/write) */
10595b52b4dSgwk #define	MACE_PADR		21  /* Physical Address (6 bytes) (read/write) */
10695b52b4dSgwk /*	RESERVED		22     Reserved (read/write as 0) */
10795b52b4dSgwk /*	RESERVED		23     Reserved (read/write as 0) */
10895b52b4dSgwk #define	MACE_MPC		24  /* Missed Packet Count (read only) */
10995b52b4dSgwk /*	RESERVED		25     Reserved (read/write as 0) */
11095b52b4dSgwk #define	MACE_RNTPC		26  /* Runt Packet Count (read only) */
11195b52b4dSgwk #define	MACE_RCVCC		27  /* Receive Collision Count (read only) */
11295b52b4dSgwk /*	RESERVED		28     Reserved (read/write as 0) */
11395b52b4dSgwk #define	MACE_UTR		29  /* User Test Register (read/write) */
11495b52b4dSgwk #define	MACE_RTR1		30  /* Reserved Test Register 1 (read/write as 0) */
11595b52b4dSgwk #define	MACE_RTR2		31  /* Reserved Test Register 2 (read/write as 0) */
11695b52b4dSgwk 
11795b52b4dSgwk #define	MACE_NREGS		32
11895b52b4dSgwk 
11995b52b4dSgwk /* 2: Transmit Frame Control (XMTFC) */
12095b52b4dSgwk #define	DRTRY			0x80	/* Disable Retry */
12195b52b4dSgwk #define	DXMTFCS			0x08	/* Disable Transmit FCS */
12295b52b4dSgwk #define	APADXMT			0x01	/* Auto Pad Transmit */
12395b52b4dSgwk 
12495b52b4dSgwk /* 3: Transmit Frame Status (XMTFS) */
12595b52b4dSgwk #define	XMTSV			0x80	/* Transmit Status Valid */
12695b52b4dSgwk #define	UFLO			0x40	/* Underflow */
12795b52b4dSgwk #define	LCOL			0x20	/* Late Collision */
12895b52b4dSgwk #define	MORE			0x10	/* More than one retry needed */
12995b52b4dSgwk #define	ONE			0x08	/* Exactly one retry needed */
13095b52b4dSgwk #define	DEFER			0x04	/* Transmission deferred */
13195b52b4dSgwk #define	LCAR			0x02	/* Loss of Carrier */
13295b52b4dSgwk #define	RTRY			0x01	/* Retry Error */
13395b52b4dSgwk 
13495b52b4dSgwk /* 4: Transmit Retry Count (XMTRC) */
13595b52b4dSgwk #define	EXDEF			0x80	/* Excessive Defer */
13695b52b4dSgwk #define	XMTRC			0x0f	/* Transmit Retry Count */
13795b52b4dSgwk 
13895b52b4dSgwk /* 5: Receive Frame Control (RCVFC) */
13995b52b4dSgwk #define	LLRCV			0x08	/* Low Latency Receive */
14095b52b4dSgwk #define	MR			0x04	/* Match/Reject */
14195b52b4dSgwk #define	ASTRPRCV		0x01	/* Auto Strip Receive */
14295b52b4dSgwk 
14395b52b4dSgwk /* 6: Receive Frame Status (RCVFS) */
14495b52b4dSgwk /* 4 byte register; read 4 times to get all of the bytes */
14595b52b4dSgwk /* Read 1: RFS0 - Receive Message Byte Count [7-0] (RCVCNT) */
14695b52b4dSgwk 
14795b52b4dSgwk /* Read 2: RFS1 - Receive Status (RCVSTS) */
14895b52b4dSgwk #define	OFLO			0x80	/* Overflow flag */
14995b52b4dSgwk #define	CLSN			0x40	/* Collision flag */
15095b52b4dSgwk #define	FRAM			0x20	/* Framing Error flag */
15195b52b4dSgwk #define	FCS			0x10	/* FCS Error flag */
15295b52b4dSgwk #define	RCVCNT			0x0f	/* Receive Message Byte Count [11-8] */
15395b52b4dSgwk 
15495b52b4dSgwk /* Read 3: RFS2 - Runt Packet Count (RNTPC) [7-0] */
15595b52b4dSgwk 
15695b52b4dSgwk /* Read 4: RFS3 - Receive Collision Count (RCVCC) [7-0] */
15795b52b4dSgwk 
15895b52b4dSgwk /* 7: FIFO Frame Count (FIFOFC) */
15995b52b4dSgwk #define	RCVFC			0xf0	/* Receive Frame Count */
16095b52b4dSgwk #define	XMTFC			0x0f	/* Transmit Frame Count */
16195b52b4dSgwk 
16295b52b4dSgwk /* 8: Interrupt Register (IR) */
16395b52b4dSgwk #define	JAB			0x80	/* Jabber Error */
16495b52b4dSgwk #define	BABL			0x40	/* Babble Error */
16595b52b4dSgwk #define	CERR			0x20	/* Collision Error */
16695b52b4dSgwk #define	RCVCCO			0x10	/* Receive Collision Count Overflow */
16795b52b4dSgwk #define	RNTPCO			0x08	/* Runt Packet Count Overflow */
16895b52b4dSgwk #define	MPCO			0x04	/* Missed Packet Count Overflow */
16995b52b4dSgwk #define	RCVINT			0x02	/* Receive Interrupt */
17095b52b4dSgwk #define	XMTINT			0x01	/* Transmit Interrupt */
17195b52b4dSgwk 
17236fd90dcSjsg /* 9: Interrupt Mask Register (IMR) */
17395b52b4dSgwk #define	JABM			0x80	/* Jabber Error Mask */
17495b52b4dSgwk #define	BABLM			0x40	/* Babble Error Mask */
17595b52b4dSgwk #define	CERRM			0x20	/* Collision Error Mask */
17695b52b4dSgwk #define	RCVCCOM			0x10	/* Receive Collision Count Overflow Mask */
17795b52b4dSgwk #define	RNTPCOM			0x08	/* Runt Packet Count Overflow Mask */
17895b52b4dSgwk #define	MPCOM			0x04	/* Missed Packet Count Overflow Mask */
17995b52b4dSgwk #define	RCVINTM			0x02	/* Receive Interrupt Mask */
18095b52b4dSgwk #define	XMTINTM			0x01	/* Transmit Interrupt Mask */
18195b52b4dSgwk 
18295b52b4dSgwk /* 10: Poll Register (PR) */
18395b52b4dSgwk #define	XMTSV			0x80	/* Transmit Status Valid */
18495b52b4dSgwk #define	TDTREQ			0x40	/* Transmit Data Transfer Request */
18595b52b4dSgwk #define	RDTREQ			0x20	/* Receive Data Transfer Request */
18695b52b4dSgwk 
18795b52b4dSgwk /* 11: BIU Configuration Control (BIUCC) */
18895b52b4dSgwk #define	BSWP			0x40	/* Byte Swap */
18995b52b4dSgwk #define	XMTSP			0x30	/* Transmit Start Point */
19095b52b4dSgwk #define	XMTSP_4			0x00	/* 4 bytes */
19195b52b4dSgwk #define	XMTSP_16		0x10	/* 16 bytes */
19295b52b4dSgwk #define	XMTSP_64		0x20	/* 64 bytes */
19395b52b4dSgwk #define	XMTSP_112		0x30	/* 112 bytes */
19495b52b4dSgwk #define	SWRST			0x01	/* Software Reset */
19595b52b4dSgwk 
19695b52b4dSgwk /* 12: FIFO Configuration Control (FIFOCC) */
19795b52b4dSgwk #define	XMTFW			0xc0	/* Transmit FIFO Watermark */
19895b52b4dSgwk #define	XMTFW_8			0x00	/* 8 write cycles */
19995b52b4dSgwk #define	XMTFW_16		0x40	/* 16 write cycles */
20095b52b4dSgwk #define	XMTFW_32		0x80	/* 32 write cycles */
20195b52b4dSgwk #define	RCVFW			0x30	/* Receive FIFO Watermark */
20295b52b4dSgwk #define	RCVFW_16		0x00	/* 16 bytes */
20395b52b4dSgwk #define	RCVFW_32		0x10	/* 32 bytes */
20495b52b4dSgwk #define	RCVFW_64		0x20	/* 64 bytes */
20595b52b4dSgwk #define	XMTFWU			0x08	/* Transmit FIFO Watermark Update */
20695b52b4dSgwk #define	RCVFWU			0x04	/* Receive FIFO Watermark Update */
20795b52b4dSgwk #define	XMTBRST			0x02	/* Transmit Burst */
20895b52b4dSgwk #define	RCVBRST			0x01	/* Receive Burst */
20995b52b4dSgwk 
21095b52b4dSgwk /* 13: MAC Configuration (MACCC) */
21195b52b4dSgwk #define	PROM			0x80	/* Promiscuous */
21295b52b4dSgwk #define	DXMT2PD			0x40	/* Disable Transmit Two Part Deferral */
21395b52b4dSgwk #define	EMBA			0x20	/* Enable Modified Back-off Algorithm */
21495b52b4dSgwk #define	DRCVPA			0x08	/* Disable Receive Physical Address */
21595b52b4dSgwk #define	DRCVBC			0x04	/* Disable Receive Broadcast */
21695b52b4dSgwk #define	ENXMT			0x02	/* Enable Transmit */
21795b52b4dSgwk #define	ENRCV			0x01	/* Enable Receive */
21895b52b4dSgwk 
21995b52b4dSgwk /* 14: PLS Configuration Control (PLSCC) */
22095b52b4dSgwk #define	XMTSEL			0x08	/* Transmit Mode Select */
22195b52b4dSgwk #define	PORTSEL			0x06	/* Port Select */
22295b52b4dSgwk #define	PORTSEL_AUI		0x00	/* Select AUI */
22395b52b4dSgwk #define	PORTSEL_10BT		0x02	/* Select 10BASE-T */
22495b52b4dSgwk #define	PORTSEL_DAI		0x04	/* Select DAI port */
22595b52b4dSgwk #define	PORTSEL_GPSI		0x06	/* Select GPSI */
22695b52b4dSgwk #define	ENPLSIO			0x01	/* Enable PLS I/O */
22795b52b4dSgwk 
22895b52b4dSgwk /* 15: PHY Configuration (PHYCC) */
22995b52b4dSgwk #define	LNKFL			0x80	/* Link Fail */
23095b52b4dSgwk #define	DLNKTST			0x40	/* Disable Link Test */
23195b52b4dSgwk #define	REVPOL			0x20	/* Reversed Polarity */
23295b52b4dSgwk #define	DAPC			0x10	/* Disable Auto Polarity Correction */
23395b52b4dSgwk #define	LRT			0x08	/* Low Receive Threshold */
23495b52b4dSgwk #define	ASEL			0x04	/* Auto Select */
23595b52b4dSgwk #define	RWAKE			0x02	/* Remote Wake */
23695b52b4dSgwk #define	AWAKE			0x01	/* Auto Wake */
23795b52b4dSgwk 
23895b52b4dSgwk /* 18: Internal Address Configuration (IAC) */
23995b52b4dSgwk #define	ADDRCHG			0x80	/* Address Change */
24095b52b4dSgwk #define	PHYADDR			0x04	/* Physical Address Reset */
24195b52b4dSgwk #define	LOGADDR			0x02	/* Logical Address Reset */
24295b52b4dSgwk 
24395b52b4dSgwk /* 28: User Test Register (UTR) */
24495b52b4dSgwk #define	RTRE			0x80	/* Reserved Test Register Enable */
24595b52b4dSgwk #define	RTRD			0x40	/* Reserved Test Register Disable */
24695b52b4dSgwk #define	RPA			0x20	/* Run Packet Accept */
24795b52b4dSgwk #define	FCOLL			0x10	/* Force Collision */
24895b52b4dSgwk #define	RCVFCSE			0x08	/* Receive FCS Enable */
24995b52b4dSgwk #define	LOOP			0x06	/* Loopback Control */
25095b52b4dSgwk #define	LOOP_NONE		0x00	/* No Loopback */
25195b52b4dSgwk #define	LOOP_EXT		0x02	/* External Loopback */
25295b52b4dSgwk #define	LOOP_INT		0x04	/* Internal Loopback, excludes MENDEC */
25395b52b4dSgwk #define	LOOP_INT_MENDEC		0x06	/* Internal Loopback, includes MENDEC */
25495b52b4dSgwk 
25595b52b4dSgwk struct mc_rxframe {
25695b52b4dSgwk 	u_int8_t		rx_rcvcnt;
25795b52b4dSgwk 	u_int8_t		rx_rcvsts;
25895b52b4dSgwk 	u_int8_t		rx_rntpc;
25995b52b4dSgwk 	u_int8_t		rx_rcvcc;
26095b52b4dSgwk 	u_char			*rx_frame;
26195b52b4dSgwk };
26295b52b4dSgwk 
26395b52b4dSgwk struct mc_softc {
26495b52b4dSgwk 	struct device	   	sc_dev;		/* base device glue */
26595b52b4dSgwk 	struct arpcom	   	sc_arpcom;	/* Ethernet common part */
26695b52b4dSgwk 	struct timeout	  	sc_tick_ch;
26795b52b4dSgwk 
26895b52b4dSgwk 	struct mc_rxframe       sc_rxframe;
26995b52b4dSgwk 	u_int8_t		sc_biucc;
27095b52b4dSgwk 	u_int8_t		sc_fifocc;
27195b52b4dSgwk 	u_int8_t		sc_plscc;
27295b52b4dSgwk 	u_int8_t		sc_enaddr[6];
27395b52b4dSgwk 	u_int8_t		sc_pad[2];
27495b52b4dSgwk 	int			sc_havecarrier; /* carrier status */
27595b52b4dSgwk 
27695b52b4dSgwk 	char			*sc_reg;
27795b52b4dSgwk 	bus_dma_tag_t		sc_dmat;
27895b52b4dSgwk 	bus_dmamap_t		sc_bufmap;
27995b52b4dSgwk 	bus_dma_segment_t       sc_bufseg[1];
28095b52b4dSgwk 
28195b52b4dSgwk 	dbdma_regmap_t		*sc_txdma;
28295b52b4dSgwk 	dbdma_regmap_t		*sc_rxdma;
28395b52b4dSgwk 	dbdma_command_t		*sc_txdmacmd;
28495b52b4dSgwk 	dbdma_command_t		*sc_rxdmacmd;
28595b52b4dSgwk 	dbdma_t			sc_txdbdma;
28695b52b4dSgwk 	dbdma_t			sc_rxdbdma;
28795b52b4dSgwk 
28895b52b4dSgwk 	caddr_t			sc_txbuf;
28995b52b4dSgwk 	caddr_t			sc_rxbuf;
29095b52b4dSgwk 	paddr_t			sc_txbuf_pa;
29195b52b4dSgwk 	paddr_t			sc_rxbuf_pa;
29295b52b4dSgwk 	int			sc_tail;
29395b52b4dSgwk 	int			sc_rxset;
29495b52b4dSgwk 	int			sc_txset;
29595b52b4dSgwk 	int			sc_txseti;
29695b52b4dSgwk };
29795b52b4dSgwk 
29895b52b4dSgwk int	mc_match(struct device *, void *, void *);
29995b52b4dSgwk void	mc_attach(struct device *, struct device *, void *);
30095b52b4dSgwk 
301471aeecfSnaddy const struct cfattach mc_ca = {
30295b52b4dSgwk 	sizeof(struct mc_softc), mc_match, mc_attach
30395b52b4dSgwk };
30495b52b4dSgwk 
30595b52b4dSgwk struct cfdriver mc_cd = {
30695b52b4dSgwk 	NULL, "mc", DV_IFNET
30795b52b4dSgwk };
30895b52b4dSgwk 
309947a7310Sgwk void	mc_init(struct mc_softc *sc);
31095b52b4dSgwk int	mc_dmaintr(void *arg);
31195b52b4dSgwk void	mc_reset_rxdma(struct mc_softc *sc);
31295b52b4dSgwk void	mc_reset_txdma(struct mc_softc *sc);
31395b52b4dSgwk int     mc_stop(struct mc_softc *sc);
31495b52b4dSgwk int     mc_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data);
31595b52b4dSgwk void    mc_start(struct ifnet *ifp);
31695b52b4dSgwk void    mc_reset(struct mc_softc *sc);
31795b52b4dSgwk void    mc_tint(struct mc_softc *sc);
31895b52b4dSgwk void	mc_rint(struct mc_softc *sc);
31995b52b4dSgwk int	mc_intr(void *);
32095b52b4dSgwk void	mc_watchdog(struct ifnet *ifp);
32195b52b4dSgwk 
32295b52b4dSgwk u_int   maceput(struct mc_softc *sc, struct mbuf *);
32395b52b4dSgwk void    mace_read(struct mc_softc *, caddr_t, int);
32495b52b4dSgwk struct mbuf *mace_get(struct mc_softc *, caddr_t, int);
325947a7310Sgwk static void mace_calcladrf(struct mc_softc *, u_int8_t *);
32695b52b4dSgwk void	mc_putpacket(struct mc_softc *, u_int);
32795b52b4dSgwk 
32895b52b4dSgwk int
32995b52b4dSgwk mc_match(struct device *parent, void *arg, void *aux)
33095b52b4dSgwk {
33195b52b4dSgwk 	struct confargs *ca = aux;
33295b52b4dSgwk 
33395b52b4dSgwk 	if (strcmp(ca->ca_name, "mace") != 0)
33495b52b4dSgwk 		return 0;
33595b52b4dSgwk 
33695b52b4dSgwk 	/* requires 6 regs */
33795b52b4dSgwk 	if (ca->ca_nreg / sizeof(int) != 6)
33895b52b4dSgwk 		return 0;
33995b52b4dSgwk 
34095b52b4dSgwk 	/* requires 3 intrs */
34195b52b4dSgwk 	if (ca->ca_nintr / sizeof(int) != 3)
34295b52b4dSgwk 		return 0;
34395b52b4dSgwk 
34495b52b4dSgwk 	return 1;
34595b52b4dSgwk }
34695b52b4dSgwk 
34795b52b4dSgwk void
34895b52b4dSgwk mc_attach(struct device *parent, struct device *self, void *aux)
34995b52b4dSgwk {
35095b52b4dSgwk 	struct confargs *ca = aux;
35195b52b4dSgwk 	struct mc_softc *sc = (struct mc_softc *)self;
35295b52b4dSgwk 	struct ifnet *ifp = &sc->sc_arpcom.ac_if;
35395b52b4dSgwk 	u_int8_t lladdr[ETHER_ADDR_LEN];
35495b52b4dSgwk 	int nseg, error;
35595b52b4dSgwk 
356e6734d7fSgwk 	if (OF_getprop(ca->ca_node, "local-mac-address", lladdr,
357e6734d7fSgwk 	    ETHER_ADDR_LEN) != ETHER_ADDR_LEN) {
35895b52b4dSgwk 		printf(": failed to get MAC address.\n");
35995b52b4dSgwk 		return;
36095b52b4dSgwk 	}
36195b52b4dSgwk 
36295b52b4dSgwk 	ca->ca_reg[0] += ca->ca_baseaddr;
36395b52b4dSgwk 	ca->ca_reg[2] += ca->ca_baseaddr;
36495b52b4dSgwk 	ca->ca_reg[4] += ca->ca_baseaddr;
36595b52b4dSgwk 
366e6734d7fSgwk 	if ((sc->sc_reg = mapiodev(ca->ca_reg[0], ca->ca_reg[1])) == NULL) {
367e6734d7fSgwk 		printf(": cannot map registers\n");
368e6734d7fSgwk 		return;
369e6734d7fSgwk 	}
37095b52b4dSgwk 
371e6734d7fSgwk 	sc->sc_dmat = ca->ca_dmat;
37295b52b4dSgwk 	sc->sc_tail = 0;
373e6734d7fSgwk 
374e6734d7fSgwk 	if ((sc->sc_txdma = mapiodev(ca->ca_reg[2], ca->ca_reg[3])) == NULL) {
375e6734d7fSgwk 		printf(": cannot map TX DMA registers\n");
376e6734d7fSgwk 		goto notxdma;
377e6734d7fSgwk 	}
378e6734d7fSgwk 	if ((sc->sc_rxdma = mapiodev(ca->ca_reg[4], ca->ca_reg[5])) == NULL) {
379e6734d7fSgwk 		printf(": cannot map RX DMA registers\n");
380e6734d7fSgwk 		goto norxdma;
381e6734d7fSgwk 	}
382e6734d7fSgwk 	if ((sc->sc_txdbdma = dbdma_alloc(sc->sc_dmat, 2)) == NULL) {
383e6734d7fSgwk 		printf(": cannot alloc TX DMA descriptors\n");
384e6734d7fSgwk 		goto notxdbdma;
385e6734d7fSgwk 	}
38695b52b4dSgwk 	sc->sc_txdmacmd = sc->sc_txdbdma->d_addr;
387e6734d7fSgwk 
388e6734d7fSgwk 	if ((sc->sc_rxdbdma = dbdma_alloc(sc->sc_dmat, 8 + 1)) == NULL) {
389e6734d7fSgwk 		printf(": cannot alloc RX DMA descriptors\n");
390e6734d7fSgwk 		goto norxdbdma;
391e6734d7fSgwk 	}
39295b52b4dSgwk 	sc->sc_rxdmacmd = sc->sc_rxdbdma->d_addr;
39395b52b4dSgwk 
394e6734d7fSgwk 	if ((error = bus_dmamem_alloc(sc->sc_dmat, MACE_BUFSZ, PAGE_SIZE, 0,
395e6734d7fSgwk 	    sc->sc_bufseg, 1, &nseg, BUS_DMA_NOWAIT))) {
396e6734d7fSgwk 		printf(": cannot allocate DMA mem (%d)\n", error);
397e6734d7fSgwk 		goto nodmamem;
39895b52b4dSgwk 	}
39995b52b4dSgwk 
400e6734d7fSgwk 	if ((error = bus_dmamem_map(sc->sc_dmat, sc->sc_bufseg, nseg,
401e6734d7fSgwk 	    MACE_BUFSZ, &sc->sc_txbuf, BUS_DMA_NOWAIT))) {
402e6734d7fSgwk 		printf(": cannot map DMA mem (%d)\n", error);
403e6734d7fSgwk 		goto nodmamap;
40495b52b4dSgwk 	}
40595b52b4dSgwk 
406e6734d7fSgwk 	if ((error = bus_dmamap_create(sc->sc_dmat, MACE_BUFSZ, 1, MACE_BUFSZ,
407e6734d7fSgwk 	    0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &sc->sc_bufmap))) {
408e6734d7fSgwk 		printf(": cannot create DMA map (%d)\n", error);
409e6734d7fSgwk 		goto nodmacreate;
41095b52b4dSgwk 	}
41195b52b4dSgwk 
412e6734d7fSgwk 	if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_bufmap, sc->sc_txbuf,
413e6734d7fSgwk 	    MACE_BUFSZ, NULL, BUS_DMA_NOWAIT))) {
414e6734d7fSgwk 		printf(": cannot load DMA map (%d)\n", error);
415e6734d7fSgwk 		goto nodmaload;
41695b52b4dSgwk 	}
41795b52b4dSgwk 
41895b52b4dSgwk 	sc->sc_txbuf_pa = sc->sc_bufmap->dm_segs->ds_addr;
41995b52b4dSgwk 	sc->sc_rxbuf = sc->sc_txbuf + MACE_BUFLEN * MACE_TXBUFS;
42095b52b4dSgwk 	sc->sc_rxbuf_pa = sc->sc_txbuf_pa + MACE_BUFLEN * MACE_TXBUFS;
42195b52b4dSgwk 
422e6734d7fSgwk 	printf(": irq %d,%d,%d", ca->ca_intr[0], ca->ca_intr[1],
423e6734d7fSgwk 	    ca->ca_intr[2]);
42495b52b4dSgwk 
42595b52b4dSgwk 	/* disable receive DMA */
42695b52b4dSgwk 	dbdma_reset(sc->sc_rxdma);
42795b52b4dSgwk 
42895b52b4dSgwk 	/* disable transmit DMA */
42995b52b4dSgwk 	dbdma_reset(sc->sc_txdma);
43095b52b4dSgwk 
43195b52b4dSgwk 	/* install interrupt handlers */
43295b52b4dSgwk 	mac_intr_establish(parent, ca->ca_intr[2], IST_LEVEL, IPL_NET,
4331ac74572Sderaadt 	    mc_dmaintr, sc, sc->sc_dev.dv_xname);
43495b52b4dSgwk 	mac_intr_establish(parent, ca->ca_intr[0],  IST_LEVEL, IPL_NET,
4351ac74572Sderaadt 	    mc_intr, sc, sc->sc_dev.dv_xname);
43695b52b4dSgwk 
43795b52b4dSgwk 	sc->sc_biucc = XMTSP_64;
43895b52b4dSgwk 	sc->sc_fifocc = XMTFW_16 | RCVFW_64 | XMTFWU | RCVFWU |
43995b52b4dSgwk 	    XMTBRST | RCVBRST;
44095b52b4dSgwk 	sc->sc_plscc = PORTSEL_GPSI | ENPLSIO;
44195b52b4dSgwk 
44295b52b4dSgwk 	/* reset the chip and disable all interrupts */
44395b52b4dSgwk 	NIC_PUT(sc, MACE_BIUCC, SWRST);
44495b52b4dSgwk 	DELAY(100);
44595b52b4dSgwk 
44695b52b4dSgwk 	NIC_PUT(sc, MACE_IMR, ~0);
44795b52b4dSgwk 
44895b52b4dSgwk 	bcopy(lladdr, sc->sc_enaddr, ETHER_ADDR_LEN);
44995b52b4dSgwk 	bcopy(sc->sc_enaddr, sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN);
45095b52b4dSgwk 	printf(": address %s\n", ether_sprintf(lladdr));
45195b52b4dSgwk 
45295b52b4dSgwk 	bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
45395b52b4dSgwk 	ifp->if_softc = sc;
45495b52b4dSgwk 	ifp->if_ioctl = mc_ioctl;
45595b52b4dSgwk 	ifp->if_start = mc_start;
45695b52b4dSgwk 	ifp->if_flags =
4579d022f3eStedu 		IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
45895b52b4dSgwk 	ifp->if_watchdog = mc_watchdog;
45995b52b4dSgwk 	ifp->if_timer = 0;
46095b52b4dSgwk 
46195b52b4dSgwk 	if_attach(ifp);
46295b52b4dSgwk 	ether_ifattach(ifp);
463e6734d7fSgwk 
464e6734d7fSgwk 	return;
465e6734d7fSgwk nodmaload:
466e6734d7fSgwk 	bus_dmamap_destroy(sc->sc_dmat, sc->sc_bufmap);
467e6734d7fSgwk nodmacreate:
468e6734d7fSgwk 	bus_dmamem_unmap(sc->sc_dmat, sc->sc_txbuf, MACE_BUFSZ);
469e6734d7fSgwk nodmamap:
470e6734d7fSgwk 	bus_dmamem_free(sc->sc_dmat, sc->sc_bufseg, 1);
471e6734d7fSgwk nodmamem:
472e6734d7fSgwk 	dbdma_free(sc->sc_rxdbdma);
473e6734d7fSgwk norxdbdma:
474e6734d7fSgwk 	dbdma_free(sc->sc_txdbdma);
475e6734d7fSgwk notxdbdma:
4764471727cSkettenis 	unmapiodev((void *)sc->sc_rxdma, ca->ca_reg[5]);
477e6734d7fSgwk norxdma:
4784471727cSkettenis 	unmapiodev((void *)sc->sc_txdma, ca->ca_reg[3]);
479e6734d7fSgwk notxdma:
4804471727cSkettenis 	unmapiodev(sc->sc_reg, ca->ca_reg[1]);
48195b52b4dSgwk }
48295b52b4dSgwk 
48395b52b4dSgwk int
48495b52b4dSgwk mc_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
48595b52b4dSgwk {
48695b52b4dSgwk 	struct mc_softc *sc = ifp->if_softc;
487967f68a4Sbrad 	int s, err = 0;
48895b52b4dSgwk 
489967f68a4Sbrad 	s = splnet();
49095b52b4dSgwk 
49195b52b4dSgwk 	switch (cmd) {
49295b52b4dSgwk 	case SIOCSIFADDR:
49395b52b4dSgwk 		ifp->if_flags |= IFF_UP;
494947a7310Sgwk 		if (!(ifp->if_flags & IFF_RUNNING))
495947a7310Sgwk 			mc_init(sc);
49695b52b4dSgwk 		break;
49795b52b4dSgwk 
49895b52b4dSgwk 	case SIOCSIFFLAGS:
49995b52b4dSgwk 		if ((ifp->if_flags & IFF_UP) == 0 &&
50095b52b4dSgwk 		    (ifp->if_flags & IFF_RUNNING) != 0) {
50195b52b4dSgwk 			/*
50295b52b4dSgwk 			 * If interface is marked down and it is running,
50395b52b4dSgwk 			 * then stop it.
50495b52b4dSgwk 			 */
50595b52b4dSgwk 			mc_stop(sc);
50695b52b4dSgwk 		} else if ((ifp->if_flags & IFF_UP) != 0 &&
50795b52b4dSgwk 		    (ifp->if_flags & IFF_RUNNING) == 0) {
50895b52b4dSgwk 			/*
50995b52b4dSgwk 			 * If interface is marked up and it is stopped,
51095b52b4dSgwk 			 * then start it.
51195b52b4dSgwk 			 */
512947a7310Sgwk 			mc_init(sc);
51395b52b4dSgwk 		} else {
51495b52b4dSgwk 			/*
51595b52b4dSgwk 			 * reset the interface to pick up any other changes
51695b52b4dSgwk 			 * in flags
51795b52b4dSgwk 			 */
51895b52b4dSgwk 			mc_reset(sc);
51995b52b4dSgwk 			mc_start(ifp);
52095b52b4dSgwk 		}
52195b52b4dSgwk 		break;
52295b52b4dSgwk 
52334f0f0fdSbrad 	default:
52434f0f0fdSbrad 		err = ether_ioctl(ifp, &sc->sc_arpcom, cmd, data);
52534f0f0fdSbrad 	}
52695b52b4dSgwk 
52795b52b4dSgwk 	if (err == ENETRESET) {
52895b52b4dSgwk 		if (ifp->if_flags & IFF_RUNNING)
52995b52b4dSgwk 			mc_reset(sc);
53095b52b4dSgwk 		err = 0;
53195b52b4dSgwk 	}
532775775feSbrad 
53395b52b4dSgwk 	splx(s);
53495b52b4dSgwk 	return (err);
53595b52b4dSgwk }
53695b52b4dSgwk 
53795b52b4dSgwk /*
53895b52b4dSgwk  * Encapsulate a packet of type family for the local net.
53995b52b4dSgwk  */
54095b52b4dSgwk void
54195b52b4dSgwk mc_start(struct ifnet *ifp)
54295b52b4dSgwk {
54395b52b4dSgwk 	struct mc_softc	*sc = ifp->if_softc;
54495b52b4dSgwk 	struct mbuf	*m;
54595b52b4dSgwk 
546de6cd8fbSdlg 	if (!(ifp->if_flags & IFF_RUNNING) || ifq_is_oactive(&ifp->if_snd))
54795b52b4dSgwk 		return;
54895b52b4dSgwk 
54995b52b4dSgwk 	while (1) {
550de6cd8fbSdlg 		if (ifq_is_oactive(&ifp->if_snd))
55195b52b4dSgwk 			return;
55295b52b4dSgwk 
55363bcfa73Spatrick 		m = ifq_dequeue(&ifp->if_snd);
5549e3a439eSgwk 		if (m == NULL)
55595b52b4dSgwk 			return;
55695b52b4dSgwk 
55795b52b4dSgwk #if NBPFILTER > 0
55895b52b4dSgwk 		/*
55995b52b4dSgwk 		 * If bpf is listening on this interface, let it
56095b52b4dSgwk 		 * see the packet before we commit it to the wire.
56195b52b4dSgwk 		 */
56295b52b4dSgwk 		if (ifp->if_bpf)
56395b52b4dSgwk 			bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
56495b52b4dSgwk #endif
56595b52b4dSgwk 
56695b52b4dSgwk 		/*
56795b52b4dSgwk 		 * Copy the mbuf chain into the transmit buffer.
56895b52b4dSgwk 		 */
569de6cd8fbSdlg 		ifq_set_oactive(&ifp->if_snd);
57095b52b4dSgwk 		maceput(sc, m);
57195b52b4dSgwk 	}
57295b52b4dSgwk }
57395b52b4dSgwk 
57495b52b4dSgwk /*
57595b52b4dSgwk  * reset and restart the MACE.  Called in case of fatal
57695b52b4dSgwk  * hardware/software errors.
57795b52b4dSgwk  */
57895b52b4dSgwk void
57995b52b4dSgwk mc_reset(struct mc_softc *sc)
58095b52b4dSgwk {
58195b52b4dSgwk 	mc_stop(sc);
58295b52b4dSgwk 	mc_init(sc);
58395b52b4dSgwk }
58495b52b4dSgwk 
585947a7310Sgwk void
58695b52b4dSgwk mc_init(struct mc_softc *sc)
58795b52b4dSgwk {
588947a7310Sgwk 	struct ifnet *ifp = &sc->sc_arpcom.ac_if;
58995b52b4dSgwk 	u_int8_t maccc, ladrf[8];
590947a7310Sgwk 	int s, i;
59195b52b4dSgwk 
59295b52b4dSgwk 	s = splnet();
59395b52b4dSgwk 
59495b52b4dSgwk 	NIC_PUT(sc, MACE_BIUCC, sc->sc_biucc);
59595b52b4dSgwk 	NIC_PUT(sc, MACE_FIFOCC, sc->sc_fifocc);
59695b52b4dSgwk 	NIC_PUT(sc, MACE_IMR, ~0); /* disable all interrupts */
59795b52b4dSgwk 	NIC_PUT(sc, MACE_PLSCC, sc->sc_plscc);
59895b52b4dSgwk 
59995b52b4dSgwk 	NIC_PUT(sc, MACE_UTR, RTRD); /* disable reserved test registers */
60095b52b4dSgwk 
60195b52b4dSgwk 	/* set MAC address */
60295b52b4dSgwk 	NIC_PUT(sc, MACE_IAC, ADDRCHG);
60395b52b4dSgwk 	while (NIC_GET(sc, MACE_IAC) & ADDRCHG)
60495b52b4dSgwk 		;
60595b52b4dSgwk 	NIC_PUT(sc, MACE_IAC, PHYADDR);
60695b52b4dSgwk 	for (i = 0; i < ETHER_ADDR_LEN; i++)
60795b52b4dSgwk 		out8rb(sc->sc_reg + MACE_REG(MACE_PADR) + i,
60895b52b4dSgwk 		    sc->sc_enaddr[i]);
60995b52b4dSgwk 
61095b52b4dSgwk 	/* set logical address filter */
611947a7310Sgwk 	mace_calcladrf(sc, ladrf);
61295b52b4dSgwk 
61395b52b4dSgwk 	NIC_PUT(sc, MACE_IAC, ADDRCHG);
61495b52b4dSgwk 	while (NIC_GET(sc, MACE_IAC) & ADDRCHG)
61595b52b4dSgwk 		;
61695b52b4dSgwk 	NIC_PUT(sc, MACE_IAC, LOGADDR);
61795b52b4dSgwk 	for (i = 0; i < 8; i++)
61895b52b4dSgwk 		out8rb(sc->sc_reg + MACE_REG(MACE_LADRF) + i,
61995b52b4dSgwk 		    ladrf[i]);
62095b52b4dSgwk 
62195b52b4dSgwk 	NIC_PUT(sc, MACE_XMTFC, APADXMT);
62295b52b4dSgwk 	/*
62395b52b4dSgwk 	* No need to autostrip padding on receive... Ethernet frames
62495b52b4dSgwk 	* don't have a length field, unlike 802.3 frames, so the MACE
62595b52b4dSgwk 	* can't figure out the length of the packet anyways.
62695b52b4dSgwk 	*/
62795b52b4dSgwk 	NIC_PUT(sc, MACE_RCVFC, 0);
62895b52b4dSgwk 
62995b52b4dSgwk 	maccc = ENXMT | ENRCV;
630947a7310Sgwk 	if (ifp->if_flags & IFF_PROMISC)
63195b52b4dSgwk 		maccc |= PROM;
63295b52b4dSgwk 
63395b52b4dSgwk 	NIC_PUT(sc, MACE_MACCC, maccc);
63495b52b4dSgwk 
63595b52b4dSgwk 	mc_reset_rxdma(sc);
63695b52b4dSgwk 	mc_reset_txdma(sc);
63795b52b4dSgwk 	/*
63895b52b4dSgwk 	* Enable all interrupts except receive, since we use the DMA
63995b52b4dSgwk 	* completion interrupt for that.
64095b52b4dSgwk 	*/
64195b52b4dSgwk 	NIC_PUT(sc, MACE_IMR, RCVINTM);
64295b52b4dSgwk 
64395b52b4dSgwk 	/* flag interface as "running" */
644947a7310Sgwk 	ifp->if_flags |= IFF_RUNNING;
645de6cd8fbSdlg 	ifq_clr_oactive(&ifp->if_snd);
64695b52b4dSgwk 
64795b52b4dSgwk 	splx(s);
64895b52b4dSgwk }
64995b52b4dSgwk 
65095b52b4dSgwk /*
65195b52b4dSgwk  * Close down an interface and free its buffers.
65295b52b4dSgwk  * Called on final close of device, or if mcinit() fails
65395b52b4dSgwk  * part way through.
65495b52b4dSgwk  */
65595b52b4dSgwk int
65695b52b4dSgwk mc_stop(struct mc_softc *sc)
65795b52b4dSgwk {
658947a7310Sgwk 	struct ifnet *ifp = &sc->sc_arpcom.ac_if;
659947a7310Sgwk 	int s;
660947a7310Sgwk 
661947a7310Sgwk 	s = splnet();
66295b52b4dSgwk 
66395b52b4dSgwk 	NIC_PUT(sc, MACE_BIUCC, SWRST);
66495b52b4dSgwk 	DELAY(100);
66595b52b4dSgwk 
666947a7310Sgwk 	ifp->if_timer = 0;
667de6cd8fbSdlg 	ifp->if_flags &= ~IFF_RUNNING;
668de6cd8fbSdlg 	ifq_clr_oactive(&ifp->if_snd);
66995b52b4dSgwk 
67095b52b4dSgwk 	splx(s);
67195b52b4dSgwk 	return (0);
67295b52b4dSgwk }
67395b52b4dSgwk 
67495b52b4dSgwk /*
67595b52b4dSgwk  * Called if any Tx packets remain unsent after 5 seconds,
67695b52b4dSgwk  * In all cases we just reset the chip, and any retransmission
67795b52b4dSgwk  * will be handled by higher level protocol timeouts.
67895b52b4dSgwk  */
67995b52b4dSgwk void
68095b52b4dSgwk mc_watchdog(struct ifnet *ifp)
68195b52b4dSgwk {
68295b52b4dSgwk 	struct mc_softc *sc = ifp->if_softc;
68395b52b4dSgwk 
68495b52b4dSgwk 	printf("mcwatchdog: resetting chip\n");
68595b52b4dSgwk 	mc_reset(sc);
68695b52b4dSgwk }
68795b52b4dSgwk 
68895b52b4dSgwk int
68995b52b4dSgwk mc_intr(void *arg)
69095b52b4dSgwk {
69195b52b4dSgwk 	struct mc_softc *sc = arg;
692415e1820Sgwk 	struct ifnet *ifp = &sc->sc_arpcom.ac_if;
69395b52b4dSgwk 	u_int8_t ir;
69495b52b4dSgwk 
69595b52b4dSgwk 	ir = NIC_GET(sc, MACE_IR) & ~NIC_GET(sc, MACE_IMR);
696415e1820Sgwk 
69795b52b4dSgwk 	if (ir & JAB) {
69895b52b4dSgwk #ifdef MCDEBUG
69995b52b4dSgwk 		printf("%s: jabber error\n", sc->sc_dev.dv_xname);
70095b52b4dSgwk #endif
701415e1820Sgwk 		ifp->if_oerrors++;
70295b52b4dSgwk 	}
70395b52b4dSgwk 
70495b52b4dSgwk 	if (ir & BABL) {
70595b52b4dSgwk #ifdef MCDEBUG
70695b52b4dSgwk 		printf("%s: babble\n", sc->sc_dev.dv_xname);
70795b52b4dSgwk #endif
708415e1820Sgwk 		ifp->if_oerrors++;
70995b52b4dSgwk 	 }
71095b52b4dSgwk 
71195b52b4dSgwk 	if (ir & CERR) {
71295b52b4dSgwk #ifdef MCDEBUG
71395b52b4dSgwk 		printf("%s: collision error\n", sc->sc_dev.dv_xname);
71495b52b4dSgwk #endif
715415e1820Sgwk 		ifp->if_collisions++;
71695b52b4dSgwk 	 }
71795b52b4dSgwk 
71895b52b4dSgwk 	/*
71995b52b4dSgwk 	 * Pretend we have carrier; if we don't this will be cleared
72095b52b4dSgwk 	 * shortly.
72195b52b4dSgwk 	 */
72295b52b4dSgwk 	sc->sc_havecarrier = 1;
72395b52b4dSgwk 
72495b52b4dSgwk 	if (ir & XMTINT)
72595b52b4dSgwk 		mc_tint(sc);
72695b52b4dSgwk 
72795b52b4dSgwk 	if (ir & RCVINT)
72895b52b4dSgwk 		mc_rint(sc);
72995b52b4dSgwk 
73095b52b4dSgwk 	return(1);
73195b52b4dSgwk }
73295b52b4dSgwk 
73395b52b4dSgwk void
73495b52b4dSgwk mc_tint(struct mc_softc *sc)
73595b52b4dSgwk {
736415e1820Sgwk 	struct ifnet *ifp = &sc->sc_arpcom.ac_if;
73795b52b4dSgwk 	u_int8_t xmtrc, xmtfs;
73895b52b4dSgwk 
73995b52b4dSgwk 	xmtrc = NIC_GET(sc, MACE_XMTRC);
74095b52b4dSgwk 	xmtfs = NIC_GET(sc, MACE_XMTFS);
74195b52b4dSgwk 
74295b52b4dSgwk 	if ((xmtfs & XMTSV) == 0)
74395b52b4dSgwk 		return;
74495b52b4dSgwk 
74595b52b4dSgwk 	if (xmtfs & UFLO) {
74695b52b4dSgwk 		printf("%s: underflow\n", sc->sc_dev.dv_xname);
74795b52b4dSgwk 		mc_reset(sc);
74895b52b4dSgwk 		return;
74995b52b4dSgwk 	}
75095b52b4dSgwk 
75195b52b4dSgwk 	if (xmtfs & LCOL) {
75295b52b4dSgwk 		printf("%s: late collision\n", sc->sc_dev.dv_xname);
753415e1820Sgwk 		ifp->if_oerrors++;
754415e1820Sgwk 		ifp->if_collisions++;
75595b52b4dSgwk 	}
75695b52b4dSgwk 
75795b52b4dSgwk 	if (xmtfs & MORE)
75895b52b4dSgwk 		/* Real number is unknown. */
759415e1820Sgwk 		ifp->if_collisions += 2;
76095b52b4dSgwk 	else if (xmtfs & ONE)
761415e1820Sgwk 		ifp->if_collisions++;
76295b52b4dSgwk 	else if (xmtfs & RTRY) {
76395b52b4dSgwk 		printf("%s: excessive collisions\n", sc->sc_dev.dv_xname);
764415e1820Sgwk 		ifp->if_collisions += 16;
765415e1820Sgwk 		ifp->if_oerrors++;
76695b52b4dSgwk 	}
76795b52b4dSgwk 
76895b52b4dSgwk 	if (xmtfs & LCAR) {
76995b52b4dSgwk 		sc->sc_havecarrier = 0;
77095b52b4dSgwk 		printf("%s: lost carrier\n", sc->sc_dev.dv_xname);
771415e1820Sgwk 		ifp->if_oerrors++;
77295b52b4dSgwk 	}
77395b52b4dSgwk 
774de6cd8fbSdlg 	ifq_clr_oactive(&ifp->if_snd);
775415e1820Sgwk 	ifp->if_timer = 0;
776415e1820Sgwk 	mc_start(ifp);
77795b52b4dSgwk }
77895b52b4dSgwk 
77995b52b4dSgwk void
78095b52b4dSgwk mc_rint(struct mc_softc *sc)
78195b52b4dSgwk {
782415e1820Sgwk 	struct ifnet *ifp = &sc->sc_arpcom.ac_if;
78395b52b4dSgwk #define rxf	sc->sc_rxframe
78495b52b4dSgwk 	u_int len;
78595b52b4dSgwk 
78695b52b4dSgwk 	len = (rxf.rx_rcvcnt | ((rxf.rx_rcvsts & 0xf) << 8)) - 4;
78795b52b4dSgwk 
78895b52b4dSgwk #ifdef MCDEBUG
78995b52b4dSgwk 	if (rxf.rx_rcvsts & 0xf0)
79095b52b4dSgwk 		printf("%s: rcvcnt %02x rcvsts %02x rntpc 0x%02x rcvcc 0x%02x\n",
79195b52b4dSgwk 		    sc->sc_dev.dv_xname, rxf.rx_rcvcnt, rxf.rx_rcvsts,
79295b52b4dSgwk 		    rxf.rx_rntpc, rxf.rx_rcvcc);
79395b52b4dSgwk #endif
79495b52b4dSgwk 
79595b52b4dSgwk 	if (rxf.rx_rcvsts & OFLO) {
79695b52b4dSgwk #ifdef MCDEBUG
79795b52b4dSgwk 		printf("%s: receive FIFO overflow\n", sc->sc_dev.dv_xname);
79895b52b4dSgwk #endif
799415e1820Sgwk 		ifp->if_ierrors++;
80095b52b4dSgwk 		return;
80195b52b4dSgwk 	}
80295b52b4dSgwk 
80395b52b4dSgwk 	if (rxf.rx_rcvsts & CLSN)
804415e1820Sgwk 		ifp->if_collisions++;
80595b52b4dSgwk 
80695b52b4dSgwk 	if (rxf.rx_rcvsts & FRAM) {
80795b52b4dSgwk #ifdef MCDEBUG
80895b52b4dSgwk 		printf("%s: framing error\n", sc->sc_dev.dv_xname);
80995b52b4dSgwk #endif
810415e1820Sgwk 		ifp->if_ierrors++;
81195b52b4dSgwk 		return;
81295b52b4dSgwk 	}
81395b52b4dSgwk 
81495b52b4dSgwk 	if (rxf.rx_rcvsts & FCS) {
81595b52b4dSgwk #ifdef MCDEBUG
81695b52b4dSgwk 		printf("%s: frame control checksum error\n", sc->sc_dev.dv_xname);
81795b52b4dSgwk #endif
818415e1820Sgwk 		ifp->if_ierrors++;
81995b52b4dSgwk 		return;
82095b52b4dSgwk 	}
82195b52b4dSgwk 
82295b52b4dSgwk 	mace_read(sc, rxf.rx_frame, len);
82395b52b4dSgwk #undef  rxf
82495b52b4dSgwk }
82595b52b4dSgwk /*
82695b52b4dSgwk  * stuff packet into MACE (at splnet)
82795b52b4dSgwk  */
82895b52b4dSgwk u_int
82995b52b4dSgwk maceput(struct mc_softc *sc, struct mbuf *m)
83095b52b4dSgwk {
831415e1820Sgwk 	struct ifnet *ifp = &sc->sc_arpcom.ac_if;
83295b52b4dSgwk 	struct mbuf *n;
83395b52b4dSgwk 	u_int len, totlen = 0;
83495b52b4dSgwk 	u_char *buff;
83595b52b4dSgwk 
83695b52b4dSgwk 	buff = sc->sc_txbuf;
83795b52b4dSgwk 
83895b52b4dSgwk 	for (; m; m = n) {
83995b52b4dSgwk 		u_char *data = mtod(m, u_char *);
84095b52b4dSgwk 		len = m->m_len;
84195b52b4dSgwk 		totlen += len;
84295b52b4dSgwk 		bcopy(data, buff, len);
84395b52b4dSgwk 		buff += len;
844822e8206Smpi 		n = m_free(m);
84595b52b4dSgwk 	}
84695b52b4dSgwk 
84795b52b4dSgwk 	if (totlen > PAGE_SIZE)
84895b52b4dSgwk 		panic("%s: maceput: packet overflow", sc->sc_dev.dv_xname);
84995b52b4dSgwk 
85095b52b4dSgwk #if 0
85195b52b4dSgwk 	if (totlen < ETHERMIN + sizeof(struct ether_header)) {
85295b52b4dSgwk 		int pad = ETHERMIN + sizeof(struct ether_header) - totlen;
85395b52b4dSgwk 		bzero(sc->sc_txbuf + totlen, pad);
85495b52b4dSgwk 		totlen = ETHERMIN + sizeof(struct ether_header);
85595b52b4dSgwk 	}
85695b52b4dSgwk #endif
85795b52b4dSgwk 
85895b52b4dSgwk 
85995b52b4dSgwk 	/* 5 seconds to watch for failing to transmit */
860415e1820Sgwk 	ifp->if_timer = 5;
86195b52b4dSgwk 	mc_putpacket(sc, totlen);
86295b52b4dSgwk 	return (totlen);
86395b52b4dSgwk }
86495b52b4dSgwk 
86595b52b4dSgwk void
86695b52b4dSgwk mace_read(struct mc_softc *sc, caddr_t pkt, int len)
86795b52b4dSgwk {
86895b52b4dSgwk 	struct ifnet *ifp = &sc->sc_arpcom.ac_if;
86986666264Sdlg 	struct mbuf_list ml = MBUF_LIST_INITIALIZER();
87095b52b4dSgwk 	struct mbuf *m;
87195b52b4dSgwk 
87295b52b4dSgwk 	if (len <= sizeof(struct ether_header) ||
87395b52b4dSgwk 	    len > ETHERMTU + sizeof(struct ether_header)) {
87495b52b4dSgwk #ifdef MCDEBUG
87595b52b4dSgwk 		printf("%s: invalid packet size %d; dropping\n",
87695b52b4dSgwk 		    sc->sc_dev.dv_xname, len);
87795b52b4dSgwk #endif
87895b52b4dSgwk 		ifp->if_ierrors++;
87995b52b4dSgwk 		return;
88095b52b4dSgwk 	}
88195b52b4dSgwk 
88295b52b4dSgwk 	m = mace_get(sc, pkt, len);
88395b52b4dSgwk 	if (m == NULL) {
88495b52b4dSgwk 		ifp->if_ierrors++;
88595b52b4dSgwk 		return;
88695b52b4dSgwk 	}
88795b52b4dSgwk 
88886666264Sdlg 	ml_enqueue(&ml, m);
88986666264Sdlg 	if_input(ifp, &ml);
89095b52b4dSgwk }
89195b52b4dSgwk 
89295b52b4dSgwk /*
89395b52b4dSgwk  * Pull data off an interface.
89495b52b4dSgwk  * Len is length of data, with local net header stripped.
89595b52b4dSgwk  * We copy the data into mbufs.  When full cluster sized units are present
89695b52b4dSgwk  * we copy into clusters.
89795b52b4dSgwk  */
89895b52b4dSgwk struct mbuf *
89995b52b4dSgwk mace_get(struct mc_softc *sc, caddr_t pkt, int totlen)
90095b52b4dSgwk {
90195b52b4dSgwk 	 struct mbuf *m;
90295b52b4dSgwk 	 struct mbuf *top, **mp;
90395b52b4dSgwk 	 int len;
90495b52b4dSgwk 
90595b52b4dSgwk 	 MGETHDR(m, M_DONTWAIT, MT_DATA);
9069e3a439eSgwk 	 if (m == NULL)
9079e3a439eSgwk 		  return (NULL);
9089e3a439eSgwk 
90995b52b4dSgwk 	 m->m_pkthdr.len = totlen;
91095b52b4dSgwk 	 len = MHLEN;
91195b52b4dSgwk 	 top = 0;
91295b52b4dSgwk 	 mp = &top;
91395b52b4dSgwk 
91495b52b4dSgwk 	 while (totlen > 0) {
91595b52b4dSgwk 		  if (top) {
91695b52b4dSgwk 			   MGET(m, M_DONTWAIT, MT_DATA);
9179e3a439eSgwk 			   if (m == NULL) {
91895b52b4dSgwk 				    m_freem(top);
9199e3a439eSgwk 				    return (NULL);
92095b52b4dSgwk 			   }
92195b52b4dSgwk 			   len = MLEN;
92295b52b4dSgwk 		  }
92395b52b4dSgwk 		  if (totlen >= MINCLSIZE) {
92495b52b4dSgwk 			   MCLGET(m, M_DONTWAIT);
92595b52b4dSgwk 			   if ((m->m_flags & M_EXT) == 0) {
92695b52b4dSgwk 				    m_free(m);
92795b52b4dSgwk 				    m_freem(top);
9289e3a439eSgwk 				    return (NULL);
92995b52b4dSgwk 			   }
93095b52b4dSgwk 			   len = MCLBYTES;
93195b52b4dSgwk 		  }
93295b52b4dSgwk 		  m->m_len = len = min(totlen, len);
93395b52b4dSgwk 		  bcopy(pkt, mtod(m, caddr_t), len);
93495b52b4dSgwk 		  pkt += len;
93595b52b4dSgwk 		  totlen -= len;
93695b52b4dSgwk 		  *mp = m;
93795b52b4dSgwk 		  mp = &m->m_next;
93895b52b4dSgwk 	 }
93995b52b4dSgwk 
94095b52b4dSgwk 	 return (top);
94195b52b4dSgwk }
94295b52b4dSgwk 
94395b52b4dSgwk void
94495b52b4dSgwk mc_putpacket(struct mc_softc *sc, u_int len)
94595b52b4dSgwk {
94695b52b4dSgwk 	dbdma_command_t *cmd = sc->sc_txdmacmd;
94795b52b4dSgwk 
94895b52b4dSgwk 	DBDMA_BUILD(cmd, DBDMA_CMD_OUT_LAST, 0, len, sc->sc_txbuf_pa,
94995b52b4dSgwk 	   DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
95095b52b4dSgwk 	cmd++;
951947a7310Sgwk 	DBDMA_BUILD(cmd, DBDMA_CMD_STOP, 0, 0, 0, DBDMA_INT_ALWAYS,
952947a7310Sgwk 	   DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
95395b52b4dSgwk 
95495b52b4dSgwk 	dbdma_start(sc->sc_txdma, sc->sc_txdbdma);
95595b52b4dSgwk }
95695b52b4dSgwk 
95795b52b4dSgwk /*
95895b52b4dSgwk  * Interrupt handler for the MACE DMA completion interrupts
95995b52b4dSgwk  */
96095b52b4dSgwk int
96195b52b4dSgwk mc_dmaintr(void *arg)
96295b52b4dSgwk {
96395b52b4dSgwk 	struct mc_softc *sc = arg;
96495b52b4dSgwk 	int status, offset, statoff;
96595b52b4dSgwk 	int datalen, resid;
96695b52b4dSgwk 	int i, n, count;
96795b52b4dSgwk 	dbdma_command_t *cmd;
96895b52b4dSgwk 
96995b52b4dSgwk 	/* We've received some packets from the MACE */
97095b52b4dSgwk 	/* Loop through, processing each of the packets */
97195b52b4dSgwk 	i = sc->sc_tail;
97295b52b4dSgwk 	for (n = 0; n < MC_RXDMABUFS; n++, i++) {
97395b52b4dSgwk 		if (i == MC_RXDMABUFS)
97495b52b4dSgwk 			i = 0;
97595b52b4dSgwk 
97695b52b4dSgwk 		cmd = &sc->sc_rxdmacmd[i];
97795b52b4dSgwk 		status = dbdma_ld16(&cmd->d_status);
97895b52b4dSgwk 		resid = dbdma_ld16(&cmd->d_resid);
97995b52b4dSgwk 
98095b52b4dSgwk 		if ((status & DBDMA_CNTRL_ACTIVE) == 0) {
98195b52b4dSgwk 			continue;
98295b52b4dSgwk 		}
98395b52b4dSgwk 
98495b52b4dSgwk 		count = dbdma_ld16(&cmd->d_count);
98595b52b4dSgwk 		datalen = count - resid;
98695b52b4dSgwk 		datalen -= 4; /* 4 == status bytes */
98795b52b4dSgwk 
98895b52b4dSgwk 		if (datalen < 4 + sizeof(struct ether_header)) {
98995b52b4dSgwk 			printf("short packet len=%d\n", datalen);
99095b52b4dSgwk 			/* continue; */
99195b52b4dSgwk 			goto next;
99295b52b4dSgwk 		}
99395b52b4dSgwk 		DBDMA_BUILD_CMD(cmd, DBDMA_CMD_STOP, 0, 0, 0, 0);
99495b52b4dSgwk 
99595b52b4dSgwk 		offset = i * MACE_BUFLEN;
99695b52b4dSgwk 		statoff = offset + datalen;
99795b52b4dSgwk 		sc->sc_rxframe.rx_rcvcnt = sc->sc_rxbuf[statoff + 0];
99895b52b4dSgwk 		sc->sc_rxframe.rx_rcvsts = sc->sc_rxbuf[statoff + 1];
99995b52b4dSgwk 		sc->sc_rxframe.rx_rntpc  = sc->sc_rxbuf[statoff + 2];
100095b52b4dSgwk 		sc->sc_rxframe.rx_rcvcc  = sc->sc_rxbuf[statoff + 3];
100195b52b4dSgwk 		sc->sc_rxframe.rx_frame  = sc->sc_rxbuf + offset;
100295b52b4dSgwk 
100395b52b4dSgwk 		mc_rint(sc);
100495b52b4dSgwk 
100595b52b4dSgwk next:
100695b52b4dSgwk 		DBDMA_BUILD_CMD(cmd, DBDMA_CMD_IN_LAST, 0, DBDMA_INT_ALWAYS,
100795b52b4dSgwk 		    DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
1008e67a46f3Sgwk 
100995b52b4dSgwk 		cmd->d_status = 0;
101095b52b4dSgwk 		cmd->d_resid = 0;
101195b52b4dSgwk 		sc->sc_tail = i + 1;
101295b52b4dSgwk 	}
101395b52b4dSgwk 
101495b52b4dSgwk 	dbdma_continue(sc->sc_rxdma);
101595b52b4dSgwk 
101695b52b4dSgwk 	return 1;
101795b52b4dSgwk }
101895b52b4dSgwk 
101995b52b4dSgwk void
102095b52b4dSgwk mc_reset_rxdma(struct mc_softc *sc)
102195b52b4dSgwk {
102295b52b4dSgwk 	dbdma_command_t *cmd = sc->sc_rxdmacmd;
102395b52b4dSgwk 	int i;
102495b52b4dSgwk 	u_int8_t maccc;
102595b52b4dSgwk 
102695b52b4dSgwk 	/* Disable receiver, reset the DMA channels */
102795b52b4dSgwk 	maccc = NIC_GET(sc, MACE_MACCC);
102895b52b4dSgwk 	NIC_PUT(sc, MACE_MACCC, maccc & ~ENRCV);
102995b52b4dSgwk 
103095b52b4dSgwk 	dbdma_reset(sc->sc_rxdma);
103195b52b4dSgwk 
103295b52b4dSgwk 	bzero(sc->sc_rxdmacmd, 8 * sizeof(dbdma_command_t));
103395b52b4dSgwk 	for (i = 0; i < MC_RXDMABUFS; i++) {
103495b52b4dSgwk 		DBDMA_BUILD(cmd, DBDMA_CMD_IN_LAST, 0, MACE_BUFLEN,
103595b52b4dSgwk 		    sc->sc_rxbuf_pa + MACE_BUFLEN * i, DBDMA_INT_ALWAYS,
103695b52b4dSgwk 		    DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
103795b52b4dSgwk 		cmd++;
103895b52b4dSgwk 	}
103995b52b4dSgwk 
104095b52b4dSgwk 	DBDMA_BUILD(cmd, DBDMA_CMD_NOP, 0, 0, 0,
104195b52b4dSgwk 	    DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_ALWAYS);
104295b52b4dSgwk 	dbdma_st32(&cmd->d_cmddep, sc->sc_rxdbdma->d_paddr);
104395b52b4dSgwk 	cmd++;
104495b52b4dSgwk 
104595b52b4dSgwk 	sc->sc_tail = 0;
104695b52b4dSgwk 
104795b52b4dSgwk 	dbdma_start(sc->sc_rxdma, sc->sc_rxdbdma);
104895b52b4dSgwk 	/* Reenable receiver, reenable DMA */
104995b52b4dSgwk 	NIC_PUT(sc, MACE_MACCC, maccc);
105095b52b4dSgwk }
105195b52b4dSgwk 
105295b52b4dSgwk void
105395b52b4dSgwk mc_reset_txdma(struct mc_softc *sc)
105495b52b4dSgwk {
105595b52b4dSgwk 	dbdma_command_t *cmd = sc->sc_txdmacmd;
105695b52b4dSgwk 	dbdma_regmap_t *dmareg = sc->sc_txdma;
105795b52b4dSgwk 	u_int8_t maccc;
105895b52b4dSgwk 
105995b52b4dSgwk 	/* disable transmitter */
106095b52b4dSgwk 	maccc = NIC_GET(sc, MACE_MACCC);
106195b52b4dSgwk 	NIC_PUT(sc, MACE_MACCC, maccc & ~ENXMT);
106295b52b4dSgwk 
106395b52b4dSgwk 	dbdma_reset(sc->sc_txdma);
106495b52b4dSgwk 
106595b52b4dSgwk 	bzero(sc->sc_txdmacmd, 2 * sizeof(dbdma_command_t));
106695b52b4dSgwk 	DBDMA_BUILD(cmd, DBDMA_CMD_OUT_LAST, 0, 0, sc->sc_txbuf_pa,
106795b52b4dSgwk 	    DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
106895b52b4dSgwk 	cmd++;
106995b52b4dSgwk 	DBDMA_BUILD(cmd, DBDMA_CMD_STOP, 0, 0, 0,
107095b52b4dSgwk 	    DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
107195b52b4dSgwk 
107295b52b4dSgwk 	out32rb(&dmareg->d_cmdptrhi, 0);
107395b52b4dSgwk 	out32rb(&dmareg->d_cmdptrlo, sc->sc_txdbdma->d_paddr);
107495b52b4dSgwk 
107595b52b4dSgwk 	/* restore old value */
107695b52b4dSgwk 	NIC_PUT(sc, MACE_MACCC, maccc);
107795b52b4dSgwk }
107895b52b4dSgwk 
107995b52b4dSgwk /*
108095b52b4dSgwk  * Go through the list of multicast addresses and calculate the logical
108195b52b4dSgwk  * address filter.
108295b52b4dSgwk  */
108395b52b4dSgwk void
1084947a7310Sgwk mace_calcladrf(struct mc_softc *sc, u_int8_t *af)
108595b52b4dSgwk {
108695b52b4dSgwk 	struct ether_multi *enm;
108795b52b4dSgwk 	u_int32_t crc;
1088947a7310Sgwk 	struct ifnet *ifp = &sc->sc_arpcom.ac_if;
1089947a7310Sgwk 	struct arpcom *ac = &sc->sc_arpcom;
109095b52b4dSgwk 	struct ether_multistep step;
109195b52b4dSgwk 	/*
109295b52b4dSgwk 	 * Set up multicast address filter by passing all multicast addresses
109395b52b4dSgwk 	 * through a crc generator, and then using the high order 6 bits as an
109495b52b4dSgwk 	 * index into the 64 bit logical address filter.  The high order bit
109595b52b4dSgwk 	 * selects the word, while the rest of the bits select the bit within
109695b52b4dSgwk 	 * the word.
109795b52b4dSgwk 	 */
109895b52b4dSgwk 
1099ef787866Smpi 	if (ac->ac_multirangecnt > 0)
1100ef787866Smpi 		goto allmulti;
1101ef787866Smpi 
110295b52b4dSgwk 	*((u_int32_t *)af) = *((u_int32_t *)af + 1) = 0;
110395b52b4dSgwk 	ETHER_FIRST_MULTI(step, ac, enm);
110495b52b4dSgwk 	while (enm != NULL) {
110595b52b4dSgwk 		crc = ether_crc32_le(enm->enm_addrlo, sizeof(enm->enm_addrlo));
110695b52b4dSgwk 
110795b52b4dSgwk 		/* Just want the 6 most significant bits. */
110895b52b4dSgwk 		crc >>= 26;
110995b52b4dSgwk 
111095b52b4dSgwk 		/* Set the corresponding bit in the filter. */
111195b52b4dSgwk 		af[crc >> 3] |= 1 << (crc & 7);
111295b52b4dSgwk 
111395b52b4dSgwk 		ETHER_NEXT_MULTI(step, enm);
111495b52b4dSgwk 	}
111595b52b4dSgwk 	ifp->if_flags &= ~IFF_ALLMULTI;
111695b52b4dSgwk 	return;
111795b52b4dSgwk 
111895b52b4dSgwk allmulti:
111995b52b4dSgwk 	ifp->if_flags |= IFF_ALLMULTI;
112095b52b4dSgwk 	*((u_int32_t *)af) = *((u_int32_t *)af + 1) = 0xffffffff;
112195b52b4dSgwk }
1122