1 1.31 andvar /* $NetBSD: if_admsw.c,v 1.31 2024/02/10 09:30:05 andvar Exp $ */ 2 1.1 dyoung 3 1.1 dyoung /*- 4 1.1 dyoung * Copyright (c) 2007 Ruslan Ermilov and Vsevolod Lobko. 5 1.1 dyoung * All rights reserved. 6 1.1 dyoung * 7 1.1 dyoung * Redistribution and use in source and binary forms, with or 8 1.1 dyoung * without modification, are permitted provided that the following 9 1.1 dyoung * conditions are met: 10 1.1 dyoung * 1. Redistributions of source code must retain the above copyright 11 1.1 dyoung * notice, this list of conditions and the following disclaimer. 12 1.1 dyoung * 2. Redistributions in binary form must reproduce the above 13 1.1 dyoung * copyright notice, this list of conditions and the following 14 1.1 dyoung * disclaimer in the documentation and/or other materials provided 15 1.1 dyoung * with the distribution. 16 1.1 dyoung * 3. The names of the authors may not be used to endorse or promote 17 1.1 dyoung * products derived from this software without specific prior 18 1.1 dyoung * written permission. 19 1.1 dyoung * 20 1.1 dyoung * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY 21 1.1 dyoung * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 22 1.1 dyoung * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 23 1.1 dyoung * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS 24 1.1 dyoung * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 25 1.1 dyoung * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26 1.1 dyoung * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 27 1.1 dyoung * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 1.1 dyoung * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 29 1.1 dyoung * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 30 1.1 dyoung * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 31 1.1 dyoung * OF SUCH DAMAGE. 32 1.1 dyoung */ 33 1.1 dyoung /* 34 1.1 dyoung * Copyright (c) 2001 Wasabi Systems, Inc. 35 1.1 dyoung * All rights reserved. 36 1.1 dyoung * 37 1.1 dyoung * Written by Jason R. Thorpe for Wasabi Systems, Inc. 38 1.1 dyoung * 39 1.1 dyoung * Redistribution and use in source and binary forms, with or without 40 1.1 dyoung * modification, are permitted provided that the following conditions 41 1.1 dyoung * are met: 42 1.1 dyoung * 1. Redistributions of source code must retain the above copyright 43 1.1 dyoung * notice, this list of conditions and the following disclaimer. 44 1.1 dyoung * 2. Redistributions in binary form must reproduce the above copyright 45 1.1 dyoung * notice, this list of conditions and the following disclaimer in the 46 1.1 dyoung * documentation and/or other materials provided with the distribution. 47 1.1 dyoung * 3. All advertising materials mentioning features or use of this software 48 1.1 dyoung * must display the following acknowledgement: 49 1.1 dyoung * This product includes software developed for the NetBSD Project by 50 1.1 dyoung * Wasabi Systems, Inc. 51 1.1 dyoung * 4. The name of Wasabi Systems, Inc. may not be used to endorse 52 1.1 dyoung * or promote products derived from this software without specific prior 53 1.1 dyoung * written permission. 54 1.1 dyoung * 55 1.1 dyoung * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 56 1.1 dyoung * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 57 1.1 dyoung * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 58 1.1 dyoung * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 59 1.1 dyoung * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 60 1.1 dyoung * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 61 1.1 dyoung * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 62 1.1 dyoung * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 63 1.1 dyoung * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 64 1.1 dyoung * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 65 1.1 dyoung * POSSIBILITY OF SUCH DAMAGE. 66 1.1 dyoung */ 67 1.1 dyoung 68 1.1 dyoung /* 69 1.1 dyoung * Device driver for Alchemy Semiconductor Au1x00 Ethernet Media 70 1.1 dyoung * Access Controller. 71 1.1 dyoung * 72 1.1 dyoung * TODO: 73 1.1 dyoung * 74 1.1 dyoung * Better Rx buffer management; we want to get new Rx buffers 75 1.1 dyoung * to the chip more quickly than we currently do. 76 1.1 dyoung */ 77 1.1 dyoung 78 1.1 dyoung #include <sys/cdefs.h> 79 1.31 andvar __KERNEL_RCSID(0, "$NetBSD: if_admsw.c,v 1.31 2024/02/10 09:30:05 andvar Exp $"); 80 1.1 dyoung 81 1.1 dyoung 82 1.1 dyoung #include <sys/param.h> 83 1.10 matt #include <sys/bus.h> 84 1.1 dyoung #include <sys/callout.h> 85 1.10 matt #include <sys/device.h> 86 1.10 matt #include <sys/endian.h> 87 1.10 matt #include <sys/errno.h> 88 1.10 matt #include <sys/intr.h> 89 1.10 matt #include <sys/ioctl.h> 90 1.10 matt #include <sys/kernel.h> 91 1.1 dyoung #include <sys/mbuf.h> 92 1.1 dyoung #include <sys/socket.h> 93 1.10 matt #include <sys/systm.h> 94 1.1 dyoung 95 1.1 dyoung #include <prop/proplib.h> 96 1.1 dyoung 97 1.1 dyoung #include <uvm/uvm_extern.h> /* for PAGE_SIZE */ 98 1.1 dyoung 99 1.1 dyoung #include <net/if.h> 100 1.1 dyoung #include <net/if_dl.h> 101 1.1 dyoung #include <net/if_media.h> 102 1.1 dyoung #include <net/if_ether.h> 103 1.1 dyoung #include <net/bpf.h> 104 1.1 dyoung 105 1.1 dyoung #include <sys/gpio.h> 106 1.1 dyoung #include <dev/gpio/gpiovar.h> 107 1.1 dyoung 108 1.1 dyoung #include <mips/adm5120/include/adm5120reg.h> 109 1.1 dyoung #include <mips/adm5120/include/adm5120var.h> 110 1.1 dyoung #include <mips/adm5120/include/adm5120_obiovar.h> 111 1.1 dyoung #include <mips/adm5120/dev/if_admswreg.h> 112 1.1 dyoung #include <mips/adm5120/dev/if_admswvar.h> 113 1.1 dyoung 114 1.1 dyoung static uint8_t vlan_matrix[SW_DEVS] = { 115 1.1 dyoung (1 << 6) | (1 << 0), /* CPU + port0 */ 116 1.1 dyoung (1 << 6) | (1 << 1), /* CPU + port1 */ 117 1.1 dyoung (1 << 6) | (1 << 2), /* CPU + port2 */ 118 1.1 dyoung (1 << 6) | (1 << 3), /* CPU + port3 */ 119 1.1 dyoung (1 << 6) | (1 << 4), /* CPU + port4 */ 120 1.1 dyoung (1 << 6) | (1 << 5), /* CPU + port5 */ 121 1.1 dyoung }; 122 1.1 dyoung 123 1.1 dyoung #ifdef ADMSW_EVENT_COUNTERS 124 1.1 dyoung #define ADMSW_EVCNT_INCR(ev) (ev)->ev_count++ 125 1.1 dyoung #else 126 1.1 dyoung #define ADMSW_EVCNT_INCR(ev) /* nothing */ 127 1.1 dyoung #endif 128 1.1 dyoung 129 1.1 dyoung static void admsw_start(struct ifnet *); 130 1.1 dyoung static void admsw_watchdog(struct ifnet *); 131 1.1 dyoung static int admsw_ioctl(struct ifnet *, u_long, void *); 132 1.1 dyoung static int admsw_init(struct ifnet *); 133 1.1 dyoung static void admsw_stop(struct ifnet *, int); 134 1.1 dyoung 135 1.1 dyoung static void admsw_shutdown(void *); 136 1.1 dyoung 137 1.1 dyoung static void admsw_reset(struct admsw_softc *); 138 1.1 dyoung static void admsw_set_filter(struct admsw_softc *); 139 1.1 dyoung 140 1.1 dyoung static int admsw_intr(void *); 141 1.1 dyoung static void admsw_txintr(struct admsw_softc *, int); 142 1.1 dyoung static void admsw_rxintr(struct admsw_softc *, int); 143 1.1 dyoung static int admsw_add_rxbuf(struct admsw_softc *, int, int); 144 1.1 dyoung #define admsw_add_rxhbuf(sc, idx) admsw_add_rxbuf(sc, idx, 1) 145 1.1 dyoung #define admsw_add_rxlbuf(sc, idx) admsw_add_rxbuf(sc, idx, 0) 146 1.1 dyoung 147 1.1 dyoung static int admsw_mediachange(struct ifnet *); 148 1.1 dyoung static void admsw_mediastatus(struct ifnet *, struct ifmediareq *); 149 1.1 dyoung 150 1.11 chs static int admsw_match(device_t, cfdata_t, void *); 151 1.11 chs static void admsw_attach(device_t, device_t, void *); 152 1.1 dyoung 153 1.11 chs CFATTACH_DECL_NEW(admsw, sizeof(struct admsw_softc), 154 1.1 dyoung admsw_match, admsw_attach, NULL, NULL); 155 1.1 dyoung 156 1.1 dyoung static int 157 1.11 chs admsw_match(device_t parent, cfdata_t cf, void *aux) 158 1.1 dyoung { 159 1.1 dyoung struct obio_attach_args *aa = aux; 160 1.1 dyoung 161 1.1 dyoung return strcmp(aa->oba_name, cf->cf_name) == 0; 162 1.1 dyoung } 163 1.1 dyoung 164 1.1 dyoung #define REG_READ(o) bus_space_read_4(sc->sc_st, sc->sc_ioh, (o)) 165 1.23 msaitoh #define REG_WRITE(o, v) bus_space_write_4(sc->sc_st, sc->sc_ioh, (o),(v)) 166 1.1 dyoung 167 1.1 dyoung 168 1.1 dyoung static void 169 1.1 dyoung admsw_init_bufs(struct admsw_softc *sc) 170 1.1 dyoung { 171 1.1 dyoung int i; 172 1.1 dyoung struct admsw_desc *desc; 173 1.1 dyoung 174 1.1 dyoung for (i = 0; i < ADMSW_NTXHDESC; i++) { 175 1.1 dyoung if (sc->sc_txhsoft[i].ds_mbuf != NULL) { 176 1.1 dyoung m_freem(sc->sc_txhsoft[i].ds_mbuf); 177 1.1 dyoung sc->sc_txhsoft[i].ds_mbuf = NULL; 178 1.1 dyoung } 179 1.1 dyoung desc = &sc->sc_txhdescs[i]; 180 1.1 dyoung desc->data = 0; 181 1.1 dyoung desc->cntl = 0; 182 1.1 dyoung desc->len = MAC_BUFLEN; 183 1.1 dyoung desc->status = 0; 184 1.1 dyoung ADMSW_CDTXHSYNC(sc, i, 185 1.23 msaitoh BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 186 1.1 dyoung } 187 1.1 dyoung sc->sc_txhdescs[ADMSW_NTXHDESC - 1].data |= ADM5120_DMA_RINGEND; 188 1.1 dyoung ADMSW_CDTXHSYNC(sc, ADMSW_NTXHDESC - 1, 189 1.23 msaitoh BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 190 1.1 dyoung 191 1.1 dyoung for (i = 0; i < ADMSW_NRXHDESC; i++) { 192 1.1 dyoung if (sc->sc_rxhsoft[i].ds_mbuf == NULL) { 193 1.1 dyoung if (admsw_add_rxhbuf(sc, i) != 0) 194 1.1 dyoung panic("admsw_init_bufs\n"); 195 1.1 dyoung } else 196 1.1 dyoung ADMSW_INIT_RXHDESC(sc, i); 197 1.1 dyoung } 198 1.1 dyoung 199 1.1 dyoung for (i = 0; i < ADMSW_NTXLDESC; i++) { 200 1.1 dyoung if (sc->sc_txlsoft[i].ds_mbuf != NULL) { 201 1.1 dyoung m_freem(sc->sc_txlsoft[i].ds_mbuf); 202 1.1 dyoung sc->sc_txlsoft[i].ds_mbuf = NULL; 203 1.1 dyoung } 204 1.1 dyoung desc = &sc->sc_txldescs[i]; 205 1.1 dyoung desc->data = 0; 206 1.1 dyoung desc->cntl = 0; 207 1.1 dyoung desc->len = MAC_BUFLEN; 208 1.1 dyoung desc->status = 0; 209 1.1 dyoung ADMSW_CDTXLSYNC(sc, i, 210 1.23 msaitoh BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 211 1.1 dyoung } 212 1.1 dyoung sc->sc_txldescs[ADMSW_NTXLDESC - 1].data |= ADM5120_DMA_RINGEND; 213 1.1 dyoung ADMSW_CDTXLSYNC(sc, ADMSW_NTXLDESC - 1, 214 1.23 msaitoh BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 215 1.1 dyoung 216 1.1 dyoung for (i = 0; i < ADMSW_NRXLDESC; i++) { 217 1.1 dyoung if (sc->sc_rxlsoft[i].ds_mbuf == NULL) { 218 1.1 dyoung if (admsw_add_rxlbuf(sc, i) != 0) 219 1.1 dyoung panic("admsw_init_bufs\n"); 220 1.1 dyoung } else 221 1.1 dyoung ADMSW_INIT_RXLDESC(sc, i); 222 1.1 dyoung } 223 1.1 dyoung 224 1.1 dyoung REG_WRITE(SEND_HBADDR_REG, ADMSW_CDTXHADDR(sc, 0)); 225 1.1 dyoung REG_WRITE(SEND_LBADDR_REG, ADMSW_CDTXLADDR(sc, 0)); 226 1.1 dyoung REG_WRITE(RECV_HBADDR_REG, ADMSW_CDRXHADDR(sc, 0)); 227 1.1 dyoung REG_WRITE(RECV_LBADDR_REG, ADMSW_CDRXLADDR(sc, 0)); 228 1.1 dyoung 229 1.1 dyoung sc->sc_txfree = ADMSW_NTXLDESC; 230 1.1 dyoung sc->sc_txnext = 0; 231 1.1 dyoung sc->sc_txdirty = 0; 232 1.1 dyoung sc->sc_rxptr = 0; 233 1.1 dyoung } 234 1.1 dyoung 235 1.1 dyoung static void 236 1.1 dyoung admsw_setvlan(struct admsw_softc *sc, char matrix[6]) 237 1.1 dyoung { 238 1.1 dyoung uint32_t i; 239 1.1 dyoung 240 1.22 msaitoh i = matrix[0] + (matrix[1] << 8) + (matrix[2] << 16) 241 1.22 msaitoh + (matrix[3] << 24); 242 1.1 dyoung REG_WRITE(VLAN_G1_REG, i); 243 1.1 dyoung i = matrix[4] + (matrix[5] << 8); 244 1.1 dyoung REG_WRITE(VLAN_G2_REG, i); 245 1.1 dyoung } 246 1.1 dyoung 247 1.1 dyoung static void 248 1.1 dyoung admsw_reset(struct admsw_softc *sc) 249 1.1 dyoung { 250 1.1 dyoung uint32_t wdog1; 251 1.1 dyoung int i; 252 1.1 dyoung 253 1.1 dyoung REG_WRITE(PORT_CONF0_REG, 254 1.1 dyoung REG_READ(PORT_CONF0_REG) | PORT_CONF0_DP_MASK); 255 1.1 dyoung REG_WRITE(CPUP_CONF_REG, 256 1.1 dyoung REG_READ(CPUP_CONF_REG) | CPUP_CONF_DCPUP); 257 1.1 dyoung 258 1.22 msaitoh /* Wait for DMA to complete. Overkill. In 3ms, we can 259 1.22 msaitoh * send at least two entire 1500-byte packets at 10 Mb/s. 260 1.1 dyoung */ 261 1.1 dyoung DELAY(3000); 262 1.1 dyoung 263 1.22 msaitoh /* The datasheet recommends that we move all PHYs to reset 264 1.22 msaitoh * state prior to software reset. 265 1.1 dyoung */ 266 1.1 dyoung REG_WRITE(PHY_CNTL2_REG, 267 1.1 dyoung REG_READ(PHY_CNTL2_REG) & ~PHY_CNTL2_PHYR_MASK); 268 1.1 dyoung 269 1.1 dyoung /* Reset the switch. */ 270 1.1 dyoung REG_WRITE(ADMSW_SW_RES, 0x1); 271 1.1 dyoung 272 1.1 dyoung DELAY(100 * 1000); 273 1.1 dyoung 274 1.1 dyoung REG_WRITE(ADMSW_BOOT_DONE, ADMSW_BOOT_DONE_BO); 275 1.1 dyoung 276 1.1 dyoung /* begin old code */ 277 1.1 dyoung REG_WRITE(CPUP_CONF_REG, 278 1.1 dyoung CPUP_CONF_DCPUP | CPUP_CONF_CRCP | CPUP_CONF_DUNP_MASK | 279 1.1 dyoung CPUP_CONF_DMCP_MASK); 280 1.1 dyoung 281 1.1 dyoung REG_WRITE(PORT_CONF0_REG, PORT_CONF0_EMCP_MASK | PORT_CONF0_EMBP_MASK); 282 1.1 dyoung 283 1.1 dyoung REG_WRITE(PHY_CNTL2_REG, 284 1.22 msaitoh REG_READ(PHY_CNTL2_REG) | PHY_CNTL2_ANE_MASK | 285 1.22 msaitoh PHY_CNTL2_PHYR_MASK | PHY_CNTL2_AMDIX_MASK); 286 1.1 dyoung 287 1.1 dyoung REG_WRITE(PHY_CNTL3_REG, REG_READ(PHY_CNTL3_REG) | PHY_CNTL3_RNT); 288 1.1 dyoung 289 1.1 dyoung REG_WRITE(ADMSW_INT_MASK, INT_MASK); 290 1.1 dyoung REG_WRITE(ADMSW_INT_ST, INT_MASK); 291 1.1 dyoung 292 1.1 dyoung /* 293 1.1 dyoung * While in DDB, we stop servicing interrupts, RX ring 294 1.1 dyoung * fills up and when free block counter falls behind FC 295 1.1 dyoung * threshold, the switch starts to emit 802.3x PAUSE 296 1.1 dyoung * frames. This can upset peer switches. 297 1.1 dyoung * 298 1.1 dyoung * Stop this from happening by disabling FC and D2 299 1.1 dyoung * thresholds. 300 1.1 dyoung */ 301 1.1 dyoung REG_WRITE(FC_TH_REG, 302 1.1 dyoung REG_READ(FC_TH_REG) & ~(FC_TH_FCS_MASK | FC_TH_D2S_MASK)); 303 1.1 dyoung 304 1.1 dyoung admsw_setvlan(sc, vlan_matrix); 305 1.1 dyoung 306 1.1 dyoung for (i = 0; i < SW_DEVS; i++) { 307 1.1 dyoung REG_WRITE(MAC_WT1_REG, 308 1.1 dyoung sc->sc_enaddr[2] | 309 1.1 dyoung (sc->sc_enaddr[3]<<8) | 310 1.1 dyoung (sc->sc_enaddr[4]<<16) | 311 1.1 dyoung ((sc->sc_enaddr[5]+i)<<24)); 312 1.1 dyoung REG_WRITE(MAC_WT0_REG, (i<<MAC_WT0_VLANID_SHIFT) | 313 1.1 dyoung (sc->sc_enaddr[0]<<16) | (sc->sc_enaddr[1]<<24) | 314 1.1 dyoung MAC_WT0_WRITE | MAC_WT0_VLANID_EN); 315 1.1 dyoung 316 1.23 msaitoh while (!(REG_READ(MAC_WT0_REG) & MAC_WT0_WRITE_DONE)) 317 1.23 msaitoh ; 318 1.1 dyoung } 319 1.1 dyoung wdog1 = REG_READ(ADM5120_WDOG1); 320 1.1 dyoung REG_WRITE(ADM5120_WDOG1, wdog1 & ~ADM5120_WDOG1_WDE); 321 1.1 dyoung } 322 1.1 dyoung 323 1.1 dyoung static void 324 1.11 chs admsw_attach(device_t parent, device_t self, void *aux) 325 1.1 dyoung { 326 1.1 dyoung uint8_t enaddr[ETHER_ADDR_LEN]; 327 1.11 chs struct admsw_softc *sc = device_private(self); 328 1.1 dyoung struct obio_attach_args *aa = aux; 329 1.1 dyoung struct ifnet *ifp; 330 1.1 dyoung bus_dma_segment_t seg; 331 1.1 dyoung int error, i, rseg; 332 1.1 dyoung prop_data_t pd; 333 1.1 dyoung 334 1.1 dyoung printf(": ADM5120 Switch Engine, %d ports\n", SW_DEVS); 335 1.1 dyoung 336 1.11 chs sc->sc_dev = self; 337 1.1 dyoung sc->sc_dmat = aa->oba_dt; 338 1.1 dyoung sc->sc_st = aa->oba_st; 339 1.1 dyoung 340 1.11 chs pd = prop_dictionary_get(device_properties(self), "mac-address"); 341 1.1 dyoung 342 1.1 dyoung if (pd == NULL) { 343 1.1 dyoung enaddr[0] = 0x02; 344 1.1 dyoung enaddr[1] = 0xaa; 345 1.1 dyoung enaddr[2] = 0xbb; 346 1.1 dyoung enaddr[3] = 0xcc; 347 1.1 dyoung enaddr[4] = 0xdd; 348 1.1 dyoung enaddr[5] = 0xee; 349 1.1 dyoung } else 350 1.1 dyoung memcpy(enaddr, prop_data_data_nocopy(pd), sizeof(enaddr)); 351 1.1 dyoung 352 1.1 dyoung memcpy(sc->sc_enaddr, enaddr, sizeof(sc->sc_enaddr)); 353 1.1 dyoung 354 1.11 chs printf("%s: base Ethernet address %s\n", device_xname(sc->sc_dev), 355 1.1 dyoung ether_sprintf(enaddr)); 356 1.1 dyoung 357 1.1 dyoung /* Map the device. */ 358 1.1 dyoung if (bus_space_map(sc->sc_st, aa->oba_addr, 512, 0, &sc->sc_ioh) != 0) { 359 1.11 chs printf("%s: unable to map device\n", device_xname(sc->sc_dev)); 360 1.1 dyoung return; 361 1.1 dyoung } 362 1.1 dyoung 363 1.1 dyoung /* Hook up the interrupt handler. */ 364 1.1 dyoung sc->sc_ih = adm5120_intr_establish(aa->oba_irq, INTR_IRQ, admsw_intr, sc); 365 1.1 dyoung 366 1.1 dyoung if (sc->sc_ih == NULL) { 367 1.1 dyoung printf("%s: unable to register interrupt handler\n", 368 1.11 chs device_xname(sc->sc_dev)); 369 1.1 dyoung return; 370 1.1 dyoung } 371 1.1 dyoung 372 1.1 dyoung /* 373 1.1 dyoung * Allocate the control data structures, and create and load the 374 1.1 dyoung * DMA map for it. 375 1.1 dyoung */ 376 1.1 dyoung if ((error = bus_dmamem_alloc(sc->sc_dmat, 377 1.1 dyoung sizeof(struct admsw_control_data), PAGE_SIZE, 0, &seg, 1, &rseg, 378 1.1 dyoung 0)) != 0) { 379 1.1 dyoung printf("%s: unable to allocate control data, error = %d\n", 380 1.11 chs device_xname(sc->sc_dev), error); 381 1.1 dyoung return; 382 1.1 dyoung } 383 1.1 dyoung if ((error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, 384 1.1 dyoung sizeof(struct admsw_control_data), (void *)&sc->sc_control_data, 385 1.1 dyoung 0)) != 0) { 386 1.1 dyoung printf("%s: unable to map control data, error = %d\n", 387 1.11 chs device_xname(sc->sc_dev), error); 388 1.1 dyoung return; 389 1.1 dyoung } 390 1.1 dyoung if ((error = bus_dmamap_create(sc->sc_dmat, 391 1.1 dyoung sizeof(struct admsw_control_data), 1, 392 1.1 dyoung sizeof(struct admsw_control_data), 0, 0, &sc->sc_cddmamap)) != 0) { 393 1.1 dyoung printf("%s: unable to create control data DMA map, " 394 1.11 chs "error = %d\n", device_xname(sc->sc_dev), error); 395 1.1 dyoung return; 396 1.1 dyoung } 397 1.1 dyoung if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_cddmamap, 398 1.1 dyoung sc->sc_control_data, sizeof(struct admsw_control_data), NULL, 399 1.1 dyoung 0)) != 0) { 400 1.1 dyoung printf("%s: unable to load control data DMA map, error = %d\n", 401 1.11 chs device_xname(sc->sc_dev), error); 402 1.1 dyoung return; 403 1.1 dyoung } 404 1.1 dyoung 405 1.1 dyoung /* 406 1.1 dyoung * Create the transmit buffer DMA maps. 407 1.1 dyoung */ 408 1.1 dyoung for (i = 0; i < ADMSW_NTXHDESC; i++) { 409 1.1 dyoung if ((error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 410 1.1 dyoung 2, MCLBYTES, 0, 0, 411 1.1 dyoung &sc->sc_txhsoft[i].ds_dmamap)) != 0) { 412 1.1 dyoung printf("%s: unable to create txh DMA map %d, " 413 1.11 chs "error = %d\n", device_xname(sc->sc_dev), i, error); 414 1.1 dyoung return; 415 1.1 dyoung } 416 1.1 dyoung sc->sc_txhsoft[i].ds_mbuf = NULL; 417 1.1 dyoung } 418 1.1 dyoung for (i = 0; i < ADMSW_NTXLDESC; i++) { 419 1.1 dyoung if ((error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 420 1.1 dyoung 2, MCLBYTES, 0, 0, 421 1.1 dyoung &sc->sc_txlsoft[i].ds_dmamap)) != 0) { 422 1.1 dyoung printf("%s: unable to create txl DMA map %d, " 423 1.11 chs "error = %d\n", device_xname(sc->sc_dev), i, error); 424 1.1 dyoung return; 425 1.1 dyoung } 426 1.1 dyoung sc->sc_txlsoft[i].ds_mbuf = NULL; 427 1.1 dyoung } 428 1.1 dyoung 429 1.1 dyoung /* 430 1.1 dyoung * Create the receive buffer DMA maps. 431 1.1 dyoung */ 432 1.1 dyoung for (i = 0; i < ADMSW_NRXHDESC; i++) { 433 1.1 dyoung if ((error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, 434 1.1 dyoung MCLBYTES, 0, 0, &sc->sc_rxhsoft[i].ds_dmamap)) != 0) { 435 1.1 dyoung printf("%s: unable to create rxh DMA map %d, " 436 1.11 chs "error = %d\n", device_xname(sc->sc_dev), i, error); 437 1.1 dyoung return; 438 1.1 dyoung } 439 1.1 dyoung sc->sc_rxhsoft[i].ds_mbuf = NULL; 440 1.1 dyoung } 441 1.1 dyoung for (i = 0; i < ADMSW_NRXLDESC; i++) { 442 1.1 dyoung if ((error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, 443 1.1 dyoung MCLBYTES, 0, 0, &sc->sc_rxlsoft[i].ds_dmamap)) != 0) { 444 1.1 dyoung printf("%s: unable to create rxl DMA map %d, " 445 1.11 chs "error = %d\n", device_xname(sc->sc_dev), i, error); 446 1.1 dyoung return; 447 1.1 dyoung } 448 1.1 dyoung sc->sc_rxlsoft[i].ds_mbuf = NULL; 449 1.1 dyoung } 450 1.1 dyoung 451 1.1 dyoung admsw_init_bufs(sc); 452 1.1 dyoung 453 1.1 dyoung admsw_reset(sc); 454 1.1 dyoung 455 1.1 dyoung for (i = 0; i < SW_DEVS; i++) { 456 1.26 msaitoh sc->sc_ethercom[i].ec_ifmedia = &sc->sc_ifmedia[i]; 457 1.1 dyoung ifmedia_init(&sc->sc_ifmedia[i], 0, admsw_mediachange, admsw_mediastatus); 458 1.1 dyoung ifmedia_add(&sc->sc_ifmedia[i], IFM_ETHER|IFM_10_T, 0, NULL); 459 1.1 dyoung ifmedia_add(&sc->sc_ifmedia[i], IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL); 460 1.1 dyoung ifmedia_add(&sc->sc_ifmedia[i], IFM_ETHER|IFM_100_TX, 0, NULL); 461 1.1 dyoung ifmedia_add(&sc->sc_ifmedia[i], IFM_ETHER|IFM_100_TX|IFM_FDX, 0, NULL); 462 1.1 dyoung ifmedia_add(&sc->sc_ifmedia[i], IFM_ETHER|IFM_AUTO, 0, NULL); 463 1.1 dyoung ifmedia_set(&sc->sc_ifmedia[i], IFM_ETHER|IFM_AUTO); 464 1.1 dyoung 465 1.1 dyoung ifp = &sc->sc_ethercom[i].ec_if; 466 1.11 chs strcpy(ifp->if_xname, device_xname(sc->sc_dev)); 467 1.1 dyoung ifp->if_xname[5] += i; 468 1.1 dyoung ifp->if_softc = sc; 469 1.1 dyoung ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 470 1.1 dyoung ifp->if_ioctl = admsw_ioctl; 471 1.1 dyoung ifp->if_start = admsw_start; 472 1.1 dyoung ifp->if_watchdog = admsw_watchdog; 473 1.1 dyoung ifp->if_init = admsw_init; 474 1.1 dyoung ifp->if_stop = admsw_stop; 475 1.1 dyoung ifp->if_capabilities |= IFCAP_CSUM_IPv4_Tx | IFCAP_CSUM_IPv4_Rx; 476 1.18 riastrad IFQ_SET_MAXLEN(&ifp->if_snd, uimax(ADMSW_NTXLDESC, IFQ_MAXLEN)); 477 1.1 dyoung IFQ_SET_READY(&ifp->if_snd); 478 1.1 dyoung 479 1.1 dyoung /* Attach the interface. */ 480 1.1 dyoung if_attach(ifp); 481 1.15 ozaki if_deferred_start_init(ifp, NULL); 482 1.1 dyoung ether_ifattach(ifp, enaddr); 483 1.1 dyoung enaddr[5]++; 484 1.1 dyoung } 485 1.1 dyoung 486 1.1 dyoung #ifdef ADMSW_EVENT_COUNTERS 487 1.1 dyoung evcnt_attach_dynamic(&sc->sc_ev_txstall, EVCNT_TYPE_MISC, 488 1.11 chs NULL, device_xname(sc->sc_dev), "txstall"); 489 1.1 dyoung evcnt_attach_dynamic(&sc->sc_ev_rxstall, EVCNT_TYPE_MISC, 490 1.11 chs NULL, device_xname(sc->sc_dev), "rxstall"); 491 1.1 dyoung evcnt_attach_dynamic(&sc->sc_ev_txintr, EVCNT_TYPE_MISC, 492 1.11 chs NULL, device_xname(sc->sc_dev), "txintr"); 493 1.1 dyoung evcnt_attach_dynamic(&sc->sc_ev_rxintr, EVCNT_TYPE_MISC, 494 1.11 chs NULL, device_xname(sc->sc_dev), "rxintr"); 495 1.1 dyoung #if 1 496 1.1 dyoung evcnt_attach_dynamic(&sc->sc_ev_rxsync, EVCNT_TYPE_MISC, 497 1.11 chs NULL, device_xname(sc->sc_dev), "rxsync"); 498 1.1 dyoung #endif 499 1.1 dyoung #endif 500 1.1 dyoung 501 1.1 dyoung admwdog_attach(sc); 502 1.1 dyoung 503 1.1 dyoung /* Make sure the interface is shutdown during reboot. */ 504 1.1 dyoung sc->sc_sdhook = shutdownhook_establish(admsw_shutdown, sc); 505 1.1 dyoung if (sc->sc_sdhook == NULL) 506 1.1 dyoung printf("%s: WARNING: unable to establish shutdown hook\n", 507 1.11 chs device_xname(sc->sc_dev)); 508 1.1 dyoung 509 1.1 dyoung /* leave interrupts and cpu port disabled */ 510 1.1 dyoung return; 511 1.1 dyoung } 512 1.1 dyoung 513 1.1 dyoung 514 1.1 dyoung /* 515 1.1 dyoung * admsw_shutdown: 516 1.1 dyoung * 517 1.1 dyoung * Make sure the interface is stopped at reboot time. 518 1.1 dyoung */ 519 1.1 dyoung static void 520 1.1 dyoung admsw_shutdown(void *arg) 521 1.1 dyoung { 522 1.1 dyoung struct admsw_softc *sc = arg; 523 1.1 dyoung int i; 524 1.1 dyoung 525 1.1 dyoung for (i = 0; i < SW_DEVS; i++) 526 1.1 dyoung admsw_stop(&sc->sc_ethercom[i].ec_if, 1); 527 1.1 dyoung } 528 1.1 dyoung 529 1.1 dyoung /* 530 1.1 dyoung * admsw_start: [ifnet interface function] 531 1.1 dyoung * 532 1.1 dyoung * Start packet transmission on the interface. 533 1.1 dyoung */ 534 1.1 dyoung static void 535 1.1 dyoung admsw_start(struct ifnet *ifp) 536 1.1 dyoung { 537 1.1 dyoung struct admsw_softc *sc = ifp->if_softc; 538 1.1 dyoung struct mbuf *m0, *m; 539 1.1 dyoung struct admsw_descsoft *ds; 540 1.1 dyoung struct admsw_desc *desc; 541 1.1 dyoung bus_dmamap_t dmamap; 542 1.1 dyoung struct ether_header *eh; 543 1.1 dyoung int error, nexttx, len, i; 544 1.1 dyoung static int vlan = 0; 545 1.1 dyoung 546 1.1 dyoung /* 547 1.1 dyoung * Loop through the send queues, setting up transmit descriptors 548 1.1 dyoung * unitl we drain the queues, or use up all available transmit 549 1.1 dyoung * descriptors. 550 1.1 dyoung */ 551 1.1 dyoung for (;;) { 552 1.1 dyoung vlan++; 553 1.1 dyoung if (vlan == SW_DEVS) 554 1.1 dyoung vlan = 0; 555 1.1 dyoung i = vlan; 556 1.1 dyoung for (;;) { 557 1.1 dyoung ifp = &sc->sc_ethercom[i].ec_if; 558 1.29 thorpej if ((ifp->if_flags & IFF_RUNNING) == 0) 559 1.29 thorpej continue; 560 1.29 thorpej /* Grab a packet off the queue. */ 561 1.29 thorpej IFQ_POLL(&ifp->if_snd, m0); 562 1.29 thorpej if (m0 != NULL) 563 1.29 thorpej break; 564 1.1 dyoung i++; 565 1.1 dyoung if (i == SW_DEVS) 566 1.1 dyoung i = 0; 567 1.1 dyoung if (i == vlan) 568 1.1 dyoung return; 569 1.1 dyoung } 570 1.1 dyoung vlan = i; 571 1.1 dyoung m = NULL; 572 1.1 dyoung 573 1.1 dyoung /* Get a spare descriptor. */ 574 1.1 dyoung if (sc->sc_txfree == 0) { 575 1.29 thorpej /* No more slots left. */ 576 1.1 dyoung ADMSW_EVCNT_INCR(&sc->sc_ev_txstall); 577 1.1 dyoung break; 578 1.1 dyoung } 579 1.1 dyoung nexttx = sc->sc_txnext; 580 1.1 dyoung desc = &sc->sc_txldescs[nexttx]; 581 1.1 dyoung ds = &sc->sc_txlsoft[nexttx]; 582 1.1 dyoung dmamap = ds->ds_dmamap; 583 1.1 dyoung 584 1.1 dyoung /* 585 1.1 dyoung * Load the DMA map. If this fails, the packet either 586 1.31 andvar * didn't fit in the allotted number of segments, or we 587 1.1 dyoung * were short on resources. In this case, we'll copy 588 1.1 dyoung * and try again. 589 1.1 dyoung */ 590 1.1 dyoung if (m0->m_pkthdr.len < ETHER_MIN_LEN || 591 1.1 dyoung bus_dmamap_load_mbuf(sc->sc_dmat, dmamap, m0, 592 1.23 msaitoh BUS_DMA_WRITE | BUS_DMA_NOWAIT) != 0) { 593 1.1 dyoung MGETHDR(m, M_DONTWAIT, MT_DATA); 594 1.1 dyoung if (m == NULL) { 595 1.1 dyoung printf("%s: unable to allocate Tx mbuf\n", 596 1.11 chs device_xname(sc->sc_dev)); 597 1.1 dyoung break; 598 1.1 dyoung } 599 1.1 dyoung if (m0->m_pkthdr.len > MHLEN) { 600 1.1 dyoung MCLGET(m, M_DONTWAIT); 601 1.1 dyoung if ((m->m_flags & M_EXT) == 0) { 602 1.1 dyoung printf("%s: unable to allocate Tx " 603 1.11 chs "cluster\n", device_xname(sc->sc_dev)); 604 1.1 dyoung m_freem(m); 605 1.1 dyoung break; 606 1.1 dyoung } 607 1.1 dyoung } 608 1.1 dyoung m->m_pkthdr.csum_flags = m0->m_pkthdr.csum_flags; 609 1.1 dyoung m_copydata(m0, 0, m0->m_pkthdr.len, mtod(m, void *)); 610 1.1 dyoung m->m_pkthdr.len = m->m_len = m0->m_pkthdr.len; 611 1.1 dyoung if (m->m_pkthdr.len < ETHER_MIN_LEN) { 612 1.1 dyoung if (M_TRAILINGSPACE(m) < ETHER_MIN_LEN - m->m_pkthdr.len) 613 1.1 dyoung panic("admsw_start: M_TRAILINGSPACE\n"); 614 1.1 dyoung memset(mtod(m, uint8_t *) + m->m_pkthdr.len, 0, 615 1.1 dyoung ETHER_MIN_LEN - ETHER_CRC_LEN - m->m_pkthdr.len); 616 1.1 dyoung m->m_pkthdr.len = m->m_len = ETHER_MIN_LEN; 617 1.1 dyoung } 618 1.1 dyoung error = bus_dmamap_load_mbuf(sc->sc_dmat, dmamap, 619 1.23 msaitoh m, BUS_DMA_WRITE | BUS_DMA_NOWAIT); 620 1.1 dyoung if (error) { 621 1.22 msaitoh printf("%s: unable to load Tx buffer, error = " 622 1.22 msaitoh "%d\n", device_xname(sc->sc_dev), error); 623 1.1 dyoung break; 624 1.1 dyoung } 625 1.1 dyoung } 626 1.1 dyoung 627 1.1 dyoung IFQ_DEQUEUE(&ifp->if_snd, m0); 628 1.1 dyoung if (m != NULL) { 629 1.1 dyoung m_freem(m0); 630 1.1 dyoung m0 = m; 631 1.1 dyoung } 632 1.1 dyoung 633 1.1 dyoung /* 634 1.1 dyoung * WE ARE NOW COMMITTED TO TRANSMITTING THE PACKET. 635 1.1 dyoung */ 636 1.1 dyoung 637 1.1 dyoung /* Sync the DMA map. */ 638 1.1 dyoung bus_dmamap_sync(sc->sc_dmat, dmamap, 0, dmamap->dm_mapsize, 639 1.1 dyoung BUS_DMASYNC_PREWRITE); 640 1.1 dyoung 641 1.1 dyoung if (dmamap->dm_nsegs != 1 && dmamap->dm_nsegs != 2) 642 1.23 msaitoh panic("admsw_start: dm_nsegs == %d\n", 643 1.23 msaitoh dmamap->dm_nsegs); 644 1.1 dyoung desc->data = dmamap->dm_segs[0].ds_addr; 645 1.1 dyoung desc->len = len = dmamap->dm_segs[0].ds_len; 646 1.1 dyoung if (dmamap->dm_nsegs > 1) { 647 1.1 dyoung len += dmamap->dm_segs[1].ds_len; 648 1.22 msaitoh desc->cntl = dmamap->dm_segs[1].ds_addr 649 1.22 msaitoh | ADM5120_DMA_BUF2ENABLE; 650 1.1 dyoung } else 651 1.1 dyoung desc->cntl = 0; 652 1.1 dyoung desc->status = (len << ADM5120_DMA_LENSHIFT) | (1 << vlan); 653 1.1 dyoung eh = mtod(m0, struct ether_header *); 654 1.1 dyoung if (ntohs(eh->ether_type) == ETHERTYPE_IP && 655 1.1 dyoung m0->m_pkthdr.csum_flags & M_CSUM_IPv4) 656 1.1 dyoung desc->status |= ADM5120_DMA_CSUM; 657 1.1 dyoung if (nexttx == ADMSW_NTXLDESC - 1) 658 1.1 dyoung desc->data |= ADM5120_DMA_RINGEND; 659 1.1 dyoung desc->data |= ADM5120_DMA_OWN; 660 1.1 dyoung 661 1.1 dyoung /* Sync the descriptor. */ 662 1.1 dyoung ADMSW_CDTXLSYNC(sc, nexttx, 663 1.23 msaitoh BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 664 1.1 dyoung 665 1.1 dyoung REG_WRITE(SEND_TRIG_REG, 1); 666 1.23 msaitoh /* printf("send slot %d\n", nexttx); */ 667 1.1 dyoung 668 1.1 dyoung /* 669 1.1 dyoung * Store a pointer to the packet so we can free it later. 670 1.1 dyoung */ 671 1.1 dyoung ds->ds_mbuf = m0; 672 1.1 dyoung 673 1.1 dyoung /* Advance the Tx pointer. */ 674 1.1 dyoung sc->sc_txfree--; 675 1.1 dyoung sc->sc_txnext = ADMSW_NEXTTXL(nexttx); 676 1.1 dyoung 677 1.1 dyoung /* Pass the packet to any BPF listeners. */ 678 1.17 msaitoh bpf_mtap(ifp, m0, BPF_D_OUT); 679 1.1 dyoung 680 1.1 dyoung /* Set a watchdog timer in case the chip flakes out. */ 681 1.1 dyoung sc->sc_ethercom[0].ec_if.if_timer = 5; 682 1.1 dyoung } 683 1.1 dyoung } 684 1.1 dyoung 685 1.1 dyoung /* 686 1.1 dyoung * admsw_watchdog: [ifnet interface function] 687 1.1 dyoung * 688 1.1 dyoung * Watchdog timer handler. 689 1.1 dyoung */ 690 1.1 dyoung static void 691 1.1 dyoung admsw_watchdog(struct ifnet *ifp) 692 1.1 dyoung { 693 1.1 dyoung struct admsw_softc *sc = ifp->if_softc; 694 1.1 dyoung int vlan; 695 1.1 dyoung 696 1.1 dyoung #if 1 697 1.1 dyoung /* Check if an interrupt was lost. */ 698 1.1 dyoung if (sc->sc_txfree == ADMSW_NTXLDESC) { 699 1.11 chs printf("%s: watchdog false alarm\n", device_xname(sc->sc_dev)); 700 1.1 dyoung return; 701 1.1 dyoung } 702 1.1 dyoung if (sc->sc_ethercom[0].ec_if.if_timer != 0) 703 1.22 msaitoh printf("%s: watchdog timer is %d!\n", device_xname(sc->sc_dev), 704 1.22 msaitoh sc->sc_ethercom[0].ec_if.if_timer); 705 1.1 dyoung admsw_txintr(sc, 0); 706 1.1 dyoung if (sc->sc_txfree == ADMSW_NTXLDESC) { 707 1.22 msaitoh printf("%s: tx IRQ lost (queue empty)\n", 708 1.22 msaitoh device_xname(sc->sc_dev)); 709 1.1 dyoung return; 710 1.1 dyoung } 711 1.1 dyoung if (sc->sc_ethercom[0].ec_if.if_timer != 0) { 712 1.22 msaitoh printf("%s: tx IRQ lost (timer recharged)\n", 713 1.22 msaitoh device_xname(sc->sc_dev)); 714 1.1 dyoung return; 715 1.1 dyoung } 716 1.1 dyoung #endif 717 1.1 dyoung 718 1.22 msaitoh printf("%s: device timeout, txfree = %d\n", 719 1.22 msaitoh device_xname(sc->sc_dev), sc->sc_txfree); 720 1.1 dyoung for (vlan = 0; vlan < SW_DEVS; vlan++) 721 1.1 dyoung admsw_stop(&sc->sc_ethercom[vlan].ec_if, 0); 722 1.1 dyoung for (vlan = 0; vlan < SW_DEVS; vlan++) 723 1.22 msaitoh (void)admsw_init(&sc->sc_ethercom[vlan].ec_if); 724 1.1 dyoung 725 1.1 dyoung /* Try to get more packets going. */ 726 1.1 dyoung admsw_start(ifp); 727 1.1 dyoung } 728 1.1 dyoung 729 1.1 dyoung /* 730 1.1 dyoung * admsw_ioctl: [ifnet interface function] 731 1.1 dyoung * 732 1.1 dyoung * Handle control requests from the operator. 733 1.1 dyoung */ 734 1.1 dyoung static int 735 1.1 dyoung admsw_ioctl(struct ifnet *ifp, u_long cmd, void *data) 736 1.1 dyoung { 737 1.1 dyoung struct admsw_softc *sc = ifp->if_softc; 738 1.1 dyoung struct ifdrv *ifd; 739 1.1 dyoung int s, error, port; 740 1.1 dyoung 741 1.26 msaitoh port = (struct ethercom *)ifp - sc->sc_ethercom; /* XXX */ 742 1.26 msaitoh if (port >= SW_DEVS) 743 1.26 msaitoh return EOPNOTSUPP; 744 1.26 msaitoh 745 1.1 dyoung s = splnet(); 746 1.1 dyoung 747 1.1 dyoung switch (cmd) { 748 1.4 dyoung case SIOCSIFCAP: 749 1.4 dyoung if ((error = ether_ioctl(ifp, cmd, data)) == ENETRESET) 750 1.4 dyoung error = 0; 751 1.4 dyoung break; 752 1.1 dyoung case SIOCGDRVSPEC: 753 1.1 dyoung case SIOCSDRVSPEC: 754 1.1 dyoung ifd = (struct ifdrv *) data; 755 1.1 dyoung if (ifd->ifd_cmd != 0 || ifd->ifd_len != sizeof(vlan_matrix)) { 756 1.1 dyoung error = EINVAL; 757 1.1 dyoung break; 758 1.1 dyoung } 759 1.1 dyoung if (cmd == SIOCGDRVSPEC) { 760 1.1 dyoung error = copyout(vlan_matrix, ifd->ifd_data, 761 1.1 dyoung sizeof(vlan_matrix)); 762 1.1 dyoung } else { 763 1.1 dyoung error = copyin(ifd->ifd_data, vlan_matrix, 764 1.1 dyoung sizeof(vlan_matrix)); 765 1.1 dyoung admsw_setvlan(sc, vlan_matrix); 766 1.1 dyoung } 767 1.1 dyoung break; 768 1.1 dyoung 769 1.1 dyoung default: 770 1.1 dyoung error = ether_ioctl(ifp, cmd, data); 771 1.1 dyoung if (error == ENETRESET) { 772 1.1 dyoung /* 773 1.1 dyoung * Multicast list has changed; set the hardware filter 774 1.1 dyoung * accordingly. 775 1.1 dyoung */ 776 1.1 dyoung admsw_set_filter(sc); 777 1.1 dyoung error = 0; 778 1.1 dyoung } 779 1.1 dyoung break; 780 1.1 dyoung } 781 1.1 dyoung 782 1.1 dyoung /* Try to get more packets going. */ 783 1.1 dyoung admsw_start(ifp); 784 1.1 dyoung 785 1.1 dyoung splx(s); 786 1.22 msaitoh return error; 787 1.1 dyoung } 788 1.1 dyoung 789 1.1 dyoung 790 1.1 dyoung /* 791 1.1 dyoung * admsw_intr: 792 1.1 dyoung * 793 1.1 dyoung * Interrupt service routine. 794 1.1 dyoung */ 795 1.1 dyoung static int 796 1.1 dyoung admsw_intr(void *arg) 797 1.1 dyoung { 798 1.1 dyoung struct admsw_softc *sc = arg; 799 1.1 dyoung uint32_t pending; 800 1.1 dyoung char buf[64]; 801 1.1 dyoung 802 1.1 dyoung pending = REG_READ(ADMSW_INT_ST); 803 1.1 dyoung 804 1.22 msaitoh if ((pending & ~(ADMSW_INTR_RHD | ADMSW_INTR_RLD | ADMSW_INTR_SHD | 805 1.22 msaitoh ADMSW_INTR_SLD | ADMSW_INTR_W1TE | ADMSW_INTR_W0TE)) != 0) { 806 1.5 christos snprintb(buf, sizeof(buf), ADMSW_INT_FMT, pending); 807 1.5 christos printf("%s: pending=%s\n", __func__, buf); 808 1.1 dyoung } 809 1.1 dyoung REG_WRITE(ADMSW_INT_ST, pending); 810 1.1 dyoung 811 1.1 dyoung if (sc->ndevs == 0) 812 1.22 msaitoh return 0; 813 1.1 dyoung 814 1.1 dyoung if ((pending & ADMSW_INTR_RHD) != 0) 815 1.1 dyoung admsw_rxintr(sc, 1); 816 1.1 dyoung 817 1.1 dyoung if ((pending & ADMSW_INTR_RLD) != 0) 818 1.1 dyoung admsw_rxintr(sc, 0); 819 1.1 dyoung 820 1.1 dyoung if ((pending & ADMSW_INTR_SHD) != 0) 821 1.1 dyoung admsw_txintr(sc, 1); 822 1.1 dyoung 823 1.1 dyoung if ((pending & ADMSW_INTR_SLD) != 0) 824 1.1 dyoung admsw_txintr(sc, 0); 825 1.1 dyoung 826 1.22 msaitoh return 1; 827 1.1 dyoung } 828 1.1 dyoung 829 1.1 dyoung /* 830 1.1 dyoung * admsw_txintr: 831 1.1 dyoung * 832 1.1 dyoung * Helper; handle transmit interrupts. 833 1.1 dyoung */ 834 1.1 dyoung static void 835 1.1 dyoung admsw_txintr(struct admsw_softc *sc, int prio) 836 1.1 dyoung { 837 1.1 dyoung struct ifnet *ifp; 838 1.1 dyoung struct admsw_desc *desc; 839 1.1 dyoung struct admsw_descsoft *ds; 840 1.1 dyoung int i, vlan; 841 1.1 dyoung int gotone = 0; 842 1.1 dyoung 843 1.23 msaitoh /* printf("txintr: txdirty: %d, txfree: %d\n", sc->sc_txdirty, sc->sc_txfree); */ 844 1.1 dyoung for (i = sc->sc_txdirty; sc->sc_txfree != ADMSW_NTXLDESC; 845 1.1 dyoung i = ADMSW_NEXTTXL(i)) { 846 1.1 dyoung 847 1.1 dyoung ADMSW_CDTXLSYNC(sc, i, 848 1.23 msaitoh BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 849 1.1 dyoung 850 1.1 dyoung desc = &sc->sc_txldescs[i]; 851 1.1 dyoung ds = &sc->sc_txlsoft[i]; 852 1.1 dyoung if (desc->data & ADM5120_DMA_OWN) { 853 1.1 dyoung ADMSW_CDTXLSYNC(sc, i, 854 1.23 msaitoh BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 855 1.1 dyoung break; 856 1.1 dyoung } 857 1.1 dyoung 858 1.1 dyoung bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap, 859 1.1 dyoung 0, ds->ds_dmamap->dm_mapsize, BUS_DMASYNC_POSTWRITE); 860 1.1 dyoung bus_dmamap_unload(sc->sc_dmat, ds->ds_dmamap); 861 1.1 dyoung m_freem(ds->ds_mbuf); 862 1.1 dyoung ds->ds_mbuf = NULL; 863 1.1 dyoung 864 1.1 dyoung vlan = ffs(desc->status & 0x3f) - 1; 865 1.1 dyoung if (vlan < 0 || vlan >= SW_DEVS) 866 1.1 dyoung panic("admsw_txintr: bad vlan\n"); 867 1.1 dyoung ifp = &sc->sc_ethercom[vlan].ec_if; 868 1.1 dyoung gotone = 1; 869 1.23 msaitoh /* printf("clear tx slot %d\n", i); */ 870 1.1 dyoung 871 1.28 thorpej if_statinc(ifp, if_opackets); 872 1.1 dyoung 873 1.1 dyoung sc->sc_txfree++; 874 1.1 dyoung } 875 1.1 dyoung 876 1.1 dyoung if (gotone) { 877 1.1 dyoung sc->sc_txdirty = i; 878 1.1 dyoung #ifdef ADMSW_EVENT_COUNTERS 879 1.1 dyoung ADMSW_EVCNT_INCR(&sc->sc_ev_txintr); 880 1.1 dyoung #endif 881 1.1 dyoung ifp = &sc->sc_ethercom[0].ec_if; 882 1.1 dyoung 883 1.1 dyoung /* Try to queue more packets. */ 884 1.15 ozaki if_schedule_deferred_start(ifp); 885 1.1 dyoung 886 1.1 dyoung /* 887 1.1 dyoung * If there are no more pending transmissions, 888 1.1 dyoung * cancel the watchdog timer. 889 1.1 dyoung */ 890 1.1 dyoung if (sc->sc_txfree == ADMSW_NTXLDESC) 891 1.1 dyoung ifp->if_timer = 0; 892 1.1 dyoung 893 1.1 dyoung } 894 1.1 dyoung 895 1.23 msaitoh /* printf("txintr end: txdirty: %d, txfree: %d\n", sc->sc_txdirty, sc->sc_txfree); */ 896 1.1 dyoung } 897 1.1 dyoung 898 1.1 dyoung /* 899 1.1 dyoung * admsw_rxintr: 900 1.1 dyoung * 901 1.1 dyoung * Helper; handle receive interrupts. 902 1.1 dyoung */ 903 1.1 dyoung static void 904 1.1 dyoung admsw_rxintr(struct admsw_softc *sc, int high) 905 1.1 dyoung { 906 1.1 dyoung struct ifnet *ifp; 907 1.1 dyoung struct admsw_descsoft *ds; 908 1.1 dyoung struct mbuf *m; 909 1.1 dyoung uint32_t stat; 910 1.1 dyoung int i, len, port, vlan; 911 1.1 dyoung 912 1.1 dyoung /* printf("rxintr\n"); */ 913 1.1 dyoung if (high) 914 1.1 dyoung panic("admsw_rxintr: high priority packet\n"); 915 1.1 dyoung 916 1.1 dyoung #ifdef ADMSW_EVENT_COUNTERS 917 1.1 dyoung int pkts = 0; 918 1.1 dyoung #endif 919 1.1 dyoung 920 1.1 dyoung #if 1 921 1.22 msaitoh ADMSW_CDRXLSYNC(sc, sc->sc_rxptr, 922 1.22 msaitoh BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 923 1.1 dyoung if ((sc->sc_rxldescs[sc->sc_rxptr].data & ADM5120_DMA_OWN) == 0) 924 1.22 msaitoh ADMSW_CDRXLSYNC(sc, sc->sc_rxptr, 925 1.22 msaitoh BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 926 1.1 dyoung else { 927 1.1 dyoung i = sc->sc_rxptr; 928 1.1 dyoung do { 929 1.22 msaitoh ADMSW_CDRXLSYNC(sc, i, 930 1.22 msaitoh BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 931 1.1 dyoung i = ADMSW_NEXTRXL(i); 932 1.1 dyoung /* the ring is empty, just return. */ 933 1.1 dyoung if (i == sc->sc_rxptr) 934 1.1 dyoung return; 935 1.22 msaitoh ADMSW_CDRXLSYNC(sc, i, 936 1.22 msaitoh BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 937 1.1 dyoung } while (sc->sc_rxldescs[i].data & ADM5120_DMA_OWN); 938 1.22 msaitoh ADMSW_CDRXLSYNC(sc, i, 939 1.22 msaitoh BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 940 1.1 dyoung 941 1.22 msaitoh ADMSW_CDRXLSYNC(sc, sc->sc_rxptr, 942 1.22 msaitoh BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 943 1.1 dyoung if ((sc->sc_rxldescs[sc->sc_rxptr].data & ADM5120_DMA_OWN) == 0) 944 1.22 msaitoh ADMSW_CDRXLSYNC(sc, sc->sc_rxptr, 945 1.22 msaitoh BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 946 1.1 dyoung else { 947 1.22 msaitoh ADMSW_CDRXLSYNC(sc, sc->sc_rxptr, 948 1.22 msaitoh BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 949 1.1 dyoung /* We've fallen behind the chip: catch it. */ 950 1.1 dyoung printf("%s: RX ring resync, base=%x, work=%x, %d -> %d\n", 951 1.11 chs device_xname(sc->sc_dev), REG_READ(RECV_LBADDR_REG), 952 1.1 dyoung REG_READ(RECV_LWADDR_REG), sc->sc_rxptr, i); 953 1.1 dyoung sc->sc_rxptr = i; 954 1.1 dyoung ADMSW_EVCNT_INCR(&sc->sc_ev_rxsync); 955 1.1 dyoung } 956 1.1 dyoung } 957 1.1 dyoung #endif 958 1.1 dyoung for (i = sc->sc_rxptr;; i = ADMSW_NEXTRXL(i)) { 959 1.1 dyoung ds = &sc->sc_rxlsoft[i]; 960 1.1 dyoung 961 1.22 msaitoh ADMSW_CDRXLSYNC(sc, i, 962 1.22 msaitoh BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 963 1.1 dyoung 964 1.1 dyoung if (sc->sc_rxldescs[i].data & ADM5120_DMA_OWN) { 965 1.22 msaitoh ADMSW_CDRXLSYNC(sc, i, 966 1.22 msaitoh BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 967 1.1 dyoung break; 968 1.1 dyoung } 969 1.1 dyoung 970 1.23 msaitoh /* printf("process slot %d\n", i); */ 971 1.1 dyoung 972 1.1 dyoung #ifdef ADMSW_EVENT_COUNTERS 973 1.1 dyoung pkts++; 974 1.1 dyoung #endif 975 1.1 dyoung 976 1.1 dyoung bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap, 0, 977 1.1 dyoung ds->ds_dmamap->dm_mapsize, BUS_DMASYNC_POSTREAD); 978 1.1 dyoung 979 1.1 dyoung stat = sc->sc_rxldescs[i].status; 980 1.1 dyoung len = (stat & ADM5120_DMA_LEN) >> ADM5120_DMA_LENSHIFT; 981 1.1 dyoung len -= ETHER_CRC_LEN; 982 1.1 dyoung port = (stat & ADM5120_DMA_PORTID) >> ADM5120_DMA_PORTSHIFT; 983 1.1 dyoung for (vlan = 0; vlan < SW_DEVS; vlan++) 984 1.1 dyoung if ((1 << port) & vlan_matrix[vlan]) 985 1.1 dyoung break; 986 1.1 dyoung if (vlan == SW_DEVS) 987 1.1 dyoung vlan = 0; 988 1.1 dyoung ifp = &sc->sc_ethercom[vlan].ec_if; 989 1.1 dyoung 990 1.1 dyoung m = ds->ds_mbuf; 991 1.1 dyoung if (admsw_add_rxlbuf(sc, i) != 0) { 992 1.28 thorpej if_statinc(ifp, if_ierrors); 993 1.1 dyoung ADMSW_INIT_RXLDESC(sc, i); 994 1.1 dyoung bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap, 0, 995 1.1 dyoung ds->ds_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD); 996 1.1 dyoung continue; 997 1.1 dyoung } 998 1.1 dyoung 999 1.14 ozaki m_set_rcvif(m, ifp); 1000 1.1 dyoung m->m_pkthdr.len = m->m_len = len; 1001 1.1 dyoung if ((stat & ADM5120_DMA_TYPE) == ADM5120_DMA_TYPE_IP) { 1002 1.1 dyoung m->m_pkthdr.csum_flags |= M_CSUM_IPv4; 1003 1.1 dyoung if (stat & ADM5120_DMA_CSUMFAIL) 1004 1.1 dyoung m->m_pkthdr.csum_flags |= M_CSUM_IPv4_BAD; 1005 1.1 dyoung } 1006 1.1 dyoung 1007 1.1 dyoung /* Pass it on. */ 1008 1.13 ozaki if_percpuq_enqueue(ifp->if_percpuq, m); 1009 1.1 dyoung } 1010 1.1 dyoung #ifdef ADMSW_EVENT_COUNTERS 1011 1.1 dyoung if (pkts) 1012 1.1 dyoung ADMSW_EVCNT_INCR(&sc->sc_ev_rxintr); 1013 1.1 dyoung 1014 1.1 dyoung if (pkts == ADMSW_NRXLDESC) 1015 1.1 dyoung ADMSW_EVCNT_INCR(&sc->sc_ev_rxstall); 1016 1.1 dyoung #endif 1017 1.1 dyoung 1018 1.1 dyoung /* Update the receive pointer. */ 1019 1.1 dyoung sc->sc_rxptr = i; 1020 1.1 dyoung } 1021 1.1 dyoung 1022 1.1 dyoung /* 1023 1.1 dyoung * admsw_init: [ifnet interface function] 1024 1.1 dyoung * 1025 1.1 dyoung * Initialize the interface. Must be called at splnet(). 1026 1.1 dyoung */ 1027 1.1 dyoung static int 1028 1.1 dyoung admsw_init(struct ifnet *ifp) 1029 1.1 dyoung { 1030 1.1 dyoung struct admsw_softc *sc = ifp->if_softc; 1031 1.1 dyoung 1032 1.1 dyoung /* printf("admsw_init called\n"); */ 1033 1.1 dyoung 1034 1.1 dyoung if ((ifp->if_flags & IFF_RUNNING) == 0) { 1035 1.1 dyoung if (sc->ndevs == 0) { 1036 1.1 dyoung admsw_init_bufs(sc); 1037 1.1 dyoung admsw_reset(sc); 1038 1.1 dyoung REG_WRITE(CPUP_CONF_REG, 1039 1.1 dyoung CPUP_CONF_CRCP | CPUP_CONF_DUNP_MASK | 1040 1.1 dyoung CPUP_CONF_DMCP_MASK); 1041 1.22 msaitoh /* Clear all pending interrupts */ 1042 1.1 dyoung REG_WRITE(ADMSW_INT_ST, INT_MASK); 1043 1.1 dyoung 1044 1.22 msaitoh /* Enable needed interrupts */ 1045 1.1 dyoung REG_WRITE(ADMSW_INT_MASK, REG_READ(ADMSW_INT_MASK) & 1046 1.23 msaitoh ~(ADMSW_INTR_SHD | ADMSW_INTR_SLD | 1047 1.23 msaitoh ADMSW_INTR_RHD | ADMSW_INTR_RLD | 1048 1.23 msaitoh ADMSW_INTR_HDF | ADMSW_INTR_LDF)); 1049 1.1 dyoung } 1050 1.1 dyoung sc->ndevs++; 1051 1.1 dyoung } 1052 1.1 dyoung 1053 1.1 dyoung /* Set the receive filter. */ 1054 1.1 dyoung admsw_set_filter(sc); 1055 1.1 dyoung 1056 1.22 msaitoh /* Mark iface as running */ 1057 1.1 dyoung ifp->if_flags |= IFF_RUNNING; 1058 1.1 dyoung 1059 1.1 dyoung return 0; 1060 1.1 dyoung } 1061 1.1 dyoung 1062 1.1 dyoung /* 1063 1.1 dyoung * admsw_stop: [ifnet interface function] 1064 1.1 dyoung * 1065 1.1 dyoung * Stop transmission on the interface. 1066 1.1 dyoung */ 1067 1.1 dyoung static void 1068 1.1 dyoung admsw_stop(struct ifnet *ifp, int disable) 1069 1.1 dyoung { 1070 1.1 dyoung struct admsw_softc *sc = ifp->if_softc; 1071 1.1 dyoung 1072 1.23 msaitoh /* printf("admsw_stop: %d\n", disable); */ 1073 1.1 dyoung 1074 1.1 dyoung if (!(ifp->if_flags & IFF_RUNNING)) 1075 1.1 dyoung return; 1076 1.1 dyoung 1077 1.1 dyoung if (--sc->ndevs == 0) { 1078 1.1 dyoung /* printf("debug: de-initializing hardware\n"); */ 1079 1.1 dyoung 1080 1.22 msaitoh /* Disable cpu port */ 1081 1.1 dyoung REG_WRITE(CPUP_CONF_REG, 1082 1.1 dyoung CPUP_CONF_DCPUP | CPUP_CONF_CRCP | 1083 1.1 dyoung CPUP_CONF_DUNP_MASK | CPUP_CONF_DMCP_MASK); 1084 1.1 dyoung 1085 1.1 dyoung /* XXX We should disable, then clear? --dyoung */ 1086 1.22 msaitoh /* Clear all pending interrupts */ 1087 1.1 dyoung REG_WRITE(ADMSW_INT_ST, INT_MASK); 1088 1.1 dyoung 1089 1.22 msaitoh /* Disable interrupts */ 1090 1.1 dyoung REG_WRITE(ADMSW_INT_MASK, INT_MASK); 1091 1.1 dyoung } 1092 1.1 dyoung 1093 1.1 dyoung /* Mark the interface as down and cancel the watchdog timer. */ 1094 1.29 thorpej ifp->if_flags &= ~IFF_RUNNING; 1095 1.1 dyoung ifp->if_timer = 0; 1096 1.1 dyoung 1097 1.1 dyoung return; 1098 1.1 dyoung } 1099 1.1 dyoung 1100 1.1 dyoung /* 1101 1.1 dyoung * admsw_set_filter: 1102 1.1 dyoung * 1103 1.1 dyoung * Set up the receive filter. 1104 1.1 dyoung */ 1105 1.1 dyoung static void 1106 1.1 dyoung admsw_set_filter(struct admsw_softc *sc) 1107 1.1 dyoung { 1108 1.1 dyoung int i; 1109 1.1 dyoung uint32_t allmc, anymc, conf, promisc; 1110 1.1 dyoung struct ether_multi *enm; 1111 1.1 dyoung struct ethercom *ec; 1112 1.1 dyoung struct ifnet *ifp; 1113 1.1 dyoung struct ether_multistep step; 1114 1.1 dyoung 1115 1.1 dyoung /* Find which ports should be operated in promisc mode. */ 1116 1.1 dyoung allmc = anymc = promisc = 0; 1117 1.1 dyoung for (i = 0; i < SW_DEVS; i++) { 1118 1.1 dyoung ec = &sc->sc_ethercom[i]; 1119 1.1 dyoung ifp = &ec->ec_if; 1120 1.1 dyoung if (ifp->if_flags & IFF_PROMISC) 1121 1.1 dyoung promisc |= vlan_matrix[i]; 1122 1.1 dyoung 1123 1.1 dyoung ifp->if_flags &= ~IFF_ALLMULTI; 1124 1.1 dyoung 1125 1.24 msaitoh ETHER_LOCK(ec); 1126 1.1 dyoung ETHER_FIRST_MULTI(step, ec, enm); 1127 1.1 dyoung while (enm != NULL) { 1128 1.1 dyoung if (memcmp(enm->enm_addrlo, enm->enm_addrhi, 1129 1.1 dyoung ETHER_ADDR_LEN) != 0) { 1130 1.1 dyoung printf("%s: punting on mcast range\n", 1131 1.1 dyoung __func__); 1132 1.1 dyoung ifp->if_flags |= IFF_ALLMULTI; 1133 1.1 dyoung allmc |= vlan_matrix[i]; 1134 1.1 dyoung break; 1135 1.1 dyoung } 1136 1.1 dyoung 1137 1.1 dyoung anymc |= vlan_matrix[i]; 1138 1.1 dyoung 1139 1.1 dyoung #if 0 1140 1.1 dyoung /* XXX extract subroutine --dyoung */ 1141 1.1 dyoung REG_WRITE(MAC_WT1_REG, 1142 1.1 dyoung enm->enm_addrlo[2] | 1143 1.1 dyoung (enm->enm_addrlo[3] << 8) | 1144 1.1 dyoung (enm->enm_addrlo[4] << 16) | 1145 1.1 dyoung (enm->enm_addrlo[5] << 24)); 1146 1.1 dyoung REG_WRITE(MAC_WT0_REG, 1147 1.1 dyoung (i << MAC_WT0_VLANID_SHIFT) | 1148 1.1 dyoung (enm->enm_addrlo[0] << 16) | 1149 1.1 dyoung (enm->enm_addrlo[1] << 24) | 1150 1.1 dyoung MAC_WT0_WRITE | MAC_WT0_VLANID_EN); 1151 1.22 msaitoh /* Timeout? */ 1152 1.22 msaitoh while (!(REG_READ(MAC_WT0_REG) & MAC_WT0_WRITE_DONE)) 1153 1.22 msaitoh ; 1154 1.1 dyoung #endif 1155 1.1 dyoung 1156 1.22 msaitoh /* Load h/w with mcast address, port = CPU */ 1157 1.1 dyoung ETHER_NEXT_MULTI(step, enm); 1158 1.1 dyoung } 1159 1.24 msaitoh ETHER_UNLOCK(ec); 1160 1.1 dyoung } 1161 1.1 dyoung 1162 1.1 dyoung conf = REG_READ(CPUP_CONF_REG); 1163 1.22 msaitoh /* 1 Disable forwarding of unknown & multicast packets to 1164 1.22 msaitoh * CPU on all ports. 1165 1.22 msaitoh * 2 Enable forwarding of unknown & multicast packets to 1166 1.22 msaitoh * CPU on ports where IFF_PROMISC or IFF_ALLMULTI is set. 1167 1.1 dyoung */ 1168 1.1 dyoung conf |= CPUP_CONF_DUNP_MASK | CPUP_CONF_DMCP_MASK; 1169 1.1 dyoung /* Enable forwarding of unknown packets to CPU on selected ports. */ 1170 1.1 dyoung conf ^= ((promisc << CPUP_CONF_DUNP_SHIFT) & CPUP_CONF_DUNP_MASK); 1171 1.1 dyoung conf ^= ((allmc << CPUP_CONF_DMCP_SHIFT) & CPUP_CONF_DMCP_MASK); 1172 1.1 dyoung conf ^= ((anymc << CPUP_CONF_DMCP_SHIFT) & CPUP_CONF_DMCP_MASK); 1173 1.1 dyoung REG_WRITE(CPUP_CONF_REG, conf); 1174 1.1 dyoung } 1175 1.1 dyoung 1176 1.1 dyoung /* 1177 1.1 dyoung * admsw_add_rxbuf: 1178 1.1 dyoung * 1179 1.1 dyoung * Add a receive buffer to the indicated descriptor. 1180 1.1 dyoung */ 1181 1.1 dyoung int 1182 1.1 dyoung admsw_add_rxbuf(struct admsw_softc *sc, int idx, int high) 1183 1.1 dyoung { 1184 1.1 dyoung struct admsw_descsoft *ds; 1185 1.1 dyoung struct mbuf *m; 1186 1.1 dyoung int error; 1187 1.1 dyoung 1188 1.1 dyoung if (high) 1189 1.1 dyoung ds = &sc->sc_rxhsoft[idx]; 1190 1.1 dyoung else 1191 1.1 dyoung ds = &sc->sc_rxlsoft[idx]; 1192 1.1 dyoung 1193 1.1 dyoung MGETHDR(m, M_DONTWAIT, MT_DATA); 1194 1.1 dyoung if (m == NULL) 1195 1.22 msaitoh return ENOBUFS; 1196 1.1 dyoung 1197 1.1 dyoung MCLGET(m, M_DONTWAIT); 1198 1.1 dyoung if ((m->m_flags & M_EXT) == 0) { 1199 1.1 dyoung m_freem(m); 1200 1.22 msaitoh return ENOBUFS; 1201 1.1 dyoung } 1202 1.1 dyoung 1203 1.1 dyoung if (ds->ds_mbuf != NULL) 1204 1.1 dyoung bus_dmamap_unload(sc->sc_dmat, ds->ds_dmamap); 1205 1.1 dyoung 1206 1.1 dyoung ds->ds_mbuf = m; 1207 1.1 dyoung 1208 1.1 dyoung error = bus_dmamap_load(sc->sc_dmat, ds->ds_dmamap, 1209 1.1 dyoung m->m_ext.ext_buf, m->m_ext.ext_size, NULL, 1210 1.1 dyoung BUS_DMA_READ | BUS_DMA_NOWAIT); 1211 1.1 dyoung if (error) { 1212 1.1 dyoung printf("%s: can't load rx DMA map %d, error = %d\n", 1213 1.11 chs device_xname(sc->sc_dev), idx, error); 1214 1.1 dyoung panic("admsw_add_rxbuf"); /* XXX */ 1215 1.1 dyoung } 1216 1.1 dyoung 1217 1.1 dyoung bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap, 0, 1218 1.1 dyoung ds->ds_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD); 1219 1.1 dyoung 1220 1.1 dyoung if (high) 1221 1.1 dyoung ADMSW_INIT_RXHDESC(sc, idx); 1222 1.1 dyoung else 1223 1.1 dyoung ADMSW_INIT_RXLDESC(sc, idx); 1224 1.1 dyoung 1225 1.22 msaitoh return 0; 1226 1.1 dyoung } 1227 1.1 dyoung 1228 1.1 dyoung int 1229 1.1 dyoung admsw_mediachange(struct ifnet *ifp) 1230 1.1 dyoung { 1231 1.1 dyoung struct admsw_softc *sc = ifp->if_softc; 1232 1.1 dyoung int port = (struct ethercom *)ifp - sc->sc_ethercom; /* XXX */ 1233 1.27 msaitoh struct ifmedia *ifm = &sc->sc_ifmedia[port]; 1234 1.1 dyoung int old, new, val; 1235 1.1 dyoung 1236 1.27 msaitoh if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) 1237 1.22 msaitoh return EINVAL; 1238 1.1 dyoung 1239 1.27 msaitoh if (IFM_SUBTYPE(ifm->ifm_media) == IFM_AUTO) { 1240 1.23 msaitoh val = PHY_CNTL2_AUTONEG | PHY_CNTL2_100M | PHY_CNTL2_FDX; 1241 1.27 msaitoh } else if (IFM_SUBTYPE(ifm->ifm_media) == IFM_100_TX) { 1242 1.27 msaitoh if ((ifm->ifm_media & IFM_FDX) != 0) 1243 1.23 msaitoh val = PHY_CNTL2_100M | PHY_CNTL2_FDX; 1244 1.1 dyoung else 1245 1.1 dyoung val = PHY_CNTL2_100M; 1246 1.27 msaitoh } else if (IFM_SUBTYPE(ifm->ifm_media) == IFM_10_T) { 1247 1.27 msaitoh if ((ifm->ifm_media & IFM_FDX) != 0) 1248 1.1 dyoung val = PHY_CNTL2_FDX; 1249 1.1 dyoung else 1250 1.1 dyoung val = 0; 1251 1.1 dyoung } else 1252 1.22 msaitoh return EINVAL; 1253 1.1 dyoung 1254 1.1 dyoung old = REG_READ(PHY_CNTL2_REG); 1255 1.23 msaitoh new = old & ~((PHY_CNTL2_AUTONEG | PHY_CNTL2_100M | PHY_CNTL2_FDX) 1256 1.23 msaitoh << port); 1257 1.1 dyoung new |= (val << port); 1258 1.1 dyoung 1259 1.1 dyoung if (new != old) 1260 1.1 dyoung REG_WRITE(PHY_CNTL2_REG, new); 1261 1.1 dyoung 1262 1.22 msaitoh return 0; 1263 1.1 dyoung } 1264 1.1 dyoung 1265 1.1 dyoung void 1266 1.1 dyoung admsw_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr) 1267 1.1 dyoung { 1268 1.1 dyoung struct admsw_softc *sc = ifp->if_softc; 1269 1.1 dyoung int port = (struct ethercom *)ifp - sc->sc_ethercom; /* XXX */ 1270 1.1 dyoung int status; 1271 1.1 dyoung 1272 1.1 dyoung ifmr->ifm_status = IFM_AVALID; 1273 1.1 dyoung ifmr->ifm_active = IFM_ETHER; 1274 1.1 dyoung 1275 1.1 dyoung status = REG_READ(PHY_ST_REG) >> port; 1276 1.1 dyoung 1277 1.1 dyoung if ((status & PHY_ST_LINKUP) == 0) { 1278 1.1 dyoung ifmr->ifm_active |= IFM_NONE; 1279 1.1 dyoung return; 1280 1.1 dyoung } 1281 1.1 dyoung 1282 1.1 dyoung ifmr->ifm_status |= IFM_ACTIVE; 1283 1.1 dyoung ifmr->ifm_active |= (status & PHY_ST_100M) ? IFM_100_TX : IFM_10_T; 1284 1.1 dyoung if (status & PHY_ST_FDX) 1285 1.1 dyoung ifmr->ifm_active |= IFM_FDX; 1286 1.12 msaitoh else 1287 1.12 msaitoh ifmr->ifm_active |= IFM_HDX; 1288 1.1 dyoung } 1289