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