xref: /freebsd/sys/dev/fxp/if_fxp.c (revision dfe61cf102778c55f2f85cddfba57c2e1b13ff83)
1a17c678eSDavid Greenman /*
2a17c678eSDavid Greenman  * Copyright (c) 1995, David Greenman
3a17c678eSDavid Greenman  * All rights reserved.
4a17c678eSDavid Greenman  *
5a17c678eSDavid Greenman  * Redistribution and use in source and binary forms, with or without
6a17c678eSDavid Greenman  * modification, are permitted provided that the following conditions
7a17c678eSDavid Greenman  * are met:
8a17c678eSDavid Greenman  * 1. Redistributions of source code must retain the above copyright
9a17c678eSDavid Greenman  *    notice unmodified, this list of conditions, and the following
10a17c678eSDavid Greenman  *    disclaimer.
11a17c678eSDavid Greenman  * 2. Redistributions in binary form must reproduce the above copyright
12a17c678eSDavid Greenman  *    notice, this list of conditions and the following disclaimer in the
13a17c678eSDavid Greenman  *    documentation and/or other materials provided with the distribution.
14a17c678eSDavid Greenman  * 3. All advertising materials mentioning features or use of this software
15a17c678eSDavid Greenman  *    must display the following acknowledgement:
16a17c678eSDavid Greenman  *	This product includes software developed by David Greenman.
17a17c678eSDavid Greenman  * 4. The name of the author may not be used to endorse or promote products
18a17c678eSDavid Greenman  *    derived from this software without specific prior written permission.
19a17c678eSDavid Greenman  *
20a17c678eSDavid Greenman  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21a17c678eSDavid Greenman  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22a17c678eSDavid Greenman  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23a17c678eSDavid Greenman  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24a17c678eSDavid Greenman  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25a17c678eSDavid Greenman  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26a17c678eSDavid Greenman  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27a17c678eSDavid Greenman  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28a17c678eSDavid Greenman  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29a17c678eSDavid Greenman  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30a17c678eSDavid Greenman  * SUCH DAMAGE.
31a17c678eSDavid Greenman  *
32dfe61cf1SDavid Greenman  *	$Id: if_fxp.c,v 1.1 1995/11/28 23:55:20 davidg Exp $
33a17c678eSDavid Greenman  */
34a17c678eSDavid Greenman 
35a17c678eSDavid Greenman /*
36a17c678eSDavid Greenman  * Intel EtherExpress Pro/100 PCI Fast Ethernet driver
37a17c678eSDavid Greenman  */
38a17c678eSDavid Greenman 
39a17c678eSDavid Greenman #include "bpfilter.h"
40a17c678eSDavid Greenman 
41a17c678eSDavid Greenman #include <sys/param.h>
42a17c678eSDavid Greenman #include <sys/systm.h>
43a17c678eSDavid Greenman #include <sys/ioctl.h>
44a17c678eSDavid Greenman #include <sys/mbuf.h>
45a17c678eSDavid Greenman #include <sys/malloc.h>
46a17c678eSDavid Greenman #include <sys/kernel.h>
47a17c678eSDavid Greenman #include <sys/devconf.h>
48a17c678eSDavid Greenman #include <sys/syslog.h>
49a17c678eSDavid Greenman 
50a17c678eSDavid Greenman #include <net/if.h>
51a17c678eSDavid Greenman #include <net/if_dl.h>
52a17c678eSDavid Greenman #include <net/if_types.h>
53a17c678eSDavid Greenman 
54a17c678eSDavid Greenman #ifdef INET
55a17c678eSDavid Greenman #include <netinet/in.h>
56a17c678eSDavid Greenman #include <netinet/in_systm.h>
57a17c678eSDavid Greenman #include <netinet/in_var.h>
58a17c678eSDavid Greenman #include <netinet/ip.h>
59a17c678eSDavid Greenman #include <netinet/if_ether.h>
60a17c678eSDavid Greenman #endif
61a17c678eSDavid Greenman 
62a17c678eSDavid Greenman #ifdef IPX
63a17c678eSDavid Greenman #include <netipx/ipx.h>
64a17c678eSDavid Greenman #include <netipx/ipx_if.h>
65a17c678eSDavid Greenman #endif
66a17c678eSDavid Greenman 
67a17c678eSDavid Greenman #ifdef NS
68a17c678eSDavid Greenman #include <netns/ns.h>
69a17c678eSDavid Greenman #include <netns/ns_if.h>
70a17c678eSDavid Greenman #endif
71a17c678eSDavid Greenman 
72a17c678eSDavid Greenman #if NBPFILTER > 0
73a17c678eSDavid Greenman #include <net/bpf.h>
74a17c678eSDavid Greenman #include <net/bpfdesc.h>
75a17c678eSDavid Greenman #endif
76a17c678eSDavid Greenman 
77dfe61cf1SDavid Greenman #include <vm/vm.h>		/* for vtophys */
78dfe61cf1SDavid Greenman #include <vm/vm_param.h>	/* for vtophys */
79dfe61cf1SDavid Greenman #include <machine/pmap.h>	/* for vtophys */
80dfe61cf1SDavid Greenman #include <machine/clock.h>	/* for DELAY */
81a17c678eSDavid Greenman 
82a17c678eSDavid Greenman #include <pci/pcivar.h>
83a17c678eSDavid Greenman #include <pci/if_fxpreg.h>
84a17c678eSDavid Greenman 
85a17c678eSDavid Greenman struct fxp_softc {
86dfe61cf1SDavid Greenman 	struct arpcom arpcom;		/* per-interface network data */
87dfe61cf1SDavid Greenman 	caddr_t bpf;			/* BPF token */
88dfe61cf1SDavid Greenman 	struct fxp_csr *csr;		/* control/status registers */
89a17c678eSDavid Greenman 	struct fxp_cb_tx *cbl_base;	/* base of TxCB list */
90a17c678eSDavid Greenman 	struct fxp_cb_tx *cbl_first;	/* first active TxCB in list */
91a17c678eSDavid Greenman 	struct fxp_cb_tx *cbl_last;	/* last active TxCB in list */
92a17c678eSDavid Greenman 	struct mbuf *rfa_headm;		/* first mbuf in receive frame area */
93a17c678eSDavid Greenman 	struct mbuf *rfa_tailm;		/* last mbuf in receive frame area */
94a17c678eSDavid Greenman 	struct fxp_stats *fxp_stats;	/* Pointer to interface stats */
95a17c678eSDavid Greenman 	int tx_queued;			/* # of active TxCB's */
96a17c678eSDavid Greenman 	int promisc_mode;		/* promiscuous mode enabled */
97a17c678eSDavid Greenman };
98a17c678eSDavid Greenman 
99a17c678eSDavid Greenman #include "fxp.h"
100a17c678eSDavid Greenman static struct fxp_softc *fxp_sc[NFXP];	/* XXX Yuck */
101a17c678eSDavid Greenman 
102a17c678eSDavid Greenman static u_long fxp_count;
103a17c678eSDavid Greenman 
104a17c678eSDavid Greenman /*
105a17c678eSDavid Greenman  * Template for default configuration parameters.
106a17c678eSDavid Greenman  * See struct fxp_cb_config for the bit definitions.
107a17c678eSDavid Greenman  */
108a17c678eSDavid Greenman static u_char fxp_cb_config_template[] = {
109a17c678eSDavid Greenman 	0x0, 0x0,		/* cb_status */
110a17c678eSDavid Greenman 	0x80, 0x2,		/* cb_command */
111a17c678eSDavid Greenman 	0xff, 0xff, 0xff, 0xff,	/* link_addr */
112a17c678eSDavid Greenman 	0x16,	/*  0 */
113a17c678eSDavid Greenman 	0x8,	/*  1 */
114a17c678eSDavid Greenman 	0x0,	/*  2 */
115a17c678eSDavid Greenman 	0x0,	/*  3 */
116a17c678eSDavid Greenman 	0x0,	/*  4 */
117a17c678eSDavid Greenman 	0x80,	/*  5 */
118a17c678eSDavid Greenman 	0xb2,	/*  6 */
119a17c678eSDavid Greenman 	0x3,	/*  7 */
120a17c678eSDavid Greenman 	0x1,	/*  8 */
121a17c678eSDavid Greenman 	0x0,	/*  9 */
122a17c678eSDavid Greenman 	0x26,	/* 10 */
123a17c678eSDavid Greenman 	0x0,	/* 11 */
124a17c678eSDavid Greenman 	0x60,	/* 12 */
125a17c678eSDavid Greenman 	0x0,	/* 13 */
126a17c678eSDavid Greenman 	0xf2,	/* 14 */
127a17c678eSDavid Greenman 	0x48,	/* 15 */
128a17c678eSDavid Greenman 	0x0,	/* 16 */
129a17c678eSDavid Greenman 	0x40,	/* 17 */
130a17c678eSDavid Greenman 	0xf3,	/* 18 */
131a17c678eSDavid Greenman 	0x0,	/* 19 */
132a17c678eSDavid Greenman 	0x3f,	/* 20 */
133a17c678eSDavid Greenman 	0x5,	/* 21 */
134a17c678eSDavid Greenman 	0x0, 0x0
135a17c678eSDavid Greenman };
136a17c678eSDavid Greenman 
137a17c678eSDavid Greenman static char *fxp_probe		__P((pcici_t, pcidi_t));
138a17c678eSDavid Greenman static void fxp_attach		__P((pcici_t, int));
139a17c678eSDavid Greenman static int fxp_shutdown		__P((struct kern_devconf *, int));
140a17c678eSDavid Greenman static int fxp_intr		__P((void *));
141a17c678eSDavid Greenman static void fxp_start		__P((struct ifnet *));
142a17c678eSDavid Greenman static int fxp_ioctl		__P((struct ifnet *, int, caddr_t));
143a17c678eSDavid Greenman static void fxp_init		__P((int));
144a17c678eSDavid Greenman static void fxp_stop		__P((int));
145a17c678eSDavid Greenman static void fxp_watchdog	__P((int));
146a17c678eSDavid Greenman static void fxp_get_macaddr	__P((struct fxp_softc *));
147a17c678eSDavid Greenman static int fxp_add_rfabuf	__P((struct fxp_softc *, struct mbuf *));
148a17c678eSDavid Greenman 
149a17c678eSDavid Greenman timeout_t fxp_stats_update;
150a17c678eSDavid Greenman 
151a17c678eSDavid Greenman static struct pci_device fxp_device = {
152a17c678eSDavid Greenman 	"fxp",
153a17c678eSDavid Greenman 	fxp_probe,
154a17c678eSDavid Greenman 	fxp_attach,
155a17c678eSDavid Greenman 	&fxp_count,
156a17c678eSDavid Greenman 	fxp_shutdown
157a17c678eSDavid Greenman };
158a17c678eSDavid Greenman DATA_SET(pcidevice_set, fxp_device);
159a17c678eSDavid Greenman 
160a17c678eSDavid Greenman /*
161a17c678eSDavid Greenman  * Number of transmit control blocks. This determines the number
162a17c678eSDavid Greenman  * of transmit buffers that can be chained in the CB list.
163a17c678eSDavid Greenman  * This must be a power of two.
164a17c678eSDavid Greenman  */
165a17c678eSDavid Greenman #define FXP_NTXCB	64
166a17c678eSDavid Greenman 
167a17c678eSDavid Greenman /*
168a17c678eSDavid Greenman  * TxCB list index mask. This is used to do list wrap-around.
169a17c678eSDavid Greenman  */
170a17c678eSDavid Greenman #define FXP_TXCB_MASK	(FXP_NTXCB - 1)
171a17c678eSDavid Greenman 
172a17c678eSDavid Greenman /*
173a17c678eSDavid Greenman  * Number of DMA segments in a TxCB. Note that this is carefully
174a17c678eSDavid Greenman  * chosen to make the total struct size an even power of two.
175a17c678eSDavid Greenman  */
176a17c678eSDavid Greenman #define FXP_NTXSEG	13
177a17c678eSDavid Greenman 
178a17c678eSDavid Greenman /*
179a17c678eSDavid Greenman  * Number of receive frame area buffers. These are large so chose
180a17c678eSDavid Greenman  * wisely.
181a17c678eSDavid Greenman  */
182a17c678eSDavid Greenman #define FXP_NRFABUFS	32
183a17c678eSDavid Greenman 
184dfe61cf1SDavid Greenman /*
185dfe61cf1SDavid Greenman  * Wait for the previous command to be accepted (but not necessarily
186dfe61cf1SDavid Greenman  * completed).
187dfe61cf1SDavid Greenman  */
188a17c678eSDavid Greenman static inline void
189a17c678eSDavid Greenman fxp_scb_wait(csr)
190a17c678eSDavid Greenman 	struct fxp_csr *csr;
191a17c678eSDavid Greenman {
192a17c678eSDavid Greenman 	int i = 10000;
193a17c678eSDavid Greenman 
194a17c678eSDavid Greenman 	while ((csr->scb_command & FXP_SCB_COMMAND_MASK) && --i);
195a17c678eSDavid Greenman }
196a17c678eSDavid Greenman 
197dfe61cf1SDavid Greenman /*
198dfe61cf1SDavid Greenman  * Return identification string if this is device is ours.
199dfe61cf1SDavid Greenman  */
200a17c678eSDavid Greenman static char *
201a17c678eSDavid Greenman fxp_probe(config_id, device_id)
202a17c678eSDavid Greenman 	pcici_t config_id;
203a17c678eSDavid Greenman 	pcidi_t device_id;
204a17c678eSDavid Greenman {
205a17c678eSDavid Greenman 	if (((device_id & 0xffff) == FXP_VENDORID_INTEL) &&
206a17c678eSDavid Greenman 	    ((device_id >> 16) & 0xffff) == FXP_DEVICEID_i82557)
207a17c678eSDavid Greenman 		return ("Intel EtherExpress Pro/100 Fast Ethernet");
208a17c678eSDavid Greenman 
209a17c678eSDavid Greenman 	return NULL;
210a17c678eSDavid Greenman }
211a17c678eSDavid Greenman 
212a17c678eSDavid Greenman /*
213a17c678eSDavid Greenman  * Allocate data structures and attach the device.
214a17c678eSDavid Greenman  */
215a17c678eSDavid Greenman static void
216a17c678eSDavid Greenman fxp_attach(config_id, unit)
217a17c678eSDavid Greenman 	pcici_t config_id;
218a17c678eSDavid Greenman 	int unit;
219a17c678eSDavid Greenman {
220a17c678eSDavid Greenman 	struct fxp_softc *sc;
221a17c678eSDavid Greenman 	struct ifnet *ifp;
222a17c678eSDavid Greenman 	vm_offset_t pbase;
223a17c678eSDavid Greenman 	int s, i;
224a17c678eSDavid Greenman 
225a17c678eSDavid Greenman 	sc = malloc(sizeof(struct fxp_softc), M_DEVBUF, M_NOWAIT);
226a17c678eSDavid Greenman 	if (sc == NULL)
227a17c678eSDavid Greenman 		return;
228a17c678eSDavid Greenman 	bzero(sc, sizeof(struct fxp_softc));
229a17c678eSDavid Greenman 
230a17c678eSDavid Greenman 	s = splimp();
231a17c678eSDavid Greenman 
232dfe61cf1SDavid Greenman 	/*
233dfe61cf1SDavid Greenman 	 * Map control/status registers.
234dfe61cf1SDavid Greenman 	 */
235a17c678eSDavid Greenman 	if (!pci_map_mem(config_id, FXP_PCI_MMBA,
236a17c678eSDavid Greenman 	    (vm_offset_t *)&sc->csr, &pbase)) {
237a17c678eSDavid Greenman 		printf("fxp%d: couldn't map memory\n", unit);
238a17c678eSDavid Greenman 		goto fail;
239a17c678eSDavid Greenman 	}
240a17c678eSDavid Greenman 
241a17c678eSDavid Greenman 	/*
242dfe61cf1SDavid Greenman 	 * Issue a software reset.
243a17c678eSDavid Greenman 	 */
244a17c678eSDavid Greenman 	sc->csr->port = 0;
245a17c678eSDavid Greenman 	DELAY(10);
246a17c678eSDavid Greenman 
247dfe61cf1SDavid Greenman 	/*
248dfe61cf1SDavid Greenman 	 * Allocate our interrupt.
249dfe61cf1SDavid Greenman 	 */
250a17c678eSDavid Greenman 	if (!pci_map_int(config_id, fxp_intr, sc, &net_imask)) {
251a17c678eSDavid Greenman 		printf("fxp%d: couldn't map interrupt\n", unit);
252a17c678eSDavid Greenman 		goto fail;
253a17c678eSDavid Greenman 	}
254a17c678eSDavid Greenman 
255a17c678eSDavid Greenman 	sc->cbl_base = malloc(sizeof(struct fxp_cb_tx) * FXP_NTXCB,
256a17c678eSDavid Greenman 	    M_DEVBUF, M_NOWAIT);
257a17c678eSDavid Greenman 	if (sc->cbl_base == NULL)
258a17c678eSDavid Greenman 		goto malloc_fail;
259a17c678eSDavid Greenman 
260a17c678eSDavid Greenman 	sc->fxp_stats = malloc(sizeof(struct fxp_stats), M_DEVBUF, M_NOWAIT);
261a17c678eSDavid Greenman 	if (sc->fxp_stats == NULL)
262a17c678eSDavid Greenman 		goto malloc_fail;
263a17c678eSDavid Greenman 	bzero(sc->fxp_stats, sizeof(struct fxp_stats));
264a17c678eSDavid Greenman 
265dfe61cf1SDavid Greenman 	/*
266dfe61cf1SDavid Greenman 	 * Pre-allocate our receive buffers.
267dfe61cf1SDavid Greenman 	 */
268a17c678eSDavid Greenman 	for (i = 0; i < FXP_NRFABUFS; i++) {
269a17c678eSDavid Greenman 		if (fxp_add_rfabuf(sc, NULL) != 0) {
270a17c678eSDavid Greenman 			goto malloc_fail;
271a17c678eSDavid Greenman 		}
272a17c678eSDavid Greenman 	}
273a17c678eSDavid Greenman 
274a17c678eSDavid Greenman 	fxp_sc[unit] = sc;
275a17c678eSDavid Greenman 
276a17c678eSDavid Greenman 	ifp = &sc->arpcom.ac_if;
277a17c678eSDavid Greenman 	ifp->if_unit = unit;
278a17c678eSDavid Greenman 	ifp->if_name = "fxp";
279a17c678eSDavid Greenman 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
280a17c678eSDavid Greenman 	ifp->if_ioctl = fxp_ioctl;
281a17c678eSDavid Greenman 	ifp->if_output = ether_output;
282a17c678eSDavid Greenman 	ifp->if_start = fxp_start;
283a17c678eSDavid Greenman 	ifp->if_watchdog = fxp_watchdog;
284a17c678eSDavid Greenman 
285a17c678eSDavid Greenman 	fxp_get_macaddr(sc);
286a17c678eSDavid Greenman 	printf("fxp%d: Ethernet address %s\n", unit,
287a17c678eSDavid Greenman 	    ether_sprintf(sc->arpcom.ac_enaddr));
288a17c678eSDavid Greenman 
289dfe61cf1SDavid Greenman 	/*
290dfe61cf1SDavid Greenman 	 * Attach the interface.
291dfe61cf1SDavid Greenman 	 */
292a17c678eSDavid Greenman 	if_attach(ifp);
293a17c678eSDavid Greenman #if NBPFILTER > 0
294a17c678eSDavid Greenman 	bpfattach(&sc->bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
295a17c678eSDavid Greenman #endif
296a17c678eSDavid Greenman 	splx(s);
297a17c678eSDavid Greenman 	return;
298a17c678eSDavid Greenman 
299a17c678eSDavid Greenman malloc_fail:
300a17c678eSDavid Greenman 	printf("fxp%d: Failed to malloc memory\n", unit);
301a17c678eSDavid Greenman 	(void) pci_unmap_int(config_id);
302a17c678eSDavid Greenman 	if (sc && sc->cbl_base)
303a17c678eSDavid Greenman 		free(sc->cbl_base, M_DEVBUF);
304a17c678eSDavid Greenman 	if (sc && sc->fxp_stats)
305a17c678eSDavid Greenman 		free(sc->fxp_stats, M_DEVBUF);
306a17c678eSDavid Greenman 	/* frees entire chain */
307a17c678eSDavid Greenman 	if (sc && sc->rfa_headm)
308a17c678eSDavid Greenman 		m_freem(sc->rfa_headm);
309a17c678eSDavid Greenman fail:
310a17c678eSDavid Greenman 	if (sc)
311a17c678eSDavid Greenman 		free(sc, M_DEVBUF);
312a17c678eSDavid Greenman 	splx(s);
313a17c678eSDavid Greenman }
314a17c678eSDavid Greenman 
315a17c678eSDavid Greenman /*
316a17c678eSDavid Greenman  * Read station (MAC) address from serial EEPROM. Basically, you
317a17c678eSDavid Greenman  * manually shift in the read opcode (one bit at a time) and then
318a17c678eSDavid Greenman  * shift in the address, and then you shift out the data (all of
319a17c678eSDavid Greenman  * this one bit at a time). The word size is 16 bits, so you have
320a17c678eSDavid Greenman  * to provide the address for every 16 bits of data. The MAC address
321a17c678eSDavid Greenman  * is in the first 3 words (6 bytes total).
322a17c678eSDavid Greenman  */
323a17c678eSDavid Greenman static void
324a17c678eSDavid Greenman fxp_get_macaddr(sc)
325a17c678eSDavid Greenman 	struct fxp_softc *sc;
326a17c678eSDavid Greenman {
327a17c678eSDavid Greenman 	struct fxp_csr *csr;
328a17c678eSDavid Greenman 	u_short reg, *data;
329a17c678eSDavid Greenman 	int i, x;
330a17c678eSDavid Greenman 
331a17c678eSDavid Greenman 	csr = sc->csr;
332a17c678eSDavid Greenman 	data = (u_short *)sc->arpcom.ac_enaddr;
333a17c678eSDavid Greenman 
334a17c678eSDavid Greenman 	for (i = 0; i < 3; i++) {
335a17c678eSDavid Greenman 		csr->eeprom_control = FXP_EEPROM_EECS;
336a17c678eSDavid Greenman 		/*
337a17c678eSDavid Greenman 		 * Shift in read opcode.
338a17c678eSDavid Greenman 		 */
339a17c678eSDavid Greenman 		for (x = 3; x > 0; x--) {
340a17c678eSDavid Greenman 			if (FXP_EEPROM_OPC_READ & (1 << (x - 1))) {
341a17c678eSDavid Greenman 				reg = FXP_EEPROM_EECS | FXP_EEPROM_EEDI;
342a17c678eSDavid Greenman 			} else {
343a17c678eSDavid Greenman 				reg = FXP_EEPROM_EECS;
344a17c678eSDavid Greenman 			}
345a17c678eSDavid Greenman 			csr->eeprom_control = reg;
346a17c678eSDavid Greenman 			csr->eeprom_control = reg | FXP_EEPROM_EESK;
347a17c678eSDavid Greenman 			DELAY(1);
348a17c678eSDavid Greenman 			csr->eeprom_control = reg;
349a17c678eSDavid Greenman 			DELAY(1);
350a17c678eSDavid Greenman 		}
351a17c678eSDavid Greenman 		/*
352a17c678eSDavid Greenman 		 * Shift in address.
353a17c678eSDavid Greenman 		 */
354a17c678eSDavid Greenman 		for (x = 6; x > 0; x--) {
355a17c678eSDavid Greenman 			if (i & (1 << (x - 1))) {
356a17c678eSDavid Greenman 				reg = FXP_EEPROM_EECS | FXP_EEPROM_EEDI;
357a17c678eSDavid Greenman 			} else {
358a17c678eSDavid Greenman 				reg = FXP_EEPROM_EECS;
359a17c678eSDavid Greenman 			}
360a17c678eSDavid Greenman 			csr->eeprom_control = reg;
361a17c678eSDavid Greenman 			csr->eeprom_control = reg | FXP_EEPROM_EESK;
362a17c678eSDavid Greenman 			DELAY(1);
363a17c678eSDavid Greenman 			csr->eeprom_control = reg;
364a17c678eSDavid Greenman 			DELAY(1);
365a17c678eSDavid Greenman 		}
366a17c678eSDavid Greenman 		reg = FXP_EEPROM_EECS;
367a17c678eSDavid Greenman 		data[i] = 0;
368a17c678eSDavid Greenman 		/*
369a17c678eSDavid Greenman 		 * Shift out data.
370a17c678eSDavid Greenman 		 */
371a17c678eSDavid Greenman 		for (x = 16; x > 0; x--) {
372a17c678eSDavid Greenman 			csr->eeprom_control = reg | FXP_EEPROM_EESK;
373a17c678eSDavid Greenman 			DELAY(1);
374a17c678eSDavid Greenman 			if (csr->eeprom_control & FXP_EEPROM_EEDO)
375a17c678eSDavid Greenman 				data[i] |= (1 << (x - 1));
376a17c678eSDavid Greenman 			csr->eeprom_control = reg;
377a17c678eSDavid Greenman 			DELAY(1);
378a17c678eSDavid Greenman 		}
379a17c678eSDavid Greenman 		csr->eeprom_control = 0;
380a17c678eSDavid Greenman 		DELAY(1);
381a17c678eSDavid Greenman 	}
382a17c678eSDavid Greenman }
383a17c678eSDavid Greenman 
384a17c678eSDavid Greenman /*
385a17c678eSDavid Greenman  * Device shutdown routine. Usually called at system shutdown. The
386a17c678eSDavid Greenman  * main purpose of this routine is to shut off receiver DMA so that
387a17c678eSDavid Greenman  * kernel memory doesn't get clobbered during warmboot.
388a17c678eSDavid Greenman  */
389a17c678eSDavid Greenman static int
390a17c678eSDavid Greenman fxp_shutdown(kdc, force)
391a17c678eSDavid Greenman 	struct kern_devconf *kdc;
392a17c678eSDavid Greenman 	int force;
393a17c678eSDavid Greenman {
394a17c678eSDavid Greenman 	struct fxp_softc *sc = fxp_sc[kdc->kdc_unit];
395a17c678eSDavid Greenman 
396a17c678eSDavid Greenman 	/*
397a17c678eSDavid Greenman 	 * Cancel stats updater.
398a17c678eSDavid Greenman 	 */
399a17c678eSDavid Greenman 	untimeout(fxp_stats_update, sc);
400a17c678eSDavid Greenman 	/*
401a17c678eSDavid Greenman 	 * Issue software reset.
402a17c678eSDavid Greenman 	 */
403a17c678eSDavid Greenman 	sc->csr->port = 0;
404a17c678eSDavid Greenman 
405a17c678eSDavid Greenman 	(void) dev_detach(kdc);
406a17c678eSDavid Greenman 	return 0;
407a17c678eSDavid Greenman }
408a17c678eSDavid Greenman 
409a17c678eSDavid Greenman /*
410a17c678eSDavid Greenman  * Start packet transmission on the interface.
411a17c678eSDavid Greenman  */
412a17c678eSDavid Greenman static void
413a17c678eSDavid Greenman fxp_start(ifp)
414a17c678eSDavid Greenman 	struct ifnet *ifp;
415a17c678eSDavid Greenman {
416a17c678eSDavid Greenman 	struct fxp_softc *sc = fxp_sc[ifp->if_unit];
417a17c678eSDavid Greenman 	struct fxp_csr *csr = sc->csr;
418a17c678eSDavid Greenman 	struct fxp_cb_tx *txp;
419a17c678eSDavid Greenman 	struct mbuf *m, *mb_head;
420a17c678eSDavid Greenman 	int segment;
421a17c678eSDavid Greenman 
422a17c678eSDavid Greenman txloop:
423a17c678eSDavid Greenman 	/*
424a17c678eSDavid Greenman 	 * See if a TxCB is available. If not, indicate this to the
425a17c678eSDavid Greenman 	 * outside world and exit.
426a17c678eSDavid Greenman 	 */
427a17c678eSDavid Greenman 	if (sc->tx_queued >= FXP_NTXCB) {
428a17c678eSDavid Greenman 		ifp->if_flags |= IFF_OACTIVE;
429a17c678eSDavid Greenman 		return;
430a17c678eSDavid Greenman 	}
431dfe61cf1SDavid Greenman 	/*
432dfe61cf1SDavid Greenman 	 * Grab a packet to transmit.
433dfe61cf1SDavid Greenman 	 */
434a17c678eSDavid Greenman 	IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, mb_head);
435a17c678eSDavid Greenman 	if (mb_head == NULL) {
436a17c678eSDavid Greenman 		/*
437a17c678eSDavid Greenman 		 * No more packets to send.
438a17c678eSDavid Greenman 		 */
439a17c678eSDavid Greenman 		return;
440a17c678eSDavid Greenman 	}
441a17c678eSDavid Greenman 
442dfe61cf1SDavid Greenman 	/*
443dfe61cf1SDavid Greenman 	 * Get pointer to next available (unused) descriptor.
444dfe61cf1SDavid Greenman 	 */
445a17c678eSDavid Greenman 	txp = sc->cbl_last->next;
446a17c678eSDavid Greenman 
447a17c678eSDavid Greenman 	/*
448a17c678eSDavid Greenman 	 * Go through each of the mbufs in the chain and initialize
449a17c678eSDavid Greenman 	 * the transmit buffers descriptors with the physical address
450a17c678eSDavid Greenman 	 * and size of the mbuf.
451a17c678eSDavid Greenman 	 */
452a17c678eSDavid Greenman 	for (m = mb_head, segment = 0; m != NULL; m = m->m_next) {
453a17c678eSDavid Greenman 		if (m->m_len != 0) {
454a17c678eSDavid Greenman 			if (segment == FXP_NTXSEG)
455a17c678eSDavid Greenman 				break;
456a17c678eSDavid Greenman 			txp->tbd[segment].tb_addr =
457a17c678eSDavid Greenman 			    vtophys(mtod(m, vm_offset_t));
458a17c678eSDavid Greenman 			txp->tbd[segment].tb_size = m->m_len;
459a17c678eSDavid Greenman 			segment++;
460a17c678eSDavid Greenman 		}
461a17c678eSDavid Greenman 	}
462a17c678eSDavid Greenman 	if (m != NULL && segment == FXP_NTXSEG) {
463a17c678eSDavid Greenman 		/*
464a17c678eSDavid Greenman 		 * We ran out of segments. We have to recopy this mbuf
465a17c678eSDavid Greenman 		 * chain first.
466a17c678eSDavid Greenman 		 */
467a17c678eSDavid Greenman 		panic("fxp%d: ran out of segments", ifp->if_unit);
468a17c678eSDavid Greenman 	} else {
469a17c678eSDavid Greenman 		txp->tbd_number = segment;
470a17c678eSDavid Greenman 	}
471a17c678eSDavid Greenman 	/*
472a17c678eSDavid Greenman 	 * Finish the initialization of this TxCB.
473a17c678eSDavid Greenman 	 */
474a17c678eSDavid Greenman 	txp->cb_status = 0;
475a17c678eSDavid Greenman 	txp->cb_command =
476a17c678eSDavid Greenman 	    FXP_CB_COMMAND_XMIT | FXP_CB_COMMAND_SF | FXP_CB_COMMAND_S;
477a17c678eSDavid Greenman 	txp->tx_threshold = 16;	/* bytes*8 */
478a17c678eSDavid Greenman 	txp->mb_head = mb_head;
479a17c678eSDavid Greenman 
480a17c678eSDavid Greenman 	/*
481a17c678eSDavid Greenman 	 * Advance the end-of-list forward.
482a17c678eSDavid Greenman 	 */
483a17c678eSDavid Greenman 	sc->cbl_last->cb_command &= ~FXP_CB_COMMAND_S;
484a17c678eSDavid Greenman 	sc->cbl_last = txp;
485a17c678eSDavid Greenman 
486a17c678eSDavid Greenman 	/*
487a17c678eSDavid Greenman 	 * If no packets were previously queued then advance the first
488a17c678eSDavid Greenman 	 * pointer to this TxCB.
489a17c678eSDavid Greenman 	 */
490a17c678eSDavid Greenman 	if (sc->tx_queued++ == 0) {
491a17c678eSDavid Greenman 		sc->cbl_first = txp;
492a17c678eSDavid Greenman 	}
493a17c678eSDavid Greenman 
494a17c678eSDavid Greenman 	/*
495a17c678eSDavid Greenman 	 * Resume transmission if suspended.
496a17c678eSDavid Greenman 	 */
497a17c678eSDavid Greenman 	fxp_scb_wait(csr);
498a17c678eSDavid Greenman 	csr->scb_command = FXP_SCB_COMMAND_CU_RESUME;
499a17c678eSDavid Greenman 
500a17c678eSDavid Greenman #if NBPFILTER > 0
501a17c678eSDavid Greenman 	/*
502a17c678eSDavid Greenman 	 * Pass packet to bpf if there is a listener.
503a17c678eSDavid Greenman 	 */
504a17c678eSDavid Greenman 	if (sc->bpf != NULL)
505a17c678eSDavid Greenman 		bpf_mtap(sc->bpf, mb_head);
506a17c678eSDavid Greenman #endif
507a17c678eSDavid Greenman 	/*
508a17c678eSDavid Greenman 	 * Set a 5 second timer just in case we don't hear from the
509a17c678eSDavid Greenman 	 * card again.
510a17c678eSDavid Greenman 	 */
511a17c678eSDavid Greenman 	ifp->if_timer = 5;
512a17c678eSDavid Greenman 
513a17c678eSDavid Greenman 	goto txloop;
514a17c678eSDavid Greenman }
515a17c678eSDavid Greenman 
516a17c678eSDavid Greenman /*
517a17c678eSDavid Greenman  * Process interface interrupts. Returns 1 if the interrupt
518a17c678eSDavid Greenman  * was handled, 0 if it wasn't.
519a17c678eSDavid Greenman  */
520a17c678eSDavid Greenman static int
521a17c678eSDavid Greenman fxp_intr(arg)
522a17c678eSDavid Greenman 	void *arg;
523a17c678eSDavid Greenman {
524a17c678eSDavid Greenman 	struct fxp_softc *sc = arg;
525a17c678eSDavid Greenman 	struct fxp_csr *csr = sc->csr;
526a17c678eSDavid Greenman 	struct ifnet *ifp = &sc->arpcom.ac_if;
527a17c678eSDavid Greenman 	int found = 0;
528a17c678eSDavid Greenman 	u_char statack;
529a17c678eSDavid Greenman 
530a17c678eSDavid Greenman 	while ((statack = csr->scb_statack) != 0) {
531a17c678eSDavid Greenman 		found = 1;
532a17c678eSDavid Greenman 		/*
533a17c678eSDavid Greenman 		 * First ACK all the interrupts in this pass.
534a17c678eSDavid Greenman 		 */
535a17c678eSDavid Greenman 		csr->scb_statack = statack;
536a17c678eSDavid Greenman 
537a17c678eSDavid Greenman 		/*
538a17c678eSDavid Greenman 		 * Free any finished transmit mbuf chains.
539a17c678eSDavid Greenman 		 */
540a17c678eSDavid Greenman 		if (statack & FXP_SCB_STATACK_CNA) {
541a17c678eSDavid Greenman 			struct fxp_cb_tx *txp;
542a17c678eSDavid Greenman 
543a17c678eSDavid Greenman 			for (txp = sc->cbl_first;
544a17c678eSDavid Greenman 			    (txp->cb_status & FXP_CB_STATUS_C) &&
545a17c678eSDavid Greenman 			    txp->mb_head != NULL;
546a17c678eSDavid Greenman 			    txp = txp->next) {
547a17c678eSDavid Greenman 				m_freem(txp->mb_head);
548a17c678eSDavid Greenman 				txp->mb_head = NULL;
549a17c678eSDavid Greenman 				sc->tx_queued--;
550a17c678eSDavid Greenman 			}
551a17c678eSDavid Greenman 			sc->cbl_first = txp;
552a17c678eSDavid Greenman 			/*
553a17c678eSDavid Greenman 			 * We unconditionally clear IFF_OACTIVE since it
554a17c678eSDavid Greenman 			 * doesn't hurt to do so even if the tx queue is
555a17c678eSDavid Greenman 			 * still full - it will just get set again in
556a17c678eSDavid Greenman 			 * fxp_start(). If we get a CNA interrupt, it is
557a17c678eSDavid Greenman 			 * (almost?) certain that we've freed up space for
558a17c678eSDavid Greenman 			 * at least one more packet.
559a17c678eSDavid Greenman 			 */
560a17c678eSDavid Greenman 			ifp->if_flags &= ~IFF_OACTIVE;
561a17c678eSDavid Greenman 			/*
562a17c678eSDavid Greenman 			 * Clear watchdog timer. It may or may not be set
563a17c678eSDavid Greenman 			 * again in fxp_start().
564a17c678eSDavid Greenman 			 */
565a17c678eSDavid Greenman 			ifp->if_timer = 0;
566a17c678eSDavid Greenman 			fxp_start(ifp);
567a17c678eSDavid Greenman 		}
568a17c678eSDavid Greenman 		/*
569a17c678eSDavid Greenman 		 * Process receiver interrupts. If a no-resource (RNR)
570a17c678eSDavid Greenman 		 * condition exists, get whatever packets we can and
571a17c678eSDavid Greenman 		 * re-start the receiver.
572a17c678eSDavid Greenman 		 */
573a17c678eSDavid Greenman 		if (statack & (FXP_SCB_STATACK_FR | FXP_SCB_STATACK_RNR)) {
574a17c678eSDavid Greenman 			struct mbuf *m;
575a17c678eSDavid Greenman 			struct fxp_rfa *rfa;
576a17c678eSDavid Greenman rcvloop:
577a17c678eSDavid Greenman 			m = sc->rfa_headm;
578dfe61cf1SDavid Greenman 			rfa = (struct fxp_rfa *)m->m_ext.ext_buf;
579a17c678eSDavid Greenman 
580a17c678eSDavid Greenman 			if (rfa->rfa_status & FXP_RFA_STATUS_C) {
581dfe61cf1SDavid Greenman 				/*
582dfe61cf1SDavid Greenman 				 * Remove first packet from the chain.
583dfe61cf1SDavid Greenman 				 */
584a17c678eSDavid Greenman 				sc->rfa_headm = m->m_next;
585a17c678eSDavid Greenman 				m->m_next = NULL;
586a17c678eSDavid Greenman 
587dfe61cf1SDavid Greenman 				/*
588dfe61cf1SDavid Greenman 				 * Add a new buffer to the receive chain. If this
589dfe61cf1SDavid Greenman 				 * fails, the old buffer is recycled instead.
590dfe61cf1SDavid Greenman 				 */
591a17c678eSDavid Greenman 				if (fxp_add_rfabuf(sc, m) == 0) {
592a17c678eSDavid Greenman 					struct ether_header *eh;
593a17c678eSDavid Greenman 					u_short total_len;
594a17c678eSDavid Greenman 
595a17c678eSDavid Greenman 					total_len = rfa->actual_size & (MCLBYTES - 1);
596a17c678eSDavid Greenman 					m->m_pkthdr.rcvif = ifp;
597a17c678eSDavid Greenman 					m->m_pkthdr.len = m->m_len = total_len -
598a17c678eSDavid Greenman 					    sizeof(struct ether_header);
599a17c678eSDavid Greenman 					eh = mtod(m, struct ether_header *);
600a17c678eSDavid Greenman #if NBPFILTER > 0
601a17c678eSDavid Greenman 					if (sc->bpf != NULL) {
602a17c678eSDavid Greenman 						bpf_tap(sc->bpf, mtod(m, caddr_t), total_len);
603a17c678eSDavid Greenman 						/*
604a17c678eSDavid Greenman 						 * Only pass this packet up if it is for us.
605a17c678eSDavid Greenman 						 */
606a17c678eSDavid Greenman 						if ((ifp->if_flags & IFF_PROMISC) &&
607a17c678eSDavid Greenman 						    (rfa->rfa_status & FXP_RFA_STATUS_IAMATCH) &&
608a17c678eSDavid Greenman 						    (eh->ether_dhost[0] & 1) == 0) {
609a17c678eSDavid Greenman 							m_freem(m);
610a17c678eSDavid Greenman 							goto rcvloop;
611a17c678eSDavid Greenman 						}
612a17c678eSDavid Greenman 					}
613a17c678eSDavid Greenman #endif
614a17c678eSDavid Greenman 					m->m_data += sizeof(struct ether_header);
615a17c678eSDavid Greenman 					ether_input(ifp, eh, m);
616a17c678eSDavid Greenman 				}
617a17c678eSDavid Greenman 				goto rcvloop;
618a17c678eSDavid Greenman 			}
619a17c678eSDavid Greenman 			if (statack & FXP_SCB_STATACK_RNR) {
620a17c678eSDavid Greenman 				struct fxp_csr *csr = sc->csr;
621a17c678eSDavid Greenman 
622a17c678eSDavid Greenman 				ifp->if_ierrors++;
623a17c678eSDavid Greenman 				fxp_scb_wait(csr);
624dfe61cf1SDavid Greenman 				csr->scb_general = vtophys(sc->rfa_headm->m_ext.ext_buf);
625a17c678eSDavid Greenman 				csr->scb_command = FXP_SCB_COMMAND_RU_START;
626a17c678eSDavid Greenman 			}
627a17c678eSDavid Greenman 		}
628a17c678eSDavid Greenman 	}
629a17c678eSDavid Greenman 
630a17c678eSDavid Greenman 	return found;
631a17c678eSDavid Greenman }
632a17c678eSDavid Greenman 
633dfe61cf1SDavid Greenman /*
634dfe61cf1SDavid Greenman  * Update packet in/out/collision statistics. The i82557 doesn't
635dfe61cf1SDavid Greenman  * allow you to access these counters without doing a fairly
636dfe61cf1SDavid Greenman  * expensive DMA to get _all_ of the statistics it maintains, so
637dfe61cf1SDavid Greenman  * we do this operation here only once per second. The statistics
638dfe61cf1SDavid Greenman  * counters in the kernel are updated from the previous dump-stats
639dfe61cf1SDavid Greenman  * DMA and then a new dump-stats DMA is started. The on-chip
640dfe61cf1SDavid Greenman  * counters are zeroed when the DMA completes. If we can't start
641dfe61cf1SDavid Greenman  * the DMA immediately, we don't wait - we just prepare to read
642dfe61cf1SDavid Greenman  * them again next time.
643dfe61cf1SDavid Greenman  */
644a17c678eSDavid Greenman void
645a17c678eSDavid Greenman fxp_stats_update(arg)
646a17c678eSDavid Greenman 	void *arg;
647a17c678eSDavid Greenman {
648a17c678eSDavid Greenman 	struct fxp_softc *sc = arg;
649a17c678eSDavid Greenman 	struct ifnet *ifp = &sc->arpcom.ac_if;
650a17c678eSDavid Greenman 	struct fxp_stats *sp = sc->fxp_stats;
651a17c678eSDavid Greenman 
652a17c678eSDavid Greenman 	ifp->if_opackets += sp->tx_good;
653a17c678eSDavid Greenman 	ifp->if_collisions += sp->tx_total_collisions;
654a17c678eSDavid Greenman 	ifp->if_ipackets += sp->rx_good;
655a17c678eSDavid Greenman 	/*
656a17c678eSDavid Greenman 	 * If there is a pending command, don't wait for it to
657a17c678eSDavid Greenman 	 * be accepted - we'll pick up the stats the next time
658a17c678eSDavid Greenman 	 * around. Make sure we don't count the stats twice
659a17c678eSDavid Greenman 	 * however.
660a17c678eSDavid Greenman 	 */
661dfe61cf1SDavid Greenman 	if ((sc->csr->scb_command & FXP_SCB_COMMAND_MASK) == 0) {
662a17c678eSDavid Greenman 		/*
663dfe61cf1SDavid Greenman 		 * Start another stats dump. By waiting for it to be
664dfe61cf1SDavid Greenman 		 * accepted, we avoid having to do splhigh locking when
665dfe61cf1SDavid Greenman 		 * writing scb_command in other parts of the driver.
666a17c678eSDavid Greenman 		 */
667a17c678eSDavid Greenman 		sc->csr->scb_command = FXP_SCB_COMMAND_CU_DUMPRESET;
668a17c678eSDavid Greenman 		fxp_scb_wait(sc);
669dfe61cf1SDavid Greenman 	} else {
670dfe61cf1SDavid Greenman 		/*
671dfe61cf1SDavid Greenman 		 * A previous command is still waiting to be accepted.
672dfe61cf1SDavid Greenman 		 * Just zero our copy of the stats and wait for the
673dfe61cf1SDavid Greenman 		 * next timer event to pdate them.
674dfe61cf1SDavid Greenman 		 */
675dfe61cf1SDavid Greenman 		sp->tx_good = 0;
676dfe61cf1SDavid Greenman 		sp->tx_total_collisions = 0;
677dfe61cf1SDavid Greenman 		sp->rx_good = 0;
678dfe61cf1SDavid Greenman 	}
679a17c678eSDavid Greenman 	/*
680a17c678eSDavid Greenman 	 * Schedule another timeout one second from now.
681a17c678eSDavid Greenman 	 */
682a17c678eSDavid Greenman 	timeout(fxp_stats_update, sc, hz);
683a17c678eSDavid Greenman }
684a17c678eSDavid Greenman 
685a17c678eSDavid Greenman /*
686a17c678eSDavid Greenman  * Stop the interface. Cancels the statistics updater and resets
687a17c678eSDavid Greenman  * the interface.
688a17c678eSDavid Greenman  */
689a17c678eSDavid Greenman static void
690a17c678eSDavid Greenman fxp_stop(unit)
691a17c678eSDavid Greenman 	int unit;
692a17c678eSDavid Greenman {
693a17c678eSDavid Greenman 	struct fxp_softc *sc = fxp_sc[unit];
694a17c678eSDavid Greenman 	struct ifnet *ifp = &sc->arpcom.ac_if;
695a17c678eSDavid Greenman 
696a17c678eSDavid Greenman 	/*
697a17c678eSDavid Greenman 	 * Cancel stats updater.
698a17c678eSDavid Greenman 	 */
699a17c678eSDavid Greenman 	untimeout(fxp_stats_update, sc);
700a17c678eSDavid Greenman 	sc->csr->port = 0;
701a17c678eSDavid Greenman 	DELAY(10);
702a17c678eSDavid Greenman 
703a17c678eSDavid Greenman 	ifp->if_flags &= ~IFF_RUNNING;
704a17c678eSDavid Greenman }
705a17c678eSDavid Greenman 
706a17c678eSDavid Greenman /*
707a17c678eSDavid Greenman  * Watchdog/transmission transmit timeout handler. Called when a
708a17c678eSDavid Greenman  * transmission is started on the interface, but no interrupt is
709a17c678eSDavid Greenman  * received before the timeout. This usually indicates that the
710a17c678eSDavid Greenman  * card has wedged for some reason.
711a17c678eSDavid Greenman  */
712a17c678eSDavid Greenman static void
713a17c678eSDavid Greenman fxp_watchdog(unit)
714a17c678eSDavid Greenman 	int unit;
715a17c678eSDavid Greenman {
716a17c678eSDavid Greenman 	struct fxp_softc *sc = fxp_sc[unit];
717a17c678eSDavid Greenman 	struct ifnet *ifp = &sc->arpcom.ac_if;
718a17c678eSDavid Greenman 
719a17c678eSDavid Greenman 	log(LOG_ERR, "fxp%d: device timeout\n", unit);
720a17c678eSDavid Greenman 	++sc->arpcom.ac_if.if_oerrors;
721a17c678eSDavid Greenman 
722a17c678eSDavid Greenman 	fxp_stop(unit);
723a17c678eSDavid Greenman 	fxp_init(unit);
724a17c678eSDavid Greenman }
725a17c678eSDavid Greenman 
726a17c678eSDavid Greenman static void
727a17c678eSDavid Greenman fxp_init(unit)
728a17c678eSDavid Greenman 	int unit;
729a17c678eSDavid Greenman {
730a17c678eSDavid Greenman 	struct fxp_softc *sc = fxp_sc[unit];
731a17c678eSDavid Greenman 	struct ifnet *ifp = &sc->arpcom.ac_if;
732a17c678eSDavid Greenman 	struct fxp_cb_config *cbp;
733a17c678eSDavid Greenman 	struct fxp_cb_ias *cb_ias;
734a17c678eSDavid Greenman 	struct fxp_cb_tx *txp;
735a17c678eSDavid Greenman 	struct fxp_csr *csr = sc->csr;
736a17c678eSDavid Greenman 	int i, s, mcast, prm;
737a17c678eSDavid Greenman 
738a17c678eSDavid Greenman 	/*
739a17c678eSDavid Greenman 	 * Cancel stats updater.
740a17c678eSDavid Greenman 	 */
741a17c678eSDavid Greenman 	untimeout(fxp_stats_update, sc);
742a17c678eSDavid Greenman 
743a17c678eSDavid Greenman 	s = splimp();
744a17c678eSDavid Greenman 	/*
745a17c678eSDavid Greenman 	 * Issue software reset and wait 10us for the card to recover.
746a17c678eSDavid Greenman 	 */
747a17c678eSDavid Greenman 	csr->port = 0;
748a17c678eSDavid Greenman 	DELAY(10);
749a17c678eSDavid Greenman 
750a17c678eSDavid Greenman 	prm = (ifp->if_flags & IFF_PROMISC) ? 1 : 0;
751a17c678eSDavid Greenman 	sc->promisc_mode = prm;
752a17c678eSDavid Greenman 	/*
753a17c678eSDavid Greenman 	 * Sleeze out here and enable reception of all multicasts if
754a17c678eSDavid Greenman 	 * multicasts are enabled. Ideally, we'd program the multicast
755a17c678eSDavid Greenman 	 * address filter to only accept specific multicasts.
756a17c678eSDavid Greenman 	 */
757a17c678eSDavid Greenman 	mcast = (ifp->if_flags & (IFF_MULTICAST|IFF_ALLMULTI)) ? 1 : 0;
758a17c678eSDavid Greenman 
759a17c678eSDavid Greenman 	/*
760a17c678eSDavid Greenman 	 * Initialize base of CBL and RFA memory. Loading with zero
761a17c678eSDavid Greenman 	 * sets it up for regular linear addressing.
762a17c678eSDavid Greenman 	 */
763a17c678eSDavid Greenman 	csr->scb_general = 0;
764a17c678eSDavid Greenman 	csr->scb_command = FXP_SCB_COMMAND_CU_BASE;
765a17c678eSDavid Greenman 
766a17c678eSDavid Greenman 	fxp_scb_wait(csr);
767a17c678eSDavid Greenman 	csr->scb_command = FXP_SCB_COMMAND_RU_BASE;
768a17c678eSDavid Greenman 
769a17c678eSDavid Greenman 	/*
770a17c678eSDavid Greenman 	 * Initialize base of dump-stats buffer.
771a17c678eSDavid Greenman 	 */
772a17c678eSDavid Greenman 	fxp_scb_wait(csr);
773a17c678eSDavid Greenman 	csr->scb_general = vtophys(sc->fxp_stats);
774a17c678eSDavid Greenman 	csr->scb_command = FXP_SCB_COMMAND_CU_DUMP_ADR;
775a17c678eSDavid Greenman 
776a17c678eSDavid Greenman 	/*
777a17c678eSDavid Greenman 	 * We temporarily use memory that contains the TxCB list to
778a17c678eSDavid Greenman 	 * construct the config CB. The TxCB list memory is rebuilt
779a17c678eSDavid Greenman 	 * later.
780a17c678eSDavid Greenman 	 */
781a17c678eSDavid Greenman 	cbp = (struct fxp_cb_config *) sc->cbl_base;
782a17c678eSDavid Greenman 
783a17c678eSDavid Greenman 	/*
784a17c678eSDavid Greenman 	 * This bcopy is kind of disgusting, but there are a bunch of must be
785a17c678eSDavid Greenman 	 * zero and must be one bits in this structure and this is the easiest
786a17c678eSDavid Greenman 	 * way to initialize them all to proper values.
787a17c678eSDavid Greenman 	 */
788a17c678eSDavid Greenman 	bcopy(fxp_cb_config_template, cbp, sizeof(struct fxp_cb_config));
789a17c678eSDavid Greenman 
790a17c678eSDavid Greenman 	cbp->cb_status =	0;
791a17c678eSDavid Greenman 	cbp->cb_command =	FXP_CB_COMMAND_CONFIG | FXP_CB_COMMAND_EL;
792a17c678eSDavid Greenman 	cbp->link_addr =	-1;	/* (no) next command */
793a17c678eSDavid Greenman 	cbp->byte_count =	22;	/* (22) bytes to config */
794a17c678eSDavid Greenman 	cbp->rx_fifo_limit =	8;	/* rx fifo threshold */
795a17c678eSDavid Greenman 	cbp->tx_fifo_limit =	0;	/* tx fifo threshold */
796a17c678eSDavid Greenman 	cbp->adaptive_ifs =	0;	/* (no) adaptive interframe spacing */
797a17c678eSDavid Greenman 	cbp->rx_dma_bytecount =	0;	/* (no) rx DMA max */
798a17c678eSDavid Greenman 	cbp->tx_dma_bytecount =	0;	/* (no) tx DMA max */
799a17c678eSDavid Greenman 	cbp->dma_bce =		1;	/* (enable) dma max counters */
800a17c678eSDavid Greenman 	cbp->late_scb =		0;	/* (don't) defer SCB update */
801a17c678eSDavid Greenman 	cbp->tno_int =		0;	/* (disable) tx not okay interrupt */
802a17c678eSDavid Greenman 	cbp->ci_int =		0;	/* (do) interrupt on CU not active */
803a17c678eSDavid Greenman 	cbp->save_bf =		prm;	/* save bad frames */
804a17c678eSDavid Greenman 	cbp->disc_short_rx =	!prm;	/* discard short packets */
805a17c678eSDavid Greenman 	cbp->underrun_retry =	1;	/* retry mode (1) on DMA underrun */
806a17c678eSDavid Greenman 	cbp->mediatype =	1;	/* (MII) interface mode */
807a17c678eSDavid Greenman 	cbp->nsai =		1;	/* (don't) disable source addr insert */
808a17c678eSDavid Greenman 	cbp->preamble_length =	2;	/* (7 byte) preamble */
809a17c678eSDavid Greenman 	cbp->loopback =		0;	/* (don't) loopback */
810a17c678eSDavid Greenman 	cbp->linear_priority =	0;	/* (normal CSMA/CD operation) */
811a17c678eSDavid Greenman 	cbp->linear_pri_mode =	0;	/* (wait after xmit only) */
812a17c678eSDavid Greenman 	cbp->interfrm_spacing =	6;	/* (96 bits of) interframe spacing */
813a17c678eSDavid Greenman 	cbp->promiscuous =	prm;	/* promiscuous mode */
814a17c678eSDavid Greenman 	cbp->bcast_disable =	0;	/* (don't) disable broadcasts */
815a17c678eSDavid Greenman 	cbp->crscdt =		0;	/* (CRS only) */
816a17c678eSDavid Greenman 	cbp->stripping =	!prm;	/* truncate rx packet to byte count */
817a17c678eSDavid Greenman 	cbp->padding =		1;	/* (do) pad short tx packets */
818a17c678eSDavid Greenman 	cbp->rcv_crc_xfer =	0;	/* (don't) xfer CRC to host */
819a17c678eSDavid Greenman 	cbp->force_fdx =	0;	/* (don't) force full duplex */
820a17c678eSDavid Greenman 	cbp->fdx_pin_en =	0;	/* (ignore) FDX# pin */
821a17c678eSDavid Greenman 	cbp->multi_ia =		0;	/* (don't) accept multiple IAs */
822a17c678eSDavid Greenman 	cbp->mc_all =		mcast;	/* accept all multicasts */
823a17c678eSDavid Greenman 
824a17c678eSDavid Greenman 	/*
825a17c678eSDavid Greenman 	 * Start the config command/DMA.
826a17c678eSDavid Greenman 	 */
827a17c678eSDavid Greenman 	fxp_scb_wait(csr);
828a17c678eSDavid Greenman 	csr->scb_general = vtophys(cbp);
829a17c678eSDavid Greenman 	csr->scb_command = FXP_SCB_COMMAND_CU_START;
830a17c678eSDavid Greenman 	/* ...and wait for it to complete. */
831a17c678eSDavid Greenman 	while (!(cbp->cb_status & FXP_CB_STATUS_C));
832a17c678eSDavid Greenman 
833a17c678eSDavid Greenman 	/*
834a17c678eSDavid Greenman 	 * Now initialize the station address. Temporarily use the TxCB
835a17c678eSDavid Greenman 	 * memory area like we did above for the config CB.
836a17c678eSDavid Greenman 	 */
837a17c678eSDavid Greenman 	cb_ias = (struct fxp_cb_ias *) sc->cbl_base;
838a17c678eSDavid Greenman 	cb_ias->cb_status = 0;
839a17c678eSDavid Greenman 	cb_ias->cb_command = FXP_CB_COMMAND_IAS | FXP_CB_COMMAND_EL;
840a17c678eSDavid Greenman 	cb_ias->link_addr = -1;
841a17c678eSDavid Greenman 	bcopy(sc->arpcom.ac_enaddr, (void *)cb_ias->macaddr,
842a17c678eSDavid Greenman 	    sizeof(sc->arpcom.ac_enaddr));
843a17c678eSDavid Greenman 
844a17c678eSDavid Greenman 	/*
845a17c678eSDavid Greenman 	 * Start the IAS (Individual Address Setup) command/DMA.
846a17c678eSDavid Greenman 	 */
847a17c678eSDavid Greenman 	fxp_scb_wait(csr);
848a17c678eSDavid Greenman 	csr->scb_command = FXP_SCB_COMMAND_CU_START;
849a17c678eSDavid Greenman 	/* ...and wait for it to complete. */
850a17c678eSDavid Greenman 	while (!(cb_ias->cb_status & FXP_CB_STATUS_C));
851a17c678eSDavid Greenman 
852a17c678eSDavid Greenman 	/*
853a17c678eSDavid Greenman 	 * Initialize transmit control block (TxCB) list.
854a17c678eSDavid Greenman 	 */
855a17c678eSDavid Greenman 
856a17c678eSDavid Greenman 	txp = sc->cbl_base;
857a17c678eSDavid Greenman 	bzero(txp, sizeof(struct fxp_cb_tx) * FXP_NTXCB);
858a17c678eSDavid Greenman 	for (i = 0; i < FXP_NTXCB; i++) {
859a17c678eSDavid Greenman 		txp[i].cb_status = FXP_CB_STATUS_C | FXP_CB_STATUS_OK;
860a17c678eSDavid Greenman 		txp[i].cb_command = FXP_CB_COMMAND_NOP;
861a17c678eSDavid Greenman 		txp[i].link_addr = vtophys(&txp[(i + 1) & FXP_TXCB_MASK]);
862a17c678eSDavid Greenman 		txp[i].tbd_array_addr = vtophys(&txp[i].tbd[0]);
863a17c678eSDavid Greenman 		txp[i].next = &txp[(i + 1) & FXP_TXCB_MASK];
864a17c678eSDavid Greenman 	}
865a17c678eSDavid Greenman 	/*
866a17c678eSDavid Greenman 	 * Set the stop flag on the first TxCB and start the control
867a17c678eSDavid Greenman 	 * unit. It will execute the NOP and then suspend.
868a17c678eSDavid Greenman 	 */
869a17c678eSDavid Greenman 	txp->cb_command = FXP_CB_COMMAND_NOP | FXP_CB_COMMAND_S;
870a17c678eSDavid Greenman 	sc->cbl_first = sc->cbl_last = txp;
871a17c678eSDavid Greenman 	sc->tx_queued = 0;
872a17c678eSDavid Greenman 
873a17c678eSDavid Greenman 	fxp_scb_wait(csr);
874a17c678eSDavid Greenman 	csr->scb_command = FXP_SCB_COMMAND_CU_START;
875a17c678eSDavid Greenman 
876a17c678eSDavid Greenman 	/*
877a17c678eSDavid Greenman 	 * Initialize receiver buffer area - RFA.
878a17c678eSDavid Greenman 	 */
879a17c678eSDavid Greenman 	fxp_scb_wait(csr);
880dfe61cf1SDavid Greenman 	csr->scb_general = vtophys(sc->rfa_headm->m_ext.ext_buf);
881a17c678eSDavid Greenman 	csr->scb_command = FXP_SCB_COMMAND_RU_START;
882a17c678eSDavid Greenman 
883a17c678eSDavid Greenman 	ifp->if_flags |= IFF_RUNNING;
884a17c678eSDavid Greenman 	ifp->if_flags &= ~IFF_OACTIVE;
885a17c678eSDavid Greenman 	splx(s);
886a17c678eSDavid Greenman 
887a17c678eSDavid Greenman 	/*
888a17c678eSDavid Greenman 	 * Start stats updater.
889a17c678eSDavid Greenman 	 */
890a17c678eSDavid Greenman 	timeout(fxp_stats_update, sc, hz);
891a17c678eSDavid Greenman }
892a17c678eSDavid Greenman 
893a17c678eSDavid Greenman /*
894a17c678eSDavid Greenman  * Add a buffer to the end of the RFA buffer list.
895a17c678eSDavid Greenman  * Return 0 if successful, 1 for failure. A failure results in
896a17c678eSDavid Greenman  * adding the 'oldm' (if non-NULL) on to the end of the list -
897a17c678eSDavid Greenman  * tossing out it's old contents and recycling it.
898a17c678eSDavid Greenman  * The RFA struct is stuck at the beginning of mbuf cluster and the
899a17c678eSDavid Greenman  * data pointer is fixed up to point just past it.
900a17c678eSDavid Greenman  */
901a17c678eSDavid Greenman static int
902a17c678eSDavid Greenman fxp_add_rfabuf(sc, oldm)
903a17c678eSDavid Greenman 	struct fxp_softc *sc;
904a17c678eSDavid Greenman 	struct mbuf *oldm;
905a17c678eSDavid Greenman {
906a17c678eSDavid Greenman 	struct mbuf *m;
907a17c678eSDavid Greenman 	struct fxp_rfa *rfa, *p_rfa;
908a17c678eSDavid Greenman 
909a17c678eSDavid Greenman 	MGETHDR(m, M_DONTWAIT, MT_DATA);
910a17c678eSDavid Greenman 	if (m != NULL) {
911a17c678eSDavid Greenman 		MCLGET(m, M_DONTWAIT);
912a17c678eSDavid Greenman 		if ((m->m_flags & M_EXT) == 0) {
913a17c678eSDavid Greenman 			m_freem(m);
914a17c678eSDavid Greenman 			m = oldm;
915a17c678eSDavid Greenman 		}
916a17c678eSDavid Greenman 	} else {
917a17c678eSDavid Greenman 		m = oldm;
918a17c678eSDavid Greenman 	}
919a17c678eSDavid Greenman 	if (m == NULL)
920a17c678eSDavid Greenman 		return 1;
921a17c678eSDavid Greenman 	rfa = mtod(m, struct fxp_rfa *);
922a17c678eSDavid Greenman 	rfa->rfa_status = 0;
923a17c678eSDavid Greenman 	rfa->rfa_control = FXP_RFA_CONTROL_EL;
924a17c678eSDavid Greenman 	rfa->link_addr = -1;
925a17c678eSDavid Greenman 	rfa->rbd_addr = -1;
926a17c678eSDavid Greenman 	rfa->actual_size = 0;
927a17c678eSDavid Greenman 	rfa->size = MCLBYTES - sizeof(struct fxp_rfa);
928a17c678eSDavid Greenman 	m->m_data += sizeof(struct fxp_rfa);
929dfe61cf1SDavid Greenman 	/*
930dfe61cf1SDavid Greenman 	 * If there are other buffers already on the list, attach this
931dfe61cf1SDavid Greenman 	 * one to the end by fixing up the tail to point to this one.
932dfe61cf1SDavid Greenman 	 */
933a17c678eSDavid Greenman 	if (sc->rfa_headm != NULL) {
934dfe61cf1SDavid Greenman 		p_rfa = (struct fxp_rfa *) sc->rfa_tailm->m_ext.ext_buf;
935a17c678eSDavid Greenman 		sc->rfa_tailm->m_next = m;
936a17c678eSDavid Greenman 		p_rfa->link_addr = vtophys(rfa);
937a17c678eSDavid Greenman 		p_rfa->rfa_control &= ~FXP_RFA_CONTROL_EL;
938a17c678eSDavid Greenman 	} else {
939a17c678eSDavid Greenman 		sc->rfa_headm = m;
940a17c678eSDavid Greenman 	}
941a17c678eSDavid Greenman 	sc->rfa_tailm = m;
942a17c678eSDavid Greenman 
943dfe61cf1SDavid Greenman 	return (m == oldm);
944a17c678eSDavid Greenman }
945a17c678eSDavid Greenman 
946a17c678eSDavid Greenman static int
947a17c678eSDavid Greenman fxp_ioctl(ifp, command, data)
948a17c678eSDavid Greenman 	struct ifnet *ifp;
949a17c678eSDavid Greenman 	int command;
950a17c678eSDavid Greenman 	caddr_t data;
951a17c678eSDavid Greenman {
952a17c678eSDavid Greenman 	struct ifaddr *ifa = (struct ifaddr *) data;
953a17c678eSDavid Greenman 	struct fxp_softc *sc = fxp_sc[ifp->if_unit];
954a17c678eSDavid Greenman 	struct ifreq *ifr = (struct ifreq *) data;
955a17c678eSDavid Greenman 	int s, error = 0;
956a17c678eSDavid Greenman 
957a17c678eSDavid Greenman 	s = splimp();
958a17c678eSDavid Greenman 
959a17c678eSDavid Greenman 	switch (command) {
960a17c678eSDavid Greenman 
961a17c678eSDavid Greenman 	case SIOCSIFADDR:
962a17c678eSDavid Greenman 		ifp->if_flags |= IFF_UP;
963a17c678eSDavid Greenman 
964a17c678eSDavid Greenman 		switch (ifa->ifa_addr->sa_family) {
965a17c678eSDavid Greenman #ifdef INET
966a17c678eSDavid Greenman 		case AF_INET:
967a17c678eSDavid Greenman 			fxp_init(ifp->if_unit);	/* before arpwhohas */
968a17c678eSDavid Greenman 			arp_ifinit((struct arpcom *)ifp, ifa);
969a17c678eSDavid Greenman 			break;
970a17c678eSDavid Greenman #endif
971a17c678eSDavid Greenman #ifdef IPX
972a17c678eSDavid Greenman 		/*
973a17c678eSDavid Greenman 		 * XXX - This code is probably wrong
974a17c678eSDavid Greenman 		 */
975a17c678eSDavid Greenman 		case AF_IPX:
976a17c678eSDavid Greenman 			{
977a17c678eSDavid Greenman 				register struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr);
978a17c678eSDavid Greenman 
979a17c678eSDavid Greenman 				if (ipx_nullhost(*ina))
980a17c678eSDavid Greenman 					ina->x_host =
981a17c678eSDavid Greenman 					    *(union ipx_host *) (sc->arpcom.ac_enaddr);
982a17c678eSDavid Greenman 				else {
983a17c678eSDavid Greenman 					bcopy((caddr_t) ina->x_host.c_host,
984a17c678eSDavid Greenman 					      (caddr_t) sc->arpcom.ac_enaddr,
985a17c678eSDavid Greenman 					      sizeof(sc->arpcom.ac_enaddr));
986a17c678eSDavid Greenman 				}
987a17c678eSDavid Greenman 
988a17c678eSDavid Greenman 				/*
989a17c678eSDavid Greenman 				 * Set new address
990a17c678eSDavid Greenman 				 */
991a17c678eSDavid Greenman 				fxp_init(ifp->if_unit);
992a17c678eSDavid Greenman 				break;
993a17c678eSDavid Greenman 			}
994a17c678eSDavid Greenman #endif
995a17c678eSDavid Greenman #ifdef NS
996a17c678eSDavid Greenman 		/*
997a17c678eSDavid Greenman 		 * XXX - This code is probably wrong
998a17c678eSDavid Greenman 		 */
999a17c678eSDavid Greenman 		case AF_NS:
1000a17c678eSDavid Greenman 			{
1001a17c678eSDavid Greenman 				register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
1002a17c678eSDavid Greenman 
1003a17c678eSDavid Greenman 				if (ns_nullhost(*ina))
1004a17c678eSDavid Greenman 					ina->x_host =
1005a17c678eSDavid Greenman 					    *(union ns_host *) (sc->arpcom.ac_enaddr);
1006a17c678eSDavid Greenman 				else {
1007a17c678eSDavid Greenman 					bcopy((caddr_t) ina->x_host.c_host,
1008a17c678eSDavid Greenman 					      (caddr_t) sc->arpcom.ac_enaddr,
1009a17c678eSDavid Greenman 					      sizeof(sc->arpcom.ac_enaddr));
1010a17c678eSDavid Greenman 				}
1011a17c678eSDavid Greenman 
1012a17c678eSDavid Greenman 				/*
1013a17c678eSDavid Greenman 				 * Set new address
1014a17c678eSDavid Greenman 				 */
1015a17c678eSDavid Greenman 				fxp_init(ifp->if_unit);
1016a17c678eSDavid Greenman 				break;
1017a17c678eSDavid Greenman 			}
1018a17c678eSDavid Greenman #endif
1019a17c678eSDavid Greenman 		default:
1020a17c678eSDavid Greenman 			fxp_init(ifp->if_unit);
1021a17c678eSDavid Greenman 			break;
1022a17c678eSDavid Greenman 		}
1023a17c678eSDavid Greenman 		break;
1024a17c678eSDavid Greenman 
1025a17c678eSDavid Greenman 	case SIOCGIFADDR:
1026a17c678eSDavid Greenman 		{
1027a17c678eSDavid Greenman 			struct sockaddr *sa;
1028a17c678eSDavid Greenman 
1029a17c678eSDavid Greenman 			sa = (struct sockaddr *) & ifr->ifr_data;
1030a17c678eSDavid Greenman 			bcopy((caddr_t) sc->arpcom.ac_enaddr,
1031a17c678eSDavid Greenman 			      (caddr_t) sa->sa_data, sizeof(sc->arpcom.ac_enaddr));
1032a17c678eSDavid Greenman 		}
1033a17c678eSDavid Greenman 		break;
1034a17c678eSDavid Greenman 
1035a17c678eSDavid Greenman 	case SIOCSIFFLAGS:
1036a17c678eSDavid Greenman 
1037a17c678eSDavid Greenman 		/*
1038a17c678eSDavid Greenman 		 * If interface is marked up and not running, then start it.
1039a17c678eSDavid Greenman 		 * If it is marked down and running, stop it.
1040a17c678eSDavid Greenman 		 * XXX If it's up then re-initialize it. This is so flags
1041a17c678eSDavid Greenman 		 * such as IFF_PROMISC are handled.
1042a17c678eSDavid Greenman 		 */
1043a17c678eSDavid Greenman 		if (ifp->if_flags & IFF_UP) {
1044a17c678eSDavid Greenman 			fxp_init(ifp->if_unit);
1045a17c678eSDavid Greenman 		} else {
1046a17c678eSDavid Greenman 			if (ifp->if_flags & IFF_RUNNING)
1047a17c678eSDavid Greenman 				fxp_stop(ifp->if_unit);
1048a17c678eSDavid Greenman 		}
1049a17c678eSDavid Greenman 		break;
1050a17c678eSDavid Greenman 
1051a17c678eSDavid Greenman 	case SIOCADDMULTI:
1052a17c678eSDavid Greenman 	case SIOCDELMULTI:
1053a17c678eSDavid Greenman 		/*
1054a17c678eSDavid Greenman 		 * Update out multicast list.
1055a17c678eSDavid Greenman 		 */
1056a17c678eSDavid Greenman 		error = (command == SIOCADDMULTI) ?
1057a17c678eSDavid Greenman 		    ether_addmulti(ifr, &sc->arpcom) :
1058a17c678eSDavid Greenman 		    ether_delmulti(ifr, &sc->arpcom);
1059a17c678eSDavid Greenman 
1060a17c678eSDavid Greenman 		if (error == ENETRESET) {
1061a17c678eSDavid Greenman 			/*
1062a17c678eSDavid Greenman 			 * Multicast list has changed; set the hardware filter
1063a17c678eSDavid Greenman 			 * accordingly.
1064a17c678eSDavid Greenman 			 */
1065a17c678eSDavid Greenman 			fxp_init(ifp->if_unit);
1066a17c678eSDavid Greenman 
1067a17c678eSDavid Greenman 			error = 0;
1068a17c678eSDavid Greenman 		}
1069a17c678eSDavid Greenman 		break;
1070a17c678eSDavid Greenman 
1071a17c678eSDavid Greenman 	case SIOCSIFMTU:
1072a17c678eSDavid Greenman 		/*
1073a17c678eSDavid Greenman 		 * Set the interface MTU.
1074a17c678eSDavid Greenman 		 */
1075a17c678eSDavid Greenman 		if (ifr->ifr_mtu > ETHERMTU) {
1076a17c678eSDavid Greenman 			error = EINVAL;
1077a17c678eSDavid Greenman 		} else {
1078a17c678eSDavid Greenman 			ifp->if_mtu = ifr->ifr_mtu;
1079a17c678eSDavid Greenman 		}
1080a17c678eSDavid Greenman 		break;
1081a17c678eSDavid Greenman 
1082a17c678eSDavid Greenman 	default:
1083a17c678eSDavid Greenman 		error = EINVAL;
1084a17c678eSDavid Greenman 	}
1085a17c678eSDavid Greenman 	(void) splx(s);
1086a17c678eSDavid Greenman 	return (error);
1087a17c678eSDavid Greenman }
1088