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 * 15a17c678eSDavid Greenman * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16a17c678eSDavid Greenman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17a17c678eSDavid Greenman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18a17c678eSDavid Greenman * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19a17c678eSDavid Greenman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20a17c678eSDavid Greenman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21a17c678eSDavid Greenman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22a17c678eSDavid Greenman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23a17c678eSDavid Greenman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24a17c678eSDavid Greenman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25a17c678eSDavid Greenman * SUCH DAMAGE. 26a17c678eSDavid Greenman * 271cd443acSDavid Greenman * $Id: if_fxp.c,v 1.18 1996/09/20 11:05:39 davidg Exp $ 28a17c678eSDavid Greenman */ 29a17c678eSDavid Greenman 30a17c678eSDavid Greenman /* 31ae12cddaSDavid Greenman * Intel EtherExpress Pro/100B PCI Fast Ethernet driver 32a17c678eSDavid Greenman */ 33a17c678eSDavid Greenman 34a17c678eSDavid Greenman #include "bpfilter.h" 35a17c678eSDavid Greenman 36a17c678eSDavid Greenman #include <sys/param.h> 37a17c678eSDavid Greenman #include <sys/systm.h> 38a17c678eSDavid Greenman #include <sys/ioctl.h> 39a17c678eSDavid Greenman #include <sys/mbuf.h> 40a17c678eSDavid Greenman #include <sys/malloc.h> 41a17c678eSDavid Greenman #include <sys/kernel.h> 42a17c678eSDavid Greenman #include <sys/syslog.h> 43a17c678eSDavid Greenman 44a17c678eSDavid Greenman #include <net/if.h> 45a17c678eSDavid Greenman #include <net/if_dl.h> 46a17c678eSDavid Greenman #include <net/if_types.h> 47a17c678eSDavid Greenman 48a17c678eSDavid Greenman #ifdef INET 49a17c678eSDavid Greenman #include <netinet/in.h> 50a17c678eSDavid Greenman #include <netinet/in_systm.h> 51a17c678eSDavid Greenman #include <netinet/in_var.h> 52a17c678eSDavid Greenman #include <netinet/ip.h> 53a17c678eSDavid Greenman #include <netinet/if_ether.h> 54a17c678eSDavid Greenman #endif 55a17c678eSDavid Greenman 56a17c678eSDavid Greenman #ifdef IPX 57a17c678eSDavid Greenman #include <netipx/ipx.h> 58a17c678eSDavid Greenman #include <netipx/ipx_if.h> 59a17c678eSDavid Greenman #endif 60a17c678eSDavid Greenman 61a17c678eSDavid Greenman #ifdef NS 62a17c678eSDavid Greenman #include <netns/ns.h> 63a17c678eSDavid Greenman #include <netns/ns_if.h> 64a17c678eSDavid Greenman #endif 65a17c678eSDavid Greenman 66a17c678eSDavid Greenman #if NBPFILTER > 0 67a17c678eSDavid Greenman #include <net/bpf.h> 68a17c678eSDavid Greenman #include <net/bpfdesc.h> 69a17c678eSDavid Greenman #endif 70a17c678eSDavid Greenman 71dfe61cf1SDavid Greenman #include <vm/vm.h> /* for vtophys */ 72dfe61cf1SDavid Greenman #include <vm/vm_param.h> /* for vtophys */ 73efeaf95aSDavid Greenman #include <vm/pmap.h> /* for vtophys */ 74dfe61cf1SDavid Greenman #include <machine/clock.h> /* for DELAY */ 75a17c678eSDavid Greenman 76a17c678eSDavid Greenman #include <pci/pcivar.h> 77a17c678eSDavid Greenman #include <pci/if_fxpreg.h> 78a17c678eSDavid Greenman 79a17c678eSDavid Greenman struct fxp_softc { 80dfe61cf1SDavid Greenman struct arpcom arpcom; /* per-interface network data */ 81dfe61cf1SDavid Greenman struct fxp_csr *csr; /* control/status registers */ 82a17c678eSDavid Greenman struct fxp_cb_tx *cbl_base; /* base of TxCB list */ 83a17c678eSDavid Greenman struct fxp_cb_tx *cbl_first; /* first active TxCB in list */ 84a17c678eSDavid Greenman struct fxp_cb_tx *cbl_last; /* last active TxCB in list */ 85a17c678eSDavid Greenman struct mbuf *rfa_headm; /* first mbuf in receive frame area */ 86a17c678eSDavid Greenman struct mbuf *rfa_tailm; /* last mbuf in receive frame area */ 87a17c678eSDavid Greenman struct fxp_stats *fxp_stats; /* Pointer to interface stats */ 88a17c678eSDavid Greenman int tx_queued; /* # of active TxCB's */ 89a17c678eSDavid Greenman int promisc_mode; /* promiscuous mode enabled */ 90a17c678eSDavid Greenman }; 91a17c678eSDavid Greenman 92a17c678eSDavid Greenman static u_long fxp_count; 93a17c678eSDavid Greenman 94a17c678eSDavid Greenman /* 95a17c678eSDavid Greenman * Template for default configuration parameters. 96a17c678eSDavid Greenman * See struct fxp_cb_config for the bit definitions. 97a17c678eSDavid Greenman */ 98a17c678eSDavid Greenman static u_char fxp_cb_config_template[] = { 99a17c678eSDavid Greenman 0x0, 0x0, /* cb_status */ 100a17c678eSDavid Greenman 0x80, 0x2, /* cb_command */ 101a17c678eSDavid Greenman 0xff, 0xff, 0xff, 0xff, /* link_addr */ 102a17c678eSDavid Greenman 0x16, /* 0 */ 103a17c678eSDavid Greenman 0x8, /* 1 */ 104a17c678eSDavid Greenman 0x0, /* 2 */ 105a17c678eSDavid Greenman 0x0, /* 3 */ 106a17c678eSDavid Greenman 0x0, /* 4 */ 107a17c678eSDavid Greenman 0x80, /* 5 */ 108a17c678eSDavid Greenman 0xb2, /* 6 */ 109a17c678eSDavid Greenman 0x3, /* 7 */ 110a17c678eSDavid Greenman 0x1, /* 8 */ 111a17c678eSDavid Greenman 0x0, /* 9 */ 112a17c678eSDavid Greenman 0x26, /* 10 */ 113a17c678eSDavid Greenman 0x0, /* 11 */ 114a17c678eSDavid Greenman 0x60, /* 12 */ 115a17c678eSDavid Greenman 0x0, /* 13 */ 116a17c678eSDavid Greenman 0xf2, /* 14 */ 117a17c678eSDavid Greenman 0x48, /* 15 */ 118a17c678eSDavid Greenman 0x0, /* 16 */ 119a17c678eSDavid Greenman 0x40, /* 17 */ 120a17c678eSDavid Greenman 0xf3, /* 18 */ 121a17c678eSDavid Greenman 0x0, /* 19 */ 122a17c678eSDavid Greenman 0x3f, /* 20 */ 123a17c678eSDavid Greenman 0x5, /* 21 */ 124a17c678eSDavid Greenman 0x0, 0x0 125a17c678eSDavid Greenman }; 126a17c678eSDavid Greenman 1271cd443acSDavid Greenman static inline void fxp_scb_wait __P((struct fxp_csr *)); 128a17c678eSDavid Greenman static char *fxp_probe __P((pcici_t, pcidi_t)); 129a17c678eSDavid Greenman static void fxp_attach __P((pcici_t, int)); 130dd7610fcSStefan Eßer static void fxp_intr __P((void *)); 131a17c678eSDavid Greenman static void fxp_start __P((struct ifnet *)); 132a17c678eSDavid Greenman static int fxp_ioctl __P((struct ifnet *, int, caddr_t)); 1334a5f1499SDavid Greenman static void fxp_init __P((struct ifnet *)); 1344a5f1499SDavid Greenman static void fxp_stop __P((struct fxp_softc *)); 1354a5f1499SDavid Greenman static void fxp_watchdog __P((struct ifnet *)); 136a17c678eSDavid Greenman static void fxp_get_macaddr __P((struct fxp_softc *)); 137a17c678eSDavid Greenman static int fxp_add_rfabuf __P((struct fxp_softc *, struct mbuf *)); 1384a684684SDavid Greenman static void fxp_shutdown __P((int, void *)); 139a17c678eSDavid Greenman 140a17c678eSDavid Greenman timeout_t fxp_stats_update; 141a17c678eSDavid Greenman 142a17c678eSDavid Greenman static struct pci_device fxp_device = { 143a17c678eSDavid Greenman "fxp", 144a17c678eSDavid Greenman fxp_probe, 145a17c678eSDavid Greenman fxp_attach, 146a17c678eSDavid Greenman &fxp_count, 1474a684684SDavid Greenman NULL 148a17c678eSDavid Greenman }; 149a17c678eSDavid Greenman DATA_SET(pcidevice_set, fxp_device); 150a17c678eSDavid Greenman 151a17c678eSDavid Greenman /* 152f9be9005SDavid Greenman * Set initial transmit threshold at 64 (512 bytes). This is 153f9be9005SDavid Greenman * increased by 64 (512 bytes) at a time, to maximum of 192 154f9be9005SDavid Greenman * (1536 bytes), if an underrun occurs. 155f9be9005SDavid Greenman */ 156f9be9005SDavid Greenman static int tx_threshold = 64; 157f9be9005SDavid Greenman 158f9be9005SDavid Greenman /* 159a17c678eSDavid Greenman * Number of transmit control blocks. This determines the number 160a17c678eSDavid Greenman * of transmit buffers that can be chained in the CB list. 161a17c678eSDavid Greenman * This must be a power of two. 162a17c678eSDavid Greenman */ 1631cd443acSDavid Greenman #define FXP_NTXCB 128 164a17c678eSDavid Greenman 165a17c678eSDavid Greenman /* 166a17c678eSDavid Greenman * TxCB list index mask. This is used to do list wrap-around. 167a17c678eSDavid Greenman */ 168a17c678eSDavid Greenman #define FXP_TXCB_MASK (FXP_NTXCB - 1) 169a17c678eSDavid Greenman 170a17c678eSDavid Greenman /* 171a17c678eSDavid Greenman * Number of DMA segments in a TxCB. Note that this is carefully 17223a0ed7cSDavid Greenman * chosen to make the total struct size an even power of two. It's 17323a0ed7cSDavid Greenman * critical that no TxCB be split across a page boundry since 17423a0ed7cSDavid Greenman * no attempt is made to allocate physically contiguous memory. 17523a0ed7cSDavid Greenman * 17623a0ed7cSDavid Greenman * XXX - don't forget to change the hard-coded constant in the 17723a0ed7cSDavid Greenman * fxp_cb_tx struct (defined in if_fxpreg.h), too! 178a17c678eSDavid Greenman */ 17923a0ed7cSDavid Greenman #define FXP_NTXSEG 29 180a17c678eSDavid Greenman 181a17c678eSDavid Greenman /* 182a17c678eSDavid Greenman * Number of receive frame area buffers. These are large so chose 183a17c678eSDavid Greenman * wisely. 184a17c678eSDavid Greenman */ 185a17c678eSDavid Greenman #define FXP_NRFABUFS 32 186a17c678eSDavid Greenman 187dfe61cf1SDavid Greenman /* 188dfe61cf1SDavid Greenman * Wait for the previous command to be accepted (but not necessarily 189dfe61cf1SDavid Greenman * completed). 190dfe61cf1SDavid Greenman */ 1911cd443acSDavid Greenman static inline void 192a17c678eSDavid Greenman fxp_scb_wait(csr) 193a17c678eSDavid Greenman struct fxp_csr *csr; 194a17c678eSDavid Greenman { 195a17c678eSDavid Greenman int i = 10000; 196a17c678eSDavid Greenman 197a17c678eSDavid Greenman while ((csr->scb_command & FXP_SCB_COMMAND_MASK) && --i); 198a17c678eSDavid Greenman } 199a17c678eSDavid Greenman 200dfe61cf1SDavid Greenman /* 201dfe61cf1SDavid Greenman * Return identification string if this is device is ours. 202dfe61cf1SDavid Greenman */ 203a17c678eSDavid Greenman static char * 204a17c678eSDavid Greenman fxp_probe(config_id, device_id) 205a17c678eSDavid Greenman pcici_t config_id; 206a17c678eSDavid Greenman pcidi_t device_id; 207a17c678eSDavid Greenman { 208a17c678eSDavid Greenman if (((device_id & 0xffff) == FXP_VENDORID_INTEL) && 209a17c678eSDavid Greenman ((device_id >> 16) & 0xffff) == FXP_DEVICEID_i82557) 210ae12cddaSDavid Greenman return ("Intel EtherExpress Pro/100B Fast Ethernet"); 211a17c678eSDavid Greenman 212a17c678eSDavid Greenman return NULL; 213a17c678eSDavid Greenman } 214a17c678eSDavid Greenman 215a17c678eSDavid Greenman /* 216a17c678eSDavid Greenman * Allocate data structures and attach the device. 217a17c678eSDavid Greenman */ 218a17c678eSDavid Greenman static void 219a17c678eSDavid Greenman fxp_attach(config_id, unit) 220a17c678eSDavid Greenman pcici_t config_id; 221a17c678eSDavid Greenman int unit; 222a17c678eSDavid Greenman { 223a17c678eSDavid Greenman struct fxp_softc *sc; 224a17c678eSDavid Greenman struct ifnet *ifp; 225a17c678eSDavid Greenman vm_offset_t pbase; 226a17c678eSDavid Greenman int s, i; 227a17c678eSDavid Greenman 228a17c678eSDavid Greenman sc = malloc(sizeof(struct fxp_softc), M_DEVBUF, M_NOWAIT); 229a17c678eSDavid Greenman if (sc == NULL) 230a17c678eSDavid Greenman return; 231a17c678eSDavid Greenman bzero(sc, sizeof(struct fxp_softc)); 232a17c678eSDavid Greenman 233a17c678eSDavid Greenman s = splimp(); 234a17c678eSDavid Greenman 235dfe61cf1SDavid Greenman /* 236dfe61cf1SDavid Greenman * Map control/status registers. 237dfe61cf1SDavid Greenman */ 238a17c678eSDavid Greenman if (!pci_map_mem(config_id, FXP_PCI_MMBA, 239a17c678eSDavid Greenman (vm_offset_t *)&sc->csr, &pbase)) { 240a17c678eSDavid Greenman printf("fxp%d: couldn't map memory\n", unit); 241a17c678eSDavid Greenman goto fail; 242a17c678eSDavid Greenman } 243a17c678eSDavid Greenman 244a17c678eSDavid Greenman /* 245dfe61cf1SDavid Greenman * Issue a software reset. 246a17c678eSDavid Greenman */ 247a17c678eSDavid Greenman sc->csr->port = 0; 248a17c678eSDavid Greenman DELAY(10); 249a17c678eSDavid Greenman 250dfe61cf1SDavid Greenman /* 251dfe61cf1SDavid Greenman * Allocate our interrupt. 252dfe61cf1SDavid Greenman */ 253a17c678eSDavid Greenman if (!pci_map_int(config_id, fxp_intr, sc, &net_imask)) { 254a17c678eSDavid Greenman printf("fxp%d: couldn't map interrupt\n", unit); 255a17c678eSDavid Greenman goto fail; 256a17c678eSDavid Greenman } 257a17c678eSDavid Greenman 258a17c678eSDavid Greenman sc->cbl_base = malloc(sizeof(struct fxp_cb_tx) * FXP_NTXCB, 259a17c678eSDavid Greenman M_DEVBUF, M_NOWAIT); 260a17c678eSDavid Greenman if (sc->cbl_base == NULL) 261a17c678eSDavid Greenman goto malloc_fail; 262a17c678eSDavid Greenman 263a17c678eSDavid Greenman sc->fxp_stats = malloc(sizeof(struct fxp_stats), M_DEVBUF, M_NOWAIT); 264a17c678eSDavid Greenman if (sc->fxp_stats == NULL) 265a17c678eSDavid Greenman goto malloc_fail; 266a17c678eSDavid Greenman bzero(sc->fxp_stats, sizeof(struct fxp_stats)); 267a17c678eSDavid Greenman 268dfe61cf1SDavid Greenman /* 269dfe61cf1SDavid Greenman * Pre-allocate our receive buffers. 270dfe61cf1SDavid Greenman */ 271a17c678eSDavid Greenman for (i = 0; i < FXP_NRFABUFS; i++) { 272a17c678eSDavid Greenman if (fxp_add_rfabuf(sc, NULL) != 0) { 273a17c678eSDavid Greenman goto malloc_fail; 274a17c678eSDavid Greenman } 275a17c678eSDavid Greenman } 276a17c678eSDavid Greenman 277a17c678eSDavid Greenman ifp = &sc->arpcom.ac_if; 2789b44ff22SGarrett Wollman ifp->if_softc = sc; 279a17c678eSDavid Greenman ifp->if_unit = unit; 280a17c678eSDavid Greenman ifp->if_name = "fxp"; 281a17c678eSDavid Greenman ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 282a17c678eSDavid Greenman ifp->if_ioctl = fxp_ioctl; 283a17c678eSDavid Greenman ifp->if_output = ether_output; 284a17c678eSDavid Greenman ifp->if_start = fxp_start; 285a17c678eSDavid Greenman ifp->if_watchdog = fxp_watchdog; 286a330e1f1SGary Palmer ifp->if_baudrate = 100000000; 287a17c678eSDavid Greenman 288a17c678eSDavid Greenman fxp_get_macaddr(sc); 28918b7be40SPoul-Henning Kamp printf("fxp%d: Ethernet address %6D\n", unit, 29018b7be40SPoul-Henning Kamp sc->arpcom.ac_enaddr, ":"); 291a17c678eSDavid Greenman 292dfe61cf1SDavid Greenman /* 293dfe61cf1SDavid Greenman * Attach the interface. 294dfe61cf1SDavid Greenman */ 295a17c678eSDavid Greenman if_attach(ifp); 2969b44ff22SGarrett Wollman ether_ifattach(ifp); 2979b44ff22SGarrett Wollman 298a17c678eSDavid Greenman #if NBPFILTER > 0 2999b44ff22SGarrett Wollman bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header)); 300a17c678eSDavid Greenman #endif 3014a684684SDavid Greenman 3024a684684SDavid Greenman /* 3034a684684SDavid Greenman * Add shutdown hook so that DMA is disabled prior to reboot. Not 3044a684684SDavid Greenman * doing do could allow DMA to corrupt kernel memory during the 3054a684684SDavid Greenman * reboot before the driver initializes. 3064a684684SDavid Greenman */ 3074a684684SDavid Greenman at_shutdown(fxp_shutdown, sc, SHUTDOWN_POST_SYNC); 3084a684684SDavid Greenman 309a17c678eSDavid Greenman splx(s); 310a17c678eSDavid Greenman return; 311a17c678eSDavid Greenman 312a17c678eSDavid Greenman malloc_fail: 313a17c678eSDavid Greenman printf("fxp%d: Failed to malloc memory\n", unit); 314a17c678eSDavid Greenman (void) pci_unmap_int(config_id); 315a17c678eSDavid Greenman if (sc && sc->cbl_base) 316a17c678eSDavid Greenman free(sc->cbl_base, M_DEVBUF); 317a17c678eSDavid Greenman if (sc && sc->fxp_stats) 318a17c678eSDavid Greenman free(sc->fxp_stats, M_DEVBUF); 319a17c678eSDavid Greenman /* frees entire chain */ 320a17c678eSDavid Greenman if (sc && sc->rfa_headm) 321a17c678eSDavid Greenman m_freem(sc->rfa_headm); 322a17c678eSDavid Greenman fail: 323a17c678eSDavid Greenman if (sc) 324a17c678eSDavid Greenman free(sc, M_DEVBUF); 325a17c678eSDavid Greenman splx(s); 326a17c678eSDavid Greenman } 327a17c678eSDavid Greenman 328a17c678eSDavid Greenman /* 329a17c678eSDavid Greenman * Read station (MAC) address from serial EEPROM. Basically, you 330a17c678eSDavid Greenman * manually shift in the read opcode (one bit at a time) and then 331a17c678eSDavid Greenman * shift in the address, and then you shift out the data (all of 332a17c678eSDavid Greenman * this one bit at a time). The word size is 16 bits, so you have 333a17c678eSDavid Greenman * to provide the address for every 16 bits of data. The MAC address 334a17c678eSDavid Greenman * is in the first 3 words (6 bytes total). 335a17c678eSDavid Greenman */ 336a17c678eSDavid Greenman static void 337a17c678eSDavid Greenman fxp_get_macaddr(sc) 338a17c678eSDavid Greenman struct fxp_softc *sc; 339a17c678eSDavid Greenman { 340a17c678eSDavid Greenman struct fxp_csr *csr; 341a17c678eSDavid Greenman u_short reg, *data; 342a17c678eSDavid Greenman int i, x; 343a17c678eSDavid Greenman 344a17c678eSDavid Greenman csr = sc->csr; 345a17c678eSDavid Greenman data = (u_short *)sc->arpcom.ac_enaddr; 346a17c678eSDavid Greenman 347a17c678eSDavid Greenman for (i = 0; i < 3; i++) { 348a17c678eSDavid Greenman csr->eeprom_control = FXP_EEPROM_EECS; 349a17c678eSDavid Greenman /* 350a17c678eSDavid Greenman * Shift in read opcode. 351a17c678eSDavid Greenman */ 352a17c678eSDavid Greenman for (x = 3; x > 0; x--) { 353a17c678eSDavid Greenman if (FXP_EEPROM_OPC_READ & (1 << (x - 1))) { 354a17c678eSDavid Greenman reg = FXP_EEPROM_EECS | FXP_EEPROM_EEDI; 355a17c678eSDavid Greenman } else { 356a17c678eSDavid Greenman reg = FXP_EEPROM_EECS; 357a17c678eSDavid Greenman } 358a17c678eSDavid Greenman csr->eeprom_control = reg; 359a17c678eSDavid Greenman csr->eeprom_control = reg | FXP_EEPROM_EESK; 360a17c678eSDavid Greenman DELAY(1); 361a17c678eSDavid Greenman csr->eeprom_control = reg; 362a17c678eSDavid Greenman DELAY(1); 363a17c678eSDavid Greenman } 364a17c678eSDavid Greenman /* 365a17c678eSDavid Greenman * Shift in address. 366a17c678eSDavid Greenman */ 367a17c678eSDavid Greenman for (x = 6; x > 0; x--) { 368a17c678eSDavid Greenman if (i & (1 << (x - 1))) { 369a17c678eSDavid Greenman reg = FXP_EEPROM_EECS | FXP_EEPROM_EEDI; 370a17c678eSDavid Greenman } else { 371a17c678eSDavid Greenman reg = FXP_EEPROM_EECS; 372a17c678eSDavid Greenman } 373a17c678eSDavid Greenman csr->eeprom_control = reg; 374a17c678eSDavid Greenman csr->eeprom_control = reg | FXP_EEPROM_EESK; 375a17c678eSDavid Greenman DELAY(1); 376a17c678eSDavid Greenman csr->eeprom_control = reg; 377a17c678eSDavid Greenman DELAY(1); 378a17c678eSDavid Greenman } 379a17c678eSDavid Greenman reg = FXP_EEPROM_EECS; 380a17c678eSDavid Greenman data[i] = 0; 381a17c678eSDavid Greenman /* 382a17c678eSDavid Greenman * Shift out data. 383a17c678eSDavid Greenman */ 384a17c678eSDavid Greenman for (x = 16; x > 0; x--) { 385a17c678eSDavid Greenman csr->eeprom_control = reg | FXP_EEPROM_EESK; 386a17c678eSDavid Greenman DELAY(1); 387a17c678eSDavid Greenman if (csr->eeprom_control & FXP_EEPROM_EEDO) 388a17c678eSDavid Greenman data[i] |= (1 << (x - 1)); 389a17c678eSDavid Greenman csr->eeprom_control = reg; 390a17c678eSDavid Greenman DELAY(1); 391a17c678eSDavid Greenman } 392a17c678eSDavid Greenman csr->eeprom_control = 0; 393a17c678eSDavid Greenman DELAY(1); 394a17c678eSDavid Greenman } 395a17c678eSDavid Greenman } 396a17c678eSDavid Greenman 397a17c678eSDavid Greenman /* 3984a684684SDavid Greenman * Device shutdown routine. Called at system shutdown after sync. The 399a17c678eSDavid Greenman * main purpose of this routine is to shut off receiver DMA so that 400a17c678eSDavid Greenman * kernel memory doesn't get clobbered during warmboot. 401a17c678eSDavid Greenman */ 4024a684684SDavid Greenman static void 4034a684684SDavid Greenman fxp_shutdown(howto, sc) 4044a684684SDavid Greenman int howto; 4054a684684SDavid Greenman void *sc; 406a17c678eSDavid Greenman { 4074a684684SDavid Greenman fxp_stop((struct fxp_softc *) sc); 408a17c678eSDavid Greenman } 409a17c678eSDavid Greenman 410a17c678eSDavid Greenman /* 411a17c678eSDavid Greenman * Start packet transmission on the interface. 412a17c678eSDavid Greenman */ 413a17c678eSDavid Greenman static void 414a17c678eSDavid Greenman fxp_start(ifp) 415a17c678eSDavid Greenman struct ifnet *ifp; 416a17c678eSDavid Greenman { 4179b44ff22SGarrett Wollman struct fxp_softc *sc = ifp->if_softc; 418a17c678eSDavid Greenman struct fxp_csr *csr = sc->csr; 419a17c678eSDavid Greenman struct fxp_cb_tx *txp; 420a17c678eSDavid Greenman struct mbuf *m, *mb_head; 421a17c678eSDavid Greenman int segment; 422a17c678eSDavid Greenman 423a17c678eSDavid Greenman txloop: 424a17c678eSDavid Greenman /* 4251cd443acSDavid Greenman * See if we're all filled up with buffers to transmit. 426a17c678eSDavid Greenman */ 4271cd443acSDavid Greenman if (sc->tx_queued >= FXP_NTXCB) 428a17c678eSDavid Greenman return; 4291cd443acSDavid Greenman 430dfe61cf1SDavid Greenman /* 431dfe61cf1SDavid Greenman * Grab a packet to transmit. 432dfe61cf1SDavid Greenman */ 433a17c678eSDavid Greenman IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, mb_head); 434a17c678eSDavid Greenman if (mb_head == NULL) { 435a17c678eSDavid Greenman /* 436a17c678eSDavid Greenman * No more packets to send. 437a17c678eSDavid Greenman */ 438a17c678eSDavid Greenman return; 439a17c678eSDavid Greenman } 440a17c678eSDavid Greenman 441dfe61cf1SDavid Greenman /* 442dfe61cf1SDavid Greenman * Get pointer to next available (unused) descriptor. 443dfe61cf1SDavid Greenman */ 444a17c678eSDavid Greenman txp = sc->cbl_last->next; 445a17c678eSDavid Greenman 446a17c678eSDavid Greenman /* 447a17c678eSDavid Greenman * Go through each of the mbufs in the chain and initialize 448a17c678eSDavid Greenman * the transmit buffers descriptors with the physical address 449a17c678eSDavid Greenman * and size of the mbuf. 450a17c678eSDavid Greenman */ 45123a0ed7cSDavid Greenman tbdinit: 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) { 46323a0ed7cSDavid Greenman struct mbuf *mn; 46423a0ed7cSDavid Greenman 465a17c678eSDavid Greenman /* 466a17c678eSDavid Greenman * We ran out of segments. We have to recopy this mbuf 467a17c678eSDavid Greenman * chain first. 468a17c678eSDavid Greenman */ 46923a0ed7cSDavid Greenman MGETHDR(mn, M_DONTWAIT, MT_DATA); 47023a0ed7cSDavid Greenman if (mn == NULL) { 47123a0ed7cSDavid Greenman m_freem(mb_head); 47223a0ed7cSDavid Greenman return; 473a17c678eSDavid Greenman } 47423a0ed7cSDavid Greenman if (mb_head->m_pkthdr.len > MHLEN) { 47523a0ed7cSDavid Greenman MCLGET(mn, M_DONTWAIT); 47623a0ed7cSDavid Greenman if ((mn->m_flags & M_EXT) == 0) { 47723a0ed7cSDavid Greenman m_freem(mn); 47823a0ed7cSDavid Greenman m_freem(mb_head); 47923a0ed7cSDavid Greenman return; 48023a0ed7cSDavid Greenman } 48123a0ed7cSDavid Greenman } 48223a0ed7cSDavid Greenman m_copydata(mb_head, 0, mb_head->m_pkthdr.len, mtod(mn, caddr_t)); 48323a0ed7cSDavid Greenman mn->m_pkthdr.len = mn->m_len = mb_head->m_pkthdr.len; 48423a0ed7cSDavid Greenman m_freem(mb_head); 48523a0ed7cSDavid Greenman mb_head = mn; 48623a0ed7cSDavid Greenman goto tbdinit; 48723a0ed7cSDavid Greenman } 48823a0ed7cSDavid Greenman 48923a0ed7cSDavid Greenman txp->tbd_number = segment; 4901cd443acSDavid Greenman txp->mb_head = mb_head; 49123a0ed7cSDavid Greenman 492a17c678eSDavid Greenman /* 493a17c678eSDavid Greenman * Finish the initialization of this TxCB. 494a17c678eSDavid Greenman */ 495a17c678eSDavid Greenman txp->cb_status = 0; 496a17c678eSDavid Greenman txp->cb_command = 497a17c678eSDavid Greenman FXP_CB_COMMAND_XMIT | FXP_CB_COMMAND_SF | FXP_CB_COMMAND_S; 498f9be9005SDavid Greenman txp->tx_threshold = tx_threshold; 499a17c678eSDavid Greenman 500a17c678eSDavid Greenman /* 501a17c678eSDavid Greenman * Advance the end-of-list forward. 502a17c678eSDavid Greenman */ 503a17c678eSDavid Greenman sc->cbl_last->cb_command &= ~FXP_CB_COMMAND_S; 504a17c678eSDavid Greenman sc->cbl_last = txp; 505a17c678eSDavid Greenman 506a17c678eSDavid Greenman /* 5071cd443acSDavid Greenman * Advance the beginning of the list forward if there are 5081cd443acSDavid Greenman * no other packets queued (when nothing is queued, cbl_first 5091cd443acSDavid Greenman * sits on the last TxCB that was sent out).. 510a17c678eSDavid Greenman */ 5111cd443acSDavid Greenman if (sc->tx_queued == 0) 512a17c678eSDavid Greenman sc->cbl_first = txp; 513a17c678eSDavid Greenman 5141cd443acSDavid Greenman sc->tx_queued++; 5151cd443acSDavid Greenman 5161cd443acSDavid Greenman if (csr->scb_cus == FXP_SCB_CUS_SUSPENDED) { 5171cd443acSDavid Greenman fxp_scb_wait(csr); 5183ba65732SDavid Greenman 519a17c678eSDavid Greenman /* 5201cd443acSDavid Greenman * Resume transmission. 521a17c678eSDavid Greenman */ 522a17c678eSDavid Greenman csr->scb_command = FXP_SCB_COMMAND_CU_RESUME; 5231cd443acSDavid Greenman } 524a17c678eSDavid Greenman 525a17c678eSDavid Greenman #if NBPFILTER > 0 526a17c678eSDavid Greenman /* 527a17c678eSDavid Greenman * Pass packet to bpf if there is a listener. 528a17c678eSDavid Greenman */ 5299b44ff22SGarrett Wollman if (ifp->if_bpf != NULL) 5309b44ff22SGarrett Wollman bpf_mtap(ifp, mb_head); 531a17c678eSDavid Greenman #endif 532a17c678eSDavid Greenman /* 533a17c678eSDavid Greenman * Set a 5 second timer just in case we don't hear from the 534a17c678eSDavid Greenman * card again. 535a17c678eSDavid Greenman */ 536a17c678eSDavid Greenman ifp->if_timer = 5; 537a17c678eSDavid Greenman 538a17c678eSDavid Greenman goto txloop; 539a17c678eSDavid Greenman } 540a17c678eSDavid Greenman 541a17c678eSDavid Greenman /* 542a17c678eSDavid Greenman * Process interface interrupts. Returns 1 if the interrupt 543a17c678eSDavid Greenman * was handled, 0 if it wasn't. 544a17c678eSDavid Greenman */ 545dd7610fcSStefan Eßer static void 546a17c678eSDavid Greenman fxp_intr(arg) 547a17c678eSDavid Greenman void *arg; 548a17c678eSDavid Greenman { 549a17c678eSDavid Greenman struct fxp_softc *sc = arg; 550a17c678eSDavid Greenman struct fxp_csr *csr = sc->csr; 551a17c678eSDavid Greenman struct ifnet *ifp = &sc->arpcom.ac_if; 5521cd443acSDavid Greenman u_int8_t statack; 553a17c678eSDavid Greenman 554a17c678eSDavid Greenman while ((statack = csr->scb_statack) != 0) { 555a17c678eSDavid Greenman /* 556a17c678eSDavid Greenman * First ACK all the interrupts in this pass. 557a17c678eSDavid Greenman */ 558a17c678eSDavid Greenman csr->scb_statack = statack; 559a17c678eSDavid Greenman 560a17c678eSDavid Greenman /* 561a17c678eSDavid Greenman * Free any finished transmit mbuf chains. 562a17c678eSDavid Greenman */ 563a17c678eSDavid Greenman if (statack & FXP_SCB_STATACK_CNA) { 564a17c678eSDavid Greenman struct fxp_cb_tx *txp; 565a17c678eSDavid Greenman 566a17c678eSDavid Greenman for (txp = sc->cbl_first; 5671cd443acSDavid Greenman (txp->cb_status & FXP_CB_STATUS_C) != 0; 568a17c678eSDavid Greenman txp = txp->next) { 5691cd443acSDavid Greenman if (txp->mb_head != NULL) { 570a17c678eSDavid Greenman m_freem(txp->mb_head); 571a17c678eSDavid Greenman txp->mb_head = NULL; 572a17c678eSDavid Greenman sc->tx_queued--; 573a17c678eSDavid Greenman } 5741cd443acSDavid Greenman if (txp->cb_command & FXP_CB_COMMAND_S) 5751cd443acSDavid Greenman break; 5761cd443acSDavid Greenman } 577a17c678eSDavid Greenman sc->cbl_first = txp; 578a17c678eSDavid Greenman /* 579a17c678eSDavid Greenman * Clear watchdog timer. It may or may not be set 580a17c678eSDavid Greenman * again in fxp_start(). 581a17c678eSDavid Greenman */ 582a17c678eSDavid Greenman ifp->if_timer = 0; 583a17c678eSDavid Greenman fxp_start(ifp); 584a17c678eSDavid Greenman } 585a17c678eSDavid Greenman /* 586a17c678eSDavid Greenman * Process receiver interrupts. If a no-resource (RNR) 587a17c678eSDavid Greenman * condition exists, get whatever packets we can and 588a17c678eSDavid Greenman * re-start the receiver. 589a17c678eSDavid Greenman */ 590a17c678eSDavid Greenman if (statack & (FXP_SCB_STATACK_FR | FXP_SCB_STATACK_RNR)) { 591a17c678eSDavid Greenman struct mbuf *m; 592a17c678eSDavid Greenman struct fxp_rfa *rfa; 593a17c678eSDavid Greenman rcvloop: 594a17c678eSDavid Greenman m = sc->rfa_headm; 595dfe61cf1SDavid Greenman rfa = (struct fxp_rfa *)m->m_ext.ext_buf; 596a17c678eSDavid Greenman 597a17c678eSDavid Greenman if (rfa->rfa_status & FXP_RFA_STATUS_C) { 598dfe61cf1SDavid Greenman /* 599dfe61cf1SDavid Greenman * Remove first packet from the chain. 600dfe61cf1SDavid Greenman */ 601a17c678eSDavid Greenman sc->rfa_headm = m->m_next; 602a17c678eSDavid Greenman m->m_next = NULL; 603a17c678eSDavid Greenman 604dfe61cf1SDavid Greenman /* 605dfe61cf1SDavid Greenman * Add a new buffer to the receive chain. If this 606dfe61cf1SDavid Greenman * fails, the old buffer is recycled instead. 607dfe61cf1SDavid Greenman */ 608a17c678eSDavid Greenman if (fxp_add_rfabuf(sc, m) == 0) { 609a17c678eSDavid Greenman struct ether_header *eh; 610a17c678eSDavid Greenman u_short total_len; 611a17c678eSDavid Greenman 612a17c678eSDavid Greenman total_len = rfa->actual_size & (MCLBYTES - 1); 613a17c678eSDavid Greenman m->m_pkthdr.rcvif = ifp; 614a17c678eSDavid Greenman m->m_pkthdr.len = m->m_len = total_len - 615a17c678eSDavid Greenman sizeof(struct ether_header); 616a17c678eSDavid Greenman eh = mtod(m, struct ether_header *); 617a17c678eSDavid Greenman #if NBPFILTER > 0 6189b44ff22SGarrett Wollman if (ifp->if_bpf != NULL) { 6199b44ff22SGarrett Wollman bpf_tap(ifp, mtod(m, caddr_t), total_len); 620a17c678eSDavid Greenman /* 621a17c678eSDavid Greenman * Only pass this packet up if it is for us. 622a17c678eSDavid Greenman */ 623a17c678eSDavid Greenman if ((ifp->if_flags & IFF_PROMISC) && 624a17c678eSDavid Greenman (rfa->rfa_status & FXP_RFA_STATUS_IAMATCH) && 625a17c678eSDavid Greenman (eh->ether_dhost[0] & 1) == 0) { 626a17c678eSDavid Greenman m_freem(m); 627a17c678eSDavid Greenman goto rcvloop; 628a17c678eSDavid Greenman } 629a17c678eSDavid Greenman } 630a17c678eSDavid Greenman #endif 631a17c678eSDavid Greenman m->m_data += sizeof(struct ether_header); 632a17c678eSDavid Greenman ether_input(ifp, eh, m); 633a17c678eSDavid Greenman } 634a17c678eSDavid Greenman goto rcvloop; 635a17c678eSDavid Greenman } 636a17c678eSDavid Greenman if (statack & FXP_SCB_STATACK_RNR) { 637a17c678eSDavid Greenman struct fxp_csr *csr = sc->csr; 638a17c678eSDavid Greenman 6391cd443acSDavid Greenman fxp_scb_wait(csr); 640dfe61cf1SDavid Greenman csr->scb_general = vtophys(sc->rfa_headm->m_ext.ext_buf); 641a17c678eSDavid Greenman csr->scb_command = FXP_SCB_COMMAND_RU_START; 642a17c678eSDavid Greenman } 643a17c678eSDavid Greenman } 644a17c678eSDavid Greenman } 645a17c678eSDavid Greenman } 646a17c678eSDavid Greenman 647dfe61cf1SDavid Greenman /* 648dfe61cf1SDavid Greenman * Update packet in/out/collision statistics. The i82557 doesn't 649dfe61cf1SDavid Greenman * allow you to access these counters without doing a fairly 650dfe61cf1SDavid Greenman * expensive DMA to get _all_ of the statistics it maintains, so 651dfe61cf1SDavid Greenman * we do this operation here only once per second. The statistics 652dfe61cf1SDavid Greenman * counters in the kernel are updated from the previous dump-stats 653dfe61cf1SDavid Greenman * DMA and then a new dump-stats DMA is started. The on-chip 654dfe61cf1SDavid Greenman * counters are zeroed when the DMA completes. If we can't start 655dfe61cf1SDavid Greenman * the DMA immediately, we don't wait - we just prepare to read 656dfe61cf1SDavid Greenman * them again next time. 657dfe61cf1SDavid Greenman */ 658a17c678eSDavid Greenman void 659a17c678eSDavid Greenman fxp_stats_update(arg) 660a17c678eSDavid Greenman void *arg; 661a17c678eSDavid Greenman { 662a17c678eSDavid Greenman struct fxp_softc *sc = arg; 663a17c678eSDavid Greenman struct ifnet *ifp = &sc->arpcom.ac_if; 664a17c678eSDavid Greenman struct fxp_stats *sp = sc->fxp_stats; 665a17c678eSDavid Greenman 666a17c678eSDavid Greenman ifp->if_opackets += sp->tx_good; 667a17c678eSDavid Greenman ifp->if_collisions += sp->tx_total_collisions; 668a17c678eSDavid Greenman ifp->if_ipackets += sp->rx_good; 6693ba65732SDavid Greenman ifp->if_ierrors += 6703ba65732SDavid Greenman sp->rx_crc_errors + 6713ba65732SDavid Greenman sp->rx_alignment_errors + 6723ba65732SDavid Greenman sp->rx_rnr_errors + 6733ba65732SDavid Greenman sp->rx_overrun_errors + 6743ba65732SDavid Greenman sp->rx_shortframes; 675a17c678eSDavid Greenman /* 676f9be9005SDavid Greenman * If any transmit underruns occured, bump up the transmit 677f9be9005SDavid Greenman * threshold by another 512 bytes (64 * 8). 678f9be9005SDavid Greenman */ 679f9be9005SDavid Greenman if (sp->tx_underruns) { 680f9be9005SDavid Greenman ifp->if_oerrors += sp->tx_underruns; 681f9be9005SDavid Greenman if (tx_threshold < 192) 682f9be9005SDavid Greenman tx_threshold += 64; 683f9be9005SDavid Greenman } 684f9be9005SDavid Greenman /* 6853ba65732SDavid Greenman * If there is no pending command, start another stats 6863ba65732SDavid Greenman * dump. Otherwise punt for now. 687a17c678eSDavid Greenman */ 688dfe61cf1SDavid Greenman if ((sc->csr->scb_command & FXP_SCB_COMMAND_MASK) == 0) { 689a17c678eSDavid Greenman /* 690dfe61cf1SDavid Greenman * Start another stats dump. By waiting for it to be 691dfe61cf1SDavid Greenman * accepted, we avoid having to do splhigh locking when 692dfe61cf1SDavid Greenman * writing scb_command in other parts of the driver. 693a17c678eSDavid Greenman */ 694a17c678eSDavid Greenman sc->csr->scb_command = FXP_SCB_COMMAND_CU_DUMPRESET; 6951cd443acSDavid Greenman fxp_scb_wait(sc->csr); 696dfe61cf1SDavid Greenman } else { 697dfe61cf1SDavid Greenman /* 698dfe61cf1SDavid Greenman * A previous command is still waiting to be accepted. 699dfe61cf1SDavid Greenman * Just zero our copy of the stats and wait for the 7003ba65732SDavid Greenman * next timer event to update them. 701dfe61cf1SDavid Greenman */ 702dfe61cf1SDavid Greenman sp->tx_good = 0; 703f9be9005SDavid Greenman sp->tx_underruns = 0; 704dfe61cf1SDavid Greenman sp->tx_total_collisions = 0; 7053ba65732SDavid Greenman 706dfe61cf1SDavid Greenman sp->rx_good = 0; 7073ba65732SDavid Greenman sp->rx_crc_errors = 0; 7083ba65732SDavid Greenman sp->rx_alignment_errors = 0; 7093ba65732SDavid Greenman sp->rx_rnr_errors = 0; 7103ba65732SDavid Greenman sp->rx_overrun_errors = 0; 7113ba65732SDavid Greenman sp->rx_shortframes = 0;; 712dfe61cf1SDavid Greenman } 713a17c678eSDavid Greenman /* 714a17c678eSDavid Greenman * Schedule another timeout one second from now. 715a17c678eSDavid Greenman */ 716a17c678eSDavid Greenman timeout(fxp_stats_update, sc, hz); 717a17c678eSDavid Greenman } 718a17c678eSDavid Greenman 719a17c678eSDavid Greenman /* 720a17c678eSDavid Greenman * Stop the interface. Cancels the statistics updater and resets 721a17c678eSDavid Greenman * the interface. 722a17c678eSDavid Greenman */ 723a17c678eSDavid Greenman static void 7244a5f1499SDavid Greenman fxp_stop(sc) 7254a5f1499SDavid Greenman struct fxp_softc *sc; 726a17c678eSDavid Greenman { 727a17c678eSDavid Greenman struct ifnet *ifp = &sc->arpcom.ac_if; 7283ba65732SDavid Greenman struct fxp_cb_tx *txp; 7293ba65732SDavid Greenman int i; 730a17c678eSDavid Greenman 731a17c678eSDavid Greenman /* 732a17c678eSDavid Greenman * Cancel stats updater. 733a17c678eSDavid Greenman */ 734a17c678eSDavid Greenman untimeout(fxp_stats_update, sc); 7353ba65732SDavid Greenman 7363ba65732SDavid Greenman /* 7373ba65732SDavid Greenman * Issue software reset 7383ba65732SDavid Greenman */ 739a17c678eSDavid Greenman sc->csr->port = 0; 740a17c678eSDavid Greenman DELAY(10); 741a17c678eSDavid Greenman 7423ba65732SDavid Greenman /* 7433ba65732SDavid Greenman * Release any xmit buffers. 7443ba65732SDavid Greenman */ 7453ba65732SDavid Greenman for (txp = sc->cbl_first; txp != NULL && txp->mb_head != NULL; 7463ba65732SDavid Greenman txp = txp->next) { 7473ba65732SDavid Greenman m_freem(txp->mb_head); 7483ba65732SDavid Greenman txp->mb_head = NULL; 7493ba65732SDavid Greenman } 7503ba65732SDavid Greenman sc->tx_queued = 0; 7513ba65732SDavid Greenman 7523ba65732SDavid Greenman /* 7533ba65732SDavid Greenman * Free all the receive buffers then reallocate/reinitialize 7543ba65732SDavid Greenman */ 7553ba65732SDavid Greenman if (sc->rfa_headm != NULL) 7563ba65732SDavid Greenman m_freem(sc->rfa_headm); 7573ba65732SDavid Greenman sc->rfa_headm = NULL; 7583ba65732SDavid Greenman sc->rfa_tailm = NULL; 7593ba65732SDavid Greenman for (i = 0; i < FXP_NRFABUFS; i++) { 7603ba65732SDavid Greenman if (fxp_add_rfabuf(sc, NULL) != 0) { 7613ba65732SDavid Greenman /* 7623ba65732SDavid Greenman * This "can't happen" - we're at splimp() 7633ba65732SDavid Greenman * and we just freed all the buffers we need 7643ba65732SDavid Greenman * above. 7653ba65732SDavid Greenman */ 7663ba65732SDavid Greenman panic("fxp_stop: no buffers!"); 7673ba65732SDavid Greenman } 7683ba65732SDavid Greenman } 7693ba65732SDavid Greenman 7703ba65732SDavid Greenman ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); 7713ba65732SDavid Greenman ifp->if_timer = 0; 772a17c678eSDavid Greenman } 773a17c678eSDavid Greenman 774a17c678eSDavid Greenman /* 775a17c678eSDavid Greenman * Watchdog/transmission transmit timeout handler. Called when a 776a17c678eSDavid Greenman * transmission is started on the interface, but no interrupt is 777a17c678eSDavid Greenman * received before the timeout. This usually indicates that the 778a17c678eSDavid Greenman * card has wedged for some reason. 779a17c678eSDavid Greenman */ 780a17c678eSDavid Greenman static void 7814a5f1499SDavid Greenman fxp_watchdog(ifp) 7824a5f1499SDavid Greenman struct ifnet *ifp; 783a17c678eSDavid Greenman { 7844a5f1499SDavid Greenman log(LOG_ERR, "fxp%d: device timeout\n", ifp->if_unit); 7854a5f1499SDavid Greenman ifp->if_oerrors++; 786a17c678eSDavid Greenman 7874a5f1499SDavid Greenman fxp_init(ifp); 788a17c678eSDavid Greenman } 789a17c678eSDavid Greenman 790a17c678eSDavid Greenman static void 7914a5f1499SDavid Greenman fxp_init(ifp) 7924a5f1499SDavid Greenman struct ifnet *ifp; 793a17c678eSDavid Greenman { 7949b44ff22SGarrett Wollman struct fxp_softc *sc = ifp->if_softc; 795a17c678eSDavid Greenman struct fxp_cb_config *cbp; 796a17c678eSDavid Greenman struct fxp_cb_ias *cb_ias; 797a17c678eSDavid Greenman struct fxp_cb_tx *txp; 798a17c678eSDavid Greenman struct fxp_csr *csr = sc->csr; 799a17c678eSDavid Greenman int i, s, mcast, prm; 800a17c678eSDavid Greenman 801a17c678eSDavid Greenman s = splimp(); 802a17c678eSDavid Greenman /* 8033ba65732SDavid Greenman * Cancel any pending I/O 804a17c678eSDavid Greenman */ 8053ba65732SDavid Greenman fxp_stop(sc); 806a17c678eSDavid Greenman 807a17c678eSDavid Greenman prm = (ifp->if_flags & IFF_PROMISC) ? 1 : 0; 808a17c678eSDavid Greenman sc->promisc_mode = prm; 809a17c678eSDavid Greenman /* 810a17c678eSDavid Greenman * Sleeze out here and enable reception of all multicasts if 811a17c678eSDavid Greenman * multicasts are enabled. Ideally, we'd program the multicast 812a17c678eSDavid Greenman * address filter to only accept specific multicasts. 813a17c678eSDavid Greenman */ 814a17c678eSDavid Greenman mcast = (ifp->if_flags & (IFF_MULTICAST|IFF_ALLMULTI)) ? 1 : 0; 815a17c678eSDavid Greenman 816a17c678eSDavid Greenman /* 817a17c678eSDavid Greenman * Initialize base of CBL and RFA memory. Loading with zero 818a17c678eSDavid Greenman * sets it up for regular linear addressing. 819a17c678eSDavid Greenman */ 820a17c678eSDavid Greenman csr->scb_general = 0; 821a17c678eSDavid Greenman csr->scb_command = FXP_SCB_COMMAND_CU_BASE; 822a17c678eSDavid Greenman 8231cd443acSDavid Greenman fxp_scb_wait(csr); 824a17c678eSDavid Greenman csr->scb_command = FXP_SCB_COMMAND_RU_BASE; 825a17c678eSDavid Greenman 826a17c678eSDavid Greenman /* 827a17c678eSDavid Greenman * Initialize base of dump-stats buffer. 828a17c678eSDavid Greenman */ 8291cd443acSDavid Greenman fxp_scb_wait(csr); 830a17c678eSDavid Greenman csr->scb_general = vtophys(sc->fxp_stats); 831a17c678eSDavid Greenman csr->scb_command = FXP_SCB_COMMAND_CU_DUMP_ADR; 832a17c678eSDavid Greenman 833a17c678eSDavid Greenman /* 834a17c678eSDavid Greenman * We temporarily use memory that contains the TxCB list to 835a17c678eSDavid Greenman * construct the config CB. The TxCB list memory is rebuilt 836a17c678eSDavid Greenman * later. 837a17c678eSDavid Greenman */ 838a17c678eSDavid Greenman cbp = (struct fxp_cb_config *) sc->cbl_base; 839a17c678eSDavid Greenman 840a17c678eSDavid Greenman /* 841a17c678eSDavid Greenman * This bcopy is kind of disgusting, but there are a bunch of must be 842a17c678eSDavid Greenman * zero and must be one bits in this structure and this is the easiest 843a17c678eSDavid Greenman * way to initialize them all to proper values. 844a17c678eSDavid Greenman */ 845a17c678eSDavid Greenman bcopy(fxp_cb_config_template, cbp, sizeof(struct fxp_cb_config)); 846a17c678eSDavid Greenman 847a17c678eSDavid Greenman cbp->cb_status = 0; 848a17c678eSDavid Greenman cbp->cb_command = FXP_CB_COMMAND_CONFIG | FXP_CB_COMMAND_EL; 849a17c678eSDavid Greenman cbp->link_addr = -1; /* (no) next command */ 850a17c678eSDavid Greenman cbp->byte_count = 22; /* (22) bytes to config */ 851a17c678eSDavid Greenman cbp->rx_fifo_limit = 8; /* rx fifo threshold */ 852a17c678eSDavid Greenman cbp->tx_fifo_limit = 0; /* tx fifo threshold */ 853a17c678eSDavid Greenman cbp->adaptive_ifs = 0; /* (no) adaptive interframe spacing */ 8541cd443acSDavid Greenman cbp->rx_dma_bytecount = 16; /* (no) rx DMA max */ 8551cd443acSDavid Greenman cbp->tx_dma_bytecount = 16; /* (no) tx DMA max */ 856a17c678eSDavid Greenman cbp->dma_bce = 1; /* (enable) dma max counters */ 857a17c678eSDavid Greenman cbp->late_scb = 0; /* (don't) defer SCB update */ 858a17c678eSDavid Greenman cbp->tno_int = 0; /* (disable) tx not okay interrupt */ 859a17c678eSDavid Greenman cbp->ci_int = 0; /* (do) interrupt on CU not active */ 860a17c678eSDavid Greenman cbp->save_bf = prm; /* save bad frames */ 861a17c678eSDavid Greenman cbp->disc_short_rx = !prm; /* discard short packets */ 862a17c678eSDavid Greenman cbp->underrun_retry = 1; /* retry mode (1) on DMA underrun */ 863a17c678eSDavid Greenman cbp->mediatype = 1; /* (MII) interface mode */ 864a17c678eSDavid Greenman cbp->nsai = 1; /* (don't) disable source addr insert */ 865a17c678eSDavid Greenman cbp->preamble_length = 2; /* (7 byte) preamble */ 866a17c678eSDavid Greenman cbp->loopback = 0; /* (don't) loopback */ 867a17c678eSDavid Greenman cbp->linear_priority = 0; /* (normal CSMA/CD operation) */ 868a17c678eSDavid Greenman cbp->linear_pri_mode = 0; /* (wait after xmit only) */ 869a17c678eSDavid Greenman cbp->interfrm_spacing = 6; /* (96 bits of) interframe spacing */ 870a17c678eSDavid Greenman cbp->promiscuous = prm; /* promiscuous mode */ 871a17c678eSDavid Greenman cbp->bcast_disable = 0; /* (don't) disable broadcasts */ 872a17c678eSDavid Greenman cbp->crscdt = 0; /* (CRS only) */ 873a17c678eSDavid Greenman cbp->stripping = !prm; /* truncate rx packet to byte count */ 874a17c678eSDavid Greenman cbp->padding = 1; /* (do) pad short tx packets */ 875a17c678eSDavid Greenman cbp->rcv_crc_xfer = 0; /* (don't) xfer CRC to host */ 876a17c678eSDavid Greenman cbp->force_fdx = 0; /* (don't) force full duplex */ 8773ba65732SDavid Greenman cbp->fdx_pin_en = 1; /* (enable) FDX# pin */ 878a17c678eSDavid Greenman cbp->multi_ia = 0; /* (don't) accept multiple IAs */ 879a17c678eSDavid Greenman cbp->mc_all = mcast; /* accept all multicasts */ 880a17c678eSDavid Greenman 881a17c678eSDavid Greenman /* 882a17c678eSDavid Greenman * Start the config command/DMA. 883a17c678eSDavid Greenman */ 8841cd443acSDavid Greenman fxp_scb_wait(csr); 885a17c678eSDavid Greenman csr->scb_general = vtophys(cbp); 886a17c678eSDavid Greenman csr->scb_command = FXP_SCB_COMMAND_CU_START; 887a17c678eSDavid Greenman /* ...and wait for it to complete. */ 888a17c678eSDavid Greenman while (!(cbp->cb_status & FXP_CB_STATUS_C)); 889a17c678eSDavid Greenman 890a17c678eSDavid Greenman /* 891a17c678eSDavid Greenman * Now initialize the station address. Temporarily use the TxCB 892a17c678eSDavid Greenman * memory area like we did above for the config CB. 893a17c678eSDavid Greenman */ 894a17c678eSDavid Greenman cb_ias = (struct fxp_cb_ias *) sc->cbl_base; 895a17c678eSDavid Greenman cb_ias->cb_status = 0; 896a17c678eSDavid Greenman cb_ias->cb_command = FXP_CB_COMMAND_IAS | FXP_CB_COMMAND_EL; 897a17c678eSDavid Greenman cb_ias->link_addr = -1; 898a17c678eSDavid Greenman bcopy(sc->arpcom.ac_enaddr, (void *)cb_ias->macaddr, 899a17c678eSDavid Greenman sizeof(sc->arpcom.ac_enaddr)); 900a17c678eSDavid Greenman 901a17c678eSDavid Greenman /* 902a17c678eSDavid Greenman * Start the IAS (Individual Address Setup) command/DMA. 903a17c678eSDavid Greenman */ 9041cd443acSDavid Greenman fxp_scb_wait(csr); 905a17c678eSDavid Greenman csr->scb_command = FXP_SCB_COMMAND_CU_START; 906a17c678eSDavid Greenman /* ...and wait for it to complete. */ 907a17c678eSDavid Greenman while (!(cb_ias->cb_status & FXP_CB_STATUS_C)); 908a17c678eSDavid Greenman 909a17c678eSDavid Greenman /* 910a17c678eSDavid Greenman * Initialize transmit control block (TxCB) list. 911a17c678eSDavid Greenman */ 912a17c678eSDavid Greenman 913a17c678eSDavid Greenman txp = sc->cbl_base; 914a17c678eSDavid Greenman bzero(txp, sizeof(struct fxp_cb_tx) * FXP_NTXCB); 915a17c678eSDavid Greenman for (i = 0; i < FXP_NTXCB; i++) { 916a17c678eSDavid Greenman txp[i].cb_status = FXP_CB_STATUS_C | FXP_CB_STATUS_OK; 917a17c678eSDavid Greenman txp[i].cb_command = FXP_CB_COMMAND_NOP; 918a17c678eSDavid Greenman txp[i].link_addr = vtophys(&txp[(i + 1) & FXP_TXCB_MASK]); 919a17c678eSDavid Greenman txp[i].tbd_array_addr = vtophys(&txp[i].tbd[0]); 920a17c678eSDavid Greenman txp[i].next = &txp[(i + 1) & FXP_TXCB_MASK]; 921a17c678eSDavid Greenman } 922a17c678eSDavid Greenman /* 923a17c678eSDavid Greenman * Set the stop flag on the first TxCB and start the control 924a17c678eSDavid Greenman * unit. It will execute the NOP and then suspend. 925a17c678eSDavid Greenman */ 926a17c678eSDavid Greenman txp->cb_command = FXP_CB_COMMAND_NOP | FXP_CB_COMMAND_S; 927a17c678eSDavid Greenman sc->cbl_first = sc->cbl_last = txp; 928a17c678eSDavid Greenman sc->tx_queued = 0; 929a17c678eSDavid Greenman 9301cd443acSDavid Greenman fxp_scb_wait(csr); 931a17c678eSDavid Greenman csr->scb_command = FXP_SCB_COMMAND_CU_START; 932a17c678eSDavid Greenman 933a17c678eSDavid Greenman /* 934a17c678eSDavid Greenman * Initialize receiver buffer area - RFA. 935a17c678eSDavid Greenman */ 9361cd443acSDavid Greenman fxp_scb_wait(csr); 937dfe61cf1SDavid Greenman csr->scb_general = vtophys(sc->rfa_headm->m_ext.ext_buf); 938a17c678eSDavid Greenman csr->scb_command = FXP_SCB_COMMAND_RU_START; 939a17c678eSDavid Greenman 940a17c678eSDavid Greenman ifp->if_flags |= IFF_RUNNING; 941a17c678eSDavid Greenman ifp->if_flags &= ~IFF_OACTIVE; 942a17c678eSDavid Greenman splx(s); 943a17c678eSDavid Greenman 944a17c678eSDavid Greenman /* 945a17c678eSDavid Greenman * Start stats updater. 946a17c678eSDavid Greenman */ 947a17c678eSDavid Greenman timeout(fxp_stats_update, sc, hz); 948a17c678eSDavid Greenman } 949a17c678eSDavid Greenman 950a17c678eSDavid Greenman /* 951a17c678eSDavid Greenman * Add a buffer to the end of the RFA buffer list. 952a17c678eSDavid Greenman * Return 0 if successful, 1 for failure. A failure results in 953a17c678eSDavid Greenman * adding the 'oldm' (if non-NULL) on to the end of the list - 954a17c678eSDavid Greenman * tossing out it's old contents and recycling it. 955a17c678eSDavid Greenman * The RFA struct is stuck at the beginning of mbuf cluster and the 956a17c678eSDavid Greenman * data pointer is fixed up to point just past it. 957a17c678eSDavid Greenman */ 958a17c678eSDavid Greenman static int 959a17c678eSDavid Greenman fxp_add_rfabuf(sc, oldm) 960a17c678eSDavid Greenman struct fxp_softc *sc; 961a17c678eSDavid Greenman struct mbuf *oldm; 962a17c678eSDavid Greenman { 963a17c678eSDavid Greenman struct mbuf *m; 964a17c678eSDavid Greenman struct fxp_rfa *rfa, *p_rfa; 965a17c678eSDavid Greenman 966a17c678eSDavid Greenman MGETHDR(m, M_DONTWAIT, MT_DATA); 967a17c678eSDavid Greenman if (m != NULL) { 968a17c678eSDavid Greenman MCLGET(m, M_DONTWAIT); 969a17c678eSDavid Greenman if ((m->m_flags & M_EXT) == 0) { 970a17c678eSDavid Greenman m_freem(m); 971eadd5e3aSDavid Greenman if (oldm == NULL) 972eadd5e3aSDavid Greenman return 1; 973a17c678eSDavid Greenman m = oldm; 974eadd5e3aSDavid Greenman m->m_data = m->m_ext.ext_buf; 975a17c678eSDavid Greenman } 976a17c678eSDavid Greenman } else { 977eadd5e3aSDavid Greenman if (oldm == NULL) 978a17c678eSDavid Greenman return 1; 979eadd5e3aSDavid Greenman m = oldm; 980eadd5e3aSDavid Greenman m->m_data = m->m_ext.ext_buf; 981eadd5e3aSDavid Greenman } 982eadd5e3aSDavid Greenman /* 983eadd5e3aSDavid Greenman * Get a pointer to the base of the mbuf cluster and move 984eadd5e3aSDavid Greenman * data start past it. 985eadd5e3aSDavid Greenman */ 986a17c678eSDavid Greenman rfa = mtod(m, struct fxp_rfa *); 987eadd5e3aSDavid Greenman m->m_data += sizeof(struct fxp_rfa); 988eadd5e3aSDavid Greenman rfa->size = MCLBYTES - sizeof(struct fxp_rfa); 989eadd5e3aSDavid Greenman 990a17c678eSDavid Greenman rfa->rfa_status = 0; 991a17c678eSDavid Greenman rfa->rfa_control = FXP_RFA_CONTROL_EL; 992a17c678eSDavid Greenman rfa->link_addr = -1; 993a17c678eSDavid Greenman rfa->rbd_addr = -1; 994a17c678eSDavid Greenman rfa->actual_size = 0; 995dfe61cf1SDavid Greenman /* 996dfe61cf1SDavid Greenman * If there are other buffers already on the list, attach this 997dfe61cf1SDavid Greenman * one to the end by fixing up the tail to point to this one. 998dfe61cf1SDavid Greenman */ 999a17c678eSDavid Greenman if (sc->rfa_headm != NULL) { 1000dfe61cf1SDavid Greenman p_rfa = (struct fxp_rfa *) sc->rfa_tailm->m_ext.ext_buf; 1001a17c678eSDavid Greenman sc->rfa_tailm->m_next = m; 1002a17c678eSDavid Greenman p_rfa->link_addr = vtophys(rfa); 1003a17c678eSDavid Greenman p_rfa->rfa_control &= ~FXP_RFA_CONTROL_EL; 1004a17c678eSDavid Greenman } else { 1005a17c678eSDavid Greenman sc->rfa_headm = m; 1006a17c678eSDavid Greenman } 1007a17c678eSDavid Greenman sc->rfa_tailm = m; 1008a17c678eSDavid Greenman 1009dfe61cf1SDavid Greenman return (m == oldm); 1010a17c678eSDavid Greenman } 1011a17c678eSDavid Greenman 1012a17c678eSDavid Greenman static int 1013a17c678eSDavid Greenman fxp_ioctl(ifp, command, data) 1014a17c678eSDavid Greenman struct ifnet *ifp; 1015a17c678eSDavid Greenman int command; 1016a17c678eSDavid Greenman caddr_t data; 1017a17c678eSDavid Greenman { 1018a17c678eSDavid Greenman struct ifaddr *ifa = (struct ifaddr *) data; 10199b44ff22SGarrett Wollman struct fxp_softc *sc = ifp->if_softc; 1020a17c678eSDavid Greenman struct ifreq *ifr = (struct ifreq *) data; 1021a17c678eSDavid Greenman int s, error = 0; 1022a17c678eSDavid Greenman 1023a17c678eSDavid Greenman s = splimp(); 1024a17c678eSDavid Greenman 1025a17c678eSDavid Greenman switch (command) { 1026a17c678eSDavid Greenman 1027a17c678eSDavid Greenman case SIOCSIFADDR: 1028a17c678eSDavid Greenman ifp->if_flags |= IFF_UP; 1029a17c678eSDavid Greenman 1030a17c678eSDavid Greenman switch (ifa->ifa_addr->sa_family) { 1031a17c678eSDavid Greenman #ifdef INET 1032a17c678eSDavid Greenman case AF_INET: 10334a5f1499SDavid Greenman fxp_init(ifp); /* before arpwhohas */ 1034a17c678eSDavid Greenman arp_ifinit((struct arpcom *)ifp, ifa); 1035a17c678eSDavid Greenman break; 1036a17c678eSDavid Greenman #endif 1037a17c678eSDavid Greenman #ifdef IPX 1038a17c678eSDavid Greenman /* 1039a17c678eSDavid Greenman * XXX - This code is probably wrong 1040a17c678eSDavid Greenman */ 1041a17c678eSDavid Greenman case AF_IPX: 1042a17c678eSDavid Greenman { 1043a17c678eSDavid Greenman register struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr); 1044a17c678eSDavid Greenman 1045a17c678eSDavid Greenman if (ipx_nullhost(*ina)) 1046a17c678eSDavid Greenman ina->x_host = 1047a17c678eSDavid Greenman *(union ipx_host *) (sc->arpcom.ac_enaddr); 1048a17c678eSDavid Greenman else { 1049a17c678eSDavid Greenman bcopy((caddr_t) ina->x_host.c_host, 1050a17c678eSDavid Greenman (caddr_t) sc->arpcom.ac_enaddr, 1051a17c678eSDavid Greenman sizeof(sc->arpcom.ac_enaddr)); 1052a17c678eSDavid Greenman } 1053a17c678eSDavid Greenman 1054a17c678eSDavid Greenman /* 1055a17c678eSDavid Greenman * Set new address 1056a17c678eSDavid Greenman */ 10574a5f1499SDavid Greenman fxp_init(ifp); 1058a17c678eSDavid Greenman break; 1059a17c678eSDavid Greenman } 1060a17c678eSDavid Greenman #endif 1061a17c678eSDavid Greenman #ifdef NS 1062a17c678eSDavid Greenman /* 1063a17c678eSDavid Greenman * XXX - This code is probably wrong 1064a17c678eSDavid Greenman */ 1065a17c678eSDavid Greenman case AF_NS: 1066a17c678eSDavid Greenman { 1067a17c678eSDavid Greenman register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); 1068a17c678eSDavid Greenman 1069a17c678eSDavid Greenman if (ns_nullhost(*ina)) 1070a17c678eSDavid Greenman ina->x_host = 1071a17c678eSDavid Greenman *(union ns_host *) (sc->arpcom.ac_enaddr); 1072a17c678eSDavid Greenman else { 1073a17c678eSDavid Greenman bcopy((caddr_t) ina->x_host.c_host, 1074a17c678eSDavid Greenman (caddr_t) sc->arpcom.ac_enaddr, 1075a17c678eSDavid Greenman sizeof(sc->arpcom.ac_enaddr)); 1076a17c678eSDavid Greenman } 1077a17c678eSDavid Greenman 1078a17c678eSDavid Greenman /* 1079a17c678eSDavid Greenman * Set new address 1080a17c678eSDavid Greenman */ 10814a5f1499SDavid Greenman fxp_init(ifp); 1082a17c678eSDavid Greenman break; 1083a17c678eSDavid Greenman } 1084a17c678eSDavid Greenman #endif 1085a17c678eSDavid Greenman default: 10864a5f1499SDavid Greenman fxp_init(ifp); 1087a17c678eSDavid Greenman break; 1088a17c678eSDavid Greenman } 1089a17c678eSDavid Greenman break; 1090a17c678eSDavid Greenman 1091a17c678eSDavid Greenman case SIOCGIFADDR: 1092a17c678eSDavid Greenman { 1093a17c678eSDavid Greenman struct sockaddr *sa; 1094a17c678eSDavid Greenman 1095a17c678eSDavid Greenman sa = (struct sockaddr *) & ifr->ifr_data; 1096a17c678eSDavid Greenman bcopy((caddr_t) sc->arpcom.ac_enaddr, 1097a17c678eSDavid Greenman (caddr_t) sa->sa_data, sizeof(sc->arpcom.ac_enaddr)); 1098a17c678eSDavid Greenman } 1099a17c678eSDavid Greenman break; 1100a17c678eSDavid Greenman 1101a17c678eSDavid Greenman case SIOCSIFFLAGS: 1102a17c678eSDavid Greenman 1103a17c678eSDavid Greenman /* 1104a17c678eSDavid Greenman * If interface is marked up and not running, then start it. 1105a17c678eSDavid Greenman * If it is marked down and running, stop it. 1106a17c678eSDavid Greenman * XXX If it's up then re-initialize it. This is so flags 1107a17c678eSDavid Greenman * such as IFF_PROMISC are handled. 1108a17c678eSDavid Greenman */ 1109a17c678eSDavid Greenman if (ifp->if_flags & IFF_UP) { 11104a5f1499SDavid Greenman fxp_init(ifp); 1111a17c678eSDavid Greenman } else { 1112a17c678eSDavid Greenman if (ifp->if_flags & IFF_RUNNING) 11134a5f1499SDavid Greenman fxp_stop(sc); 1114a17c678eSDavid Greenman } 1115a17c678eSDavid Greenman break; 1116a17c678eSDavid Greenman 1117a17c678eSDavid Greenman case SIOCADDMULTI: 1118a17c678eSDavid Greenman case SIOCDELMULTI: 1119a17c678eSDavid Greenman /* 1120a17c678eSDavid Greenman * Update out multicast list. 1121a17c678eSDavid Greenman */ 1122a17c678eSDavid Greenman error = (command == SIOCADDMULTI) ? 1123a17c678eSDavid Greenman ether_addmulti(ifr, &sc->arpcom) : 1124a17c678eSDavid Greenman ether_delmulti(ifr, &sc->arpcom); 1125a17c678eSDavid Greenman 1126a17c678eSDavid Greenman if (error == ENETRESET) { 1127a17c678eSDavid Greenman /* 1128a17c678eSDavid Greenman * Multicast list has changed; set the hardware filter 1129a17c678eSDavid Greenman * accordingly. 1130a17c678eSDavid Greenman */ 11314a5f1499SDavid Greenman fxp_init(ifp); 1132a17c678eSDavid Greenman 1133a17c678eSDavid Greenman error = 0; 1134a17c678eSDavid Greenman } 1135a17c678eSDavid Greenman break; 1136a17c678eSDavid Greenman 1137a17c678eSDavid Greenman case SIOCSIFMTU: 1138a17c678eSDavid Greenman /* 1139a17c678eSDavid Greenman * Set the interface MTU. 1140a17c678eSDavid Greenman */ 1141a17c678eSDavid Greenman if (ifr->ifr_mtu > ETHERMTU) { 1142a17c678eSDavid Greenman error = EINVAL; 1143a17c678eSDavid Greenman } else { 1144a17c678eSDavid Greenman ifp->if_mtu = ifr->ifr_mtu; 1145a17c678eSDavid Greenman } 1146a17c678eSDavid Greenman break; 1147a17c678eSDavid Greenman 1148a17c678eSDavid Greenman default: 1149a17c678eSDavid Greenman error = EINVAL; 1150a17c678eSDavid Greenman } 1151a17c678eSDavid Greenman (void) splx(s); 1152a17c678eSDavid Greenman return (error); 1153a17c678eSDavid Greenman } 1154