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; 3179fa6ccfbSMatt Jacob int rid, m1, m2, ebitmap; 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; 3609fa6ccfbSMatt Jacob ebitmap = 0; 3619fa6ccfbSMatt Jacob if (getenv_int("fxp_iomap", &ebitmap)) { 3629fa6ccfbSMatt Jacob if (ebitmap & (1 << device_get_unit(dev))) { 3639fa6ccfbSMatt Jacob m1 = PCIM_CMD_PORTEN; 3649fa6ccfbSMatt Jacob m2 = PCIM_CMD_MEMEN; 3659fa6ccfbSMatt Jacob } 3669fa6ccfbSMatt Jacob } 3679fa6ccfbSMatt Jacob 3689fa6ccfbSMatt Jacob if (val & m1) { 3699fa6ccfbSMatt Jacob sc->rtp = 3709fa6ccfbSMatt Jacob (m1 == PCIM_CMD_MEMEN)? SYS_RES_MEMORY : SYS_RES_IOPORT; 3719fa6ccfbSMatt Jacob sc->rgd = (m1 == PCIM_CMD_MEMEN)? FXP_PCI_MMBA : FXP_PCI_IOBA; 3729fa6ccfbSMatt Jacob sc->mem = bus_alloc_resource(dev, sc->rtp, &sc->rgd, 3736182fdbdSPeter Wemm 0, ~0, 1, RF_ACTIVE); 3749fa6ccfbSMatt Jacob } 3759fa6ccfbSMatt Jacob if (sc->mem == NULL && (val & m2)) { 3769fa6ccfbSMatt Jacob sc->rtp = 3779fa6ccfbSMatt Jacob (m2 == PCIM_CMD_MEMEN)? SYS_RES_MEMORY : SYS_RES_IOPORT; 3789fa6ccfbSMatt Jacob sc->rgd = (m2 == PCIM_CMD_MEMEN)? FXP_PCI_MMBA : FXP_PCI_IOBA; 3799fa6ccfbSMatt Jacob sc->mem = bus_alloc_resource(dev, sc->rtp, &sc->rgd, 3809fa6ccfbSMatt Jacob 0, ~0, 1, RF_ACTIVE); 3819fa6ccfbSMatt Jacob } 3829fa6ccfbSMatt Jacob 3836182fdbdSPeter Wemm if (!sc->mem) { 3849fa6ccfbSMatt Jacob device_printf(dev, "could not map device registers\n"); 3856182fdbdSPeter Wemm error = ENXIO; 386a17c678eSDavid Greenman goto fail; 387a17c678eSDavid Greenman } 3889fa6ccfbSMatt Jacob if (bootverbose) { 3899fa6ccfbSMatt Jacob device_printf(dev, "using %s space register mapping\n", 3909fa6ccfbSMatt Jacob sc->rtp == SYS_RES_MEMORY? "memory" : "I/O"); 3919fa6ccfbSMatt Jacob } 3924fc1dda9SAndrew Gallatin 3934fc1dda9SAndrew Gallatin sc->sc_st = rman_get_bustag(sc->mem); 3944fc1dda9SAndrew Gallatin sc->sc_sh = rman_get_bushandle(sc->mem); 395a17c678eSDavid Greenman 396a17c678eSDavid Greenman /* 397dfe61cf1SDavid Greenman * Allocate our interrupt. 398dfe61cf1SDavid Greenman */ 3996182fdbdSPeter Wemm rid = 0; 4006182fdbdSPeter Wemm sc->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, 4016182fdbdSPeter Wemm RF_SHAREABLE | RF_ACTIVE); 4026182fdbdSPeter Wemm if (sc->irq == NULL) { 4036182fdbdSPeter Wemm device_printf(dev, "could not map interrupt\n"); 4046182fdbdSPeter Wemm error = ENXIO; 4056182fdbdSPeter Wemm goto fail; 4066182fdbdSPeter Wemm } 4076182fdbdSPeter Wemm 408566643e3SDoug Rabson error = bus_setup_intr(dev, sc->irq, INTR_TYPE_NET, 409566643e3SDoug Rabson fxp_intr, sc, &sc->ih); 4106182fdbdSPeter Wemm if (error) { 4116182fdbdSPeter Wemm device_printf(dev, "could not setup irq\n"); 412a17c678eSDavid Greenman goto fail; 413a17c678eSDavid Greenman } 414a17c678eSDavid Greenman 415ba8c6fd5SDavid Greenman /* Do generic parts of attach. */ 416ba8c6fd5SDavid Greenman if (fxp_attach_common(sc, sc->arpcom.ac_enaddr)) { 417ba8c6fd5SDavid Greenman /* Failed! */ 4186182fdbdSPeter Wemm bus_teardown_intr(dev, sc->irq, sc->ih); 4196182fdbdSPeter Wemm bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq); 4209fa6ccfbSMatt Jacob bus_release_resource(dev, sc->rtp, sc->rgd, sc->mem); 4216182fdbdSPeter Wemm error = ENXIO; 422ba8c6fd5SDavid Greenman goto fail; 423a17c678eSDavid Greenman } 424a17c678eSDavid Greenman 4256182fdbdSPeter Wemm device_printf(dev, "Ethernet address %6D%s\n", 426ba8c6fd5SDavid Greenman sc->arpcom.ac_enaddr, ":", sc->phy_10Mbps_only ? ", 10Mbps" : ""); 427dccee1a1SDavid Greenman 428a17c678eSDavid Greenman ifp = &sc->arpcom.ac_if; 4296182fdbdSPeter Wemm ifp->if_unit = device_get_unit(dev); 430a17c678eSDavid Greenman ifp->if_name = "fxp"; 431a17c678eSDavid Greenman ifp->if_output = ether_output; 432a330e1f1SGary Palmer ifp->if_baudrate = 100000000; 433fb583156SDavid Greenman ifp->if_init = fxp_init; 434ba8c6fd5SDavid Greenman ifp->if_softc = sc; 435ba8c6fd5SDavid Greenman ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 436ba8c6fd5SDavid Greenman ifp->if_ioctl = fxp_ioctl; 437ba8c6fd5SDavid Greenman ifp->if_start = fxp_start; 438ba8c6fd5SDavid Greenman ifp->if_watchdog = fxp_watchdog; 439a17c678eSDavid Greenman 440dfe61cf1SDavid Greenman /* 441dfe61cf1SDavid Greenman * Attach the interface. 442dfe61cf1SDavid Greenman */ 44321b8ebd9SArchie Cobbs ether_ifattach(ifp, ETHER_BPF_SUPPORTED); 444483b9871SDavid Greenman /* 4453114fdb4SDavid Greenman * Let the system queue as many packets as we have available 4463114fdb4SDavid Greenman * TX descriptors. 447483b9871SDavid Greenman */ 4483114fdb4SDavid Greenman ifp->if_snd.ifq_maxlen = FXP_NTXCB - 1; 4494a684684SDavid Greenman 45094927790SDavid Greenman FXP_UNLOCK(sc); 4516182fdbdSPeter Wemm return 0; 452a17c678eSDavid Greenman 453a17c678eSDavid Greenman fail: 45494927790SDavid Greenman FXP_UNLOCK(sc); 4550f4dc94cSChuck Paterson mtx_destroy(&sc->sc_mtx); 4566182fdbdSPeter Wemm return error; 4576182fdbdSPeter Wemm } 4586182fdbdSPeter Wemm 4596182fdbdSPeter Wemm /* 4606182fdbdSPeter Wemm * Detach interface. 4616182fdbdSPeter Wemm */ 4626182fdbdSPeter Wemm static int 4636182fdbdSPeter Wemm fxp_detach(device_t dev) 4646182fdbdSPeter Wemm { 4656182fdbdSPeter Wemm struct fxp_softc *sc = device_get_softc(dev); 4666182fdbdSPeter Wemm 46794927790SDavid Greenman FXP_LOCK(sc); 4686182fdbdSPeter Wemm 4696182fdbdSPeter Wemm /* 4706182fdbdSPeter Wemm * Close down routes etc. 4716182fdbdSPeter Wemm */ 47221b8ebd9SArchie Cobbs ether_ifdetach(&sc->arpcom.ac_if, ETHER_BPF_SUPPORTED); 4736182fdbdSPeter Wemm 4746182fdbdSPeter Wemm /* 4756182fdbdSPeter Wemm * Stop DMA and drop transmit queue. 4766182fdbdSPeter Wemm */ 4776182fdbdSPeter Wemm fxp_stop(sc); 4786182fdbdSPeter Wemm 4796182fdbdSPeter Wemm /* 4806182fdbdSPeter Wemm * Deallocate resources. 4816182fdbdSPeter Wemm */ 4826182fdbdSPeter Wemm bus_teardown_intr(dev, sc->irq, sc->ih); 4836182fdbdSPeter Wemm bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq); 4849fa6ccfbSMatt Jacob bus_release_resource(dev, sc->rtp, sc->rgd, sc->mem); 4856182fdbdSPeter Wemm 4866182fdbdSPeter Wemm /* 4876182fdbdSPeter Wemm * Free all the receive buffers. 4886182fdbdSPeter Wemm */ 4896182fdbdSPeter Wemm if (sc->rfa_headm != NULL) 4906182fdbdSPeter Wemm m_freem(sc->rfa_headm); 4916182fdbdSPeter Wemm 4926182fdbdSPeter Wemm /* 4936182fdbdSPeter Wemm * Free all media structures. 4946182fdbdSPeter Wemm */ 4956182fdbdSPeter Wemm ifmedia_removeall(&sc->sc_media); 4966182fdbdSPeter Wemm 4976182fdbdSPeter Wemm /* 4986182fdbdSPeter Wemm * Free anciliary structures. 4996182fdbdSPeter Wemm */ 5006182fdbdSPeter Wemm free(sc->cbl_base, M_DEVBUF); 5016182fdbdSPeter Wemm free(sc->fxp_stats, M_DEVBUF); 5026182fdbdSPeter Wemm free(sc->mcsp, M_DEVBUF); 5036182fdbdSPeter Wemm 50494927790SDavid Greenman FXP_UNLOCK(sc); 505f59dd3aeSChuck Paterson mtx_destroy(&sc->sc_mtx); 5066182fdbdSPeter Wemm 5076182fdbdSPeter Wemm return 0; 508a17c678eSDavid Greenman } 509a17c678eSDavid Greenman 510a17c678eSDavid Greenman /* 5114a684684SDavid Greenman * Device shutdown routine. Called at system shutdown after sync. The 512a17c678eSDavid Greenman * main purpose of this routine is to shut off receiver DMA so that 513a17c678eSDavid Greenman * kernel memory doesn't get clobbered during warmboot. 514a17c678eSDavid Greenman */ 5156182fdbdSPeter Wemm static int 5166182fdbdSPeter Wemm fxp_shutdown(device_t dev) 517a17c678eSDavid Greenman { 5186182fdbdSPeter Wemm /* 5196182fdbdSPeter Wemm * Make sure that DMA is disabled prior to reboot. Not doing 5206182fdbdSPeter Wemm * do could allow DMA to corrupt kernel memory during the 5216182fdbdSPeter Wemm * reboot before the driver initializes. 5226182fdbdSPeter Wemm */ 5236182fdbdSPeter Wemm fxp_stop((struct fxp_softc *) device_get_softc(dev)); 5246182fdbdSPeter Wemm return 0; 525a17c678eSDavid Greenman } 526a17c678eSDavid Greenman 5277dced78aSDavid Greenman /* 5287dced78aSDavid Greenman * Device suspend routine. Stop the interface and save some PCI 5297dced78aSDavid Greenman * settings in case the BIOS doesn't restore them properly on 5307dced78aSDavid Greenman * resume. 5317dced78aSDavid Greenman */ 5327dced78aSDavid Greenman static int 5337dced78aSDavid Greenman fxp_suspend(device_t dev) 5347dced78aSDavid Greenman { 5357dced78aSDavid Greenman struct fxp_softc *sc = device_get_softc(dev); 5362053b07dSDavid Greenman int i; 5377dced78aSDavid Greenman 53894927790SDavid Greenman FXP_LOCK(sc); 5397dced78aSDavid Greenman 5407dced78aSDavid Greenman fxp_stop(sc); 5417dced78aSDavid Greenman 5427dced78aSDavid Greenman for (i=0; i<5; i++) 5437dced78aSDavid Greenman sc->saved_maps[i] = pci_read_config(dev, PCIR_MAPS + i*4, 4); 5447dced78aSDavid Greenman sc->saved_biosaddr = pci_read_config(dev, PCIR_BIOS, 4); 5457dced78aSDavid Greenman sc->saved_intline = pci_read_config(dev, PCIR_INTLINE, 1); 5467dced78aSDavid Greenman sc->saved_cachelnsz = pci_read_config(dev, PCIR_CACHELNSZ, 1); 5477dced78aSDavid Greenman sc->saved_lattimer = pci_read_config(dev, PCIR_LATTIMER, 1); 5487dced78aSDavid Greenman 5497dced78aSDavid Greenman sc->suspended = 1; 5507dced78aSDavid Greenman 55194927790SDavid Greenman FXP_UNLOCK(sc); 5527dced78aSDavid Greenman 5537dced78aSDavid Greenman return 0; 5547dced78aSDavid Greenman } 5557dced78aSDavid Greenman 5567dced78aSDavid Greenman /* 5577dced78aSDavid Greenman * Device resume routine. Restore some PCI settings in case the BIOS 5587dced78aSDavid Greenman * doesn't, re-enable busmastering, and restart the interface if 5597dced78aSDavid Greenman * appropriate. 5607dced78aSDavid Greenman */ 5617dced78aSDavid Greenman static int 5627dced78aSDavid Greenman fxp_resume(device_t dev) 5637dced78aSDavid Greenman { 5647dced78aSDavid Greenman struct fxp_softc *sc = device_get_softc(dev); 5657dced78aSDavid Greenman struct ifnet *ifp = &sc->sc_if; 5667dced78aSDavid Greenman u_int16_t pci_command; 5672053b07dSDavid Greenman int i; 5687dced78aSDavid Greenman 56994927790SDavid Greenman FXP_LOCK(sc); 5707dced78aSDavid Greenman 5717dced78aSDavid Greenman /* better way to do this? */ 5727dced78aSDavid Greenman for (i=0; i<5; i++) 5737dced78aSDavid Greenman pci_write_config(dev, PCIR_MAPS + i*4, sc->saved_maps[i], 4); 5747dced78aSDavid Greenman pci_write_config(dev, PCIR_BIOS, sc->saved_biosaddr, 4); 5757dced78aSDavid Greenman pci_write_config(dev, PCIR_INTLINE, sc->saved_intline, 1); 5767dced78aSDavid Greenman pci_write_config(dev, PCIR_CACHELNSZ, sc->saved_cachelnsz, 1); 5777dced78aSDavid Greenman pci_write_config(dev, PCIR_LATTIMER, sc->saved_lattimer, 1); 5787dced78aSDavid Greenman 5797dced78aSDavid Greenman /* reenable busmastering */ 5807dced78aSDavid Greenman pci_command = pci_read_config(dev, PCIR_COMMAND, 2); 5817dced78aSDavid Greenman pci_command |= (PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN); 5827dced78aSDavid Greenman pci_write_config(dev, PCIR_COMMAND, pci_command, 2); 5837dced78aSDavid Greenman 5847dced78aSDavid Greenman CSR_WRITE_4(sc, FXP_CSR_PORT, FXP_PORT_SELECTIVE_RESET); 5857dced78aSDavid Greenman DELAY(10); 5867dced78aSDavid Greenman 5877dced78aSDavid Greenman /* reinitialize interface if necessary */ 5887dced78aSDavid Greenman if (ifp->if_flags & IFF_UP) 5897dced78aSDavid Greenman fxp_init(sc); 5907dced78aSDavid Greenman 5917dced78aSDavid Greenman sc->suspended = 0; 5927dced78aSDavid Greenman 59394927790SDavid Greenman FXP_UNLOCK(sc); 5947dced78aSDavid Greenman 5957dced78aSDavid Greenman return 0; 5967dced78aSDavid Greenman } 5977dced78aSDavid Greenman 5986182fdbdSPeter Wemm static device_method_t fxp_methods[] = { 5996182fdbdSPeter Wemm /* Device interface */ 6006182fdbdSPeter Wemm DEVMETHOD(device_probe, fxp_probe), 6016182fdbdSPeter Wemm DEVMETHOD(device_attach, fxp_attach), 6026182fdbdSPeter Wemm DEVMETHOD(device_detach, fxp_detach), 6036182fdbdSPeter Wemm DEVMETHOD(device_shutdown, fxp_shutdown), 6047dced78aSDavid Greenman DEVMETHOD(device_suspend, fxp_suspend), 6057dced78aSDavid Greenman DEVMETHOD(device_resume, fxp_resume), 6066182fdbdSPeter Wemm 6076182fdbdSPeter Wemm { 0, 0 } 6086182fdbdSPeter Wemm }; 6096182fdbdSPeter Wemm 6106182fdbdSPeter Wemm static driver_t fxp_driver = { 6116182fdbdSPeter Wemm "fxp", 6126182fdbdSPeter Wemm fxp_methods, 6136182fdbdSPeter Wemm sizeof(struct fxp_softc), 6146182fdbdSPeter Wemm }; 6156182fdbdSPeter Wemm 6166182fdbdSPeter Wemm static devclass_t fxp_devclass; 6176182fdbdSPeter Wemm 6189e4c647cSBill Paul DRIVER_MODULE(if_fxp, pci, fxp_driver, fxp_devclass, 0, 0); 619869975bfSWarner Losh DRIVER_MODULE(if_fxp, cardbus, fxp_driver, fxp_devclass, 0, 0); 6206182fdbdSPeter Wemm 621ba8c6fd5SDavid Greenman /* 622ba8c6fd5SDavid Greenman * Do generic parts of attach. 623ba8c6fd5SDavid Greenman */ 624ba8c6fd5SDavid Greenman static int 625ba8c6fd5SDavid Greenman fxp_attach_common(sc, enaddr) 626ba8c6fd5SDavid Greenman struct fxp_softc *sc; 627ba8c6fd5SDavid Greenman u_int8_t *enaddr; 628ba8c6fd5SDavid Greenman { 629ba8c6fd5SDavid Greenman u_int16_t data; 630ba8c6fd5SDavid Greenman int i, nmedia, defmedia; 631ba8c6fd5SDavid Greenman const int *media; 632ba8c6fd5SDavid Greenman 633ba8c6fd5SDavid Greenman /* 634ba8c6fd5SDavid Greenman * Reset to a stable state. 635ba8c6fd5SDavid Greenman */ 636ba8c6fd5SDavid Greenman CSR_WRITE_4(sc, FXP_CSR_PORT, FXP_PORT_SELECTIVE_RESET); 637ba8c6fd5SDavid Greenman DELAY(10); 638ba8c6fd5SDavid Greenman 639ba8c6fd5SDavid Greenman sc->cbl_base = malloc(sizeof(struct fxp_cb_tx) * FXP_NTXCB, 6407cc0979fSDavid Malone M_DEVBUF, M_NOWAIT | M_ZERO); 641ba8c6fd5SDavid Greenman if (sc->cbl_base == NULL) 642ba8c6fd5SDavid Greenman goto fail; 643ba8c6fd5SDavid Greenman 6447cc0979fSDavid Malone sc->fxp_stats = malloc(sizeof(struct fxp_stats), M_DEVBUF, 6457cc0979fSDavid Malone M_NOWAIT | M_ZERO); 646ba8c6fd5SDavid Greenman if (sc->fxp_stats == NULL) 647ba8c6fd5SDavid Greenman goto fail; 648ba8c6fd5SDavid Greenman 649397f9dfeSDavid Greenman sc->mcsp = malloc(sizeof(struct fxp_cb_mcs), M_DEVBUF, M_NOWAIT); 650397f9dfeSDavid Greenman if (sc->mcsp == NULL) 651397f9dfeSDavid Greenman goto fail; 652397f9dfeSDavid Greenman 653ba8c6fd5SDavid Greenman /* 654ba8c6fd5SDavid Greenman * Pre-allocate our receive buffers. 655ba8c6fd5SDavid Greenman */ 656ba8c6fd5SDavid Greenman for (i = 0; i < FXP_NRFABUFS; i++) { 657ba8c6fd5SDavid Greenman if (fxp_add_rfabuf(sc, NULL) != 0) { 658ba8c6fd5SDavid Greenman goto fail; 659ba8c6fd5SDavid Greenman } 660ba8c6fd5SDavid Greenman } 661ba8c6fd5SDavid Greenman 662ba8c6fd5SDavid Greenman /* 663e9bf2fa7SDavid Greenman * Find out how large of an SEEPROM we have. 664e9bf2fa7SDavid Greenman */ 665e9bf2fa7SDavid Greenman fxp_autosize_eeprom(sc); 666e9bf2fa7SDavid Greenman 667e9bf2fa7SDavid Greenman /* 668ba8c6fd5SDavid Greenman * Get info about the primary PHY 669ba8c6fd5SDavid Greenman */ 670ba8c6fd5SDavid Greenman fxp_read_eeprom(sc, (u_int16_t *)&data, 6, 1); 671ba8c6fd5SDavid Greenman sc->phy_primary_addr = data & 0xff; 672ba8c6fd5SDavid Greenman sc->phy_primary_device = (data >> 8) & 0x3f; 673ba8c6fd5SDavid Greenman sc->phy_10Mbps_only = data >> 15; 674ba8c6fd5SDavid Greenman 675ba8c6fd5SDavid Greenman /* 676ba8c6fd5SDavid Greenman * Read MAC address. 677ba8c6fd5SDavid Greenman */ 678ba8c6fd5SDavid Greenman fxp_read_eeprom(sc, (u_int16_t *)enaddr, 0, 3); 679ba8c6fd5SDavid Greenman 680ba8c6fd5SDavid Greenman /* 681ba8c6fd5SDavid Greenman * Initialize the media structures. 682ba8c6fd5SDavid Greenman */ 683ba8c6fd5SDavid Greenman 684ba8c6fd5SDavid Greenman media = fxp_media_default; 685ba8c6fd5SDavid Greenman nmedia = sizeof(fxp_media_default) / sizeof(fxp_media_default[0]); 686ba8c6fd5SDavid Greenman defmedia = FXP_MEDIA_DEFAULT_DEFMEDIA; 687ba8c6fd5SDavid Greenman 688ba8c6fd5SDavid Greenman for (i = 0; i < NFXPMEDIA; i++) { 689ba8c6fd5SDavid Greenman if (sc->phy_primary_device == fxp_media[i].fsm_phy) { 690ba8c6fd5SDavid Greenman media = fxp_media[i].fsm_media; 691ba8c6fd5SDavid Greenman nmedia = fxp_media[i].fsm_nmedia; 692ba8c6fd5SDavid Greenman defmedia = fxp_media[i].fsm_defmedia; 693ba8c6fd5SDavid Greenman } 694ba8c6fd5SDavid Greenman } 695ba8c6fd5SDavid Greenman 696ba8c6fd5SDavid Greenman ifmedia_init(&sc->sc_media, 0, fxp_mediachange, fxp_mediastatus); 697ba8c6fd5SDavid Greenman for (i = 0; i < nmedia; i++) { 698ba8c6fd5SDavid Greenman if (IFM_SUBTYPE(media[i]) == IFM_100_TX && sc->phy_10Mbps_only) 699ba8c6fd5SDavid Greenman continue; 700ba8c6fd5SDavid Greenman ifmedia_add(&sc->sc_media, media[i], 0, NULL); 701ba8c6fd5SDavid Greenman } 702ba8c6fd5SDavid Greenman ifmedia_set(&sc->sc_media, defmedia); 703ba8c6fd5SDavid Greenman 704ba8c6fd5SDavid Greenman return (0); 705ba8c6fd5SDavid Greenman 706ba8c6fd5SDavid Greenman fail: 70794927790SDavid Greenman printf("fxp%d: Failed to malloc memory\n", FXP_UNIT(sc)); 708ba8c6fd5SDavid Greenman if (sc->cbl_base) 709ba8c6fd5SDavid Greenman free(sc->cbl_base, M_DEVBUF); 710ba8c6fd5SDavid Greenman if (sc->fxp_stats) 711ba8c6fd5SDavid Greenman free(sc->fxp_stats, M_DEVBUF); 712397f9dfeSDavid Greenman if (sc->mcsp) 713397f9dfeSDavid Greenman free(sc->mcsp, M_DEVBUF); 714ba8c6fd5SDavid Greenman /* frees entire chain */ 715ba8c6fd5SDavid Greenman if (sc->rfa_headm) 716ba8c6fd5SDavid Greenman m_freem(sc->rfa_headm); 717ba8c6fd5SDavid Greenman 718ba8c6fd5SDavid Greenman return (ENOMEM); 719ba8c6fd5SDavid Greenman } 720ba8c6fd5SDavid Greenman 721ba8c6fd5SDavid Greenman /* 722e9bf2fa7SDavid Greenman * From NetBSD: 723e9bf2fa7SDavid Greenman * 724e9bf2fa7SDavid Greenman * Figure out EEPROM size. 725e9bf2fa7SDavid Greenman * 726e9bf2fa7SDavid Greenman * 559's can have either 64-word or 256-word EEPROMs, the 558 727e9bf2fa7SDavid Greenman * datasheet only talks about 64-word EEPROMs, and the 557 datasheet 728e9bf2fa7SDavid Greenman * talks about the existance of 16 to 256 word EEPROMs. 729e9bf2fa7SDavid Greenman * 730e9bf2fa7SDavid Greenman * The only known sizes are 64 and 256, where the 256 version is used 731e9bf2fa7SDavid Greenman * by CardBus cards to store CIS information. 732e9bf2fa7SDavid Greenman * 733e9bf2fa7SDavid Greenman * The address is shifted in msb-to-lsb, and after the last 734e9bf2fa7SDavid Greenman * address-bit the EEPROM is supposed to output a `dummy zero' bit, 735e9bf2fa7SDavid Greenman * after which follows the actual data. We try to detect this zero, by 736e9bf2fa7SDavid Greenman * probing the data-out bit in the EEPROM control register just after 737e9bf2fa7SDavid Greenman * having shifted in a bit. If the bit is zero, we assume we've 738e9bf2fa7SDavid Greenman * shifted enough address bits. The data-out should be tri-state, 739e9bf2fa7SDavid Greenman * before this, which should translate to a logical one. 740e9bf2fa7SDavid Greenman * 741e9bf2fa7SDavid Greenman * Other ways to do this would be to try to read a register with known 742e9bf2fa7SDavid Greenman * contents with a varying number of address bits, but no such 743e9bf2fa7SDavid Greenman * register seem to be available. The high bits of register 10 are 01 744e9bf2fa7SDavid Greenman * on the 558 and 559, but apparently not on the 557. 745e9bf2fa7SDavid Greenman * 746e9bf2fa7SDavid Greenman * The Linux driver computes a checksum on the EEPROM data, but the 747e9bf2fa7SDavid Greenman * value of this checksum is not very well documented. 748e9bf2fa7SDavid Greenman */ 749e9bf2fa7SDavid Greenman static void 750e9bf2fa7SDavid Greenman fxp_autosize_eeprom(sc) 751e9bf2fa7SDavid Greenman struct fxp_softc *sc; 752e9bf2fa7SDavid Greenman { 753e9bf2fa7SDavid Greenman u_int16_t reg; 754e9bf2fa7SDavid Greenman int x; 755e9bf2fa7SDavid Greenman 756e9bf2fa7SDavid Greenman CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS); 757e9bf2fa7SDavid Greenman /* 758e9bf2fa7SDavid Greenman * Shift in read opcode. 759e9bf2fa7SDavid Greenman */ 760e9bf2fa7SDavid Greenman for (x = 3; x > 0; x--) { 761e9bf2fa7SDavid Greenman if (FXP_EEPROM_OPC_READ & (1 << (x - 1))) { 762e9bf2fa7SDavid Greenman reg = FXP_EEPROM_EECS | FXP_EEPROM_EEDI; 763e9bf2fa7SDavid Greenman } else { 764e9bf2fa7SDavid Greenman reg = FXP_EEPROM_EECS; 765e9bf2fa7SDavid Greenman } 766e9bf2fa7SDavid Greenman CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg); 767e9bf2fa7SDavid Greenman CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 768e9bf2fa7SDavid Greenman reg | FXP_EEPROM_EESK); 769e9bf2fa7SDavid Greenman DELAY(1); 770e9bf2fa7SDavid Greenman CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg); 771e9bf2fa7SDavid Greenman DELAY(1); 772e9bf2fa7SDavid Greenman } 773e9bf2fa7SDavid Greenman /* 774e9bf2fa7SDavid Greenman * Shift in address. 775e9bf2fa7SDavid Greenman * Wait for the dummy zero following a correct address shift. 776e9bf2fa7SDavid Greenman */ 777e9bf2fa7SDavid Greenman for (x = 1; x <= 8; x++) { 778e9bf2fa7SDavid Greenman CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS); 779e9bf2fa7SDavid Greenman CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 780e9bf2fa7SDavid Greenman FXP_EEPROM_EECS | FXP_EEPROM_EESK); 781e9bf2fa7SDavid Greenman DELAY(1); 782e9bf2fa7SDavid Greenman if ((CSR_READ_2(sc, FXP_CSR_EEPROMCONTROL) & FXP_EEPROM_EEDO) == 0) 783e9bf2fa7SDavid Greenman break; 784e9bf2fa7SDavid Greenman CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS); 785e9bf2fa7SDavid Greenman DELAY(1); 786e9bf2fa7SDavid Greenman } 787e9bf2fa7SDavid Greenman CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 0); 788e9bf2fa7SDavid Greenman DELAY(1); 789e9bf2fa7SDavid Greenman sc->eeprom_size = x; 790e9bf2fa7SDavid Greenman } 791e9bf2fa7SDavid Greenman /* 792ba8c6fd5SDavid Greenman * Read from the serial EEPROM. Basically, you manually shift in 793ba8c6fd5SDavid Greenman * the read opcode (one bit at a time) and then shift in the address, 794ba8c6fd5SDavid Greenman * and then you shift out the data (all of this one bit at a time). 795ba8c6fd5SDavid Greenman * The word size is 16 bits, so you have to provide the address for 796ba8c6fd5SDavid Greenman * every 16 bits of data. 797ba8c6fd5SDavid Greenman */ 798ba8c6fd5SDavid Greenman static void 799ba8c6fd5SDavid Greenman fxp_read_eeprom(sc, data, offset, words) 800ba8c6fd5SDavid Greenman struct fxp_softc *sc; 801ba8c6fd5SDavid Greenman u_short *data; 802ba8c6fd5SDavid Greenman int offset; 803ba8c6fd5SDavid Greenman int words; 804ba8c6fd5SDavid Greenman { 805ba8c6fd5SDavid Greenman u_int16_t reg; 806ba8c6fd5SDavid Greenman int i, x; 807ba8c6fd5SDavid Greenman 808ba8c6fd5SDavid Greenman for (i = 0; i < words; i++) { 809ba8c6fd5SDavid Greenman CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS); 810ba8c6fd5SDavid Greenman /* 811ba8c6fd5SDavid Greenman * Shift in read opcode. 812ba8c6fd5SDavid Greenman */ 813ba8c6fd5SDavid Greenman for (x = 3; x > 0; x--) { 814ba8c6fd5SDavid Greenman if (FXP_EEPROM_OPC_READ & (1 << (x - 1))) { 815ba8c6fd5SDavid Greenman reg = FXP_EEPROM_EECS | FXP_EEPROM_EEDI; 816ba8c6fd5SDavid Greenman } else { 817ba8c6fd5SDavid Greenman reg = FXP_EEPROM_EECS; 818ba8c6fd5SDavid Greenman } 819ba8c6fd5SDavid Greenman CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg); 820ba8c6fd5SDavid Greenman CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 821ba8c6fd5SDavid Greenman reg | FXP_EEPROM_EESK); 822ba8c6fd5SDavid Greenman DELAY(1); 823ba8c6fd5SDavid Greenman CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg); 824ba8c6fd5SDavid Greenman DELAY(1); 825ba8c6fd5SDavid Greenman } 826ba8c6fd5SDavid Greenman /* 827ba8c6fd5SDavid Greenman * Shift in address. 828ba8c6fd5SDavid Greenman */ 829e9bf2fa7SDavid Greenman for (x = sc->eeprom_size; x > 0; x--) { 830ba8c6fd5SDavid Greenman if ((i + offset) & (1 << (x - 1))) { 831ba8c6fd5SDavid Greenman reg = FXP_EEPROM_EECS | FXP_EEPROM_EEDI; 832ba8c6fd5SDavid Greenman } else { 833ba8c6fd5SDavid Greenman reg = FXP_EEPROM_EECS; 834ba8c6fd5SDavid Greenman } 835ba8c6fd5SDavid Greenman CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg); 836ba8c6fd5SDavid Greenman CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 837ba8c6fd5SDavid Greenman reg | FXP_EEPROM_EESK); 838ba8c6fd5SDavid Greenman DELAY(1); 839ba8c6fd5SDavid Greenman CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg); 840ba8c6fd5SDavid Greenman DELAY(1); 841ba8c6fd5SDavid Greenman } 842ba8c6fd5SDavid Greenman reg = FXP_EEPROM_EECS; 843ba8c6fd5SDavid Greenman data[i] = 0; 844ba8c6fd5SDavid Greenman /* 845ba8c6fd5SDavid Greenman * Shift out data. 846ba8c6fd5SDavid Greenman */ 847ba8c6fd5SDavid Greenman for (x = 16; x > 0; x--) { 848ba8c6fd5SDavid Greenman CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 849ba8c6fd5SDavid Greenman reg | FXP_EEPROM_EESK); 850ba8c6fd5SDavid Greenman DELAY(1); 851ba8c6fd5SDavid Greenman if (CSR_READ_2(sc, FXP_CSR_EEPROMCONTROL) & 852ba8c6fd5SDavid Greenman FXP_EEPROM_EEDO) 853ba8c6fd5SDavid Greenman data[i] |= (1 << (x - 1)); 854ba8c6fd5SDavid Greenman CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg); 855ba8c6fd5SDavid Greenman DELAY(1); 856ba8c6fd5SDavid Greenman } 857ba8c6fd5SDavid Greenman CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 0); 858ba8c6fd5SDavid Greenman DELAY(1); 859ba8c6fd5SDavid Greenman } 860ba8c6fd5SDavid Greenman } 861ba8c6fd5SDavid Greenman 862a17c678eSDavid Greenman /* 863a17c678eSDavid Greenman * Start packet transmission on the interface. 864a17c678eSDavid Greenman */ 865a17c678eSDavid Greenman static void 866a17c678eSDavid Greenman fxp_start(ifp) 867a17c678eSDavid Greenman struct ifnet *ifp; 868a17c678eSDavid Greenman { 8699b44ff22SGarrett Wollman struct fxp_softc *sc = ifp->if_softc; 870a17c678eSDavid Greenman struct fxp_cb_tx *txp; 871a17c678eSDavid Greenman 87294927790SDavid Greenman FXP_LOCK(sc); 873a17c678eSDavid Greenman /* 874483b9871SDavid Greenman * See if we need to suspend xmit until the multicast filter 875483b9871SDavid Greenman * has been reprogrammed (which can only be done at the head 876483b9871SDavid Greenman * of the command chain). 877a17c678eSDavid Greenman */ 8780f4dc94cSChuck Paterson if (sc->need_mcsetup) { 87994927790SDavid Greenman FXP_UNLOCK(sc); 880a17c678eSDavid Greenman return; 8810f4dc94cSChuck Paterson } 8821cd443acSDavid Greenman 883483b9871SDavid Greenman txp = NULL; 884483b9871SDavid Greenman 885483b9871SDavid Greenman /* 886483b9871SDavid Greenman * We're finished if there is nothing more to add to the list or if 887483b9871SDavid Greenman * we're all filled up with buffers to transmit. 8883114fdb4SDavid Greenman * NOTE: One TxCB is reserved to guarantee that fxp_mc_setup() can add 8893114fdb4SDavid Greenman * a NOP command when needed. 890483b9871SDavid Greenman */ 8913114fdb4SDavid Greenman while (ifp->if_snd.ifq_head != NULL && sc->tx_queued < FXP_NTXCB - 1) { 892483b9871SDavid Greenman struct mbuf *m, *mb_head; 893483b9871SDavid Greenman int segment; 894483b9871SDavid Greenman 895dfe61cf1SDavid Greenman /* 896dfe61cf1SDavid Greenman * Grab a packet to transmit. 897dfe61cf1SDavid Greenman */ 8986318197eSDavid Greenman IF_DEQUEUE(&ifp->if_snd, mb_head); 899a17c678eSDavid Greenman 900dfe61cf1SDavid Greenman /* 901483b9871SDavid Greenman * Get pointer to next available tx desc. 902dfe61cf1SDavid Greenman */ 903a17c678eSDavid Greenman txp = sc->cbl_last->next; 904a17c678eSDavid Greenman 905a17c678eSDavid Greenman /* 906a17c678eSDavid Greenman * Go through each of the mbufs in the chain and initialize 907483b9871SDavid Greenman * the transmit buffer descriptors with the physical address 908a17c678eSDavid Greenman * and size of the mbuf. 909a17c678eSDavid Greenman */ 91023a0ed7cSDavid Greenman tbdinit: 911a17c678eSDavid Greenman for (m = mb_head, segment = 0; m != NULL; m = m->m_next) { 912a17c678eSDavid Greenman if (m->m_len != 0) { 913a17c678eSDavid Greenman if (segment == FXP_NTXSEG) 914a17c678eSDavid Greenman break; 915a17c678eSDavid Greenman txp->tbd[segment].tb_addr = 916a17c678eSDavid Greenman vtophys(mtod(m, vm_offset_t)); 917a17c678eSDavid Greenman txp->tbd[segment].tb_size = m->m_len; 918a17c678eSDavid Greenman segment++; 919a17c678eSDavid Greenman } 920a17c678eSDavid Greenman } 921fb583156SDavid Greenman if (m != NULL) { 92223a0ed7cSDavid Greenman struct mbuf *mn; 92323a0ed7cSDavid Greenman 924a17c678eSDavid Greenman /* 925a17c678eSDavid Greenman * We ran out of segments. We have to recopy this mbuf 926483b9871SDavid Greenman * chain first. Bail out if we can't get the new buffers. 927a17c678eSDavid Greenman */ 92823a0ed7cSDavid Greenman MGETHDR(mn, M_DONTWAIT, MT_DATA); 92923a0ed7cSDavid Greenman if (mn == NULL) { 93023a0ed7cSDavid Greenman m_freem(mb_head); 931483b9871SDavid Greenman break; 932a17c678eSDavid Greenman } 93323a0ed7cSDavid Greenman if (mb_head->m_pkthdr.len > MHLEN) { 93423a0ed7cSDavid Greenman MCLGET(mn, M_DONTWAIT); 93523a0ed7cSDavid Greenman if ((mn->m_flags & M_EXT) == 0) { 93623a0ed7cSDavid Greenman m_freem(mn); 93723a0ed7cSDavid Greenman m_freem(mb_head); 938483b9871SDavid Greenman break; 93923a0ed7cSDavid Greenman } 94023a0ed7cSDavid Greenman } 941ba8c6fd5SDavid Greenman m_copydata(mb_head, 0, mb_head->m_pkthdr.len, 942ba8c6fd5SDavid Greenman mtod(mn, caddr_t)); 94323a0ed7cSDavid Greenman mn->m_pkthdr.len = mn->m_len = mb_head->m_pkthdr.len; 94423a0ed7cSDavid Greenman m_freem(mb_head); 94523a0ed7cSDavid Greenman mb_head = mn; 94623a0ed7cSDavid Greenman goto tbdinit; 94723a0ed7cSDavid Greenman } 94823a0ed7cSDavid Greenman 94923a0ed7cSDavid Greenman txp->tbd_number = segment; 9501cd443acSDavid Greenman txp->mb_head = mb_head; 951a17c678eSDavid Greenman txp->cb_status = 0; 9523114fdb4SDavid Greenman if (sc->tx_queued != FXP_CXINT_THRESH - 1) { 953a17c678eSDavid Greenman txp->cb_command = 954a17c678eSDavid Greenman FXP_CB_COMMAND_XMIT | FXP_CB_COMMAND_SF | FXP_CB_COMMAND_S; 9553114fdb4SDavid Greenman } else { 9563114fdb4SDavid Greenman txp->cb_command = 9573114fdb4SDavid Greenman FXP_CB_COMMAND_XMIT | FXP_CB_COMMAND_SF | FXP_CB_COMMAND_S | FXP_CB_COMMAND_I; 9583114fdb4SDavid Greenman /* 9593114fdb4SDavid Greenman * Set a 5 second timer just in case we don't hear from the 9603114fdb4SDavid Greenman * card again. 9613114fdb4SDavid Greenman */ 9623114fdb4SDavid Greenman ifp->if_timer = 5; 9633114fdb4SDavid Greenman } 964f9be9005SDavid Greenman txp->tx_threshold = tx_threshold; 965a17c678eSDavid Greenman 966a17c678eSDavid Greenman /* 967483b9871SDavid Greenman * Advance the end of list forward. 968a17c678eSDavid Greenman */ 96906175228SAndrew Gallatin 97006175228SAndrew Gallatin #ifdef __alpha__ 97106175228SAndrew Gallatin /* 97206175228SAndrew Gallatin * On platforms which can't access memory in 16-bit 97306175228SAndrew Gallatin * granularities, we must prevent the card from DMA'ing 97406175228SAndrew Gallatin * up the status while we update the command field. 97506175228SAndrew Gallatin * This could cause us to overwrite the completion status. 97606175228SAndrew Gallatin */ 97706175228SAndrew Gallatin atomic_clear_short(&sc->cbl_last->cb_command, 97806175228SAndrew Gallatin FXP_CB_COMMAND_S); 97906175228SAndrew Gallatin #else 980a17c678eSDavid Greenman sc->cbl_last->cb_command &= ~FXP_CB_COMMAND_S; 98106175228SAndrew Gallatin #endif /*__alpha__*/ 982a17c678eSDavid Greenman sc->cbl_last = txp; 983a17c678eSDavid Greenman 984a17c678eSDavid Greenman /* 9851cd443acSDavid Greenman * Advance the beginning of the list forward if there are 9861cd443acSDavid Greenman * no other packets queued (when nothing is queued, cbl_first 987483b9871SDavid Greenman * sits on the last TxCB that was sent out). 988a17c678eSDavid Greenman */ 9891cd443acSDavid Greenman if (sc->tx_queued == 0) 990a17c678eSDavid Greenman sc->cbl_first = txp; 991a17c678eSDavid Greenman 9921cd443acSDavid Greenman sc->tx_queued++; 9931cd443acSDavid Greenman 994a17c678eSDavid Greenman /* 995a17c678eSDavid Greenman * Pass packet to bpf if there is a listener. 996a17c678eSDavid Greenman */ 997fb583156SDavid Greenman if (ifp->if_bpf) 99894927790SDavid Greenman bpf_mtap(ifp, mb_head); 999483b9871SDavid Greenman } 1000483b9871SDavid Greenman 1001483b9871SDavid Greenman /* 1002483b9871SDavid Greenman * We're finished. If we added to the list, issue a RESUME to get DMA 1003483b9871SDavid Greenman * going again if suspended. 1004483b9871SDavid Greenman */ 1005483b9871SDavid Greenman if (txp != NULL) { 1006483b9871SDavid Greenman fxp_scb_wait(sc); 1007483b9871SDavid Greenman CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_RESUME); 1008483b9871SDavid Greenman } 100994927790SDavid Greenman FXP_UNLOCK(sc); 1010a17c678eSDavid Greenman } 1011a17c678eSDavid Greenman 1012a17c678eSDavid Greenman /* 10139c7d2607SDavid Greenman * Process interface interrupts. 1014a17c678eSDavid Greenman */ 101594927790SDavid Greenman static void 1016a17c678eSDavid Greenman fxp_intr(arg) 1017a17c678eSDavid Greenman void *arg; 1018a17c678eSDavid Greenman { 1019a17c678eSDavid Greenman struct fxp_softc *sc = arg; 1020ba8c6fd5SDavid Greenman struct ifnet *ifp = &sc->sc_if; 10211cd443acSDavid Greenman u_int8_t statack; 10220f4dc94cSChuck Paterson 102394927790SDavid Greenman FXP_LOCK(sc); 1024a17c678eSDavid Greenman 1025b184b38eSDavid Greenman if (sc->suspended) { 102694927790SDavid Greenman FXP_UNLOCK(sc); 1027b184b38eSDavid Greenman return; 1028b184b38eSDavid Greenman } 1029b184b38eSDavid Greenman 1030b184b38eSDavid Greenman while ((statack = CSR_READ_1(sc, FXP_CSR_SCB_STATACK)) != 0) { 1031a17c678eSDavid Greenman /* 1032a17c678eSDavid Greenman * First ACK all the interrupts in this pass. 1033a17c678eSDavid Greenman */ 1034ba8c6fd5SDavid Greenman CSR_WRITE_1(sc, FXP_CSR_SCB_STATACK, statack); 1035a17c678eSDavid Greenman 1036a17c678eSDavid Greenman /* 10373114fdb4SDavid Greenman * Free any finished transmit mbuf chains. 103806936301SBill Paul * 103906936301SBill Paul * Handle the CNA event likt a CXTNO event. It used to 104006936301SBill Paul * be that this event (control unit not ready) was not 104106936301SBill Paul * encountered, but it is now with the SMPng modifications. 104206936301SBill Paul * The exact sequence of events that occur when the interface 104306936301SBill Paul * is brought up are different now, and if this event 104406936301SBill Paul * goes unhandled, the configuration/rxfilter setup sequence 104506936301SBill Paul * can stall for several seconds. The result is that no 104606936301SBill Paul * packets go out onto the wire for about 5 to 10 seconds 104706936301SBill Paul * after the interface is ifconfig'ed for the first time. 10483114fdb4SDavid Greenman */ 104906936301SBill Paul if (statack & (FXP_SCB_STATACK_CXTNO | FXP_SCB_STATACK_CNA)) { 10503114fdb4SDavid Greenman struct fxp_cb_tx *txp; 10513114fdb4SDavid Greenman 10523114fdb4SDavid Greenman for (txp = sc->cbl_first; sc->tx_queued && 10533114fdb4SDavid Greenman (txp->cb_status & FXP_CB_STATUS_C) != 0; 10543114fdb4SDavid Greenman txp = txp->next) { 10553114fdb4SDavid Greenman if (txp->mb_head != NULL) { 10563114fdb4SDavid Greenman m_freem(txp->mb_head); 10573114fdb4SDavid Greenman txp->mb_head = NULL; 10583114fdb4SDavid Greenman } 10593114fdb4SDavid Greenman sc->tx_queued--; 10603114fdb4SDavid Greenman } 10613114fdb4SDavid Greenman sc->cbl_first = txp; 10623114fdb4SDavid Greenman ifp->if_timer = 0; 10633114fdb4SDavid Greenman if (sc->tx_queued == 0) { 10643114fdb4SDavid Greenman if (sc->need_mcsetup) 10653114fdb4SDavid Greenman fxp_mc_setup(sc); 10663114fdb4SDavid Greenman } 10673114fdb4SDavid Greenman /* 10683114fdb4SDavid Greenman * Try to start more packets transmitting. 10693114fdb4SDavid Greenman */ 10703114fdb4SDavid Greenman if (ifp->if_snd.ifq_head != NULL) 10713114fdb4SDavid Greenman fxp_start(ifp); 10723114fdb4SDavid Greenman } 10733114fdb4SDavid Greenman /* 1074a17c678eSDavid Greenman * Process receiver interrupts. If a no-resource (RNR) 1075a17c678eSDavid Greenman * condition exists, get whatever packets we can and 1076a17c678eSDavid Greenman * re-start the receiver. 1077a17c678eSDavid Greenman */ 1078a17c678eSDavid Greenman if (statack & (FXP_SCB_STATACK_FR | FXP_SCB_STATACK_RNR)) { 1079a17c678eSDavid Greenman struct mbuf *m; 1080a17c678eSDavid Greenman struct fxp_rfa *rfa; 1081a17c678eSDavid Greenman rcvloop: 1082a17c678eSDavid Greenman m = sc->rfa_headm; 1083ba8c6fd5SDavid Greenman rfa = (struct fxp_rfa *)(m->m_ext.ext_buf + 1084ba8c6fd5SDavid Greenman RFA_ALIGNMENT_FUDGE); 1085a17c678eSDavid Greenman 1086a17c678eSDavid Greenman if (rfa->rfa_status & FXP_RFA_STATUS_C) { 1087dfe61cf1SDavid Greenman /* 1088dfe61cf1SDavid Greenman * Remove first packet from the chain. 1089dfe61cf1SDavid Greenman */ 1090a17c678eSDavid Greenman sc->rfa_headm = m->m_next; 1091a17c678eSDavid Greenman m->m_next = NULL; 1092a17c678eSDavid Greenman 1093dfe61cf1SDavid Greenman /* 1094ba8c6fd5SDavid Greenman * Add a new buffer to the receive chain. 1095ba8c6fd5SDavid Greenman * If this fails, the old buffer is recycled 1096ba8c6fd5SDavid Greenman * instead. 1097dfe61cf1SDavid Greenman */ 1098a17c678eSDavid Greenman if (fxp_add_rfabuf(sc, m) == 0) { 1099a17c678eSDavid Greenman struct ether_header *eh; 1100aed53495SDavid Greenman int total_len; 1101a17c678eSDavid Greenman 1102ba8c6fd5SDavid Greenman total_len = rfa->actual_size & 1103ba8c6fd5SDavid Greenman (MCLBYTES - 1); 1104ba8c6fd5SDavid Greenman if (total_len < 1105ba8c6fd5SDavid Greenman sizeof(struct ether_header)) { 110606339180SDavid Greenman m_freem(m); 110706339180SDavid Greenman goto rcvloop; 110806339180SDavid Greenman } 1109a17c678eSDavid Greenman m->m_pkthdr.rcvif = ifp; 11102e2de7f2SArchie Cobbs m->m_pkthdr.len = m->m_len = total_len; 1111a17c678eSDavid Greenman eh = mtod(m, struct ether_header *); 1112ba8c6fd5SDavid Greenman m->m_data += 1113ba8c6fd5SDavid Greenman sizeof(struct ether_header); 1114ab090e5bSLuigi Rizzo m->m_len -= 1115ab090e5bSLuigi Rizzo sizeof(struct ether_header); 1116ab090e5bSLuigi Rizzo m->m_pkthdr.len = m->m_len; 1117a17c678eSDavid Greenman ether_input(ifp, eh, m); 1118a17c678eSDavid Greenman } 1119a17c678eSDavid Greenman goto rcvloop; 1120a17c678eSDavid Greenman } 1121a17c678eSDavid Greenman if (statack & FXP_SCB_STATACK_RNR) { 1122ba8c6fd5SDavid Greenman fxp_scb_wait(sc); 1123ba8c6fd5SDavid Greenman CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, 1124ba8c6fd5SDavid Greenman vtophys(sc->rfa_headm->m_ext.ext_buf) + 1125ba8c6fd5SDavid Greenman RFA_ALIGNMENT_FUDGE); 1126ba8c6fd5SDavid Greenman CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, 1127ba8c6fd5SDavid Greenman FXP_SCB_COMMAND_RU_START); 1128a17c678eSDavid Greenman } 1129a17c678eSDavid Greenman } 1130a17c678eSDavid Greenman } 113194927790SDavid Greenman FXP_UNLOCK(sc); 1132a17c678eSDavid Greenman } 1133a17c678eSDavid Greenman 1134dfe61cf1SDavid Greenman /* 1135dfe61cf1SDavid Greenman * Update packet in/out/collision statistics. The i82557 doesn't 1136dfe61cf1SDavid Greenman * allow you to access these counters without doing a fairly 1137dfe61cf1SDavid Greenman * expensive DMA to get _all_ of the statistics it maintains, so 1138dfe61cf1SDavid Greenman * we do this operation here only once per second. The statistics 1139dfe61cf1SDavid Greenman * counters in the kernel are updated from the previous dump-stats 1140dfe61cf1SDavid Greenman * DMA and then a new dump-stats DMA is started. The on-chip 1141dfe61cf1SDavid Greenman * counters are zeroed when the DMA completes. If we can't start 1142dfe61cf1SDavid Greenman * the DMA immediately, we don't wait - we just prepare to read 1143dfe61cf1SDavid Greenman * them again next time. 1144dfe61cf1SDavid Greenman */ 1145303b270bSEivind Eklund static void 1146a17c678eSDavid Greenman fxp_stats_update(arg) 1147a17c678eSDavid Greenman void *arg; 1148a17c678eSDavid Greenman { 1149a17c678eSDavid Greenman struct fxp_softc *sc = arg; 1150ba8c6fd5SDavid Greenman struct ifnet *ifp = &sc->sc_if; 1151a17c678eSDavid Greenman struct fxp_stats *sp = sc->fxp_stats; 1152c8cc6fcaSDavid Greenman struct fxp_cb_tx *txp; 1153a17c678eSDavid Greenman 1154a17c678eSDavid Greenman ifp->if_opackets += sp->tx_good; 1155a17c678eSDavid Greenman ifp->if_collisions += sp->tx_total_collisions; 1156397f9dfeSDavid Greenman if (sp->rx_good) { 1157397f9dfeSDavid Greenman ifp->if_ipackets += sp->rx_good; 1158397f9dfeSDavid Greenman sc->rx_idle_secs = 0; 1159397f9dfeSDavid Greenman } else { 1160c8cc6fcaSDavid Greenman /* 1161c8cc6fcaSDavid Greenman * Receiver's been idle for another second. 1162c8cc6fcaSDavid Greenman */ 1163397f9dfeSDavid Greenman sc->rx_idle_secs++; 1164397f9dfeSDavid Greenman } 11653ba65732SDavid Greenman ifp->if_ierrors += 11663ba65732SDavid Greenman sp->rx_crc_errors + 11673ba65732SDavid Greenman sp->rx_alignment_errors + 11683ba65732SDavid Greenman sp->rx_rnr_errors + 11696e39e599SDavid Greenman sp->rx_overrun_errors; 1170a17c678eSDavid Greenman /* 1171f9be9005SDavid Greenman * If any transmit underruns occured, bump up the transmit 1172f9be9005SDavid Greenman * threshold by another 512 bytes (64 * 8). 1173f9be9005SDavid Greenman */ 1174f9be9005SDavid Greenman if (sp->tx_underruns) { 1175f9be9005SDavid Greenman ifp->if_oerrors += sp->tx_underruns; 1176f9be9005SDavid Greenman if (tx_threshold < 192) 1177f9be9005SDavid Greenman tx_threshold += 64; 1178f9be9005SDavid Greenman } 117994927790SDavid Greenman FXP_LOCK(sc); 1180397f9dfeSDavid Greenman /* 1181c8cc6fcaSDavid Greenman * Release any xmit buffers that have completed DMA. This isn't 1182c8cc6fcaSDavid Greenman * strictly necessary to do here, but it's advantagous for mbufs 1183c8cc6fcaSDavid Greenman * with external storage to be released in a timely manner rather 1184c8cc6fcaSDavid Greenman * than being defered for a potentially long time. This limits 1185c8cc6fcaSDavid Greenman * the delay to a maximum of one second. 1186c8cc6fcaSDavid Greenman */ 1187c8cc6fcaSDavid Greenman for (txp = sc->cbl_first; sc->tx_queued && 1188c8cc6fcaSDavid Greenman (txp->cb_status & FXP_CB_STATUS_C) != 0; 1189c8cc6fcaSDavid Greenman txp = txp->next) { 1190c8cc6fcaSDavid Greenman if (txp->mb_head != NULL) { 1191c8cc6fcaSDavid Greenman m_freem(txp->mb_head); 1192c8cc6fcaSDavid Greenman txp->mb_head = NULL; 1193c8cc6fcaSDavid Greenman } 1194c8cc6fcaSDavid Greenman sc->tx_queued--; 1195c8cc6fcaSDavid Greenman } 1196c8cc6fcaSDavid Greenman sc->cbl_first = txp; 1197c8cc6fcaSDavid Greenman /* 1198397f9dfeSDavid Greenman * If we haven't received any packets in FXP_MAC_RX_IDLE seconds, 1199397f9dfeSDavid Greenman * then assume the receiver has locked up and attempt to clear 1200397f9dfeSDavid Greenman * the condition by reprogramming the multicast filter. This is 1201397f9dfeSDavid Greenman * a work-around for a bug in the 82557 where the receiver locks 1202397f9dfeSDavid Greenman * up if it gets certain types of garbage in the syncronization 1203397f9dfeSDavid Greenman * bits prior to the packet header. This bug is supposed to only 1204397f9dfeSDavid Greenman * occur in 10Mbps mode, but has been seen to occur in 100Mbps 1205397f9dfeSDavid Greenman * mode as well (perhaps due to a 10/100 speed transition). 1206397f9dfeSDavid Greenman */ 1207397f9dfeSDavid Greenman if (sc->rx_idle_secs > FXP_MAX_RX_IDLE) { 1208397f9dfeSDavid Greenman sc->rx_idle_secs = 0; 1209397f9dfeSDavid Greenman fxp_mc_setup(sc); 1210397f9dfeSDavid Greenman } 1211f9be9005SDavid Greenman /* 12123ba65732SDavid Greenman * If there is no pending command, start another stats 12133ba65732SDavid Greenman * dump. Otherwise punt for now. 1214a17c678eSDavid Greenman */ 1215397f9dfeSDavid Greenman if (CSR_READ_1(sc, FXP_CSR_SCB_COMMAND) == 0) { 1216a17c678eSDavid Greenman /* 1217397f9dfeSDavid Greenman * Start another stats dump. 1218a17c678eSDavid Greenman */ 1219ba8c6fd5SDavid Greenman CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, 1220ba8c6fd5SDavid Greenman FXP_SCB_COMMAND_CU_DUMPRESET); 1221dfe61cf1SDavid Greenman } else { 1222dfe61cf1SDavid Greenman /* 1223dfe61cf1SDavid Greenman * A previous command is still waiting to be accepted. 1224dfe61cf1SDavid Greenman * Just zero our copy of the stats and wait for the 12253ba65732SDavid Greenman * next timer event to update them. 1226dfe61cf1SDavid Greenman */ 1227dfe61cf1SDavid Greenman sp->tx_good = 0; 1228f9be9005SDavid Greenman sp->tx_underruns = 0; 1229dfe61cf1SDavid Greenman sp->tx_total_collisions = 0; 12303ba65732SDavid Greenman 1231dfe61cf1SDavid Greenman sp->rx_good = 0; 12323ba65732SDavid Greenman sp->rx_crc_errors = 0; 12333ba65732SDavid Greenman sp->rx_alignment_errors = 0; 12343ba65732SDavid Greenman sp->rx_rnr_errors = 0; 12353ba65732SDavid Greenman sp->rx_overrun_errors = 0; 1236dfe61cf1SDavid Greenman } 123794927790SDavid Greenman FXP_UNLOCK(sc); 1238a17c678eSDavid Greenman /* 1239a17c678eSDavid Greenman * Schedule another timeout one second from now. 1240a17c678eSDavid Greenman */ 1241397f9dfeSDavid Greenman sc->stat_ch = timeout(fxp_stats_update, sc, hz); 1242a17c678eSDavid Greenman } 1243a17c678eSDavid Greenman 1244a17c678eSDavid Greenman /* 1245a17c678eSDavid Greenman * Stop the interface. Cancels the statistics updater and resets 1246a17c678eSDavid Greenman * the interface. 1247a17c678eSDavid Greenman */ 1248a17c678eSDavid Greenman static void 12494a5f1499SDavid Greenman fxp_stop(sc) 12504a5f1499SDavid Greenman struct fxp_softc *sc; 1251a17c678eSDavid Greenman { 1252ba8c6fd5SDavid Greenman struct ifnet *ifp = &sc->sc_if; 12533ba65732SDavid Greenman struct fxp_cb_tx *txp; 12543ba65732SDavid Greenman int i; 1255a17c678eSDavid Greenman 125694927790SDavid Greenman FXP_LOCK(sc); 12570f4dc94cSChuck Paterson 12587dced78aSDavid Greenman ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); 12597dced78aSDavid Greenman ifp->if_timer = 0; 12607dced78aSDavid Greenman 1261a17c678eSDavid Greenman /* 1262a17c678eSDavid Greenman * Cancel stats updater. 1263a17c678eSDavid Greenman */ 12646c951b44SJustin T. Gibbs untimeout(fxp_stats_update, sc, sc->stat_ch); 12653ba65732SDavid Greenman 12663ba65732SDavid Greenman /* 12673ba65732SDavid Greenman * Issue software reset 12683ba65732SDavid Greenman */ 1269ba8c6fd5SDavid Greenman CSR_WRITE_4(sc, FXP_CSR_PORT, FXP_PORT_SELECTIVE_RESET); 1270a17c678eSDavid Greenman DELAY(10); 1271a17c678eSDavid Greenman 12723ba65732SDavid Greenman /* 12733ba65732SDavid Greenman * Release any xmit buffers. 12743ba65732SDavid Greenman */ 1275da91462dSDavid Greenman txp = sc->cbl_base; 1276da91462dSDavid Greenman if (txp != NULL) { 1277da91462dSDavid Greenman for (i = 0; i < FXP_NTXCB; i++) { 1278da91462dSDavid Greenman if (txp[i].mb_head != NULL) { 1279da91462dSDavid Greenman m_freem(txp[i].mb_head); 1280da91462dSDavid Greenman txp[i].mb_head = NULL; 1281da91462dSDavid Greenman } 1282da91462dSDavid Greenman } 12833ba65732SDavid Greenman } 12843ba65732SDavid Greenman sc->tx_queued = 0; 12853ba65732SDavid Greenman 12863ba65732SDavid Greenman /* 12873ba65732SDavid Greenman * Free all the receive buffers then reallocate/reinitialize 12883ba65732SDavid Greenman */ 12893ba65732SDavid Greenman if (sc->rfa_headm != NULL) 12903ba65732SDavid Greenman m_freem(sc->rfa_headm); 12913ba65732SDavid Greenman sc->rfa_headm = NULL; 12923ba65732SDavid Greenman sc->rfa_tailm = NULL; 12933ba65732SDavid Greenman for (i = 0; i < FXP_NRFABUFS; i++) { 12943ba65732SDavid Greenman if (fxp_add_rfabuf(sc, NULL) != 0) { 12953ba65732SDavid Greenman /* 12963ba65732SDavid Greenman * This "can't happen" - we're at splimp() 12973ba65732SDavid Greenman * and we just freed all the buffers we need 12983ba65732SDavid Greenman * above. 12993ba65732SDavid Greenman */ 13003ba65732SDavid Greenman panic("fxp_stop: no buffers!"); 13013ba65732SDavid Greenman } 13023ba65732SDavid Greenman } 13033ba65732SDavid Greenman 130494927790SDavid Greenman FXP_UNLOCK(sc); 1305a17c678eSDavid Greenman } 1306a17c678eSDavid Greenman 1307a17c678eSDavid Greenman /* 1308a17c678eSDavid Greenman * Watchdog/transmission transmit timeout handler. Called when a 1309a17c678eSDavid Greenman * transmission is started on the interface, but no interrupt is 1310a17c678eSDavid Greenman * received before the timeout. This usually indicates that the 1311a17c678eSDavid Greenman * card has wedged for some reason. 1312a17c678eSDavid Greenman */ 1313a17c678eSDavid Greenman static void 13144a5f1499SDavid Greenman fxp_watchdog(ifp) 13154a5f1499SDavid Greenman struct ifnet *ifp; 1316a17c678eSDavid Greenman { 1317ba8c6fd5SDavid Greenman struct fxp_softc *sc = ifp->if_softc; 1318ba8c6fd5SDavid Greenman 131994927790SDavid Greenman printf("fxp%d: device timeout\n", FXP_UNIT(sc)); 13204a5f1499SDavid Greenman ifp->if_oerrors++; 1321a17c678eSDavid Greenman 1322ba8c6fd5SDavid Greenman fxp_init(sc); 1323a17c678eSDavid Greenman } 1324a17c678eSDavid Greenman 1325a17c678eSDavid Greenman static void 1326fb583156SDavid Greenman fxp_init(xsc) 1327fb583156SDavid Greenman void *xsc; 1328a17c678eSDavid Greenman { 1329fb583156SDavid Greenman struct fxp_softc *sc = xsc; 1330ba8c6fd5SDavid Greenman struct ifnet *ifp = &sc->sc_if; 1331a17c678eSDavid Greenman struct fxp_cb_config *cbp; 1332a17c678eSDavid Greenman struct fxp_cb_ias *cb_ias; 1333a17c678eSDavid Greenman struct fxp_cb_tx *txp; 13340f4dc94cSChuck Paterson int i, prm; 1335a17c678eSDavid Greenman 133694927790SDavid Greenman FXP_LOCK(sc); 1337a17c678eSDavid Greenman /* 13383ba65732SDavid Greenman * Cancel any pending I/O 1339a17c678eSDavid Greenman */ 13403ba65732SDavid Greenman fxp_stop(sc); 1341a17c678eSDavid Greenman 1342a17c678eSDavid Greenman prm = (ifp->if_flags & IFF_PROMISC) ? 1 : 0; 1343a17c678eSDavid Greenman 1344a17c678eSDavid Greenman /* 1345a17c678eSDavid Greenman * Initialize base of CBL and RFA memory. Loading with zero 1346a17c678eSDavid Greenman * sets it up for regular linear addressing. 1347a17c678eSDavid Greenman */ 1348ba8c6fd5SDavid Greenman CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, 0); 1349ba8c6fd5SDavid Greenman CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_BASE); 1350a17c678eSDavid Greenman 1351ba8c6fd5SDavid Greenman fxp_scb_wait(sc); 1352ba8c6fd5SDavid Greenman CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_RU_BASE); 1353a17c678eSDavid Greenman 1354a17c678eSDavid Greenman /* 1355a17c678eSDavid Greenman * Initialize base of dump-stats buffer. 1356a17c678eSDavid Greenman */ 1357ba8c6fd5SDavid Greenman fxp_scb_wait(sc); 1358ba8c6fd5SDavid Greenman CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, vtophys(sc->fxp_stats)); 1359ba8c6fd5SDavid Greenman CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_DUMP_ADR); 1360a17c678eSDavid Greenman 1361a17c678eSDavid Greenman /* 1362a17c678eSDavid Greenman * We temporarily use memory that contains the TxCB list to 1363a17c678eSDavid Greenman * construct the config CB. The TxCB list memory is rebuilt 1364a17c678eSDavid Greenman * later. 1365a17c678eSDavid Greenman */ 1366a17c678eSDavid Greenman cbp = (struct fxp_cb_config *) sc->cbl_base; 1367a17c678eSDavid Greenman 1368a17c678eSDavid Greenman /* 1369a17c678eSDavid Greenman * This bcopy is kind of disgusting, but there are a bunch of must be 1370a17c678eSDavid Greenman * zero and must be one bits in this structure and this is the easiest 1371a17c678eSDavid Greenman * way to initialize them all to proper values. 1372a17c678eSDavid Greenman */ 1373d244b0e9SPeter Wemm bcopy(fxp_cb_config_template, 1374d244b0e9SPeter Wemm (void *)(uintptr_t)(volatile void *)&cbp->cb_status, 1375397f9dfeSDavid Greenman sizeof(fxp_cb_config_template)); 1376a17c678eSDavid Greenman 1377a17c678eSDavid Greenman cbp->cb_status = 0; 1378a17c678eSDavid Greenman cbp->cb_command = FXP_CB_COMMAND_CONFIG | FXP_CB_COMMAND_EL; 1379a17c678eSDavid Greenman cbp->link_addr = -1; /* (no) next command */ 1380a17c678eSDavid Greenman cbp->byte_count = 22; /* (22) bytes to config */ 1381001696daSDavid Greenman cbp->rx_fifo_limit = 8; /* rx fifo threshold (32 bytes) */ 1382001696daSDavid Greenman cbp->tx_fifo_limit = 0; /* tx fifo threshold (0 bytes) */ 1383a17c678eSDavid Greenman cbp->adaptive_ifs = 0; /* (no) adaptive interframe spacing */ 1384001696daSDavid Greenman cbp->rx_dma_bytecount = 0; /* (no) rx DMA max */ 1385001696daSDavid Greenman cbp->tx_dma_bytecount = 0; /* (no) tx DMA max */ 1386001696daSDavid Greenman cbp->dma_bce = 0; /* (disable) dma max counters */ 1387a17c678eSDavid Greenman cbp->late_scb = 0; /* (don't) defer SCB update */ 1388a17c678eSDavid Greenman cbp->tno_int = 0; /* (disable) tx not okay interrupt */ 13893114fdb4SDavid Greenman cbp->ci_int = 1; /* interrupt on CU idle */ 1390a17c678eSDavid Greenman cbp->save_bf = prm; /* save bad frames */ 1391a17c678eSDavid Greenman cbp->disc_short_rx = !prm; /* discard short packets */ 1392a17c678eSDavid Greenman cbp->underrun_retry = 1; /* retry mode (1) on DMA underrun */ 1393dccee1a1SDavid Greenman cbp->mediatype = !sc->phy_10Mbps_only; /* interface mode */ 1394a17c678eSDavid Greenman cbp->nsai = 1; /* (don't) disable source addr insert */ 1395a17c678eSDavid Greenman cbp->preamble_length = 2; /* (7 byte) preamble */ 1396a17c678eSDavid Greenman cbp->loopback = 0; /* (don't) loopback */ 1397a17c678eSDavid Greenman cbp->linear_priority = 0; /* (normal CSMA/CD operation) */ 1398a17c678eSDavid Greenman cbp->linear_pri_mode = 0; /* (wait after xmit only) */ 1399a17c678eSDavid Greenman cbp->interfrm_spacing = 6; /* (96 bits of) interframe spacing */ 1400a17c678eSDavid Greenman cbp->promiscuous = prm; /* promiscuous mode */ 1401a17c678eSDavid Greenman cbp->bcast_disable = 0; /* (don't) disable broadcasts */ 1402001696daSDavid Greenman cbp->crscdt = 0; /* (CRS only) */ 1403a17c678eSDavid Greenman cbp->stripping = !prm; /* truncate rx packet to byte count */ 1404a17c678eSDavid Greenman cbp->padding = 1; /* (do) pad short tx packets */ 1405a17c678eSDavid Greenman cbp->rcv_crc_xfer = 0; /* (don't) xfer CRC to host */ 1406a17c678eSDavid Greenman cbp->force_fdx = 0; /* (don't) force full duplex */ 14073ba65732SDavid Greenman cbp->fdx_pin_en = 1; /* (enable) FDX# pin */ 1408a17c678eSDavid Greenman cbp->multi_ia = 0; /* (don't) accept multiple IAs */ 1409397f9dfeSDavid Greenman cbp->mc_all = sc->all_mcasts;/* accept all multicasts */ 1410a17c678eSDavid Greenman 1411a17c678eSDavid Greenman /* 1412a17c678eSDavid Greenman * Start the config command/DMA. 1413a17c678eSDavid Greenman */ 1414ba8c6fd5SDavid Greenman fxp_scb_wait(sc); 1415397f9dfeSDavid Greenman CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, vtophys(&cbp->cb_status)); 1416ba8c6fd5SDavid Greenman CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START); 1417a17c678eSDavid Greenman /* ...and wait for it to complete. */ 14187dced78aSDavid Greenman fxp_dma_wait(&cbp->cb_status, sc); 1419a17c678eSDavid Greenman 1420a17c678eSDavid Greenman /* 1421a17c678eSDavid Greenman * Now initialize the station address. Temporarily use the TxCB 1422a17c678eSDavid Greenman * memory area like we did above for the config CB. 1423a17c678eSDavid Greenman */ 1424a17c678eSDavid Greenman cb_ias = (struct fxp_cb_ias *) sc->cbl_base; 1425a17c678eSDavid Greenman cb_ias->cb_status = 0; 1426a17c678eSDavid Greenman cb_ias->cb_command = FXP_CB_COMMAND_IAS | FXP_CB_COMMAND_EL; 1427a17c678eSDavid Greenman cb_ias->link_addr = -1; 1428d244b0e9SPeter Wemm bcopy(sc->arpcom.ac_enaddr, 1429d244b0e9SPeter Wemm (void *)(uintptr_t)(volatile void *)cb_ias->macaddr, 1430a17c678eSDavid Greenman sizeof(sc->arpcom.ac_enaddr)); 1431a17c678eSDavid Greenman 1432a17c678eSDavid Greenman /* 1433a17c678eSDavid Greenman * Start the IAS (Individual Address Setup) command/DMA. 1434a17c678eSDavid Greenman */ 1435ba8c6fd5SDavid Greenman fxp_scb_wait(sc); 1436ba8c6fd5SDavid Greenman CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START); 1437a17c678eSDavid Greenman /* ...and wait for it to complete. */ 14387dced78aSDavid Greenman fxp_dma_wait(&cb_ias->cb_status, sc); 1439a17c678eSDavid Greenman 1440a17c678eSDavid Greenman /* 1441a17c678eSDavid Greenman * Initialize transmit control block (TxCB) list. 1442a17c678eSDavid Greenman */ 1443a17c678eSDavid Greenman 1444a17c678eSDavid Greenman txp = sc->cbl_base; 1445a17c678eSDavid Greenman bzero(txp, sizeof(struct fxp_cb_tx) * FXP_NTXCB); 1446a17c678eSDavid Greenman for (i = 0; i < FXP_NTXCB; i++) { 1447a17c678eSDavid Greenman txp[i].cb_status = FXP_CB_STATUS_C | FXP_CB_STATUS_OK; 1448a17c678eSDavid Greenman txp[i].cb_command = FXP_CB_COMMAND_NOP; 1449397f9dfeSDavid Greenman txp[i].link_addr = vtophys(&txp[(i + 1) & FXP_TXCB_MASK].cb_status); 1450a17c678eSDavid Greenman txp[i].tbd_array_addr = vtophys(&txp[i].tbd[0]); 1451a17c678eSDavid Greenman txp[i].next = &txp[(i + 1) & FXP_TXCB_MASK]; 1452a17c678eSDavid Greenman } 1453a17c678eSDavid Greenman /* 1454397f9dfeSDavid Greenman * Set the suspend flag on the first TxCB and start the control 1455a17c678eSDavid Greenman * unit. It will execute the NOP and then suspend. 1456a17c678eSDavid Greenman */ 1457a17c678eSDavid Greenman txp->cb_command = FXP_CB_COMMAND_NOP | FXP_CB_COMMAND_S; 1458a17c678eSDavid Greenman sc->cbl_first = sc->cbl_last = txp; 1459397f9dfeSDavid Greenman sc->tx_queued = 1; 1460a17c678eSDavid Greenman 1461ba8c6fd5SDavid Greenman fxp_scb_wait(sc); 1462ba8c6fd5SDavid Greenman CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START); 1463a17c678eSDavid Greenman 1464a17c678eSDavid Greenman /* 1465a17c678eSDavid Greenman * Initialize receiver buffer area - RFA. 1466a17c678eSDavid Greenman */ 1467ba8c6fd5SDavid Greenman fxp_scb_wait(sc); 1468ba8c6fd5SDavid Greenman CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, 1469ba8c6fd5SDavid Greenman vtophys(sc->rfa_headm->m_ext.ext_buf) + RFA_ALIGNMENT_FUDGE); 1470ba8c6fd5SDavid Greenman CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_RU_START); 1471a17c678eSDavid Greenman 1472dccee1a1SDavid Greenman /* 1473ba8c6fd5SDavid Greenman * Set current media. 1474dccee1a1SDavid Greenman */ 1475ba8c6fd5SDavid Greenman fxp_set_media(sc, sc->sc_media.ifm_cur->ifm_media); 1476dccee1a1SDavid Greenman 1477a17c678eSDavid Greenman ifp->if_flags |= IFF_RUNNING; 1478a17c678eSDavid Greenman ifp->if_flags &= ~IFF_OACTIVE; 147994927790SDavid Greenman FXP_UNLOCK(sc); 1480a17c678eSDavid Greenman 1481a17c678eSDavid Greenman /* 1482a17c678eSDavid Greenman * Start stats updater. 1483a17c678eSDavid Greenman */ 14846c951b44SJustin T. Gibbs sc->stat_ch = timeout(fxp_stats_update, sc, hz); 1485a17c678eSDavid Greenman } 1486a17c678eSDavid Greenman 1487303b270bSEivind Eklund static void 1488ba8c6fd5SDavid Greenman fxp_set_media(sc, media) 1489ba8c6fd5SDavid Greenman struct fxp_softc *sc; 1490ba8c6fd5SDavid Greenman int media; 1491ba8c6fd5SDavid Greenman { 1492ba8c6fd5SDavid Greenman 1493ba8c6fd5SDavid Greenman switch (sc->phy_primary_device) { 1494ba8c6fd5SDavid Greenman case FXP_PHY_DP83840: 1495ba8c6fd5SDavid Greenman case FXP_PHY_DP83840A: 1496ba8c6fd5SDavid Greenman fxp_mdi_write(sc, sc->phy_primary_addr, FXP_DP83840_PCR, 1497ba8c6fd5SDavid Greenman fxp_mdi_read(sc, sc->phy_primary_addr, FXP_DP83840_PCR) | 1498ba8c6fd5SDavid Greenman FXP_DP83840_PCR_LED4_MODE | /* LED4 always indicates duplex */ 1499ba8c6fd5SDavid Greenman FXP_DP83840_PCR_F_CONNECT | /* force link disconnect bypass */ 1500ba8c6fd5SDavid Greenman FXP_DP83840_PCR_BIT10); /* XXX I have no idea */ 1501ba8c6fd5SDavid Greenman /* fall through */ 150292924291SDavid Greenman case FXP_PHY_82553A: 150392924291SDavid Greenman case FXP_PHY_82553C: /* untested */ 1504ba8c6fd5SDavid Greenman case FXP_PHY_82555: 150592924291SDavid Greenman case FXP_PHY_82555B: 1506ba8c6fd5SDavid Greenman if (IFM_SUBTYPE(media) != IFM_AUTO) { 1507ba8c6fd5SDavid Greenman int flags; 1508ba8c6fd5SDavid Greenman 1509ba8c6fd5SDavid Greenman flags = (IFM_SUBTYPE(media) == IFM_100_TX) ? 1510ba8c6fd5SDavid Greenman FXP_PHY_BMCR_SPEED_100M : 0; 1511ba8c6fd5SDavid Greenman flags |= (media & IFM_FDX) ? 1512ba8c6fd5SDavid Greenman FXP_PHY_BMCR_FULLDUPLEX : 0; 1513ba8c6fd5SDavid Greenman fxp_mdi_write(sc, sc->phy_primary_addr, 1514ba8c6fd5SDavid Greenman FXP_PHY_BMCR, 1515ba8c6fd5SDavid Greenman (fxp_mdi_read(sc, sc->phy_primary_addr, 1516ba8c6fd5SDavid Greenman FXP_PHY_BMCR) & 1517ba8c6fd5SDavid Greenman ~(FXP_PHY_BMCR_AUTOEN | FXP_PHY_BMCR_SPEED_100M | 1518ba8c6fd5SDavid Greenman FXP_PHY_BMCR_FULLDUPLEX)) | flags); 1519ba8c6fd5SDavid Greenman } else { 1520ba8c6fd5SDavid Greenman fxp_mdi_write(sc, sc->phy_primary_addr, 1521ba8c6fd5SDavid Greenman FXP_PHY_BMCR, 1522ba8c6fd5SDavid Greenman (fxp_mdi_read(sc, sc->phy_primary_addr, 1523ba8c6fd5SDavid Greenman FXP_PHY_BMCR) | FXP_PHY_BMCR_AUTOEN)); 1524ba8c6fd5SDavid Greenman } 1525ba8c6fd5SDavid Greenman break; 1526ba8c6fd5SDavid Greenman /* 1527ba8c6fd5SDavid Greenman * The Seeq 80c24 doesn't have a PHY programming interface, so do 1528ba8c6fd5SDavid Greenman * nothing. 1529ba8c6fd5SDavid Greenman */ 1530ba8c6fd5SDavid Greenman case FXP_PHY_80C24: 1531ba8c6fd5SDavid Greenman break; 1532ba8c6fd5SDavid Greenman default: 153394927790SDavid Greenman printf("fxp%d: warning: unsupported PHY, type = %d, addr = %d\n", 153494927790SDavid Greenman FXP_UNIT(sc), sc->phy_primary_device, 1535ba8c6fd5SDavid Greenman sc->phy_primary_addr); 1536ba8c6fd5SDavid Greenman } 1537ba8c6fd5SDavid Greenman } 1538ba8c6fd5SDavid Greenman 1539ba8c6fd5SDavid Greenman /* 1540ba8c6fd5SDavid Greenman * Change media according to request. 1541ba8c6fd5SDavid Greenman */ 1542ba8c6fd5SDavid Greenman int 1543ba8c6fd5SDavid Greenman fxp_mediachange(ifp) 1544ba8c6fd5SDavid Greenman struct ifnet *ifp; 1545ba8c6fd5SDavid Greenman { 1546ba8c6fd5SDavid Greenman struct fxp_softc *sc = ifp->if_softc; 1547ba8c6fd5SDavid Greenman struct ifmedia *ifm = &sc->sc_media; 1548ba8c6fd5SDavid Greenman 1549ba8c6fd5SDavid Greenman if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) 1550ba8c6fd5SDavid Greenman return (EINVAL); 1551ba8c6fd5SDavid Greenman 1552ba8c6fd5SDavid Greenman fxp_set_media(sc, ifm->ifm_media); 1553ba8c6fd5SDavid Greenman return (0); 1554ba8c6fd5SDavid Greenman } 1555ba8c6fd5SDavid Greenman 1556ba8c6fd5SDavid Greenman /* 1557ba8c6fd5SDavid Greenman * Notify the world which media we're using. 1558ba8c6fd5SDavid Greenman */ 1559ba8c6fd5SDavid Greenman void 1560ba8c6fd5SDavid Greenman fxp_mediastatus(ifp, ifmr) 1561ba8c6fd5SDavid Greenman struct ifnet *ifp; 1562ba8c6fd5SDavid Greenman struct ifmediareq *ifmr; 1563ba8c6fd5SDavid Greenman { 1564ba8c6fd5SDavid Greenman struct fxp_softc *sc = ifp->if_softc; 1565a7280784SJulian Elischer int flags, stsflags; 1566ba8c6fd5SDavid Greenman 1567ba8c6fd5SDavid Greenman switch (sc->phy_primary_device) { 1568ba8c6fd5SDavid Greenman case FXP_PHY_82555: 156935517ab7SDavid Greenman case FXP_PHY_82555B: 1570a7280784SJulian Elischer case FXP_PHY_DP83840: 1571a7280784SJulian Elischer case FXP_PHY_DP83840A: 1572a7280784SJulian Elischer ifmr->ifm_status = IFM_AVALID; /* IFM_ACTIVE will be valid */ 1573ba8c6fd5SDavid Greenman ifmr->ifm_active = IFM_ETHER; 1574a7280784SJulian Elischer /* 1575a7280784SJulian Elischer * the following is not an error. 1576a7280784SJulian Elischer * You need to read this register twice to get current 1577a7280784SJulian Elischer * status. This is correct documented behaviour, the 1578a7280784SJulian Elischer * first read gets latched values. 1579a7280784SJulian Elischer */ 1580a7280784SJulian Elischer stsflags = fxp_mdi_read(sc, sc->phy_primary_addr, FXP_PHY_STS); 1581a7280784SJulian Elischer stsflags = fxp_mdi_read(sc, sc->phy_primary_addr, FXP_PHY_STS); 1582a7280784SJulian Elischer if (stsflags & FXP_PHY_STS_LINK_STS) 1583a7280784SJulian Elischer ifmr->ifm_status |= IFM_ACTIVE; 1584a7280784SJulian Elischer 1585a7280784SJulian Elischer /* 1586a7280784SJulian Elischer * If we are in auto mode, then try report the result. 1587a7280784SJulian Elischer */ 1588a7280784SJulian Elischer flags = fxp_mdi_read(sc, sc->phy_primary_addr, FXP_PHY_BMCR); 1589f1bf08c2SJulian Elischer if (flags & FXP_PHY_BMCR_AUTOEN) { 1590f1bf08c2SJulian Elischer ifmr->ifm_active |= IFM_AUTO; /* XXX presently 0 */ 1591a7280784SJulian Elischer if (stsflags & FXP_PHY_STS_AUTO_DONE) { 1592f1bf08c2SJulian Elischer /* 1593a7280784SJulian Elischer * Intel and National parts report 1594a7280784SJulian Elischer * differently on what they found. 1595f1bf08c2SJulian Elischer */ 1596f1bf08c2SJulian Elischer if ((sc->phy_primary_device == FXP_PHY_82555) 1597f1bf08c2SJulian Elischer || (sc->phy_primary_device == FXP_PHY_82555B)) { 1598f1bf08c2SJulian Elischer flags = fxp_mdi_read(sc, 1599a7280784SJulian Elischer sc->phy_primary_addr, 1600a7280784SJulian Elischer FXP_PHY_USC); 1601f1bf08c2SJulian Elischer 1602f1bf08c2SJulian Elischer if (flags & FXP_PHY_USC_SPEED) 1603f1bf08c2SJulian Elischer ifmr->ifm_active |= IFM_100_TX; 1604f1bf08c2SJulian Elischer else 1605f1bf08c2SJulian Elischer ifmr->ifm_active |= IFM_10_T; 1606f1bf08c2SJulian Elischer 1607f1bf08c2SJulian Elischer if (flags & FXP_PHY_USC_DUPLEX) 1608f1bf08c2SJulian Elischer ifmr->ifm_active |= IFM_FDX; 1609a7280784SJulian Elischer } else { /* it's National. only know speed */ 1610a7280784SJulian Elischer flags = fxp_mdi_read(sc, 1611a7280784SJulian Elischer sc->phy_primary_addr, 1612a7280784SJulian Elischer FXP_DP83840_PAR); 1613a7280784SJulian Elischer 1614a7280784SJulian Elischer if (flags & FXP_DP83840_PAR_SPEED_10) 1615a7280784SJulian Elischer ifmr->ifm_active |= IFM_10_T; 1616a7280784SJulian Elischer else 1617a7280784SJulian Elischer ifmr->ifm_active |= IFM_100_TX; 1618f1bf08c2SJulian Elischer } 1619a7280784SJulian Elischer } 1620a7280784SJulian Elischer } else { /* in manual mode.. just report what we were set to */ 1621ba8c6fd5SDavid Greenman if (flags & FXP_PHY_BMCR_SPEED_100M) 1622ba8c6fd5SDavid Greenman ifmr->ifm_active |= IFM_100_TX; 1623ba8c6fd5SDavid Greenman else 1624ba8c6fd5SDavid Greenman ifmr->ifm_active |= IFM_10_T; 1625ba8c6fd5SDavid Greenman 1626ba8c6fd5SDavid Greenman if (flags & FXP_PHY_BMCR_FULLDUPLEX) 1627ba8c6fd5SDavid Greenman ifmr->ifm_active |= IFM_FDX; 1628ba8c6fd5SDavid Greenman } 1629ba8c6fd5SDavid Greenman break; 1630ba8c6fd5SDavid Greenman 1631ba8c6fd5SDavid Greenman case FXP_PHY_80C24: 1632ba8c6fd5SDavid Greenman default: 1633ba8c6fd5SDavid Greenman ifmr->ifm_active = IFM_ETHER|IFM_MANUAL; /* XXX IFM_AUTO ? */ 1634ba8c6fd5SDavid Greenman } 1635ba8c6fd5SDavid Greenman } 1636ba8c6fd5SDavid Greenman 1637a17c678eSDavid Greenman /* 1638a17c678eSDavid Greenman * Add a buffer to the end of the RFA buffer list. 1639a17c678eSDavid Greenman * Return 0 if successful, 1 for failure. A failure results in 1640a17c678eSDavid Greenman * adding the 'oldm' (if non-NULL) on to the end of the list - 1641dc733423SDag-Erling Smørgrav * tossing out its old contents and recycling it. 1642a17c678eSDavid Greenman * The RFA struct is stuck at the beginning of mbuf cluster and the 1643a17c678eSDavid Greenman * data pointer is fixed up to point just past it. 1644a17c678eSDavid Greenman */ 1645a17c678eSDavid Greenman static int 1646a17c678eSDavid Greenman fxp_add_rfabuf(sc, oldm) 1647a17c678eSDavid Greenman struct fxp_softc *sc; 1648a17c678eSDavid Greenman struct mbuf *oldm; 1649a17c678eSDavid Greenman { 1650ba8c6fd5SDavid Greenman u_int32_t v; 1651a17c678eSDavid Greenman struct mbuf *m; 1652a17c678eSDavid Greenman struct fxp_rfa *rfa, *p_rfa; 1653a17c678eSDavid Greenman 1654a17c678eSDavid Greenman MGETHDR(m, M_DONTWAIT, MT_DATA); 1655a17c678eSDavid Greenman if (m != NULL) { 1656a17c678eSDavid Greenman MCLGET(m, M_DONTWAIT); 1657a17c678eSDavid Greenman if ((m->m_flags & M_EXT) == 0) { 1658a17c678eSDavid Greenman m_freem(m); 1659eadd5e3aSDavid Greenman if (oldm == NULL) 1660eadd5e3aSDavid Greenman return 1; 1661a17c678eSDavid Greenman m = oldm; 1662eadd5e3aSDavid Greenman m->m_data = m->m_ext.ext_buf; 1663a17c678eSDavid Greenman } 1664a17c678eSDavid Greenman } else { 1665eadd5e3aSDavid Greenman if (oldm == NULL) 1666a17c678eSDavid Greenman return 1; 1667eadd5e3aSDavid Greenman m = oldm; 1668eadd5e3aSDavid Greenman m->m_data = m->m_ext.ext_buf; 1669eadd5e3aSDavid Greenman } 1670ba8c6fd5SDavid Greenman 1671ba8c6fd5SDavid Greenman /* 1672ba8c6fd5SDavid Greenman * Move the data pointer up so that the incoming data packet 1673ba8c6fd5SDavid Greenman * will be 32-bit aligned. 1674ba8c6fd5SDavid Greenman */ 1675ba8c6fd5SDavid Greenman m->m_data += RFA_ALIGNMENT_FUDGE; 1676ba8c6fd5SDavid Greenman 1677eadd5e3aSDavid Greenman /* 1678eadd5e3aSDavid Greenman * Get a pointer to the base of the mbuf cluster and move 1679eadd5e3aSDavid Greenman * data start past it. 1680eadd5e3aSDavid Greenman */ 1681a17c678eSDavid Greenman rfa = mtod(m, struct fxp_rfa *); 1682eadd5e3aSDavid Greenman m->m_data += sizeof(struct fxp_rfa); 16834fc1dda9SAndrew Gallatin rfa->size = (u_int16_t)(MCLBYTES - sizeof(struct fxp_rfa) - RFA_ALIGNMENT_FUDGE); 1684eadd5e3aSDavid Greenman 1685ba8c6fd5SDavid Greenman /* 1686ba8c6fd5SDavid Greenman * Initialize the rest of the RFA. Note that since the RFA 1687ba8c6fd5SDavid Greenman * is misaligned, we cannot store values directly. Instead, 1688ba8c6fd5SDavid Greenman * we use an optimized, inline copy. 1689ba8c6fd5SDavid Greenman */ 16904fc1dda9SAndrew Gallatin 1691a17c678eSDavid Greenman rfa->rfa_status = 0; 1692a17c678eSDavid Greenman rfa->rfa_control = FXP_RFA_CONTROL_EL; 1693a17c678eSDavid Greenman rfa->actual_size = 0; 1694ba8c6fd5SDavid Greenman 1695ba8c6fd5SDavid Greenman v = -1; 16964fc1dda9SAndrew Gallatin fxp_lwcopy(&v, (volatile u_int32_t *) rfa->link_addr); 16974fc1dda9SAndrew Gallatin fxp_lwcopy(&v, (volatile u_int32_t *) rfa->rbd_addr); 1698ba8c6fd5SDavid Greenman 1699dfe61cf1SDavid Greenman /* 1700dfe61cf1SDavid Greenman * If there are other buffers already on the list, attach this 1701dfe61cf1SDavid Greenman * one to the end by fixing up the tail to point to this one. 1702dfe61cf1SDavid Greenman */ 1703a17c678eSDavid Greenman if (sc->rfa_headm != NULL) { 1704ba8c6fd5SDavid Greenman p_rfa = (struct fxp_rfa *) (sc->rfa_tailm->m_ext.ext_buf + 1705ba8c6fd5SDavid Greenman RFA_ALIGNMENT_FUDGE); 1706a17c678eSDavid Greenman sc->rfa_tailm->m_next = m; 1707ba8c6fd5SDavid Greenman v = vtophys(rfa); 17084fc1dda9SAndrew Gallatin fxp_lwcopy(&v, (volatile u_int32_t *) p_rfa->link_addr); 1709aed53495SDavid Greenman p_rfa->rfa_control = 0; 1710a17c678eSDavid Greenman } else { 1711a17c678eSDavid Greenman sc->rfa_headm = m; 1712a17c678eSDavid Greenman } 1713a17c678eSDavid Greenman sc->rfa_tailm = m; 1714a17c678eSDavid Greenman 1715dfe61cf1SDavid Greenman return (m == oldm); 1716a17c678eSDavid Greenman } 1717a17c678eSDavid Greenman 17186ebc3153SDavid Greenman static volatile int 1719ba8c6fd5SDavid Greenman fxp_mdi_read(sc, phy, reg) 1720ba8c6fd5SDavid Greenman struct fxp_softc *sc; 1721dccee1a1SDavid Greenman int phy; 1722dccee1a1SDavid Greenman int reg; 1723dccee1a1SDavid Greenman { 1724dccee1a1SDavid Greenman int count = 10000; 17256ebc3153SDavid Greenman int value; 1726dccee1a1SDavid Greenman 1727ba8c6fd5SDavid Greenman CSR_WRITE_4(sc, FXP_CSR_MDICONTROL, 1728ba8c6fd5SDavid Greenman (FXP_MDI_READ << 26) | (reg << 16) | (phy << 21)); 1729dccee1a1SDavid Greenman 1730ba8c6fd5SDavid Greenman while (((value = CSR_READ_4(sc, FXP_CSR_MDICONTROL)) & 0x10000000) == 0 1731ba8c6fd5SDavid Greenman && count--) 17326ebc3153SDavid Greenman DELAY(10); 1733dccee1a1SDavid Greenman 1734dccee1a1SDavid Greenman if (count <= 0) 173594927790SDavid Greenman printf("fxp%d: fxp_mdi_read: timed out\n", FXP_UNIT(sc)); 1736dccee1a1SDavid Greenman 17376ebc3153SDavid Greenman return (value & 0xffff); 1738dccee1a1SDavid Greenman } 1739dccee1a1SDavid Greenman 1740dccee1a1SDavid Greenman static void 1741ba8c6fd5SDavid Greenman fxp_mdi_write(sc, phy, reg, value) 1742ba8c6fd5SDavid Greenman struct fxp_softc *sc; 1743dccee1a1SDavid Greenman int phy; 1744dccee1a1SDavid Greenman int reg; 1745dccee1a1SDavid Greenman int value; 1746dccee1a1SDavid Greenman { 1747dccee1a1SDavid Greenman int count = 10000; 1748dccee1a1SDavid Greenman 1749ba8c6fd5SDavid Greenman CSR_WRITE_4(sc, FXP_CSR_MDICONTROL, 1750ba8c6fd5SDavid Greenman (FXP_MDI_WRITE << 26) | (reg << 16) | (phy << 21) | 1751ba8c6fd5SDavid Greenman (value & 0xffff)); 1752dccee1a1SDavid Greenman 1753ba8c6fd5SDavid Greenman while((CSR_READ_4(sc, FXP_CSR_MDICONTROL) & 0x10000000) == 0 && 1754ba8c6fd5SDavid Greenman count--) 17556ebc3153SDavid Greenman DELAY(10); 1756dccee1a1SDavid Greenman 1757dccee1a1SDavid Greenman if (count <= 0) 175894927790SDavid Greenman printf("fxp%d: fxp_mdi_write: timed out\n", FXP_UNIT(sc)); 1759dccee1a1SDavid Greenman } 1760dccee1a1SDavid Greenman 1761dccee1a1SDavid Greenman static int 1762a17c678eSDavid Greenman fxp_ioctl(ifp, command, data) 1763a17c678eSDavid Greenman struct ifnet *ifp; 176494927790SDavid Greenman u_long command; 1765a17c678eSDavid Greenman caddr_t data; 1766a17c678eSDavid Greenman { 17679b44ff22SGarrett Wollman struct fxp_softc *sc = ifp->if_softc; 1768a17c678eSDavid Greenman struct ifreq *ifr = (struct ifreq *)data; 17690f4dc94cSChuck Paterson int error = 0; 1770a17c678eSDavid Greenman 177194927790SDavid Greenman FXP_LOCK(sc); 1772a17c678eSDavid Greenman 1773a17c678eSDavid Greenman switch (command) { 1774a17c678eSDavid Greenman 1775a17c678eSDavid Greenman case SIOCSIFADDR: 1776a17c678eSDavid Greenman case SIOCGIFADDR: 1777fb583156SDavid Greenman case SIOCSIFMTU: 1778fb583156SDavid Greenman error = ether_ioctl(ifp, command, data); 1779a17c678eSDavid Greenman break; 1780a17c678eSDavid Greenman 1781a17c678eSDavid Greenman case SIOCSIFFLAGS: 1782397f9dfeSDavid Greenman sc->all_mcasts = (ifp->if_flags & IFF_ALLMULTI) ? 1 : 0; 1783a17c678eSDavid Greenman 1784a17c678eSDavid Greenman /* 1785a17c678eSDavid Greenman * If interface is marked up and not running, then start it. 1786a17c678eSDavid Greenman * If it is marked down and running, stop it. 1787a17c678eSDavid Greenman * XXX If it's up then re-initialize it. This is so flags 1788a17c678eSDavid Greenman * such as IFF_PROMISC are handled. 1789a17c678eSDavid Greenman */ 1790a17c678eSDavid Greenman if (ifp->if_flags & IFF_UP) { 1791fb583156SDavid Greenman fxp_init(sc); 1792a17c678eSDavid Greenman } else { 1793a17c678eSDavid Greenman if (ifp->if_flags & IFF_RUNNING) 17944a5f1499SDavid Greenman fxp_stop(sc); 1795a17c678eSDavid Greenman } 1796a17c678eSDavid Greenman break; 1797a17c678eSDavid Greenman 1798a17c678eSDavid Greenman case SIOCADDMULTI: 1799a17c678eSDavid Greenman case SIOCDELMULTI: 1800397f9dfeSDavid Greenman sc->all_mcasts = (ifp->if_flags & IFF_ALLMULTI) ? 1 : 0; 1801a17c678eSDavid Greenman /* 1802a17c678eSDavid Greenman * Multicast list has changed; set the hardware filter 1803a17c678eSDavid Greenman * accordingly. 1804a17c678eSDavid Greenman */ 1805397f9dfeSDavid Greenman if (!sc->all_mcasts) 1806397f9dfeSDavid Greenman fxp_mc_setup(sc); 1807397f9dfeSDavid Greenman /* 1808397f9dfeSDavid Greenman * fxp_mc_setup() can turn on sc->all_mcasts, so check it 1809397f9dfeSDavid Greenman * again rather than else {}. 1810397f9dfeSDavid Greenman */ 1811397f9dfeSDavid Greenman if (sc->all_mcasts) 1812fb583156SDavid Greenman fxp_init(sc); 1813a17c678eSDavid Greenman error = 0; 1814ba8c6fd5SDavid Greenman break; 1815ba8c6fd5SDavid Greenman 1816ba8c6fd5SDavid Greenman case SIOCSIFMEDIA: 1817ba8c6fd5SDavid Greenman case SIOCGIFMEDIA: 1818ba8c6fd5SDavid Greenman error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, command); 1819a17c678eSDavid Greenman break; 1820a17c678eSDavid Greenman 1821a17c678eSDavid Greenman default: 1822a17c678eSDavid Greenman error = EINVAL; 1823a17c678eSDavid Greenman } 182494927790SDavid Greenman FXP_UNLOCK(sc); 1825a17c678eSDavid Greenman return (error); 1826a17c678eSDavid Greenman } 1827397f9dfeSDavid Greenman 1828397f9dfeSDavid Greenman /* 1829397f9dfeSDavid Greenman * Program the multicast filter. 1830397f9dfeSDavid Greenman * 1831397f9dfeSDavid Greenman * We have an artificial restriction that the multicast setup command 1832397f9dfeSDavid Greenman * must be the first command in the chain, so we take steps to ensure 18333114fdb4SDavid Greenman * this. By requiring this, it allows us to keep up the performance of 1834397f9dfeSDavid Greenman * the pre-initialized command ring (esp. link pointers) by not actually 1835dc733423SDag-Erling Smørgrav * inserting the mcsetup command in the ring - i.e. its link pointer 1836397f9dfeSDavid Greenman * points to the TxCB ring, but the mcsetup descriptor itself is not part 1837397f9dfeSDavid Greenman * of it. We then can do 'CU_START' on the mcsetup descriptor and have it 1838397f9dfeSDavid Greenman * lead into the regular TxCB ring when it completes. 1839397f9dfeSDavid Greenman * 1840397f9dfeSDavid Greenman * This function must be called at splimp. 1841397f9dfeSDavid Greenman */ 1842397f9dfeSDavid Greenman static void 1843397f9dfeSDavid Greenman fxp_mc_setup(sc) 1844397f9dfeSDavid Greenman struct fxp_softc *sc; 1845397f9dfeSDavid Greenman { 1846397f9dfeSDavid Greenman struct fxp_cb_mcs *mcsp = sc->mcsp; 1847397f9dfeSDavid Greenman struct ifnet *ifp = &sc->sc_if; 1848397f9dfeSDavid Greenman struct ifmultiaddr *ifma; 1849397f9dfeSDavid Greenman int nmcasts; 18507dced78aSDavid Greenman int count; 1851397f9dfeSDavid Greenman 18523114fdb4SDavid Greenman /* 18533114fdb4SDavid Greenman * If there are queued commands, we must wait until they are all 18543114fdb4SDavid Greenman * completed. If we are already waiting, then add a NOP command 18553114fdb4SDavid Greenman * with interrupt option so that we're notified when all commands 18563114fdb4SDavid Greenman * have been completed - fxp_start() ensures that no additional 18573114fdb4SDavid Greenman * TX commands will be added when need_mcsetup is true. 18583114fdb4SDavid Greenman */ 1859397f9dfeSDavid Greenman if (sc->tx_queued) { 18603114fdb4SDavid Greenman struct fxp_cb_tx *txp; 18613114fdb4SDavid Greenman 18623114fdb4SDavid Greenman /* 18633114fdb4SDavid Greenman * need_mcsetup will be true if we are already waiting for the 18643114fdb4SDavid Greenman * NOP command to be completed (see below). In this case, bail. 18653114fdb4SDavid Greenman */ 18663114fdb4SDavid Greenman if (sc->need_mcsetup) 18673114fdb4SDavid Greenman return; 1868397f9dfeSDavid Greenman sc->need_mcsetup = 1; 18693114fdb4SDavid Greenman 18703114fdb4SDavid Greenman /* 18713114fdb4SDavid Greenman * Add a NOP command with interrupt so that we are notified when all 18723114fdb4SDavid Greenman * TX commands have been processed. 18733114fdb4SDavid Greenman */ 18743114fdb4SDavid Greenman txp = sc->cbl_last->next; 18753114fdb4SDavid Greenman txp->mb_head = NULL; 18763114fdb4SDavid Greenman txp->cb_status = 0; 18773114fdb4SDavid Greenman txp->cb_command = FXP_CB_COMMAND_NOP | FXP_CB_COMMAND_S | FXP_CB_COMMAND_I; 18783114fdb4SDavid Greenman /* 18793114fdb4SDavid Greenman * Advance the end of list forward. 18803114fdb4SDavid Greenman */ 18813114fdb4SDavid Greenman sc->cbl_last->cb_command &= ~FXP_CB_COMMAND_S; 18823114fdb4SDavid Greenman sc->cbl_last = txp; 18833114fdb4SDavid Greenman sc->tx_queued++; 18843114fdb4SDavid Greenman /* 18853114fdb4SDavid Greenman * Issue a resume in case the CU has just suspended. 18863114fdb4SDavid Greenman */ 18873114fdb4SDavid Greenman fxp_scb_wait(sc); 18883114fdb4SDavid Greenman CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_RESUME); 18893114fdb4SDavid Greenman /* 18903114fdb4SDavid Greenman * Set a 5 second timer just in case we don't hear from the 18913114fdb4SDavid Greenman * card again. 18923114fdb4SDavid Greenman */ 18933114fdb4SDavid Greenman ifp->if_timer = 5; 18943114fdb4SDavid Greenman 1895397f9dfeSDavid Greenman return; 1896397f9dfeSDavid Greenman } 1897397f9dfeSDavid Greenman sc->need_mcsetup = 0; 1898397f9dfeSDavid Greenman 1899397f9dfeSDavid Greenman /* 1900397f9dfeSDavid Greenman * Initialize multicast setup descriptor. 1901397f9dfeSDavid Greenman */ 1902397f9dfeSDavid Greenman mcsp->next = sc->cbl_base; 1903397f9dfeSDavid Greenman mcsp->mb_head = NULL; 1904397f9dfeSDavid Greenman mcsp->cb_status = 0; 19053114fdb4SDavid Greenman mcsp->cb_command = FXP_CB_COMMAND_MCAS | FXP_CB_COMMAND_S | FXP_CB_COMMAND_I; 1906397f9dfeSDavid Greenman mcsp->link_addr = vtophys(&sc->cbl_base->cb_status); 1907397f9dfeSDavid Greenman 1908397f9dfeSDavid Greenman nmcasts = 0; 1909397f9dfeSDavid Greenman if (!sc->all_mcasts) { 1910397f9dfeSDavid Greenman for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL; 1911397f9dfeSDavid Greenman ifma = ifma->ifma_link.le_next) { 1912397f9dfeSDavid Greenman if (ifma->ifma_addr->sa_family != AF_LINK) 1913397f9dfeSDavid Greenman continue; 1914397f9dfeSDavid Greenman if (nmcasts >= MAXMCADDR) { 1915397f9dfeSDavid Greenman sc->all_mcasts = 1; 1916397f9dfeSDavid Greenman nmcasts = 0; 1917397f9dfeSDavid Greenman break; 1918397f9dfeSDavid Greenman } 1919397f9dfeSDavid Greenman bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr), 1920d244b0e9SPeter Wemm (void *)(uintptr_t)(volatile void *) 1921d244b0e9SPeter Wemm &sc->mcsp->mc_addr[nmcasts][0], 6); 1922397f9dfeSDavid Greenman nmcasts++; 1923397f9dfeSDavid Greenman } 1924397f9dfeSDavid Greenman } 1925397f9dfeSDavid Greenman mcsp->mc_cnt = nmcasts * 6; 1926397f9dfeSDavid Greenman sc->cbl_first = sc->cbl_last = (struct fxp_cb_tx *) mcsp; 1927397f9dfeSDavid Greenman sc->tx_queued = 1; 1928397f9dfeSDavid Greenman 1929397f9dfeSDavid Greenman /* 1930397f9dfeSDavid Greenman * Wait until command unit is not active. This should never 1931397f9dfeSDavid Greenman * be the case when nothing is queued, but make sure anyway. 1932397f9dfeSDavid Greenman */ 19337dced78aSDavid Greenman count = 100; 1934397f9dfeSDavid Greenman while ((CSR_READ_1(sc, FXP_CSR_SCB_RUSCUS) >> 6) == 19357dced78aSDavid Greenman FXP_SCB_CUS_ACTIVE && --count) 19367dced78aSDavid Greenman DELAY(10); 19377dced78aSDavid Greenman if (count == 0) { 193894927790SDavid Greenman printf("fxp%d: command queue timeout\n", FXP_UNIT(sc)); 19397dced78aSDavid Greenman return; 19407dced78aSDavid Greenman } 1941397f9dfeSDavid Greenman 1942397f9dfeSDavid Greenman /* 1943397f9dfeSDavid Greenman * Start the multicast setup command. 1944397f9dfeSDavid Greenman */ 1945397f9dfeSDavid Greenman fxp_scb_wait(sc); 1946397f9dfeSDavid Greenman CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, vtophys(&mcsp->cb_status)); 1947397f9dfeSDavid Greenman CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START); 1948397f9dfeSDavid Greenman 19493114fdb4SDavid Greenman ifp->if_timer = 2; 1950397f9dfeSDavid Greenman return; 1951397f9dfeSDavid Greenman } 1952