1 1.96 thorpej /* $NetBSD: if_xi.c,v 1.96 2022/09/25 21:53:54 thorpej Exp $ */ 2 1.1 gmcgarry /* OpenBSD: if_xe.c,v 1.9 1999/09/16 11:28:42 niklas Exp */ 3 1.5 thorpej 4 1.5 thorpej /* 5 1.39 mycroft * Copyright (c) 2004 Charles M. Hannum. All rights reserved. 6 1.39 mycroft * 7 1.39 mycroft * Redistribution and use in source and binary forms, with or without 8 1.39 mycroft * modification, are permitted provided that the following conditions 9 1.39 mycroft * are met: 10 1.39 mycroft * 1. Redistributions of source code must retain the above copyright 11 1.39 mycroft * notice, this list of conditions and the following disclaimer. 12 1.39 mycroft * 2. Redistributions in binary form must reproduce the above copyright 13 1.39 mycroft * notice, this list of conditions and the following disclaimer in the 14 1.39 mycroft * documentation and/or other materials provided with the distribution. 15 1.39 mycroft * 3. All advertising materials mentioning features or use of this software 16 1.39 mycroft * must display the following acknowledgement: 17 1.39 mycroft * This product includes software developed by Charles M. Hannum. 18 1.39 mycroft * 4. The name of the author may not be used to endorse or promote products 19 1.39 mycroft * derived from this software without specific prior written permission. 20 1.5 thorpej */ 21 1.1 gmcgarry 22 1.1 gmcgarry /* 23 1.1 gmcgarry * Copyright (c) 1999 Niklas Hallqvist, Brandon Creighton, Job de Haas 24 1.1 gmcgarry * All rights reserved. 25 1.1 gmcgarry * 26 1.1 gmcgarry * Redistribution and use in source and binary forms, with or without 27 1.1 gmcgarry * modification, are permitted provided that the following conditions 28 1.1 gmcgarry * are met: 29 1.1 gmcgarry * 1. Redistributions of source code must retain the above copyright 30 1.1 gmcgarry * notice, this list of conditions and the following disclaimer. 31 1.1 gmcgarry * 2. Redistributions in binary form must reproduce the above copyright 32 1.1 gmcgarry * notice, this list of conditions and the following disclaimer in the 33 1.1 gmcgarry * documentation and/or other materials provided with the distribution. 34 1.1 gmcgarry * 3. All advertising materials mentioning features or use of this software 35 1.1 gmcgarry * must display the following acknowledgement: 36 1.1 gmcgarry * This product includes software developed by Niklas Hallqvist, 37 1.1 gmcgarry * Brandon Creighton and Job de Haas. 38 1.1 gmcgarry * 4. The name of the author may not be used to endorse or promote products 39 1.1 gmcgarry * derived from this software without specific prior written permission 40 1.1 gmcgarry * 41 1.1 gmcgarry * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 42 1.1 gmcgarry * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 43 1.1 gmcgarry * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 44 1.1 gmcgarry * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 45 1.1 gmcgarry * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 46 1.1 gmcgarry * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 47 1.1 gmcgarry * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 48 1.1 gmcgarry * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 49 1.1 gmcgarry * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 50 1.1 gmcgarry * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 51 1.1 gmcgarry */ 52 1.1 gmcgarry 53 1.1 gmcgarry /* 54 1.1 gmcgarry * A driver for Xircom CreditCard PCMCIA Ethernet adapters. 55 1.1 gmcgarry */ 56 1.1 gmcgarry 57 1.18 lukem #include <sys/cdefs.h> 58 1.96 thorpej __KERNEL_RCSID(0, "$NetBSD: if_xi.c,v 1.96 2022/09/25 21:53:54 thorpej Exp $"); 59 1.1 gmcgarry 60 1.1 gmcgarry #include "opt_inet.h" 61 1.1 gmcgarry 62 1.1 gmcgarry #include <sys/param.h> 63 1.1 gmcgarry #include <sys/systm.h> 64 1.1 gmcgarry #include <sys/device.h> 65 1.1 gmcgarry #include <sys/ioctl.h> 66 1.1 gmcgarry #include <sys/mbuf.h> 67 1.1 gmcgarry #include <sys/socket.h> 68 1.47 mycroft #include <sys/kernel.h> 69 1.47 mycroft #include <sys/proc.h> 70 1.1 gmcgarry 71 1.1 gmcgarry #include <net/if.h> 72 1.1 gmcgarry #include <net/if_dl.h> 73 1.1 gmcgarry #include <net/if_media.h> 74 1.1 gmcgarry #include <net/if_types.h> 75 1.1 gmcgarry #include <net/if_ether.h> 76 1.81 msaitoh #include <net/bpf.h> 77 1.1 gmcgarry 78 1.1 gmcgarry #ifdef INET 79 1.1 gmcgarry #include <netinet/in.h> 80 1.1 gmcgarry #include <netinet/in_systm.h> 81 1.1 gmcgarry #include <netinet/in_var.h> 82 1.1 gmcgarry #include <netinet/ip.h> 83 1.1 gmcgarry #include <netinet/if_inarp.h> 84 1.1 gmcgarry #endif 85 1.1 gmcgarry 86 1.1 gmcgarry /* 87 1.1 gmcgarry * Maximum number of bytes to read per interrupt. Linux recommends 88 1.1 gmcgarry * somewhere between 2000-22000. 89 1.1 gmcgarry * XXX This is currently a hard maximum. 90 1.1 gmcgarry */ 91 1.1 gmcgarry #define MAX_BYTES_INTR 12000 92 1.1 gmcgarry 93 1.1 gmcgarry #include <dev/mii/mii.h> 94 1.1 gmcgarry #include <dev/mii/miivar.h> 95 1.1 gmcgarry 96 1.1 gmcgarry #include <dev/pcmcia/pcmciareg.h> 97 1.1 gmcgarry #include <dev/pcmcia/pcmciavar.h> 98 1.1 gmcgarry #include <dev/pcmcia/pcmciadevs.h> 99 1.1 gmcgarry 100 1.1 gmcgarry #include <dev/pcmcia/if_xireg.h> 101 1.39 mycroft #include <dev/pcmcia/if_xivar.h> 102 1.1 gmcgarry 103 1.1 gmcgarry #ifdef __GNUC__ 104 1.54 perry #define INLINE inline 105 1.1 gmcgarry #else 106 1.1 gmcgarry #define INLINE 107 1.1 gmcgarry #endif /* __GNUC__ */ 108 1.1 gmcgarry 109 1.39 mycroft #define XIDEBUG 110 1.40 mycroft #define XIDEBUG_VALUE 0 111 1.35 mycroft 112 1.1 gmcgarry #ifdef XIDEBUG 113 1.1 gmcgarry #define DPRINTF(cat, x) if (xidebug & (cat)) printf x 114 1.1 gmcgarry 115 1.39 mycroft #define XID_CONFIG 0x01 116 1.39 mycroft #define XID_MII 0x02 117 1.39 mycroft #define XID_INTR 0x04 118 1.39 mycroft #define XID_FIFO 0x08 119 1.39 mycroft #define XID_MCAST 0x10 120 1.1 gmcgarry 121 1.1 gmcgarry #ifdef XIDEBUG_VALUE 122 1.1 gmcgarry int xidebug = XIDEBUG_VALUE; 123 1.1 gmcgarry #else 124 1.1 gmcgarry int xidebug = 0; 125 1.1 gmcgarry #endif 126 1.1 gmcgarry #else 127 1.1 gmcgarry #define DPRINTF(cat, x) (void)0 128 1.1 gmcgarry #endif 129 1.1 gmcgarry 130 1.92 maxv #define STATIC static 131 1.1 gmcgarry 132 1.51 perry STATIC int xi_enable(struct xi_softc *); 133 1.51 perry STATIC void xi_disable(struct xi_softc *); 134 1.51 perry STATIC void xi_cycle_power(struct xi_softc *); 135 1.88 msaitoh STATIC int xi_ether_ioctl(struct ifnet *, u_long, void *); 136 1.51 perry STATIC void xi_full_reset(struct xi_softc *); 137 1.51 perry STATIC void xi_init(struct xi_softc *); 138 1.60 christos STATIC int xi_ioctl(struct ifnet *, u_long, void *); 139 1.85 msaitoh STATIC int xi_mdi_read(device_t, int, int, uint16_t *); 140 1.85 msaitoh STATIC int xi_mdi_write(device_t, int, int, uint16_t); 141 1.51 perry STATIC int xi_mediachange(struct ifnet *); 142 1.84 msaitoh STATIC uint16_t xi_get(struct xi_softc *); 143 1.51 perry STATIC void xi_reset(struct xi_softc *); 144 1.51 perry STATIC void xi_set_address(struct xi_softc *); 145 1.51 perry STATIC void xi_start(struct ifnet *); 146 1.73 matt STATIC void xi_statchg(struct ifnet *); 147 1.51 perry STATIC void xi_stop(struct xi_softc *); 148 1.51 perry STATIC void xi_watchdog(struct ifnet *); 149 1.3 gmcgarry 150 1.39 mycroft void 151 1.84 msaitoh xi_attach(struct xi_softc *sc, uint8_t *myea) 152 1.1 gmcgarry { 153 1.1 gmcgarry struct ifnet *ifp = &sc->sc_ethercom.ec_if; 154 1.88 msaitoh struct mii_data * const mii = &sc->sc_mii; 155 1.85 msaitoh #ifdef XIDEBUG 156 1.85 msaitoh uint16_t bmsr; 157 1.85 msaitoh #endif 158 1.39 mycroft #if 0 159 1.1 gmcgarry /* 160 1.11 gmcgarry * Configuration as advised by DINGO documentation. 161 1.1 gmcgarry * Dingo has some extra configuration registers in the CCR space. 162 1.1 gmcgarry */ 163 1.39 mycroft if (sc->sc_chipset >= XI_CHIPSET_DINGO) { 164 1.1 gmcgarry struct pcmcia_mem_handle pcmh; 165 1.1 gmcgarry int ccr_window; 166 1.30 martin bus_size_t ccr_offset; 167 1.1 gmcgarry 168 1.11 gmcgarry /* get access to the DINGO CCR space */ 169 1.1 gmcgarry if (pcmcia_mem_alloc(psc->sc_pf, PCMCIA_CCR_SIZE_DINGO, 170 1.1 gmcgarry &pcmh)) { 171 1.2 gmcgarry DPRINTF(XID_CONFIG, ("xi: bad mem alloc\n")); 172 1.1 gmcgarry goto fail; 173 1.1 gmcgarry } 174 1.1 gmcgarry if (pcmcia_mem_map(psc->sc_pf, PCMCIA_MEM_ATTR, 175 1.1 gmcgarry psc->sc_pf->ccr_base, PCMCIA_CCR_SIZE_DINGO, 176 1.1 gmcgarry &pcmh, &ccr_offset, &ccr_window)) { 177 1.2 gmcgarry DPRINTF(XID_CONFIG, ("xi: bad mem map\n")); 178 1.1 gmcgarry pcmcia_mem_free(psc->sc_pf, &pcmh); 179 1.1 gmcgarry goto fail; 180 1.1 gmcgarry } 181 1.1 gmcgarry 182 1.11 gmcgarry /* enable the second function - usually modem */ 183 1.1 gmcgarry bus_space_write_1(pcmh.memt, pcmh.memh, 184 1.1 gmcgarry ccr_offset + PCMCIA_CCR_DCOR0, PCMCIA_CCR_DCOR0_SFINT); 185 1.1 gmcgarry bus_space_write_1(pcmh.memt, pcmh.memh, 186 1.1 gmcgarry ccr_offset + PCMCIA_CCR_DCOR1, 187 1.1 gmcgarry PCMCIA_CCR_DCOR1_FORCE_LEVIREQ | PCMCIA_CCR_DCOR1_D6); 188 1.1 gmcgarry bus_space_write_1(pcmh.memt, pcmh.memh, 189 1.1 gmcgarry ccr_offset + PCMCIA_CCR_DCOR2, 0); 190 1.1 gmcgarry bus_space_write_1(pcmh.memt, pcmh.memh, 191 1.1 gmcgarry ccr_offset + PCMCIA_CCR_DCOR3, 0); 192 1.1 gmcgarry bus_space_write_1(pcmh.memt, pcmh.memh, 193 1.1 gmcgarry ccr_offset + PCMCIA_CCR_DCOR4, 0); 194 1.1 gmcgarry 195 1.1 gmcgarry /* We don't need them anymore and can free them (I think). */ 196 1.1 gmcgarry pcmcia_mem_unmap(psc->sc_pf, ccr_window); 197 1.1 gmcgarry pcmcia_mem_free(psc->sc_pf, &pcmh); 198 1.1 gmcgarry } 199 1.39 mycroft #endif 200 1.11 gmcgarry 201 1.39 mycroft /* Reset and initialize the card. */ 202 1.39 mycroft xi_full_reset(sc); 203 1.1 gmcgarry 204 1.88 msaitoh device_printf(sc->sc_dev, "MAC address %s\n", ether_sprintf(myea)); 205 1.1 gmcgarry 206 1.1 gmcgarry ifp = &sc->sc_ethercom.ec_if; 207 1.39 mycroft /* Initialize the ifnet structure. */ 208 1.69 dyoung strlcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ); 209 1.1 gmcgarry ifp->if_softc = sc; 210 1.1 gmcgarry ifp->if_start = xi_start; 211 1.1 gmcgarry ifp->if_ioctl = xi_ioctl; 212 1.1 gmcgarry ifp->if_watchdog = xi_watchdog; 213 1.86 msaitoh ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 214 1.7 thorpej IFQ_SET_READY(&ifp->if_snd); 215 1.1 gmcgarry 216 1.39 mycroft /* 802.1q capability */ 217 1.39 mycroft sc->sc_ethercom.ec_capabilities |= ETHERCAP_VLAN_MTU; 218 1.39 mycroft 219 1.39 mycroft /* Attach the interface. */ 220 1.39 mycroft if_attach(ifp); 221 1.79 ozaki if_deferred_start_init(ifp, NULL); 222 1.39 mycroft ether_ifattach(ifp, myea); 223 1.1 gmcgarry 224 1.1 gmcgarry /* 225 1.1 gmcgarry * Initialize our media structures and probe the MII. 226 1.1 gmcgarry */ 227 1.88 msaitoh mii->mii_ifp = ifp; 228 1.88 msaitoh mii->mii_readreg = xi_mdi_read; 229 1.88 msaitoh mii->mii_writereg = xi_mdi_write; 230 1.88 msaitoh mii->mii_statchg = xi_statchg; 231 1.88 msaitoh sc->sc_ethercom.ec_mii = mii; 232 1.88 msaitoh ifmedia_init(&mii->mii_media, 0, xi_mediachange, ether_mediastatus); 233 1.85 msaitoh #ifdef XIDEBUG 234 1.85 msaitoh xi_mdi_read(sc->sc_dev, 0, 1, &bmsr); 235 1.85 msaitoh DPRINTF(XID_MII | XID_CONFIG, ("xi: bmsr %x\n", bmsr)); 236 1.85 msaitoh #endif 237 1.39 mycroft 238 1.88 msaitoh mii_attach(sc->sc_dev, mii, 0xffffffff, MII_PHY_ANY, 239 1.1 gmcgarry MII_OFFSET_ANY, 0); 240 1.88 msaitoh if (LIST_FIRST(&mii->mii_phys) == NULL) 241 1.88 msaitoh ifmedia_add(&mii->mii_media, IFM_ETHER | IFM_AUTO, 0, NULL); 242 1.88 msaitoh ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_AUTO); 243 1.1 gmcgarry 244 1.72 tls rnd_attach_source(&sc->sc_rnd_source, device_xname(sc->sc_dev), 245 1.74 tls RND_TYPE_NET, RND_FLAG_DEFAULT); 246 1.1 gmcgarry } 247 1.1 gmcgarry 248 1.1 gmcgarry int 249 1.67 cegger xi_detach(device_t self, int flags) 250 1.1 gmcgarry { 251 1.68 dyoung struct xi_softc *sc = device_private(self); 252 1.1 gmcgarry struct ifnet *ifp = &sc->sc_ethercom.ec_if; 253 1.1 gmcgarry 254 1.39 mycroft DPRINTF(XID_CONFIG, ("xi_detach()\n")); 255 1.1 gmcgarry 256 1.42 mycroft xi_disable(sc); 257 1.1 gmcgarry 258 1.39 mycroft rnd_detach_source(&sc->sc_rnd_source); 259 1.1 gmcgarry 260 1.39 mycroft mii_detach(&sc->sc_mii, MII_PHY_ANY, MII_OFFSET_ANY); 261 1.39 mycroft ether_ifdetach(ifp); 262 1.39 mycroft if_detach(ifp); 263 1.94 thorpej ifmedia_fini(&sc->sc_mii.mii_media); 264 1.1 gmcgarry 265 1.1 gmcgarry return 0; 266 1.1 gmcgarry } 267 1.1 gmcgarry 268 1.1 gmcgarry int 269 1.66 dsl xi_intr(void *arg) 270 1.1 gmcgarry { 271 1.1 gmcgarry struct xi_softc *sc = arg; 272 1.1 gmcgarry struct ifnet *ifp = &sc->sc_ethercom.ec_if; 273 1.84 msaitoh uint8_t esr, rsr, isr, rx_status; 274 1.84 msaitoh uint16_t tx_status, recvcount = 0, tempint; 275 1.1 gmcgarry 276 1.2 gmcgarry DPRINTF(XID_CONFIG, ("xi_intr()\n")); 277 1.1 gmcgarry 278 1.69 dyoung if (sc->sc_enabled == 0 || !device_is_active(sc->sc_dev)) 279 1.1 gmcgarry return (0); 280 1.1 gmcgarry 281 1.1 gmcgarry ifp->if_timer = 0; /* turn watchdog timer off */ 282 1.1 gmcgarry 283 1.45 mycroft PAGE(sc, 0); 284 1.39 mycroft if (sc->sc_chipset >= XI_CHIPSET_MOHAWK) { 285 1.1 gmcgarry /* Disable interrupt (Linux does it). */ 286 1.48 mycroft bus_space_write_1(sc->sc_bst, sc->sc_bsh, CR, 0); 287 1.1 gmcgarry } 288 1.1 gmcgarry 289 1.48 mycroft esr = bus_space_read_1(sc->sc_bst, sc->sc_bsh, ESR); 290 1.48 mycroft isr = bus_space_read_1(sc->sc_bst, sc->sc_bsh, ISR0); 291 1.48 mycroft rsr = bus_space_read_1(sc->sc_bst, sc->sc_bsh, RSR); 292 1.52 perry 293 1.1 gmcgarry /* Check to see if card has been ejected. */ 294 1.1 gmcgarry if (isr == 0xff) { 295 1.1 gmcgarry #ifdef DIAGNOSTIC 296 1.69 dyoung printf("%s: interrupt for dead card\n", 297 1.69 dyoung device_xname(sc->sc_dev)); 298 1.1 gmcgarry #endif 299 1.1 gmcgarry goto end; 300 1.1 gmcgarry } 301 1.39 mycroft DPRINTF(XID_INTR, ("xi: isr=%02x\n", isr)); 302 1.1 gmcgarry 303 1.39 mycroft PAGE(sc, 0x40); 304 1.1 gmcgarry rx_status = 305 1.48 mycroft bus_space_read_1(sc->sc_bst, sc->sc_bsh, RXST0); 306 1.48 mycroft bus_space_write_1(sc->sc_bst, sc->sc_bsh, RXST0, ~rx_status & 0xff); 307 1.1 gmcgarry tx_status = 308 1.48 mycroft bus_space_read_1(sc->sc_bst, sc->sc_bsh, TXST0); 309 1.23 martin tx_status |= 310 1.48 mycroft bus_space_read_1(sc->sc_bst, sc->sc_bsh, TXST1) << 8; 311 1.48 mycroft bus_space_write_1(sc->sc_bst, sc->sc_bsh, TXST0, 0); 312 1.48 mycroft bus_space_write_1(sc->sc_bst, sc->sc_bsh, TXST1, 0); 313 1.39 mycroft DPRINTF(XID_INTR, ("xi: rx_status=%02x tx_status=%04x\n", rx_status, 314 1.39 mycroft tx_status)); 315 1.1 gmcgarry 316 1.1 gmcgarry PAGE(sc, 0); 317 1.1 gmcgarry while (esr & FULL_PKT_RCV) { 318 1.1 gmcgarry if (!(rsr & RSR_RX_OK)) 319 1.1 gmcgarry break; 320 1.1 gmcgarry 321 1.1 gmcgarry /* Compare bytes read this interrupt to hard maximum. */ 322 1.1 gmcgarry if (recvcount > MAX_BYTES_INTR) { 323 1.1 gmcgarry DPRINTF(XID_INTR, 324 1.2 gmcgarry ("xi: too many bytes this interrupt\n")); 325 1.94 thorpej if_statinc(ifp, if_iqdrops); 326 1.1 gmcgarry /* Drop packet. */ 327 1.48 mycroft bus_space_write_2(sc->sc_bst, sc->sc_bsh, DO0, 328 1.48 mycroft DO_SKIP_RX_PKT); 329 1.1 gmcgarry } 330 1.1 gmcgarry tempint = xi_get(sc); /* XXX doesn't check the error! */ 331 1.1 gmcgarry recvcount += tempint; 332 1.48 mycroft esr = bus_space_read_1(sc->sc_bst, sc->sc_bsh, ESR); 333 1.48 mycroft rsr = bus_space_read_1(sc->sc_bst, sc->sc_bsh, RSR); 334 1.1 gmcgarry } 335 1.52 perry 336 1.1 gmcgarry /* Packet too long? */ 337 1.1 gmcgarry if (rsr & RSR_TOO_LONG) { 338 1.94 thorpej if_statinc(ifp, if_ierrors); 339 1.2 gmcgarry DPRINTF(XID_INTR, ("xi: packet too long\n")); 340 1.1 gmcgarry } 341 1.1 gmcgarry 342 1.1 gmcgarry /* CRC error? */ 343 1.1 gmcgarry if (rsr & RSR_CRCERR) { 344 1.94 thorpej if_statinc(ifp, if_ierrors); 345 1.2 gmcgarry DPRINTF(XID_INTR, ("xi: CRC error detected\n")); 346 1.1 gmcgarry } 347 1.1 gmcgarry 348 1.1 gmcgarry /* Alignment error? */ 349 1.1 gmcgarry if (rsr & RSR_ALIGNERR) { 350 1.94 thorpej if_statinc(ifp, if_ierrors); 351 1.2 gmcgarry DPRINTF(XID_INTR, ("xi: alignment error detected\n")); 352 1.1 gmcgarry } 353 1.1 gmcgarry 354 1.1 gmcgarry /* Check for rx overrun. */ 355 1.1 gmcgarry if (rx_status & RX_OVERRUN) { 356 1.94 thorpej if_statinc(ifp, if_ierrors); 357 1.48 mycroft bus_space_write_1(sc->sc_bst, sc->sc_bsh, CR, CLR_RX_OVERRUN); 358 1.2 gmcgarry DPRINTF(XID_INTR, ("xi: overrun cleared\n")); 359 1.1 gmcgarry } 360 1.52 perry 361 1.1 gmcgarry /* Try to start more packets transmitting. */ 362 1.79 ozaki if_schedule_deferred_start(ifp); 363 1.1 gmcgarry 364 1.1 gmcgarry /* Detected excessive collisions? */ 365 1.94 thorpej if ((tx_status & EXCESSIVE_COLL) /* XXX && ifp->if_opackets > 0 */) { 366 1.2 gmcgarry DPRINTF(XID_INTR, ("xi: excessive collisions\n")); 367 1.48 mycroft bus_space_write_1(sc->sc_bst, sc->sc_bsh, CR, RESTART_TX); 368 1.94 thorpej if_statinc(ifp, if_oerrors); 369 1.1 gmcgarry } 370 1.52 perry 371 1.94 thorpej if ((tx_status & TX_ABORT) /* && XXX ifp->if_opackets > 0 */) 372 1.94 thorpej if_statinc(ifp, if_oerrors); 373 1.1 gmcgarry 374 1.33 mycroft /* have handled the interrupt */ 375 1.52 perry rnd_add_uint32(&sc->sc_rnd_source, tx_status); 376 1.33 mycroft 377 1.1 gmcgarry end: 378 1.1 gmcgarry /* Reenable interrupts. */ 379 1.45 mycroft PAGE(sc, 0); 380 1.48 mycroft bus_space_write_1(sc->sc_bst, sc->sc_bsh, CR, ENABLE_INT); 381 1.11 gmcgarry 382 1.1 gmcgarry return (1); 383 1.1 gmcgarry } 384 1.1 gmcgarry 385 1.1 gmcgarry /* 386 1.1 gmcgarry * Pull a packet from the card into an mbuf chain. 387 1.1 gmcgarry */ 388 1.84 msaitoh STATIC uint16_t 389 1.66 dsl xi_get(struct xi_softc *sc) 390 1.1 gmcgarry { 391 1.1 gmcgarry struct ifnet *ifp = &sc->sc_ethercom.ec_if; 392 1.1 gmcgarry struct mbuf *top, **mp, *m; 393 1.84 msaitoh uint16_t pktlen, len, recvcount = 0; 394 1.84 msaitoh uint8_t *data; 395 1.52 perry 396 1.2 gmcgarry DPRINTF(XID_CONFIG, ("xi_get()\n")); 397 1.1 gmcgarry 398 1.1 gmcgarry PAGE(sc, 0); 399 1.1 gmcgarry pktlen = 400 1.48 mycroft bus_space_read_2(sc->sc_bst, sc->sc_bsh, RBC0) & RBC_COUNT_MASK; 401 1.1 gmcgarry 402 1.1 gmcgarry DPRINTF(XID_CONFIG, ("xi_get: pktlen=%d\n", pktlen)); 403 1.1 gmcgarry 404 1.1 gmcgarry if (pktlen == 0) { 405 1.1 gmcgarry /* 406 1.1 gmcgarry * XXX At least one CE2 sets RBC0 == 0 occasionally, and only 407 1.1 gmcgarry * when MPE is set. It is not known why. 408 1.1 gmcgarry */ 409 1.1 gmcgarry return (0); 410 1.1 gmcgarry } 411 1.1 gmcgarry 412 1.1 gmcgarry /* XXX should this be incremented now ? */ 413 1.1 gmcgarry recvcount += pktlen; 414 1.1 gmcgarry 415 1.1 gmcgarry MGETHDR(m, M_DONTWAIT, MT_DATA); 416 1.56 christos if (m == NULL) 417 1.1 gmcgarry return (recvcount); 418 1.77 ozaki m_set_rcvif(m, ifp); 419 1.1 gmcgarry m->m_pkthdr.len = pktlen; 420 1.1 gmcgarry len = MHLEN; 421 1.56 christos top = NULL; 422 1.1 gmcgarry mp = ⊤ 423 1.52 perry 424 1.1 gmcgarry while (pktlen > 0) { 425 1.1 gmcgarry if (top) { 426 1.1 gmcgarry MGET(m, M_DONTWAIT, MT_DATA); 427 1.56 christos if (m == NULL) { 428 1.1 gmcgarry m_freem(top); 429 1.1 gmcgarry return (recvcount); 430 1.1 gmcgarry } 431 1.1 gmcgarry len = MLEN; 432 1.1 gmcgarry } 433 1.1 gmcgarry if (pktlen >= MINCLSIZE) { 434 1.1 gmcgarry MCLGET(m, M_DONTWAIT); 435 1.1 gmcgarry if (!(m->m_flags & M_EXT)) { 436 1.1 gmcgarry m_freem(m); 437 1.1 gmcgarry m_freem(top); 438 1.1 gmcgarry return (recvcount); 439 1.1 gmcgarry } 440 1.1 gmcgarry len = MCLBYTES; 441 1.1 gmcgarry } 442 1.56 christos if (top == NULL) { 443 1.60 christos char *newdata = (char *)ALIGN(m->m_data + 444 1.1 gmcgarry sizeof(struct ether_header)) - 445 1.1 gmcgarry sizeof(struct ether_header); 446 1.1 gmcgarry len -= newdata - m->m_data; 447 1.1 gmcgarry m->m_data = newdata; 448 1.1 gmcgarry } 449 1.83 riastrad len = uimin(pktlen, len); 450 1.84 msaitoh data = mtod(m, uint8_t *); 451 1.1 gmcgarry if (len > 1) { 452 1.89 msaitoh len &= ~1; 453 1.48 mycroft bus_space_read_multi_2(sc->sc_bst, sc->sc_bsh, EDP, 454 1.84 msaitoh (uint16_t *)data, len>>1); 455 1.1 gmcgarry } else 456 1.48 mycroft *data = bus_space_read_1(sc->sc_bst, sc->sc_bsh, EDP); 457 1.1 gmcgarry m->m_len = len; 458 1.1 gmcgarry pktlen -= len; 459 1.1 gmcgarry *mp = m; 460 1.1 gmcgarry mp = &m->m_next; 461 1.1 gmcgarry } 462 1.1 gmcgarry 463 1.1 gmcgarry /* Skip Rx packet. */ 464 1.48 mycroft bus_space_write_2(sc->sc_bst, sc->sc_bsh, DO0, DO_SKIP_RX_PKT); 465 1.50 thorpej 466 1.56 christos if (top == NULL) 467 1.56 christos return recvcount; 468 1.56 christos 469 1.50 thorpej /* Trim the CRC off the end of the packet. */ 470 1.50 thorpej m_adj(top, -ETHER_CRC_LEN); 471 1.50 thorpej 472 1.76 ozaki if_percpuq_enqueue(ifp->if_percpuq, top); 473 1.1 gmcgarry return (recvcount); 474 1.1 gmcgarry } 475 1.1 gmcgarry 476 1.1 gmcgarry /* 477 1.1 gmcgarry * Serial management for the MII. 478 1.1 gmcgarry * The DELAY's below stem from the fact that the maximum frequency 479 1.1 gmcgarry * acceptable on the MDC pin is 2.5 MHz and fast processors can easily 480 1.1 gmcgarry * go much faster than that. 481 1.1 gmcgarry */ 482 1.1 gmcgarry 483 1.1 gmcgarry /* Let the MII serial management be idle for one period. */ 484 1.51 perry static INLINE void xi_mdi_idle(struct xi_softc *); 485 1.1 gmcgarry static INLINE void 486 1.66 dsl xi_mdi_idle(struct xi_softc *sc) 487 1.1 gmcgarry { 488 1.1 gmcgarry bus_space_tag_t bst = sc->sc_bst; 489 1.1 gmcgarry bus_space_handle_t bsh = sc->sc_bsh; 490 1.1 gmcgarry 491 1.1 gmcgarry /* Drive MDC low... */ 492 1.48 mycroft bus_space_write_1(bst, bsh, GP2, MDC_LOW); 493 1.1 gmcgarry DELAY(1); 494 1.1 gmcgarry 495 1.1 gmcgarry /* and high again. */ 496 1.48 mycroft bus_space_write_1(bst, bsh, GP2, MDC_HIGH); 497 1.1 gmcgarry DELAY(1); 498 1.1 gmcgarry } 499 1.1 gmcgarry 500 1.1 gmcgarry /* Pulse out one bit of data. */ 501 1.51 perry static INLINE void xi_mdi_pulse(struct xi_softc *, int); 502 1.1 gmcgarry static INLINE void 503 1.66 dsl xi_mdi_pulse(struct xi_softc *sc, int data) 504 1.1 gmcgarry { 505 1.1 gmcgarry bus_space_tag_t bst = sc->sc_bst; 506 1.1 gmcgarry bus_space_handle_t bsh = sc->sc_bsh; 507 1.84 msaitoh uint8_t bit = data ? MDIO_HIGH : MDIO_LOW; 508 1.1 gmcgarry 509 1.1 gmcgarry /* First latch the data bit MDIO with clock bit MDC low...*/ 510 1.48 mycroft bus_space_write_1(bst, bsh, GP2, bit | MDC_LOW); 511 1.1 gmcgarry DELAY(1); 512 1.1 gmcgarry 513 1.1 gmcgarry /* then raise the clock again, preserving the data bit. */ 514 1.48 mycroft bus_space_write_1(bst, bsh, GP2, bit | MDC_HIGH); 515 1.1 gmcgarry DELAY(1); 516 1.1 gmcgarry } 517 1.1 gmcgarry 518 1.1 gmcgarry /* Probe one bit of data. */ 519 1.51 perry static INLINE int xi_mdi_probe(struct xi_softc *sc); 520 1.1 gmcgarry static INLINE int 521 1.66 dsl xi_mdi_probe(struct xi_softc *sc) 522 1.1 gmcgarry { 523 1.1 gmcgarry bus_space_tag_t bst = sc->sc_bst; 524 1.1 gmcgarry bus_space_handle_t bsh = sc->sc_bsh; 525 1.84 msaitoh uint8_t x; 526 1.1 gmcgarry 527 1.1 gmcgarry /* Pull clock bit MDCK low... */ 528 1.48 mycroft bus_space_write_1(bst, bsh, GP2, MDC_LOW); 529 1.1 gmcgarry DELAY(1); 530 1.1 gmcgarry 531 1.1 gmcgarry /* Read data and drive clock high again. */ 532 1.48 mycroft x = bus_space_read_1(bst, bsh, GP2); 533 1.48 mycroft bus_space_write_1(bst, bsh, GP2, MDC_HIGH); 534 1.1 gmcgarry DELAY(1); 535 1.1 gmcgarry 536 1.39 mycroft return (x & MDIO); 537 1.1 gmcgarry } 538 1.1 gmcgarry 539 1.1 gmcgarry /* Pulse out a sequence of data bits. */ 540 1.84 msaitoh static INLINE void xi_mdi_pulse_bits(struct xi_softc *, uint32_t, int); 541 1.1 gmcgarry static INLINE void 542 1.84 msaitoh xi_mdi_pulse_bits(struct xi_softc *sc, uint32_t data, int len) 543 1.1 gmcgarry { 544 1.84 msaitoh uint32_t mask; 545 1.1 gmcgarry 546 1.1 gmcgarry for (mask = 1 << (len - 1); mask; mask >>= 1) 547 1.1 gmcgarry xi_mdi_pulse(sc, data & mask); 548 1.1 gmcgarry } 549 1.1 gmcgarry 550 1.1 gmcgarry /* Read a PHY register. */ 551 1.39 mycroft STATIC int 552 1.85 msaitoh xi_mdi_read(device_t self, int phy, int reg, uint16_t *val) 553 1.1 gmcgarry { 554 1.68 dyoung struct xi_softc *sc = device_private(self); 555 1.1 gmcgarry int i; 556 1.84 msaitoh uint32_t mask; 557 1.85 msaitoh uint16_t data = 0; 558 1.1 gmcgarry 559 1.1 gmcgarry PAGE(sc, 2); 560 1.1 gmcgarry for (i = 0; i < 32; i++) /* Synchronize. */ 561 1.1 gmcgarry xi_mdi_pulse(sc, 1); 562 1.1 gmcgarry xi_mdi_pulse_bits(sc, 0x06, 4); /* Start + Read opcode */ 563 1.1 gmcgarry xi_mdi_pulse_bits(sc, phy, 5); /* PHY address */ 564 1.1 gmcgarry xi_mdi_pulse_bits(sc, reg, 5); /* PHY register */ 565 1.1 gmcgarry xi_mdi_idle(sc); /* Turn around. */ 566 1.1 gmcgarry xi_mdi_probe(sc); /* Drop initial zero bit. */ 567 1.1 gmcgarry 568 1.1 gmcgarry for (mask = 1 << 15; mask; mask >>= 1) { 569 1.1 gmcgarry if (xi_mdi_probe(sc)) 570 1.1 gmcgarry data |= mask; 571 1.1 gmcgarry } 572 1.1 gmcgarry xi_mdi_idle(sc); 573 1.1 gmcgarry 574 1.1 gmcgarry DPRINTF(XID_MII, 575 1.85 msaitoh ("xi_mdi_read: phy %d reg %d -> %04hx\n", phy, reg, data)); 576 1.1 gmcgarry 577 1.85 msaitoh *val = data; 578 1.85 msaitoh return 0; 579 1.1 gmcgarry } 580 1.1 gmcgarry 581 1.1 gmcgarry /* Write a PHY register. */ 582 1.85 msaitoh STATIC int 583 1.85 msaitoh xi_mdi_write(device_t self, int phy, int reg, uint16_t val) 584 1.1 gmcgarry { 585 1.68 dyoung struct xi_softc *sc = device_private(self); 586 1.1 gmcgarry int i; 587 1.1 gmcgarry 588 1.1 gmcgarry PAGE(sc, 2); 589 1.1 gmcgarry for (i = 0; i < 32; i++) /* Synchronize. */ 590 1.1 gmcgarry xi_mdi_pulse(sc, 1); 591 1.1 gmcgarry xi_mdi_pulse_bits(sc, 0x05, 4); /* Start + Write opcode */ 592 1.1 gmcgarry xi_mdi_pulse_bits(sc, phy, 5); /* PHY address */ 593 1.1 gmcgarry xi_mdi_pulse_bits(sc, reg, 5); /* PHY register */ 594 1.1 gmcgarry xi_mdi_pulse_bits(sc, 0x02, 2); /* Turn around. */ 595 1.85 msaitoh xi_mdi_pulse_bits(sc, val, 16); /* Write the data */ 596 1.1 gmcgarry xi_mdi_idle(sc); /* Idle away. */ 597 1.1 gmcgarry 598 1.1 gmcgarry DPRINTF(XID_MII, 599 1.85 msaitoh ("xi_mdi_write: phy %d reg %d val %04hx\n", phy, reg, val)); 600 1.85 msaitoh 601 1.85 msaitoh return 0; 602 1.1 gmcgarry } 603 1.1 gmcgarry 604 1.39 mycroft STATIC void 605 1.73 matt xi_statchg(struct ifnet *ifp) 606 1.1 gmcgarry { 607 1.1 gmcgarry /* XXX Update ifp->if_baudrate */ 608 1.1 gmcgarry } 609 1.1 gmcgarry 610 1.1 gmcgarry /* 611 1.1 gmcgarry * Change media according to request. 612 1.1 gmcgarry */ 613 1.39 mycroft STATIC int 614 1.66 dsl xi_mediachange(struct ifnet *ifp) 615 1.1 gmcgarry { 616 1.42 mycroft int s; 617 1.42 mycroft 618 1.2 gmcgarry DPRINTF(XID_CONFIG, ("xi_mediachange()\n")); 619 1.1 gmcgarry 620 1.42 mycroft if (ifp->if_flags & IFF_UP) { 621 1.42 mycroft s = splnet(); 622 1.1 gmcgarry xi_init(ifp->if_softc); 623 1.42 mycroft splx(s); 624 1.42 mycroft } 625 1.1 gmcgarry return (0); 626 1.1 gmcgarry } 627 1.1 gmcgarry 628 1.39 mycroft STATIC void 629 1.66 dsl xi_reset(struct xi_softc *sc) 630 1.1 gmcgarry { 631 1.1 gmcgarry int s; 632 1.1 gmcgarry 633 1.2 gmcgarry DPRINTF(XID_CONFIG, ("xi_reset()\n")); 634 1.1 gmcgarry 635 1.1 gmcgarry s = splnet(); 636 1.1 gmcgarry xi_stop(sc); 637 1.1 gmcgarry xi_init(sc); 638 1.1 gmcgarry splx(s); 639 1.1 gmcgarry } 640 1.1 gmcgarry 641 1.39 mycroft STATIC void 642 1.66 dsl xi_watchdog(struct ifnet *ifp) 643 1.1 gmcgarry { 644 1.1 gmcgarry struct xi_softc *sc = ifp->if_softc; 645 1.1 gmcgarry 646 1.69 dyoung printf("%s: device timeout\n", device_xname(sc->sc_dev)); 647 1.94 thorpej if_statinc(ifp, if_oerrors); 648 1.1 gmcgarry 649 1.1 gmcgarry xi_reset(sc); 650 1.1 gmcgarry } 651 1.1 gmcgarry 652 1.39 mycroft STATIC void 653 1.66 dsl xi_stop(register struct xi_softc *sc) 654 1.1 gmcgarry { 655 1.39 mycroft bus_space_tag_t bst = sc->sc_bst; 656 1.39 mycroft bus_space_handle_t bsh = sc->sc_bsh; 657 1.39 mycroft 658 1.2 gmcgarry DPRINTF(XID_CONFIG, ("xi_stop()\n")); 659 1.1 gmcgarry 660 1.44 mycroft PAGE(sc, 0x40); 661 1.48 mycroft bus_space_write_1(bst, bsh, CMD0, DISABLE_RX); 662 1.44 mycroft 663 1.1 gmcgarry /* Disable interrupts. */ 664 1.1 gmcgarry PAGE(sc, 0); 665 1.48 mycroft bus_space_write_1(bst, bsh, CR, 0); 666 1.1 gmcgarry 667 1.1 gmcgarry PAGE(sc, 1); 668 1.48 mycroft bus_space_write_1(bst, bsh, IMR0, 0); 669 1.52 perry 670 1.1 gmcgarry /* Cancel watchdog timer. */ 671 1.1 gmcgarry sc->sc_ethercom.ec_if.if_timer = 0; 672 1.1 gmcgarry } 673 1.1 gmcgarry 674 1.42 mycroft STATIC int 675 1.66 dsl xi_enable(struct xi_softc *sc) 676 1.42 mycroft { 677 1.42 mycroft int error; 678 1.42 mycroft 679 1.42 mycroft if (!sc->sc_enabled) { 680 1.42 mycroft error = (*sc->sc_enable)(sc); 681 1.42 mycroft if (error) 682 1.42 mycroft return (error); 683 1.42 mycroft sc->sc_enabled = 1; 684 1.42 mycroft xi_full_reset(sc); 685 1.42 mycroft } 686 1.42 mycroft return (0); 687 1.42 mycroft } 688 1.42 mycroft 689 1.42 mycroft STATIC void 690 1.66 dsl xi_disable(struct xi_softc *sc) 691 1.42 mycroft { 692 1.42 mycroft 693 1.42 mycroft if (sc->sc_enabled) { 694 1.42 mycroft sc->sc_enabled = 0; 695 1.42 mycroft (*sc->sc_disable)(sc); 696 1.42 mycroft } 697 1.42 mycroft } 698 1.42 mycroft 699 1.39 mycroft STATIC void 700 1.66 dsl xi_init(struct xi_softc *sc) 701 1.1 gmcgarry { 702 1.1 gmcgarry struct ifnet *ifp = &sc->sc_ethercom.ec_if; 703 1.39 mycroft bus_space_tag_t bst = sc->sc_bst; 704 1.39 mycroft bus_space_handle_t bsh = sc->sc_bsh; 705 1.1 gmcgarry 706 1.2 gmcgarry DPRINTF(XID_CONFIG, ("xi_init()\n")); 707 1.1 gmcgarry 708 1.39 mycroft /* Setup the ethernet interrupt mask. */ 709 1.39 mycroft PAGE(sc, 1); 710 1.48 mycroft bus_space_write_1(bst, bsh, IMR0, 711 1.39 mycroft ISR_TX_OFLOW | ISR_PKT_TX | ISR_MAC_INT | /* ISR_RX_EARLY | */ 712 1.39 mycroft ISR_RX_FULL | ISR_RX_PKT_REJ | ISR_FORCED_INT); 713 1.39 mycroft if (sc->sc_chipset < XI_CHIPSET_DINGO) { 714 1.39 mycroft /* XXX What is this? Not for Dingo at least. */ 715 1.39 mycroft /* Unmask TX underrun detection */ 716 1.48 mycroft bus_space_write_1(bst, bsh, IMR1, 1); 717 1.39 mycroft } 718 1.39 mycroft 719 1.39 mycroft /* Enable interrupts. */ 720 1.39 mycroft PAGE(sc, 0); 721 1.48 mycroft bus_space_write_1(bst, bsh, CR, ENABLE_INT); 722 1.39 mycroft 723 1.44 mycroft xi_set_address(sc); 724 1.44 mycroft 725 1.44 mycroft PAGE(sc, 0x40); 726 1.48 mycroft bus_space_write_1(bst, bsh, CMD0, ENABLE_RX | ONLINE); 727 1.44 mycroft 728 1.44 mycroft PAGE(sc, 0); 729 1.44 mycroft 730 1.1 gmcgarry /* Set current media. */ 731 1.1 gmcgarry mii_mediachg(&sc->sc_mii); 732 1.1 gmcgarry 733 1.1 gmcgarry ifp->if_flags |= IFF_RUNNING; 734 1.1 gmcgarry ifp->if_flags &= ~IFF_OACTIVE; 735 1.39 mycroft 736 1.42 mycroft xi_start(ifp); 737 1.1 gmcgarry } 738 1.1 gmcgarry 739 1.1 gmcgarry /* 740 1.1 gmcgarry * Start outputting on the interface. 741 1.1 gmcgarry * Always called as splnet(). 742 1.1 gmcgarry */ 743 1.39 mycroft STATIC void 744 1.66 dsl xi_start(struct ifnet *ifp) 745 1.1 gmcgarry { 746 1.1 gmcgarry struct xi_softc *sc = ifp->if_softc; 747 1.1 gmcgarry bus_space_tag_t bst = sc->sc_bst; 748 1.1 gmcgarry bus_space_handle_t bsh = sc->sc_bsh; 749 1.1 gmcgarry unsigned int s, len, pad = 0; 750 1.1 gmcgarry struct mbuf *m0, *m; 751 1.84 msaitoh uint16_t space; 752 1.1 gmcgarry 753 1.2 gmcgarry DPRINTF(XID_CONFIG, ("xi_start()\n")); 754 1.1 gmcgarry 755 1.1 gmcgarry /* Don't transmit if interface is busy or not running. */ 756 1.1 gmcgarry if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) { 757 1.2 gmcgarry DPRINTF(XID_CONFIG, ("xi: interface busy or not running\n")); 758 1.1 gmcgarry return; 759 1.1 gmcgarry } 760 1.1 gmcgarry 761 1.1 gmcgarry /* Peek at the next packet. */ 762 1.7 thorpej IFQ_POLL(&ifp->if_snd, m0); 763 1.1 gmcgarry if (m0 == 0) 764 1.1 gmcgarry return; 765 1.1 gmcgarry 766 1.1 gmcgarry /* We need to use m->m_pkthdr.len, so require the header. */ 767 1.1 gmcgarry if (!(m0->m_flags & M_PKTHDR)) 768 1.1 gmcgarry panic("xi_start: no header mbuf"); 769 1.1 gmcgarry 770 1.1 gmcgarry len = m0->m_pkthdr.len; 771 1.1 gmcgarry 772 1.39 mycroft #if 1 773 1.1 gmcgarry /* Pad to ETHER_MIN_LEN - ETHER_CRC_LEN. */ 774 1.1 gmcgarry if (len < ETHER_MIN_LEN - ETHER_CRC_LEN) 775 1.1 gmcgarry pad = ETHER_MIN_LEN - ETHER_CRC_LEN - len; 776 1.39 mycroft #else 777 1.39 mycroft pad = 0; 778 1.39 mycroft #endif 779 1.1 gmcgarry 780 1.1 gmcgarry PAGE(sc, 0); 781 1.39 mycroft 782 1.84 msaitoh bus_space_write_2(bst, bsh, TRS, (uint16_t)len + pad + 2); 783 1.48 mycroft space = bus_space_read_2(bst, bsh, TSO) & 0x7fff; 784 1.1 gmcgarry if (len + pad + 2 > space) { 785 1.1 gmcgarry DPRINTF(XID_FIFO, 786 1.2 gmcgarry ("xi: not enough space in output FIFO (%d > %d)\n", 787 1.2 gmcgarry len + pad + 2, space)); 788 1.1 gmcgarry return; 789 1.1 gmcgarry } 790 1.1 gmcgarry 791 1.7 thorpej IFQ_DEQUEUE(&ifp->if_snd, m0); 792 1.1 gmcgarry 793 1.82 msaitoh bpf_mtap(ifp, m0, BPF_D_OUT); 794 1.1 gmcgarry 795 1.1 gmcgarry /* 796 1.1 gmcgarry * Do the output at splhigh() so that an interrupt from another device 797 1.1 gmcgarry * won't cause a FIFO underrun. 798 1.1 gmcgarry */ 799 1.1 gmcgarry s = splhigh(); 800 1.1 gmcgarry 801 1.84 msaitoh bus_space_write_2(bst, bsh, EDP, (uint16_t)len + pad); 802 1.1 gmcgarry for (m = m0; m; ) { 803 1.1 gmcgarry if (m->m_len > 1) 804 1.48 mycroft bus_space_write_multi_2(bst, bsh, EDP, 805 1.84 msaitoh mtod(m, uint16_t *), m->m_len>>1); 806 1.39 mycroft if (m->m_len & 1) { 807 1.39 mycroft DPRINTF(XID_CONFIG, ("xi: XXX odd!\n")); 808 1.48 mycroft bus_space_write_1(bst, bsh, EDP, 809 1.84 msaitoh *(mtod(m, uint8_t *) + m->m_len - 1)); 810 1.39 mycroft } 811 1.78 christos m = m0 = m_free(m); 812 1.1 gmcgarry } 813 1.39 mycroft DPRINTF(XID_CONFIG, ("xi: len=%d pad=%d total=%d\n", len, pad, len+pad+4)); 814 1.39 mycroft if (sc->sc_chipset >= XI_CHIPSET_MOHAWK) 815 1.48 mycroft bus_space_write_1(bst, bsh, CR, TX_PKT | ENABLE_INT); 816 1.1 gmcgarry else { 817 1.1 gmcgarry for (; pad > 1; pad -= 2) 818 1.48 mycroft bus_space_write_2(bst, bsh, EDP, 0); 819 1.1 gmcgarry if (pad == 1) 820 1.48 mycroft bus_space_write_1(bst, bsh, EDP, 0); 821 1.1 gmcgarry } 822 1.1 gmcgarry 823 1.1 gmcgarry splx(s); 824 1.1 gmcgarry 825 1.1 gmcgarry ifp->if_timer = 5; 826 1.94 thorpej if_statinc(ifp, if_opackets); 827 1.1 gmcgarry } 828 1.1 gmcgarry 829 1.39 mycroft STATIC int 830 1.66 dsl xi_ether_ioctl(struct ifnet *ifp, u_long cmd, void *data) 831 1.1 gmcgarry { 832 1.1 gmcgarry struct ifaddr *ifa = (struct ifaddr *)data; 833 1.1 gmcgarry struct xi_softc *sc = ifp->if_softc; 834 1.42 mycroft int error; 835 1.1 gmcgarry 836 1.2 gmcgarry DPRINTF(XID_CONFIG, ("xi_ether_ioctl()\n")); 837 1.1 gmcgarry 838 1.1 gmcgarry switch (cmd) { 839 1.65 dyoung case SIOCINITIFADDR: 840 1.42 mycroft if ((error = xi_enable(sc)) != 0) 841 1.42 mycroft break; 842 1.42 mycroft 843 1.1 gmcgarry ifp->if_flags |= IFF_UP; 844 1.1 gmcgarry 845 1.65 dyoung xi_init(sc); 846 1.1 gmcgarry switch (ifa->ifa_addr->sa_family) { 847 1.1 gmcgarry #ifdef INET 848 1.1 gmcgarry case AF_INET: 849 1.1 gmcgarry arp_ifinit(ifp, ifa); 850 1.1 gmcgarry break; 851 1.1 gmcgarry #endif /* INET */ 852 1.1 gmcgarry 853 1.1 gmcgarry 854 1.1 gmcgarry default: 855 1.1 gmcgarry break; 856 1.1 gmcgarry } 857 1.1 gmcgarry break; 858 1.1 gmcgarry 859 1.1 gmcgarry default: 860 1.1 gmcgarry return (EINVAL); 861 1.1 gmcgarry } 862 1.1 gmcgarry 863 1.1 gmcgarry return (0); 864 1.1 gmcgarry } 865 1.1 gmcgarry 866 1.39 mycroft STATIC int 867 1.65 dyoung xi_ioctl(struct ifnet *ifp, u_long cmd, void *data) 868 1.1 gmcgarry { 869 1.39 mycroft struct xi_softc *sc = ifp->if_softc; 870 1.1 gmcgarry int s, error = 0; 871 1.1 gmcgarry 872 1.2 gmcgarry DPRINTF(XID_CONFIG, ("xi_ioctl()\n")); 873 1.1 gmcgarry 874 1.8 thorpej s = splnet(); 875 1.1 gmcgarry 876 1.39 mycroft switch (cmd) { 877 1.65 dyoung case SIOCINITIFADDR: 878 1.39 mycroft error = xi_ether_ioctl(ifp, cmd, data); 879 1.1 gmcgarry break; 880 1.1 gmcgarry 881 1.1 gmcgarry case SIOCSIFFLAGS: 882 1.65 dyoung if ((error = ifioctl_common(ifp, cmd, data)) != 0) 883 1.65 dyoung break; 884 1.65 dyoung /* XXX re-use ether_ioctl() */ 885 1.88 msaitoh switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) { 886 1.65 dyoung case IFF_RUNNING: 887 1.39 mycroft /* 888 1.39 mycroft * If interface is marked down and it is running, 889 1.39 mycroft * stop it. 890 1.39 mycroft */ 891 1.39 mycroft xi_stop(sc); 892 1.39 mycroft ifp->if_flags &= ~IFF_RUNNING; 893 1.42 mycroft xi_disable(sc); 894 1.65 dyoung break; 895 1.65 dyoung case IFF_UP: 896 1.39 mycroft /* 897 1.39 mycroft * If interface is marked up and it is stopped, 898 1.39 mycroft * start it. 899 1.39 mycroft */ 900 1.42 mycroft if ((error = xi_enable(sc)) != 0) 901 1.42 mycroft break; 902 1.1 gmcgarry xi_init(sc); 903 1.65 dyoung break; 904 1.88 msaitoh case IFF_UP | IFF_RUNNING: 905 1.39 mycroft /* 906 1.39 mycroft * Reset the interface to pick up changes in any 907 1.39 mycroft * other flags that affect hardware registers. 908 1.39 mycroft */ 909 1.42 mycroft xi_set_address(sc); 910 1.65 dyoung break; 911 1.65 dyoung case 0: 912 1.65 dyoung break; 913 1.1 gmcgarry } 914 1.1 gmcgarry break; 915 1.1 gmcgarry 916 1.1 gmcgarry case SIOCADDMULTI: 917 1.1 gmcgarry case SIOCDELMULTI: 918 1.39 mycroft if (sc->sc_enabled == 0) { 919 1.39 mycroft error = EIO; 920 1.39 mycroft break; 921 1.39 mycroft } 922 1.63 dyoung /*FALLTHROUGH*/ 923 1.87 msaitoh default: 924 1.62 dyoung if ((error = ether_ioctl(ifp, cmd, data)) == ENETRESET) { 925 1.1 gmcgarry /* 926 1.1 gmcgarry * Multicast list has changed; set the hardware 927 1.1 gmcgarry * filter accordingly. 928 1.1 gmcgarry */ 929 1.49 thorpej if (ifp->if_flags & IFF_RUNNING) 930 1.49 thorpej xi_set_address(sc); 931 1.1 gmcgarry error = 0; 932 1.1 gmcgarry } 933 1.1 gmcgarry break; 934 1.1 gmcgarry } 935 1.39 mycroft 936 1.1 gmcgarry splx(s); 937 1.1 gmcgarry return (error); 938 1.1 gmcgarry } 939 1.1 gmcgarry 940 1.39 mycroft STATIC void 941 1.66 dsl xi_set_address(struct xi_softc *sc) 942 1.1 gmcgarry { 943 1.1 gmcgarry bus_space_tag_t bst = sc->sc_bst; 944 1.1 gmcgarry bus_space_handle_t bsh = sc->sc_bsh; 945 1.90 msaitoh struct ethercom *ec = &sc->sc_ethercom; 946 1.11 gmcgarry struct ifnet *ifp = &sc->sc_ethercom.ec_if; 947 1.11 gmcgarry struct ether_multistep step; 948 1.1 gmcgarry struct ether_multi *enm; 949 1.39 mycroft int page, num; 950 1.11 gmcgarry int i; 951 1.84 msaitoh uint8_t x; 952 1.84 msaitoh const uint8_t *enaddr; 953 1.84 msaitoh uint8_t indaddr[64]; 954 1.1 gmcgarry 955 1.2 gmcgarry DPRINTF(XID_CONFIG, ("xi_set_address()\n")); 956 1.1 gmcgarry 957 1.84 msaitoh enaddr = (const uint8_t *)CLLADDR(ifp->if_sadl); 958 1.39 mycroft if (sc->sc_chipset >= XI_CHIPSET_MOHAWK) 959 1.39 mycroft for (i = 0; i < 6; i++) 960 1.39 mycroft indaddr[i] = enaddr[5 - i]; 961 1.39 mycroft else 962 1.39 mycroft for (i = 0; i < 6; i++) 963 1.39 mycroft indaddr[i] = enaddr[i]; 964 1.39 mycroft num = 1; 965 1.39 mycroft 966 1.93 msaitoh ETHER_LOCK(ec); 967 1.90 msaitoh if (ec->ec_multicnt > 9) { 968 1.39 mycroft ifp->if_flags |= IFF_ALLMULTI; 969 1.39 mycroft goto done; 970 1.1 gmcgarry } 971 1.11 gmcgarry 972 1.90 msaitoh ETHER_FIRST_MULTI(step, ec, enm); 973 1.39 mycroft for (; enm; num++) { 974 1.39 mycroft if (memcmp(enm->enm_addrlo, enm->enm_addrhi, 975 1.39 mycroft sizeof(enm->enm_addrlo)) != 0) { 976 1.39 mycroft /* 977 1.39 mycroft * The multicast address is really a range; 978 1.39 mycroft * it's easier just to accept all multicasts. 979 1.39 mycroft * XXX should we be setting IFF_ALLMULTI here? 980 1.39 mycroft */ 981 1.39 mycroft ifp->if_flags |= IFF_ALLMULTI; 982 1.39 mycroft goto done; 983 1.1 gmcgarry } 984 1.39 mycroft if (sc->sc_chipset >= XI_CHIPSET_MOHAWK) 985 1.39 mycroft for (i = 0; i < 6; i++) 986 1.39 mycroft indaddr[num * 6 + i] = enm->enm_addrlo[5 - i]; 987 1.39 mycroft else 988 1.39 mycroft for (i = 0; i < 6; i++) 989 1.39 mycroft indaddr[num * 6 + i] = enm->enm_addrlo[i]; 990 1.39 mycroft ETHER_NEXT_MULTI(step, enm); 991 1.39 mycroft } 992 1.39 mycroft ifp->if_flags &= ~IFF_ALLMULTI; 993 1.1 gmcgarry 994 1.39 mycroft done: 995 1.93 msaitoh ETHER_UNLOCK(ec); 996 1.39 mycroft if (num < 10) 997 1.39 mycroft memset(&indaddr[num * 6], 0xff, 6 * (10 - num)); 998 1.11 gmcgarry 999 1.39 mycroft for (page = 0; page < 8; page++) { 1000 1.39 mycroft #ifdef XIDEBUG 1001 1.39 mycroft if (xidebug & XID_MCAST) { 1002 1.46 mycroft printf("page %d before:", page); 1003 1.39 mycroft for (i = 0; i < 8; i++) 1004 1.39 mycroft printf(" %02x", indaddr[page * 8 + i]); 1005 1.11 gmcgarry printf("\n"); 1006 1.1 gmcgarry } 1007 1.11 gmcgarry #endif 1008 1.39 mycroft 1009 1.39 mycroft PAGE(sc, 0x50 + page); 1010 1.48 mycroft bus_space_write_region_1(bst, bsh, IA, &indaddr[page * 8], 1011 1.48 mycroft page == 7 ? 4 : 8); 1012 1.46 mycroft /* 1013 1.46 mycroft * XXX 1014 1.46 mycroft * Without this delay, the address registers on my CE2 get 1015 1.46 mycroft * trashed the first and I have to cycle it. I have no idea 1016 1.46 mycroft * why. - mycroft, 2004/08/09 1017 1.46 mycroft */ 1018 1.46 mycroft DELAY(50); 1019 1.46 mycroft 1020 1.46 mycroft #ifdef XIDEBUG 1021 1.46 mycroft if (xidebug & XID_MCAST) { 1022 1.48 mycroft bus_space_read_region_1(bst, bsh, IA, 1023 1.46 mycroft &indaddr[page * 8], page == 7 ? 4 : 8); 1024 1.46 mycroft printf("page %d after: ", page); 1025 1.46 mycroft for (i = 0; i < 8; i++) 1026 1.46 mycroft printf(" %02x", indaddr[page * 8 + i]); 1027 1.46 mycroft printf("\n"); 1028 1.46 mycroft } 1029 1.46 mycroft #endif 1030 1.1 gmcgarry } 1031 1.39 mycroft 1032 1.39 mycroft PAGE(sc, 0x42); 1033 1.39 mycroft x = SWC1_IND_ADDR; 1034 1.39 mycroft if (ifp->if_flags & IFF_PROMISC) 1035 1.39 mycroft x |= SWC1_PROMISC; 1036 1.88 msaitoh if (ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) 1037 1.39 mycroft x |= SWC1_MCAST_PROM; 1038 1.39 mycroft if (!LIST_FIRST(&sc->sc_mii.mii_phys)) 1039 1.39 mycroft x |= SWC1_AUTO_MEDIA; 1040 1.48 mycroft bus_space_write_1(sc->sc_bst, sc->sc_bsh, SWC1, x); 1041 1.1 gmcgarry } 1042 1.1 gmcgarry 1043 1.39 mycroft STATIC void 1044 1.66 dsl xi_cycle_power(struct xi_softc *sc) 1045 1.1 gmcgarry { 1046 1.1 gmcgarry bus_space_tag_t bst = sc->sc_bst; 1047 1.1 gmcgarry bus_space_handle_t bsh = sc->sc_bsh; 1048 1.1 gmcgarry 1049 1.2 gmcgarry DPRINTF(XID_CONFIG, ("xi_cycle_power()\n")); 1050 1.1 gmcgarry 1051 1.1 gmcgarry PAGE(sc, 4); 1052 1.1 gmcgarry DELAY(1); 1053 1.48 mycroft bus_space_write_1(bst, bsh, GP1, 0); 1054 1.47 mycroft tsleep(&xi_cycle_power, PWAIT, "xipwr1", hz * 40 / 1000); 1055 1.39 mycroft if (sc->sc_chipset >= XI_CHIPSET_MOHAWK) 1056 1.48 mycroft bus_space_write_1(bst, bsh, GP1, POWER_UP); 1057 1.1 gmcgarry else 1058 1.1 gmcgarry /* XXX What is bit 2 (aka AIC)? */ 1059 1.48 mycroft bus_space_write_1(bst, bsh, GP1, POWER_UP | 4); 1060 1.47 mycroft tsleep(&xi_cycle_power, PWAIT, "xipwr2", hz * 20 / 1000); 1061 1.1 gmcgarry } 1062 1.1 gmcgarry 1063 1.39 mycroft STATIC void 1064 1.66 dsl xi_full_reset(struct xi_softc *sc) 1065 1.1 gmcgarry { 1066 1.1 gmcgarry bus_space_tag_t bst = sc->sc_bst; 1067 1.1 gmcgarry bus_space_handle_t bsh = sc->sc_bsh; 1068 1.84 msaitoh uint8_t x; 1069 1.1 gmcgarry 1070 1.2 gmcgarry DPRINTF(XID_CONFIG, ("xi_full_reset()\n")); 1071 1.1 gmcgarry 1072 1.1 gmcgarry /* Do an as extensive reset as possible on all functions. */ 1073 1.1 gmcgarry xi_cycle_power(sc); 1074 1.48 mycroft bus_space_write_1(bst, bsh, CR, SOFT_RESET); 1075 1.47 mycroft tsleep(&xi_full_reset, PWAIT, "xirst1", hz * 20 / 1000); 1076 1.48 mycroft bus_space_write_1(bst, bsh, CR, 0); 1077 1.47 mycroft tsleep(&xi_full_reset, PWAIT, "xirst2", hz * 20 / 1000); 1078 1.39 mycroft PAGE(sc, 4); 1079 1.39 mycroft if (sc->sc_chipset >= XI_CHIPSET_MOHAWK) { 1080 1.1 gmcgarry /* 1081 1.1 gmcgarry * Drive GP1 low to power up ML6692 and GP2 high to power up 1082 1.29 tsutsui * the 10MHz chip. XXX What chip is that? The phy? 1083 1.1 gmcgarry */ 1084 1.48 mycroft bus_space_write_1(bst, bsh, GP0, GP1_OUT | GP2_OUT | GP2_WR); 1085 1.1 gmcgarry } 1086 1.47 mycroft tsleep(&xi_full_reset, PWAIT, "xirst3", hz * 500 / 1000); 1087 1.1 gmcgarry 1088 1.1 gmcgarry /* Get revision information. XXX Symbolic constants. */ 1089 1.48 mycroft sc->sc_rev = bus_space_read_1(bst, bsh, BV) & 1090 1.39 mycroft ((sc->sc_chipset >= XI_CHIPSET_MOHAWK) ? 0x70 : 0x30) >> 4; 1091 1.39 mycroft DPRINTF(XID_CONFIG, ("xi: rev=%02x\n", sc->sc_rev)); 1092 1.1 gmcgarry 1093 1.1 gmcgarry /* Media selection. XXX Maybe manual overriding too? */ 1094 1.39 mycroft if (sc->sc_chipset < XI_CHIPSET_MOHAWK) { 1095 1.1 gmcgarry /* 1096 1.1 gmcgarry * XXX I have no idea what this really does, it is from the 1097 1.1 gmcgarry * Linux driver. 1098 1.1 gmcgarry */ 1099 1.48 mycroft bus_space_write_1(bst, bsh, GP0, GP1_OUT); 1100 1.1 gmcgarry } 1101 1.47 mycroft tsleep(&xi_full_reset, PWAIT, "xirst4", hz * 40 / 1000); 1102 1.1 gmcgarry 1103 1.1 gmcgarry /* 1104 1.1 gmcgarry * Disable source insertion. 1105 1.1 gmcgarry * XXX Dingo does not have this bit, but Linux does it unconditionally. 1106 1.1 gmcgarry */ 1107 1.39 mycroft if (sc->sc_chipset < XI_CHIPSET_DINGO) { 1108 1.1 gmcgarry PAGE(sc, 0x42); 1109 1.48 mycroft bus_space_write_1(bst, bsh, SWC0, 0x20); 1110 1.1 gmcgarry } 1111 1.1 gmcgarry 1112 1.1 gmcgarry /* Set the local memory dividing line. */ 1113 1.1 gmcgarry if (sc->sc_rev != 1) { 1114 1.1 gmcgarry PAGE(sc, 2); 1115 1.95 andvar /* XXX Symbolic constant preferable. */ 1116 1.48 mycroft bus_space_write_2(bst, bsh, RBS0, 0x2000); 1117 1.1 gmcgarry } 1118 1.1 gmcgarry 1119 1.1 gmcgarry /* 1120 1.1 gmcgarry * Apparently the receive byte pointer can be bad after a reset, so 1121 1.1 gmcgarry * we hardwire it correctly. 1122 1.1 gmcgarry */ 1123 1.1 gmcgarry PAGE(sc, 0); 1124 1.48 mycroft bus_space_write_2(bst, bsh, DO0, DO_CHG_OFFSET); 1125 1.1 gmcgarry 1126 1.1 gmcgarry /* Setup ethernet MAC registers. XXX Symbolic constants. */ 1127 1.1 gmcgarry PAGE(sc, 0x40); 1128 1.48 mycroft bus_space_write_1(bst, bsh, RX0MSK, 1129 1.1 gmcgarry PKT_TOO_LONG | CRC_ERR | RX_OVERRUN | RX_ABORT | RX_OK); 1130 1.48 mycroft bus_space_write_1(bst, bsh, TX0MSK, 1131 1.1 gmcgarry CARRIER_LOST | EXCESSIVE_COLL | TX_UNDERRUN | LATE_COLLISION | 1132 1.1 gmcgarry SQE | TX_ABORT | TX_OK); 1133 1.39 mycroft if (sc->sc_chipset < XI_CHIPSET_DINGO) 1134 1.1 gmcgarry /* XXX From Linux, dunno what 0xb0 means. */ 1135 1.48 mycroft bus_space_write_1(bst, bsh, TX1MSK, 0xb0); 1136 1.48 mycroft bus_space_write_1(bst, bsh, RXST0, 0); 1137 1.48 mycroft bus_space_write_1(bst, bsh, TXST0, 0); 1138 1.48 mycroft bus_space_write_1(bst, bsh, TXST1, 0); 1139 1.1 gmcgarry 1140 1.39 mycroft PAGE(sc, 2); 1141 1.39 mycroft 1142 1.1 gmcgarry /* Enable MII function if available. */ 1143 1.39 mycroft x = 0; 1144 1.39 mycroft if (LIST_FIRST(&sc->sc_mii.mii_phys)) 1145 1.39 mycroft x |= SELECT_MII; 1146 1.48 mycroft bus_space_write_1(bst, bsh, MSR, x); 1147 1.47 mycroft tsleep(&xi_full_reset, PWAIT, "xirst5", hz * 20 / 1000); 1148 1.1 gmcgarry 1149 1.1 gmcgarry /* Configure the LED registers. */ 1150 1.1 gmcgarry /* XXX This is not good for 10base2. */ 1151 1.48 mycroft bus_space_write_1(bst, bsh, LED, 1152 1.41 mycroft (LED_TX_ACT << LED1_SHIFT) | (LED_10MB_LINK << LED0_SHIFT)); 1153 1.41 mycroft if (sc->sc_chipset >= XI_CHIPSET_DINGO) 1154 1.48 mycroft bus_space_write_1(bst, bsh, LED3, LED_100MB_LINK << LED3_SHIFT); 1155 1.1 gmcgarry 1156 1.1 gmcgarry /* 1157 1.1 gmcgarry * The Linux driver says this: 1158 1.1 gmcgarry * We should switch back to page 0 to avoid a bug in revision 0 1159 1.1 gmcgarry * where regs with offset below 8 can't be read after an access 1160 1.1 gmcgarry * to the MAC registers. 1161 1.1 gmcgarry */ 1162 1.1 gmcgarry PAGE(sc, 0); 1163 1.1 gmcgarry } 1164