1 1.53 riastrad /* $NetBSD: if_aumac.c,v 1.53 2024/06/29 12:11:11 riastradh Exp $ */ 2 1.1 simonb 3 1.1 simonb /* 4 1.1 simonb * Copyright (c) 2001 Wasabi Systems, Inc. 5 1.1 simonb * All rights reserved. 6 1.1 simonb * 7 1.1 simonb * Written by Jason R. Thorpe for Wasabi Systems, Inc. 8 1.1 simonb * 9 1.1 simonb * Redistribution and use in source and binary forms, with or without 10 1.1 simonb * modification, are permitted provided that the following conditions 11 1.1 simonb * are met: 12 1.1 simonb * 1. Redistributions of source code must retain the above copyright 13 1.1 simonb * notice, this list of conditions and the following disclaimer. 14 1.1 simonb * 2. Redistributions in binary form must reproduce the above copyright 15 1.1 simonb * notice, this list of conditions and the following disclaimer in the 16 1.1 simonb * documentation and/or other materials provided with the distribution. 17 1.1 simonb * 3. All advertising materials mentioning features or use of this software 18 1.1 simonb * must display the following acknowledgement: 19 1.1 simonb * This product includes software developed for the NetBSD Project by 20 1.1 simonb * Wasabi Systems, Inc. 21 1.1 simonb * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22 1.1 simonb * or promote products derived from this software without specific prior 23 1.1 simonb * written permission. 24 1.1 simonb * 25 1.1 simonb * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26 1.1 simonb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 1.1 simonb * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 1.1 simonb * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29 1.1 simonb * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 1.1 simonb * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 1.1 simonb * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 1.1 simonb * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 1.1 simonb * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 1.1 simonb * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 1.1 simonb * POSSIBILITY OF SUCH DAMAGE. 36 1.1 simonb */ 37 1.1 simonb 38 1.1 simonb /* 39 1.1 simonb * Device driver for Alchemy Semiconductor Au1x00 Ethernet Media 40 1.1 simonb * Access Controller. 41 1.1 simonb * 42 1.1 simonb * TODO: 43 1.1 simonb * 44 1.1 simonb * Better Rx buffer management; we want to get new Rx buffers 45 1.1 simonb * to the chip more quickly than we currently do. 46 1.1 simonb */ 47 1.1 simonb 48 1.1 simonb #include <sys/cdefs.h> 49 1.53 riastrad __KERNEL_RCSID(0, "$NetBSD: if_aumac.c,v 1.53 2024/06/29 12:11:11 riastradh Exp $"); 50 1.34 tls 51 1.1 simonb 52 1.1 simonb 53 1.1 simonb #include <sys/param.h> 54 1.31 matt #include <sys/bus.h> 55 1.1 simonb #include <sys/callout.h> 56 1.31 matt #include <sys/device.h> 57 1.31 matt #include <sys/endian.h> 58 1.46 msaitoh #include <sys/errno.h> 59 1.31 matt #include <sys/intr.h> 60 1.31 matt #include <sys/ioctl.h> 61 1.31 matt #include <sys/kernel.h> 62 1.1 simonb #include <sys/mbuf.h> 63 1.1 simonb #include <sys/socket.h> 64 1.1 simonb 65 1.29 uebayasi #include <uvm/uvm.h> /* for PAGE_SIZE */ 66 1.1 simonb 67 1.1 simonb #include <net/if.h> 68 1.1 simonb #include <net/if_dl.h> 69 1.1 simonb #include <net/if_media.h> 70 1.1 simonb #include <net/if_ether.h> 71 1.1 simonb 72 1.1 simonb #include <net/bpf.h> 73 1.39 riastrad #include <sys/rndsource.h> 74 1.1 simonb 75 1.1 simonb #include <dev/mii/mii.h> 76 1.1 simonb #include <dev/mii/miivar.h> 77 1.1 simonb 78 1.1 simonb #include <mips/alchemy/include/aureg.h> 79 1.1 simonb #include <mips/alchemy/include/auvar.h> 80 1.1 simonb #include <mips/alchemy/include/aubusvar.h> 81 1.1 simonb #include <mips/alchemy/dev/if_aumacreg.h> 82 1.1 simonb 83 1.1 simonb /* 84 1.1 simonb * The Au1X00 MAC has 4 transmit and receive descriptors. Each buffer 85 1.1 simonb * must consist of a single DMA segment, and must be aligned to a 2K 86 1.1 simonb * boundary. Therefore, this driver does not perform DMA directly 87 1.1 simonb * to/from mbufs. Instead, we copy the data to/from buffers allocated 88 1.1 simonb * at device attach time. 89 1.1 simonb * 90 1.1 simonb * We also skip the bus_dma dance. The MAC is built in to the CPU, so 91 1.1 simonb * there's little point in not making assumptions based on the CPU type. 92 1.1 simonb * We also program the Au1X00 cache to be DMA coherent, so the buffers 93 1.1 simonb * are accessed via KSEG0 addresses. 94 1.1 simonb */ 95 1.1 simonb #define AUMAC_NTXDESC 4 96 1.1 simonb #define AUMAC_NTXDESC_MASK (AUMAC_NTXDESC - 1) 97 1.1 simonb 98 1.1 simonb #define AUMAC_NRXDESC 4 99 1.1 simonb #define AUMAC_NRXDESC_MASK (AUMAC_NRXDESC - 1) 100 1.1 simonb 101 1.1 simonb #define AUMAC_NEXTTX(x) (((x) + 1) & AUMAC_NTXDESC_MASK) 102 1.1 simonb #define AUMAC_NEXTRX(x) (((x) + 1) & AUMAC_NRXDESC_MASK) 103 1.1 simonb 104 1.1 simonb #define AUMAC_TXBUF_OFFSET 0 105 1.1 simonb #define AUMAC_RXBUF_OFFSET (MAC_BUFLEN * AUMAC_NTXDESC) 106 1.1 simonb #define AUMAC_BUFSIZE (MAC_BUFLEN * (AUMAC_NTXDESC + AUMAC_NRXDESC)) 107 1.1 simonb 108 1.1 simonb struct aumac_buf { 109 1.20 simonb vaddr_t buf_vaddr; /* virtual address of buffer */ 110 1.1 simonb bus_addr_t buf_paddr; /* DMA address of buffer */ 111 1.1 simonb }; 112 1.1 simonb 113 1.1 simonb /* 114 1.1 simonb * Software state per device. 115 1.1 simonb */ 116 1.1 simonb struct aumac_softc { 117 1.33 kiyohara device_t sc_dev; /* generic device information */ 118 1.1 simonb bus_space_tag_t sc_st; /* bus space tag */ 119 1.1 simonb bus_space_handle_t sc_mac_sh; /* MAC space handle */ 120 1.1 simonb bus_space_handle_t sc_macen_sh; /* MAC enable space handle */ 121 1.1 simonb bus_space_handle_t sc_dma_sh; /* DMA space handle */ 122 1.1 simonb struct ethercom sc_ethercom; /* Ethernet common data */ 123 1.1 simonb void *sc_sdhook; /* shutdown hook */ 124 1.1 simonb 125 1.35 kiyohara int sc_irq; 126 1.1 simonb void *sc_ih; /* interrupt cookie */ 127 1.1 simonb 128 1.1 simonb struct mii_data sc_mii; /* MII/media information */ 129 1.1 simonb 130 1.1 simonb struct callout sc_tick_ch; /* tick callout */ 131 1.1 simonb 132 1.1 simonb /* Transmit and receive buffers */ 133 1.1 simonb struct aumac_buf sc_txbufs[AUMAC_NTXDESC]; 134 1.1 simonb struct aumac_buf sc_rxbufs[AUMAC_NRXDESC]; 135 1.19 christos void *sc_bufaddr; 136 1.1 simonb 137 1.1 simonb int sc_txfree; /* number of free Tx descriptors */ 138 1.1 simonb int sc_txnext; /* next Tx descriptor to use */ 139 1.1 simonb int sc_txdirty; /* first dirty Tx descriptor */ 140 1.1 simonb 141 1.1 simonb int sc_rxptr; /* next ready Rx descriptor */ 142 1.1 simonb 143 1.32 tls krndsource_t rnd_source; 144 1.15 simonb 145 1.1 simonb #ifdef AUMAC_EVENT_COUNTERS 146 1.1 simonb struct evcnt sc_ev_txstall; /* Tx stalled */ 147 1.1 simonb struct evcnt sc_ev_rxstall; /* Rx stalled */ 148 1.1 simonb struct evcnt sc_ev_txintr; /* Tx interrupts */ 149 1.1 simonb struct evcnt sc_ev_rxintr; /* Rx interrupts */ 150 1.1 simonb #endif 151 1.1 simonb 152 1.1 simonb uint32_t sc_control; /* MAC_CONTROL contents */ 153 1.1 simonb uint32_t sc_flowctrl; /* MAC_FLOWCTRL contents */ 154 1.1 simonb }; 155 1.1 simonb 156 1.1 simonb #ifdef AUMAC_EVENT_COUNTERS 157 1.1 simonb #define AUMAC_EVCNT_INCR(ev) (ev)->ev_count++ 158 1.8 simonb #else 159 1.8 simonb #define AUMAC_EVCNT_INCR(ev) /* nothing */ 160 1.1 simonb #endif 161 1.1 simonb 162 1.1 simonb #define AUMAC_INIT_RXDESC(sc, x) \ 163 1.1 simonb do { \ 164 1.1 simonb bus_space_write_4((sc)->sc_st, (sc)->sc_dma_sh, \ 165 1.1 simonb MACDMA_RX_STAT((x)), 0); \ 166 1.1 simonb bus_space_write_4((sc)->sc_st, (sc)->sc_dma_sh, \ 167 1.1 simonb MACDMA_RX_ADDR((x)), \ 168 1.1 simonb (sc)->sc_rxbufs[(x)].buf_paddr | RX_ADDR_EN); \ 169 1.1 simonb } while (/*CONSTCOND*/0) 170 1.1 simonb 171 1.1 simonb static void aumac_start(struct ifnet *); 172 1.1 simonb static void aumac_watchdog(struct ifnet *); 173 1.19 christos static int aumac_ioctl(struct ifnet *, u_long, void *); 174 1.1 simonb static int aumac_init(struct ifnet *); 175 1.1 simonb static void aumac_stop(struct ifnet *, int); 176 1.1 simonb 177 1.1 simonb static void aumac_shutdown(void *); 178 1.1 simonb 179 1.1 simonb static void aumac_tick(void *); 180 1.1 simonb 181 1.1 simonb static void aumac_set_filter(struct aumac_softc *); 182 1.1 simonb 183 1.1 simonb static void aumac_powerup(struct aumac_softc *); 184 1.1 simonb static void aumac_powerdown(struct aumac_softc *); 185 1.1 simonb 186 1.1 simonb static int aumac_intr(void *); 187 1.15 simonb static int aumac_txintr(struct aumac_softc *); 188 1.15 simonb static int aumac_rxintr(struct aumac_softc *); 189 1.1 simonb 190 1.45 msaitoh static int aumac_mii_readreg(device_t, int, int, uint16_t *); 191 1.45 msaitoh static int aumac_mii_writereg(device_t, int, int, uint16_t); 192 1.37 matt static void aumac_mii_statchg(struct ifnet *); 193 1.1 simonb static int aumac_mii_wait(struct aumac_softc *, const char *); 194 1.1 simonb 195 1.33 kiyohara static int aumac_match(device_t, struct cfdata *, void *); 196 1.33 kiyohara static void aumac_attach(device_t, device_t, void *); 197 1.1 simonb 198 1.1 simonb int aumac_copy_small = 0; 199 1.1 simonb 200 1.33 kiyohara CFATTACH_DECL_NEW(aumac, sizeof(struct aumac_softc), 201 1.6 thorpej aumac_match, aumac_attach, NULL, NULL); 202 1.1 simonb 203 1.1 simonb static int 204 1.33 kiyohara aumac_match(device_t parent, struct cfdata *cf, void *aux) 205 1.1 simonb { 206 1.1 simonb struct aubus_attach_args *aa = aux; 207 1.1 simonb 208 1.3 thorpej if (strcmp(aa->aa_name, cf->cf_name) == 0) 209 1.46 msaitoh return 1; 210 1.1 simonb 211 1.46 msaitoh return 0; 212 1.1 simonb } 213 1.1 simonb 214 1.1 simonb static void 215 1.33 kiyohara aumac_attach(device_t parent, device_t self, void *aux) 216 1.1 simonb { 217 1.17 thorpej const uint8_t *enaddr; 218 1.17 thorpej prop_data_t ea; 219 1.33 kiyohara struct aumac_softc *sc = device_private(self); 220 1.1 simonb struct aubus_attach_args *aa = aux; 221 1.1 simonb struct ifnet *ifp = &sc->sc_ethercom.ec_if; 222 1.46 msaitoh struct mii_data * const mii = &sc->sc_mii; 223 1.1 simonb struct pglist pglist; 224 1.1 simonb paddr_t bufaddr; 225 1.20 simonb vaddr_t vbufaddr; 226 1.1 simonb int i; 227 1.1 simonb 228 1.21 ad callout_init(&sc->sc_tick_ch, 0); 229 1.1 simonb 230 1.33 kiyohara aprint_normal(": Au1X00 10/100 Ethernet\n"); 231 1.33 kiyohara aprint_naive("\n"); 232 1.1 simonb 233 1.33 kiyohara sc->sc_dev = self; 234 1.1 simonb sc->sc_st = aa->aa_st; 235 1.1 simonb 236 1.1 simonb /* Get the MAC address. */ 237 1.33 kiyohara ea = prop_dictionary_get(device_properties(self), "mac-address"); 238 1.17 thorpej if (ea == NULL) { 239 1.33 kiyohara aprint_error_dev(self, "unable to get mac-addr property\n"); 240 1.1 simonb return; 241 1.1 simonb } 242 1.17 thorpej KASSERT(prop_object_type(ea) == PROP_TYPE_DATA); 243 1.17 thorpej KASSERT(prop_data_size(ea) == ETHER_ADDR_LEN); 244 1.17 thorpej enaddr = prop_data_data_nocopy(ea); 245 1.1 simonb 246 1.33 kiyohara aprint_normal_dev(self, "Ethernet address %s\n", ether_sprintf(enaddr)); 247 1.1 simonb 248 1.1 simonb /* Map the device. */ 249 1.1 simonb if (bus_space_map(sc->sc_st, aa->aa_addrs[AA_MAC_BASE], 250 1.1 simonb MACx_SIZE, 0, &sc->sc_mac_sh) != 0) { 251 1.33 kiyohara aprint_error_dev(self, "unable to map MAC registers\n"); 252 1.1 simonb return; 253 1.1 simonb } 254 1.1 simonb if (bus_space_map(sc->sc_st, aa->aa_addrs[AA_MAC_ENABLE], 255 1.1 simonb MACENx_SIZE, 0, &sc->sc_macen_sh) != 0) { 256 1.33 kiyohara aprint_error_dev(self, "unable to map MACEN registers\n"); 257 1.1 simonb return; 258 1.1 simonb } 259 1.1 simonb if (bus_space_map(sc->sc_st, aa->aa_addrs[AA_MAC_DMA_BASE], 260 1.1 simonb MACx_DMA_SIZE, 0, &sc->sc_dma_sh) != 0) { 261 1.33 kiyohara aprint_error_dev(self, "unable to map MACDMA registers\n"); 262 1.1 simonb return; 263 1.1 simonb } 264 1.1 simonb 265 1.1 simonb /* Make sure the MAC is powered off. */ 266 1.1 simonb aumac_powerdown(sc); 267 1.1 simonb 268 1.1 simonb /* Hook up the interrupt handler. */ 269 1.2 simonb sc->sc_ih = au_intr_establish(aa->aa_irq[0], 1, IPL_NET, IST_LEVEL, 270 1.1 simonb aumac_intr, sc); 271 1.1 simonb if (sc->sc_ih == NULL) { 272 1.33 kiyohara aprint_error_dev(self, 273 1.33 kiyohara "unable to register interrupt handler\n"); 274 1.1 simonb return; 275 1.1 simonb } 276 1.35 kiyohara sc->sc_irq = aa->aa_irq[0]; 277 1.35 kiyohara au_intr_disable(sc->sc_irq); 278 1.1 simonb 279 1.1 simonb /* 280 1.1 simonb * Allocate space for the transmit and receive buffers. 281 1.1 simonb */ 282 1.1 simonb if (uvm_pglistalloc(AUMAC_BUFSIZE, 0, ctob(physmem), PAGE_SIZE, 0, 283 1.1 simonb &pglist, 1, 0)) 284 1.1 simonb return; 285 1.1 simonb 286 1.13 yamt bufaddr = VM_PAGE_TO_PHYS(TAILQ_FIRST(&pglist)); 287 1.20 simonb vbufaddr = MIPS_PHYS_TO_KSEG0(bufaddr); 288 1.1 simonb 289 1.1 simonb for (i = 0; i < AUMAC_NTXDESC; i++) { 290 1.1 simonb int offset = AUMAC_TXBUF_OFFSET + (i * MAC_BUFLEN); 291 1.1 simonb 292 1.1 simonb sc->sc_txbufs[i].buf_vaddr = vbufaddr + offset; 293 1.1 simonb sc->sc_txbufs[i].buf_paddr = bufaddr + offset; 294 1.1 simonb } 295 1.1 simonb 296 1.1 simonb for (i = 0; i < AUMAC_NRXDESC; i++) { 297 1.1 simonb int offset = AUMAC_RXBUF_OFFSET + (i * MAC_BUFLEN); 298 1.1 simonb 299 1.1 simonb sc->sc_rxbufs[i].buf_vaddr = vbufaddr + offset; 300 1.1 simonb sc->sc_rxbufs[i].buf_paddr = bufaddr + offset; 301 1.1 simonb } 302 1.1 simonb 303 1.1 simonb /* 304 1.1 simonb * Power up the MAC before accessing any MAC registers (including 305 1.1 simonb * MII configuration. 306 1.1 simonb */ 307 1.1 simonb aumac_powerup(sc); 308 1.1 simonb 309 1.1 simonb /* 310 1.1 simonb * Initialize the media structures and probe the MII. 311 1.1 simonb */ 312 1.46 msaitoh mii->mii_ifp = ifp; 313 1.46 msaitoh mii->mii_readreg = aumac_mii_readreg; 314 1.46 msaitoh mii->mii_writereg = aumac_mii_writereg; 315 1.46 msaitoh mii->mii_statchg = aumac_mii_statchg; 316 1.46 msaitoh sc->sc_ethercom.ec_mii = mii; 317 1.46 msaitoh ifmedia_init(&mii->mii_media, 0, ether_mediachange, ether_mediastatus); 318 1.1 simonb 319 1.46 msaitoh mii_attach(self, mii, 0xffffffff, MII_PHY_ANY, 320 1.1 simonb MII_OFFSET_ANY, 0); 321 1.1 simonb 322 1.46 msaitoh if (LIST_FIRST(&mii->mii_phys) == NULL) { 323 1.46 msaitoh ifmedia_add(&mii->mii_media, IFM_ETHER | IFM_NONE, 324 1.46 msaitoh 0, NULL); 325 1.46 msaitoh ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_NONE); 326 1.1 simonb } else 327 1.46 msaitoh ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_AUTO); 328 1.1 simonb 329 1.33 kiyohara strcpy(ifp->if_xname, device_xname(self)); 330 1.1 simonb ifp->if_softc = sc; 331 1.1 simonb ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 332 1.1 simonb ifp->if_ioctl = aumac_ioctl; 333 1.1 simonb ifp->if_start = aumac_start; 334 1.1 simonb ifp->if_watchdog = aumac_watchdog; 335 1.1 simonb ifp->if_init = aumac_init; 336 1.1 simonb ifp->if_stop = aumac_stop; 337 1.1 simonb IFQ_SET_READY(&ifp->if_snd); 338 1.1 simonb 339 1.1 simonb /* Attach the interface. */ 340 1.46 msaitoh if_attach(ifp); 341 1.42 ozaki if_deferred_start_init(ifp, NULL); 342 1.1 simonb ether_ifattach(ifp, enaddr); 343 1.1 simonb 344 1.34 tls rnd_attach_source(&sc->rnd_source, device_xname(self), 345 1.38 tls RND_TYPE_NET, RND_FLAG_DEFAULT); 346 1.16 simonb 347 1.1 simonb #ifdef AUMAC_EVENT_COUNTERS 348 1.1 simonb evcnt_attach_dynamic(&sc->sc_ev_txstall, EVCNT_TYPE_MISC, 349 1.33 kiyohara NULL, device_xname(self), "txstall"); 350 1.1 simonb evcnt_attach_dynamic(&sc->sc_ev_rxstall, EVCNT_TYPE_MISC, 351 1.33 kiyohara NULL, device_xname(self), "rxstall"); 352 1.1 simonb evcnt_attach_dynamic(&sc->sc_ev_txintr, EVCNT_TYPE_MISC, 353 1.33 kiyohara NULL, device_xname(self), "txintr"); 354 1.1 simonb evcnt_attach_dynamic(&sc->sc_ev_rxintr, EVCNT_TYPE_MISC, 355 1.33 kiyohara NULL, device_xname(self), "rxintr"); 356 1.1 simonb #endif 357 1.1 simonb 358 1.1 simonb /* Make sure the interface is shutdown during reboot. */ 359 1.1 simonb sc->sc_sdhook = shutdownhook_establish(aumac_shutdown, sc); 360 1.1 simonb if (sc->sc_sdhook == NULL) 361 1.33 kiyohara aprint_error_dev(self, 362 1.33 kiyohara "WARNING: unable to establish shutdown hook\n"); 363 1.1 simonb return; 364 1.1 simonb } 365 1.1 simonb 366 1.1 simonb /* 367 1.1 simonb * aumac_shutdown: 368 1.1 simonb * 369 1.1 simonb * Make sure the interface is stopped at reboot time. 370 1.1 simonb */ 371 1.1 simonb static void 372 1.1 simonb aumac_shutdown(void *arg) 373 1.1 simonb { 374 1.1 simonb struct aumac_softc *sc = arg; 375 1.1 simonb 376 1.1 simonb aumac_stop(&sc->sc_ethercom.ec_if, 1); 377 1.1 simonb 378 1.1 simonb /* 379 1.1 simonb * XXX aumac_stop leaves device powered up at the moment 380 1.1 simonb * XXX but this still isn't enough to keep yamon happy... :-( 381 1.1 simonb */ 382 1.1 simonb bus_space_write_4(sc->sc_st, sc->sc_macen_sh, 0, 0); 383 1.1 simonb } 384 1.1 simonb 385 1.1 simonb /* 386 1.1 simonb * aumac_start: [ifnet interface function] 387 1.1 simonb * 388 1.1 simonb * Start packet transmission on the interface. 389 1.1 simonb */ 390 1.1 simonb static void 391 1.1 simonb aumac_start(struct ifnet *ifp) 392 1.1 simonb { 393 1.1 simonb struct aumac_softc *sc = ifp->if_softc; 394 1.1 simonb struct mbuf *m; 395 1.1 simonb int nexttx; 396 1.1 simonb 397 1.50 thorpej if ((ifp->if_flags & IFF_RUNNING) == 0) 398 1.1 simonb return; 399 1.1 simonb 400 1.1 simonb /* 401 1.1 simonb * Loop through the send queue, setting up transmit descriptors 402 1.1 simonb * unitl we drain the queue, or use up all available transmit 403 1.1 simonb * descriptors. 404 1.1 simonb */ 405 1.1 simonb for (;;) { 406 1.1 simonb /* Grab a packet off the queue. */ 407 1.1 simonb IFQ_POLL(&ifp->if_snd, m); 408 1.1 simonb if (m == NULL) 409 1.1 simonb return; 410 1.1 simonb 411 1.1 simonb /* Get a spare descriptor. */ 412 1.1 simonb if (sc->sc_txfree == 0) { 413 1.50 thorpej /* No more slots left. */ 414 1.1 simonb AUMAC_EVCNT_INCR(&sc->sc_ev_txstall); 415 1.1 simonb return; 416 1.1 simonb } 417 1.1 simonb nexttx = sc->sc_txnext; 418 1.1 simonb 419 1.1 simonb IFQ_DEQUEUE(&ifp->if_snd, m); 420 1.1 simonb 421 1.1 simonb /* 422 1.1 simonb * WE ARE NOW COMMITTED TO TRANSMITTING THE PACKET. 423 1.1 simonb */ 424 1.1 simonb 425 1.1 simonb m_copydata(m, 0, m->m_pkthdr.len, 426 1.20 simonb (void *)sc->sc_txbufs[nexttx].buf_vaddr); 427 1.9 simonb 428 1.9 simonb /* Zero out the remainder of any short packets. */ 429 1.9 simonb if (m->m_pkthdr.len < (ETHER_MIN_LEN - ETHER_CRC_LEN)) 430 1.20 simonb memset((char *)sc->sc_txbufs[nexttx].buf_vaddr + 431 1.9 simonb m->m_pkthdr.len, 0, 432 1.9 simonb ETHER_MIN_LEN - ETHER_CRC_LEN - m->m_pkthdr.len); 433 1.1 simonb 434 1.1 simonb bus_space_write_4(sc->sc_st, sc->sc_dma_sh, 435 1.1 simonb MACDMA_TX_STAT(nexttx), 0); 436 1.1 simonb bus_space_write_4(sc->sc_st, sc->sc_dma_sh, 437 1.1 simonb MACDMA_TX_LEN(nexttx), 438 1.1 simonb m->m_pkthdr.len < (ETHER_MIN_LEN - ETHER_CRC_LEN) ? 439 1.1 simonb ETHER_MIN_LEN - ETHER_CRC_LEN : m->m_pkthdr.len); 440 1.1 simonb bus_space_write_4(sc->sc_st, sc->sc_dma_sh, 441 1.1 simonb MACDMA_TX_ADDR(nexttx), 442 1.1 simonb sc->sc_txbufs[nexttx].buf_paddr | TX_ADDR_EN); 443 1.1 simonb /* XXX - needed?? we should be coherent */ 444 1.1 simonb bus_space_barrier(sc->sc_st, sc->sc_dma_sh, 0 /* XXX */, 445 1.1 simonb 0 /* XXX */, BUS_SPACE_BARRIER_WRITE); 446 1.1 simonb 447 1.1 simonb /* Advance the Tx pointer. */ 448 1.1 simonb sc->sc_txfree--; 449 1.1 simonb sc->sc_txnext = AUMAC_NEXTTX(nexttx); 450 1.1 simonb 451 1.1 simonb /* Pass the packet to any BPF listeners. */ 452 1.44 msaitoh bpf_mtap(ifp, m, BPF_D_OUT); 453 1.1 simonb 454 1.1 simonb m_freem(m); 455 1.1 simonb 456 1.1 simonb /* Set a watchdog timer in case the chip flakes out. */ 457 1.1 simonb ifp->if_timer = 5; 458 1.1 simonb } 459 1.1 simonb /* NOTREACHED */ 460 1.1 simonb } 461 1.1 simonb 462 1.1 simonb /* 463 1.1 simonb * aumac_watchdog: [ifnet interface function] 464 1.1 simonb * 465 1.1 simonb * Watchdog timer handler. 466 1.1 simonb */ 467 1.1 simonb static void 468 1.1 simonb aumac_watchdog(struct ifnet *ifp) 469 1.1 simonb { 470 1.1 simonb struct aumac_softc *sc = ifp->if_softc; 471 1.1 simonb 472 1.33 kiyohara printf("%s: device timeout\n", device_xname(sc->sc_dev)); 473 1.1 simonb (void) aumac_init(ifp); 474 1.1 simonb 475 1.1 simonb /* Try to get more packets going. */ 476 1.1 simonb aumac_start(ifp); 477 1.1 simonb } 478 1.1 simonb 479 1.1 simonb /* 480 1.1 simonb * aumac_ioctl: [ifnet interface function] 481 1.1 simonb * 482 1.1 simonb * Handle control requests from the operator. 483 1.1 simonb */ 484 1.1 simonb static int 485 1.19 christos aumac_ioctl(struct ifnet *ifp, u_long cmd, void *data) 486 1.1 simonb { 487 1.1 simonb struct aumac_softc *sc = ifp->if_softc; 488 1.1 simonb int s, error; 489 1.1 simonb 490 1.1 simonb s = splnet(); 491 1.1 simonb 492 1.24 dyoung error = ether_ioctl(ifp, cmd, data); 493 1.24 dyoung if (error == ENETRESET) { 494 1.24 dyoung /* 495 1.24 dyoung * Multicast list has changed; set the hardware filter 496 1.24 dyoung * accordingly. 497 1.24 dyoung */ 498 1.24 dyoung if (ifp->if_flags & IFF_RUNNING) 499 1.24 dyoung aumac_set_filter(sc); 500 1.36 kiyohara error = 0; 501 1.1 simonb } 502 1.1 simonb 503 1.1 simonb /* Try to get more packets going. */ 504 1.1 simonb aumac_start(ifp); 505 1.1 simonb 506 1.1 simonb splx(s); 507 1.46 msaitoh return error; 508 1.1 simonb } 509 1.1 simonb 510 1.1 simonb /* 511 1.1 simonb * aumac_intr: 512 1.1 simonb * 513 1.1 simonb * Interrupt service routine. 514 1.1 simonb */ 515 1.1 simonb static int 516 1.1 simonb aumac_intr(void *arg) 517 1.1 simonb { 518 1.1 simonb struct aumac_softc *sc = arg; 519 1.15 simonb int status; 520 1.1 simonb 521 1.1 simonb /* 522 1.1 simonb * There aren't really any interrupt status bits on the 523 1.1 simonb * Au1X00 MAC, and each MAC has a dedicated interrupt 524 1.1 simonb * in the CPU's built-in interrupt controller. Just 525 1.1 simonb * check for new incoming packets, and then Tx completions 526 1.1 simonb * (for status updating). 527 1.1 simonb */ 528 1.1 simonb if ((sc->sc_ethercom.ec_if.if_flags & IFF_RUNNING) == 0) 529 1.46 msaitoh return 0; 530 1.1 simonb 531 1.15 simonb status = aumac_rxintr(sc); 532 1.15 simonb status += aumac_txintr(sc); 533 1.1 simonb 534 1.34 tls rnd_add_uint32(&sc->rnd_source, status); 535 1.15 simonb 536 1.15 simonb return status; 537 1.1 simonb } 538 1.1 simonb 539 1.1 simonb /* 540 1.1 simonb * aumac_txintr: 541 1.1 simonb * 542 1.1 simonb * Helper; handle transmit interrupts. 543 1.1 simonb */ 544 1.15 simonb static int 545 1.1 simonb aumac_txintr(struct aumac_softc *sc) 546 1.1 simonb { 547 1.1 simonb struct ifnet *ifp = &sc->sc_ethercom.ec_if; 548 1.1 simonb uint32_t stat; 549 1.1 simonb int i; 550 1.15 simonb int pkts = 0; 551 1.1 simonb 552 1.1 simonb for (i = sc->sc_txdirty; sc->sc_txfree != AUMAC_NTXDESC; 553 1.1 simonb i = AUMAC_NEXTTX(i)) { 554 1.1 simonb if ((bus_space_read_4(sc->sc_st, sc->sc_dma_sh, 555 1.1 simonb MACDMA_TX_ADDR(i)) & TX_ADDR_DN) == 0) 556 1.1 simonb break; 557 1.15 simonb pkts++; 558 1.1 simonb 559 1.1 simonb /* ACK interrupt. */ 560 1.1 simonb bus_space_write_4(sc->sc_st, sc->sc_dma_sh, 561 1.1 simonb MACDMA_TX_ADDR(i), 0); 562 1.1 simonb 563 1.1 simonb stat = bus_space_read_4(sc->sc_st, sc->sc_dma_sh, 564 1.1 simonb MACDMA_TX_STAT(i)); 565 1.1 simonb 566 1.48 thorpej net_stat_ref_t nsr = IF_STAT_GETREF(ifp); 567 1.1 simonb if (stat & TX_STAT_FA) { 568 1.1 simonb /* XXX STATS */ 569 1.53 riastrad if_statinc_ref(ifp, nsr, if_oerrors); 570 1.53 riastrad } else { 571 1.53 riastrad if_statinc_ref(ifp, nsr, if_opackets); 572 1.53 riastrad } 573 1.53 riastrad 574 1.53 riastrad if (stat & TX_STAT_EC) { 575 1.53 riastrad if_statadd_ref(ifp, nsr, if_collisions, 16); 576 1.53 riastrad } else if (TX_STAT_CC(stat)) { 577 1.53 riastrad if_statadd_ref(ifp, nsr, if_collisions, 578 1.53 riastrad TX_STAT_CC(stat)); 579 1.53 riastrad } 580 1.48 thorpej IF_STAT_PUTREF(ifp); 581 1.1 simonb 582 1.1 simonb sc->sc_txfree++; 583 1.1 simonb 584 1.1 simonb /* Try to queue more packets. */ 585 1.42 ozaki if_schedule_deferred_start(ifp); 586 1.1 simonb } 587 1.1 simonb 588 1.15 simonb if (pkts) 589 1.1 simonb AUMAC_EVCNT_INCR(&sc->sc_ev_txintr); 590 1.1 simonb 591 1.1 simonb /* Update the dirty descriptor pointer. */ 592 1.1 simonb sc->sc_txdirty = i; 593 1.1 simonb 594 1.1 simonb /* 595 1.1 simonb * If there are no more pending transmissions, cancel the watchdog 596 1.1 simonb * timer. 597 1.1 simonb */ 598 1.1 simonb if (sc->sc_txfree == AUMAC_NTXDESC) 599 1.1 simonb ifp->if_timer = 0; 600 1.15 simonb 601 1.15 simonb return pkts; 602 1.1 simonb } 603 1.1 simonb 604 1.1 simonb /* 605 1.1 simonb * aumac_rxintr: 606 1.1 simonb * 607 1.1 simonb * Helper; handle receive interrupts. 608 1.1 simonb */ 609 1.15 simonb static int 610 1.1 simonb aumac_rxintr(struct aumac_softc *sc) 611 1.1 simonb { 612 1.1 simonb struct ifnet *ifp = &sc->sc_ethercom.ec_if; 613 1.1 simonb struct mbuf *m; 614 1.1 simonb uint32_t stat; 615 1.1 simonb int i, len; 616 1.1 simonb int pkts = 0; 617 1.1 simonb 618 1.1 simonb for (i = sc->sc_rxptr;; i = AUMAC_NEXTRX(i)) { 619 1.1 simonb if ((bus_space_read_4(sc->sc_st, sc->sc_dma_sh, 620 1.1 simonb MACDMA_RX_ADDR(i)) & RX_ADDR_DN) == 0) 621 1.1 simonb break; 622 1.1 simonb pkts++; 623 1.1 simonb 624 1.1 simonb stat = bus_space_read_4(sc->sc_st, sc->sc_dma_sh, 625 1.1 simonb MACDMA_RX_STAT(i)); 626 1.1 simonb 627 1.1 simonb #define PRINTERR(str) \ 628 1.1 simonb do { \ 629 1.1 simonb error++; \ 630 1.33 kiyohara printf("%s: %s\n", device_xname(sc->sc_dev), str); \ 631 1.1 simonb } while (0) 632 1.1 simonb 633 1.1 simonb if (stat & RX_STAT_ERRS) { 634 1.1 simonb int error = 0; 635 1.1 simonb 636 1.18 gdamore #if 0 /* 637 1.49 msaitoh * Missed frames are a semi-frequent occurrence with this hardware, 638 1.18 gdamore * and reporting of them just makes everything run slower and fills 639 1.18 gdamore * the system log. Be silent. 640 1.51 skrll * 641 1.18 gdamore * Additionally, this missed bit indicates an error with the previous 642 1.18 gdamore * packet, and not with this one! So PRINTERR is definitely wrong 643 1.18 gdamore * here. 644 1.18 gdamore * 645 1.18 gdamore * These should probably all be converted to evcnt counters anyway. 646 1.18 gdamore */ 647 1.1 simonb if (stat & RX_STAT_MI) 648 1.1 simonb PRINTERR("missed frame"); 649 1.18 gdamore #endif 650 1.1 simonb if (stat & RX_STAT_UC) 651 1.1 simonb PRINTERR("unknown control frame"); 652 1.1 simonb if (stat & RX_STAT_LE) 653 1.1 simonb PRINTERR("short frame"); 654 1.1 simonb if (stat & RX_STAT_CR) 655 1.1 simonb PRINTERR("CRC error"); 656 1.1 simonb if (stat & RX_STAT_ME) 657 1.1 simonb PRINTERR("medium error"); 658 1.1 simonb if (stat & RX_STAT_CS) 659 1.1 simonb PRINTERR("late collision"); 660 1.1 simonb if (stat & RX_STAT_FL) 661 1.1 simonb PRINTERR("frame too big"); 662 1.1 simonb if (stat & RX_STAT_RF) 663 1.1 simonb PRINTERR("runt frame (collision)"); 664 1.1 simonb if (stat & RX_STAT_WT) 665 1.1 simonb PRINTERR("watch dog"); 666 1.1 simonb if (stat & RX_STAT_DB) { 667 1.1 simonb if (stat & (RX_STAT_CS | RX_STAT_RF | 668 1.1 simonb RX_STAT_CR)) { 669 1.1 simonb if (!error) 670 1.1 simonb goto pktok; 671 1.1 simonb } else 672 1.1 simonb PRINTERR("dribbling bit"); 673 1.1 simonb } 674 1.1 simonb #undef PRINTERR 675 1.48 thorpej if_statinc(ifp, if_ierrors); 676 1.1 simonb 677 1.1 simonb dropit: 678 1.1 simonb /* reuse the current descriptor */ 679 1.1 simonb AUMAC_INIT_RXDESC(sc, i); 680 1.1 simonb continue; 681 1.1 simonb } 682 1.1 simonb pktok: 683 1.1 simonb len = RX_STAT_L(stat); 684 1.1 simonb 685 1.1 simonb /* 686 1.1 simonb * The Au1X00 MAC includes the CRC with every packet; 687 1.1 simonb * trim it off here. 688 1.1 simonb */ 689 1.1 simonb len -= ETHER_CRC_LEN; 690 1.1 simonb 691 1.1 simonb /* 692 1.1 simonb * Truncate the packet if it's too big to fit in 693 1.1 simonb * a single mbuf cluster. 694 1.1 simonb */ 695 1.1 simonb if (len > MCLBYTES - 2) 696 1.1 simonb len = MCLBYTES - 2; 697 1.1 simonb 698 1.1 simonb MGETHDR(m, M_DONTWAIT, MT_DATA); 699 1.1 simonb if (m == NULL) { 700 1.1 simonb printf("%s: unable to allocate Rx mbuf\n", 701 1.33 kiyohara device_xname(sc->sc_dev)); 702 1.1 simonb goto dropit; 703 1.1 simonb } 704 1.1 simonb if (len > MHLEN - 2) { 705 1.1 simonb MCLGET(m, M_DONTWAIT); 706 1.1 simonb if ((m->m_flags & M_EXT) == 0) { 707 1.1 simonb printf("%s: unable to allocate Rx cluster\n", 708 1.33 kiyohara device_xname(sc->sc_dev)); 709 1.1 simonb m_freem(m); 710 1.1 simonb goto dropit; 711 1.1 simonb } 712 1.1 simonb } 713 1.1 simonb 714 1.1 simonb m->m_data += 2; /* align payload */ 715 1.19 christos memcpy(mtod(m, void *), 716 1.20 simonb (void *)sc->sc_rxbufs[i].buf_vaddr, len); 717 1.1 simonb AUMAC_INIT_RXDESC(sc, i); 718 1.1 simonb 719 1.41 ozaki m_set_rcvif(m, ifp); 720 1.1 simonb m->m_pkthdr.len = m->m_len = len; 721 1.1 simonb 722 1.1 simonb /* Pass it on. */ 723 1.40 ozaki if_percpuq_enqueue(ifp->if_percpuq, m); 724 1.1 simonb } 725 1.1 simonb if (pkts) 726 1.1 simonb AUMAC_EVCNT_INCR(&sc->sc_ev_rxintr); 727 1.1 simonb if (pkts == AUMAC_NRXDESC) 728 1.1 simonb AUMAC_EVCNT_INCR(&sc->sc_ev_rxstall); 729 1.1 simonb 730 1.1 simonb /* Update the receive pointer. */ 731 1.1 simonb sc->sc_rxptr = i; 732 1.15 simonb 733 1.15 simonb return pkts; 734 1.1 simonb } 735 1.1 simonb 736 1.1 simonb /* 737 1.1 simonb * aumac_tick: 738 1.1 simonb * 739 1.1 simonb * One second timer, used to tick the MII. 740 1.1 simonb */ 741 1.1 simonb static void 742 1.1 simonb aumac_tick(void *arg) 743 1.1 simonb { 744 1.1 simonb struct aumac_softc *sc = arg; 745 1.1 simonb int s; 746 1.1 simonb 747 1.1 simonb s = splnet(); 748 1.1 simonb mii_tick(&sc->sc_mii); 749 1.1 simonb splx(s); 750 1.1 simonb 751 1.1 simonb callout_reset(&sc->sc_tick_ch, hz, aumac_tick, sc); 752 1.1 simonb } 753 1.1 simonb 754 1.1 simonb /* 755 1.1 simonb * aumac_init: [ifnet interface function] 756 1.1 simonb * 757 1.1 simonb * Initialize the interface. Must be called at splnet(). 758 1.1 simonb */ 759 1.1 simonb static int 760 1.1 simonb aumac_init(struct ifnet *ifp) 761 1.1 simonb { 762 1.1 simonb struct aumac_softc *sc = ifp->if_softc; 763 1.1 simonb int i, error = 0; 764 1.1 simonb 765 1.1 simonb /* Cancel any pending I/O, reset MAC. */ 766 1.1 simonb aumac_stop(ifp, 0); 767 1.1 simonb 768 1.1 simonb /* Set up the transmit ring. */ 769 1.1 simonb for (i = 0; i < AUMAC_NTXDESC; i++) { 770 1.1 simonb bus_space_write_4(sc->sc_st, sc->sc_dma_sh, 771 1.1 simonb MACDMA_TX_STAT(i), 0); 772 1.1 simonb bus_space_write_4(sc->sc_st, sc->sc_dma_sh, 773 1.1 simonb MACDMA_TX_LEN(i), 0); 774 1.1 simonb bus_space_write_4(sc->sc_st, sc->sc_dma_sh, 775 1.1 simonb MACDMA_TX_ADDR(i), sc->sc_txbufs[i].buf_paddr); 776 1.1 simonb } 777 1.1 simonb sc->sc_txfree = AUMAC_NTXDESC; 778 1.1 simonb sc->sc_txnext = TX_ADDR_CB(bus_space_read_4(sc->sc_st, sc->sc_dma_sh, 779 1.1 simonb MACDMA_TX_ADDR(0))); 780 1.1 simonb sc->sc_txdirty = sc->sc_txnext; 781 1.1 simonb 782 1.1 simonb /* Set up the receive ring. */ 783 1.1 simonb for (i = 0; i < AUMAC_NRXDESC; i++) 784 1.1 simonb AUMAC_INIT_RXDESC(sc, i); 785 1.1 simonb sc->sc_rxptr = RX_ADDR_CB(bus_space_read_4(sc->sc_st, sc->sc_dma_sh, 786 1.1 simonb MACDMA_RX_ADDR(0))); 787 1.1 simonb 788 1.1 simonb /* 789 1.1 simonb * Power up the MAC. 790 1.1 simonb */ 791 1.1 simonb aumac_powerup(sc); 792 1.1 simonb 793 1.1 simonb sc->sc_control |= CONTROL_DO | CONTROL_TE | CONTROL_RE; 794 1.1 simonb #if _BYTE_ORDER == _BIG_ENDIAN 795 1.1 simonb sc->sc_control |= CONTROL_EM; 796 1.1 simonb #endif 797 1.1 simonb 798 1.1 simonb /* Set the media. */ 799 1.24 dyoung if ((error = ether_mediachange(ifp)) != 0) 800 1.24 dyoung goto out; 801 1.1 simonb 802 1.1 simonb /* 803 1.1 simonb * Set the receive filter. This will actually start the transmit 804 1.1 simonb * and receive processes. 805 1.1 simonb */ 806 1.1 simonb aumac_set_filter(sc); 807 1.1 simonb 808 1.1 simonb /* Start the one second clock. */ 809 1.1 simonb callout_reset(&sc->sc_tick_ch, hz, aumac_tick, sc); 810 1.1 simonb 811 1.1 simonb /* ...all done! */ 812 1.46 msaitoh ifp->if_flags |= IFF_RUNNING; 813 1.1 simonb 814 1.35 kiyohara au_intr_enable(sc->sc_irq); 815 1.24 dyoung out: 816 1.1 simonb if (error) 817 1.33 kiyohara printf("%s: interface not running\n", device_xname(sc->sc_dev)); 818 1.46 msaitoh return error; 819 1.1 simonb } 820 1.1 simonb 821 1.1 simonb /* 822 1.1 simonb * aumac_stop: [ifnet interface function] 823 1.1 simonb * 824 1.1 simonb * Stop transmission on the interface. 825 1.1 simonb */ 826 1.1 simonb static void 827 1.1 simonb aumac_stop(struct ifnet *ifp, int disable) 828 1.1 simonb { 829 1.1 simonb struct aumac_softc *sc = ifp->if_softc; 830 1.1 simonb 831 1.1 simonb /* Stop the one-second clock. */ 832 1.1 simonb callout_stop(&sc->sc_tick_ch); 833 1.1 simonb 834 1.1 simonb /* Down the MII. */ 835 1.1 simonb mii_down(&sc->sc_mii); 836 1.1 simonb 837 1.1 simonb /* Stop the transmit and receive processes. */ 838 1.1 simonb bus_space_write_4(sc->sc_st, sc->sc_mac_sh, MAC_CONTROL, 0); 839 1.1 simonb 840 1.1 simonb /* Power down/reset the MAC. */ 841 1.1 simonb aumac_powerdown(sc); 842 1.1 simonb 843 1.35 kiyohara au_intr_disable(sc->sc_irq); 844 1.35 kiyohara 845 1.1 simonb /* Mark the interface as down and cancel the watchdog timer. */ 846 1.50 thorpej ifp->if_flags &= ~IFF_RUNNING; 847 1.1 simonb ifp->if_timer = 0; 848 1.1 simonb } 849 1.1 simonb 850 1.1 simonb /* 851 1.1 simonb * aumac_powerdown: 852 1.1 simonb * 853 1.1 simonb * Power down the MAC. 854 1.1 simonb */ 855 1.1 simonb static void 856 1.1 simonb aumac_powerdown(struct aumac_softc *sc) 857 1.1 simonb { 858 1.1 simonb 859 1.1 simonb /* Disable the MAC clocks, and place the device in reset. */ 860 1.1 simonb // bus_space_write_4(sc->sc_st, sc->sc_macen_sh, 0, MACEN_JP); 861 1.1 simonb 862 1.1 simonb // delay(10000); 863 1.1 simonb } 864 1.1 simonb 865 1.1 simonb /* 866 1.1 simonb * aumac_powerup: 867 1.1 simonb * 868 1.1 simonb * Bring the device out of reset. 869 1.1 simonb */ 870 1.1 simonb static void 871 1.1 simonb aumac_powerup(struct aumac_softc *sc) 872 1.1 simonb { 873 1.1 simonb 874 1.1 simonb /* Enable clocks to the MAC. */ 875 1.46 msaitoh bus_space_write_4(sc->sc_st, sc->sc_macen_sh, 0, MACEN_JP | MACEN_CE); 876 1.1 simonb 877 1.1 simonb /* Enable MAC, coherent transactions, pass only valid frames. */ 878 1.1 simonb bus_space_write_4(sc->sc_st, sc->sc_macen_sh, 0, 879 1.46 msaitoh MACEN_E2 | MACEN_E1 | MACEN_E0 | MACEN_CE); 880 1.1 simonb 881 1.1 simonb delay(20000); 882 1.1 simonb } 883 1.1 simonb 884 1.1 simonb /* 885 1.1 simonb * aumac_set_filter: 886 1.1 simonb * 887 1.1 simonb * Set up the receive filter. 888 1.1 simonb */ 889 1.1 simonb static void 890 1.1 simonb aumac_set_filter(struct aumac_softc *sc) 891 1.1 simonb { 892 1.1 simonb struct ethercom *ec = &sc->sc_ethercom; 893 1.1 simonb struct ifnet *ifp = &sc->sc_ethercom.ec_if; 894 1.1 simonb struct ether_multi *enm; 895 1.1 simonb struct ether_multistep step; 896 1.22 dyoung const uint8_t *enaddr = CLLADDR(ifp->if_sadl); 897 1.1 simonb uint32_t mchash[2], crc; 898 1.1 simonb 899 1.1 simonb sc->sc_control &= ~(CONTROL_PM | CONTROL_PR); 900 1.1 simonb 901 1.1 simonb /* Stop the receiver. */ 902 1.1 simonb bus_space_write_4(sc->sc_st, sc->sc_mac_sh, MAC_CONTROL, 903 1.1 simonb sc->sc_control & ~CONTROL_RE); 904 1.1 simonb 905 1.1 simonb if (ifp->if_flags & IFF_PROMISC) { 906 1.1 simonb sc->sc_control |= CONTROL_PR; 907 1.1 simonb goto allmulti; 908 1.1 simonb } 909 1.1 simonb 910 1.1 simonb /* Set the station address. */ 911 1.1 simonb bus_space_write_4(sc->sc_st, sc->sc_mac_sh, MAC_ADDRHIGH, 912 1.1 simonb enaddr[4] | (enaddr[5] << 8)); 913 1.1 simonb bus_space_write_4(sc->sc_st, sc->sc_mac_sh, MAC_ADDRLOW, 914 1.1 simonb enaddr[0] | (enaddr[1] << 8) | (enaddr[2] << 16) | 915 1.1 simonb (enaddr[3] << 24)); 916 1.1 simonb 917 1.1 simonb sc->sc_control |= CONTROL_HP; 918 1.1 simonb 919 1.1 simonb mchash[0] = mchash[1] = 0; 920 1.1 simonb 921 1.1 simonb /* 922 1.1 simonb * Set up the multicast address filter by passing all multicast 923 1.1 simonb * addresses through a CRC generator, and then using the high 924 1.1 simonb * order 6 bits as an index into the 64-bit multicast hash table. 925 1.1 simonb * The high order bits select the word, while the rest of the bits 926 1.1 simonb * select the bit within the word. 927 1.1 simonb */ 928 1.47 msaitoh ETHER_LOCK(ec); 929 1.1 simonb ETHER_FIRST_MULTI(step, ec, enm); 930 1.1 simonb while (enm != NULL) { 931 1.1 simonb if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) { 932 1.1 simonb /* 933 1.1 simonb * We must listen to a range of multicast addresses. 934 1.1 simonb * For now, just accept all multicasts, rather than 935 1.1 simonb * trying to set only those filter bits needed to match 936 1.1 simonb * the range. (At this time, the only use of address 937 1.1 simonb * ranges is for IP multicast routing, for which the 938 1.1 simonb * range is large enough to require all bits set.) 939 1.1 simonb */ 940 1.47 msaitoh ETHER_UNLOCK(ec); 941 1.1 simonb goto allmulti; 942 1.1 simonb } 943 1.1 simonb 944 1.1 simonb crc = ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN); 945 1.1 simonb 946 1.1 simonb /* Just want the 6 most significant bits. */ 947 1.1 simonb crc >>= 26; 948 1.1 simonb 949 1.1 simonb /* Set the corresponding bit in the filter. */ 950 1.1 simonb mchash[crc >> 5] |= 1U << (crc & 0x1f); 951 1.1 simonb 952 1.1 simonb ETHER_NEXT_MULTI(step, enm); 953 1.1 simonb } 954 1.47 msaitoh ETHER_UNLOCK(ec); 955 1.1 simonb 956 1.1 simonb ifp->if_flags &= ~IFF_ALLMULTI; 957 1.1 simonb 958 1.1 simonb bus_space_write_4(sc->sc_st, sc->sc_mac_sh, MAC_HASHHIGH, 959 1.1 simonb mchash[1]); 960 1.1 simonb bus_space_write_4(sc->sc_st, sc->sc_mac_sh, MAC_HASHLOW, 961 1.1 simonb mchash[0]); 962 1.1 simonb 963 1.1 simonb bus_space_write_4(sc->sc_st, sc->sc_mac_sh, MAC_CONTROL, 964 1.1 simonb sc->sc_control); 965 1.1 simonb return; 966 1.1 simonb 967 1.1 simonb allmulti: 968 1.1 simonb sc->sc_control |= CONTROL_PM; 969 1.1 simonb bus_space_write_4(sc->sc_st, sc->sc_mac_sh, MAC_CONTROL, 970 1.1 simonb sc->sc_control); 971 1.1 simonb } 972 1.1 simonb 973 1.1 simonb /* 974 1.1 simonb * aumac_mii_wait: 975 1.1 simonb * 976 1.1 simonb * Wait for the MII interface to not be busy. 977 1.1 simonb */ 978 1.1 simonb static int 979 1.1 simonb aumac_mii_wait(struct aumac_softc *sc, const char *msg) 980 1.1 simonb { 981 1.1 simonb int i; 982 1.1 simonb 983 1.1 simonb for (i = 0; i < 10000; i++) { 984 1.1 simonb if ((bus_space_read_4(sc->sc_st, sc->sc_mac_sh, 985 1.1 simonb MAC_MIICTRL) & MIICTRL_MB) == 0) 986 1.46 msaitoh return 0; 987 1.1 simonb delay(10); 988 1.1 simonb } 989 1.1 simonb 990 1.33 kiyohara printf("%s: MII failed to %s\n", device_xname(sc->sc_dev), msg); 991 1.45 msaitoh return ETIMEDOUT; 992 1.1 simonb } 993 1.1 simonb 994 1.1 simonb /* 995 1.1 simonb * aumac_mii_readreg: [mii interface function] 996 1.1 simonb * 997 1.1 simonb * Read a PHY register on the MII. 998 1.1 simonb */ 999 1.1 simonb static int 1000 1.45 msaitoh aumac_mii_readreg(device_t self, int phy, int reg, uint16_t *val) 1001 1.1 simonb { 1002 1.33 kiyohara struct aumac_softc *sc = device_private(self); 1003 1.45 msaitoh int rv; 1004 1.1 simonb 1005 1.45 msaitoh if ((rv = aumac_mii_wait(sc, "become ready")) != 0) 1006 1.45 msaitoh return rv; 1007 1.1 simonb 1008 1.1 simonb bus_space_write_4(sc->sc_st, sc->sc_mac_sh, MAC_MIICTRL, 1009 1.1 simonb MIICTRL_PHYADDR(phy) | MIICTRL_MIIREG(reg)); 1010 1.1 simonb 1011 1.45 msaitoh if ((rv = aumac_mii_wait(sc, "complete")) != 0) 1012 1.45 msaitoh return rv; 1013 1.1 simonb 1014 1.45 msaitoh *val = bus_space_read_4(sc->sc_st, sc->sc_mac_sh, MAC_MIIDATA) 1015 1.45 msaitoh & MIIDATA_MASK; 1016 1.45 msaitoh return 0; 1017 1.1 simonb } 1018 1.1 simonb 1019 1.1 simonb /* 1020 1.1 simonb * aumac_mii_writereg: [mii interface function] 1021 1.1 simonb * 1022 1.1 simonb * Write a PHY register on the MII. 1023 1.1 simonb */ 1024 1.45 msaitoh static int 1025 1.45 msaitoh aumac_mii_writereg(device_t self, int phy, int reg, uint16_t val) 1026 1.1 simonb { 1027 1.33 kiyohara struct aumac_softc *sc = device_private(self); 1028 1.45 msaitoh int rv; 1029 1.1 simonb 1030 1.45 msaitoh if ((rv = aumac_mii_wait(sc, "become ready")) != 0) 1031 1.45 msaitoh return rv; 1032 1.1 simonb 1033 1.1 simonb bus_space_write_4(sc->sc_st, sc->sc_mac_sh, MAC_MIIDATA, val); 1034 1.1 simonb bus_space_write_4(sc->sc_st, sc->sc_mac_sh, MAC_MIICTRL, 1035 1.1 simonb MIICTRL_PHYADDR(phy) | MIICTRL_MIIREG(reg) | MIICTRL_MW); 1036 1.1 simonb 1037 1.45 msaitoh return aumac_mii_wait(sc, "complete"); 1038 1.1 simonb } 1039 1.1 simonb 1040 1.1 simonb /* 1041 1.1 simonb * aumac_mii_statchg: [mii interface function] 1042 1.1 simonb * 1043 1.1 simonb * Callback from MII layer when media changes. 1044 1.1 simonb */ 1045 1.1 simonb static void 1046 1.37 matt aumac_mii_statchg(struct ifnet *ifp) 1047 1.1 simonb { 1048 1.37 matt struct aumac_softc *sc = ifp->if_softc; 1049 1.1 simonb 1050 1.1 simonb if ((sc->sc_mii.mii_media_active & IFM_FDX) != 0) 1051 1.1 simonb sc->sc_control |= CONTROL_F; 1052 1.1 simonb else 1053 1.1 simonb sc->sc_control &= ~CONTROL_F; 1054 1.1 simonb 1055 1.1 simonb bus_space_write_4(sc->sc_st, sc->sc_mac_sh, MAC_CONTROL, 1056 1.1 simonb sc->sc_control); 1057 1.1 simonb } 1058