1 1.108 thorpej /* $NetBSD: smc91cxx.c,v 1.108 2022/09/25 18:43:32 thorpej Exp $ */ 2 1.2 thorpej 3 1.2 thorpej /*- 4 1.2 thorpej * Copyright (c) 1997 The NetBSD Foundation, Inc. 5 1.2 thorpej * All rights reserved. 6 1.2 thorpej * 7 1.2 thorpej * This code is derived from software contributed to The NetBSD Foundation 8 1.2 thorpej * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 9 1.2 thorpej * NASA Ames Research Center. 10 1.2 thorpej * 11 1.2 thorpej * Redistribution and use in source and binary forms, with or without 12 1.2 thorpej * modification, are permitted provided that the following conditions 13 1.2 thorpej * are met: 14 1.2 thorpej * 1. Redistributions of source code must retain the above copyright 15 1.2 thorpej * notice, this list of conditions and the following disclaimer. 16 1.2 thorpej * 2. Redistributions in binary form must reproduce the above copyright 17 1.2 thorpej * notice, this list of conditions and the following disclaimer in the 18 1.2 thorpej * documentation and/or other materials provided with the distribution. 19 1.2 thorpej * 20 1.2 thorpej * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 1.2 thorpej * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 1.2 thorpej * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 1.3 jtc * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 1.3 jtc * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 1.2 thorpej * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 1.2 thorpej * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 1.2 thorpej * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 1.2 thorpej * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 1.2 thorpej * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 1.2 thorpej * POSSIBILITY OF SUCH DAMAGE. 31 1.2 thorpej */ 32 1.2 thorpej 33 1.51 perry /* 34 1.2 thorpej * Copyright (c) 1996 Gardner Buchanan <gbuchanan (at) shl.com> 35 1.2 thorpej * All rights reserved. 36 1.51 perry * 37 1.2 thorpej * Redistribution and use in source and binary forms, with or without 38 1.2 thorpej * modification, are permitted provided that the following conditions 39 1.2 thorpej * are met: 40 1.2 thorpej * 1. Redistributions of source code must retain the above copyright 41 1.2 thorpej * notice, this list of conditions and the following disclaimer. 42 1.2 thorpej * 2. Redistributions in binary form must reproduce the above copyright 43 1.2 thorpej * notice, this list of conditions and the following disclaimer in the 44 1.2 thorpej * documentation and/or other materials provided with the distribution. 45 1.2 thorpej * 3. All advertising materials mentioning features or use of this software 46 1.2 thorpej * must display the following acknowledgement: 47 1.2 thorpej * This product includes software developed by Gardner Buchanan. 48 1.2 thorpej * 4. The name of Gardner Buchanan may not be used to endorse or promote 49 1.2 thorpej * products derived from this software without specific prior written 50 1.2 thorpej * permission. 51 1.51 perry * 52 1.2 thorpej * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 53 1.2 thorpej * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 54 1.2 thorpej * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 55 1.2 thorpej * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 56 1.2 thorpej * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 57 1.2 thorpej * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 58 1.2 thorpej * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 59 1.2 thorpej * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 60 1.2 thorpej * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 61 1.2 thorpej * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 62 1.51 perry * 63 1.2 thorpej * from FreeBSD Id: if_sn.c,v 1.4 1996/03/18 15:47:16 gardner Exp 64 1.51 perry */ 65 1.2 thorpej 66 1.2 thorpej /* 67 1.2 thorpej * Core driver for the SMC 91Cxx family of Ethernet chips. 68 1.2 thorpej * 69 1.107 andvar * Memory allocation interrupt logic is derived from an SMC 91C90 driver 70 1.2 thorpej * written for NetBSD/amiga by Michael Hitch. 71 1.2 thorpej */ 72 1.37 lukem 73 1.37 lukem #include <sys/cdefs.h> 74 1.108 thorpej __KERNEL_RCSID(0, "$NetBSD: smc91cxx.c,v 1.108 2022/09/25 18:43:32 thorpej Exp $"); 75 1.2 thorpej 76 1.7 jonathan #include "opt_inet.h" 77 1.2 thorpej 78 1.51 perry #include <sys/param.h> 79 1.2 thorpej #include <sys/systm.h> 80 1.2 thorpej #include <sys/mbuf.h> 81 1.2 thorpej #include <sys/syslog.h> 82 1.2 thorpej #include <sys/socket.h> 83 1.2 thorpej #include <sys/device.h> 84 1.26 briggs #include <sys/kernel.h> 85 1.51 perry #include <sys/ioctl.h> 86 1.2 thorpej #include <sys/errno.h> 87 1.89 riastrad #include <sys/rndsource.h> 88 1.2 thorpej 89 1.63 ad #include <sys/bus.h> 90 1.63 ad #include <sys/intr.h> 91 1.2 thorpej 92 1.2 thorpej #include <net/if.h> 93 1.2 thorpej #include <net/if_dl.h> 94 1.2 thorpej #include <net/if_ether.h> 95 1.51 perry #include <net/if_media.h> 96 1.96 msaitoh #include <net/bpf.h> 97 1.2 thorpej 98 1.2 thorpej #ifdef INET 99 1.51 perry #include <netinet/in.h> 100 1.2 thorpej #include <netinet/if_inarp.h> 101 1.2 thorpej #include <netinet/in_systm.h> 102 1.2 thorpej #include <netinet/in_var.h> 103 1.2 thorpej #include <netinet/ip.h> 104 1.2 thorpej #endif 105 1.2 thorpej 106 1.26 briggs #include <dev/mii/mii.h> 107 1.26 briggs #include <dev/mii/miivar.h> 108 1.26 briggs #include <dev/mii/mii_bitbang.h> 109 1.26 briggs 110 1.2 thorpej #include <dev/ic/smc91cxxreg.h> 111 1.2 thorpej #include <dev/ic/smc91cxxvar.h> 112 1.40 thorpej 113 1.40 thorpej #ifndef __BUS_SPACE_HAS_STREAM_METHODS 114 1.40 thorpej #define bus_space_write_multi_stream_2 bus_space_write_multi_2 115 1.42 bsh #define bus_space_write_multi_stream_4 bus_space_write_multi_4 116 1.40 thorpej #define bus_space_read_multi_stream_2 bus_space_read_multi_2 117 1.42 bsh #define bus_space_read_multi_stream_4 bus_space_read_multi_4 118 1.42 bsh 119 1.42 bsh #define bus_space_write_stream_4 bus_space_write_4 120 1.101 msaitoh #define bus_space_read_stream_4 bus_space_read_4 121 1.40 thorpej #endif /* __BUS_SPACE_HAS_STREAM_METHODS */ 122 1.2 thorpej 123 1.2 thorpej /* XXX Hardware padding doesn't work yet(?) */ 124 1.2 thorpej #define SMC91CXX_SW_PAD 125 1.2 thorpej 126 1.86 chs const char *smc91cxx_idstrs[] = { 127 1.2 thorpej NULL, /* 0 */ 128 1.2 thorpej NULL, /* 1 */ 129 1.2 thorpej NULL, /* 2 */ 130 1.2 thorpej "SMC91C90/91C92", /* 3 */ 131 1.39 chs "SMC91C94/91C96", /* 4 */ 132 1.2 thorpej "SMC91C95", /* 5 */ 133 1.2 thorpej NULL, /* 6 */ 134 1.2 thorpej "SMC91C100", /* 7 */ 135 1.26 briggs "SMC91C100FD", /* 8 */ 136 1.45 scw "SMC91C111", /* 9 */ 137 1.2 thorpej NULL, /* 10 */ 138 1.2 thorpej NULL, /* 11 */ 139 1.2 thorpej NULL, /* 12 */ 140 1.2 thorpej NULL, /* 13 */ 141 1.2 thorpej NULL, /* 14 */ 142 1.2 thorpej NULL, /* 15 */ 143 1.2 thorpej }; 144 1.2 thorpej 145 1.2 thorpej /* Supported media types. */ 146 1.85 chs static const int smc91cxx_media[] = { 147 1.101 msaitoh IFM_ETHER | IFM_10_T, 148 1.101 msaitoh IFM_ETHER | IFM_10_5, 149 1.2 thorpej }; 150 1.101 msaitoh #define NSMC91CxxMEDIA __arraycount(smc91cxx_media) 151 1.2 thorpej 152 1.26 briggs /* 153 1.26 briggs * MII bit-bang glue. 154 1.26 briggs */ 155 1.103 maxv static uint32_t smc91cxx_mii_bitbang_read(device_t); 156 1.103 maxv static void smc91cxx_mii_bitbang_write(device_t, uint32_t); 157 1.26 briggs 158 1.85 chs static const struct mii_bitbang_ops smc91cxx_mii_bitbang_ops = { 159 1.26 briggs smc91cxx_mii_bitbang_read, 160 1.26 briggs smc91cxx_mii_bitbang_write, 161 1.26 briggs { 162 1.26 briggs MR_MDO, /* MII_BIT_MDO */ 163 1.26 briggs MR_MDI, /* MII_BIT_MDI */ 164 1.26 briggs MR_MCLK, /* MII_BIT_MDC */ 165 1.26 briggs MR_MDOE, /* MII_BIT_DIR_HOST_PHY */ 166 1.26 briggs 0, /* MII_BIT_DIR_PHY_HOST */ 167 1.26 briggs } 168 1.26 briggs }; 169 1.26 briggs 170 1.26 briggs /* MII callbacks */ 171 1.103 maxv static int smc91cxx_mii_readreg(device_t, int, int, uint16_t *); 172 1.103 maxv static int smc91cxx_mii_writereg(device_t, int, int, uint16_t); 173 1.103 maxv static void smc91cxx_statchg(struct ifnet *); 174 1.103 maxv static void smc91cxx_tick(void *); 175 1.103 maxv 176 1.103 maxv static int smc91cxx_mediachange(struct ifnet *); 177 1.103 maxv static void smc91cxx_mediastatus(struct ifnet *, struct ifmediareq *); 178 1.103 maxv 179 1.103 maxv static int smc91cxx_set_media(struct smc91cxx_softc *, int); 180 1.103 maxv 181 1.103 maxv static void smc91cxx_init(struct smc91cxx_softc *); 182 1.103 maxv static void smc91cxx_read(struct smc91cxx_softc *); 183 1.103 maxv static void smc91cxx_reset(struct smc91cxx_softc *); 184 1.103 maxv static void smc91cxx_start(struct ifnet *); 185 1.103 maxv static uint8_t smc91cxx_copy_tx_frame(struct smc91cxx_softc *, struct mbuf *); 186 1.103 maxv static void smc91cxx_stop(struct smc91cxx_softc *); 187 1.103 maxv static void smc91cxx_watchdog(struct ifnet *); 188 1.103 maxv static int smc91cxx_ioctl(struct ifnet *, u_long, void *); 189 1.103 maxv 190 1.103 maxv static int smc91cxx_enable(struct smc91cxx_softc *); 191 1.103 maxv static void smc91cxx_disable(struct smc91cxx_softc *); 192 1.2 thorpej 193 1.61 dyoung static inline int ether_cmp(const void *, const void *); 194 1.54 perry static inline int 195 1.73 dsl ether_cmp(const void *va, const void *vb) 196 1.2 thorpej { 197 1.101 msaitoh const uint8_t *a = va; 198 1.101 msaitoh const uint8_t *b = vb; 199 1.2 thorpej 200 1.2 thorpej return ((a[5] != b[5]) || (a[4] != b[4]) || (a[3] != b[3]) || 201 1.2 thorpej (a[2] != b[2]) || (a[1] != b[1]) || (a[0] != b[0])); 202 1.2 thorpej } 203 1.2 thorpej 204 1.67 matt static inline void 205 1.67 matt smc91cxx_intr_mask_write(bus_space_tag_t bst, bus_space_handle_t bsh, 206 1.67 matt uint8_t mask) 207 1.67 matt { 208 1.67 matt KDASSERT((mask & IM_ERCV_INT) == 0); 209 1.67 matt #ifdef SMC91CXX_NO_BYTE_WRITE 210 1.67 matt bus_space_write_2(bst, bsh, INTR_STAT_REG_B, mask << 8); 211 1.67 matt #else 212 1.67 matt bus_space_write_1(bst, bsh, INTR_MASK_REG_B, mask); 213 1.67 matt #endif 214 1.67 matt KDASSERT(!(bus_space_read_1(bst, bsh, INTR_MASK_REG_B) & IM_ERCV_INT)); 215 1.67 matt } 216 1.67 matt 217 1.67 matt static inline void 218 1.67 matt smc91cxx_intr_ack_write(bus_space_tag_t bst, bus_space_handle_t bsh, 219 1.85 chs uint8_t ack, uint8_t mask) 220 1.67 matt { 221 1.67 matt #ifdef SMC91CXX_NO_BYTE_WRITE 222 1.85 chs bus_space_write_2(bst, bsh, INTR_ACK_REG_B, ack | (mask << 8)); 223 1.67 matt #else 224 1.85 chs bus_space_write_1(bst, bsh, INTR_ACK_REG_B, ack); 225 1.67 matt #endif 226 1.67 matt KDASSERT(!(bus_space_read_1(bst, bsh, INTR_MASK_REG_B) & IM_ERCV_INT)); 227 1.67 matt } 228 1.67 matt 229 1.2 thorpej void 230 1.101 msaitoh smc91cxx_attach(struct smc91cxx_softc *sc, uint8_t *myea) 231 1.2 thorpej { 232 1.2 thorpej struct ifnet *ifp = &sc->sc_ec.ec_if; 233 1.2 thorpej bus_space_tag_t bst = sc->sc_bst; 234 1.2 thorpej bus_space_handle_t bsh = sc->sc_bsh; 235 1.102 msaitoh struct mii_data *mii = &sc->sc_mii; 236 1.102 msaitoh struct ifmedia *ifm = &mii->mii_media; 237 1.2 thorpej const char *idstr; 238 1.101 msaitoh uint32_t miicapabilities; 239 1.101 msaitoh uint16_t tmp; 240 1.101 msaitoh uint8_t enaddr[ETHER_ADDR_LEN]; 241 1.45 scw int i, aui, mult, scale, memsize; 242 1.26 briggs char pbuf[9]; 243 1.2 thorpej 244 1.47 mycroft tmp = bus_space_read_2(bst, bsh, BANK_SELECT_REG_W); 245 1.47 mycroft /* check magic number */ 246 1.47 mycroft if ((tmp & BSR_DETECT_MASK) != BSR_DETECT_VALUE) { 247 1.85 chs aprint_error_dev(sc->sc_dev, 248 1.85 chs "failed to detect chip, bsr=%04x\n", tmp); 249 1.47 mycroft return; 250 1.47 mycroft } 251 1.47 mycroft 252 1.2 thorpej /* Make sure the chip is stopped. */ 253 1.2 thorpej smc91cxx_stop(sc); 254 1.2 thorpej 255 1.2 thorpej SMC_SELECT_BANK(sc, 3); 256 1.2 thorpej tmp = bus_space_read_2(bst, bsh, REVISION_REG_W); 257 1.26 briggs sc->sc_chipid = RR_ID(tmp); 258 1.47 mycroft idstr = smc91cxx_idstrs[sc->sc_chipid]; 259 1.47 mycroft 260 1.83 chs aprint_normal_dev(sc->sc_dev, ""); 261 1.2 thorpej if (idstr != NULL) 262 1.47 mycroft aprint_normal("%s, ", idstr); 263 1.2 thorpej else 264 1.47 mycroft aprint_normal("unknown chip id %d, ", sc->sc_chipid); 265 1.47 mycroft aprint_normal("revision %d, ", RR_REV(tmp)); 266 1.26 briggs 267 1.26 briggs SMC_SELECT_BANK(sc, 0); 268 1.45 scw switch (sc->sc_chipid) { 269 1.45 scw default: 270 1.45 scw mult = MCR_MEM_MULT(bus_space_read_2(bst, bsh, MEM_CFG_REG_W)); 271 1.45 scw scale = MIR_SCALE_91C9x; 272 1.45 scw break; 273 1.45 scw 274 1.45 scw case CHIP_91C111: 275 1.45 scw mult = MIR_MULT_91C111; 276 1.45 scw scale = MIR_SCALE_91C111; 277 1.45 scw } 278 1.26 briggs memsize = bus_space_read_2(bst, bsh, MEM_INFO_REG_W) & MIR_TOTAL_MASK; 279 1.85 chs if (memsize == 255) 280 1.85 chs memsize++; 281 1.45 scw memsize *= scale * mult; 282 1.26 briggs 283 1.26 briggs format_bytes(pbuf, sizeof(pbuf), memsize); 284 1.47 mycroft aprint_normal("buffer size: %s\n", pbuf); 285 1.2 thorpej 286 1.2 thorpej /* Read the station address from the chip. */ 287 1.2 thorpej SMC_SELECT_BANK(sc, 1); 288 1.2 thorpej if (myea == NULL) { 289 1.2 thorpej myea = enaddr; 290 1.2 thorpej for (i = 0; i < ETHER_ADDR_LEN; i += 2) { 291 1.2 thorpej tmp = bus_space_read_2(bst, bsh, IAR_ADDR0_REG_W + i); 292 1.2 thorpej myea[i + 1] = (tmp >> 8) & 0xff; 293 1.2 thorpej myea[i] = tmp & 0xff; 294 1.2 thorpej } 295 1.2 thorpej } 296 1.83 chs aprint_normal_dev(sc->sc_dev, "MAC address %s, ", 297 1.2 thorpej ether_sprintf(myea)); 298 1.2 thorpej 299 1.2 thorpej /* Initialize the ifnet structure. */ 300 1.83 chs strlcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ); 301 1.2 thorpej ifp->if_softc = sc; 302 1.2 thorpej ifp->if_start = smc91cxx_start; 303 1.2 thorpej ifp->if_ioctl = smc91cxx_ioctl; 304 1.2 thorpej ifp->if_watchdog = smc91cxx_watchdog; 305 1.99 msaitoh ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 306 1.32 thorpej IFQ_SET_READY(&ifp->if_snd); 307 1.2 thorpej 308 1.2 thorpej /* Attach the interface. */ 309 1.2 thorpej if_attach(ifp); 310 1.95 ozaki if_deferred_start_init(ifp, NULL); 311 1.2 thorpej ether_ifattach(ifp, myea); 312 1.2 thorpej 313 1.26 briggs /* 314 1.26 briggs * Initialize our media structures and MII info. We will 315 1.26 briggs * probe the MII if we are on the SMC91Cxx 316 1.26 briggs */ 317 1.102 msaitoh mii->mii_ifp = ifp; 318 1.102 msaitoh mii->mii_readreg = smc91cxx_mii_readreg; 319 1.102 msaitoh mii->mii_writereg = smc91cxx_mii_writereg; 320 1.102 msaitoh mii->mii_statchg = smc91cxx_statchg; 321 1.102 msaitoh sc->sc_ec.ec_mii = mii; 322 1.93 msaitoh ifmedia_init(ifm, IFM_IMASK, smc91cxx_mediachange, 323 1.93 msaitoh smc91cxx_mediastatus); 324 1.26 briggs 325 1.26 briggs SMC_SELECT_BANK(sc, 1); 326 1.26 briggs tmp = bus_space_read_2(bst, bsh, CONFIG_REG_W); 327 1.26 briggs 328 1.35 thorpej miicapabilities = BMSR_MEDIAMASK|BMSR_ANEG; 329 1.26 briggs switch (sc->sc_chipid) { 330 1.26 briggs case CHIP_91100: 331 1.26 briggs /* 332 1.26 briggs * The 91100 does not have full-duplex capabilities, 333 1.26 briggs * even if the PHY does. 334 1.26 briggs */ 335 1.26 briggs miicapabilities &= ~(BMSR_100TXFDX | BMSR_10TFDX); 336 1.87 christos /*FALLTHROUGH*/ 337 1.26 briggs case CHIP_91100FD: 338 1.45 scw case CHIP_91C111: 339 1.26 briggs if (tmp & CR_MII_SELECT) { 340 1.47 mycroft aprint_normal("default media MII"); 341 1.45 scw if (sc->sc_chipid == CHIP_91C111) { 342 1.85 chs aprint_normal(" (%s PHY)\n", 343 1.85 chs (tmp & CR_AUI_SELECT) ? 344 1.45 scw "external" : "internal"); 345 1.45 scw sc->sc_internal_phy = !(tmp & CR_AUI_SELECT); 346 1.45 scw } else 347 1.47 mycroft aprint_normal("\n"); 348 1.102 msaitoh mii_attach(sc->sc_dev, mii, miicapabilities, 349 1.26 briggs MII_PHY_ANY, MII_OFFSET_ANY, 0); 350 1.102 msaitoh if (LIST_FIRST(&mii->mii_phys) == NULL) { 351 1.102 msaitoh ifmedia_add(&mii->mii_media, 352 1.101 msaitoh IFM_ETHER | IFM_NONE, 0, NULL); 353 1.102 msaitoh ifmedia_set(&mii->mii_media, 354 1.101 msaitoh IFM_ETHER | IFM_NONE); 355 1.26 briggs } else { 356 1.102 msaitoh ifmedia_set(&mii->mii_media, 357 1.101 msaitoh IFM_ETHER | IFM_AUTO); 358 1.26 briggs } 359 1.26 briggs sc->sc_flags |= SMC_FLAGS_HAS_MII; 360 1.26 briggs break; 361 1.45 scw } else 362 1.45 scw if (sc->sc_chipid == CHIP_91C111) { 363 1.101 msaitoh /* XXX: Should bring it out of low-power mode */ 364 1.47 mycroft aprint_normal("EPH interface in low power mode\n"); 365 1.45 scw sc->sc_internal_phy = 0; 366 1.45 scw return; 367 1.26 briggs } 368 1.26 briggs /*FALLTHROUGH*/ 369 1.26 briggs default: 370 1.85 chs aprint_normal("default media %s\n", 371 1.85 chs (aui = (tmp & CR_AUI_SELECT)) ? 372 1.26 briggs "AUI" : "UTP"); 373 1.26 briggs for (i = 0; i < NSMC91CxxMEDIA; i++) 374 1.26 briggs ifmedia_add(ifm, smc91cxx_media[i], 0, NULL); 375 1.26 briggs ifmedia_set(ifm, IFM_ETHER | (aui ? IFM_10_5 : IFM_10_T)); 376 1.26 briggs break; 377 1.26 briggs } 378 1.2 thorpej 379 1.83 chs rnd_attach_source(&sc->rnd_source, device_xname(sc->sc_dev), 380 1.88 tls RND_TYPE_NET, RND_FLAG_DEFAULT); 381 1.25 jhawk 382 1.60 kiyohara callout_init(&sc->sc_mii_callout, 0); 383 1.106 thorpej callout_setfunc(&sc->sc_mii_callout, smc91cxx_tick, sc); 384 1.60 kiyohara 385 1.25 jhawk /* The attach is successful. */ 386 1.25 jhawk sc->sc_flags |= SMC_FLAGS_ATTACHED; 387 1.2 thorpej } 388 1.2 thorpej 389 1.2 thorpej /* 390 1.2 thorpej * Change media according to request. 391 1.2 thorpej */ 392 1.103 maxv static int 393 1.72 dsl smc91cxx_mediachange(struct ifnet *ifp) 394 1.2 thorpej { 395 1.2 thorpej struct smc91cxx_softc *sc = ifp->if_softc; 396 1.2 thorpej 397 1.101 msaitoh return smc91cxx_set_media(sc, sc->sc_mii.mii_media.ifm_media); 398 1.2 thorpej } 399 1.2 thorpej 400 1.103 maxv static int 401 1.72 dsl smc91cxx_set_media(struct smc91cxx_softc *sc, int media) 402 1.2 thorpej { 403 1.2 thorpej bus_space_tag_t bst = sc->sc_bst; 404 1.2 thorpej bus_space_handle_t bsh = sc->sc_bsh; 405 1.101 msaitoh uint16_t tmp; 406 1.64 dyoung int rc; 407 1.2 thorpej 408 1.4 thorpej /* 409 1.4 thorpej * If the interface is not currently powered on, just return. 410 1.4 thorpej * When it is enabled later, smc91cxx_init() will properly set 411 1.4 thorpej * up the media for us. 412 1.4 thorpej */ 413 1.25 jhawk if ((sc->sc_flags & SMC_FLAGS_ENABLED) == 0) 414 1.101 msaitoh return 0; 415 1.4 thorpej 416 1.2 thorpej if (IFM_TYPE(media) != IFM_ETHER) 417 1.101 msaitoh return EINVAL; 418 1.2 thorpej 419 1.64 dyoung if ((sc->sc_flags & SMC_FLAGS_HAS_MII) == 0 || 420 1.64 dyoung (rc = mii_mediachg(&sc->sc_mii)) == ENXIO) 421 1.64 dyoung rc = 0; 422 1.26 briggs 423 1.2 thorpej switch (IFM_SUBTYPE(media)) { 424 1.2 thorpej case IFM_10_T: 425 1.2 thorpej case IFM_10_5: 426 1.2 thorpej SMC_SELECT_BANK(sc, 1); 427 1.2 thorpej tmp = bus_space_read_2(bst, bsh, CONFIG_REG_W); 428 1.2 thorpej if (IFM_SUBTYPE(media) == IFM_10_5) 429 1.2 thorpej tmp |= CR_AUI_SELECT; 430 1.2 thorpej else 431 1.2 thorpej tmp &= ~CR_AUI_SELECT; 432 1.2 thorpej bus_space_write_2(bst, bsh, CONFIG_REG_W, tmp); 433 1.2 thorpej delay(20000); /* XXX is this needed? */ 434 1.2 thorpej break; 435 1.2 thorpej 436 1.2 thorpej default: 437 1.101 msaitoh return EINVAL; 438 1.2 thorpej } 439 1.2 thorpej 440 1.64 dyoung return rc; 441 1.2 thorpej } 442 1.2 thorpej 443 1.2 thorpej /* 444 1.2 thorpej * Notify the world which media we're using. 445 1.2 thorpej */ 446 1.103 maxv static void 447 1.72 dsl smc91cxx_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr) 448 1.2 thorpej { 449 1.2 thorpej struct smc91cxx_softc *sc = ifp->if_softc; 450 1.2 thorpej bus_space_tag_t bst = sc->sc_bst; 451 1.2 thorpej bus_space_handle_t bsh = sc->sc_bsh; 452 1.101 msaitoh uint16_t tmp; 453 1.2 thorpej 454 1.25 jhawk if ((sc->sc_flags & SMC_FLAGS_ENABLED) == 0) { 455 1.4 thorpej ifmr->ifm_active = IFM_ETHER | IFM_NONE; 456 1.4 thorpej ifmr->ifm_status = 0; 457 1.4 thorpej return; 458 1.4 thorpej } 459 1.4 thorpej 460 1.101 msaitoh /* If we have MII, go ask the PHY what's going on. */ 461 1.26 briggs if (sc->sc_flags & SMC_FLAGS_HAS_MII) { 462 1.26 briggs mii_pollstat(&sc->sc_mii); 463 1.26 briggs ifmr->ifm_active = sc->sc_mii.mii_media_active; 464 1.26 briggs ifmr->ifm_status = sc->sc_mii.mii_media_status; 465 1.26 briggs return; 466 1.26 briggs } 467 1.26 briggs 468 1.2 thorpej SMC_SELECT_BANK(sc, 1); 469 1.2 thorpej tmp = bus_space_read_2(bst, bsh, CONFIG_REG_W); 470 1.2 thorpej ifmr->ifm_active = 471 1.2 thorpej IFM_ETHER | ((tmp & CR_AUI_SELECT) ? IFM_10_5 : IFM_10_T); 472 1.2 thorpej } 473 1.2 thorpej 474 1.2 thorpej /* 475 1.2 thorpej * Reset and initialize the chip. 476 1.2 thorpej */ 477 1.103 maxv static void 478 1.72 dsl smc91cxx_init(struct smc91cxx_softc *sc) 479 1.2 thorpej { 480 1.2 thorpej struct ifnet *ifp = &sc->sc_ec.ec_if; 481 1.2 thorpej bus_space_tag_t bst = sc->sc_bst; 482 1.2 thorpej bus_space_handle_t bsh = sc->sc_bsh; 483 1.101 msaitoh uint16_t tmp; 484 1.101 msaitoh const uint8_t *enaddr; 485 1.2 thorpej int s, i; 486 1.2 thorpej 487 1.11 mycroft s = splnet(); 488 1.2 thorpej 489 1.2 thorpej /* 490 1.46 wiz * This resets the registers mostly to defaults, but doesn't 491 1.85 chs * affect the EEPROM. The longest reset recovery time of those devices 492 1.85 chs * supported is the 91C111. Section 7.8 of its datasheet asks for 50ms. 493 1.2 thorpej */ 494 1.2 thorpej SMC_SELECT_BANK(sc, 0); 495 1.2 thorpej bus_space_write_2(bst, bsh, RECV_CONTROL_REG_W, RCR_SOFTRESET); 496 1.85 chs delay(5); 497 1.2 thorpej bus_space_write_2(bst, bsh, RECV_CONTROL_REG_W, 0); 498 1.85 chs delay(50000); 499 1.2 thorpej 500 1.2 thorpej bus_space_write_2(bst, bsh, TXMIT_CONTROL_REG_W, 0); 501 1.2 thorpej 502 1.2 thorpej /* Set the Ethernet address. */ 503 1.2 thorpej SMC_SELECT_BANK(sc, 1); 504 1.101 msaitoh enaddr = (const uint8_t *)CLLADDR(ifp->if_sadl); 505 1.2 thorpej for (i = 0; i < ETHER_ADDR_LEN; i += 2) { 506 1.2 thorpej tmp = enaddr[i + 1] << 8 | enaddr[i]; 507 1.2 thorpej bus_space_write_2(bst, bsh, IAR_ADDR0_REG_W + i, tmp); 508 1.2 thorpej } 509 1.2 thorpej 510 1.2 thorpej /* 511 1.2 thorpej * Set the control register to automatically release successfully 512 1.2 thorpej * transmitted packets (making the best use of our limited memory) 513 1.2 thorpej * and enable the EPH interrupt on certain TX errors. 514 1.2 thorpej */ 515 1.2 thorpej bus_space_write_2(bst, bsh, CONTROL_REG_W, (CTR_AUTO_RELEASE | 516 1.2 thorpej CTR_TE_ENABLE | CTR_CR_ENABLE | CTR_LE_ENABLE)); 517 1.2 thorpej 518 1.101 msaitoh /* Reset the MMU and wait for it to be un-busy. */ 519 1.2 thorpej SMC_SELECT_BANK(sc, 2); 520 1.2 thorpej bus_space_write_2(bst, bsh, MMU_CMD_REG_W, MMUCR_RESET); 521 1.67 matt sc->sc_txpacketno = ARR_FAILED; 522 1.48 mycroft for (;;) { 523 1.48 mycroft tmp = bus_space_read_2(bst, bsh, MMU_CMD_REG_W); 524 1.90 dholland if (tmp == 0xffff) { 525 1.101 msaitoh /* Card went away! */ 526 1.90 dholland splx(s); 527 1.48 mycroft return; 528 1.90 dholland } 529 1.48 mycroft if ((tmp & MMUCR_BUSY) == 0) 530 1.48 mycroft break; 531 1.48 mycroft } 532 1.2 thorpej 533 1.101 msaitoh /* Disable all interrupts. */ 534 1.67 matt smc91cxx_intr_mask_write(bst, bsh, 0); 535 1.2 thorpej 536 1.2 thorpej /* 537 1.45 scw * On the 91c111, enable auto-negotiation, and set the LED 538 1.45 scw * status pins to something sane. 539 1.45 scw * XXX: Should be some way for MD code to decide the latter. 540 1.45 scw */ 541 1.45 scw SMC_SELECT_BANK(sc, 0); 542 1.45 scw if (sc->sc_chipid == CHIP_91C111) { 543 1.45 scw bus_space_write_2(bst, bsh, RX_PHY_CONTROL_REG_W, 544 1.45 scw RPC_ANEG | 545 1.45 scw (RPC_LS_LINK_DETECT << RPC_LSA_SHIFT) | 546 1.45 scw (RPC_LS_TXRX << RPC_LSB_SHIFT)); 547 1.45 scw } 548 1.45 scw 549 1.101 msaitoh /* Set current media. */ 550 1.26 briggs smc91cxx_set_media(sc, sc->sc_mii.mii_media.ifm_cur->ifm_media); 551 1.2 thorpej 552 1.2 thorpej /* 553 1.2 thorpej * Set the receive filter. We want receive enable and auto 554 1.2 thorpej * strip of CRC from received packet. If we are in promisc. mode, 555 1.2 thorpej * then set that bit as well. 556 1.2 thorpej * 557 1.2 thorpej * XXX Initialize multicast filter. For now, we just accept 558 1.2 thorpej * XXX all multicast. 559 1.2 thorpej */ 560 1.2 thorpej SMC_SELECT_BANK(sc, 0); 561 1.2 thorpej 562 1.2 thorpej tmp = RCR_ENABLE | RCR_STRIP_CRC | RCR_ALMUL; 563 1.2 thorpej if (ifp->if_flags & IFF_PROMISC) 564 1.2 thorpej tmp |= RCR_PROMISC; 565 1.2 thorpej 566 1.2 thorpej bus_space_write_2(bst, bsh, RECV_CONTROL_REG_W, tmp); 567 1.2 thorpej 568 1.101 msaitoh /* Set transmitter control to "enabled". */ 569 1.2 thorpej tmp = TCR_ENABLE; 570 1.2 thorpej 571 1.2 thorpej #ifndef SMC91CXX_SW_PAD 572 1.2 thorpej /* 573 1.2 thorpej * Enable hardware padding of transmitted packets. 574 1.2 thorpej * XXX doesn't work? 575 1.2 thorpej */ 576 1.2 thorpej tmp |= TCR_PAD_ENABLE; 577 1.2 thorpej #endif 578 1.2 thorpej 579 1.2 thorpej bus_space_write_2(bst, bsh, TXMIT_CONTROL_REG_W, tmp); 580 1.2 thorpej 581 1.101 msaitoh /* Now, enable interrupts. */ 582 1.2 thorpej SMC_SELECT_BANK(sc, 2); 583 1.2 thorpej 584 1.67 matt sc->sc_intmask = IM_EPH_INT | IM_RX_OVRN_INT | IM_RCV_INT; 585 1.45 scw if (sc->sc_chipid == CHIP_91C111 && sc->sc_internal_phy) { 586 1.67 matt sc->sc_intmask |= IM_MD_INT; 587 1.45 scw } 588 1.67 matt smc91cxx_intr_mask_write(bst, bsh, sc->sc_intmask); 589 1.2 thorpej 590 1.2 thorpej /* Interface is now running, with no output active. */ 591 1.2 thorpej ifp->if_flags |= IFF_RUNNING; 592 1.2 thorpej ifp->if_flags &= ~IFF_OACTIVE; 593 1.2 thorpej 594 1.26 briggs if (sc->sc_flags & SMC_FLAGS_HAS_MII) { 595 1.26 briggs /* Start the one second clock. */ 596 1.106 thorpej callout_schedule(&sc->sc_mii_callout, hz); 597 1.26 briggs } 598 1.26 briggs 599 1.101 msaitoh /* Attempt to start any pending transmission. */ 600 1.2 thorpej smc91cxx_start(ifp); 601 1.2 thorpej 602 1.2 thorpej splx(s); 603 1.2 thorpej } 604 1.2 thorpej 605 1.2 thorpej /* 606 1.2 thorpej * Start output on an interface. 607 1.11 mycroft * Must be called at splnet or interrupt level. 608 1.2 thorpej */ 609 1.103 maxv static void 610 1.72 dsl smc91cxx_start(struct ifnet *ifp) 611 1.2 thorpej { 612 1.2 thorpej struct smc91cxx_softc *sc = ifp->if_softc; 613 1.2 thorpej bus_space_tag_t bst = sc->sc_bst; 614 1.2 thorpej bus_space_handle_t bsh = sc->sc_bsh; 615 1.2 thorpej u_int len; 616 1.43 scw struct mbuf *m; 617 1.101 msaitoh uint16_t length, npages; 618 1.101 msaitoh uint16_t oddbyte; 619 1.101 msaitoh uint8_t packetno; 620 1.2 thorpej int timo, pad; 621 1.2 thorpej 622 1.2 thorpej if ((ifp->if_flags & (IFF_RUNNING|IFF_OACTIVE)) != IFF_RUNNING) 623 1.2 thorpej return; 624 1.2 thorpej 625 1.2 thorpej again: 626 1.101 msaitoh /* Peek at the next packet. */ 627 1.32 thorpej IFQ_POLL(&ifp->if_snd, m); 628 1.32 thorpej if (m == NULL) 629 1.2 thorpej return; 630 1.2 thorpej 631 1.2 thorpej /* 632 1.2 thorpej * Compute the frame length and set pad to give an overall even 633 1.2 thorpej * number of bytes. Below, we assume that the packet length 634 1.2 thorpej * is even. 635 1.2 thorpej */ 636 1.43 scw for (len = 0; m != NULL; m = m->m_next) 637 1.2 thorpej len += m->m_len; 638 1.2 thorpej 639 1.2 thorpej /* 640 1.101 msaitoh * We drop packets that are too large. Perhaps we should 641 1.2 thorpej * truncate them instead? 642 1.2 thorpej */ 643 1.85 chs if (len > (ETHER_MAX_LEN - ETHER_CRC_LEN)) { 644 1.85 chs printf("%s: large packet discarded\n", 645 1.85 chs device_xname(sc->sc_dev)); 646 1.104 thorpej if_statinc(ifp, if_oerrors); 647 1.32 thorpej IFQ_DEQUEUE(&ifp->if_snd, m); 648 1.2 thorpej m_freem(m); 649 1.2 thorpej goto readcheck; 650 1.2 thorpej } 651 1.2 thorpej 652 1.85 chs pad = 0; 653 1.2 thorpej #ifdef SMC91CXX_SW_PAD 654 1.101 msaitoh /* Not using hardware padding; pad to ETHER_MIN_LEN. */ 655 1.2 thorpej if (len < (ETHER_MIN_LEN - ETHER_CRC_LEN)) 656 1.2 thorpej pad = ETHER_MIN_LEN - ETHER_CRC_LEN - len; 657 1.2 thorpej #endif 658 1.2 thorpej 659 1.2 thorpej length = pad + len; 660 1.2 thorpej 661 1.2 thorpej /* 662 1.2 thorpej * The MMU has a 256 byte page size. The MMU expects us to 663 1.2 thorpej * ask for "npages - 1". We include space for the status word, 664 1.2 thorpej * byte count, and control bytes in the allocation request. 665 1.2 thorpej */ 666 1.67 matt npages = ((length & ~1) + 6) >> 8; 667 1.2 thorpej 668 1.101 msaitoh /* Now allocate the memory. */ 669 1.2 thorpej SMC_SELECT_BANK(sc, 2); 670 1.2 thorpej bus_space_write_2(bst, bsh, MMU_CMD_REG_W, MMUCR_ALLOC | npages); 671 1.2 thorpej 672 1.2 thorpej timo = MEMORY_WAIT_TIME; 673 1.67 matt if (__predict_false((sc->sc_txpacketno & ARR_FAILED) == 0)) { 674 1.67 matt packetno = sc->sc_txpacketno; 675 1.67 matt sc->sc_txpacketno = ARR_FAILED; 676 1.67 matt } else { 677 1.67 matt do { 678 1.67 matt if (bus_space_read_1(bst, bsh, 679 1.101 msaitoh INTR_STAT_REG_B) & IM_ALLOC_INT) 680 1.67 matt break; 681 1.67 matt delay(1); 682 1.67 matt } while (--timo); 683 1.67 matt } 684 1.2 thorpej 685 1.2 thorpej packetno = bus_space_read_1(bst, bsh, ALLOC_RESULT_REG_B); 686 1.2 thorpej 687 1.2 thorpej if (packetno & ARR_FAILED || timo == 0) { 688 1.2 thorpej /* 689 1.2 thorpej * No transmit memory is available. Record the number 690 1.85 chs * of requested pages and enable the allocation completion 691 1.2 thorpej * interrupt. Set up the watchdog timer in case we miss 692 1.2 thorpej * the interrupt. Mark the interface as active so that 693 1.2 thorpej * no one else attempts to transmit while we're allocating 694 1.2 thorpej * memory. 695 1.2 thorpej */ 696 1.67 matt sc->sc_intmask |= IM_ALLOC_INT; 697 1.67 matt smc91cxx_intr_mask_write(bst, bsh, sc->sc_intmask); 698 1.2 thorpej ifp->if_timer = 5; 699 1.2 thorpej ifp->if_flags |= IFF_OACTIVE; 700 1.2 thorpej 701 1.2 thorpej return; 702 1.2 thorpej } 703 1.2 thorpej 704 1.101 msaitoh /* We have a packet number - set the data window. */ 705 1.85 chs bus_space_write_2(bst, bsh, PACKET_NUM_REG_B, packetno); 706 1.2 thorpej 707 1.101 msaitoh /* Point to the beginning of the packet. */ 708 1.2 thorpej bus_space_write_2(bst, bsh, POINTER_REG_W, PTR_AUTOINC /* | 0x0000 */); 709 1.2 thorpej 710 1.2 thorpej /* 711 1.2 thorpej * Send the packet length (+6 for stats, length, and control bytes) 712 1.2 thorpej * and the status word (set to zeros). 713 1.2 thorpej */ 714 1.2 thorpej bus_space_write_2(bst, bsh, DATA_REG_W, 0); 715 1.52 pooka bus_space_write_2(bst, bsh, DATA_REG_W, (length + 6) & 0x7ff); 716 1.2 thorpej 717 1.2 thorpej /* 718 1.2 thorpej * Get the packet from the kernel. This will include the Ethernet 719 1.2 thorpej * frame header, MAC address, etc. 720 1.2 thorpej */ 721 1.32 thorpej IFQ_DEQUEUE(&ifp->if_snd, m); 722 1.2 thorpej 723 1.2 thorpej /* 724 1.85 chs * Push the packet out to the card. The copying function only does 725 1.85 chs * whole words and returns the straggling byte (if any). 726 1.2 thorpej */ 727 1.67 matt oddbyte = smc91cxx_copy_tx_frame(sc, m); 728 1.2 thorpej 729 1.2 thorpej #ifdef SMC91CXX_SW_PAD 730 1.67 matt if (pad > 1 && (pad & 1)) { 731 1.85 chs bus_space_write_2(bst, bsh, DATA_REG_W, oddbyte); 732 1.67 matt oddbyte = 0; 733 1.85 chs pad -= 1; 734 1.67 matt } 735 1.67 matt 736 1.101 msaitoh /* Push out padding. */ 737 1.2 thorpej while (pad > 1) { 738 1.2 thorpej bus_space_write_2(bst, bsh, DATA_REG_W, 0); 739 1.2 thorpej pad -= 2; 740 1.2 thorpej } 741 1.2 thorpej #endif 742 1.2 thorpej 743 1.2 thorpej /* 744 1.2 thorpej * Push out control byte and unused packet byte. The control byte 745 1.85 chs * denotes whether this is an odd or even length packet, and that 746 1.85 chs * no special CRC handling is necessary. 747 1.2 thorpej */ 748 1.67 matt bus_space_write_2(bst, bsh, DATA_REG_W, 749 1.85 chs oddbyte | ((length & 1) ? (CTLB_ODD << 8) : 0)); 750 1.2 thorpej 751 1.2 thorpej /* 752 1.2 thorpej * Enable transmit interrupts and let the chip go. Set a watchdog 753 1.2 thorpej * in case we miss the interrupt. 754 1.2 thorpej */ 755 1.67 matt sc->sc_intmask |= IM_TX_INT | IM_TX_EMPTY_INT; 756 1.67 matt smc91cxx_intr_mask_write(bst, bsh, sc->sc_intmask); 757 1.2 thorpej 758 1.2 thorpej bus_space_write_2(bst, bsh, MMU_CMD_REG_W, MMUCR_ENQUEUE); 759 1.2 thorpej 760 1.2 thorpej ifp->if_timer = 5; 761 1.2 thorpej 762 1.2 thorpej /* Hand off a copy to the bpf. */ 763 1.97 msaitoh bpf_mtap(ifp, m, BPF_D_OUT); 764 1.2 thorpej 765 1.104 thorpej if_statinc(ifp, if_opackets); 766 1.43 scw m_freem(m); 767 1.2 thorpej 768 1.2 thorpej readcheck: 769 1.2 thorpej /* 770 1.85 chs * Check for incoming packets. We don't want to overflow the small 771 1.2 thorpej * RX FIFO. If nothing has arrived, attempt to queue another 772 1.2 thorpej * transmit packet. 773 1.2 thorpej */ 774 1.2 thorpej if (bus_space_read_2(bst, bsh, FIFO_PORTS_REG_W) & FIFO_REMPTY) 775 1.2 thorpej goto again; 776 1.2 thorpej } 777 1.2 thorpej 778 1.2 thorpej /* 779 1.43 scw * Squirt a (possibly misaligned) mbuf to the device 780 1.43 scw */ 781 1.103 maxv static uint8_t 782 1.72 dsl smc91cxx_copy_tx_frame(struct smc91cxx_softc *sc, struct mbuf *m0) 783 1.43 scw { 784 1.43 scw bus_space_tag_t bst = sc->sc_bst; 785 1.43 scw bus_space_handle_t bsh = sc->sc_bsh; 786 1.43 scw struct mbuf *m; 787 1.43 scw int len, leftover; 788 1.101 msaitoh uint16_t dbuf; 789 1.101 msaitoh uint8_t *p; 790 1.43 scw #ifdef DIAGNOSTIC 791 1.101 msaitoh uint8_t *lim; 792 1.43 scw #endif 793 1.43 scw 794 1.101 msaitoh /* Start out with no leftover data */ 795 1.43 scw leftover = 0; 796 1.43 scw dbuf = 0; 797 1.43 scw 798 1.43 scw /* Process the chain of mbufs */ 799 1.43 scw for (m = m0; m != NULL; m = m->m_next) { 800 1.101 msaitoh /* Process all of the data in a single mbuf. */ 801 1.101 msaitoh p = mtod(m, uint8_t *); 802 1.43 scw len = m->m_len; 803 1.43 scw #ifdef DIAGNOSTIC 804 1.43 scw lim = p + len; 805 1.43 scw #endif 806 1.43 scw 807 1.43 scw while (len > 0) { 808 1.43 scw if (leftover) { 809 1.43 scw /* 810 1.43 scw * Data left over (from mbuf or realignment). 811 1.43 scw * Buffer the next byte, and write it and 812 1.43 scw * the leftover data out. 813 1.43 scw */ 814 1.43 scw dbuf |= *p++ << 8; 815 1.43 scw len--; 816 1.43 scw bus_space_write_2(bst, bsh, DATA_REG_W, dbuf); 817 1.43 scw leftover = 0; 818 1.43 scw } else if ((long) p & 1) { 819 1.101 msaitoh /* Misaligned data. Buffer the next byte. */ 820 1.43 scw dbuf = *p++; 821 1.43 scw len--; 822 1.43 scw leftover = 1; 823 1.43 scw } else { 824 1.43 scw /* 825 1.43 scw * Aligned data. This is the case we like. 826 1.43 scw * 827 1.43 scw * Write-region out as much as we can, then 828 1.43 scw * buffer the remaining byte (if any). 829 1.43 scw */ 830 1.43 scw leftover = len & 1; 831 1.43 scw len &= ~1; 832 1.43 scw bus_space_write_multi_stream_2(bst, bsh, 833 1.101 msaitoh DATA_REG_W, (uint16_t *)p, len >> 1); 834 1.43 scw p += len; 835 1.43 scw 836 1.43 scw if (leftover) 837 1.43 scw dbuf = *p++; 838 1.43 scw len = 0; 839 1.43 scw } 840 1.43 scw } 841 1.43 scw if (len < 0) 842 1.43 scw panic("smc91cxx_copy_tx_frame: negative len"); 843 1.43 scw #ifdef DIAGNOSTIC 844 1.43 scw if (p != lim) 845 1.43 scw panic("smc91cxx_copy_tx_frame: p != lim"); 846 1.43 scw #endif 847 1.43 scw } 848 1.85 chs 849 1.67 matt return dbuf; 850 1.43 scw } 851 1.43 scw 852 1.43 scw /* 853 1.2 thorpej * Interrupt service routine. 854 1.2 thorpej */ 855 1.2 thorpej int 856 1.72 dsl smc91cxx_intr(void *arg) 857 1.2 thorpej { 858 1.2 thorpej struct smc91cxx_softc *sc = arg; 859 1.2 thorpej struct ifnet *ifp = &sc->sc_ec.ec_if; 860 1.2 thorpej bus_space_tag_t bst = sc->sc_bst; 861 1.2 thorpej bus_space_handle_t bsh = sc->sc_bsh; 862 1.101 msaitoh uint8_t mask, interrupts, status; 863 1.101 msaitoh uint16_t packetno, tx_status, card_stats; 864 1.101 msaitoh uint16_t v; 865 1.2 thorpej 866 1.25 jhawk if ((sc->sc_flags & SMC_FLAGS_ENABLED) == 0 || 867 1.83 chs !device_is_active(sc->sc_dev)) 868 1.101 msaitoh return 0; 869 1.4 thorpej 870 1.2 thorpej SMC_SELECT_BANK(sc, 2); 871 1.2 thorpej 872 1.101 msaitoh /* Obtain the current interrupt status and mask. */ 873 1.67 matt v = bus_space_read_2(bst, bsh, INTR_STAT_REG_B); 874 1.2 thorpej 875 1.2 thorpej /* 876 1.2 thorpej * Get the set of interrupt which occurred and eliminate any 877 1.2 thorpej * which are not enabled. 878 1.2 thorpej */ 879 1.67 matt mask = v >> 8; 880 1.67 matt interrupts = v & 0xff; 881 1.67 matt KDASSERT(mask == sc->sc_intmask); 882 1.2 thorpej status = interrupts & mask; 883 1.2 thorpej 884 1.2 thorpej /* Ours? */ 885 1.2 thorpej if (status == 0) 886 1.101 msaitoh return 0; 887 1.2 thorpej 888 1.101 msaitoh /* It's ours; disable all interrupts while we process them. */ 889 1.67 matt smc91cxx_intr_mask_write(bst, bsh, 0); 890 1.2 thorpej 891 1.101 msaitoh /* Receive overrun interrupts. */ 892 1.2 thorpej if (status & IM_RX_OVRN_INT) { 893 1.85 chs smc91cxx_intr_ack_write(bst, bsh, IM_RX_OVRN_INT, 0); 894 1.104 thorpej if_statinc(ifp, if_ierrors); 895 1.2 thorpej } 896 1.2 thorpej 897 1.101 msaitoh /* Receive interrupts. */ 898 1.2 thorpej if (status & IM_RCV_INT) { 899 1.2 thorpej smc91cxx_read(sc); 900 1.2 thorpej } 901 1.2 thorpej 902 1.101 msaitoh /* Memory allocation interrupts. */ 903 1.2 thorpej if (status & IM_ALLOC_INT) { 904 1.2 thorpej /* Disable this interrupt. */ 905 1.2 thorpej mask &= ~IM_ALLOC_INT; 906 1.67 matt sc->sc_intmask &= ~IM_ALLOC_INT; 907 1.2 thorpej 908 1.101 msaitoh /* Save allocated packet number for use in start */ 909 1.67 matt packetno = bus_space_read_1(bst, bsh, ALLOC_RESULT_REG_B); 910 1.67 matt KASSERT(sc->sc_txpacketno & ARR_FAILED); 911 1.67 matt sc->sc_txpacketno = packetno; 912 1.2 thorpej 913 1.101 msaitoh /* We can transmit again! */ 914 1.2 thorpej ifp->if_flags &= ~IFF_OACTIVE; 915 1.2 thorpej ifp->if_timer = 0; 916 1.2 thorpej } 917 1.2 thorpej 918 1.2 thorpej /* 919 1.2 thorpej * Transmit complete interrupt. Handle transmission error messages. 920 1.2 thorpej * This will only be called on error condition because of AUTO RELEASE 921 1.2 thorpej * mode. 922 1.2 thorpej */ 923 1.2 thorpej if (status & IM_TX_INT) { 924 1.85 chs smc91cxx_intr_ack_write(bst, bsh, IM_TX_INT, 0); 925 1.2 thorpej 926 1.2 thorpej packetno = bus_space_read_2(bst, bsh, FIFO_PORTS_REG_W) & 927 1.2 thorpej FIFO_TX_MASK; 928 1.2 thorpej 929 1.101 msaitoh /* Select this as the packet to read from. */ 930 1.85 chs bus_space_write_2(bst, bsh, PACKET_NUM_REG_B, packetno); 931 1.2 thorpej 932 1.2 thorpej /* 933 1.85 chs * Position the pointer to the beginning of the packet, wait 934 1.85 chs * for preload. 935 1.2 thorpej */ 936 1.2 thorpej bus_space_write_2(bst, bsh, POINTER_REG_W, 937 1.2 thorpej PTR_AUTOINC | PTR_READ /* | 0x0000 */); 938 1.85 chs delay(1); 939 1.2 thorpej 940 1.2 thorpej /* 941 1.2 thorpej * Fetch the TX status word. This will be a copy of 942 1.2 thorpej * the EPH_STATUS_REG_W at the time of the transmission 943 1.2 thorpej * failure. 944 1.2 thorpej */ 945 1.2 thorpej tx_status = bus_space_read_2(bst, bsh, DATA_REG_W); 946 1.2 thorpej 947 1.67 matt if (tx_status & EPHSR_TX_SUC) { 948 1.67 matt static struct timeval txsuc_last; 949 1.67 matt static int txsuc_count; 950 1.67 matt if (ppsratecheck(&txsuc_last, &txsuc_count, 1)) 951 1.67 matt printf("%s: successful packet caused TX" 952 1.83 chs " interrupt?!\n", device_xname(sc->sc_dev)); 953 1.67 matt } else 954 1.104 thorpej if_statinc(ifp, if_oerrors); 955 1.2 thorpej 956 1.2 thorpej if (tx_status & EPHSR_LATCOL) 957 1.104 thorpej if_statinc(ifp, if_collisions); 958 1.2 thorpej 959 1.67 matt /* Disable this interrupt (start will reenable if needed). */ 960 1.67 matt mask &= ~IM_TX_INT; 961 1.67 matt sc->sc_intmask &= ~IM_TX_INT; 962 1.67 matt 963 1.2 thorpej /* 964 1.2 thorpej * Some of these errors disable the transmitter; reenable it. 965 1.2 thorpej */ 966 1.2 thorpej SMC_SELECT_BANK(sc, 0); 967 1.2 thorpej #ifdef SMC91CXX_SW_PAD 968 1.2 thorpej bus_space_write_2(bst, bsh, TXMIT_CONTROL_REG_W, TCR_ENABLE); 969 1.2 thorpej #else 970 1.2 thorpej bus_space_write_2(bst, bsh, TXMIT_CONTROL_REG_W, 971 1.2 thorpej TCR_ENABLE | TCR_PAD_ENABLE); 972 1.2 thorpej #endif 973 1.2 thorpej 974 1.101 msaitoh /* Kill the failed packet and wait for the MMU to unbusy. */ 975 1.2 thorpej SMC_SELECT_BANK(sc, 2); 976 1.2 thorpej while (bus_space_read_2(bst, bsh, MMU_CMD_REG_W) & MMUCR_BUSY) 977 1.2 thorpej /* XXX bound this loop! */ ; 978 1.2 thorpej bus_space_write_2(bst, bsh, MMU_CMD_REG_W, MMUCR_FREEPKT); 979 1.2 thorpej 980 1.2 thorpej ifp->if_timer = 0; 981 1.2 thorpej } 982 1.2 thorpej 983 1.2 thorpej /* 984 1.2 thorpej * Transmit underrun interrupts. We use this opportunity to 985 1.2 thorpej * update transmit statistics from the card. 986 1.2 thorpej */ 987 1.2 thorpej if (status & IM_TX_EMPTY_INT) { 988 1.85 chs smc91cxx_intr_ack_write(bst, bsh, IM_TX_EMPTY_INT, 0); 989 1.2 thorpej 990 1.2 thorpej /* Disable this interrupt. */ 991 1.2 thorpej mask &= ~IM_TX_EMPTY_INT; 992 1.67 matt sc->sc_intmask &= ~IM_TX_EMPTY_INT; 993 1.2 thorpej 994 1.2 thorpej SMC_SELECT_BANK(sc, 0); 995 1.2 thorpej card_stats = bus_space_read_2(bst, bsh, COUNTER_REG_W); 996 1.2 thorpej 997 1.2 thorpej /* Single collisions. */ 998 1.104 thorpej if (card_stats & ECR_COLN_MASK) 999 1.104 thorpej if_statadd(ifp, if_collisions, 1000 1.104 thorpej card_stats & ECR_COLN_MASK); 1001 1.2 thorpej 1002 1.2 thorpej /* Multiple collisions. */ 1003 1.104 thorpej if ((card_stats & ECR_MCOLN_MASK) >> 4) 1004 1.104 thorpej if_statadd(ifp, if_collisions, 1005 1.104 thorpej (card_stats & ECR_MCOLN_MASK) >> 4); 1006 1.2 thorpej 1007 1.2 thorpej SMC_SELECT_BANK(sc, 2); 1008 1.2 thorpej 1009 1.2 thorpej ifp->if_timer = 0; 1010 1.45 scw } 1011 1.45 scw 1012 1.101 msaitoh /* Internal PHY status change */ 1013 1.45 scw if (sc->sc_chipid == CHIP_91C111 && sc->sc_internal_phy && 1014 1.45 scw (status & IM_MD_INT)) { 1015 1.85 chs 1016 1.101 msaitoh /* Internal PHY status change */ 1017 1.85 chs smc91cxx_intr_ack_write(bst, bsh, IM_MD_INT, 0); 1018 1.84 msaitoh mii_pollstat(&sc->sc_mii); 1019 1.2 thorpej } 1020 1.2 thorpej 1021 1.101 msaitoh /* Other errors. Reset the interface. */ 1022 1.2 thorpej if (status & IM_EPH_INT) { 1023 1.2 thorpej smc91cxx_stop(sc); 1024 1.2 thorpej smc91cxx_init(sc); 1025 1.2 thorpej } 1026 1.2 thorpej 1027 1.101 msaitoh /* Attempt to queue more packets for transmission. */ 1028 1.95 ozaki if_schedule_deferred_start(ifp); 1029 1.2 thorpej 1030 1.2 thorpej /* 1031 1.2 thorpej * Reenable the interrupts we wish to receive now that processing 1032 1.2 thorpej * is complete. 1033 1.2 thorpej */ 1034 1.67 matt mask |= sc->sc_intmask; 1035 1.67 matt smc91cxx_intr_mask_write(bst, bsh, mask); 1036 1.5 explorer 1037 1.5 explorer if (status) 1038 1.5 explorer rnd_add_uint32(&sc->rnd_source, status); 1039 1.2 thorpej 1040 1.101 msaitoh return 1; 1041 1.2 thorpej } 1042 1.2 thorpej 1043 1.2 thorpej /* 1044 1.2 thorpej * Read a packet from the card and pass it up to the kernel. 1045 1.2 thorpej * NOTE! WE EXPECT TO BE IN REGISTER WINDOW 2! 1046 1.2 thorpej */ 1047 1.103 maxv static void 1048 1.72 dsl smc91cxx_read(struct smc91cxx_softc *sc) 1049 1.2 thorpej { 1050 1.2 thorpej struct ifnet *ifp = &sc->sc_ec.ec_if; 1051 1.2 thorpej bus_space_tag_t bst = sc->sc_bst; 1052 1.2 thorpej bus_space_handle_t bsh = sc->sc_bsh; 1053 1.2 thorpej struct ether_header *eh; 1054 1.2 thorpej struct mbuf *m; 1055 1.101 msaitoh uint16_t status, packetno, packetlen; 1056 1.101 msaitoh uint8_t *data; 1057 1.101 msaitoh uint32_t dr; 1058 1.85 chs bool first = true; 1059 1.2 thorpej 1060 1.2 thorpej again: 1061 1.2 thorpej /* 1062 1.2 thorpej * Set data pointer to the beginning of the packet. Since 1063 1.2 thorpej * PTR_RCV is set, the packet number will be found automatically 1064 1.2 thorpej * in FIFO_PORTS_REG_W, FIFO_RX_MASK. 1065 1.2 thorpej */ 1066 1.67 matt packetno = bus_space_read_2(bst, bsh, FIFO_PORTS_REG_W); 1067 1.85 chs if (packetno & FIFO_REMPTY) { 1068 1.85 chs if (first) { 1069 1.85 chs aprint_error_dev(sc->sc_dev, 1070 1.85 chs "receive interrupt on empty fifo\n"); 1071 1.85 chs } 1072 1.67 matt return; 1073 1.85 chs } 1074 1.85 chs first = false; 1075 1.67 matt 1076 1.2 thorpej bus_space_write_2(bst, bsh, POINTER_REG_W, 1077 1.2 thorpej PTR_READ | PTR_RCV | PTR_AUTOINC /* | 0x0000 */); 1078 1.85 chs delay(1); 1079 1.2 thorpej 1080 1.101 msaitoh /* First two words are status and packet length. */ 1081 1.85 chs dr = bus_space_read_4(bst, bsh, DATA_REG_W); 1082 1.101 msaitoh status = (uint16_t)dr; 1083 1.101 msaitoh packetlen = (uint16_t)(dr >> 16); 1084 1.41 scw 1085 1.41 scw packetlen &= RLEN_MASK; 1086 1.67 matt if (packetlen < ETHER_MIN_LEN - ETHER_CRC_LEN + 6 || packetlen > 1534) { 1087 1.104 thorpej if_statinc(ifp, if_ierrors); 1088 1.67 matt goto out; 1089 1.67 matt } 1090 1.2 thorpej 1091 1.2 thorpej /* 1092 1.2 thorpej * The packet length includes 3 extra words: status, length, 1093 1.2 thorpej * and an extra word that includes the control byte. 1094 1.2 thorpej */ 1095 1.2 thorpej packetlen -= 6; 1096 1.2 thorpej 1097 1.101 msaitoh /* Account for receive errors and discard. */ 1098 1.2 thorpej if (status & RS_ERRORS) { 1099 1.104 thorpej if_statinc(ifp, if_ierrors); 1100 1.2 thorpej goto out; 1101 1.2 thorpej } 1102 1.2 thorpej 1103 1.101 msaitoh /* Adjust for odd-length packet. */ 1104 1.2 thorpej if (status & RS_ODDFRAME) 1105 1.2 thorpej packetlen++; 1106 1.2 thorpej 1107 1.101 msaitoh /* Allocate a header mbuf. */ 1108 1.2 thorpej MGETHDR(m, M_DONTWAIT, MT_DATA); 1109 1.2 thorpej if (m == NULL) 1110 1.2 thorpej goto out; 1111 1.92 ozaki m_set_rcvif(m, ifp); 1112 1.33 itojun m->m_pkthdr.len = packetlen; 1113 1.2 thorpej 1114 1.2 thorpej /* 1115 1.2 thorpej * Always put the packet in a cluster. 1116 1.2 thorpej * XXX should chain small mbufs if less than threshold. 1117 1.2 thorpej */ 1118 1.2 thorpej MCLGET(m, M_DONTWAIT); 1119 1.2 thorpej if ((m->m_flags & M_EXT) == 0) { 1120 1.2 thorpej m_freem(m); 1121 1.104 thorpej if_statinc(ifp, if_ierrors); 1122 1.85 chs aprint_error_dev(sc->sc_dev, 1123 1.85 chs "can't allocate cluster for incoming packet\n"); 1124 1.2 thorpej goto out; 1125 1.2 thorpej } 1126 1.2 thorpej 1127 1.2 thorpej /* 1128 1.38 thorpej * Pull the packet off the interface. Make sure the payload 1129 1.38 thorpej * is aligned. 1130 1.2 thorpej */ 1131 1.41 scw if ((sc->sc_flags & SMC_FLAGS_32BIT_READ) == 0) { 1132 1.101 msaitoh m->m_data = (char *)ALIGN(mtod(m, char *) + 1133 1.41 scw sizeof(struct ether_header)) - sizeof(struct ether_header); 1134 1.41 scw 1135 1.41 scw eh = mtod(m, struct ether_header *); 1136 1.101 msaitoh data = mtod(m, uint8_t *); 1137 1.85 chs KASSERT(trunc_page((uintptr_t)data) == 1138 1.85 chs trunc_page((uintptr_t)data + packetlen - 1)); 1139 1.41 scw if (packetlen > 1) 1140 1.41 scw bus_space_read_multi_stream_2(bst, bsh, DATA_REG_W, 1141 1.101 msaitoh (uint16_t *)data, packetlen >> 1); 1142 1.41 scw if (packetlen & 1) { 1143 1.41 scw data += packetlen & ~1; 1144 1.41 scw *data = bus_space_read_1(bst, bsh, DATA_REG_B); 1145 1.41 scw } 1146 1.41 scw } else { 1147 1.101 msaitoh m->m_data = (void *)ALIGN(mtod(m, void *)); 1148 1.41 scw eh = mtod(m, struct ether_header *); 1149 1.101 msaitoh data = mtod(m, uint8_t *); 1150 1.85 chs KASSERT(trunc_page((uintptr_t)data) == 1151 1.85 chs trunc_page((uintptr_t)data + packetlen - 1)); 1152 1.41 scw if (packetlen > 3) 1153 1.41 scw bus_space_read_multi_stream_4(bst, bsh, DATA_REG_W, 1154 1.101 msaitoh (uint32_t *)data, packetlen >> 2); 1155 1.41 scw if (packetlen & 3) { 1156 1.41 scw data += packetlen & ~3; 1157 1.101 msaitoh *((uint32_t *)data) = 1158 1.41 scw bus_space_read_stream_4(bst, bsh, DATA_REG_W); 1159 1.41 scw } 1160 1.2 thorpej } 1161 1.2 thorpej 1162 1.21 itojun /* 1163 1.21 itojun * Make sure to behave as IFF_SIMPLEX in all cases. 1164 1.21 itojun * This is to cope with SMC91C92 (Megahertz XJ10BT), which 1165 1.21 itojun * loops back packets to itself on promiscuous mode. 1166 1.21 itojun * (should be ensured by chipset configuration) 1167 1.21 itojun */ 1168 1.19 itojun if ((ifp->if_flags & IFF_PROMISC) != 0) { 1169 1.101 msaitoh /* Drop packet looped back from myself. */ 1170 1.61 dyoung if (ether_cmp(eh->ether_shost, CLLADDR(ifp->if_sadl)) == 0) { 1171 1.2 thorpej m_freem(m); 1172 1.2 thorpej goto out; 1173 1.2 thorpej } 1174 1.2 thorpej } 1175 1.21 itojun 1176 1.43 scw m->m_pkthdr.len = m->m_len = packetlen; 1177 1.43 scw 1178 1.91 ozaki if_percpuq_enqueue(ifp->if_percpuq, m); 1179 1.2 thorpej 1180 1.2 thorpej out: 1181 1.101 msaitoh /* Tell the card to free the memory occupied by this packet. */ 1182 1.2 thorpej while (bus_space_read_2(bst, bsh, MMU_CMD_REG_W) & MMUCR_BUSY) 1183 1.2 thorpej /* XXX bound this loop! */ ; 1184 1.2 thorpej bus_space_write_2(bst, bsh, MMU_CMD_REG_W, MMUCR_RELEASE); 1185 1.2 thorpej 1186 1.101 msaitoh /* Check for another packet. */ 1187 1.2 thorpej goto again; 1188 1.2 thorpej } 1189 1.2 thorpej 1190 1.2 thorpej /* 1191 1.2 thorpej * Process an ioctl request. 1192 1.2 thorpej */ 1193 1.103 maxv static int 1194 1.72 dsl smc91cxx_ioctl(struct ifnet *ifp, u_long cmd, void *data) 1195 1.2 thorpej { 1196 1.2 thorpej struct smc91cxx_softc *sc = ifp->if_softc; 1197 1.2 thorpej struct ifaddr *ifa = (struct ifaddr *)data; 1198 1.2 thorpej int s, error = 0; 1199 1.2 thorpej 1200 1.11 mycroft s = splnet(); 1201 1.2 thorpej 1202 1.2 thorpej switch (cmd) { 1203 1.71 dyoung case SIOCINITIFADDR: 1204 1.4 thorpej if ((error = smc91cxx_enable(sc)) != 0) 1205 1.4 thorpej break; 1206 1.2 thorpej ifp->if_flags |= IFF_UP; 1207 1.71 dyoung smc91cxx_init(sc); 1208 1.2 thorpej switch (ifa->ifa_addr->sa_family) { 1209 1.2 thorpej #ifdef INET 1210 1.2 thorpej case AF_INET: 1211 1.71 dyoung arp_ifinit(ifp, ifa); 1212 1.71 dyoung break; 1213 1.2 thorpej #endif 1214 1.2 thorpej default: 1215 1.2 thorpej break; 1216 1.2 thorpej } 1217 1.2 thorpej break; 1218 1.2 thorpej 1219 1.2 thorpej 1220 1.2 thorpej case SIOCSIFFLAGS: 1221 1.71 dyoung if ((error = ifioctl_common(ifp, cmd, data)) != 0) 1222 1.71 dyoung break; 1223 1.71 dyoung /* XXX re-use ether_ioctl() */ 1224 1.71 dyoung switch (ifp->if_flags & (IFF_UP|IFF_RUNNING)) { 1225 1.71 dyoung case IFF_RUNNING: 1226 1.2 thorpej /* 1227 1.2 thorpej * If interface is marked down and it is running, 1228 1.2 thorpej * stop it. 1229 1.2 thorpej */ 1230 1.2 thorpej smc91cxx_stop(sc); 1231 1.2 thorpej ifp->if_flags &= ~IFF_RUNNING; 1232 1.4 thorpej smc91cxx_disable(sc); 1233 1.71 dyoung break; 1234 1.71 dyoung case IFF_UP: 1235 1.2 thorpej /* 1236 1.2 thorpej * If interface is marked up and it is stopped, 1237 1.2 thorpej * start it. 1238 1.2 thorpej */ 1239 1.4 thorpej if ((error = smc91cxx_enable(sc)) != 0) 1240 1.4 thorpej break; 1241 1.2 thorpej smc91cxx_init(sc); 1242 1.71 dyoung break; 1243 1.71 dyoung case IFF_UP|IFF_RUNNING: 1244 1.2 thorpej /* 1245 1.2 thorpej * Reset the interface to pick up changes in any 1246 1.2 thorpej * other flags that affect hardware registers. 1247 1.2 thorpej */ 1248 1.2 thorpej smc91cxx_reset(sc); 1249 1.71 dyoung break; 1250 1.71 dyoung case 0: 1251 1.71 dyoung break; 1252 1.2 thorpej } 1253 1.2 thorpej break; 1254 1.2 thorpej 1255 1.2 thorpej case SIOCADDMULTI: 1256 1.2 thorpej case SIOCDELMULTI: 1257 1.25 jhawk if ((sc->sc_flags & SMC_FLAGS_ENABLED) == 0) { 1258 1.4 thorpej error = EIO; 1259 1.4 thorpej break; 1260 1.4 thorpej } 1261 1.4 thorpej 1262 1.100 msaitoh /* FALLTHROUGH */ 1263 1.100 msaitoh default: 1264 1.62 dyoung if ((error = ether_ioctl(ifp, cmd, data)) == ENETRESET) { 1265 1.2 thorpej /* 1266 1.2 thorpej * Multicast list has changed; set the hardware 1267 1.2 thorpej * filter accordingly. 1268 1.2 thorpej */ 1269 1.49 thorpej if (ifp->if_flags & IFF_RUNNING) 1270 1.49 thorpej smc91cxx_reset(sc); 1271 1.2 thorpej error = 0; 1272 1.2 thorpej } 1273 1.2 thorpej break; 1274 1.2 thorpej } 1275 1.2 thorpej 1276 1.2 thorpej splx(s); 1277 1.101 msaitoh return error; 1278 1.2 thorpej } 1279 1.2 thorpej 1280 1.2 thorpej /* 1281 1.2 thorpej * Reset the interface. 1282 1.2 thorpej */ 1283 1.103 maxv static void 1284 1.72 dsl smc91cxx_reset(struct smc91cxx_softc *sc) 1285 1.2 thorpej { 1286 1.2 thorpej int s; 1287 1.2 thorpej 1288 1.11 mycroft s = splnet(); 1289 1.2 thorpej smc91cxx_stop(sc); 1290 1.2 thorpej smc91cxx_init(sc); 1291 1.2 thorpej splx(s); 1292 1.2 thorpej } 1293 1.2 thorpej 1294 1.2 thorpej /* 1295 1.2 thorpej * Watchdog timer. 1296 1.2 thorpej */ 1297 1.103 maxv static void 1298 1.72 dsl smc91cxx_watchdog(struct ifnet *ifp) 1299 1.2 thorpej { 1300 1.2 thorpej struct smc91cxx_softc *sc = ifp->if_softc; 1301 1.2 thorpej 1302 1.83 chs log(LOG_ERR, "%s: device timeout\n", device_xname(sc->sc_dev)); 1303 1.104 thorpej if_statinc(ifp, if_oerrors); 1304 1.2 thorpej smc91cxx_reset(sc); 1305 1.2 thorpej } 1306 1.2 thorpej 1307 1.2 thorpej /* 1308 1.2 thorpej * Stop output on the interface. 1309 1.2 thorpej */ 1310 1.103 maxv static void 1311 1.72 dsl smc91cxx_stop(struct smc91cxx_softc *sc) 1312 1.2 thorpej { 1313 1.2 thorpej bus_space_tag_t bst = sc->sc_bst; 1314 1.2 thorpej bus_space_handle_t bsh = sc->sc_bsh; 1315 1.2 thorpej 1316 1.101 msaitoh /* Clear interrupt mask; disable all interrupts. */ 1317 1.2 thorpej SMC_SELECT_BANK(sc, 2); 1318 1.67 matt smc91cxx_intr_mask_write(bst, bsh, 0); 1319 1.2 thorpej 1320 1.101 msaitoh /* Disable transmitter and receiver. */ 1321 1.2 thorpej SMC_SELECT_BANK(sc, 0); 1322 1.2 thorpej bus_space_write_2(bst, bsh, RECV_CONTROL_REG_W, 0); 1323 1.2 thorpej bus_space_write_2(bst, bsh, TXMIT_CONTROL_REG_W, 0); 1324 1.2 thorpej 1325 1.101 msaitoh /* Cancel watchdog timer. */ 1326 1.2 thorpej sc->sc_ec.ec_if.if_timer = 0; 1327 1.4 thorpej } 1328 1.4 thorpej 1329 1.4 thorpej /* 1330 1.4 thorpej * Enable power on the interface. 1331 1.4 thorpej */ 1332 1.103 maxv static int 1333 1.72 dsl smc91cxx_enable(struct smc91cxx_softc *sc) 1334 1.4 thorpej { 1335 1.4 thorpej 1336 1.25 jhawk if ((sc->sc_flags & SMC_FLAGS_ENABLED) == 0 && sc->sc_enable != NULL) { 1337 1.4 thorpej if ((*sc->sc_enable)(sc) != 0) { 1338 1.83 chs aprint_error_dev(sc->sc_dev, "device enable failed\n"); 1339 1.101 msaitoh return EIO; 1340 1.4 thorpej } 1341 1.4 thorpej } 1342 1.4 thorpej 1343 1.25 jhawk sc->sc_flags |= SMC_FLAGS_ENABLED; 1344 1.101 msaitoh return 0; 1345 1.4 thorpej } 1346 1.4 thorpej 1347 1.4 thorpej /* 1348 1.4 thorpej * Disable power on the interface. 1349 1.4 thorpej */ 1350 1.103 maxv static void 1351 1.72 dsl smc91cxx_disable(struct smc91cxx_softc *sc) 1352 1.4 thorpej { 1353 1.4 thorpej 1354 1.25 jhawk if ((sc->sc_flags & SMC_FLAGS_ENABLED) != 0 && sc->sc_disable != NULL) { 1355 1.4 thorpej (*sc->sc_disable)(sc); 1356 1.25 jhawk sc->sc_flags &= ~SMC_FLAGS_ENABLED; 1357 1.4 thorpej } 1358 1.13 thorpej } 1359 1.13 thorpej 1360 1.13 thorpej int 1361 1.75 cegger smc91cxx_activate(device_t self, enum devact act) 1362 1.13 thorpej { 1363 1.76 dyoung struct smc91cxx_softc *sc = device_private(self); 1364 1.13 thorpej 1365 1.13 thorpej switch (act) { 1366 1.13 thorpej case DVACT_DEACTIVATE: 1367 1.24 enami if_deactivate(&sc->sc_ec.ec_if); 1368 1.76 dyoung return 0; 1369 1.76 dyoung default: 1370 1.76 dyoung return EOPNOTSUPP; 1371 1.13 thorpej } 1372 1.22 itojun } 1373 1.22 itojun 1374 1.22 itojun int 1375 1.75 cegger smc91cxx_detach(device_t self, int flags) 1376 1.22 itojun { 1377 1.81 matt struct smc91cxx_softc *sc = device_private(self); 1378 1.22 itojun struct ifnet *ifp = &sc->sc_ec.ec_if; 1379 1.22 itojun 1380 1.25 jhawk /* Succeed now if there's no work to do. */ 1381 1.25 jhawk if ((sc->sc_flags & SMC_FLAGS_ATTACHED) == 0) 1382 1.101 msaitoh return 0; 1383 1.25 jhawk 1384 1.25 jhawk /* smc91cxx_disable() checks SMC_FLAGS_ENABLED */ 1385 1.22 itojun smc91cxx_disable(sc); 1386 1.22 itojun 1387 1.22 itojun /* smc91cxx_attach() never fails */ 1388 1.22 itojun 1389 1.22 itojun rnd_detach_source(&sc->rnd_source); 1390 1.80 tls 1391 1.22 itojun ether_ifdetach(ifp); 1392 1.22 itojun if_detach(ifp); 1393 1.22 itojun 1394 1.105 thorpej /* Delete all media. */ 1395 1.105 thorpej ifmedia_fini(&sc->sc_mii.mii_media); 1396 1.105 thorpej 1397 1.101 msaitoh return 0; 1398 1.2 thorpej } 1399 1.26 briggs 1400 1.103 maxv static uint32_t 1401 1.75 cegger smc91cxx_mii_bitbang_read(device_t self) 1402 1.26 briggs { 1403 1.81 matt struct smc91cxx_softc *sc = device_private(self); 1404 1.26 briggs 1405 1.26 briggs /* We're already in bank 3. */ 1406 1.101 msaitoh return bus_space_read_2(sc->sc_bst, sc->sc_bsh, MGMT_REG_W); 1407 1.26 briggs } 1408 1.26 briggs 1409 1.103 maxv static void 1410 1.101 msaitoh smc91cxx_mii_bitbang_write(device_t self, uint32_t val) 1411 1.26 briggs { 1412 1.81 matt struct smc91cxx_softc *sc = device_private(self); 1413 1.26 briggs 1414 1.26 briggs /* We're already in bank 3. */ 1415 1.26 briggs bus_space_write_2(sc->sc_bst, sc->sc_bsh, MGMT_REG_W, val); 1416 1.26 briggs } 1417 1.26 briggs 1418 1.103 maxv static int 1419 1.98 msaitoh smc91cxx_mii_readreg(device_t self, int phy, int reg, uint16_t *val) 1420 1.26 briggs { 1421 1.81 matt struct smc91cxx_softc *sc = device_private(self); 1422 1.98 msaitoh int rv; 1423 1.26 briggs 1424 1.26 briggs SMC_SELECT_BANK(sc, 3); 1425 1.26 briggs 1426 1.98 msaitoh rv = mii_bitbang_readreg(self, &smc91cxx_mii_bitbang_ops, phy, reg, 1427 1.98 msaitoh val); 1428 1.26 briggs 1429 1.26 briggs SMC_SELECT_BANK(sc, 2); 1430 1.26 briggs 1431 1.98 msaitoh return rv; 1432 1.26 briggs } 1433 1.26 briggs 1434 1.103 maxv static int 1435 1.98 msaitoh smc91cxx_mii_writereg(device_t self, int phy, int reg, uint16_t val) 1436 1.26 briggs { 1437 1.81 matt struct smc91cxx_softc *sc = device_private(self); 1438 1.98 msaitoh int rv; 1439 1.26 briggs 1440 1.26 briggs SMC_SELECT_BANK(sc, 3); 1441 1.26 briggs 1442 1.98 msaitoh rv = mii_bitbang_writereg(self, &smc91cxx_mii_bitbang_ops, phy, reg, 1443 1.98 msaitoh val); 1444 1.26 briggs 1445 1.26 briggs SMC_SELECT_BANK(sc, 2); 1446 1.98 msaitoh 1447 1.98 msaitoh return rv; 1448 1.26 briggs } 1449 1.26 briggs 1450 1.103 maxv static void 1451 1.82 matt smc91cxx_statchg(struct ifnet *ifp) 1452 1.26 briggs { 1453 1.82 matt struct smc91cxx_softc *sc = ifp->if_softc; 1454 1.26 briggs bus_space_tag_t bst = sc->sc_bst; 1455 1.26 briggs bus_space_handle_t bsh = sc->sc_bsh; 1456 1.26 briggs int mctl; 1457 1.26 briggs 1458 1.26 briggs SMC_SELECT_BANK(sc, 0); 1459 1.26 briggs mctl = bus_space_read_2(bst, bsh, TXMIT_CONTROL_REG_W); 1460 1.26 briggs if (sc->sc_mii.mii_media_active & IFM_FDX) 1461 1.26 briggs mctl |= TCR_SWFDUP; 1462 1.26 briggs else 1463 1.26 briggs mctl &= ~TCR_SWFDUP; 1464 1.26 briggs bus_space_write_2(bst, bsh, TXMIT_CONTROL_REG_W, mctl); 1465 1.101 msaitoh SMC_SELECT_BANK(sc, 2); /* Back to operating window */ 1466 1.26 briggs } 1467 1.26 briggs 1468 1.26 briggs /* 1469 1.26 briggs * One second timer, used to tick the MII. 1470 1.26 briggs */ 1471 1.103 maxv static void 1472 1.72 dsl smc91cxx_tick(void *arg) 1473 1.26 briggs { 1474 1.26 briggs struct smc91cxx_softc *sc = arg; 1475 1.26 briggs int s; 1476 1.26 briggs 1477 1.26 briggs #ifdef DIAGNOSTIC 1478 1.26 briggs if ((sc->sc_flags & SMC_FLAGS_HAS_MII) == 0) 1479 1.26 briggs panic("smc91cxx_tick"); 1480 1.26 briggs #endif 1481 1.26 briggs 1482 1.83 chs if (!device_is_active(sc->sc_dev)) 1483 1.26 briggs return; 1484 1.26 briggs 1485 1.26 briggs s = splnet(); 1486 1.26 briggs mii_tick(&sc->sc_mii); 1487 1.26 briggs splx(s); 1488 1.26 briggs 1489 1.106 thorpej callout_schedule(&sc->sc_mii_callout, hz); 1490 1.26 briggs } 1491