1a17c678eSDavid Greenman /* 2a17c678eSDavid Greenman * Copyright (c) 1995, David Greenman 3a17c678eSDavid Greenman * All rights reserved. 4a17c678eSDavid Greenman * 594927790SDavid Greenman * Modifications to support media selection: 6ba8c6fd5SDavid Greenman * Copyright (c) 1997 Jason R. Thorpe. All rights reserved. 7ba8c6fd5SDavid Greenman * 8a17c678eSDavid Greenman * Redistribution and use in source and binary forms, with or without 9a17c678eSDavid Greenman * modification, are permitted provided that the following conditions 10a17c678eSDavid Greenman * are met: 11a17c678eSDavid Greenman * 1. Redistributions of source code must retain the above copyright 12a17c678eSDavid Greenman * notice unmodified, this list of conditions, and the following 13a17c678eSDavid Greenman * disclaimer. 14a17c678eSDavid Greenman * 2. Redistributions in binary form must reproduce the above copyright 15a17c678eSDavid Greenman * notice, this list of conditions and the following disclaimer in the 16a17c678eSDavid Greenman * documentation and/or other materials provided with the distribution. 17a17c678eSDavid Greenman * 18a17c678eSDavid Greenman * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19a17c678eSDavid Greenman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20a17c678eSDavid Greenman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21a17c678eSDavid Greenman * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22a17c678eSDavid Greenman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23a17c678eSDavid Greenman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24a17c678eSDavid Greenman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25a17c678eSDavid Greenman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26a17c678eSDavid Greenman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27a17c678eSDavid Greenman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28a17c678eSDavid Greenman * SUCH DAMAGE. 29a17c678eSDavid Greenman * 30c3aac50fSPeter Wemm * $FreeBSD$ 31a17c678eSDavid Greenman */ 32a17c678eSDavid Greenman 33a17c678eSDavid Greenman /* 34ae12cddaSDavid Greenman * Intel EtherExpress Pro/100B PCI Fast Ethernet driver 35a17c678eSDavid Greenman */ 36a17c678eSDavid Greenman 37a17c678eSDavid Greenman #include <sys/param.h> 38a17c678eSDavid Greenman #include <sys/systm.h> 39a17c678eSDavid Greenman #include <sys/mbuf.h> 40a17c678eSDavid Greenman #include <sys/malloc.h> 4135e0e5b3SJohn Baldwin #include <sys/mutex.h> 42a17c678eSDavid Greenman #include <sys/kernel.h> 434458ac71SBruce Evans #include <sys/socket.h> 44a17c678eSDavid Greenman 45a17c678eSDavid Greenman #include <net/if.h> 46397f9dfeSDavid Greenman #include <net/if_dl.h> 47ba8c6fd5SDavid Greenman #include <net/if_media.h> 48a17c678eSDavid Greenman 49a17c678eSDavid Greenman #ifdef NS 50a17c678eSDavid Greenman #include <netns/ns.h> 51a17c678eSDavid Greenman #include <netns/ns_if.h> 52a17c678eSDavid Greenman #endif 53a17c678eSDavid Greenman 54a17c678eSDavid Greenman #include <net/bpf.h> 55ba8c6fd5SDavid Greenman #include <sys/sockio.h> 566182fdbdSPeter Wemm #include <sys/bus.h> 576182fdbdSPeter Wemm #include <machine/bus.h> 586182fdbdSPeter Wemm #include <sys/rman.h> 596182fdbdSPeter Wemm #include <machine/resource.h> 60ba8c6fd5SDavid Greenman 611d5e9e22SEivind Eklund #include <net/ethernet.h> 621d5e9e22SEivind Eklund #include <net/if_arp.h> 63ba8c6fd5SDavid Greenman 64dfe61cf1SDavid Greenman #include <vm/vm.h> /* for vtophys */ 65efeaf95aSDavid Greenman #include <vm/pmap.h> /* for vtophys */ 66a17c678eSDavid Greenman 67a17c678eSDavid Greenman #include <pci/pcivar.h> 68df373873SWes Peters #include <pci/pcireg.h> /* for PCIM_CMD_xxx */ 69a17c678eSDavid Greenman #include <pci/if_fxpreg.h> 70ba8c6fd5SDavid Greenman #include <pci/if_fxpvar.h> 71a17c678eSDavid Greenman 724fc1dda9SAndrew Gallatin #ifdef __alpha__ /* XXX */ 734fc1dda9SAndrew Gallatin /* XXX XXX NEED REAL DMA MAPPING SUPPORT XXX XXX */ 744fc1dda9SAndrew Gallatin #undef vtophys 754fc1dda9SAndrew Gallatin #define vtophys(va) alpha_XXX_dmamap((vm_offset_t)(va)) 764fc1dda9SAndrew Gallatin #endif /* __alpha__ */ 774fc1dda9SAndrew Gallatin 78ba8c6fd5SDavid Greenman /* 79ba8c6fd5SDavid Greenman * NOTE! On the Alpha, we have an alignment constraint. The 80ba8c6fd5SDavid Greenman * card DMAs the packet immediately following the RFA. However, 81ba8c6fd5SDavid Greenman * the first thing in the packet is a 14-byte Ethernet header. 82ba8c6fd5SDavid Greenman * This means that the packet is misaligned. To compensate, 83ba8c6fd5SDavid Greenman * we actually offset the RFA 2 bytes into the cluster. This 84ba8c6fd5SDavid Greenman * alignes the packet after the Ethernet header at a 32-bit 85ba8c6fd5SDavid Greenman * boundary. HOWEVER! This means that the RFA is misaligned! 86ba8c6fd5SDavid Greenman */ 87ba8c6fd5SDavid Greenman #define RFA_ALIGNMENT_FUDGE 2 88ba8c6fd5SDavid Greenman 89ba8c6fd5SDavid Greenman /* 90ba8c6fd5SDavid Greenman * Inline function to copy a 16-bit aligned 32-bit quantity. 91ba8c6fd5SDavid Greenman */ 92ba8c6fd5SDavid Greenman static __inline void fxp_lwcopy __P((volatile u_int32_t *, 93ba8c6fd5SDavid Greenman volatile u_int32_t *)); 94ba8c6fd5SDavid Greenman static __inline void 95ba8c6fd5SDavid Greenman fxp_lwcopy(src, dst) 96ba8c6fd5SDavid Greenman volatile u_int32_t *src, *dst; 97ba8c6fd5SDavid Greenman { 98aed53495SDavid Greenman #ifdef __i386__ 99aed53495SDavid Greenman *dst = *src; 100aed53495SDavid Greenman #else 101fe08c21aSMatthew Dillon volatile u_int16_t *a = (volatile u_int16_t *)src; 102fe08c21aSMatthew Dillon volatile u_int16_t *b = (volatile u_int16_t *)dst; 103ba8c6fd5SDavid Greenman 104ba8c6fd5SDavid Greenman b[0] = a[0]; 105ba8c6fd5SDavid Greenman b[1] = a[1]; 106aed53495SDavid Greenman #endif 107ba8c6fd5SDavid Greenman } 108a17c678eSDavid Greenman 109a17c678eSDavid Greenman /* 110a17c678eSDavid Greenman * Template for default configuration parameters. 111a17c678eSDavid Greenman * See struct fxp_cb_config for the bit definitions. 112a17c678eSDavid Greenman */ 113a17c678eSDavid Greenman static u_char fxp_cb_config_template[] = { 114a17c678eSDavid Greenman 0x0, 0x0, /* cb_status */ 115a17c678eSDavid Greenman 0x80, 0x2, /* cb_command */ 116a17c678eSDavid Greenman 0xff, 0xff, 0xff, 0xff, /* link_addr */ 117a17c678eSDavid Greenman 0x16, /* 0 */ 118a17c678eSDavid Greenman 0x8, /* 1 */ 119a17c678eSDavid Greenman 0x0, /* 2 */ 120a17c678eSDavid Greenman 0x0, /* 3 */ 121a17c678eSDavid Greenman 0x0, /* 4 */ 122a17c678eSDavid Greenman 0x80, /* 5 */ 123a17c678eSDavid Greenman 0xb2, /* 6 */ 124a17c678eSDavid Greenman 0x3, /* 7 */ 125a17c678eSDavid Greenman 0x1, /* 8 */ 126a17c678eSDavid Greenman 0x0, /* 9 */ 127a17c678eSDavid Greenman 0x26, /* 10 */ 128a17c678eSDavid Greenman 0x0, /* 11 */ 129a17c678eSDavid Greenman 0x60, /* 12 */ 130a17c678eSDavid Greenman 0x0, /* 13 */ 131a17c678eSDavid Greenman 0xf2, /* 14 */ 132a17c678eSDavid Greenman 0x48, /* 15 */ 133a17c678eSDavid Greenman 0x0, /* 16 */ 134a17c678eSDavid Greenman 0x40, /* 17 */ 135a17c678eSDavid Greenman 0xf3, /* 18 */ 136a17c678eSDavid Greenman 0x0, /* 19 */ 137a17c678eSDavid Greenman 0x3f, /* 20 */ 138397f9dfeSDavid Greenman 0x5 /* 21 */ 139a17c678eSDavid Greenman }; 140a17c678eSDavid Greenman 141ba8c6fd5SDavid Greenman /* Supported media types. */ 142ba8c6fd5SDavid Greenman struct fxp_supported_media { 143ba8c6fd5SDavid Greenman const int fsm_phy; /* PHY type */ 144ba8c6fd5SDavid Greenman const int *fsm_media; /* the media array */ 145ba8c6fd5SDavid Greenman const int fsm_nmedia; /* the number of supported media */ 146ba8c6fd5SDavid Greenman const int fsm_defmedia; /* default media for this PHY */ 147ba8c6fd5SDavid Greenman }; 148ba8c6fd5SDavid Greenman 149303b270bSEivind Eklund static const int fxp_media_standard[] = { 150ba8c6fd5SDavid Greenman IFM_ETHER|IFM_10_T, 151ba8c6fd5SDavid Greenman IFM_ETHER|IFM_10_T|IFM_FDX, 152ba8c6fd5SDavid Greenman IFM_ETHER|IFM_100_TX, 153ba8c6fd5SDavid Greenman IFM_ETHER|IFM_100_TX|IFM_FDX, 154ba8c6fd5SDavid Greenman IFM_ETHER|IFM_AUTO, 155ba8c6fd5SDavid Greenman }; 156ba8c6fd5SDavid Greenman #define FXP_MEDIA_STANDARD_DEFMEDIA (IFM_ETHER|IFM_AUTO) 157ba8c6fd5SDavid Greenman 158303b270bSEivind Eklund static const int fxp_media_default[] = { 159ba8c6fd5SDavid Greenman IFM_ETHER|IFM_MANUAL, /* XXX IFM_AUTO ? */ 160ba8c6fd5SDavid Greenman }; 161ba8c6fd5SDavid Greenman #define FXP_MEDIA_DEFAULT_DEFMEDIA (IFM_ETHER|IFM_MANUAL) 162ba8c6fd5SDavid Greenman 163303b270bSEivind Eklund static const struct fxp_supported_media fxp_media[] = { 164ba8c6fd5SDavid Greenman { FXP_PHY_DP83840, fxp_media_standard, 165ba8c6fd5SDavid Greenman sizeof(fxp_media_standard) / sizeof(fxp_media_standard[0]), 166ba8c6fd5SDavid Greenman FXP_MEDIA_STANDARD_DEFMEDIA }, 167ba8c6fd5SDavid Greenman { FXP_PHY_DP83840A, fxp_media_standard, 168ba8c6fd5SDavid Greenman sizeof(fxp_media_standard) / sizeof(fxp_media_standard[0]), 169ba8c6fd5SDavid Greenman FXP_MEDIA_STANDARD_DEFMEDIA }, 17092924291SDavid Greenman { FXP_PHY_82553A, fxp_media_standard, 17192924291SDavid Greenman sizeof(fxp_media_standard) / sizeof(fxp_media_standard[0]), 17292924291SDavid Greenman FXP_MEDIA_STANDARD_DEFMEDIA }, 17392924291SDavid Greenman { FXP_PHY_82553C, fxp_media_standard, 17492924291SDavid Greenman sizeof(fxp_media_standard) / sizeof(fxp_media_standard[0]), 17592924291SDavid Greenman FXP_MEDIA_STANDARD_DEFMEDIA }, 176ba8c6fd5SDavid Greenman { FXP_PHY_82555, fxp_media_standard, 177ba8c6fd5SDavid Greenman sizeof(fxp_media_standard) / sizeof(fxp_media_standard[0]), 178ba8c6fd5SDavid Greenman FXP_MEDIA_STANDARD_DEFMEDIA }, 17992924291SDavid Greenman { FXP_PHY_82555B, fxp_media_standard, 18092924291SDavid Greenman sizeof(fxp_media_standard) / sizeof(fxp_media_standard[0]), 18192924291SDavid Greenman FXP_MEDIA_STANDARD_DEFMEDIA }, 182ba8c6fd5SDavid Greenman { FXP_PHY_80C24, fxp_media_default, 183ba8c6fd5SDavid Greenman sizeof(fxp_media_default) / sizeof(fxp_media_default[0]), 184ba8c6fd5SDavid Greenman FXP_MEDIA_DEFAULT_DEFMEDIA }, 185ba8c6fd5SDavid Greenman }; 186ba8c6fd5SDavid Greenman #define NFXPMEDIA (sizeof(fxp_media) / sizeof(fxp_media[0])) 187ba8c6fd5SDavid Greenman 188ba8c6fd5SDavid Greenman static int fxp_mediachange __P((struct ifnet *)); 189ba8c6fd5SDavid Greenman static void fxp_mediastatus __P((struct ifnet *, struct ifmediareq *)); 190303b270bSEivind Eklund static void fxp_set_media __P((struct fxp_softc *, int)); 191c1087c13SBruce Evans static __inline void fxp_scb_wait __P((struct fxp_softc *)); 1927dced78aSDavid Greenman static __inline void fxp_dma_wait __P((volatile u_int16_t *, struct fxp_softc *sc)); 19394927790SDavid Greenman static void fxp_intr __P((void *)); 194a17c678eSDavid Greenman static void fxp_start __P((struct ifnet *)); 195ba8c6fd5SDavid Greenman static int fxp_ioctl __P((struct ifnet *, 19694927790SDavid Greenman u_long, caddr_t)); 197fb583156SDavid Greenman static void fxp_init __P((void *)); 1984a5f1499SDavid Greenman static void fxp_stop __P((struct fxp_softc *)); 1994a5f1499SDavid Greenman static void fxp_watchdog __P((struct ifnet *)); 200a17c678eSDavid Greenman static int fxp_add_rfabuf __P((struct fxp_softc *, struct mbuf *)); 201ba8c6fd5SDavid Greenman static int fxp_mdi_read __P((struct fxp_softc *, int, int)); 202ba8c6fd5SDavid Greenman static void fxp_mdi_write __P((struct fxp_softc *, int, int, int)); 203e9bf2fa7SDavid Greenman static void fxp_autosize_eeprom __P((struct fxp_softc *)); 204ba8c6fd5SDavid Greenman static void fxp_read_eeprom __P((struct fxp_softc *, u_int16_t *, 205ba8c6fd5SDavid Greenman int, int)); 206ba8c6fd5SDavid Greenman static int fxp_attach_common __P((struct fxp_softc *, u_int8_t *)); 207303b270bSEivind Eklund static void fxp_stats_update __P((void *)); 208397f9dfeSDavid Greenman static void fxp_mc_setup __P((struct fxp_softc *)); 209a17c678eSDavid Greenman 210a17c678eSDavid Greenman /* 211f9be9005SDavid Greenman * Set initial transmit threshold at 64 (512 bytes). This is 212f9be9005SDavid Greenman * increased by 64 (512 bytes) at a time, to maximum of 192 213f9be9005SDavid Greenman * (1536 bytes), if an underrun occurs. 214f9be9005SDavid Greenman */ 215f9be9005SDavid Greenman static int tx_threshold = 64; 216f9be9005SDavid Greenman 217f9be9005SDavid Greenman /* 218a17c678eSDavid Greenman * Number of transmit control blocks. This determines the number 219a17c678eSDavid Greenman * of transmit buffers that can be chained in the CB list. 220a17c678eSDavid Greenman * This must be a power of two. 221a17c678eSDavid Greenman */ 2221cd443acSDavid Greenman #define FXP_NTXCB 128 223a17c678eSDavid Greenman 224a17c678eSDavid Greenman /* 2253114fdb4SDavid Greenman * Number of completed TX commands at which point an interrupt 2263114fdb4SDavid Greenman * will be generated to garbage collect the attached buffers. 2273114fdb4SDavid Greenman * Must be at least one less than FXP_NTXCB, and should be 2283114fdb4SDavid Greenman * enough less so that the transmitter doesn't becomes idle 2293114fdb4SDavid Greenman * during the buffer rundown (which would reduce performance). 2303114fdb4SDavid Greenman */ 2313114fdb4SDavid Greenman #define FXP_CXINT_THRESH 120 2323114fdb4SDavid Greenman 2333114fdb4SDavid Greenman /* 234a17c678eSDavid Greenman * TxCB list index mask. This is used to do list wrap-around. 235a17c678eSDavid Greenman */ 236a17c678eSDavid Greenman #define FXP_TXCB_MASK (FXP_NTXCB - 1) 237a17c678eSDavid Greenman 238a17c678eSDavid Greenman /* 239a17c678eSDavid Greenman * Number of receive frame area buffers. These are large so chose 240a17c678eSDavid Greenman * wisely. 241a17c678eSDavid Greenman */ 2426f5818b0SDavid Greenman #define FXP_NRFABUFS 64 243a17c678eSDavid Greenman 244dfe61cf1SDavid Greenman /* 245397f9dfeSDavid Greenman * Maximum number of seconds that the receiver can be idle before we 246397f9dfeSDavid Greenman * assume it's dead and attempt to reset it by reprogramming the 247397f9dfeSDavid Greenman * multicast filter. This is part of a work-around for a bug in the 248397f9dfeSDavid Greenman * NIC. See fxp_stats_update(). 249397f9dfeSDavid Greenman */ 250397f9dfeSDavid Greenman #define FXP_MAX_RX_IDLE 15 251397f9dfeSDavid Greenman 252397f9dfeSDavid Greenman /* 253dfe61cf1SDavid Greenman * Wait for the previous command to be accepted (but not necessarily 254dfe61cf1SDavid Greenman * completed). 255dfe61cf1SDavid Greenman */ 256c1087c13SBruce Evans static __inline void 257ba8c6fd5SDavid Greenman fxp_scb_wait(sc) 258ba8c6fd5SDavid Greenman struct fxp_softc *sc; 259a17c678eSDavid Greenman { 260a17c678eSDavid Greenman int i = 10000; 261a17c678eSDavid Greenman 2627dced78aSDavid Greenman while (CSR_READ_1(sc, FXP_CSR_SCB_COMMAND) && --i) 2637dced78aSDavid Greenman DELAY(2); 2647dced78aSDavid Greenman if (i == 0) 26594927790SDavid Greenman printf("fxp%d: SCB timeout\n", FXP_UNIT(sc)); 2667dced78aSDavid Greenman } 2677dced78aSDavid Greenman 2687dced78aSDavid Greenman static __inline void 2697dced78aSDavid Greenman fxp_dma_wait(status, sc) 2707dced78aSDavid Greenman volatile u_int16_t *status; 2717dced78aSDavid Greenman struct fxp_softc *sc; 2727dced78aSDavid Greenman { 2737dced78aSDavid Greenman int i = 10000; 2747dced78aSDavid Greenman 2757dced78aSDavid Greenman while (!(*status & FXP_CB_STATUS_C) && --i) 2767dced78aSDavid Greenman DELAY(2); 2777dced78aSDavid Greenman if (i == 0) 27894927790SDavid Greenman printf("fxp%d: DMA timeout\n", FXP_UNIT(sc)); 279a17c678eSDavid Greenman } 280a17c678eSDavid Greenman 281dfe61cf1SDavid Greenman /* 282dfe61cf1SDavid Greenman * Return identification string if this is device is ours. 283dfe61cf1SDavid Greenman */ 2846182fdbdSPeter Wemm static int 2856182fdbdSPeter Wemm fxp_probe(device_t dev) 286a17c678eSDavid Greenman { 28755ce7b51SDavid Greenman if (pci_get_vendor(dev) == FXP_VENDORID_INTEL) { 28855ce7b51SDavid Greenman switch (pci_get_device(dev)) { 28955ce7b51SDavid Greenman 29055ce7b51SDavid Greenman case FXP_DEVICEID_i82557: 29155ce7b51SDavid Greenman device_set_desc(dev, "Intel Pro 10/100B/100+ Ethernet"); 2926182fdbdSPeter Wemm return 0; 29355ce7b51SDavid Greenman case FXP_DEVICEID_i82559: 294dd68ef16SPeter Wemm device_set_desc(dev, "Intel InBusiness 10/100 Ethernet"); 295dd68ef16SPeter Wemm return 0; 29655ce7b51SDavid Greenman case FXP_DEVICEID_i82559ER: 29755ce7b51SDavid Greenman device_set_desc(dev, "Intel Embedded 10/100 Ethernet"); 29855ce7b51SDavid Greenman return 0; 299b2f5cb03SBill Paul case FXP_DEVICEID_i82562: 300b2f5cb03SBill Paul device_set_desc(dev, "Intel PLC 10/100 Ethernet"); 301b2f5cb03SBill Paul return 0; 30255ce7b51SDavid Greenman default: 30355ce7b51SDavid Greenman break; 30455ce7b51SDavid Greenman } 305dd68ef16SPeter Wemm } 306a17c678eSDavid Greenman 3076182fdbdSPeter Wemm return ENXIO; 3086182fdbdSPeter Wemm } 3096182fdbdSPeter Wemm 3106182fdbdSPeter Wemm static int 3116182fdbdSPeter Wemm fxp_attach(device_t dev) 312a17c678eSDavid Greenman { 3136182fdbdSPeter Wemm int error = 0; 3146182fdbdSPeter Wemm struct fxp_softc *sc = device_get_softc(dev); 315ba8c6fd5SDavid Greenman struct ifnet *ifp; 3169fa6ccfbSMatt Jacob u_int32_t val; 3172a05a4ebSMatt Jacob int rid, m1, m2, prefer_iomap; 318a17c678eSDavid Greenman 31908812b39SBosko Milekic mtx_init(&sc->sc_mtx, device_get_nameunit(dev), MTX_DEF | MTX_RECURSE); 3206c951b44SJustin T. Gibbs callout_handle_init(&sc->stat_ch); 321a17c678eSDavid Greenman 32294927790SDavid Greenman FXP_LOCK(sc); 323a17c678eSDavid Greenman 324dfe61cf1SDavid Greenman /* 3259fa6ccfbSMatt Jacob * Enable bus mastering. Enable memory space too, in case 3269fa6ccfbSMatt Jacob * BIOS/Prom forgot about it. 327df373873SWes Peters */ 3286182fdbdSPeter Wemm val = pci_read_config(dev, PCIR_COMMAND, 2); 329df373873SWes Peters val |= (PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN); 3306182fdbdSPeter Wemm pci_write_config(dev, PCIR_COMMAND, val, 2); 3319fa6ccfbSMatt Jacob val = pci_read_config(dev, PCIR_COMMAND, 2); 332df373873SWes Peters 3338d799694SBill Paul if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { 3348d799694SBill Paul u_int32_t iobase, membase, irq; 3358d799694SBill Paul 3368d799694SBill Paul /* Save important PCI config data. */ 3378d799694SBill Paul iobase = pci_read_config(dev, FXP_PCI_IOBA, 4); 3388d799694SBill Paul membase = pci_read_config(dev, FXP_PCI_MMBA, 4); 3398d799694SBill Paul irq = pci_read_config(dev, PCIR_INTLINE, 4); 3408d799694SBill Paul 3418d799694SBill Paul /* Reset the power state. */ 3428d799694SBill Paul device_printf(dev, "chip is in D%d power mode " 3438d799694SBill Paul "-- setting to D0\n", pci_get_powerstate(dev)); 3448d799694SBill Paul 3458d799694SBill Paul pci_set_powerstate(dev, PCI_POWERSTATE_D0); 3468d799694SBill Paul 3478d799694SBill Paul /* Restore PCI config data. */ 3488d799694SBill Paul pci_write_config(dev, FXP_PCI_IOBA, iobase, 4); 3498d799694SBill Paul pci_write_config(dev, FXP_PCI_MMBA, membase, 4); 3508d799694SBill Paul pci_write_config(dev, PCIR_INTLINE, irq, 4); 3518d799694SBill Paul } 3528d799694SBill Paul 353df373873SWes Peters /* 3549fa6ccfbSMatt Jacob * Figure out which we should try first - memory mapping or i/o mapping? 3559fa6ccfbSMatt Jacob * We default to memory mapping. Then we accept an override from the 3569fa6ccfbSMatt Jacob * command line. Then we check to see which one is enabled. 357dfe61cf1SDavid Greenman */ 3589fa6ccfbSMatt Jacob m1 = PCIM_CMD_MEMEN; 3599fa6ccfbSMatt Jacob m2 = PCIM_CMD_PORTEN; 3602a05a4ebSMatt Jacob prefer_iomap = 0; 3612a05a4ebSMatt Jacob if (resource_int_value(device_get_name(dev), device_get_unit(dev), 3622a05a4ebSMatt Jacob "prefer_iomap", &prefer_iomap) == 0 && prefer_iomap != 0) { 3639fa6ccfbSMatt Jacob m1 = PCIM_CMD_PORTEN; 3649fa6ccfbSMatt Jacob m2 = PCIM_CMD_MEMEN; 3659fa6ccfbSMatt Jacob } 3669fa6ccfbSMatt Jacob 3679fa6ccfbSMatt Jacob if (val & m1) { 3689fa6ccfbSMatt Jacob sc->rtp = 3699fa6ccfbSMatt Jacob (m1 == PCIM_CMD_MEMEN)? SYS_RES_MEMORY : SYS_RES_IOPORT; 3709fa6ccfbSMatt Jacob sc->rgd = (m1 == PCIM_CMD_MEMEN)? FXP_PCI_MMBA : FXP_PCI_IOBA; 3719fa6ccfbSMatt Jacob sc->mem = bus_alloc_resource(dev, sc->rtp, &sc->rgd, 3726182fdbdSPeter Wemm 0, ~0, 1, RF_ACTIVE); 3739fa6ccfbSMatt Jacob } 3749fa6ccfbSMatt Jacob if (sc->mem == NULL && (val & m2)) { 3759fa6ccfbSMatt Jacob sc->rtp = 3769fa6ccfbSMatt Jacob (m2 == PCIM_CMD_MEMEN)? SYS_RES_MEMORY : SYS_RES_IOPORT; 3779fa6ccfbSMatt Jacob sc->rgd = (m2 == PCIM_CMD_MEMEN)? FXP_PCI_MMBA : FXP_PCI_IOBA; 3789fa6ccfbSMatt Jacob sc->mem = bus_alloc_resource(dev, sc->rtp, &sc->rgd, 3799fa6ccfbSMatt Jacob 0, ~0, 1, RF_ACTIVE); 3809fa6ccfbSMatt Jacob } 3819fa6ccfbSMatt Jacob 3826182fdbdSPeter Wemm if (!sc->mem) { 3839fa6ccfbSMatt Jacob device_printf(dev, "could not map device registers\n"); 3846182fdbdSPeter Wemm error = ENXIO; 385a17c678eSDavid Greenman goto fail; 386a17c678eSDavid Greenman } 3879fa6ccfbSMatt Jacob if (bootverbose) { 3889fa6ccfbSMatt Jacob device_printf(dev, "using %s space register mapping\n", 3899fa6ccfbSMatt Jacob sc->rtp == SYS_RES_MEMORY? "memory" : "I/O"); 3909fa6ccfbSMatt Jacob } 3914fc1dda9SAndrew Gallatin 3924fc1dda9SAndrew Gallatin sc->sc_st = rman_get_bustag(sc->mem); 3934fc1dda9SAndrew Gallatin sc->sc_sh = rman_get_bushandle(sc->mem); 394a17c678eSDavid Greenman 395a17c678eSDavid Greenman /* 396dfe61cf1SDavid Greenman * Allocate our interrupt. 397dfe61cf1SDavid Greenman */ 3986182fdbdSPeter Wemm rid = 0; 3996182fdbdSPeter Wemm sc->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, 4006182fdbdSPeter Wemm RF_SHAREABLE | RF_ACTIVE); 4016182fdbdSPeter Wemm if (sc->irq == NULL) { 4026182fdbdSPeter Wemm device_printf(dev, "could not map interrupt\n"); 4036182fdbdSPeter Wemm error = ENXIO; 4046182fdbdSPeter Wemm goto fail; 4056182fdbdSPeter Wemm } 4066182fdbdSPeter Wemm 407566643e3SDoug Rabson error = bus_setup_intr(dev, sc->irq, INTR_TYPE_NET, 408566643e3SDoug Rabson fxp_intr, sc, &sc->ih); 4096182fdbdSPeter Wemm if (error) { 4106182fdbdSPeter Wemm device_printf(dev, "could not setup irq\n"); 411a17c678eSDavid Greenman goto fail; 412a17c678eSDavid Greenman } 413a17c678eSDavid Greenman 414ba8c6fd5SDavid Greenman /* Do generic parts of attach. */ 415ba8c6fd5SDavid Greenman if (fxp_attach_common(sc, sc->arpcom.ac_enaddr)) { 416ba8c6fd5SDavid Greenman /* Failed! */ 4176182fdbdSPeter Wemm bus_teardown_intr(dev, sc->irq, sc->ih); 4186182fdbdSPeter Wemm bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq); 4199fa6ccfbSMatt Jacob bus_release_resource(dev, sc->rtp, sc->rgd, sc->mem); 4206182fdbdSPeter Wemm error = ENXIO; 421ba8c6fd5SDavid Greenman goto fail; 422a17c678eSDavid Greenman } 423a17c678eSDavid Greenman 4246182fdbdSPeter Wemm device_printf(dev, "Ethernet address %6D%s\n", 425ba8c6fd5SDavid Greenman sc->arpcom.ac_enaddr, ":", sc->phy_10Mbps_only ? ", 10Mbps" : ""); 426dccee1a1SDavid Greenman 427a17c678eSDavid Greenman ifp = &sc->arpcom.ac_if; 4286182fdbdSPeter Wemm ifp->if_unit = device_get_unit(dev); 429a17c678eSDavid Greenman ifp->if_name = "fxp"; 430a17c678eSDavid Greenman ifp->if_output = ether_output; 431a330e1f1SGary Palmer ifp->if_baudrate = 100000000; 432fb583156SDavid Greenman ifp->if_init = fxp_init; 433ba8c6fd5SDavid Greenman ifp->if_softc = sc; 434ba8c6fd5SDavid Greenman ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 435ba8c6fd5SDavid Greenman ifp->if_ioctl = fxp_ioctl; 436ba8c6fd5SDavid Greenman ifp->if_start = fxp_start; 437ba8c6fd5SDavid Greenman ifp->if_watchdog = fxp_watchdog; 438a17c678eSDavid Greenman 439dfe61cf1SDavid Greenman /* 440dfe61cf1SDavid Greenman * Attach the interface. 441dfe61cf1SDavid Greenman */ 44221b8ebd9SArchie Cobbs ether_ifattach(ifp, ETHER_BPF_SUPPORTED); 443483b9871SDavid Greenman /* 4443114fdb4SDavid Greenman * Let the system queue as many packets as we have available 4453114fdb4SDavid Greenman * TX descriptors. 446483b9871SDavid Greenman */ 4473114fdb4SDavid Greenman ifp->if_snd.ifq_maxlen = FXP_NTXCB - 1; 4484a684684SDavid Greenman 44994927790SDavid Greenman FXP_UNLOCK(sc); 4506182fdbdSPeter Wemm return 0; 451a17c678eSDavid Greenman 452a17c678eSDavid Greenman fail: 45394927790SDavid Greenman FXP_UNLOCK(sc); 4540f4dc94cSChuck Paterson mtx_destroy(&sc->sc_mtx); 4556182fdbdSPeter Wemm return error; 4566182fdbdSPeter Wemm } 4576182fdbdSPeter Wemm 4586182fdbdSPeter Wemm /* 4596182fdbdSPeter Wemm * Detach interface. 4606182fdbdSPeter Wemm */ 4616182fdbdSPeter Wemm static int 4626182fdbdSPeter Wemm fxp_detach(device_t dev) 4636182fdbdSPeter Wemm { 4646182fdbdSPeter Wemm struct fxp_softc *sc = device_get_softc(dev); 4656182fdbdSPeter Wemm 46694927790SDavid Greenman FXP_LOCK(sc); 4676182fdbdSPeter Wemm 4686182fdbdSPeter Wemm /* 4696182fdbdSPeter Wemm * Close down routes etc. 4706182fdbdSPeter Wemm */ 47121b8ebd9SArchie Cobbs ether_ifdetach(&sc->arpcom.ac_if, ETHER_BPF_SUPPORTED); 4726182fdbdSPeter Wemm 4736182fdbdSPeter Wemm /* 4746182fdbdSPeter Wemm * Stop DMA and drop transmit queue. 4756182fdbdSPeter Wemm */ 4766182fdbdSPeter Wemm fxp_stop(sc); 4776182fdbdSPeter Wemm 4786182fdbdSPeter Wemm /* 4796182fdbdSPeter Wemm * Deallocate resources. 4806182fdbdSPeter Wemm */ 4816182fdbdSPeter Wemm bus_teardown_intr(dev, sc->irq, sc->ih); 4826182fdbdSPeter Wemm bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq); 4839fa6ccfbSMatt Jacob bus_release_resource(dev, sc->rtp, sc->rgd, sc->mem); 4846182fdbdSPeter Wemm 4856182fdbdSPeter Wemm /* 4866182fdbdSPeter Wemm * Free all the receive buffers. 4876182fdbdSPeter Wemm */ 4886182fdbdSPeter Wemm if (sc->rfa_headm != NULL) 4896182fdbdSPeter Wemm m_freem(sc->rfa_headm); 4906182fdbdSPeter Wemm 4916182fdbdSPeter Wemm /* 4926182fdbdSPeter Wemm * Free all media structures. 4936182fdbdSPeter Wemm */ 4946182fdbdSPeter Wemm ifmedia_removeall(&sc->sc_media); 4956182fdbdSPeter Wemm 4966182fdbdSPeter Wemm /* 4976182fdbdSPeter Wemm * Free anciliary structures. 4986182fdbdSPeter Wemm */ 4996182fdbdSPeter Wemm free(sc->cbl_base, M_DEVBUF); 5006182fdbdSPeter Wemm free(sc->fxp_stats, M_DEVBUF); 5016182fdbdSPeter Wemm free(sc->mcsp, M_DEVBUF); 5026182fdbdSPeter Wemm 50394927790SDavid Greenman FXP_UNLOCK(sc); 504f59dd3aeSChuck Paterson mtx_destroy(&sc->sc_mtx); 5056182fdbdSPeter Wemm 5066182fdbdSPeter Wemm return 0; 507a17c678eSDavid Greenman } 508a17c678eSDavid Greenman 509a17c678eSDavid Greenman /* 5104a684684SDavid Greenman * Device shutdown routine. Called at system shutdown after sync. The 511a17c678eSDavid Greenman * main purpose of this routine is to shut off receiver DMA so that 512a17c678eSDavid Greenman * kernel memory doesn't get clobbered during warmboot. 513a17c678eSDavid Greenman */ 5146182fdbdSPeter Wemm static int 5156182fdbdSPeter Wemm fxp_shutdown(device_t dev) 516a17c678eSDavid Greenman { 5176182fdbdSPeter Wemm /* 5186182fdbdSPeter Wemm * Make sure that DMA is disabled prior to reboot. Not doing 5196182fdbdSPeter Wemm * do could allow DMA to corrupt kernel memory during the 5206182fdbdSPeter Wemm * reboot before the driver initializes. 5216182fdbdSPeter Wemm */ 5226182fdbdSPeter Wemm fxp_stop((struct fxp_softc *) device_get_softc(dev)); 5236182fdbdSPeter Wemm return 0; 524a17c678eSDavid Greenman } 525a17c678eSDavid Greenman 5267dced78aSDavid Greenman /* 5277dced78aSDavid Greenman * Device suspend routine. Stop the interface and save some PCI 5287dced78aSDavid Greenman * settings in case the BIOS doesn't restore them properly on 5297dced78aSDavid Greenman * resume. 5307dced78aSDavid Greenman */ 5317dced78aSDavid Greenman static int 5327dced78aSDavid Greenman fxp_suspend(device_t dev) 5337dced78aSDavid Greenman { 5347dced78aSDavid Greenman struct fxp_softc *sc = device_get_softc(dev); 5352053b07dSDavid Greenman int i; 5367dced78aSDavid Greenman 53794927790SDavid Greenman FXP_LOCK(sc); 5387dced78aSDavid Greenman 5397dced78aSDavid Greenman fxp_stop(sc); 5407dced78aSDavid Greenman 5417dced78aSDavid Greenman for (i=0; i<5; i++) 5427dced78aSDavid Greenman sc->saved_maps[i] = pci_read_config(dev, PCIR_MAPS + i*4, 4); 5437dced78aSDavid Greenman sc->saved_biosaddr = pci_read_config(dev, PCIR_BIOS, 4); 5447dced78aSDavid Greenman sc->saved_intline = pci_read_config(dev, PCIR_INTLINE, 1); 5457dced78aSDavid Greenman sc->saved_cachelnsz = pci_read_config(dev, PCIR_CACHELNSZ, 1); 5467dced78aSDavid Greenman sc->saved_lattimer = pci_read_config(dev, PCIR_LATTIMER, 1); 5477dced78aSDavid Greenman 5487dced78aSDavid Greenman sc->suspended = 1; 5497dced78aSDavid Greenman 55094927790SDavid Greenman FXP_UNLOCK(sc); 5517dced78aSDavid Greenman 5527dced78aSDavid Greenman return 0; 5537dced78aSDavid Greenman } 5547dced78aSDavid Greenman 5557dced78aSDavid Greenman /* 5567dced78aSDavid Greenman * Device resume routine. Restore some PCI settings in case the BIOS 5577dced78aSDavid Greenman * doesn't, re-enable busmastering, and restart the interface if 5587dced78aSDavid Greenman * appropriate. 5597dced78aSDavid Greenman */ 5607dced78aSDavid Greenman static int 5617dced78aSDavid Greenman fxp_resume(device_t dev) 5627dced78aSDavid Greenman { 5637dced78aSDavid Greenman struct fxp_softc *sc = device_get_softc(dev); 5647dced78aSDavid Greenman struct ifnet *ifp = &sc->sc_if; 5657dced78aSDavid Greenman u_int16_t pci_command; 5662053b07dSDavid Greenman int i; 5677dced78aSDavid Greenman 56894927790SDavid Greenman FXP_LOCK(sc); 5697dced78aSDavid Greenman 5707dced78aSDavid Greenman /* better way to do this? */ 5717dced78aSDavid Greenman for (i=0; i<5; i++) 5727dced78aSDavid Greenman pci_write_config(dev, PCIR_MAPS + i*4, sc->saved_maps[i], 4); 5737dced78aSDavid Greenman pci_write_config(dev, PCIR_BIOS, sc->saved_biosaddr, 4); 5747dced78aSDavid Greenman pci_write_config(dev, PCIR_INTLINE, sc->saved_intline, 1); 5757dced78aSDavid Greenman pci_write_config(dev, PCIR_CACHELNSZ, sc->saved_cachelnsz, 1); 5767dced78aSDavid Greenman pci_write_config(dev, PCIR_LATTIMER, sc->saved_lattimer, 1); 5777dced78aSDavid Greenman 5787dced78aSDavid Greenman /* reenable busmastering */ 5797dced78aSDavid Greenman pci_command = pci_read_config(dev, PCIR_COMMAND, 2); 5807dced78aSDavid Greenman pci_command |= (PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN); 5817dced78aSDavid Greenman pci_write_config(dev, PCIR_COMMAND, pci_command, 2); 5827dced78aSDavid Greenman 5837dced78aSDavid Greenman CSR_WRITE_4(sc, FXP_CSR_PORT, FXP_PORT_SELECTIVE_RESET); 5847dced78aSDavid Greenman DELAY(10); 5857dced78aSDavid Greenman 5867dced78aSDavid Greenman /* reinitialize interface if necessary */ 5877dced78aSDavid Greenman if (ifp->if_flags & IFF_UP) 5887dced78aSDavid Greenman fxp_init(sc); 5897dced78aSDavid Greenman 5907dced78aSDavid Greenman sc->suspended = 0; 5917dced78aSDavid Greenman 59294927790SDavid Greenman FXP_UNLOCK(sc); 5937dced78aSDavid Greenman 5947dced78aSDavid Greenman return 0; 5957dced78aSDavid Greenman } 5967dced78aSDavid Greenman 5976182fdbdSPeter Wemm static device_method_t fxp_methods[] = { 5986182fdbdSPeter Wemm /* Device interface */ 5996182fdbdSPeter Wemm DEVMETHOD(device_probe, fxp_probe), 6006182fdbdSPeter Wemm DEVMETHOD(device_attach, fxp_attach), 6016182fdbdSPeter Wemm DEVMETHOD(device_detach, fxp_detach), 6026182fdbdSPeter Wemm DEVMETHOD(device_shutdown, fxp_shutdown), 6037dced78aSDavid Greenman DEVMETHOD(device_suspend, fxp_suspend), 6047dced78aSDavid Greenman DEVMETHOD(device_resume, fxp_resume), 6056182fdbdSPeter Wemm 6066182fdbdSPeter Wemm { 0, 0 } 6076182fdbdSPeter Wemm }; 6086182fdbdSPeter Wemm 6096182fdbdSPeter Wemm static driver_t fxp_driver = { 6106182fdbdSPeter Wemm "fxp", 6116182fdbdSPeter Wemm fxp_methods, 6126182fdbdSPeter Wemm sizeof(struct fxp_softc), 6136182fdbdSPeter Wemm }; 6146182fdbdSPeter Wemm 6156182fdbdSPeter Wemm static devclass_t fxp_devclass; 6166182fdbdSPeter Wemm 6179e4c647cSBill Paul DRIVER_MODULE(if_fxp, pci, fxp_driver, fxp_devclass, 0, 0); 618869975bfSWarner Losh DRIVER_MODULE(if_fxp, cardbus, fxp_driver, fxp_devclass, 0, 0); 6196182fdbdSPeter Wemm 620ba8c6fd5SDavid Greenman /* 621ba8c6fd5SDavid Greenman * Do generic parts of attach. 622ba8c6fd5SDavid Greenman */ 623ba8c6fd5SDavid Greenman static int 624ba8c6fd5SDavid Greenman fxp_attach_common(sc, enaddr) 625ba8c6fd5SDavid Greenman struct fxp_softc *sc; 626ba8c6fd5SDavid Greenman u_int8_t *enaddr; 627ba8c6fd5SDavid Greenman { 628ba8c6fd5SDavid Greenman u_int16_t data; 629ba8c6fd5SDavid Greenman int i, nmedia, defmedia; 630ba8c6fd5SDavid Greenman const int *media; 631ba8c6fd5SDavid Greenman 632ba8c6fd5SDavid Greenman /* 633ba8c6fd5SDavid Greenman * Reset to a stable state. 634ba8c6fd5SDavid Greenman */ 635ba8c6fd5SDavid Greenman CSR_WRITE_4(sc, FXP_CSR_PORT, FXP_PORT_SELECTIVE_RESET); 636ba8c6fd5SDavid Greenman DELAY(10); 637ba8c6fd5SDavid Greenman 638ba8c6fd5SDavid Greenman sc->cbl_base = malloc(sizeof(struct fxp_cb_tx) * FXP_NTXCB, 6397cc0979fSDavid Malone M_DEVBUF, M_NOWAIT | M_ZERO); 640ba8c6fd5SDavid Greenman if (sc->cbl_base == NULL) 641ba8c6fd5SDavid Greenman goto fail; 642ba8c6fd5SDavid Greenman 6437cc0979fSDavid Malone sc->fxp_stats = malloc(sizeof(struct fxp_stats), M_DEVBUF, 6447cc0979fSDavid Malone M_NOWAIT | M_ZERO); 645ba8c6fd5SDavid Greenman if (sc->fxp_stats == NULL) 646ba8c6fd5SDavid Greenman goto fail; 647ba8c6fd5SDavid Greenman 648397f9dfeSDavid Greenman sc->mcsp = malloc(sizeof(struct fxp_cb_mcs), M_DEVBUF, M_NOWAIT); 649397f9dfeSDavid Greenman if (sc->mcsp == NULL) 650397f9dfeSDavid Greenman goto fail; 651397f9dfeSDavid Greenman 652ba8c6fd5SDavid Greenman /* 653ba8c6fd5SDavid Greenman * Pre-allocate our receive buffers. 654ba8c6fd5SDavid Greenman */ 655ba8c6fd5SDavid Greenman for (i = 0; i < FXP_NRFABUFS; i++) { 656ba8c6fd5SDavid Greenman if (fxp_add_rfabuf(sc, NULL) != 0) { 657ba8c6fd5SDavid Greenman goto fail; 658ba8c6fd5SDavid Greenman } 659ba8c6fd5SDavid Greenman } 660ba8c6fd5SDavid Greenman 661ba8c6fd5SDavid Greenman /* 662e9bf2fa7SDavid Greenman * Find out how large of an SEEPROM we have. 663e9bf2fa7SDavid Greenman */ 664e9bf2fa7SDavid Greenman fxp_autosize_eeprom(sc); 665e9bf2fa7SDavid Greenman 666e9bf2fa7SDavid Greenman /* 667ba8c6fd5SDavid Greenman * Get info about the primary PHY 668ba8c6fd5SDavid Greenman */ 669ba8c6fd5SDavid Greenman fxp_read_eeprom(sc, (u_int16_t *)&data, 6, 1); 670ba8c6fd5SDavid Greenman sc->phy_primary_addr = data & 0xff; 671ba8c6fd5SDavid Greenman sc->phy_primary_device = (data >> 8) & 0x3f; 672ba8c6fd5SDavid Greenman sc->phy_10Mbps_only = data >> 15; 673ba8c6fd5SDavid Greenman 674ba8c6fd5SDavid Greenman /* 675ba8c6fd5SDavid Greenman * Read MAC address. 676ba8c6fd5SDavid Greenman */ 677ba8c6fd5SDavid Greenman fxp_read_eeprom(sc, (u_int16_t *)enaddr, 0, 3); 678ba8c6fd5SDavid Greenman 679ba8c6fd5SDavid Greenman /* 680ba8c6fd5SDavid Greenman * Initialize the media structures. 681ba8c6fd5SDavid Greenman */ 682ba8c6fd5SDavid Greenman 683ba8c6fd5SDavid Greenman media = fxp_media_default; 684ba8c6fd5SDavid Greenman nmedia = sizeof(fxp_media_default) / sizeof(fxp_media_default[0]); 685ba8c6fd5SDavid Greenman defmedia = FXP_MEDIA_DEFAULT_DEFMEDIA; 686ba8c6fd5SDavid Greenman 687ba8c6fd5SDavid Greenman for (i = 0; i < NFXPMEDIA; i++) { 688ba8c6fd5SDavid Greenman if (sc->phy_primary_device == fxp_media[i].fsm_phy) { 689ba8c6fd5SDavid Greenman media = fxp_media[i].fsm_media; 690ba8c6fd5SDavid Greenman nmedia = fxp_media[i].fsm_nmedia; 691ba8c6fd5SDavid Greenman defmedia = fxp_media[i].fsm_defmedia; 692ba8c6fd5SDavid Greenman } 693ba8c6fd5SDavid Greenman } 694ba8c6fd5SDavid Greenman 695ba8c6fd5SDavid Greenman ifmedia_init(&sc->sc_media, 0, fxp_mediachange, fxp_mediastatus); 696ba8c6fd5SDavid Greenman for (i = 0; i < nmedia; i++) { 697ba8c6fd5SDavid Greenman if (IFM_SUBTYPE(media[i]) == IFM_100_TX && sc->phy_10Mbps_only) 698ba8c6fd5SDavid Greenman continue; 699ba8c6fd5SDavid Greenman ifmedia_add(&sc->sc_media, media[i], 0, NULL); 700ba8c6fd5SDavid Greenman } 701ba8c6fd5SDavid Greenman ifmedia_set(&sc->sc_media, defmedia); 702ba8c6fd5SDavid Greenman 703ba8c6fd5SDavid Greenman return (0); 704ba8c6fd5SDavid Greenman 705ba8c6fd5SDavid Greenman fail: 70694927790SDavid Greenman printf("fxp%d: Failed to malloc memory\n", FXP_UNIT(sc)); 707ba8c6fd5SDavid Greenman if (sc->cbl_base) 708ba8c6fd5SDavid Greenman free(sc->cbl_base, M_DEVBUF); 709ba8c6fd5SDavid Greenman if (sc->fxp_stats) 710ba8c6fd5SDavid Greenman free(sc->fxp_stats, M_DEVBUF); 711397f9dfeSDavid Greenman if (sc->mcsp) 712397f9dfeSDavid Greenman free(sc->mcsp, M_DEVBUF); 713ba8c6fd5SDavid Greenman /* frees entire chain */ 714ba8c6fd5SDavid Greenman if (sc->rfa_headm) 715ba8c6fd5SDavid Greenman m_freem(sc->rfa_headm); 716ba8c6fd5SDavid Greenman 717ba8c6fd5SDavid Greenman return (ENOMEM); 718ba8c6fd5SDavid Greenman } 719ba8c6fd5SDavid Greenman 720ba8c6fd5SDavid Greenman /* 721e9bf2fa7SDavid Greenman * From NetBSD: 722e9bf2fa7SDavid Greenman * 723e9bf2fa7SDavid Greenman * Figure out EEPROM size. 724e9bf2fa7SDavid Greenman * 725e9bf2fa7SDavid Greenman * 559's can have either 64-word or 256-word EEPROMs, the 558 726e9bf2fa7SDavid Greenman * datasheet only talks about 64-word EEPROMs, and the 557 datasheet 727e9bf2fa7SDavid Greenman * talks about the existance of 16 to 256 word EEPROMs. 728e9bf2fa7SDavid Greenman * 729e9bf2fa7SDavid Greenman * The only known sizes are 64 and 256, where the 256 version is used 730e9bf2fa7SDavid Greenman * by CardBus cards to store CIS information. 731e9bf2fa7SDavid Greenman * 732e9bf2fa7SDavid Greenman * The address is shifted in msb-to-lsb, and after the last 733e9bf2fa7SDavid Greenman * address-bit the EEPROM is supposed to output a `dummy zero' bit, 734e9bf2fa7SDavid Greenman * after which follows the actual data. We try to detect this zero, by 735e9bf2fa7SDavid Greenman * probing the data-out bit in the EEPROM control register just after 736e9bf2fa7SDavid Greenman * having shifted in a bit. If the bit is zero, we assume we've 737e9bf2fa7SDavid Greenman * shifted enough address bits. The data-out should be tri-state, 738e9bf2fa7SDavid Greenman * before this, which should translate to a logical one. 739e9bf2fa7SDavid Greenman * 740e9bf2fa7SDavid Greenman * Other ways to do this would be to try to read a register with known 741e9bf2fa7SDavid Greenman * contents with a varying number of address bits, but no such 742e9bf2fa7SDavid Greenman * register seem to be available. The high bits of register 10 are 01 743e9bf2fa7SDavid Greenman * on the 558 and 559, but apparently not on the 557. 744e9bf2fa7SDavid Greenman * 745e9bf2fa7SDavid Greenman * The Linux driver computes a checksum on the EEPROM data, but the 746e9bf2fa7SDavid Greenman * value of this checksum is not very well documented. 747e9bf2fa7SDavid Greenman */ 748e9bf2fa7SDavid Greenman static void 749e9bf2fa7SDavid Greenman fxp_autosize_eeprom(sc) 750e9bf2fa7SDavid Greenman struct fxp_softc *sc; 751e9bf2fa7SDavid Greenman { 752e9bf2fa7SDavid Greenman u_int16_t reg; 753e9bf2fa7SDavid Greenman int x; 754e9bf2fa7SDavid Greenman 755e9bf2fa7SDavid Greenman CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS); 756e9bf2fa7SDavid Greenman /* 757e9bf2fa7SDavid Greenman * Shift in read opcode. 758e9bf2fa7SDavid Greenman */ 759e9bf2fa7SDavid Greenman for (x = 3; x > 0; x--) { 760e9bf2fa7SDavid Greenman if (FXP_EEPROM_OPC_READ & (1 << (x - 1))) { 761e9bf2fa7SDavid Greenman reg = FXP_EEPROM_EECS | FXP_EEPROM_EEDI; 762e9bf2fa7SDavid Greenman } else { 763e9bf2fa7SDavid Greenman reg = FXP_EEPROM_EECS; 764e9bf2fa7SDavid Greenman } 765e9bf2fa7SDavid Greenman CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg); 766e9bf2fa7SDavid Greenman CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 767e9bf2fa7SDavid Greenman reg | FXP_EEPROM_EESK); 768e9bf2fa7SDavid Greenman DELAY(1); 769e9bf2fa7SDavid Greenman CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg); 770e9bf2fa7SDavid Greenman DELAY(1); 771e9bf2fa7SDavid Greenman } 772e9bf2fa7SDavid Greenman /* 773e9bf2fa7SDavid Greenman * Shift in address. 774e9bf2fa7SDavid Greenman * Wait for the dummy zero following a correct address shift. 775e9bf2fa7SDavid Greenman */ 776e9bf2fa7SDavid Greenman for (x = 1; x <= 8; x++) { 777e9bf2fa7SDavid Greenman CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS); 778e9bf2fa7SDavid Greenman CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 779e9bf2fa7SDavid Greenman FXP_EEPROM_EECS | FXP_EEPROM_EESK); 780e9bf2fa7SDavid Greenman DELAY(1); 781e9bf2fa7SDavid Greenman if ((CSR_READ_2(sc, FXP_CSR_EEPROMCONTROL) & FXP_EEPROM_EEDO) == 0) 782e9bf2fa7SDavid Greenman break; 783e9bf2fa7SDavid Greenman CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS); 784e9bf2fa7SDavid Greenman DELAY(1); 785e9bf2fa7SDavid Greenman } 786e9bf2fa7SDavid Greenman CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 0); 787e9bf2fa7SDavid Greenman DELAY(1); 788e9bf2fa7SDavid Greenman sc->eeprom_size = x; 789e9bf2fa7SDavid Greenman } 790e9bf2fa7SDavid Greenman /* 791ba8c6fd5SDavid Greenman * Read from the serial EEPROM. Basically, you manually shift in 792ba8c6fd5SDavid Greenman * the read opcode (one bit at a time) and then shift in the address, 793ba8c6fd5SDavid Greenman * and then you shift out the data (all of this one bit at a time). 794ba8c6fd5SDavid Greenman * The word size is 16 bits, so you have to provide the address for 795ba8c6fd5SDavid Greenman * every 16 bits of data. 796ba8c6fd5SDavid Greenman */ 797ba8c6fd5SDavid Greenman static void 798ba8c6fd5SDavid Greenman fxp_read_eeprom(sc, data, offset, words) 799ba8c6fd5SDavid Greenman struct fxp_softc *sc; 800ba8c6fd5SDavid Greenman u_short *data; 801ba8c6fd5SDavid Greenman int offset; 802ba8c6fd5SDavid Greenman int words; 803ba8c6fd5SDavid Greenman { 804ba8c6fd5SDavid Greenman u_int16_t reg; 805ba8c6fd5SDavid Greenman int i, x; 806ba8c6fd5SDavid Greenman 807ba8c6fd5SDavid Greenman for (i = 0; i < words; i++) { 808ba8c6fd5SDavid Greenman CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS); 809ba8c6fd5SDavid Greenman /* 810ba8c6fd5SDavid Greenman * Shift in read opcode. 811ba8c6fd5SDavid Greenman */ 812ba8c6fd5SDavid Greenman for (x = 3; x > 0; x--) { 813ba8c6fd5SDavid Greenman if (FXP_EEPROM_OPC_READ & (1 << (x - 1))) { 814ba8c6fd5SDavid Greenman reg = FXP_EEPROM_EECS | FXP_EEPROM_EEDI; 815ba8c6fd5SDavid Greenman } else { 816ba8c6fd5SDavid Greenman reg = FXP_EEPROM_EECS; 817ba8c6fd5SDavid Greenman } 818ba8c6fd5SDavid Greenman CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg); 819ba8c6fd5SDavid Greenman CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 820ba8c6fd5SDavid Greenman reg | FXP_EEPROM_EESK); 821ba8c6fd5SDavid Greenman DELAY(1); 822ba8c6fd5SDavid Greenman CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg); 823ba8c6fd5SDavid Greenman DELAY(1); 824ba8c6fd5SDavid Greenman } 825ba8c6fd5SDavid Greenman /* 826ba8c6fd5SDavid Greenman * Shift in address. 827ba8c6fd5SDavid Greenman */ 828e9bf2fa7SDavid Greenman for (x = sc->eeprom_size; x > 0; x--) { 829ba8c6fd5SDavid Greenman if ((i + offset) & (1 << (x - 1))) { 830ba8c6fd5SDavid Greenman reg = FXP_EEPROM_EECS | FXP_EEPROM_EEDI; 831ba8c6fd5SDavid Greenman } else { 832ba8c6fd5SDavid Greenman reg = FXP_EEPROM_EECS; 833ba8c6fd5SDavid Greenman } 834ba8c6fd5SDavid Greenman CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg); 835ba8c6fd5SDavid Greenman CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 836ba8c6fd5SDavid Greenman reg | FXP_EEPROM_EESK); 837ba8c6fd5SDavid Greenman DELAY(1); 838ba8c6fd5SDavid Greenman CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg); 839ba8c6fd5SDavid Greenman DELAY(1); 840ba8c6fd5SDavid Greenman } 841ba8c6fd5SDavid Greenman reg = FXP_EEPROM_EECS; 842ba8c6fd5SDavid Greenman data[i] = 0; 843ba8c6fd5SDavid Greenman /* 844ba8c6fd5SDavid Greenman * Shift out data. 845ba8c6fd5SDavid Greenman */ 846ba8c6fd5SDavid Greenman for (x = 16; x > 0; x--) { 847ba8c6fd5SDavid Greenman CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 848ba8c6fd5SDavid Greenman reg | FXP_EEPROM_EESK); 849ba8c6fd5SDavid Greenman DELAY(1); 850ba8c6fd5SDavid Greenman if (CSR_READ_2(sc, FXP_CSR_EEPROMCONTROL) & 851ba8c6fd5SDavid Greenman FXP_EEPROM_EEDO) 852ba8c6fd5SDavid Greenman data[i] |= (1 << (x - 1)); 853ba8c6fd5SDavid Greenman CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg); 854ba8c6fd5SDavid Greenman DELAY(1); 855ba8c6fd5SDavid Greenman } 856ba8c6fd5SDavid Greenman CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 0); 857ba8c6fd5SDavid Greenman DELAY(1); 858ba8c6fd5SDavid Greenman } 859ba8c6fd5SDavid Greenman } 860ba8c6fd5SDavid Greenman 861a17c678eSDavid Greenman /* 862a17c678eSDavid Greenman * Start packet transmission on the interface. 863a17c678eSDavid Greenman */ 864a17c678eSDavid Greenman static void 865a17c678eSDavid Greenman fxp_start(ifp) 866a17c678eSDavid Greenman struct ifnet *ifp; 867a17c678eSDavid Greenman { 8689b44ff22SGarrett Wollman struct fxp_softc *sc = ifp->if_softc; 869a17c678eSDavid Greenman struct fxp_cb_tx *txp; 870a17c678eSDavid Greenman 87194927790SDavid Greenman FXP_LOCK(sc); 872a17c678eSDavid Greenman /* 873483b9871SDavid Greenman * See if we need to suspend xmit until the multicast filter 874483b9871SDavid Greenman * has been reprogrammed (which can only be done at the head 875483b9871SDavid Greenman * of the command chain). 876a17c678eSDavid Greenman */ 8770f4dc94cSChuck Paterson if (sc->need_mcsetup) { 87894927790SDavid Greenman FXP_UNLOCK(sc); 879a17c678eSDavid Greenman return; 8800f4dc94cSChuck Paterson } 8811cd443acSDavid Greenman 882483b9871SDavid Greenman txp = NULL; 883483b9871SDavid Greenman 884483b9871SDavid Greenman /* 885483b9871SDavid Greenman * We're finished if there is nothing more to add to the list or if 886483b9871SDavid Greenman * we're all filled up with buffers to transmit. 8873114fdb4SDavid Greenman * NOTE: One TxCB is reserved to guarantee that fxp_mc_setup() can add 8883114fdb4SDavid Greenman * a NOP command when needed. 889483b9871SDavid Greenman */ 8903114fdb4SDavid Greenman while (ifp->if_snd.ifq_head != NULL && sc->tx_queued < FXP_NTXCB - 1) { 891483b9871SDavid Greenman struct mbuf *m, *mb_head; 892483b9871SDavid Greenman int segment; 893483b9871SDavid Greenman 894dfe61cf1SDavid Greenman /* 895dfe61cf1SDavid Greenman * Grab a packet to transmit. 896dfe61cf1SDavid Greenman */ 8976318197eSDavid Greenman IF_DEQUEUE(&ifp->if_snd, mb_head); 898a17c678eSDavid Greenman 899dfe61cf1SDavid Greenman /* 900483b9871SDavid Greenman * Get pointer to next available tx desc. 901dfe61cf1SDavid Greenman */ 902a17c678eSDavid Greenman txp = sc->cbl_last->next; 903a17c678eSDavid Greenman 904a17c678eSDavid Greenman /* 905a17c678eSDavid Greenman * Go through each of the mbufs in the chain and initialize 906483b9871SDavid Greenman * the transmit buffer descriptors with the physical address 907a17c678eSDavid Greenman * and size of the mbuf. 908a17c678eSDavid Greenman */ 90923a0ed7cSDavid Greenman tbdinit: 910a17c678eSDavid Greenman for (m = mb_head, segment = 0; m != NULL; m = m->m_next) { 911a17c678eSDavid Greenman if (m->m_len != 0) { 912a17c678eSDavid Greenman if (segment == FXP_NTXSEG) 913a17c678eSDavid Greenman break; 914a17c678eSDavid Greenman txp->tbd[segment].tb_addr = 915a17c678eSDavid Greenman vtophys(mtod(m, vm_offset_t)); 916a17c678eSDavid Greenman txp->tbd[segment].tb_size = m->m_len; 917a17c678eSDavid Greenman segment++; 918a17c678eSDavid Greenman } 919a17c678eSDavid Greenman } 920fb583156SDavid Greenman if (m != NULL) { 92123a0ed7cSDavid Greenman struct mbuf *mn; 92223a0ed7cSDavid Greenman 923a17c678eSDavid Greenman /* 924a17c678eSDavid Greenman * We ran out of segments. We have to recopy this mbuf 925483b9871SDavid Greenman * chain first. Bail out if we can't get the new buffers. 926a17c678eSDavid Greenman */ 92723a0ed7cSDavid Greenman MGETHDR(mn, M_DONTWAIT, MT_DATA); 92823a0ed7cSDavid Greenman if (mn == NULL) { 92923a0ed7cSDavid Greenman m_freem(mb_head); 930483b9871SDavid Greenman break; 931a17c678eSDavid Greenman } 93223a0ed7cSDavid Greenman if (mb_head->m_pkthdr.len > MHLEN) { 93323a0ed7cSDavid Greenman MCLGET(mn, M_DONTWAIT); 93423a0ed7cSDavid Greenman if ((mn->m_flags & M_EXT) == 0) { 93523a0ed7cSDavid Greenman m_freem(mn); 93623a0ed7cSDavid Greenman m_freem(mb_head); 937483b9871SDavid Greenman break; 93823a0ed7cSDavid Greenman } 93923a0ed7cSDavid Greenman } 940ba8c6fd5SDavid Greenman m_copydata(mb_head, 0, mb_head->m_pkthdr.len, 941ba8c6fd5SDavid Greenman mtod(mn, caddr_t)); 94223a0ed7cSDavid Greenman mn->m_pkthdr.len = mn->m_len = mb_head->m_pkthdr.len; 94323a0ed7cSDavid Greenman m_freem(mb_head); 94423a0ed7cSDavid Greenman mb_head = mn; 94523a0ed7cSDavid Greenman goto tbdinit; 94623a0ed7cSDavid Greenman } 94723a0ed7cSDavid Greenman 94823a0ed7cSDavid Greenman txp->tbd_number = segment; 9491cd443acSDavid Greenman txp->mb_head = mb_head; 950a17c678eSDavid Greenman txp->cb_status = 0; 9513114fdb4SDavid Greenman if (sc->tx_queued != FXP_CXINT_THRESH - 1) { 952a17c678eSDavid Greenman txp->cb_command = 953a17c678eSDavid Greenman FXP_CB_COMMAND_XMIT | FXP_CB_COMMAND_SF | FXP_CB_COMMAND_S; 9543114fdb4SDavid Greenman } else { 9553114fdb4SDavid Greenman txp->cb_command = 9563114fdb4SDavid Greenman FXP_CB_COMMAND_XMIT | FXP_CB_COMMAND_SF | FXP_CB_COMMAND_S | FXP_CB_COMMAND_I; 9573114fdb4SDavid Greenman /* 9583114fdb4SDavid Greenman * Set a 5 second timer just in case we don't hear from the 9593114fdb4SDavid Greenman * card again. 9603114fdb4SDavid Greenman */ 9613114fdb4SDavid Greenman ifp->if_timer = 5; 9623114fdb4SDavid Greenman } 963f9be9005SDavid Greenman txp->tx_threshold = tx_threshold; 964a17c678eSDavid Greenman 965a17c678eSDavid Greenman /* 966483b9871SDavid Greenman * Advance the end of list forward. 967a17c678eSDavid Greenman */ 96806175228SAndrew Gallatin 96906175228SAndrew Gallatin #ifdef __alpha__ 97006175228SAndrew Gallatin /* 97106175228SAndrew Gallatin * On platforms which can't access memory in 16-bit 97206175228SAndrew Gallatin * granularities, we must prevent the card from DMA'ing 97306175228SAndrew Gallatin * up the status while we update the command field. 97406175228SAndrew Gallatin * This could cause us to overwrite the completion status. 97506175228SAndrew Gallatin */ 97606175228SAndrew Gallatin atomic_clear_short(&sc->cbl_last->cb_command, 97706175228SAndrew Gallatin FXP_CB_COMMAND_S); 97806175228SAndrew Gallatin #else 979a17c678eSDavid Greenman sc->cbl_last->cb_command &= ~FXP_CB_COMMAND_S; 98006175228SAndrew Gallatin #endif /*__alpha__*/ 981a17c678eSDavid Greenman sc->cbl_last = txp; 982a17c678eSDavid Greenman 983a17c678eSDavid Greenman /* 9841cd443acSDavid Greenman * Advance the beginning of the list forward if there are 9851cd443acSDavid Greenman * no other packets queued (when nothing is queued, cbl_first 986483b9871SDavid Greenman * sits on the last TxCB that was sent out). 987a17c678eSDavid Greenman */ 9881cd443acSDavid Greenman if (sc->tx_queued == 0) 989a17c678eSDavid Greenman sc->cbl_first = txp; 990a17c678eSDavid Greenman 9911cd443acSDavid Greenman sc->tx_queued++; 9921cd443acSDavid Greenman 993a17c678eSDavid Greenman /* 994a17c678eSDavid Greenman * Pass packet to bpf if there is a listener. 995a17c678eSDavid Greenman */ 996fb583156SDavid Greenman if (ifp->if_bpf) 99794927790SDavid Greenman bpf_mtap(ifp, mb_head); 998483b9871SDavid Greenman } 999483b9871SDavid Greenman 1000483b9871SDavid Greenman /* 1001483b9871SDavid Greenman * We're finished. If we added to the list, issue a RESUME to get DMA 1002483b9871SDavid Greenman * going again if suspended. 1003483b9871SDavid Greenman */ 1004483b9871SDavid Greenman if (txp != NULL) { 1005483b9871SDavid Greenman fxp_scb_wait(sc); 1006483b9871SDavid Greenman CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_RESUME); 1007483b9871SDavid Greenman } 100894927790SDavid Greenman FXP_UNLOCK(sc); 1009a17c678eSDavid Greenman } 1010a17c678eSDavid Greenman 1011a17c678eSDavid Greenman /* 10129c7d2607SDavid Greenman * Process interface interrupts. 1013a17c678eSDavid Greenman */ 101494927790SDavid Greenman static void 1015a17c678eSDavid Greenman fxp_intr(arg) 1016a17c678eSDavid Greenman void *arg; 1017a17c678eSDavid Greenman { 1018a17c678eSDavid Greenman struct fxp_softc *sc = arg; 1019ba8c6fd5SDavid Greenman struct ifnet *ifp = &sc->sc_if; 10201cd443acSDavid Greenman u_int8_t statack; 10210f4dc94cSChuck Paterson 102294927790SDavid Greenman FXP_LOCK(sc); 1023a17c678eSDavid Greenman 1024b184b38eSDavid Greenman if (sc->suspended) { 102594927790SDavid Greenman FXP_UNLOCK(sc); 1026b184b38eSDavid Greenman return; 1027b184b38eSDavid Greenman } 1028b184b38eSDavid Greenman 1029b184b38eSDavid Greenman while ((statack = CSR_READ_1(sc, FXP_CSR_SCB_STATACK)) != 0) { 1030a17c678eSDavid Greenman /* 1031a17c678eSDavid Greenman * First ACK all the interrupts in this pass. 1032a17c678eSDavid Greenman */ 1033ba8c6fd5SDavid Greenman CSR_WRITE_1(sc, FXP_CSR_SCB_STATACK, statack); 1034a17c678eSDavid Greenman 1035a17c678eSDavid Greenman /* 10363114fdb4SDavid Greenman * Free any finished transmit mbuf chains. 103706936301SBill Paul * 103806936301SBill Paul * Handle the CNA event likt a CXTNO event. It used to 103906936301SBill Paul * be that this event (control unit not ready) was not 104006936301SBill Paul * encountered, but it is now with the SMPng modifications. 104106936301SBill Paul * The exact sequence of events that occur when the interface 104206936301SBill Paul * is brought up are different now, and if this event 104306936301SBill Paul * goes unhandled, the configuration/rxfilter setup sequence 104406936301SBill Paul * can stall for several seconds. The result is that no 104506936301SBill Paul * packets go out onto the wire for about 5 to 10 seconds 104606936301SBill Paul * after the interface is ifconfig'ed for the first time. 10473114fdb4SDavid Greenman */ 104806936301SBill Paul if (statack & (FXP_SCB_STATACK_CXTNO | FXP_SCB_STATACK_CNA)) { 10493114fdb4SDavid Greenman struct fxp_cb_tx *txp; 10503114fdb4SDavid Greenman 10513114fdb4SDavid Greenman for (txp = sc->cbl_first; sc->tx_queued && 10523114fdb4SDavid Greenman (txp->cb_status & FXP_CB_STATUS_C) != 0; 10533114fdb4SDavid Greenman txp = txp->next) { 10543114fdb4SDavid Greenman if (txp->mb_head != NULL) { 10553114fdb4SDavid Greenman m_freem(txp->mb_head); 10563114fdb4SDavid Greenman txp->mb_head = NULL; 10573114fdb4SDavid Greenman } 10583114fdb4SDavid Greenman sc->tx_queued--; 10593114fdb4SDavid Greenman } 10603114fdb4SDavid Greenman sc->cbl_first = txp; 10613114fdb4SDavid Greenman ifp->if_timer = 0; 10623114fdb4SDavid Greenman if (sc->tx_queued == 0) { 10633114fdb4SDavid Greenman if (sc->need_mcsetup) 10643114fdb4SDavid Greenman fxp_mc_setup(sc); 10653114fdb4SDavid Greenman } 10663114fdb4SDavid Greenman /* 10673114fdb4SDavid Greenman * Try to start more packets transmitting. 10683114fdb4SDavid Greenman */ 10693114fdb4SDavid Greenman if (ifp->if_snd.ifq_head != NULL) 10703114fdb4SDavid Greenman fxp_start(ifp); 10713114fdb4SDavid Greenman } 10723114fdb4SDavid Greenman /* 1073a17c678eSDavid Greenman * Process receiver interrupts. If a no-resource (RNR) 1074a17c678eSDavid Greenman * condition exists, get whatever packets we can and 1075a17c678eSDavid Greenman * re-start the receiver. 1076a17c678eSDavid Greenman */ 1077a17c678eSDavid Greenman if (statack & (FXP_SCB_STATACK_FR | FXP_SCB_STATACK_RNR)) { 1078a17c678eSDavid Greenman struct mbuf *m; 1079a17c678eSDavid Greenman struct fxp_rfa *rfa; 1080a17c678eSDavid Greenman rcvloop: 1081a17c678eSDavid Greenman m = sc->rfa_headm; 1082ba8c6fd5SDavid Greenman rfa = (struct fxp_rfa *)(m->m_ext.ext_buf + 1083ba8c6fd5SDavid Greenman RFA_ALIGNMENT_FUDGE); 1084a17c678eSDavid Greenman 1085a17c678eSDavid Greenman if (rfa->rfa_status & FXP_RFA_STATUS_C) { 1086dfe61cf1SDavid Greenman /* 1087dfe61cf1SDavid Greenman * Remove first packet from the chain. 1088dfe61cf1SDavid Greenman */ 1089a17c678eSDavid Greenman sc->rfa_headm = m->m_next; 1090a17c678eSDavid Greenman m->m_next = NULL; 1091a17c678eSDavid Greenman 1092dfe61cf1SDavid Greenman /* 1093ba8c6fd5SDavid Greenman * Add a new buffer to the receive chain. 1094ba8c6fd5SDavid Greenman * If this fails, the old buffer is recycled 1095ba8c6fd5SDavid Greenman * instead. 1096dfe61cf1SDavid Greenman */ 1097a17c678eSDavid Greenman if (fxp_add_rfabuf(sc, m) == 0) { 1098a17c678eSDavid Greenman struct ether_header *eh; 1099aed53495SDavid Greenman int total_len; 1100a17c678eSDavid Greenman 1101ba8c6fd5SDavid Greenman total_len = rfa->actual_size & 1102ba8c6fd5SDavid Greenman (MCLBYTES - 1); 1103ba8c6fd5SDavid Greenman if (total_len < 1104ba8c6fd5SDavid Greenman sizeof(struct ether_header)) { 110506339180SDavid Greenman m_freem(m); 110606339180SDavid Greenman goto rcvloop; 110706339180SDavid Greenman } 1108a17c678eSDavid Greenman m->m_pkthdr.rcvif = ifp; 11092e2de7f2SArchie Cobbs m->m_pkthdr.len = m->m_len = total_len; 1110a17c678eSDavid Greenman eh = mtod(m, struct ether_header *); 1111ba8c6fd5SDavid Greenman m->m_data += 1112ba8c6fd5SDavid Greenman sizeof(struct ether_header); 1113ab090e5bSLuigi Rizzo m->m_len -= 1114ab090e5bSLuigi Rizzo sizeof(struct ether_header); 1115ab090e5bSLuigi Rizzo m->m_pkthdr.len = m->m_len; 1116a17c678eSDavid Greenman ether_input(ifp, eh, m); 1117a17c678eSDavid Greenman } 1118a17c678eSDavid Greenman goto rcvloop; 1119a17c678eSDavid Greenman } 1120a17c678eSDavid Greenman if (statack & FXP_SCB_STATACK_RNR) { 1121ba8c6fd5SDavid Greenman fxp_scb_wait(sc); 1122ba8c6fd5SDavid Greenman CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, 1123ba8c6fd5SDavid Greenman vtophys(sc->rfa_headm->m_ext.ext_buf) + 1124ba8c6fd5SDavid Greenman RFA_ALIGNMENT_FUDGE); 1125ba8c6fd5SDavid Greenman CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, 1126ba8c6fd5SDavid Greenman FXP_SCB_COMMAND_RU_START); 1127a17c678eSDavid Greenman } 1128a17c678eSDavid Greenman } 1129a17c678eSDavid Greenman } 113094927790SDavid Greenman FXP_UNLOCK(sc); 1131a17c678eSDavid Greenman } 1132a17c678eSDavid Greenman 1133dfe61cf1SDavid Greenman /* 1134dfe61cf1SDavid Greenman * Update packet in/out/collision statistics. The i82557 doesn't 1135dfe61cf1SDavid Greenman * allow you to access these counters without doing a fairly 1136dfe61cf1SDavid Greenman * expensive DMA to get _all_ of the statistics it maintains, so 1137dfe61cf1SDavid Greenman * we do this operation here only once per second. The statistics 1138dfe61cf1SDavid Greenman * counters in the kernel are updated from the previous dump-stats 1139dfe61cf1SDavid Greenman * DMA and then a new dump-stats DMA is started. The on-chip 1140dfe61cf1SDavid Greenman * counters are zeroed when the DMA completes. If we can't start 1141dfe61cf1SDavid Greenman * the DMA immediately, we don't wait - we just prepare to read 1142dfe61cf1SDavid Greenman * them again next time. 1143dfe61cf1SDavid Greenman */ 1144303b270bSEivind Eklund static void 1145a17c678eSDavid Greenman fxp_stats_update(arg) 1146a17c678eSDavid Greenman void *arg; 1147a17c678eSDavid Greenman { 1148a17c678eSDavid Greenman struct fxp_softc *sc = arg; 1149ba8c6fd5SDavid Greenman struct ifnet *ifp = &sc->sc_if; 1150a17c678eSDavid Greenman struct fxp_stats *sp = sc->fxp_stats; 1151c8cc6fcaSDavid Greenman struct fxp_cb_tx *txp; 1152a17c678eSDavid Greenman 1153a17c678eSDavid Greenman ifp->if_opackets += sp->tx_good; 1154a17c678eSDavid Greenman ifp->if_collisions += sp->tx_total_collisions; 1155397f9dfeSDavid Greenman if (sp->rx_good) { 1156397f9dfeSDavid Greenman ifp->if_ipackets += sp->rx_good; 1157397f9dfeSDavid Greenman sc->rx_idle_secs = 0; 1158397f9dfeSDavid Greenman } else { 1159c8cc6fcaSDavid Greenman /* 1160c8cc6fcaSDavid Greenman * Receiver's been idle for another second. 1161c8cc6fcaSDavid Greenman */ 1162397f9dfeSDavid Greenman sc->rx_idle_secs++; 1163397f9dfeSDavid Greenman } 11643ba65732SDavid Greenman ifp->if_ierrors += 11653ba65732SDavid Greenman sp->rx_crc_errors + 11663ba65732SDavid Greenman sp->rx_alignment_errors + 11673ba65732SDavid Greenman sp->rx_rnr_errors + 11686e39e599SDavid Greenman sp->rx_overrun_errors; 1169a17c678eSDavid Greenman /* 1170f9be9005SDavid Greenman * If any transmit underruns occured, bump up the transmit 1171f9be9005SDavid Greenman * threshold by another 512 bytes (64 * 8). 1172f9be9005SDavid Greenman */ 1173f9be9005SDavid Greenman if (sp->tx_underruns) { 1174f9be9005SDavid Greenman ifp->if_oerrors += sp->tx_underruns; 1175f9be9005SDavid Greenman if (tx_threshold < 192) 1176f9be9005SDavid Greenman tx_threshold += 64; 1177f9be9005SDavid Greenman } 117894927790SDavid Greenman FXP_LOCK(sc); 1179397f9dfeSDavid Greenman /* 1180c8cc6fcaSDavid Greenman * Release any xmit buffers that have completed DMA. This isn't 1181c8cc6fcaSDavid Greenman * strictly necessary to do here, but it's advantagous for mbufs 1182c8cc6fcaSDavid Greenman * with external storage to be released in a timely manner rather 1183c8cc6fcaSDavid Greenman * than being defered for a potentially long time. This limits 1184c8cc6fcaSDavid Greenman * the delay to a maximum of one second. 1185c8cc6fcaSDavid Greenman */ 1186c8cc6fcaSDavid Greenman for (txp = sc->cbl_first; sc->tx_queued && 1187c8cc6fcaSDavid Greenman (txp->cb_status & FXP_CB_STATUS_C) != 0; 1188c8cc6fcaSDavid Greenman txp = txp->next) { 1189c8cc6fcaSDavid Greenman if (txp->mb_head != NULL) { 1190c8cc6fcaSDavid Greenman m_freem(txp->mb_head); 1191c8cc6fcaSDavid Greenman txp->mb_head = NULL; 1192c8cc6fcaSDavid Greenman } 1193c8cc6fcaSDavid Greenman sc->tx_queued--; 1194c8cc6fcaSDavid Greenman } 1195c8cc6fcaSDavid Greenman sc->cbl_first = txp; 1196c8cc6fcaSDavid Greenman /* 1197397f9dfeSDavid Greenman * If we haven't received any packets in FXP_MAC_RX_IDLE seconds, 1198397f9dfeSDavid Greenman * then assume the receiver has locked up and attempt to clear 1199397f9dfeSDavid Greenman * the condition by reprogramming the multicast filter. This is 1200397f9dfeSDavid Greenman * a work-around for a bug in the 82557 where the receiver locks 1201397f9dfeSDavid Greenman * up if it gets certain types of garbage in the syncronization 1202397f9dfeSDavid Greenman * bits prior to the packet header. This bug is supposed to only 1203397f9dfeSDavid Greenman * occur in 10Mbps mode, but has been seen to occur in 100Mbps 1204397f9dfeSDavid Greenman * mode as well (perhaps due to a 10/100 speed transition). 1205397f9dfeSDavid Greenman */ 1206397f9dfeSDavid Greenman if (sc->rx_idle_secs > FXP_MAX_RX_IDLE) { 1207397f9dfeSDavid Greenman sc->rx_idle_secs = 0; 1208397f9dfeSDavid Greenman fxp_mc_setup(sc); 1209397f9dfeSDavid Greenman } 1210f9be9005SDavid Greenman /* 12113ba65732SDavid Greenman * If there is no pending command, start another stats 12123ba65732SDavid Greenman * dump. Otherwise punt for now. 1213a17c678eSDavid Greenman */ 1214397f9dfeSDavid Greenman if (CSR_READ_1(sc, FXP_CSR_SCB_COMMAND) == 0) { 1215a17c678eSDavid Greenman /* 1216397f9dfeSDavid Greenman * Start another stats dump. 1217a17c678eSDavid Greenman */ 1218ba8c6fd5SDavid Greenman CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, 1219ba8c6fd5SDavid Greenman FXP_SCB_COMMAND_CU_DUMPRESET); 1220dfe61cf1SDavid Greenman } else { 1221dfe61cf1SDavid Greenman /* 1222dfe61cf1SDavid Greenman * A previous command is still waiting to be accepted. 1223dfe61cf1SDavid Greenman * Just zero our copy of the stats and wait for the 12243ba65732SDavid Greenman * next timer event to update them. 1225dfe61cf1SDavid Greenman */ 1226dfe61cf1SDavid Greenman sp->tx_good = 0; 1227f9be9005SDavid Greenman sp->tx_underruns = 0; 1228dfe61cf1SDavid Greenman sp->tx_total_collisions = 0; 12293ba65732SDavid Greenman 1230dfe61cf1SDavid Greenman sp->rx_good = 0; 12313ba65732SDavid Greenman sp->rx_crc_errors = 0; 12323ba65732SDavid Greenman sp->rx_alignment_errors = 0; 12333ba65732SDavid Greenman sp->rx_rnr_errors = 0; 12343ba65732SDavid Greenman sp->rx_overrun_errors = 0; 1235dfe61cf1SDavid Greenman } 123694927790SDavid Greenman FXP_UNLOCK(sc); 1237a17c678eSDavid Greenman /* 1238a17c678eSDavid Greenman * Schedule another timeout one second from now. 1239a17c678eSDavid Greenman */ 1240397f9dfeSDavid Greenman sc->stat_ch = timeout(fxp_stats_update, sc, hz); 1241a17c678eSDavid Greenman } 1242a17c678eSDavid Greenman 1243a17c678eSDavid Greenman /* 1244a17c678eSDavid Greenman * Stop the interface. Cancels the statistics updater and resets 1245a17c678eSDavid Greenman * the interface. 1246a17c678eSDavid Greenman */ 1247a17c678eSDavid Greenman static void 12484a5f1499SDavid Greenman fxp_stop(sc) 12494a5f1499SDavid Greenman struct fxp_softc *sc; 1250a17c678eSDavid Greenman { 1251ba8c6fd5SDavid Greenman struct ifnet *ifp = &sc->sc_if; 12523ba65732SDavid Greenman struct fxp_cb_tx *txp; 12533ba65732SDavid Greenman int i; 1254a17c678eSDavid Greenman 125594927790SDavid Greenman FXP_LOCK(sc); 12560f4dc94cSChuck Paterson 12577dced78aSDavid Greenman ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); 12587dced78aSDavid Greenman ifp->if_timer = 0; 12597dced78aSDavid Greenman 1260a17c678eSDavid Greenman /* 1261a17c678eSDavid Greenman * Cancel stats updater. 1262a17c678eSDavid Greenman */ 12636c951b44SJustin T. Gibbs untimeout(fxp_stats_update, sc, sc->stat_ch); 12643ba65732SDavid Greenman 12653ba65732SDavid Greenman /* 12663ba65732SDavid Greenman * Issue software reset 12673ba65732SDavid Greenman */ 1268ba8c6fd5SDavid Greenman CSR_WRITE_4(sc, FXP_CSR_PORT, FXP_PORT_SELECTIVE_RESET); 1269a17c678eSDavid Greenman DELAY(10); 1270a17c678eSDavid Greenman 12713ba65732SDavid Greenman /* 12723ba65732SDavid Greenman * Release any xmit buffers. 12733ba65732SDavid Greenman */ 1274da91462dSDavid Greenman txp = sc->cbl_base; 1275da91462dSDavid Greenman if (txp != NULL) { 1276da91462dSDavid Greenman for (i = 0; i < FXP_NTXCB; i++) { 1277da91462dSDavid Greenman if (txp[i].mb_head != NULL) { 1278da91462dSDavid Greenman m_freem(txp[i].mb_head); 1279da91462dSDavid Greenman txp[i].mb_head = NULL; 1280da91462dSDavid Greenman } 1281da91462dSDavid Greenman } 12823ba65732SDavid Greenman } 12833ba65732SDavid Greenman sc->tx_queued = 0; 12843ba65732SDavid Greenman 12853ba65732SDavid Greenman /* 12863ba65732SDavid Greenman * Free all the receive buffers then reallocate/reinitialize 12873ba65732SDavid Greenman */ 12883ba65732SDavid Greenman if (sc->rfa_headm != NULL) 12893ba65732SDavid Greenman m_freem(sc->rfa_headm); 12903ba65732SDavid Greenman sc->rfa_headm = NULL; 12913ba65732SDavid Greenman sc->rfa_tailm = NULL; 12923ba65732SDavid Greenman for (i = 0; i < FXP_NRFABUFS; i++) { 12933ba65732SDavid Greenman if (fxp_add_rfabuf(sc, NULL) != 0) { 12943ba65732SDavid Greenman /* 12953ba65732SDavid Greenman * This "can't happen" - we're at splimp() 12963ba65732SDavid Greenman * and we just freed all the buffers we need 12973ba65732SDavid Greenman * above. 12983ba65732SDavid Greenman */ 12993ba65732SDavid Greenman panic("fxp_stop: no buffers!"); 13003ba65732SDavid Greenman } 13013ba65732SDavid Greenman } 13023ba65732SDavid Greenman 130394927790SDavid Greenman FXP_UNLOCK(sc); 1304a17c678eSDavid Greenman } 1305a17c678eSDavid Greenman 1306a17c678eSDavid Greenman /* 1307a17c678eSDavid Greenman * Watchdog/transmission transmit timeout handler. Called when a 1308a17c678eSDavid Greenman * transmission is started on the interface, but no interrupt is 1309a17c678eSDavid Greenman * received before the timeout. This usually indicates that the 1310a17c678eSDavid Greenman * card has wedged for some reason. 1311a17c678eSDavid Greenman */ 1312a17c678eSDavid Greenman static void 13134a5f1499SDavid Greenman fxp_watchdog(ifp) 13144a5f1499SDavid Greenman struct ifnet *ifp; 1315a17c678eSDavid Greenman { 1316ba8c6fd5SDavid Greenman struct fxp_softc *sc = ifp->if_softc; 1317ba8c6fd5SDavid Greenman 131894927790SDavid Greenman printf("fxp%d: device timeout\n", FXP_UNIT(sc)); 13194a5f1499SDavid Greenman ifp->if_oerrors++; 1320a17c678eSDavid Greenman 1321ba8c6fd5SDavid Greenman fxp_init(sc); 1322a17c678eSDavid Greenman } 1323a17c678eSDavid Greenman 1324a17c678eSDavid Greenman static void 1325fb583156SDavid Greenman fxp_init(xsc) 1326fb583156SDavid Greenman void *xsc; 1327a17c678eSDavid Greenman { 1328fb583156SDavid Greenman struct fxp_softc *sc = xsc; 1329ba8c6fd5SDavid Greenman struct ifnet *ifp = &sc->sc_if; 1330a17c678eSDavid Greenman struct fxp_cb_config *cbp; 1331a17c678eSDavid Greenman struct fxp_cb_ias *cb_ias; 1332a17c678eSDavid Greenman struct fxp_cb_tx *txp; 13330f4dc94cSChuck Paterson int i, prm; 1334a17c678eSDavid Greenman 133594927790SDavid Greenman FXP_LOCK(sc); 1336a17c678eSDavid Greenman /* 13373ba65732SDavid Greenman * Cancel any pending I/O 1338a17c678eSDavid Greenman */ 13393ba65732SDavid Greenman fxp_stop(sc); 1340a17c678eSDavid Greenman 1341a17c678eSDavid Greenman prm = (ifp->if_flags & IFF_PROMISC) ? 1 : 0; 1342a17c678eSDavid Greenman 1343a17c678eSDavid Greenman /* 1344a17c678eSDavid Greenman * Initialize base of CBL and RFA memory. Loading with zero 1345a17c678eSDavid Greenman * sets it up for regular linear addressing. 1346a17c678eSDavid Greenman */ 1347ba8c6fd5SDavid Greenman CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, 0); 1348ba8c6fd5SDavid Greenman CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_BASE); 1349a17c678eSDavid Greenman 1350ba8c6fd5SDavid Greenman fxp_scb_wait(sc); 1351ba8c6fd5SDavid Greenman CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_RU_BASE); 1352a17c678eSDavid Greenman 1353a17c678eSDavid Greenman /* 1354a17c678eSDavid Greenman * Initialize base of dump-stats buffer. 1355a17c678eSDavid Greenman */ 1356ba8c6fd5SDavid Greenman fxp_scb_wait(sc); 1357ba8c6fd5SDavid Greenman CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, vtophys(sc->fxp_stats)); 1358ba8c6fd5SDavid Greenman CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_DUMP_ADR); 1359a17c678eSDavid Greenman 1360a17c678eSDavid Greenman /* 1361a17c678eSDavid Greenman * We temporarily use memory that contains the TxCB list to 1362a17c678eSDavid Greenman * construct the config CB. The TxCB list memory is rebuilt 1363a17c678eSDavid Greenman * later. 1364a17c678eSDavid Greenman */ 1365a17c678eSDavid Greenman cbp = (struct fxp_cb_config *) sc->cbl_base; 1366a17c678eSDavid Greenman 1367a17c678eSDavid Greenman /* 1368a17c678eSDavid Greenman * This bcopy is kind of disgusting, but there are a bunch of must be 1369a17c678eSDavid Greenman * zero and must be one bits in this structure and this is the easiest 1370a17c678eSDavid Greenman * way to initialize them all to proper values. 1371a17c678eSDavid Greenman */ 1372d244b0e9SPeter Wemm bcopy(fxp_cb_config_template, 1373d244b0e9SPeter Wemm (void *)(uintptr_t)(volatile void *)&cbp->cb_status, 1374397f9dfeSDavid Greenman sizeof(fxp_cb_config_template)); 1375a17c678eSDavid Greenman 1376a17c678eSDavid Greenman cbp->cb_status = 0; 1377a17c678eSDavid Greenman cbp->cb_command = FXP_CB_COMMAND_CONFIG | FXP_CB_COMMAND_EL; 1378a17c678eSDavid Greenman cbp->link_addr = -1; /* (no) next command */ 1379a17c678eSDavid Greenman cbp->byte_count = 22; /* (22) bytes to config */ 1380001696daSDavid Greenman cbp->rx_fifo_limit = 8; /* rx fifo threshold (32 bytes) */ 1381001696daSDavid Greenman cbp->tx_fifo_limit = 0; /* tx fifo threshold (0 bytes) */ 1382a17c678eSDavid Greenman cbp->adaptive_ifs = 0; /* (no) adaptive interframe spacing */ 1383001696daSDavid Greenman cbp->rx_dma_bytecount = 0; /* (no) rx DMA max */ 1384001696daSDavid Greenman cbp->tx_dma_bytecount = 0; /* (no) tx DMA max */ 1385001696daSDavid Greenman cbp->dma_bce = 0; /* (disable) dma max counters */ 1386a17c678eSDavid Greenman cbp->late_scb = 0; /* (don't) defer SCB update */ 1387a17c678eSDavid Greenman cbp->tno_int = 0; /* (disable) tx not okay interrupt */ 13883114fdb4SDavid Greenman cbp->ci_int = 1; /* interrupt on CU idle */ 1389a17c678eSDavid Greenman cbp->save_bf = prm; /* save bad frames */ 1390a17c678eSDavid Greenman cbp->disc_short_rx = !prm; /* discard short packets */ 1391a17c678eSDavid Greenman cbp->underrun_retry = 1; /* retry mode (1) on DMA underrun */ 1392dccee1a1SDavid Greenman cbp->mediatype = !sc->phy_10Mbps_only; /* interface mode */ 1393a17c678eSDavid Greenman cbp->nsai = 1; /* (don't) disable source addr insert */ 1394a17c678eSDavid Greenman cbp->preamble_length = 2; /* (7 byte) preamble */ 1395a17c678eSDavid Greenman cbp->loopback = 0; /* (don't) loopback */ 1396a17c678eSDavid Greenman cbp->linear_priority = 0; /* (normal CSMA/CD operation) */ 1397a17c678eSDavid Greenman cbp->linear_pri_mode = 0; /* (wait after xmit only) */ 1398a17c678eSDavid Greenman cbp->interfrm_spacing = 6; /* (96 bits of) interframe spacing */ 1399a17c678eSDavid Greenman cbp->promiscuous = prm; /* promiscuous mode */ 1400a17c678eSDavid Greenman cbp->bcast_disable = 0; /* (don't) disable broadcasts */ 1401001696daSDavid Greenman cbp->crscdt = 0; /* (CRS only) */ 1402a17c678eSDavid Greenman cbp->stripping = !prm; /* truncate rx packet to byte count */ 1403a17c678eSDavid Greenman cbp->padding = 1; /* (do) pad short tx packets */ 1404a17c678eSDavid Greenman cbp->rcv_crc_xfer = 0; /* (don't) xfer CRC to host */ 1405a17c678eSDavid Greenman cbp->force_fdx = 0; /* (don't) force full duplex */ 14063ba65732SDavid Greenman cbp->fdx_pin_en = 1; /* (enable) FDX# pin */ 1407a17c678eSDavid Greenman cbp->multi_ia = 0; /* (don't) accept multiple IAs */ 1408397f9dfeSDavid Greenman cbp->mc_all = sc->all_mcasts;/* accept all multicasts */ 1409a17c678eSDavid Greenman 1410a17c678eSDavid Greenman /* 1411a17c678eSDavid Greenman * Start the config command/DMA. 1412a17c678eSDavid Greenman */ 1413ba8c6fd5SDavid Greenman fxp_scb_wait(sc); 1414397f9dfeSDavid Greenman CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, vtophys(&cbp->cb_status)); 1415ba8c6fd5SDavid Greenman CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START); 1416a17c678eSDavid Greenman /* ...and wait for it to complete. */ 14177dced78aSDavid Greenman fxp_dma_wait(&cbp->cb_status, sc); 1418a17c678eSDavid Greenman 1419a17c678eSDavid Greenman /* 1420a17c678eSDavid Greenman * Now initialize the station address. Temporarily use the TxCB 1421a17c678eSDavid Greenman * memory area like we did above for the config CB. 1422a17c678eSDavid Greenman */ 1423a17c678eSDavid Greenman cb_ias = (struct fxp_cb_ias *) sc->cbl_base; 1424a17c678eSDavid Greenman cb_ias->cb_status = 0; 1425a17c678eSDavid Greenman cb_ias->cb_command = FXP_CB_COMMAND_IAS | FXP_CB_COMMAND_EL; 1426a17c678eSDavid Greenman cb_ias->link_addr = -1; 1427d244b0e9SPeter Wemm bcopy(sc->arpcom.ac_enaddr, 1428d244b0e9SPeter Wemm (void *)(uintptr_t)(volatile void *)cb_ias->macaddr, 1429a17c678eSDavid Greenman sizeof(sc->arpcom.ac_enaddr)); 1430a17c678eSDavid Greenman 1431a17c678eSDavid Greenman /* 1432a17c678eSDavid Greenman * Start the IAS (Individual Address Setup) command/DMA. 1433a17c678eSDavid Greenman */ 1434ba8c6fd5SDavid Greenman fxp_scb_wait(sc); 1435ba8c6fd5SDavid Greenman CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START); 1436a17c678eSDavid Greenman /* ...and wait for it to complete. */ 14377dced78aSDavid Greenman fxp_dma_wait(&cb_ias->cb_status, sc); 1438a17c678eSDavid Greenman 1439a17c678eSDavid Greenman /* 1440a17c678eSDavid Greenman * Initialize transmit control block (TxCB) list. 1441a17c678eSDavid Greenman */ 1442a17c678eSDavid Greenman 1443a17c678eSDavid Greenman txp = sc->cbl_base; 1444a17c678eSDavid Greenman bzero(txp, sizeof(struct fxp_cb_tx) * FXP_NTXCB); 1445a17c678eSDavid Greenman for (i = 0; i < FXP_NTXCB; i++) { 1446a17c678eSDavid Greenman txp[i].cb_status = FXP_CB_STATUS_C | FXP_CB_STATUS_OK; 1447a17c678eSDavid Greenman txp[i].cb_command = FXP_CB_COMMAND_NOP; 1448397f9dfeSDavid Greenman txp[i].link_addr = vtophys(&txp[(i + 1) & FXP_TXCB_MASK].cb_status); 1449a17c678eSDavid Greenman txp[i].tbd_array_addr = vtophys(&txp[i].tbd[0]); 1450a17c678eSDavid Greenman txp[i].next = &txp[(i + 1) & FXP_TXCB_MASK]; 1451a17c678eSDavid Greenman } 1452a17c678eSDavid Greenman /* 1453397f9dfeSDavid Greenman * Set the suspend flag on the first TxCB and start the control 1454a17c678eSDavid Greenman * unit. It will execute the NOP and then suspend. 1455a17c678eSDavid Greenman */ 1456a17c678eSDavid Greenman txp->cb_command = FXP_CB_COMMAND_NOP | FXP_CB_COMMAND_S; 1457a17c678eSDavid Greenman sc->cbl_first = sc->cbl_last = txp; 1458397f9dfeSDavid Greenman sc->tx_queued = 1; 1459a17c678eSDavid Greenman 1460ba8c6fd5SDavid Greenman fxp_scb_wait(sc); 1461ba8c6fd5SDavid Greenman CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START); 1462a17c678eSDavid Greenman 1463a17c678eSDavid Greenman /* 1464a17c678eSDavid Greenman * Initialize receiver buffer area - RFA. 1465a17c678eSDavid Greenman */ 1466ba8c6fd5SDavid Greenman fxp_scb_wait(sc); 1467ba8c6fd5SDavid Greenman CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, 1468ba8c6fd5SDavid Greenman vtophys(sc->rfa_headm->m_ext.ext_buf) + RFA_ALIGNMENT_FUDGE); 1469ba8c6fd5SDavid Greenman CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_RU_START); 1470a17c678eSDavid Greenman 1471dccee1a1SDavid Greenman /* 1472ba8c6fd5SDavid Greenman * Set current media. 1473dccee1a1SDavid Greenman */ 1474ba8c6fd5SDavid Greenman fxp_set_media(sc, sc->sc_media.ifm_cur->ifm_media); 1475dccee1a1SDavid Greenman 1476a17c678eSDavid Greenman ifp->if_flags |= IFF_RUNNING; 1477a17c678eSDavid Greenman ifp->if_flags &= ~IFF_OACTIVE; 147894927790SDavid Greenman FXP_UNLOCK(sc); 1479a17c678eSDavid Greenman 1480a17c678eSDavid Greenman /* 1481a17c678eSDavid Greenman * Start stats updater. 1482a17c678eSDavid Greenman */ 14836c951b44SJustin T. Gibbs sc->stat_ch = timeout(fxp_stats_update, sc, hz); 1484a17c678eSDavid Greenman } 1485a17c678eSDavid Greenman 1486303b270bSEivind Eklund static void 1487ba8c6fd5SDavid Greenman fxp_set_media(sc, media) 1488ba8c6fd5SDavid Greenman struct fxp_softc *sc; 1489ba8c6fd5SDavid Greenman int media; 1490ba8c6fd5SDavid Greenman { 1491ba8c6fd5SDavid Greenman 1492ba8c6fd5SDavid Greenman switch (sc->phy_primary_device) { 1493ba8c6fd5SDavid Greenman case FXP_PHY_DP83840: 1494ba8c6fd5SDavid Greenman case FXP_PHY_DP83840A: 1495ba8c6fd5SDavid Greenman fxp_mdi_write(sc, sc->phy_primary_addr, FXP_DP83840_PCR, 1496ba8c6fd5SDavid Greenman fxp_mdi_read(sc, sc->phy_primary_addr, FXP_DP83840_PCR) | 1497ba8c6fd5SDavid Greenman FXP_DP83840_PCR_LED4_MODE | /* LED4 always indicates duplex */ 1498ba8c6fd5SDavid Greenman FXP_DP83840_PCR_F_CONNECT | /* force link disconnect bypass */ 1499ba8c6fd5SDavid Greenman FXP_DP83840_PCR_BIT10); /* XXX I have no idea */ 1500ba8c6fd5SDavid Greenman /* fall through */ 150192924291SDavid Greenman case FXP_PHY_82553A: 150292924291SDavid Greenman case FXP_PHY_82553C: /* untested */ 1503ba8c6fd5SDavid Greenman case FXP_PHY_82555: 150492924291SDavid Greenman case FXP_PHY_82555B: 1505ba8c6fd5SDavid Greenman if (IFM_SUBTYPE(media) != IFM_AUTO) { 1506ba8c6fd5SDavid Greenman int flags; 1507ba8c6fd5SDavid Greenman 1508ba8c6fd5SDavid Greenman flags = (IFM_SUBTYPE(media) == IFM_100_TX) ? 1509ba8c6fd5SDavid Greenman FXP_PHY_BMCR_SPEED_100M : 0; 1510ba8c6fd5SDavid Greenman flags |= (media & IFM_FDX) ? 1511ba8c6fd5SDavid Greenman FXP_PHY_BMCR_FULLDUPLEX : 0; 1512ba8c6fd5SDavid Greenman fxp_mdi_write(sc, sc->phy_primary_addr, 1513ba8c6fd5SDavid Greenman FXP_PHY_BMCR, 1514ba8c6fd5SDavid Greenman (fxp_mdi_read(sc, sc->phy_primary_addr, 1515ba8c6fd5SDavid Greenman FXP_PHY_BMCR) & 1516ba8c6fd5SDavid Greenman ~(FXP_PHY_BMCR_AUTOEN | FXP_PHY_BMCR_SPEED_100M | 1517ba8c6fd5SDavid Greenman FXP_PHY_BMCR_FULLDUPLEX)) | flags); 1518ba8c6fd5SDavid Greenman } else { 1519ba8c6fd5SDavid Greenman fxp_mdi_write(sc, sc->phy_primary_addr, 1520ba8c6fd5SDavid Greenman FXP_PHY_BMCR, 1521ba8c6fd5SDavid Greenman (fxp_mdi_read(sc, sc->phy_primary_addr, 1522ba8c6fd5SDavid Greenman FXP_PHY_BMCR) | FXP_PHY_BMCR_AUTOEN)); 1523ba8c6fd5SDavid Greenman } 1524ba8c6fd5SDavid Greenman break; 1525ba8c6fd5SDavid Greenman /* 1526ba8c6fd5SDavid Greenman * The Seeq 80c24 doesn't have a PHY programming interface, so do 1527ba8c6fd5SDavid Greenman * nothing. 1528ba8c6fd5SDavid Greenman */ 1529ba8c6fd5SDavid Greenman case FXP_PHY_80C24: 1530ba8c6fd5SDavid Greenman break; 1531ba8c6fd5SDavid Greenman default: 153294927790SDavid Greenman printf("fxp%d: warning: unsupported PHY, type = %d, addr = %d\n", 153394927790SDavid Greenman FXP_UNIT(sc), sc->phy_primary_device, 1534ba8c6fd5SDavid Greenman sc->phy_primary_addr); 1535ba8c6fd5SDavid Greenman } 1536ba8c6fd5SDavid Greenman } 1537ba8c6fd5SDavid Greenman 1538ba8c6fd5SDavid Greenman /* 1539ba8c6fd5SDavid Greenman * Change media according to request. 1540ba8c6fd5SDavid Greenman */ 1541ba8c6fd5SDavid Greenman int 1542ba8c6fd5SDavid Greenman fxp_mediachange(ifp) 1543ba8c6fd5SDavid Greenman struct ifnet *ifp; 1544ba8c6fd5SDavid Greenman { 1545ba8c6fd5SDavid Greenman struct fxp_softc *sc = ifp->if_softc; 1546ba8c6fd5SDavid Greenman struct ifmedia *ifm = &sc->sc_media; 1547ba8c6fd5SDavid Greenman 1548ba8c6fd5SDavid Greenman if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) 1549ba8c6fd5SDavid Greenman return (EINVAL); 1550ba8c6fd5SDavid Greenman 1551ba8c6fd5SDavid Greenman fxp_set_media(sc, ifm->ifm_media); 1552ba8c6fd5SDavid Greenman return (0); 1553ba8c6fd5SDavid Greenman } 1554ba8c6fd5SDavid Greenman 1555ba8c6fd5SDavid Greenman /* 1556ba8c6fd5SDavid Greenman * Notify the world which media we're using. 1557ba8c6fd5SDavid Greenman */ 1558ba8c6fd5SDavid Greenman void 1559ba8c6fd5SDavid Greenman fxp_mediastatus(ifp, ifmr) 1560ba8c6fd5SDavid Greenman struct ifnet *ifp; 1561ba8c6fd5SDavid Greenman struct ifmediareq *ifmr; 1562ba8c6fd5SDavid Greenman { 1563ba8c6fd5SDavid Greenman struct fxp_softc *sc = ifp->if_softc; 1564a7280784SJulian Elischer int flags, stsflags; 1565ba8c6fd5SDavid Greenman 1566ba8c6fd5SDavid Greenman switch (sc->phy_primary_device) { 1567ba8c6fd5SDavid Greenman case FXP_PHY_82555: 156835517ab7SDavid Greenman case FXP_PHY_82555B: 1569a7280784SJulian Elischer case FXP_PHY_DP83840: 1570a7280784SJulian Elischer case FXP_PHY_DP83840A: 1571a7280784SJulian Elischer ifmr->ifm_status = IFM_AVALID; /* IFM_ACTIVE will be valid */ 1572ba8c6fd5SDavid Greenman ifmr->ifm_active = IFM_ETHER; 1573a7280784SJulian Elischer /* 1574a7280784SJulian Elischer * the following is not an error. 1575a7280784SJulian Elischer * You need to read this register twice to get current 1576a7280784SJulian Elischer * status. This is correct documented behaviour, the 1577a7280784SJulian Elischer * first read gets latched values. 1578a7280784SJulian Elischer */ 1579a7280784SJulian Elischer stsflags = fxp_mdi_read(sc, sc->phy_primary_addr, FXP_PHY_STS); 1580a7280784SJulian Elischer stsflags = fxp_mdi_read(sc, sc->phy_primary_addr, FXP_PHY_STS); 1581a7280784SJulian Elischer if (stsflags & FXP_PHY_STS_LINK_STS) 1582a7280784SJulian Elischer ifmr->ifm_status |= IFM_ACTIVE; 1583a7280784SJulian Elischer 1584a7280784SJulian Elischer /* 1585a7280784SJulian Elischer * If we are in auto mode, then try report the result. 1586a7280784SJulian Elischer */ 1587a7280784SJulian Elischer flags = fxp_mdi_read(sc, sc->phy_primary_addr, FXP_PHY_BMCR); 1588f1bf08c2SJulian Elischer if (flags & FXP_PHY_BMCR_AUTOEN) { 1589f1bf08c2SJulian Elischer ifmr->ifm_active |= IFM_AUTO; /* XXX presently 0 */ 1590a7280784SJulian Elischer if (stsflags & FXP_PHY_STS_AUTO_DONE) { 1591f1bf08c2SJulian Elischer /* 1592a7280784SJulian Elischer * Intel and National parts report 1593a7280784SJulian Elischer * differently on what they found. 1594f1bf08c2SJulian Elischer */ 1595f1bf08c2SJulian Elischer if ((sc->phy_primary_device == FXP_PHY_82555) 1596f1bf08c2SJulian Elischer || (sc->phy_primary_device == FXP_PHY_82555B)) { 1597f1bf08c2SJulian Elischer flags = fxp_mdi_read(sc, 1598a7280784SJulian Elischer sc->phy_primary_addr, 1599a7280784SJulian Elischer FXP_PHY_USC); 1600f1bf08c2SJulian Elischer 1601f1bf08c2SJulian Elischer if (flags & FXP_PHY_USC_SPEED) 1602f1bf08c2SJulian Elischer ifmr->ifm_active |= IFM_100_TX; 1603f1bf08c2SJulian Elischer else 1604f1bf08c2SJulian Elischer ifmr->ifm_active |= IFM_10_T; 1605f1bf08c2SJulian Elischer 1606f1bf08c2SJulian Elischer if (flags & FXP_PHY_USC_DUPLEX) 1607f1bf08c2SJulian Elischer ifmr->ifm_active |= IFM_FDX; 1608a7280784SJulian Elischer } else { /* it's National. only know speed */ 1609a7280784SJulian Elischer flags = fxp_mdi_read(sc, 1610a7280784SJulian Elischer sc->phy_primary_addr, 1611a7280784SJulian Elischer FXP_DP83840_PAR); 1612a7280784SJulian Elischer 1613a7280784SJulian Elischer if (flags & FXP_DP83840_PAR_SPEED_10) 1614a7280784SJulian Elischer ifmr->ifm_active |= IFM_10_T; 1615a7280784SJulian Elischer else 1616a7280784SJulian Elischer ifmr->ifm_active |= IFM_100_TX; 1617f1bf08c2SJulian Elischer } 1618a7280784SJulian Elischer } 1619a7280784SJulian Elischer } else { /* in manual mode.. just report what we were set to */ 1620ba8c6fd5SDavid Greenman if (flags & FXP_PHY_BMCR_SPEED_100M) 1621ba8c6fd5SDavid Greenman ifmr->ifm_active |= IFM_100_TX; 1622ba8c6fd5SDavid Greenman else 1623ba8c6fd5SDavid Greenman ifmr->ifm_active |= IFM_10_T; 1624ba8c6fd5SDavid Greenman 1625ba8c6fd5SDavid Greenman if (flags & FXP_PHY_BMCR_FULLDUPLEX) 1626ba8c6fd5SDavid Greenman ifmr->ifm_active |= IFM_FDX; 1627ba8c6fd5SDavid Greenman } 1628ba8c6fd5SDavid Greenman break; 1629ba8c6fd5SDavid Greenman 1630ba8c6fd5SDavid Greenman case FXP_PHY_80C24: 1631ba8c6fd5SDavid Greenman default: 1632ba8c6fd5SDavid Greenman ifmr->ifm_active = IFM_ETHER|IFM_MANUAL; /* XXX IFM_AUTO ? */ 1633ba8c6fd5SDavid Greenman } 1634ba8c6fd5SDavid Greenman } 1635ba8c6fd5SDavid Greenman 1636a17c678eSDavid Greenman /* 1637a17c678eSDavid Greenman * Add a buffer to the end of the RFA buffer list. 1638a17c678eSDavid Greenman * Return 0 if successful, 1 for failure. A failure results in 1639a17c678eSDavid Greenman * adding the 'oldm' (if non-NULL) on to the end of the list - 1640dc733423SDag-Erling Smørgrav * tossing out its old contents and recycling it. 1641a17c678eSDavid Greenman * The RFA struct is stuck at the beginning of mbuf cluster and the 1642a17c678eSDavid Greenman * data pointer is fixed up to point just past it. 1643a17c678eSDavid Greenman */ 1644a17c678eSDavid Greenman static int 1645a17c678eSDavid Greenman fxp_add_rfabuf(sc, oldm) 1646a17c678eSDavid Greenman struct fxp_softc *sc; 1647a17c678eSDavid Greenman struct mbuf *oldm; 1648a17c678eSDavid Greenman { 1649ba8c6fd5SDavid Greenman u_int32_t v; 1650a17c678eSDavid Greenman struct mbuf *m; 1651a17c678eSDavid Greenman struct fxp_rfa *rfa, *p_rfa; 1652a17c678eSDavid Greenman 1653a17c678eSDavid Greenman MGETHDR(m, M_DONTWAIT, MT_DATA); 1654a17c678eSDavid Greenman if (m != NULL) { 1655a17c678eSDavid Greenman MCLGET(m, M_DONTWAIT); 1656a17c678eSDavid Greenman if ((m->m_flags & M_EXT) == 0) { 1657a17c678eSDavid Greenman m_freem(m); 1658eadd5e3aSDavid Greenman if (oldm == NULL) 1659eadd5e3aSDavid Greenman return 1; 1660a17c678eSDavid Greenman m = oldm; 1661eadd5e3aSDavid Greenman m->m_data = m->m_ext.ext_buf; 1662a17c678eSDavid Greenman } 1663a17c678eSDavid Greenman } else { 1664eadd5e3aSDavid Greenman if (oldm == NULL) 1665a17c678eSDavid Greenman return 1; 1666eadd5e3aSDavid Greenman m = oldm; 1667eadd5e3aSDavid Greenman m->m_data = m->m_ext.ext_buf; 1668eadd5e3aSDavid Greenman } 1669ba8c6fd5SDavid Greenman 1670ba8c6fd5SDavid Greenman /* 1671ba8c6fd5SDavid Greenman * Move the data pointer up so that the incoming data packet 1672ba8c6fd5SDavid Greenman * will be 32-bit aligned. 1673ba8c6fd5SDavid Greenman */ 1674ba8c6fd5SDavid Greenman m->m_data += RFA_ALIGNMENT_FUDGE; 1675ba8c6fd5SDavid Greenman 1676eadd5e3aSDavid Greenman /* 1677eadd5e3aSDavid Greenman * Get a pointer to the base of the mbuf cluster and move 1678eadd5e3aSDavid Greenman * data start past it. 1679eadd5e3aSDavid Greenman */ 1680a17c678eSDavid Greenman rfa = mtod(m, struct fxp_rfa *); 1681eadd5e3aSDavid Greenman m->m_data += sizeof(struct fxp_rfa); 16824fc1dda9SAndrew Gallatin rfa->size = (u_int16_t)(MCLBYTES - sizeof(struct fxp_rfa) - RFA_ALIGNMENT_FUDGE); 1683eadd5e3aSDavid Greenman 1684ba8c6fd5SDavid Greenman /* 1685ba8c6fd5SDavid Greenman * Initialize the rest of the RFA. Note that since the RFA 1686ba8c6fd5SDavid Greenman * is misaligned, we cannot store values directly. Instead, 1687ba8c6fd5SDavid Greenman * we use an optimized, inline copy. 1688ba8c6fd5SDavid Greenman */ 16894fc1dda9SAndrew Gallatin 1690a17c678eSDavid Greenman rfa->rfa_status = 0; 1691a17c678eSDavid Greenman rfa->rfa_control = FXP_RFA_CONTROL_EL; 1692a17c678eSDavid Greenman rfa->actual_size = 0; 1693ba8c6fd5SDavid Greenman 1694ba8c6fd5SDavid Greenman v = -1; 16954fc1dda9SAndrew Gallatin fxp_lwcopy(&v, (volatile u_int32_t *) rfa->link_addr); 16964fc1dda9SAndrew Gallatin fxp_lwcopy(&v, (volatile u_int32_t *) rfa->rbd_addr); 1697ba8c6fd5SDavid Greenman 1698dfe61cf1SDavid Greenman /* 1699dfe61cf1SDavid Greenman * If there are other buffers already on the list, attach this 1700dfe61cf1SDavid Greenman * one to the end by fixing up the tail to point to this one. 1701dfe61cf1SDavid Greenman */ 1702a17c678eSDavid Greenman if (sc->rfa_headm != NULL) { 1703ba8c6fd5SDavid Greenman p_rfa = (struct fxp_rfa *) (sc->rfa_tailm->m_ext.ext_buf + 1704ba8c6fd5SDavid Greenman RFA_ALIGNMENT_FUDGE); 1705a17c678eSDavid Greenman sc->rfa_tailm->m_next = m; 1706ba8c6fd5SDavid Greenman v = vtophys(rfa); 17074fc1dda9SAndrew Gallatin fxp_lwcopy(&v, (volatile u_int32_t *) p_rfa->link_addr); 1708aed53495SDavid Greenman p_rfa->rfa_control = 0; 1709a17c678eSDavid Greenman } else { 1710a17c678eSDavid Greenman sc->rfa_headm = m; 1711a17c678eSDavid Greenman } 1712a17c678eSDavid Greenman sc->rfa_tailm = m; 1713a17c678eSDavid Greenman 1714dfe61cf1SDavid Greenman return (m == oldm); 1715a17c678eSDavid Greenman } 1716a17c678eSDavid Greenman 17176ebc3153SDavid Greenman static volatile int 1718ba8c6fd5SDavid Greenman fxp_mdi_read(sc, phy, reg) 1719ba8c6fd5SDavid Greenman struct fxp_softc *sc; 1720dccee1a1SDavid Greenman int phy; 1721dccee1a1SDavid Greenman int reg; 1722dccee1a1SDavid Greenman { 1723dccee1a1SDavid Greenman int count = 10000; 17246ebc3153SDavid Greenman int value; 1725dccee1a1SDavid Greenman 1726ba8c6fd5SDavid Greenman CSR_WRITE_4(sc, FXP_CSR_MDICONTROL, 1727ba8c6fd5SDavid Greenman (FXP_MDI_READ << 26) | (reg << 16) | (phy << 21)); 1728dccee1a1SDavid Greenman 1729ba8c6fd5SDavid Greenman while (((value = CSR_READ_4(sc, FXP_CSR_MDICONTROL)) & 0x10000000) == 0 1730ba8c6fd5SDavid Greenman && count--) 17316ebc3153SDavid Greenman DELAY(10); 1732dccee1a1SDavid Greenman 1733dccee1a1SDavid Greenman if (count <= 0) 173494927790SDavid Greenman printf("fxp%d: fxp_mdi_read: timed out\n", FXP_UNIT(sc)); 1735dccee1a1SDavid Greenman 17366ebc3153SDavid Greenman return (value & 0xffff); 1737dccee1a1SDavid Greenman } 1738dccee1a1SDavid Greenman 1739dccee1a1SDavid Greenman static void 1740ba8c6fd5SDavid Greenman fxp_mdi_write(sc, phy, reg, value) 1741ba8c6fd5SDavid Greenman struct fxp_softc *sc; 1742dccee1a1SDavid Greenman int phy; 1743dccee1a1SDavid Greenman int reg; 1744dccee1a1SDavid Greenman int value; 1745dccee1a1SDavid Greenman { 1746dccee1a1SDavid Greenman int count = 10000; 1747dccee1a1SDavid Greenman 1748ba8c6fd5SDavid Greenman CSR_WRITE_4(sc, FXP_CSR_MDICONTROL, 1749ba8c6fd5SDavid Greenman (FXP_MDI_WRITE << 26) | (reg << 16) | (phy << 21) | 1750ba8c6fd5SDavid Greenman (value & 0xffff)); 1751dccee1a1SDavid Greenman 1752ba8c6fd5SDavid Greenman while((CSR_READ_4(sc, FXP_CSR_MDICONTROL) & 0x10000000) == 0 && 1753ba8c6fd5SDavid Greenman count--) 17546ebc3153SDavid Greenman DELAY(10); 1755dccee1a1SDavid Greenman 1756dccee1a1SDavid Greenman if (count <= 0) 175794927790SDavid Greenman printf("fxp%d: fxp_mdi_write: timed out\n", FXP_UNIT(sc)); 1758dccee1a1SDavid Greenman } 1759dccee1a1SDavid Greenman 1760dccee1a1SDavid Greenman static int 1761a17c678eSDavid Greenman fxp_ioctl(ifp, command, data) 1762a17c678eSDavid Greenman struct ifnet *ifp; 176394927790SDavid Greenman u_long command; 1764a17c678eSDavid Greenman caddr_t data; 1765a17c678eSDavid Greenman { 17669b44ff22SGarrett Wollman struct fxp_softc *sc = ifp->if_softc; 1767a17c678eSDavid Greenman struct ifreq *ifr = (struct ifreq *)data; 17680f4dc94cSChuck Paterson int error = 0; 1769a17c678eSDavid Greenman 177094927790SDavid Greenman FXP_LOCK(sc); 1771a17c678eSDavid Greenman 1772a17c678eSDavid Greenman switch (command) { 1773a17c678eSDavid Greenman 1774a17c678eSDavid Greenman case SIOCSIFADDR: 1775a17c678eSDavid Greenman case SIOCGIFADDR: 1776fb583156SDavid Greenman case SIOCSIFMTU: 1777fb583156SDavid Greenman error = ether_ioctl(ifp, command, data); 1778a17c678eSDavid Greenman break; 1779a17c678eSDavid Greenman 1780a17c678eSDavid Greenman case SIOCSIFFLAGS: 1781397f9dfeSDavid Greenman sc->all_mcasts = (ifp->if_flags & IFF_ALLMULTI) ? 1 : 0; 1782a17c678eSDavid Greenman 1783a17c678eSDavid Greenman /* 1784a17c678eSDavid Greenman * If interface is marked up and not running, then start it. 1785a17c678eSDavid Greenman * If it is marked down and running, stop it. 1786a17c678eSDavid Greenman * XXX If it's up then re-initialize it. This is so flags 1787a17c678eSDavid Greenman * such as IFF_PROMISC are handled. 1788a17c678eSDavid Greenman */ 1789a17c678eSDavid Greenman if (ifp->if_flags & IFF_UP) { 1790fb583156SDavid Greenman fxp_init(sc); 1791a17c678eSDavid Greenman } else { 1792a17c678eSDavid Greenman if (ifp->if_flags & IFF_RUNNING) 17934a5f1499SDavid Greenman fxp_stop(sc); 1794a17c678eSDavid Greenman } 1795a17c678eSDavid Greenman break; 1796a17c678eSDavid Greenman 1797a17c678eSDavid Greenman case SIOCADDMULTI: 1798a17c678eSDavid Greenman case SIOCDELMULTI: 1799397f9dfeSDavid Greenman sc->all_mcasts = (ifp->if_flags & IFF_ALLMULTI) ? 1 : 0; 1800a17c678eSDavid Greenman /* 1801a17c678eSDavid Greenman * Multicast list has changed; set the hardware filter 1802a17c678eSDavid Greenman * accordingly. 1803a17c678eSDavid Greenman */ 1804397f9dfeSDavid Greenman if (!sc->all_mcasts) 1805397f9dfeSDavid Greenman fxp_mc_setup(sc); 1806397f9dfeSDavid Greenman /* 1807397f9dfeSDavid Greenman * fxp_mc_setup() can turn on sc->all_mcasts, so check it 1808397f9dfeSDavid Greenman * again rather than else {}. 1809397f9dfeSDavid Greenman */ 1810397f9dfeSDavid Greenman if (sc->all_mcasts) 1811fb583156SDavid Greenman fxp_init(sc); 1812a17c678eSDavid Greenman error = 0; 1813ba8c6fd5SDavid Greenman break; 1814ba8c6fd5SDavid Greenman 1815ba8c6fd5SDavid Greenman case SIOCSIFMEDIA: 1816ba8c6fd5SDavid Greenman case SIOCGIFMEDIA: 1817ba8c6fd5SDavid Greenman error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, command); 1818a17c678eSDavid Greenman break; 1819a17c678eSDavid Greenman 1820a17c678eSDavid Greenman default: 1821a17c678eSDavid Greenman error = EINVAL; 1822a17c678eSDavid Greenman } 182394927790SDavid Greenman FXP_UNLOCK(sc); 1824a17c678eSDavid Greenman return (error); 1825a17c678eSDavid Greenman } 1826397f9dfeSDavid Greenman 1827397f9dfeSDavid Greenman /* 1828397f9dfeSDavid Greenman * Program the multicast filter. 1829397f9dfeSDavid Greenman * 1830397f9dfeSDavid Greenman * We have an artificial restriction that the multicast setup command 1831397f9dfeSDavid Greenman * must be the first command in the chain, so we take steps to ensure 18323114fdb4SDavid Greenman * this. By requiring this, it allows us to keep up the performance of 1833397f9dfeSDavid Greenman * the pre-initialized command ring (esp. link pointers) by not actually 1834dc733423SDag-Erling Smørgrav * inserting the mcsetup command in the ring - i.e. its link pointer 1835397f9dfeSDavid Greenman * points to the TxCB ring, but the mcsetup descriptor itself is not part 1836397f9dfeSDavid Greenman * of it. We then can do 'CU_START' on the mcsetup descriptor and have it 1837397f9dfeSDavid Greenman * lead into the regular TxCB ring when it completes. 1838397f9dfeSDavid Greenman * 1839397f9dfeSDavid Greenman * This function must be called at splimp. 1840397f9dfeSDavid Greenman */ 1841397f9dfeSDavid Greenman static void 1842397f9dfeSDavid Greenman fxp_mc_setup(sc) 1843397f9dfeSDavid Greenman struct fxp_softc *sc; 1844397f9dfeSDavid Greenman { 1845397f9dfeSDavid Greenman struct fxp_cb_mcs *mcsp = sc->mcsp; 1846397f9dfeSDavid Greenman struct ifnet *ifp = &sc->sc_if; 1847397f9dfeSDavid Greenman struct ifmultiaddr *ifma; 1848397f9dfeSDavid Greenman int nmcasts; 18497dced78aSDavid Greenman int count; 1850397f9dfeSDavid Greenman 18513114fdb4SDavid Greenman /* 18523114fdb4SDavid Greenman * If there are queued commands, we must wait until they are all 18533114fdb4SDavid Greenman * completed. If we are already waiting, then add a NOP command 18543114fdb4SDavid Greenman * with interrupt option so that we're notified when all commands 18553114fdb4SDavid Greenman * have been completed - fxp_start() ensures that no additional 18563114fdb4SDavid Greenman * TX commands will be added when need_mcsetup is true. 18573114fdb4SDavid Greenman */ 1858397f9dfeSDavid Greenman if (sc->tx_queued) { 18593114fdb4SDavid Greenman struct fxp_cb_tx *txp; 18603114fdb4SDavid Greenman 18613114fdb4SDavid Greenman /* 18623114fdb4SDavid Greenman * need_mcsetup will be true if we are already waiting for the 18633114fdb4SDavid Greenman * NOP command to be completed (see below). In this case, bail. 18643114fdb4SDavid Greenman */ 18653114fdb4SDavid Greenman if (sc->need_mcsetup) 18663114fdb4SDavid Greenman return; 1867397f9dfeSDavid Greenman sc->need_mcsetup = 1; 18683114fdb4SDavid Greenman 18693114fdb4SDavid Greenman /* 18703114fdb4SDavid Greenman * Add a NOP command with interrupt so that we are notified when all 18713114fdb4SDavid Greenman * TX commands have been processed. 18723114fdb4SDavid Greenman */ 18733114fdb4SDavid Greenman txp = sc->cbl_last->next; 18743114fdb4SDavid Greenman txp->mb_head = NULL; 18753114fdb4SDavid Greenman txp->cb_status = 0; 18763114fdb4SDavid Greenman txp->cb_command = FXP_CB_COMMAND_NOP | FXP_CB_COMMAND_S | FXP_CB_COMMAND_I; 18773114fdb4SDavid Greenman /* 18783114fdb4SDavid Greenman * Advance the end of list forward. 18793114fdb4SDavid Greenman */ 18803114fdb4SDavid Greenman sc->cbl_last->cb_command &= ~FXP_CB_COMMAND_S; 18813114fdb4SDavid Greenman sc->cbl_last = txp; 18823114fdb4SDavid Greenman sc->tx_queued++; 18833114fdb4SDavid Greenman /* 18843114fdb4SDavid Greenman * Issue a resume in case the CU has just suspended. 18853114fdb4SDavid Greenman */ 18863114fdb4SDavid Greenman fxp_scb_wait(sc); 18873114fdb4SDavid Greenman CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_RESUME); 18883114fdb4SDavid Greenman /* 18893114fdb4SDavid Greenman * Set a 5 second timer just in case we don't hear from the 18903114fdb4SDavid Greenman * card again. 18913114fdb4SDavid Greenman */ 18923114fdb4SDavid Greenman ifp->if_timer = 5; 18933114fdb4SDavid Greenman 1894397f9dfeSDavid Greenman return; 1895397f9dfeSDavid Greenman } 1896397f9dfeSDavid Greenman sc->need_mcsetup = 0; 1897397f9dfeSDavid Greenman 1898397f9dfeSDavid Greenman /* 1899397f9dfeSDavid Greenman * Initialize multicast setup descriptor. 1900397f9dfeSDavid Greenman */ 1901397f9dfeSDavid Greenman mcsp->next = sc->cbl_base; 1902397f9dfeSDavid Greenman mcsp->mb_head = NULL; 1903397f9dfeSDavid Greenman mcsp->cb_status = 0; 19043114fdb4SDavid Greenman mcsp->cb_command = FXP_CB_COMMAND_MCAS | FXP_CB_COMMAND_S | FXP_CB_COMMAND_I; 1905397f9dfeSDavid Greenman mcsp->link_addr = vtophys(&sc->cbl_base->cb_status); 1906397f9dfeSDavid Greenman 1907397f9dfeSDavid Greenman nmcasts = 0; 1908397f9dfeSDavid Greenman if (!sc->all_mcasts) { 19096817526dSPoul-Henning Kamp TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 1910397f9dfeSDavid Greenman if (ifma->ifma_addr->sa_family != AF_LINK) 1911397f9dfeSDavid Greenman continue; 1912397f9dfeSDavid Greenman if (nmcasts >= MAXMCADDR) { 1913397f9dfeSDavid Greenman sc->all_mcasts = 1; 1914397f9dfeSDavid Greenman nmcasts = 0; 1915397f9dfeSDavid Greenman break; 1916397f9dfeSDavid Greenman } 1917397f9dfeSDavid Greenman bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr), 1918d244b0e9SPeter Wemm (void *)(uintptr_t)(volatile void *) 1919d244b0e9SPeter Wemm &sc->mcsp->mc_addr[nmcasts][0], 6); 1920397f9dfeSDavid Greenman nmcasts++; 1921397f9dfeSDavid Greenman } 1922397f9dfeSDavid Greenman } 1923397f9dfeSDavid Greenman mcsp->mc_cnt = nmcasts * 6; 1924397f9dfeSDavid Greenman sc->cbl_first = sc->cbl_last = (struct fxp_cb_tx *) mcsp; 1925397f9dfeSDavid Greenman sc->tx_queued = 1; 1926397f9dfeSDavid Greenman 1927397f9dfeSDavid Greenman /* 1928397f9dfeSDavid Greenman * Wait until command unit is not active. This should never 1929397f9dfeSDavid Greenman * be the case when nothing is queued, but make sure anyway. 1930397f9dfeSDavid Greenman */ 19317dced78aSDavid Greenman count = 100; 1932397f9dfeSDavid Greenman while ((CSR_READ_1(sc, FXP_CSR_SCB_RUSCUS) >> 6) == 19337dced78aSDavid Greenman FXP_SCB_CUS_ACTIVE && --count) 19347dced78aSDavid Greenman DELAY(10); 19357dced78aSDavid Greenman if (count == 0) { 193694927790SDavid Greenman printf("fxp%d: command queue timeout\n", FXP_UNIT(sc)); 19377dced78aSDavid Greenman return; 19387dced78aSDavid Greenman } 1939397f9dfeSDavid Greenman 1940397f9dfeSDavid Greenman /* 1941397f9dfeSDavid Greenman * Start the multicast setup command. 1942397f9dfeSDavid Greenman */ 1943397f9dfeSDavid Greenman fxp_scb_wait(sc); 1944397f9dfeSDavid Greenman CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, vtophys(&mcsp->cb_status)); 1945397f9dfeSDavid Greenman CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START); 1946397f9dfeSDavid Greenman 19473114fdb4SDavid Greenman ifp->if_timer = 2; 1948397f9dfeSDavid Greenman return; 1949397f9dfeSDavid Greenman } 1950