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 * 27eadd5e3aSDavid Greenman * $Id: if_fxp.c,v 1.17 1996/09/20 04:11:53 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 1273ba65732SDavid Greenman static inline int 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 */ 163a17c678eSDavid Greenman #define FXP_NTXCB 64 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 */ 1913ba65732SDavid Greenman static inline int 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); 1983ba65732SDavid Greenman return (i); 199a17c678eSDavid Greenman } 200a17c678eSDavid Greenman 201dfe61cf1SDavid Greenman /* 202dfe61cf1SDavid Greenman * Return identification string if this is device is ours. 203dfe61cf1SDavid Greenman */ 204a17c678eSDavid Greenman static char * 205a17c678eSDavid Greenman fxp_probe(config_id, device_id) 206a17c678eSDavid Greenman pcici_t config_id; 207a17c678eSDavid Greenman pcidi_t device_id; 208a17c678eSDavid Greenman { 209a17c678eSDavid Greenman if (((device_id & 0xffff) == FXP_VENDORID_INTEL) && 210a17c678eSDavid Greenman ((device_id >> 16) & 0xffff) == FXP_DEVICEID_i82557) 211ae12cddaSDavid Greenman return ("Intel EtherExpress Pro/100B Fast Ethernet"); 212a17c678eSDavid Greenman 213a17c678eSDavid Greenman return NULL; 214a17c678eSDavid Greenman } 215a17c678eSDavid Greenman 216a17c678eSDavid Greenman /* 217a17c678eSDavid Greenman * Allocate data structures and attach the device. 218a17c678eSDavid Greenman */ 219a17c678eSDavid Greenman static void 220a17c678eSDavid Greenman fxp_attach(config_id, unit) 221a17c678eSDavid Greenman pcici_t config_id; 222a17c678eSDavid Greenman int unit; 223a17c678eSDavid Greenman { 224a17c678eSDavid Greenman struct fxp_softc *sc; 225a17c678eSDavid Greenman struct ifnet *ifp; 226a17c678eSDavid Greenman vm_offset_t pbase; 227a17c678eSDavid Greenman int s, i; 228a17c678eSDavid Greenman 229a17c678eSDavid Greenman sc = malloc(sizeof(struct fxp_softc), M_DEVBUF, M_NOWAIT); 230a17c678eSDavid Greenman if (sc == NULL) 231a17c678eSDavid Greenman return; 232a17c678eSDavid Greenman bzero(sc, sizeof(struct fxp_softc)); 233a17c678eSDavid Greenman 234a17c678eSDavid Greenman s = splimp(); 235a17c678eSDavid Greenman 236dfe61cf1SDavid Greenman /* 237dfe61cf1SDavid Greenman * Map control/status registers. 238dfe61cf1SDavid Greenman */ 239a17c678eSDavid Greenman if (!pci_map_mem(config_id, FXP_PCI_MMBA, 240a17c678eSDavid Greenman (vm_offset_t *)&sc->csr, &pbase)) { 241a17c678eSDavid Greenman printf("fxp%d: couldn't map memory\n", unit); 242a17c678eSDavid Greenman goto fail; 243a17c678eSDavid Greenman } 244a17c678eSDavid Greenman 245a17c678eSDavid Greenman /* 246dfe61cf1SDavid Greenman * Issue a software reset. 247a17c678eSDavid Greenman */ 248a17c678eSDavid Greenman sc->csr->port = 0; 249a17c678eSDavid Greenman DELAY(10); 250a17c678eSDavid Greenman 251dfe61cf1SDavid Greenman /* 252dfe61cf1SDavid Greenman * Allocate our interrupt. 253dfe61cf1SDavid Greenman */ 254a17c678eSDavid Greenman if (!pci_map_int(config_id, fxp_intr, sc, &net_imask)) { 255a17c678eSDavid Greenman printf("fxp%d: couldn't map interrupt\n", unit); 256a17c678eSDavid Greenman goto fail; 257a17c678eSDavid Greenman } 258a17c678eSDavid Greenman 259a17c678eSDavid Greenman sc->cbl_base = malloc(sizeof(struct fxp_cb_tx) * FXP_NTXCB, 260a17c678eSDavid Greenman M_DEVBUF, M_NOWAIT); 261a17c678eSDavid Greenman if (sc->cbl_base == NULL) 262a17c678eSDavid Greenman goto malloc_fail; 263a17c678eSDavid Greenman 264a17c678eSDavid Greenman sc->fxp_stats = malloc(sizeof(struct fxp_stats), M_DEVBUF, M_NOWAIT); 265a17c678eSDavid Greenman if (sc->fxp_stats == NULL) 266a17c678eSDavid Greenman goto malloc_fail; 267a17c678eSDavid Greenman bzero(sc->fxp_stats, sizeof(struct fxp_stats)); 268a17c678eSDavid Greenman 269dfe61cf1SDavid Greenman /* 270dfe61cf1SDavid Greenman * Pre-allocate our receive buffers. 271dfe61cf1SDavid Greenman */ 272a17c678eSDavid Greenman for (i = 0; i < FXP_NRFABUFS; i++) { 273a17c678eSDavid Greenman if (fxp_add_rfabuf(sc, NULL) != 0) { 274a17c678eSDavid Greenman goto malloc_fail; 275a17c678eSDavid Greenman } 276a17c678eSDavid Greenman } 277a17c678eSDavid Greenman 278a17c678eSDavid Greenman ifp = &sc->arpcom.ac_if; 2799b44ff22SGarrett Wollman ifp->if_softc = sc; 280a17c678eSDavid Greenman ifp->if_unit = unit; 281a17c678eSDavid Greenman ifp->if_name = "fxp"; 282a17c678eSDavid Greenman ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 283a17c678eSDavid Greenman ifp->if_ioctl = fxp_ioctl; 284a17c678eSDavid Greenman ifp->if_output = ether_output; 285a17c678eSDavid Greenman ifp->if_start = fxp_start; 286a17c678eSDavid Greenman ifp->if_watchdog = fxp_watchdog; 287a330e1f1SGary Palmer ifp->if_baudrate = 100000000; 288a17c678eSDavid Greenman 289a17c678eSDavid Greenman fxp_get_macaddr(sc); 29018b7be40SPoul-Henning Kamp printf("fxp%d: Ethernet address %6D\n", unit, 29118b7be40SPoul-Henning Kamp sc->arpcom.ac_enaddr, ":"); 292a17c678eSDavid Greenman 293dfe61cf1SDavid Greenman /* 294dfe61cf1SDavid Greenman * Attach the interface. 295dfe61cf1SDavid Greenman */ 296a17c678eSDavid Greenman if_attach(ifp); 2979b44ff22SGarrett Wollman ether_ifattach(ifp); 2989b44ff22SGarrett Wollman 299a17c678eSDavid Greenman #if NBPFILTER > 0 3009b44ff22SGarrett Wollman bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header)); 301a17c678eSDavid Greenman #endif 3024a684684SDavid Greenman 3034a684684SDavid Greenman /* 3044a684684SDavid Greenman * Add shutdown hook so that DMA is disabled prior to reboot. Not 3054a684684SDavid Greenman * doing do could allow DMA to corrupt kernel memory during the 3064a684684SDavid Greenman * reboot before the driver initializes. 3074a684684SDavid Greenman */ 3084a684684SDavid Greenman at_shutdown(fxp_shutdown, sc, SHUTDOWN_POST_SYNC); 3094a684684SDavid Greenman 310a17c678eSDavid Greenman splx(s); 311a17c678eSDavid Greenman return; 312a17c678eSDavid Greenman 313a17c678eSDavid Greenman malloc_fail: 314a17c678eSDavid Greenman printf("fxp%d: Failed to malloc memory\n", unit); 315a17c678eSDavid Greenman (void) pci_unmap_int(config_id); 316a17c678eSDavid Greenman if (sc && sc->cbl_base) 317a17c678eSDavid Greenman free(sc->cbl_base, M_DEVBUF); 318a17c678eSDavid Greenman if (sc && sc->fxp_stats) 319a17c678eSDavid Greenman free(sc->fxp_stats, M_DEVBUF); 320a17c678eSDavid Greenman /* frees entire chain */ 321a17c678eSDavid Greenman if (sc && sc->rfa_headm) 322a17c678eSDavid Greenman m_freem(sc->rfa_headm); 323a17c678eSDavid Greenman fail: 324a17c678eSDavid Greenman if (sc) 325a17c678eSDavid Greenman free(sc, M_DEVBUF); 326a17c678eSDavid Greenman splx(s); 327a17c678eSDavid Greenman } 328a17c678eSDavid Greenman 329a17c678eSDavid Greenman /* 330a17c678eSDavid Greenman * Read station (MAC) address from serial EEPROM. Basically, you 331a17c678eSDavid Greenman * manually shift in the read opcode (one bit at a time) and then 332a17c678eSDavid Greenman * shift in the address, and then you shift out the data (all of 333a17c678eSDavid Greenman * this one bit at a time). The word size is 16 bits, so you have 334a17c678eSDavid Greenman * to provide the address for every 16 bits of data. The MAC address 335a17c678eSDavid Greenman * is in the first 3 words (6 bytes total). 336a17c678eSDavid Greenman */ 337a17c678eSDavid Greenman static void 338a17c678eSDavid Greenman fxp_get_macaddr(sc) 339a17c678eSDavid Greenman struct fxp_softc *sc; 340a17c678eSDavid Greenman { 341a17c678eSDavid Greenman struct fxp_csr *csr; 342a17c678eSDavid Greenman u_short reg, *data; 343a17c678eSDavid Greenman int i, x; 344a17c678eSDavid Greenman 345a17c678eSDavid Greenman csr = sc->csr; 346a17c678eSDavid Greenman data = (u_short *)sc->arpcom.ac_enaddr; 347a17c678eSDavid Greenman 348a17c678eSDavid Greenman for (i = 0; i < 3; i++) { 349a17c678eSDavid Greenman csr->eeprom_control = FXP_EEPROM_EECS; 350a17c678eSDavid Greenman /* 351a17c678eSDavid Greenman * Shift in read opcode. 352a17c678eSDavid Greenman */ 353a17c678eSDavid Greenman for (x = 3; x > 0; x--) { 354a17c678eSDavid Greenman if (FXP_EEPROM_OPC_READ & (1 << (x - 1))) { 355a17c678eSDavid Greenman reg = FXP_EEPROM_EECS | FXP_EEPROM_EEDI; 356a17c678eSDavid Greenman } else { 357a17c678eSDavid Greenman reg = FXP_EEPROM_EECS; 358a17c678eSDavid Greenman } 359a17c678eSDavid Greenman csr->eeprom_control = reg; 360a17c678eSDavid Greenman csr->eeprom_control = reg | FXP_EEPROM_EESK; 361a17c678eSDavid Greenman DELAY(1); 362a17c678eSDavid Greenman csr->eeprom_control = reg; 363a17c678eSDavid Greenman DELAY(1); 364a17c678eSDavid Greenman } 365a17c678eSDavid Greenman /* 366a17c678eSDavid Greenman * Shift in address. 367a17c678eSDavid Greenman */ 368a17c678eSDavid Greenman for (x = 6; x > 0; x--) { 369a17c678eSDavid Greenman if (i & (1 << (x - 1))) { 370a17c678eSDavid Greenman reg = FXP_EEPROM_EECS | FXP_EEPROM_EEDI; 371a17c678eSDavid Greenman } else { 372a17c678eSDavid Greenman reg = FXP_EEPROM_EECS; 373a17c678eSDavid Greenman } 374a17c678eSDavid Greenman csr->eeprom_control = reg; 375a17c678eSDavid Greenman csr->eeprom_control = reg | FXP_EEPROM_EESK; 376a17c678eSDavid Greenman DELAY(1); 377a17c678eSDavid Greenman csr->eeprom_control = reg; 378a17c678eSDavid Greenman DELAY(1); 379a17c678eSDavid Greenman } 380a17c678eSDavid Greenman reg = FXP_EEPROM_EECS; 381a17c678eSDavid Greenman data[i] = 0; 382a17c678eSDavid Greenman /* 383a17c678eSDavid Greenman * Shift out data. 384a17c678eSDavid Greenman */ 385a17c678eSDavid Greenman for (x = 16; x > 0; x--) { 386a17c678eSDavid Greenman csr->eeprom_control = reg | FXP_EEPROM_EESK; 387a17c678eSDavid Greenman DELAY(1); 388a17c678eSDavid Greenman if (csr->eeprom_control & FXP_EEPROM_EEDO) 389a17c678eSDavid Greenman data[i] |= (1 << (x - 1)); 390a17c678eSDavid Greenman csr->eeprom_control = reg; 391a17c678eSDavid Greenman DELAY(1); 392a17c678eSDavid Greenman } 393a17c678eSDavid Greenman csr->eeprom_control = 0; 394a17c678eSDavid Greenman DELAY(1); 395a17c678eSDavid Greenman } 396a17c678eSDavid Greenman } 397a17c678eSDavid Greenman 398a17c678eSDavid Greenman /* 3994a684684SDavid Greenman * Device shutdown routine. Called at system shutdown after sync. The 400a17c678eSDavid Greenman * main purpose of this routine is to shut off receiver DMA so that 401a17c678eSDavid Greenman * kernel memory doesn't get clobbered during warmboot. 402a17c678eSDavid Greenman */ 4034a684684SDavid Greenman static void 4044a684684SDavid Greenman fxp_shutdown(howto, sc) 4054a684684SDavid Greenman int howto; 4064a684684SDavid Greenman void *sc; 407a17c678eSDavid Greenman { 4084a684684SDavid Greenman fxp_stop((struct fxp_softc *) sc); 409a17c678eSDavid Greenman } 410a17c678eSDavid Greenman 411a17c678eSDavid Greenman /* 412a17c678eSDavid Greenman * Start packet transmission on the interface. 413a17c678eSDavid Greenman */ 414a17c678eSDavid Greenman static void 415a17c678eSDavid Greenman fxp_start(ifp) 416a17c678eSDavid Greenman struct ifnet *ifp; 417a17c678eSDavid Greenman { 4189b44ff22SGarrett Wollman struct fxp_softc *sc = ifp->if_softc; 419a17c678eSDavid Greenman struct fxp_csr *csr = sc->csr; 420a17c678eSDavid Greenman struct fxp_cb_tx *txp; 421a17c678eSDavid Greenman struct mbuf *m, *mb_head; 422a17c678eSDavid Greenman int segment; 423a17c678eSDavid Greenman 424a17c678eSDavid Greenman txloop: 425a17c678eSDavid Greenman /* 426a17c678eSDavid Greenman * See if a TxCB is available. If not, indicate this to the 427a17c678eSDavid Greenman * outside world and exit. 428a17c678eSDavid Greenman */ 429a17c678eSDavid Greenman if (sc->tx_queued >= FXP_NTXCB) { 430a17c678eSDavid Greenman ifp->if_flags |= IFF_OACTIVE; 431a17c678eSDavid Greenman return; 432a17c678eSDavid Greenman } 433dfe61cf1SDavid Greenman /* 434dfe61cf1SDavid Greenman * Grab a packet to transmit. 435dfe61cf1SDavid Greenman */ 436a17c678eSDavid Greenman IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, mb_head); 437a17c678eSDavid Greenman if (mb_head == NULL) { 438a17c678eSDavid Greenman /* 439a17c678eSDavid Greenman * No more packets to send. 440a17c678eSDavid Greenman */ 441a17c678eSDavid Greenman return; 442a17c678eSDavid Greenman } 443a17c678eSDavid Greenman 444dfe61cf1SDavid Greenman /* 445dfe61cf1SDavid Greenman * Get pointer to next available (unused) descriptor. 446dfe61cf1SDavid Greenman */ 447a17c678eSDavid Greenman txp = sc->cbl_last->next; 448a17c678eSDavid Greenman 449a17c678eSDavid Greenman /* 450a17c678eSDavid Greenman * Go through each of the mbufs in the chain and initialize 451a17c678eSDavid Greenman * the transmit buffers descriptors with the physical address 452a17c678eSDavid Greenman * and size of the mbuf. 453a17c678eSDavid Greenman */ 45423a0ed7cSDavid Greenman tbdinit: 455a17c678eSDavid Greenman for (m = mb_head, segment = 0; m != NULL; m = m->m_next) { 456a17c678eSDavid Greenman if (m->m_len != 0) { 457a17c678eSDavid Greenman if (segment == FXP_NTXSEG) 458a17c678eSDavid Greenman break; 459a17c678eSDavid Greenman txp->tbd[segment].tb_addr = 460a17c678eSDavid Greenman vtophys(mtod(m, vm_offset_t)); 461a17c678eSDavid Greenman txp->tbd[segment].tb_size = m->m_len; 462a17c678eSDavid Greenman segment++; 463a17c678eSDavid Greenman } 464a17c678eSDavid Greenman } 465a17c678eSDavid Greenman if (m != NULL && segment == FXP_NTXSEG) { 46623a0ed7cSDavid Greenman struct mbuf *mn; 46723a0ed7cSDavid Greenman 468a17c678eSDavid Greenman /* 469a17c678eSDavid Greenman * We ran out of segments. We have to recopy this mbuf 470a17c678eSDavid Greenman * chain first. 471a17c678eSDavid Greenman */ 47223a0ed7cSDavid Greenman MGETHDR(mn, M_DONTWAIT, MT_DATA); 47323a0ed7cSDavid Greenman if (mn == NULL) { 47423a0ed7cSDavid Greenman m_freem(mb_head); 47523a0ed7cSDavid Greenman return; 476a17c678eSDavid Greenman } 47723a0ed7cSDavid Greenman if (mb_head->m_pkthdr.len > MHLEN) { 47823a0ed7cSDavid Greenman MCLGET(mn, M_DONTWAIT); 47923a0ed7cSDavid Greenman if ((mn->m_flags & M_EXT) == 0) { 48023a0ed7cSDavid Greenman m_freem(mn); 48123a0ed7cSDavid Greenman m_freem(mb_head); 48223a0ed7cSDavid Greenman return; 48323a0ed7cSDavid Greenman } 48423a0ed7cSDavid Greenman } 48523a0ed7cSDavid Greenman m_copydata(mb_head, 0, mb_head->m_pkthdr.len, mtod(mn, caddr_t)); 48623a0ed7cSDavid Greenman mn->m_pkthdr.len = mn->m_len = mb_head->m_pkthdr.len; 48723a0ed7cSDavid Greenman m_freem(mb_head); 48823a0ed7cSDavid Greenman mb_head = mn; 48923a0ed7cSDavid Greenman goto tbdinit; 49023a0ed7cSDavid Greenman } 49123a0ed7cSDavid Greenman 49223a0ed7cSDavid Greenman txp->tbd_number = segment; 49323a0ed7cSDavid Greenman 494a17c678eSDavid Greenman /* 495a17c678eSDavid Greenman * Finish the initialization of this TxCB. 496a17c678eSDavid Greenman */ 497a17c678eSDavid Greenman txp->cb_status = 0; 498a17c678eSDavid Greenman txp->cb_command = 499a17c678eSDavid Greenman FXP_CB_COMMAND_XMIT | FXP_CB_COMMAND_SF | FXP_CB_COMMAND_S; 500f9be9005SDavid Greenman txp->tx_threshold = tx_threshold; 501a17c678eSDavid Greenman txp->mb_head = mb_head; 502a17c678eSDavid Greenman 503a17c678eSDavid Greenman /* 504a17c678eSDavid Greenman * Advance the end-of-list forward. 505a17c678eSDavid Greenman */ 506a17c678eSDavid Greenman sc->cbl_last->cb_command &= ~FXP_CB_COMMAND_S; 507a17c678eSDavid Greenman sc->cbl_last = txp; 508a17c678eSDavid Greenman 509a17c678eSDavid Greenman /* 510a17c678eSDavid Greenman * If no packets were previously queued then advance the first 511a17c678eSDavid Greenman * pointer to this TxCB. 512a17c678eSDavid Greenman */ 513a17c678eSDavid Greenman if (sc->tx_queued++ == 0) { 514a17c678eSDavid Greenman sc->cbl_first = txp; 515a17c678eSDavid Greenman } 516a17c678eSDavid Greenman 5173ba65732SDavid Greenman if (!fxp_scb_wait(csr)) { 5183ba65732SDavid Greenman /* 5193ba65732SDavid Greenman * Hmmm, card has gone out to lunch 5203ba65732SDavid Greenman */ 5213ba65732SDavid Greenman fxp_init(ifp); 5223ba65732SDavid Greenman goto txloop; 5233ba65732SDavid Greenman } 5243ba65732SDavid Greenman 525a17c678eSDavid Greenman /* 526a17c678eSDavid Greenman * Resume transmission if suspended. 527a17c678eSDavid Greenman */ 528a17c678eSDavid Greenman csr->scb_command = FXP_SCB_COMMAND_CU_RESUME; 529a17c678eSDavid Greenman 530a17c678eSDavid Greenman #if NBPFILTER > 0 531a17c678eSDavid Greenman /* 532a17c678eSDavid Greenman * Pass packet to bpf if there is a listener. 533a17c678eSDavid Greenman */ 5349b44ff22SGarrett Wollman if (ifp->if_bpf != NULL) 5359b44ff22SGarrett Wollman bpf_mtap(ifp, mb_head); 536a17c678eSDavid Greenman #endif 537a17c678eSDavid Greenman /* 538a17c678eSDavid Greenman * Set a 5 second timer just in case we don't hear from the 539a17c678eSDavid Greenman * card again. 540a17c678eSDavid Greenman */ 541a17c678eSDavid Greenman ifp->if_timer = 5; 542a17c678eSDavid Greenman 543a17c678eSDavid Greenman goto txloop; 544a17c678eSDavid Greenman } 545a17c678eSDavid Greenman 546a17c678eSDavid Greenman /* 547a17c678eSDavid Greenman * Process interface interrupts. Returns 1 if the interrupt 548a17c678eSDavid Greenman * was handled, 0 if it wasn't. 549a17c678eSDavid Greenman */ 550dd7610fcSStefan Eßer static void 551a17c678eSDavid Greenman fxp_intr(arg) 552a17c678eSDavid Greenman void *arg; 553a17c678eSDavid Greenman { 554a17c678eSDavid Greenman struct fxp_softc *sc = arg; 555a17c678eSDavid Greenman struct fxp_csr *csr = sc->csr; 556a17c678eSDavid Greenman struct ifnet *ifp = &sc->arpcom.ac_if; 557a17c678eSDavid Greenman u_char statack; 558a17c678eSDavid Greenman 559a17c678eSDavid Greenman while ((statack = csr->scb_statack) != 0) { 560a17c678eSDavid Greenman /* 561a17c678eSDavid Greenman * First ACK all the interrupts in this pass. 562a17c678eSDavid Greenman */ 563a17c678eSDavid Greenman csr->scb_statack = statack; 564a17c678eSDavid Greenman 565a17c678eSDavid Greenman /* 566a17c678eSDavid Greenman * Free any finished transmit mbuf chains. 567a17c678eSDavid Greenman */ 568a17c678eSDavid Greenman if (statack & FXP_SCB_STATACK_CNA) { 569a17c678eSDavid Greenman struct fxp_cb_tx *txp; 570a17c678eSDavid Greenman 571a17c678eSDavid Greenman for (txp = sc->cbl_first; 572a17c678eSDavid Greenman (txp->cb_status & FXP_CB_STATUS_C) && 573a17c678eSDavid Greenman txp->mb_head != NULL; 574a17c678eSDavid Greenman txp = txp->next) { 575a17c678eSDavid Greenman m_freem(txp->mb_head); 576a17c678eSDavid Greenman txp->mb_head = NULL; 577a17c678eSDavid Greenman sc->tx_queued--; 578a17c678eSDavid Greenman } 579a17c678eSDavid Greenman sc->cbl_first = txp; 580a17c678eSDavid Greenman /* 581a17c678eSDavid Greenman * We unconditionally clear IFF_OACTIVE since it 582a17c678eSDavid Greenman * doesn't hurt to do so even if the tx queue is 583a17c678eSDavid Greenman * still full - it will just get set again in 584a17c678eSDavid Greenman * fxp_start(). If we get a CNA interrupt, it is 585a17c678eSDavid Greenman * (almost?) certain that we've freed up space for 586a17c678eSDavid Greenman * at least one more packet. 587a17c678eSDavid Greenman */ 588a17c678eSDavid Greenman ifp->if_flags &= ~IFF_OACTIVE; 589a17c678eSDavid Greenman /* 590a17c678eSDavid Greenman * Clear watchdog timer. It may or may not be set 591a17c678eSDavid Greenman * again in fxp_start(). 592a17c678eSDavid Greenman */ 593a17c678eSDavid Greenman ifp->if_timer = 0; 594a17c678eSDavid Greenman fxp_start(ifp); 595a17c678eSDavid Greenman } 596a17c678eSDavid Greenman /* 597a17c678eSDavid Greenman * Process receiver interrupts. If a no-resource (RNR) 598a17c678eSDavid Greenman * condition exists, get whatever packets we can and 599a17c678eSDavid Greenman * re-start the receiver. 600a17c678eSDavid Greenman */ 601a17c678eSDavid Greenman if (statack & (FXP_SCB_STATACK_FR | FXP_SCB_STATACK_RNR)) { 602a17c678eSDavid Greenman struct mbuf *m; 603a17c678eSDavid Greenman struct fxp_rfa *rfa; 604a17c678eSDavid Greenman rcvloop: 605a17c678eSDavid Greenman m = sc->rfa_headm; 606dfe61cf1SDavid Greenman rfa = (struct fxp_rfa *)m->m_ext.ext_buf; 607a17c678eSDavid Greenman 608a17c678eSDavid Greenman if (rfa->rfa_status & FXP_RFA_STATUS_C) { 609dfe61cf1SDavid Greenman /* 610dfe61cf1SDavid Greenman * Remove first packet from the chain. 611dfe61cf1SDavid Greenman */ 612a17c678eSDavid Greenman sc->rfa_headm = m->m_next; 613a17c678eSDavid Greenman m->m_next = NULL; 614a17c678eSDavid Greenman 615dfe61cf1SDavid Greenman /* 616dfe61cf1SDavid Greenman * Add a new buffer to the receive chain. If this 617dfe61cf1SDavid Greenman * fails, the old buffer is recycled instead. 618dfe61cf1SDavid Greenman */ 619a17c678eSDavid Greenman if (fxp_add_rfabuf(sc, m) == 0) { 620a17c678eSDavid Greenman struct ether_header *eh; 621a17c678eSDavid Greenman u_short total_len; 622a17c678eSDavid Greenman 623a17c678eSDavid Greenman total_len = rfa->actual_size & (MCLBYTES - 1); 624a17c678eSDavid Greenman m->m_pkthdr.rcvif = ifp; 625a17c678eSDavid Greenman m->m_pkthdr.len = m->m_len = total_len - 626a17c678eSDavid Greenman sizeof(struct ether_header); 627a17c678eSDavid Greenman eh = mtod(m, struct ether_header *); 628a17c678eSDavid Greenman #if NBPFILTER > 0 6299b44ff22SGarrett Wollman if (ifp->if_bpf != NULL) { 6309b44ff22SGarrett Wollman bpf_tap(ifp, mtod(m, caddr_t), total_len); 631a17c678eSDavid Greenman /* 632a17c678eSDavid Greenman * Only pass this packet up if it is for us. 633a17c678eSDavid Greenman */ 634a17c678eSDavid Greenman if ((ifp->if_flags & IFF_PROMISC) && 635a17c678eSDavid Greenman (rfa->rfa_status & FXP_RFA_STATUS_IAMATCH) && 636a17c678eSDavid Greenman (eh->ether_dhost[0] & 1) == 0) { 637a17c678eSDavid Greenman m_freem(m); 638a17c678eSDavid Greenman goto rcvloop; 639a17c678eSDavid Greenman } 640a17c678eSDavid Greenman } 641a17c678eSDavid Greenman #endif 642a17c678eSDavid Greenman m->m_data += sizeof(struct ether_header); 643a17c678eSDavid Greenman ether_input(ifp, eh, m); 644a17c678eSDavid Greenman } 645a17c678eSDavid Greenman goto rcvloop; 646a17c678eSDavid Greenman } 647a17c678eSDavid Greenman if (statack & FXP_SCB_STATACK_RNR) { 648a17c678eSDavid Greenman struct fxp_csr *csr = sc->csr; 649a17c678eSDavid Greenman 6503ba65732SDavid Greenman (void) fxp_scb_wait(csr); 651dfe61cf1SDavid Greenman csr->scb_general = vtophys(sc->rfa_headm->m_ext.ext_buf); 652a17c678eSDavid Greenman csr->scb_command = FXP_SCB_COMMAND_RU_START; 653a17c678eSDavid Greenman } 654a17c678eSDavid Greenman } 655a17c678eSDavid Greenman } 656a17c678eSDavid Greenman } 657a17c678eSDavid Greenman 658dfe61cf1SDavid Greenman /* 659dfe61cf1SDavid Greenman * Update packet in/out/collision statistics. The i82557 doesn't 660dfe61cf1SDavid Greenman * allow you to access these counters without doing a fairly 661dfe61cf1SDavid Greenman * expensive DMA to get _all_ of the statistics it maintains, so 662dfe61cf1SDavid Greenman * we do this operation here only once per second. The statistics 663dfe61cf1SDavid Greenman * counters in the kernel are updated from the previous dump-stats 664dfe61cf1SDavid Greenman * DMA and then a new dump-stats DMA is started. The on-chip 665dfe61cf1SDavid Greenman * counters are zeroed when the DMA completes. If we can't start 666dfe61cf1SDavid Greenman * the DMA immediately, we don't wait - we just prepare to read 667dfe61cf1SDavid Greenman * them again next time. 668dfe61cf1SDavid Greenman */ 669a17c678eSDavid Greenman void 670a17c678eSDavid Greenman fxp_stats_update(arg) 671a17c678eSDavid Greenman void *arg; 672a17c678eSDavid Greenman { 673a17c678eSDavid Greenman struct fxp_softc *sc = arg; 674a17c678eSDavid Greenman struct ifnet *ifp = &sc->arpcom.ac_if; 675a17c678eSDavid Greenman struct fxp_stats *sp = sc->fxp_stats; 676a17c678eSDavid Greenman 677a17c678eSDavid Greenman ifp->if_opackets += sp->tx_good; 678a17c678eSDavid Greenman ifp->if_collisions += sp->tx_total_collisions; 679a17c678eSDavid Greenman ifp->if_ipackets += sp->rx_good; 6803ba65732SDavid Greenman ifp->if_ierrors += 6813ba65732SDavid Greenman sp->rx_crc_errors + 6823ba65732SDavid Greenman sp->rx_alignment_errors + 6833ba65732SDavid Greenman sp->rx_rnr_errors + 6843ba65732SDavid Greenman sp->rx_overrun_errors + 6853ba65732SDavid Greenman sp->rx_shortframes; 686a17c678eSDavid Greenman /* 687f9be9005SDavid Greenman * If any transmit underruns occured, bump up the transmit 688f9be9005SDavid Greenman * threshold by another 512 bytes (64 * 8). 689f9be9005SDavid Greenman */ 690f9be9005SDavid Greenman if (sp->tx_underruns) { 691f9be9005SDavid Greenman ifp->if_oerrors += sp->tx_underruns; 692f9be9005SDavid Greenman if (tx_threshold < 192) 693f9be9005SDavid Greenman tx_threshold += 64; 694f9be9005SDavid Greenman } 695f9be9005SDavid Greenman /* 6963ba65732SDavid Greenman * If there is no pending command, start another stats 6973ba65732SDavid Greenman * dump. Otherwise punt for now. 698a17c678eSDavid Greenman */ 699dfe61cf1SDavid Greenman if ((sc->csr->scb_command & FXP_SCB_COMMAND_MASK) == 0) { 700a17c678eSDavid Greenman /* 701dfe61cf1SDavid Greenman * Start another stats dump. By waiting for it to be 702dfe61cf1SDavid Greenman * accepted, we avoid having to do splhigh locking when 703dfe61cf1SDavid Greenman * writing scb_command in other parts of the driver. 704a17c678eSDavid Greenman */ 705a17c678eSDavid Greenman sc->csr->scb_command = FXP_SCB_COMMAND_CU_DUMPRESET; 7063ba65732SDavid Greenman (void) fxp_scb_wait(sc->csr); 707dfe61cf1SDavid Greenman } else { 708dfe61cf1SDavid Greenman /* 709dfe61cf1SDavid Greenman * A previous command is still waiting to be accepted. 710dfe61cf1SDavid Greenman * Just zero our copy of the stats and wait for the 7113ba65732SDavid Greenman * next timer event to update them. 712dfe61cf1SDavid Greenman */ 713dfe61cf1SDavid Greenman sp->tx_good = 0; 714f9be9005SDavid Greenman sp->tx_underruns = 0; 715dfe61cf1SDavid Greenman sp->tx_total_collisions = 0; 7163ba65732SDavid Greenman 717dfe61cf1SDavid Greenman sp->rx_good = 0; 7183ba65732SDavid Greenman sp->rx_crc_errors = 0; 7193ba65732SDavid Greenman sp->rx_alignment_errors = 0; 7203ba65732SDavid Greenman sp->rx_rnr_errors = 0; 7213ba65732SDavid Greenman sp->rx_overrun_errors = 0; 7223ba65732SDavid Greenman sp->rx_shortframes = 0;; 723dfe61cf1SDavid Greenman } 724a17c678eSDavid Greenman /* 725a17c678eSDavid Greenman * Schedule another timeout one second from now. 726a17c678eSDavid Greenman */ 727a17c678eSDavid Greenman timeout(fxp_stats_update, sc, hz); 728a17c678eSDavid Greenman } 729a17c678eSDavid Greenman 730a17c678eSDavid Greenman /* 731a17c678eSDavid Greenman * Stop the interface. Cancels the statistics updater and resets 732a17c678eSDavid Greenman * the interface. 733a17c678eSDavid Greenman */ 734a17c678eSDavid Greenman static void 7354a5f1499SDavid Greenman fxp_stop(sc) 7364a5f1499SDavid Greenman struct fxp_softc *sc; 737a17c678eSDavid Greenman { 738a17c678eSDavid Greenman struct ifnet *ifp = &sc->arpcom.ac_if; 7393ba65732SDavid Greenman struct fxp_cb_tx *txp; 7403ba65732SDavid Greenman int i; 741a17c678eSDavid Greenman 742a17c678eSDavid Greenman /* 743a17c678eSDavid Greenman * Cancel stats updater. 744a17c678eSDavid Greenman */ 745a17c678eSDavid Greenman untimeout(fxp_stats_update, sc); 7463ba65732SDavid Greenman 7473ba65732SDavid Greenman /* 7483ba65732SDavid Greenman * Issue software reset 7493ba65732SDavid Greenman */ 750a17c678eSDavid Greenman sc->csr->port = 0; 751a17c678eSDavid Greenman DELAY(10); 752a17c678eSDavid Greenman 7533ba65732SDavid Greenman /* 7543ba65732SDavid Greenman * Release any xmit buffers. 7553ba65732SDavid Greenman */ 7563ba65732SDavid Greenman for (txp = sc->cbl_first; txp != NULL && txp->mb_head != NULL; 7573ba65732SDavid Greenman txp = txp->next) { 7583ba65732SDavid Greenman m_freem(txp->mb_head); 7593ba65732SDavid Greenman txp->mb_head = NULL; 7603ba65732SDavid Greenman } 7613ba65732SDavid Greenman sc->tx_queued = 0; 7623ba65732SDavid Greenman 7633ba65732SDavid Greenman /* 7643ba65732SDavid Greenman * Free all the receive buffers then reallocate/reinitialize 7653ba65732SDavid Greenman */ 7663ba65732SDavid Greenman if (sc->rfa_headm != NULL) 7673ba65732SDavid Greenman m_freem(sc->rfa_headm); 7683ba65732SDavid Greenman sc->rfa_headm = NULL; 7693ba65732SDavid Greenman sc->rfa_tailm = NULL; 7703ba65732SDavid Greenman for (i = 0; i < FXP_NRFABUFS; i++) { 7713ba65732SDavid Greenman if (fxp_add_rfabuf(sc, NULL) != 0) { 7723ba65732SDavid Greenman /* 7733ba65732SDavid Greenman * This "can't happen" - we're at splimp() 7743ba65732SDavid Greenman * and we just freed all the buffers we need 7753ba65732SDavid Greenman * above. 7763ba65732SDavid Greenman */ 7773ba65732SDavid Greenman panic("fxp_stop: no buffers!"); 7783ba65732SDavid Greenman } 7793ba65732SDavid Greenman } 7803ba65732SDavid Greenman 7813ba65732SDavid Greenman ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); 7823ba65732SDavid Greenman ifp->if_timer = 0; 783a17c678eSDavid Greenman } 784a17c678eSDavid Greenman 785a17c678eSDavid Greenman /* 786a17c678eSDavid Greenman * Watchdog/transmission transmit timeout handler. Called when a 787a17c678eSDavid Greenman * transmission is started on the interface, but no interrupt is 788a17c678eSDavid Greenman * received before the timeout. This usually indicates that the 789a17c678eSDavid Greenman * card has wedged for some reason. 790a17c678eSDavid Greenman */ 791a17c678eSDavid Greenman static void 7924a5f1499SDavid Greenman fxp_watchdog(ifp) 7934a5f1499SDavid Greenman struct ifnet *ifp; 794a17c678eSDavid Greenman { 7954a5f1499SDavid Greenman log(LOG_ERR, "fxp%d: device timeout\n", ifp->if_unit); 7964a5f1499SDavid Greenman ifp->if_oerrors++; 797a17c678eSDavid Greenman 7984a5f1499SDavid Greenman fxp_init(ifp); 799a17c678eSDavid Greenman } 800a17c678eSDavid Greenman 801a17c678eSDavid Greenman static void 8024a5f1499SDavid Greenman fxp_init(ifp) 8034a5f1499SDavid Greenman struct ifnet *ifp; 804a17c678eSDavid Greenman { 8059b44ff22SGarrett Wollman struct fxp_softc *sc = ifp->if_softc; 806a17c678eSDavid Greenman struct fxp_cb_config *cbp; 807a17c678eSDavid Greenman struct fxp_cb_ias *cb_ias; 808a17c678eSDavid Greenman struct fxp_cb_tx *txp; 809a17c678eSDavid Greenman struct fxp_csr *csr = sc->csr; 810a17c678eSDavid Greenman int i, s, mcast, prm; 811a17c678eSDavid Greenman 812a17c678eSDavid Greenman s = splimp(); 813a17c678eSDavid Greenman /* 8143ba65732SDavid Greenman * Cancel any pending I/O 815a17c678eSDavid Greenman */ 8163ba65732SDavid Greenman fxp_stop(sc); 817a17c678eSDavid Greenman 818a17c678eSDavid Greenman prm = (ifp->if_flags & IFF_PROMISC) ? 1 : 0; 819a17c678eSDavid Greenman sc->promisc_mode = prm; 820a17c678eSDavid Greenman /* 821a17c678eSDavid Greenman * Sleeze out here and enable reception of all multicasts if 822a17c678eSDavid Greenman * multicasts are enabled. Ideally, we'd program the multicast 823a17c678eSDavid Greenman * address filter to only accept specific multicasts. 824a17c678eSDavid Greenman */ 825a17c678eSDavid Greenman mcast = (ifp->if_flags & (IFF_MULTICAST|IFF_ALLMULTI)) ? 1 : 0; 826a17c678eSDavid Greenman 827a17c678eSDavid Greenman /* 828a17c678eSDavid Greenman * Initialize base of CBL and RFA memory. Loading with zero 829a17c678eSDavid Greenman * sets it up for regular linear addressing. 830a17c678eSDavid Greenman */ 831a17c678eSDavid Greenman csr->scb_general = 0; 832a17c678eSDavid Greenman csr->scb_command = FXP_SCB_COMMAND_CU_BASE; 833a17c678eSDavid Greenman 8343ba65732SDavid Greenman (void) fxp_scb_wait(csr); 835a17c678eSDavid Greenman csr->scb_command = FXP_SCB_COMMAND_RU_BASE; 836a17c678eSDavid Greenman 837a17c678eSDavid Greenman /* 838a17c678eSDavid Greenman * Initialize base of dump-stats buffer. 839a17c678eSDavid Greenman */ 8403ba65732SDavid Greenman (void) fxp_scb_wait(csr); 841a17c678eSDavid Greenman csr->scb_general = vtophys(sc->fxp_stats); 842a17c678eSDavid Greenman csr->scb_command = FXP_SCB_COMMAND_CU_DUMP_ADR; 843a17c678eSDavid Greenman 844a17c678eSDavid Greenman /* 845a17c678eSDavid Greenman * We temporarily use memory that contains the TxCB list to 846a17c678eSDavid Greenman * construct the config CB. The TxCB list memory is rebuilt 847a17c678eSDavid Greenman * later. 848a17c678eSDavid Greenman */ 849a17c678eSDavid Greenman cbp = (struct fxp_cb_config *) sc->cbl_base; 850a17c678eSDavid Greenman 851a17c678eSDavid Greenman /* 852a17c678eSDavid Greenman * This bcopy is kind of disgusting, but there are a bunch of must be 853a17c678eSDavid Greenman * zero and must be one bits in this structure and this is the easiest 854a17c678eSDavid Greenman * way to initialize them all to proper values. 855a17c678eSDavid Greenman */ 856a17c678eSDavid Greenman bcopy(fxp_cb_config_template, cbp, sizeof(struct fxp_cb_config)); 857a17c678eSDavid Greenman 858a17c678eSDavid Greenman cbp->cb_status = 0; 859a17c678eSDavid Greenman cbp->cb_command = FXP_CB_COMMAND_CONFIG | FXP_CB_COMMAND_EL; 860a17c678eSDavid Greenman cbp->link_addr = -1; /* (no) next command */ 861a17c678eSDavid Greenman cbp->byte_count = 22; /* (22) bytes to config */ 862a17c678eSDavid Greenman cbp->rx_fifo_limit = 8; /* rx fifo threshold */ 863a17c678eSDavid Greenman cbp->tx_fifo_limit = 0; /* tx fifo threshold */ 864a17c678eSDavid Greenman cbp->adaptive_ifs = 0; /* (no) adaptive interframe spacing */ 865a17c678eSDavid Greenman cbp->rx_dma_bytecount = 0; /* (no) rx DMA max */ 866a17c678eSDavid Greenman cbp->tx_dma_bytecount = 0; /* (no) tx DMA max */ 867a17c678eSDavid Greenman cbp->dma_bce = 1; /* (enable) dma max counters */ 868a17c678eSDavid Greenman cbp->late_scb = 0; /* (don't) defer SCB update */ 869a17c678eSDavid Greenman cbp->tno_int = 0; /* (disable) tx not okay interrupt */ 870a17c678eSDavid Greenman cbp->ci_int = 0; /* (do) interrupt on CU not active */ 871a17c678eSDavid Greenman cbp->save_bf = prm; /* save bad frames */ 872a17c678eSDavid Greenman cbp->disc_short_rx = !prm; /* discard short packets */ 873a17c678eSDavid Greenman cbp->underrun_retry = 1; /* retry mode (1) on DMA underrun */ 874a17c678eSDavid Greenman cbp->mediatype = 1; /* (MII) interface mode */ 875a17c678eSDavid Greenman cbp->nsai = 1; /* (don't) disable source addr insert */ 876a17c678eSDavid Greenman cbp->preamble_length = 2; /* (7 byte) preamble */ 877a17c678eSDavid Greenman cbp->loopback = 0; /* (don't) loopback */ 878a17c678eSDavid Greenman cbp->linear_priority = 0; /* (normal CSMA/CD operation) */ 879a17c678eSDavid Greenman cbp->linear_pri_mode = 0; /* (wait after xmit only) */ 880a17c678eSDavid Greenman cbp->interfrm_spacing = 6; /* (96 bits of) interframe spacing */ 881a17c678eSDavid Greenman cbp->promiscuous = prm; /* promiscuous mode */ 882a17c678eSDavid Greenman cbp->bcast_disable = 0; /* (don't) disable broadcasts */ 883a17c678eSDavid Greenman cbp->crscdt = 0; /* (CRS only) */ 884a17c678eSDavid Greenman cbp->stripping = !prm; /* truncate rx packet to byte count */ 885a17c678eSDavid Greenman cbp->padding = 1; /* (do) pad short tx packets */ 886a17c678eSDavid Greenman cbp->rcv_crc_xfer = 0; /* (don't) xfer CRC to host */ 887a17c678eSDavid Greenman cbp->force_fdx = 0; /* (don't) force full duplex */ 8883ba65732SDavid Greenman cbp->fdx_pin_en = 1; /* (enable) FDX# pin */ 889a17c678eSDavid Greenman cbp->multi_ia = 0; /* (don't) accept multiple IAs */ 890a17c678eSDavid Greenman cbp->mc_all = mcast; /* accept all multicasts */ 891a17c678eSDavid Greenman 892a17c678eSDavid Greenman /* 893a17c678eSDavid Greenman * Start the config command/DMA. 894a17c678eSDavid Greenman */ 8953ba65732SDavid Greenman (void) fxp_scb_wait(csr); 896a17c678eSDavid Greenman csr->scb_general = vtophys(cbp); 897a17c678eSDavid Greenman csr->scb_command = FXP_SCB_COMMAND_CU_START; 898a17c678eSDavid Greenman /* ...and wait for it to complete. */ 899a17c678eSDavid Greenman while (!(cbp->cb_status & FXP_CB_STATUS_C)); 900a17c678eSDavid Greenman 901a17c678eSDavid Greenman /* 902a17c678eSDavid Greenman * Now initialize the station address. Temporarily use the TxCB 903a17c678eSDavid Greenman * memory area like we did above for the config CB. 904a17c678eSDavid Greenman */ 905a17c678eSDavid Greenman cb_ias = (struct fxp_cb_ias *) sc->cbl_base; 906a17c678eSDavid Greenman cb_ias->cb_status = 0; 907a17c678eSDavid Greenman cb_ias->cb_command = FXP_CB_COMMAND_IAS | FXP_CB_COMMAND_EL; 908a17c678eSDavid Greenman cb_ias->link_addr = -1; 909a17c678eSDavid Greenman bcopy(sc->arpcom.ac_enaddr, (void *)cb_ias->macaddr, 910a17c678eSDavid Greenman sizeof(sc->arpcom.ac_enaddr)); 911a17c678eSDavid Greenman 912a17c678eSDavid Greenman /* 913a17c678eSDavid Greenman * Start the IAS (Individual Address Setup) command/DMA. 914a17c678eSDavid Greenman */ 9153ba65732SDavid Greenman (void) fxp_scb_wait(csr); 916a17c678eSDavid Greenman csr->scb_command = FXP_SCB_COMMAND_CU_START; 917a17c678eSDavid Greenman /* ...and wait for it to complete. */ 918a17c678eSDavid Greenman while (!(cb_ias->cb_status & FXP_CB_STATUS_C)); 919a17c678eSDavid Greenman 920a17c678eSDavid Greenman /* 921a17c678eSDavid Greenman * Initialize transmit control block (TxCB) list. 922a17c678eSDavid Greenman */ 923a17c678eSDavid Greenman 924a17c678eSDavid Greenman txp = sc->cbl_base; 925a17c678eSDavid Greenman bzero(txp, sizeof(struct fxp_cb_tx) * FXP_NTXCB); 926a17c678eSDavid Greenman for (i = 0; i < FXP_NTXCB; i++) { 927a17c678eSDavid Greenman txp[i].cb_status = FXP_CB_STATUS_C | FXP_CB_STATUS_OK; 928a17c678eSDavid Greenman txp[i].cb_command = FXP_CB_COMMAND_NOP; 929a17c678eSDavid Greenman txp[i].link_addr = vtophys(&txp[(i + 1) & FXP_TXCB_MASK]); 930a17c678eSDavid Greenman txp[i].tbd_array_addr = vtophys(&txp[i].tbd[0]); 931a17c678eSDavid Greenman txp[i].next = &txp[(i + 1) & FXP_TXCB_MASK]; 932a17c678eSDavid Greenman } 933a17c678eSDavid Greenman /* 934a17c678eSDavid Greenman * Set the stop flag on the first TxCB and start the control 935a17c678eSDavid Greenman * unit. It will execute the NOP and then suspend. 936a17c678eSDavid Greenman */ 937a17c678eSDavid Greenman txp->cb_command = FXP_CB_COMMAND_NOP | FXP_CB_COMMAND_S; 938a17c678eSDavid Greenman sc->cbl_first = sc->cbl_last = txp; 939a17c678eSDavid Greenman sc->tx_queued = 0; 940a17c678eSDavid Greenman 9413ba65732SDavid Greenman (void) fxp_scb_wait(csr); 942a17c678eSDavid Greenman csr->scb_command = FXP_SCB_COMMAND_CU_START; 943a17c678eSDavid Greenman 944a17c678eSDavid Greenman /* 945a17c678eSDavid Greenman * Initialize receiver buffer area - RFA. 946a17c678eSDavid Greenman */ 9473ba65732SDavid Greenman (void) fxp_scb_wait(csr); 948dfe61cf1SDavid Greenman csr->scb_general = vtophys(sc->rfa_headm->m_ext.ext_buf); 949a17c678eSDavid Greenman csr->scb_command = FXP_SCB_COMMAND_RU_START; 950a17c678eSDavid Greenman 951a17c678eSDavid Greenman ifp->if_flags |= IFF_RUNNING; 952a17c678eSDavid Greenman ifp->if_flags &= ~IFF_OACTIVE; 953a17c678eSDavid Greenman splx(s); 954a17c678eSDavid Greenman 955a17c678eSDavid Greenman /* 956a17c678eSDavid Greenman * Start stats updater. 957a17c678eSDavid Greenman */ 958a17c678eSDavid Greenman timeout(fxp_stats_update, sc, hz); 959a17c678eSDavid Greenman } 960a17c678eSDavid Greenman 961a17c678eSDavid Greenman /* 962a17c678eSDavid Greenman * Add a buffer to the end of the RFA buffer list. 963a17c678eSDavid Greenman * Return 0 if successful, 1 for failure. A failure results in 964a17c678eSDavid Greenman * adding the 'oldm' (if non-NULL) on to the end of the list - 965a17c678eSDavid Greenman * tossing out it's old contents and recycling it. 966a17c678eSDavid Greenman * The RFA struct is stuck at the beginning of mbuf cluster and the 967a17c678eSDavid Greenman * data pointer is fixed up to point just past it. 968a17c678eSDavid Greenman */ 969a17c678eSDavid Greenman static int 970a17c678eSDavid Greenman fxp_add_rfabuf(sc, oldm) 971a17c678eSDavid Greenman struct fxp_softc *sc; 972a17c678eSDavid Greenman struct mbuf *oldm; 973a17c678eSDavid Greenman { 974a17c678eSDavid Greenman struct mbuf *m; 975a17c678eSDavid Greenman struct fxp_rfa *rfa, *p_rfa; 976a17c678eSDavid Greenman 977a17c678eSDavid Greenman MGETHDR(m, M_DONTWAIT, MT_DATA); 978a17c678eSDavid Greenman if (m != NULL) { 979a17c678eSDavid Greenman MCLGET(m, M_DONTWAIT); 980a17c678eSDavid Greenman if ((m->m_flags & M_EXT) == 0) { 981a17c678eSDavid Greenman m_freem(m); 982eadd5e3aSDavid Greenman if (oldm == NULL) 983eadd5e3aSDavid Greenman return 1; 984a17c678eSDavid Greenman m = oldm; 985eadd5e3aSDavid Greenman m->m_data = m->m_ext.ext_buf; 986a17c678eSDavid Greenman } 987a17c678eSDavid Greenman } else { 988eadd5e3aSDavid Greenman if (oldm == NULL) 989a17c678eSDavid Greenman return 1; 990eadd5e3aSDavid Greenman m = oldm; 991eadd5e3aSDavid Greenman m->m_data = m->m_ext.ext_buf; 992eadd5e3aSDavid Greenman } 993eadd5e3aSDavid Greenman /* 994eadd5e3aSDavid Greenman * Get a pointer to the base of the mbuf cluster and move 995eadd5e3aSDavid Greenman * data start past it. 996eadd5e3aSDavid Greenman */ 997a17c678eSDavid Greenman rfa = mtod(m, struct fxp_rfa *); 998eadd5e3aSDavid Greenman m->m_data += sizeof(struct fxp_rfa); 999eadd5e3aSDavid Greenman rfa->size = MCLBYTES - sizeof(struct fxp_rfa); 1000eadd5e3aSDavid Greenman 1001a17c678eSDavid Greenman rfa->rfa_status = 0; 1002a17c678eSDavid Greenman rfa->rfa_control = FXP_RFA_CONTROL_EL; 1003a17c678eSDavid Greenman rfa->link_addr = -1; 1004a17c678eSDavid Greenman rfa->rbd_addr = -1; 1005a17c678eSDavid Greenman rfa->actual_size = 0; 1006dfe61cf1SDavid Greenman /* 1007dfe61cf1SDavid Greenman * If there are other buffers already on the list, attach this 1008dfe61cf1SDavid Greenman * one to the end by fixing up the tail to point to this one. 1009dfe61cf1SDavid Greenman */ 1010a17c678eSDavid Greenman if (sc->rfa_headm != NULL) { 1011dfe61cf1SDavid Greenman p_rfa = (struct fxp_rfa *) sc->rfa_tailm->m_ext.ext_buf; 1012a17c678eSDavid Greenman sc->rfa_tailm->m_next = m; 1013a17c678eSDavid Greenman p_rfa->link_addr = vtophys(rfa); 1014a17c678eSDavid Greenman p_rfa->rfa_control &= ~FXP_RFA_CONTROL_EL; 1015a17c678eSDavid Greenman } else { 1016a17c678eSDavid Greenman sc->rfa_headm = m; 1017a17c678eSDavid Greenman } 1018a17c678eSDavid Greenman sc->rfa_tailm = m; 1019a17c678eSDavid Greenman 1020dfe61cf1SDavid Greenman return (m == oldm); 1021a17c678eSDavid Greenman } 1022a17c678eSDavid Greenman 1023a17c678eSDavid Greenman static int 1024a17c678eSDavid Greenman fxp_ioctl(ifp, command, data) 1025a17c678eSDavid Greenman struct ifnet *ifp; 1026a17c678eSDavid Greenman int command; 1027a17c678eSDavid Greenman caddr_t data; 1028a17c678eSDavid Greenman { 1029a17c678eSDavid Greenman struct ifaddr *ifa = (struct ifaddr *) data; 10309b44ff22SGarrett Wollman struct fxp_softc *sc = ifp->if_softc; 1031a17c678eSDavid Greenman struct ifreq *ifr = (struct ifreq *) data; 1032a17c678eSDavid Greenman int s, error = 0; 1033a17c678eSDavid Greenman 1034a17c678eSDavid Greenman s = splimp(); 1035a17c678eSDavid Greenman 1036a17c678eSDavid Greenman switch (command) { 1037a17c678eSDavid Greenman 1038a17c678eSDavid Greenman case SIOCSIFADDR: 1039a17c678eSDavid Greenman ifp->if_flags |= IFF_UP; 1040a17c678eSDavid Greenman 1041a17c678eSDavid Greenman switch (ifa->ifa_addr->sa_family) { 1042a17c678eSDavid Greenman #ifdef INET 1043a17c678eSDavid Greenman case AF_INET: 10444a5f1499SDavid Greenman fxp_init(ifp); /* before arpwhohas */ 1045a17c678eSDavid Greenman arp_ifinit((struct arpcom *)ifp, ifa); 1046a17c678eSDavid Greenman break; 1047a17c678eSDavid Greenman #endif 1048a17c678eSDavid Greenman #ifdef IPX 1049a17c678eSDavid Greenman /* 1050a17c678eSDavid Greenman * XXX - This code is probably wrong 1051a17c678eSDavid Greenman */ 1052a17c678eSDavid Greenman case AF_IPX: 1053a17c678eSDavid Greenman { 1054a17c678eSDavid Greenman register struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr); 1055a17c678eSDavid Greenman 1056a17c678eSDavid Greenman if (ipx_nullhost(*ina)) 1057a17c678eSDavid Greenman ina->x_host = 1058a17c678eSDavid Greenman *(union ipx_host *) (sc->arpcom.ac_enaddr); 1059a17c678eSDavid Greenman else { 1060a17c678eSDavid Greenman bcopy((caddr_t) ina->x_host.c_host, 1061a17c678eSDavid Greenman (caddr_t) sc->arpcom.ac_enaddr, 1062a17c678eSDavid Greenman sizeof(sc->arpcom.ac_enaddr)); 1063a17c678eSDavid Greenman } 1064a17c678eSDavid Greenman 1065a17c678eSDavid Greenman /* 1066a17c678eSDavid Greenman * Set new address 1067a17c678eSDavid Greenman */ 10684a5f1499SDavid Greenman fxp_init(ifp); 1069a17c678eSDavid Greenman break; 1070a17c678eSDavid Greenman } 1071a17c678eSDavid Greenman #endif 1072a17c678eSDavid Greenman #ifdef NS 1073a17c678eSDavid Greenman /* 1074a17c678eSDavid Greenman * XXX - This code is probably wrong 1075a17c678eSDavid Greenman */ 1076a17c678eSDavid Greenman case AF_NS: 1077a17c678eSDavid Greenman { 1078a17c678eSDavid Greenman register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); 1079a17c678eSDavid Greenman 1080a17c678eSDavid Greenman if (ns_nullhost(*ina)) 1081a17c678eSDavid Greenman ina->x_host = 1082a17c678eSDavid Greenman *(union ns_host *) (sc->arpcom.ac_enaddr); 1083a17c678eSDavid Greenman else { 1084a17c678eSDavid Greenman bcopy((caddr_t) ina->x_host.c_host, 1085a17c678eSDavid Greenman (caddr_t) sc->arpcom.ac_enaddr, 1086a17c678eSDavid Greenman sizeof(sc->arpcom.ac_enaddr)); 1087a17c678eSDavid Greenman } 1088a17c678eSDavid Greenman 1089a17c678eSDavid Greenman /* 1090a17c678eSDavid Greenman * Set new address 1091a17c678eSDavid Greenman */ 10924a5f1499SDavid Greenman fxp_init(ifp); 1093a17c678eSDavid Greenman break; 1094a17c678eSDavid Greenman } 1095a17c678eSDavid Greenman #endif 1096a17c678eSDavid Greenman default: 10974a5f1499SDavid Greenman fxp_init(ifp); 1098a17c678eSDavid Greenman break; 1099a17c678eSDavid Greenman } 1100a17c678eSDavid Greenman break; 1101a17c678eSDavid Greenman 1102a17c678eSDavid Greenman case SIOCGIFADDR: 1103a17c678eSDavid Greenman { 1104a17c678eSDavid Greenman struct sockaddr *sa; 1105a17c678eSDavid Greenman 1106a17c678eSDavid Greenman sa = (struct sockaddr *) & ifr->ifr_data; 1107a17c678eSDavid Greenman bcopy((caddr_t) sc->arpcom.ac_enaddr, 1108a17c678eSDavid Greenman (caddr_t) sa->sa_data, sizeof(sc->arpcom.ac_enaddr)); 1109a17c678eSDavid Greenman } 1110a17c678eSDavid Greenman break; 1111a17c678eSDavid Greenman 1112a17c678eSDavid Greenman case SIOCSIFFLAGS: 1113a17c678eSDavid Greenman 1114a17c678eSDavid Greenman /* 1115a17c678eSDavid Greenman * If interface is marked up and not running, then start it. 1116a17c678eSDavid Greenman * If it is marked down and running, stop it. 1117a17c678eSDavid Greenman * XXX If it's up then re-initialize it. This is so flags 1118a17c678eSDavid Greenman * such as IFF_PROMISC are handled. 1119a17c678eSDavid Greenman */ 1120a17c678eSDavid Greenman if (ifp->if_flags & IFF_UP) { 11214a5f1499SDavid Greenman fxp_init(ifp); 1122a17c678eSDavid Greenman } else { 1123a17c678eSDavid Greenman if (ifp->if_flags & IFF_RUNNING) 11244a5f1499SDavid Greenman fxp_stop(sc); 1125a17c678eSDavid Greenman } 1126a17c678eSDavid Greenman break; 1127a17c678eSDavid Greenman 1128a17c678eSDavid Greenman case SIOCADDMULTI: 1129a17c678eSDavid Greenman case SIOCDELMULTI: 1130a17c678eSDavid Greenman /* 1131a17c678eSDavid Greenman * Update out multicast list. 1132a17c678eSDavid Greenman */ 1133a17c678eSDavid Greenman error = (command == SIOCADDMULTI) ? 1134a17c678eSDavid Greenman ether_addmulti(ifr, &sc->arpcom) : 1135a17c678eSDavid Greenman ether_delmulti(ifr, &sc->arpcom); 1136a17c678eSDavid Greenman 1137a17c678eSDavid Greenman if (error == ENETRESET) { 1138a17c678eSDavid Greenman /* 1139a17c678eSDavid Greenman * Multicast list has changed; set the hardware filter 1140a17c678eSDavid Greenman * accordingly. 1141a17c678eSDavid Greenman */ 11424a5f1499SDavid Greenman fxp_init(ifp); 1143a17c678eSDavid Greenman 1144a17c678eSDavid Greenman error = 0; 1145a17c678eSDavid Greenman } 1146a17c678eSDavid Greenman break; 1147a17c678eSDavid Greenman 1148a17c678eSDavid Greenman case SIOCSIFMTU: 1149a17c678eSDavid Greenman /* 1150a17c678eSDavid Greenman * Set the interface MTU. 1151a17c678eSDavid Greenman */ 1152a17c678eSDavid Greenman if (ifr->ifr_mtu > ETHERMTU) { 1153a17c678eSDavid Greenman error = EINVAL; 1154a17c678eSDavid Greenman } else { 1155a17c678eSDavid Greenman ifp->if_mtu = ifr->ifr_mtu; 1156a17c678eSDavid Greenman } 1157a17c678eSDavid Greenman break; 1158a17c678eSDavid Greenman 1159a17c678eSDavid Greenman default: 1160a17c678eSDavid Greenman error = EINVAL; 1161a17c678eSDavid Greenman } 1162a17c678eSDavid Greenman (void) splx(s); 1163a17c678eSDavid Greenman return (error); 1164a17c678eSDavid Greenman } 1165