1 1.22 thorpej /* $NetBSD: gemini_gmac.c,v 1.22 2021/08/07 16:18:44 thorpej Exp $ */ 2 1.1 matt /*- 3 1.1 matt * Copyright (c) 2008 The NetBSD Foundation, Inc. 4 1.1 matt * All rights reserved. 5 1.1 matt * 6 1.1 matt * This code is derived from software contributed to The NetBSD Foundation 7 1.1 matt * by Matt Thomas <matt (at) 3am-software.com> 8 1.1 matt * 9 1.1 matt * Redistribution and use in source and binary forms, with or without 10 1.1 matt * modification, are permitted provided that the following conditions 11 1.1 matt * are met: 12 1.1 matt * 1. Redistributions of source code must retain the above copyright 13 1.1 matt * notice, this list of conditions and the following disclaimer. 14 1.1 matt * 2. Redistributions in binary form must reproduce the above copyright 15 1.1 matt * notice, this list of conditions and the following disclaimer in the 16 1.1 matt * documentation and/or other materials provided with the distribution. 17 1.1 matt * 18 1.1 matt * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 19 1.1 matt * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 1.1 matt * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21 1.1 matt * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 22 1.1 matt * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 1.1 matt * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 1.1 matt * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 1.1 matt * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 1.1 matt * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 1.1 matt * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 1.1 matt * POSSIBILITY OF SUCH DAMAGE. 29 1.1 matt */ 30 1.1 matt 31 1.1 matt #include "locators.h" 32 1.1 matt #include <sys/param.h> 33 1.1 matt #include <sys/device.h> 34 1.1 matt #include <sys/kmem.h> 35 1.1 matt #include <sys/mbuf.h> 36 1.1 matt 37 1.1 matt #include <net/if.h> 38 1.1 matt #include <net/if_ether.h> 39 1.1 matt 40 1.7 dyoung #include <sys/bus.h> 41 1.1 matt 42 1.1 matt #include <arm/gemini/gemini_reg.h> 43 1.1 matt #include <arm/gemini/gemini_obiovar.h> 44 1.1 matt #include <arm/gemini/gemini_gmacvar.h> 45 1.1 matt #include <arm/gemini/gemini_gpiovar.h> 46 1.1 matt 47 1.1 matt #include <dev/mii/mii.h> 48 1.1 matt #include <dev/mii/mii_bitbang.h> 49 1.1 matt 50 1.1 matt #include <sys/gpio.h> 51 1.1 matt 52 1.22 thorpej __KERNEL_RCSID(0, "$NetBSD: gemini_gmac.c,v 1.22 2021/08/07 16:18:44 thorpej Exp $"); 53 1.1 matt 54 1.1 matt #define SWFREEQ_DESCS 256 /* one page worth */ 55 1.1 matt #define HWFREEQ_DESCS 256 /* one page worth */ 56 1.1 matt 57 1.1 matt static int geminigmac_match(device_t, cfdata_t, void *); 58 1.1 matt static void geminigmac_attach(device_t, device_t, void *); 59 1.1 matt static int geminigmac_find(device_t, cfdata_t, const int *, void *); 60 1.1 matt static int geminigmac_print(void *aux, const char *name); 61 1.1 matt 62 1.17 msaitoh static int geminigmac_mii_readreg(device_t, int, int, uint16_t *); 63 1.17 msaitoh static int geminigmac_mii_writereg(device_t, int, int, uint16_t); 64 1.1 matt 65 1.1 matt #define GPIO_MDIO 21 66 1.1 matt #define GPIO_MDCLK 22 67 1.1 matt 68 1.1 matt #define MDIN __BIT(3) 69 1.1 matt #define MDOUT __BIT(2) 70 1.1 matt #define MDCLK __BIT(1) 71 1.1 matt #define MDTOPHY __BIT(0) 72 1.1 matt 73 1.1 matt CFATTACH_DECL_NEW(geminigmac, sizeof(struct gmac_softc), 74 1.1 matt geminigmac_match, geminigmac_attach, NULL, NULL); 75 1.1 matt 76 1.1 matt extern struct cfdriver geminigmac_cd; 77 1.1 matt extern struct cfdriver geminigpio_cd; 78 1.1 matt 79 1.1 matt void 80 1.3 matt gmac_swfree_min_update(struct gmac_softc *sc) 81 1.3 matt { 82 1.3 matt uint32_t v; 83 1.3 matt 84 1.3 matt if (sc->sc_swfreeq != NULL 85 1.3 matt && sc->sc_swfree_min > sc->sc_swfreeq->hwq_size - 1) 86 1.3 matt sc->sc_swfree_min = sc->sc_swfreeq->hwq_size - 1; 87 1.3 matt 88 1.3 matt v = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GMAC_QFE_THRESHOLD); 89 1.3 matt v &= ~QFE_SWFQ_THRESHOLD_MASK; 90 1.3 matt v |= QFE_SWFQ_THRESHOLD(sc->sc_swfree_min); 91 1.3 matt bus_space_write_4(sc->sc_iot, sc->sc_ioh, GMAC_QFE_THRESHOLD, v); 92 1.3 matt } 93 1.3 matt 94 1.3 matt void 95 1.1 matt gmac_intr_update(struct gmac_softc *sc) 96 1.1 matt { 97 1.1 matt bus_space_write_4(sc->sc_iot, sc->sc_ioh, GMAC_INT0_MASK, 98 1.1 matt ~sc->sc_int_enabled[0]); 99 1.1 matt bus_space_write_4(sc->sc_iot, sc->sc_ioh, GMAC_INT1_MASK, 100 1.1 matt ~sc->sc_int_enabled[1]); 101 1.1 matt bus_space_write_4(sc->sc_iot, sc->sc_ioh, GMAC_INT2_MASK, 102 1.1 matt ~sc->sc_int_enabled[2]); 103 1.1 matt bus_space_write_4(sc->sc_iot, sc->sc_ioh, GMAC_INT3_MASK, 104 1.1 matt ~sc->sc_int_enabled[3]); 105 1.1 matt bus_space_write_4(sc->sc_iot, sc->sc_ioh, GMAC_INT4_MASK, 106 1.1 matt ~sc->sc_int_enabled[4]); 107 1.1 matt } 108 1.1 matt 109 1.1 matt static void 110 1.1 matt gmac_init(struct gmac_softc *sc) 111 1.1 matt { 112 1.1 matt gmac_hwqmem_t *hqm; 113 1.1 matt 114 1.2 matt /* 115 1.2 matt * This shouldn't be needed. 116 1.2 matt */ 117 1.2 matt for (bus_size_t i = 0; i < GMAC_TOE_QH_SIZE; i += 4) { 118 1.2 matt bus_space_write_4(sc->sc_iot, sc->sc_ioh, 119 1.2 matt GMAC_TOE_QH_OFFSET + i, 0); 120 1.2 matt } 121 1.2 matt #if 0 122 1.2 matt { 123 1.2 matt bus_space_handle_t global_ioh; 124 1.2 matt int error; 125 1.2 matt 126 1.2 matt error = bus_space_map(sc->sc_iot, GEMINI_GLOBAL_BASE, 4, 0, 127 1.2 matt &global_ioh); 128 1.2 matt KASSERT(error == 0); 129 1.2 matt aprint_normal_dev(sc->sc_dev, "gmac_init: global_ioh=%#zx\n", global_ioh); 130 1.20 skrll bus_space_write_4(sc->sc_iot, global_ioh, GEMINI_GLOBAL_RESET_CTL, 131 1.2 matt GLOBAL_RESET_GMAC0|GLOBAL_RESET_GMAC1); 132 1.2 matt do { 133 1.2 matt v = bus_space_read_4(sc->sc_iot, global_ioh, 134 1.2 matt GEMINI_GLOBAL_RESET_CTL); 135 1.2 matt } while (v & (GLOBAL_RESET_GMAC0|GLOBAL_RESET_GMAC1)); 136 1.2 matt bus_space_unmap(sc->sc_iot, global_ioh, 4); 137 1.2 matt DELAY(1000); 138 1.2 matt } 139 1.2 matt #endif 140 1.2 matt 141 1.3 matt sc->sc_swfree_min = 4; /* MIN_RXMAPS; */ 142 1.3 matt 143 1.3 matt gmac_swfree_min_update(sc); 144 1.2 matt 145 1.1 matt bus_space_write_4(sc->sc_iot, sc->sc_ioh, GMAC_SKBSIZE, 146 1.1 matt SKB_SIZE_SET(PAGE_SIZE, MCLBYTES)); 147 1.1 matt 148 1.1 matt sc->sc_int_select[0] = INT0_GMAC1; 149 1.1 matt sc->sc_int_select[1] = INT1_GMAC1; 150 1.1 matt sc->sc_int_select[2] = INT2_GMAC1; 151 1.1 matt sc->sc_int_select[3] = INT3_GMAC1; 152 1.1 matt sc->sc_int_select[4] = INT4_GMAC1; 153 1.1 matt 154 1.1 matt bus_space_write_4(sc->sc_iot, sc->sc_ioh, GMAC_INT0_SELECT, INT0_GMAC1); 155 1.1 matt bus_space_write_4(sc->sc_iot, sc->sc_ioh, GMAC_INT1_SELECT, INT1_GMAC1); 156 1.1 matt bus_space_write_4(sc->sc_iot, sc->sc_ioh, GMAC_INT2_SELECT, INT2_GMAC1); 157 1.1 matt bus_space_write_4(sc->sc_iot, sc->sc_ioh, GMAC_INT3_SELECT, INT3_GMAC1); 158 1.1 matt bus_space_write_4(sc->sc_iot, sc->sc_ioh, GMAC_INT4_SELECT, INT4_GMAC1); 159 1.1 matt 160 1.2 matt bus_space_write_4(sc->sc_iot, sc->sc_ioh, GMAC_INT0_STATUS, ~0); 161 1.2 matt bus_space_write_4(sc->sc_iot, sc->sc_ioh, GMAC_INT1_STATUS, ~0); 162 1.2 matt bus_space_write_4(sc->sc_iot, sc->sc_ioh, GMAC_INT2_STATUS, ~0); 163 1.2 matt bus_space_write_4(sc->sc_iot, sc->sc_ioh, GMAC_INT3_STATUS, ~0); 164 1.2 matt bus_space_write_4(sc->sc_iot, sc->sc_ioh, GMAC_INT4_STATUS, ~0); 165 1.2 matt 166 1.1 matt gmac_intr_update(sc); 167 1.1 matt 168 1.3 matt aprint_debug_dev(sc->sc_dev, "gmac_init: sts=%#x/%#x/%#x/%#x/%#x\n", 169 1.2 matt bus_space_read_4(sc->sc_iot, sc->sc_ioh, GMAC_INT0_STATUS), 170 1.2 matt bus_space_read_4(sc->sc_iot, sc->sc_ioh, GMAC_INT1_STATUS), 171 1.2 matt bus_space_read_4(sc->sc_iot, sc->sc_ioh, GMAC_INT2_STATUS), 172 1.2 matt bus_space_read_4(sc->sc_iot, sc->sc_ioh, GMAC_INT3_STATUS), 173 1.2 matt bus_space_read_4(sc->sc_iot, sc->sc_ioh, GMAC_INT4_STATUS)); 174 1.2 matt 175 1.3 matt aprint_debug_dev(sc->sc_dev, "gmac_init: mask=%#x/%#x/%#x/%#x/%#x\n", 176 1.2 matt bus_space_read_4(sc->sc_iot, sc->sc_ioh, GMAC_INT0_MASK), 177 1.2 matt bus_space_read_4(sc->sc_iot, sc->sc_ioh, GMAC_INT1_MASK), 178 1.2 matt bus_space_read_4(sc->sc_iot, sc->sc_ioh, GMAC_INT2_MASK), 179 1.2 matt bus_space_read_4(sc->sc_iot, sc->sc_ioh, GMAC_INT3_MASK), 180 1.2 matt bus_space_read_4(sc->sc_iot, sc->sc_ioh, GMAC_INT4_MASK)); 181 1.2 matt 182 1.3 matt aprint_debug_dev(sc->sc_dev, "gmac_init: select=%#x/%#x/%#x/%#x/%#x\n", 183 1.2 matt bus_space_read_4(sc->sc_iot, sc->sc_ioh, GMAC_INT0_SELECT), 184 1.2 matt bus_space_read_4(sc->sc_iot, sc->sc_ioh, GMAC_INT1_SELECT), 185 1.2 matt bus_space_read_4(sc->sc_iot, sc->sc_ioh, GMAC_INT2_SELECT), 186 1.2 matt bus_space_read_4(sc->sc_iot, sc->sc_ioh, GMAC_INT3_SELECT), 187 1.2 matt bus_space_read_4(sc->sc_iot, sc->sc_ioh, GMAC_INT4_SELECT)); 188 1.2 matt 189 1.3 matt aprint_debug_dev(sc->sc_dev, "gmac_init: create rx dmamap cache\n"); 190 1.1 matt /* 191 1.1 matt * Allocate the cache for receive dmamaps. 192 1.1 matt */ 193 1.1 matt sc->sc_rxmaps = gmac_mapcache_create(sc->sc_dmat, MAX_RXMAPS, 194 1.1 matt MCLBYTES, 1); 195 1.1 matt KASSERT(sc->sc_rxmaps != NULL); 196 1.1 matt 197 1.3 matt aprint_debug_dev(sc->sc_dev, "gmac_init: create tx dmamap cache\n"); 198 1.2 matt /* 199 1.2 matt * Allocate the cache for transmit dmamaps. 200 1.2 matt */ 201 1.2 matt sc->sc_txmaps = gmac_mapcache_create(sc->sc_dmat, MAX_TXMAPS, 202 1.2 matt ETHERMTU_JUMBO + ETHER_HDR_LEN, 16); 203 1.2 matt KASSERT(sc->sc_txmaps != NULL); 204 1.2 matt 205 1.3 matt aprint_debug_dev(sc->sc_dev, "gmac_init: create sw freeq\n"); 206 1.1 matt /* 207 1.1 matt * Allocate the memory for sw (receive) free queue 208 1.1 matt */ 209 1.3 matt hqm = gmac_hwqmem_create(sc->sc_rxmaps, 32 /*SWFREEQ_DESCS*/, 1, 210 1.1 matt HQM_PRODUCER|HQM_RX); 211 1.1 matt sc->sc_swfreeq = gmac_hwqueue_create(hqm, sc->sc_iot, sc->sc_ioh, 212 1.1 matt GMAC_SWFREEQ_RWPTR, GMAC_SWFREEQ_BASE, 0); 213 1.1 matt KASSERT(sc->sc_swfreeq != NULL); 214 1.1 matt 215 1.3 matt aprint_debug_dev(sc->sc_dev, "gmac_init: create hw freeq\n"); 216 1.1 matt /* 217 1.3 matt * Allocate the memory for hw (receive) free queue 218 1.1 matt */ 219 1.3 matt hqm = gmac_hwqmem_create(sc->sc_rxmaps, HWFREEQ_DESCS, 1, 220 1.3 matt HQM_PRODUCER|HQM_RX); 221 1.1 matt sc->sc_hwfreeq = gmac_hwqueue_create(hqm, sc->sc_iot, sc->sc_ioh, 222 1.1 matt GMAC_HWFREEQ_RWPTR, GMAC_HWFREEQ_BASE, 0); 223 1.1 matt KASSERT(sc->sc_hwfreeq != NULL); 224 1.2 matt 225 1.3 matt aprint_debug_dev(sc->sc_dev, "gmac_init: done\n"); 226 1.1 matt } 227 1.1 matt 228 1.1 matt int 229 1.1 matt geminigmac_match(device_t parent, cfdata_t cf, void *aux) 230 1.1 matt { 231 1.1 matt struct obio_attach_args *obio = aux; 232 1.1 matt 233 1.1 matt if (obio->obio_addr != GEMINI_GMAC_BASE) 234 1.1 matt return 0; 235 1.1 matt 236 1.1 matt return 1; 237 1.1 matt } 238 1.1 matt 239 1.1 matt void 240 1.1 matt geminigmac_attach(device_t parent, device_t self, void *aux) 241 1.1 matt { 242 1.1 matt struct gmac_softc *sc = device_private(self); 243 1.1 matt struct obio_attach_args *obio = aux; 244 1.1 matt struct gmac_attach_args gma; 245 1.1 matt cfdata_t cf; 246 1.1 matt uint32_t v; 247 1.1 matt int error; 248 1.1 matt 249 1.1 matt sc->sc_dev = self; 250 1.1 matt sc->sc_iot = obio->obio_iot; 251 1.1 matt sc->sc_dmat = obio->obio_dmat; 252 1.1 matt sc->sc_gpio_dev = geminigpio_cd.cd_devs[0]; 253 1.1 matt sc->sc_gpio_mdclk = GPIO_MDCLK; 254 1.1 matt sc->sc_gpio_mdout = GPIO_MDIO; 255 1.1 matt sc->sc_gpio_mdin = GPIO_MDIO; 256 1.1 matt KASSERT(sc->sc_gpio_dev != NULL); 257 1.1 matt 258 1.1 matt error = bus_space_map(sc->sc_iot, obio->obio_addr, obio->obio_size, 0, 259 1.1 matt &sc->sc_ioh); 260 1.1 matt if (error) { 261 1.1 matt aprint_error(": error mapping registers: %d", error); 262 1.1 matt return; 263 1.1 matt } 264 1.1 matt 265 1.1 matt v = bus_space_read_4(sc->sc_iot, sc->sc_ioh, 0); 266 1.1 matt aprint_normal(": devid %d rev %d\n", GMAC_TOE_DEVID(v), 267 1.1 matt GMAC_TOE_REVID(v)); 268 1.1 matt aprint_naive("\n"); 269 1.1 matt 270 1.1 matt mutex_init(&sc->sc_mdiolock, MUTEX_DEFAULT, IPL_NET); 271 1.1 matt 272 1.1 matt /* 273 1.1 matt * Initialize the GPIO pins 274 1.1 matt */ 275 1.1 matt geminigpio_pin_ctl(sc->sc_gpio_dev, sc->sc_gpio_mdclk, GPIO_PIN_OUTPUT); 276 1.1 matt geminigpio_pin_ctl(sc->sc_gpio_dev, sc->sc_gpio_mdout, GPIO_PIN_OUTPUT); 277 1.1 matt if (sc->sc_gpio_mdout != sc->sc_gpio_mdin) 278 1.1 matt geminigpio_pin_ctl(sc->sc_gpio_dev, sc->sc_gpio_mdin, 279 1.1 matt GPIO_PIN_INPUT); 280 1.1 matt 281 1.1 matt /* 282 1.1 matt * Set the MDIO GPIO pins to a known state. 283 1.1 matt */ 284 1.1 matt geminigpio_pin_write(sc->sc_gpio_dev, sc->sc_gpio_mdclk, 0); 285 1.1 matt geminigpio_pin_write(sc->sc_gpio_dev, sc->sc_gpio_mdout, 0); 286 1.1 matt sc->sc_mdiobits = MDCLK; 287 1.1 matt 288 1.1 matt gmac_init(sc); 289 1.1 matt 290 1.1 matt gma.gma_iot = sc->sc_iot; 291 1.1 matt gma.gma_ioh = sc->sc_ioh; 292 1.1 matt gma.gma_dmat = sc->sc_dmat; 293 1.1 matt 294 1.1 matt gma.gma_mii_readreg = geminigmac_mii_readreg; 295 1.1 matt gma.gma_mii_writereg = geminigmac_mii_writereg; 296 1.1 matt 297 1.1 matt gma.gma_port = 0; 298 1.1 matt gma.gma_phy = -1; 299 1.1 matt gma.gma_intr = 1; 300 1.1 matt 301 1.21 thorpej cf = config_search(sc->sc_dev, &gma, 302 1.22 thorpej CFARGS(.submatch = geminigmac_find, 303 1.22 thorpej .iattr = geminigmac_cd.cd_name)); 304 1.1 matt if (cf != NULL) 305 1.21 thorpej config_attach(sc->sc_dev, cf, &gma, geminigmac_print, 306 1.22 thorpej CFARGS_NONE); 307 1.1 matt 308 1.1 matt gma.gma_port = 1; 309 1.1 matt gma.gma_phy = -1; 310 1.1 matt gma.gma_intr = 2; 311 1.1 matt 312 1.21 thorpej cf = config_search(sc->sc_dev, &gma, 313 1.22 thorpej CFARGS(.submatch = geminigmac_find, 314 1.22 thorpej .iattr = geminigmac_cd.cd_name)); 315 1.1 matt if (cf != NULL) 316 1.21 thorpej config_attach(sc->sc_dev, cf, &gma, geminigmac_print, 317 1.22 thorpej CFARGS_NONE); 318 1.1 matt } 319 1.1 matt 320 1.1 matt static int 321 1.1 matt geminigmac_find(device_t parent, cfdata_t cf, const int *ldesc, void *aux) 322 1.1 matt { 323 1.1 matt struct gmac_attach_args * const gma = aux; 324 1.1 matt 325 1.1 matt if (gma->gma_port != cf->cf_loc[GEMINIGMACCF_PORT]) 326 1.1 matt return 0; 327 1.1 matt if (gma->gma_intr != cf->cf_loc[GEMINIGMACCF_INTR]) 328 1.1 matt return 0; 329 1.1 matt 330 1.1 matt gma->gma_phy = cf->cf_loc[GEMINIGMACCF_PHY]; 331 1.1 matt gma->gma_intr = cf->cf_loc[GEMINIGMACCF_INTR]; 332 1.1 matt 333 1.1 matt return config_match(parent, cf, gma); 334 1.1 matt } 335 1.1 matt 336 1.1 matt static int 337 1.1 matt geminigmac_print(void *aux, const char *name) 338 1.1 matt { 339 1.1 matt struct gmac_attach_args * const gma = aux; 340 1.1 matt 341 1.1 matt aprint_normal(" port %d", gma->gma_port); 342 1.1 matt aprint_normal(" phy %d", gma->gma_phy); 343 1.1 matt aprint_normal(" intr %d", gma->gma_intr); 344 1.1 matt 345 1.1 matt return UNCONF; 346 1.1 matt } 347 1.1 matt 348 1.1 matt static uint32_t 349 1.1 matt gemini_gmac_gpio_read(device_t dv) 350 1.1 matt { 351 1.1 matt struct gmac_softc * const sc = device_private(dv); 352 1.1 matt int value = geminigpio_pin_read(sc->sc_gpio_dev, GPIO_MDIO); 353 1.1 matt 354 1.1 matt KASSERT((sc->sc_mdiobits & MDTOPHY) == 0); 355 1.1 matt 356 1.1 matt return value ? MDIN : 0; 357 1.1 matt } 358 1.1 matt 359 1.1 matt static void 360 1.1 matt gemini_gmac_gpio_write(device_t dv, uint32_t bits) 361 1.1 matt { 362 1.1 matt struct gmac_softc * const sc = device_private(dv); 363 1.1 matt 364 1.1 matt if ((sc->sc_mdiobits ^ bits) & MDTOPHY) { 365 1.1 matt int flags = (bits & MDTOPHY) ? GPIO_PIN_OUTPUT : GPIO_PIN_INPUT; 366 1.1 matt geminigpio_pin_ctl(sc->sc_gpio_dev, GPIO_MDIO, flags); 367 1.1 matt } 368 1.1 matt 369 1.1 matt if ((sc->sc_mdiobits ^ bits) & MDOUT) { 370 1.1 matt int flags = ((bits & MDOUT) != 0); 371 1.1 matt geminigpio_pin_write(sc->sc_gpio_dev, GPIO_MDIO, flags); 372 1.1 matt } 373 1.1 matt 374 1.1 matt if ((sc->sc_mdiobits ^ bits) & MDCLK) { 375 1.1 matt int flags = ((bits & MDCLK) != 0); 376 1.1 matt geminigpio_pin_write(sc->sc_gpio_dev, GPIO_MDCLK, flags); 377 1.1 matt } 378 1.1 matt 379 1.1 matt sc->sc_mdiobits = bits; 380 1.1 matt } 381 1.1 matt 382 1.1 matt static const struct mii_bitbang_ops geminigmac_mii_bitbang_ops = { 383 1.1 matt .mbo_read = gemini_gmac_gpio_read, 384 1.1 matt .mbo_write = gemini_gmac_gpio_write, 385 1.1 matt .mbo_bits[MII_BIT_MDO] = MDOUT, 386 1.1 matt .mbo_bits[MII_BIT_MDI] = MDIN, 387 1.1 matt .mbo_bits[MII_BIT_MDC] = MDCLK, 388 1.1 matt .mbo_bits[MII_BIT_DIR_HOST_PHY] = MDTOPHY, 389 1.1 matt }; 390 1.1 matt 391 1.1 matt int 392 1.17 msaitoh geminigmac_mii_readreg(device_t dv, int phy, int reg, uint16_t *val) 393 1.1 matt { 394 1.1 matt device_t parent = device_parent(dv); 395 1.1 matt struct gmac_softc * const sc = device_private(parent); 396 1.1 matt int rv; 397 1.1 matt 398 1.1 matt mutex_enter(&sc->sc_mdiolock); 399 1.17 msaitoh rv = mii_bitbang_readreg(parent, &geminigmac_mii_bitbang_ops, phy, 400 1.17 msaitoh reg, val); 401 1.1 matt mutex_exit(&sc->sc_mdiolock); 402 1.1 matt 403 1.3 matt //aprint_debug_dev(dv, "mii_readreg(%d, %d): %#x\n", phy, reg, rv); 404 1.2 matt 405 1.1 matt return rv; 406 1.1 matt } 407 1.1 matt 408 1.17 msaitoh int 409 1.17 msaitoh geminigmac_mii_writereg(device_t dv, int phy, int reg, uint16_t val) 410 1.1 matt { 411 1.1 matt device_t parent = device_parent(dv); 412 1.1 matt struct gmac_softc * const sc = device_private(parent); 413 1.1 matt 414 1.3 matt //aprint_debug_dev(dv, "mii_writereg(%d, %d, %#x)\n", phy, reg, val); 415 1.2 matt 416 1.1 matt mutex_enter(&sc->sc_mdiolock); 417 1.17 msaitoh rv = mii_bitbang_writereg(parent, &geminigmac_mii_bitbang_ops, phy, 418 1.17 msaitoh reg, val); 419 1.1 matt mutex_exit(&sc->sc_mdiolock); 420 1.17 msaitoh 421 1.17 msaitoh return rv; 422 1.1 matt } 423 1.1 matt 424 1.1 matt 425 1.1 matt gmac_mapcache_t * 426 1.1 matt gmac_mapcache_create(bus_dma_tag_t dmat, size_t maxmaps, bus_size_t mapsize, 427 1.1 matt int nsegs) 428 1.1 matt { 429 1.1 matt gmac_mapcache_t *mc; 430 1.1 matt 431 1.1 matt mc = kmem_zalloc(offsetof(gmac_mapcache_t, mc_maps[maxmaps]), 432 1.1 matt KM_SLEEP); 433 1.1 matt if (mc == NULL) 434 1.1 matt return NULL; 435 1.1 matt 436 1.1 matt mc->mc_max = maxmaps; 437 1.1 matt mc->mc_dmat = dmat; 438 1.1 matt mc->mc_mapsize = mapsize; 439 1.1 matt mc->mc_nsegs = nsegs; 440 1.1 matt return mc; 441 1.1 matt } 442 1.1 matt 443 1.1 matt void 444 1.1 matt gmac_mapcache_destroy(gmac_mapcache_t **mc_p) 445 1.1 matt { 446 1.1 matt gmac_mapcache_t *mc = *mc_p; 447 1.1 matt 448 1.1 matt if (mc == NULL) 449 1.1 matt return; 450 1.1 matt 451 1.1 matt KASSERT(mc->mc_used == 0); 452 1.1 matt while (mc->mc_free-- > 0) { 453 1.1 matt KASSERT(mc->mc_maps[mc->mc_free] != NULL); 454 1.1 matt bus_dmamap_destroy(mc->mc_dmat, mc->mc_maps[mc->mc_free]); 455 1.1 matt mc->mc_maps[mc->mc_free] = NULL; 456 1.1 matt } 457 1.1 matt 458 1.1 matt kmem_free(mc, offsetof(gmac_mapcache_t, mc_maps[mc->mc_max])); 459 1.1 matt *mc_p = NULL; 460 1.1 matt } 461 1.1 matt 462 1.1 matt int 463 1.1 matt gmac_mapcache_fill(gmac_mapcache_t *mc, size_t limit) 464 1.1 matt { 465 1.1 matt int error; 466 1.1 matt 467 1.1 matt KASSERT(limit <= mc->mc_max); 468 1.3 matt aprint_debug("gmac_mapcache_fill(%p): limit=%zu used=%zu free=%zu\n", 469 1.1 matt mc, limit, mc->mc_used, mc->mc_free); 470 1.1 matt 471 1.1 matt for (error = 0; mc->mc_free + mc->mc_used < limit; mc->mc_free++) { 472 1.1 matt KASSERT(mc->mc_maps[mc->mc_free] == NULL); 473 1.1 matt error = bus_dmamap_create(mc->mc_dmat, mc->mc_mapsize, 474 1.1 matt mc->mc_nsegs, mc->mc_mapsize, 0, 475 1.1 matt BUS_DMA_ALLOCNOW|BUS_DMA_WAITOK, 476 1.1 matt &mc->mc_maps[mc->mc_free]); 477 1.1 matt if (error) 478 1.1 matt break; 479 1.1 matt } 480 1.3 matt aprint_debug("gmac_mapcache_fill(%p): limit=%zu used=%zu free=%zu\n", 481 1.1 matt mc, limit, mc->mc_used, mc->mc_free); 482 1.1 matt 483 1.1 matt return error; 484 1.1 matt } 485 1.1 matt 486 1.1 matt bus_dmamap_t 487 1.1 matt gmac_mapcache_get(gmac_mapcache_t *mc) 488 1.1 matt { 489 1.1 matt bus_dmamap_t map; 490 1.1 matt 491 1.1 matt KASSERT(mc != NULL); 492 1.1 matt 493 1.1 matt if (mc->mc_free == 0) { 494 1.1 matt int error; 495 1.1 matt if (mc->mc_used == mc->mc_max) 496 1.1 matt return NULL; 497 1.1 matt error = bus_dmamap_create(mc->mc_dmat, mc->mc_mapsize, 498 1.1 matt mc->mc_nsegs, mc->mc_mapsize, 0, 499 1.1 matt BUS_DMA_ALLOCNOW|BUS_DMA_NOWAIT, 500 1.1 matt &map); 501 1.1 matt if (error) 502 1.1 matt return NULL; 503 1.1 matt KASSERT(mc->mc_maps[mc->mc_free] == NULL); 504 1.1 matt } else { 505 1.1 matt KASSERT(mc->mc_free <= mc->mc_max); 506 1.1 matt map = mc->mc_maps[--mc->mc_free]; 507 1.1 matt mc->mc_maps[mc->mc_free] = NULL; 508 1.1 matt } 509 1.1 matt mc->mc_used++; 510 1.1 matt KASSERT(map != NULL); 511 1.1 matt 512 1.1 matt return map; 513 1.1 matt } 514 1.1 matt 515 1.1 matt void 516 1.1 matt gmac_mapcache_put(gmac_mapcache_t *mc, bus_dmamap_t map) 517 1.1 matt { 518 1.1 matt KASSERT(mc->mc_free + mc->mc_used < mc->mc_max); 519 1.1 matt KASSERT(mc->mc_maps[mc->mc_free] == NULL); 520 1.1 matt 521 1.1 matt mc->mc_maps[mc->mc_free++] = map; 522 1.1 matt mc->mc_used--; 523 1.1 matt } 524 1.1 matt 525 1.1 matt gmac_desc_t * 526 1.1 matt gmac_hwqueue_desc(gmac_hwqueue_t *hwq, size_t i) 527 1.1 matt { 528 1.1 matt i += hwq->hwq_wptr; 529 1.1 matt if (i >= hwq->hwq_size) 530 1.1 matt i -= hwq->hwq_size; 531 1.20 skrll return hwq->hwq_base + i; 532 1.1 matt } 533 1.1 matt 534 1.2 matt static void 535 1.2 matt gmac_hwqueue_txconsume(gmac_hwqueue_t *hwq, const gmac_desc_t *d) 536 1.2 matt { 537 1.2 matt gmac_hwqmem_t * const hqm = hwq->hwq_hqm; 538 1.2 matt struct ifnet *ifp; 539 1.2 matt bus_dmamap_t map; 540 1.2 matt struct mbuf *m; 541 1.2 matt 542 1.2 matt IF_DEQUEUE(&hwq->hwq_ifq, m); 543 1.2 matt KASSERT(m != NULL); 544 1.2 matt map = M_GETCTX(m, bus_dmamap_t); 545 1.2 matt 546 1.2 matt bus_dmamap_sync(hqm->hqm_dmat, map, 0, map->dm_mapsize, 547 1.2 matt BUS_DMASYNC_POSTWRITE); 548 1.2 matt bus_dmamap_unload(hqm->hqm_dmat, map); 549 1.2 matt M_SETCTX(m, NULL); 550 1.2 matt gmac_mapcache_put(hqm->hqm_mc, map); 551 1.2 matt 552 1.2 matt ifp = hwq->hwq_ifp; 553 1.19 skrll if_statinc(ifp, if_opackets); 554 1.19 skrll if_statiadd(ifp, if_obytes, m->m_pkthdr.len); 555 1.2 matt 556 1.3 matt aprint_debug("gmac_hwqueue_txconsume(%p): %zu@%p: %s m=%p\n", 557 1.2 matt hwq, d - hwq->hwq_base, d, ifp->if_xname, m); 558 1.2 matt 559 1.16 msaitoh bpf_mtap(ifp, m, BPF_D_OUT); 560 1.2 matt m_freem(m); 561 1.2 matt } 562 1.2 matt 563 1.1 matt void 564 1.1 matt gmac_hwqueue_sync(gmac_hwqueue_t *hwq) 565 1.1 matt { 566 1.1 matt gmac_hwqmem_t * const hqm = hwq->hwq_hqm; 567 1.2 matt uint32_t v; 568 1.2 matt uint16_t old_rptr; 569 1.2 matt size_t rptr; 570 1.1 matt 571 1.1 matt KASSERT(hqm->hqm_flags & HQM_PRODUCER); 572 1.1 matt 573 1.2 matt old_rptr = hwq->hwq_rptr; 574 1.2 matt v = bus_space_read_4(hwq->hwq_iot, hwq->hwq_qrwptr_ioh, 0); 575 1.2 matt hwq->hwq_rptr = (v >> 0) & 0xffff; 576 1.2 matt hwq->hwq_wptr = (v >> 16) & 0xffff; 577 1.1 matt 578 1.1 matt if (old_rptr == hwq->hwq_rptr) 579 1.1 matt return; 580 1.1 matt 581 1.3 matt aprint_debug("gmac_hwqueue_sync(%p): entry rptr old=%u new=%u free=%u(%u)\n", 582 1.3 matt hwq, old_rptr, hwq->hwq_rptr, hwq->hwq_free, 583 1.3 matt hwq->hwq_size - hwq->hwq_free - 1); 584 1.3 matt 585 1.2 matt hwq->hwq_free += (hwq->hwq_rptr - old_rptr) & (hwq->hwq_size - 1); 586 1.2 matt for (rptr = old_rptr; 587 1.2 matt rptr != hwq->hwq_rptr; 588 1.3 matt rptr = (rptr + 1) & (hwq->hwq_size - 1)) { 589 1.3 matt gmac_desc_t * const d = hwq->hwq_base + rptr; 590 1.3 matt if (hqm->hqm_flags & HQM_TX) { 591 1.20 skrll bus_dmamap_sync(hqm->hqm_dmat, hqm->hqm_dmamap, 592 1.3 matt sizeof(gmac_desc_t [hwq->hwq_qoff + rptr]), 593 1.3 matt sizeof(gmac_desc_t), 594 1.3 matt BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); 595 1.3 matt if (d->d_desc3 & htole32(DESC3_EOF)) 596 1.3 matt gmac_hwqueue_txconsume(hwq, d); 597 1.3 matt } else { 598 1.20 skrll bus_dmamap_sync(hqm->hqm_dmat, hqm->hqm_dmamap, 599 1.3 matt sizeof(gmac_desc_t [hwq->hwq_qoff + rptr]), 600 1.3 matt sizeof(gmac_desc_t), 601 1.3 matt BUS_DMASYNC_POSTWRITE); 602 1.3 matt 603 1.3 matt aprint_debug("gmac_hwqueue_sync(%p): %zu@%p=%#x/%#x/%#x/%#x\n", 604 1.3 matt hwq, rptr, d, d->d_desc0, d->d_desc1, 605 1.3 matt d->d_bufaddr, d->d_desc3); 606 1.20 skrll bus_dmamap_sync(hqm->hqm_dmat, hqm->hqm_dmamap, 607 1.3 matt sizeof(gmac_desc_t [hwq->hwq_qoff + rptr]), 608 1.3 matt sizeof(gmac_desc_t), 609 1.3 matt BUS_DMASYNC_PREWRITE); 610 1.2 matt } 611 1.1 matt } 612 1.2 matt 613 1.3 matt aprint_debug("gmac_hwqueue_sync(%p): exit rptr old=%u new=%u free=%u(%u)\n", 614 1.3 matt hwq, old_rptr, hwq->hwq_rptr, hwq->hwq_free, 615 1.3 matt hwq->hwq_size - hwq->hwq_free - 1); 616 1.1 matt } 617 1.1 matt 618 1.1 matt void 619 1.1 matt gmac_hwqueue_produce(gmac_hwqueue_t *hwq, size_t count) 620 1.1 matt { 621 1.1 matt gmac_hwqmem_t * const hqm = hwq->hwq_hqm; 622 1.3 matt uint16_t wptr; 623 1.3 matt uint16_t rptr = bus_space_read_4(hwq->hwq_iot, hwq->hwq_qrwptr_ioh, 0); 624 1.1 matt 625 1.1 matt KASSERT(count < hwq->hwq_free); 626 1.1 matt KASSERT(hqm->hqm_flags & HQM_PRODUCER); 627 1.3 matt KASSERT(hwq->hwq_wptr == bus_space_read_4(hwq->hwq_iot, hwq->hwq_qrwptr_ioh, 0) >> 16); 628 1.1 matt 629 1.3 matt aprint_debug("gmac_hwqueue_produce(%p, %zu): rptr=%u(%u) wptr old=%u", 630 1.3 matt hwq, count, hwq->hwq_rptr, rptr, hwq->hwq_wptr); 631 1.2 matt 632 1.1 matt hwq->hwq_free -= count; 633 1.3 matt #if 1 634 1.3 matt for (wptr = hwq->hwq_wptr; 635 1.3 matt count > 0; 636 1.3 matt count--, wptr = (wptr + 1) & (hwq->hwq_size - 1)) { 637 1.3 matt KASSERT(((wptr + 1) & (hwq->hwq_size - 1)) != hwq->hwq_rptr); 638 1.20 skrll bus_dmamap_sync(hqm->hqm_dmat, hqm->hqm_dmamap, 639 1.3 matt sizeof(gmac_desc_t [hwq->hwq_qoff + wptr]), 640 1.3 matt sizeof(gmac_desc_t), 641 1.3 matt BUS_DMASYNC_PREWRITE); 642 1.3 matt } 643 1.3 matt KASSERT(count == 0); 644 1.3 matt hwq->hwq_wptr = wptr; 645 1.3 matt #else 646 1.1 matt if (hwq->hwq_wptr + count >= hwq->hwq_size) { 647 1.20 skrll bus_dmamap_sync(hqm->hqm_dmat, hqm->hqm_dmamap, 648 1.1 matt sizeof(gmac_desc_t [hwq->hwq_qoff + hwq->hwq_wptr]), 649 1.1 matt sizeof(gmac_desc_t [hwq->hwq_size - hwq->hwq_wptr]), 650 1.2 matt BUS_DMASYNC_PREWRITE); 651 1.1 matt count -= hwq->hwq_size - hwq->hwq_wptr; 652 1.1 matt hwq->hwq_wptr = 0; 653 1.1 matt } 654 1.1 matt if (count > 0) { 655 1.20 skrll bus_dmamap_sync(hqm->hqm_dmat, hqm->hqm_dmamap, 656 1.1 matt sizeof(gmac_desc_t [hwq->hwq_qoff + hwq->hwq_wptr]), 657 1.2 matt sizeof(gmac_desc_t [count]), 658 1.2 matt BUS_DMASYNC_PREWRITE); 659 1.2 matt hwq->hwq_wptr += count; 660 1.3 matt hwq->hwq_wptr &= (hwq->hwq_size - 1); 661 1.1 matt } 662 1.3 matt #endif 663 1.1 matt 664 1.1 matt /* 665 1.1 matt * Tell the h/w we've produced a few more descriptors. 666 1.2 matt * (don't bother writing the rptr since it's RO). 667 1.1 matt */ 668 1.1 matt bus_space_write_4(hwq->hwq_iot, hwq->hwq_qrwptr_ioh, 0, 669 1.2 matt hwq->hwq_wptr << 16); 670 1.2 matt 671 1.3 matt aprint_debug(" new=%u\n", hwq->hwq_wptr); 672 1.1 matt } 673 1.1 matt 674 1.3 matt size_t 675 1.3 matt gmac_rxproduce(gmac_hwqueue_t *hwq, size_t free_min) 676 1.3 matt { 677 1.3 matt gmac_hwqmem_t * const hqm = hwq->hwq_hqm; 678 1.3 matt size_t i; 679 1.3 matt 680 1.3 matt aprint_debug("gmac_rxproduce(%p): entry free=%u(%u) free_min=%zu ifq_len=%d\n", 681 1.3 matt hwq, hwq->hwq_free, hwq->hwq_size - hwq->hwq_free - 1, 682 1.3 matt free_min, hwq->hwq_ifq.ifq_len); 683 1.3 matt 684 1.3 matt gmac_hwqueue_sync(hwq); 685 1.3 matt 686 1.3 matt aprint_debug("gmac_rxproduce(%p): postsync free=%u(%u)\n", 687 1.3 matt hwq, hwq->hwq_free, hwq->hwq_size - hwq->hwq_free - 1); 688 1.3 matt 689 1.3 matt for (i = 0; hwq->hwq_free > 0 && hwq->hwq_size - hwq->hwq_free - 1 < free_min; i++) { 690 1.3 matt bus_dmamap_t map; 691 1.3 matt gmac_desc_t * const d = gmac_hwqueue_desc(hwq, 0); 692 1.3 matt struct mbuf *m, *m0; 693 1.3 matt int error; 694 1.3 matt 695 1.3 matt if (d->d_bufaddr && (le32toh(d->d_bufaddr) >> 16) != 0xdead) { 696 1.3 matt gmac_hwqueue_produce(hwq, 1); 697 1.3 matt continue; 698 1.3 matt } 699 1.3 matt 700 1.3 matt map = gmac_mapcache_get(hqm->hqm_mc); 701 1.3 matt if (map == NULL) 702 1.3 matt break; 703 1.3 matt 704 1.3 matt KASSERT(map->dm_mapsize == 0); 705 1.3 matt 706 1.14 maxv m = m_gethdr(M_DONTWAIT, MT_DATA); 707 1.3 matt if (m == NULL) { 708 1.3 matt gmac_mapcache_put(hqm->hqm_mc, map); 709 1.3 matt break; 710 1.3 matt } 711 1.3 matt 712 1.3 matt MCLGET(m, M_DONTWAIT); 713 1.3 matt if ((m->m_flags & M_EXT) == 0) { 714 1.3 matt m_free(m); 715 1.3 matt gmac_mapcache_put(hqm->hqm_mc, map); 716 1.3 matt break; 717 1.3 matt } 718 1.3 matt error = bus_dmamap_load(hqm->hqm_dmat, map, m->m_data, 719 1.3 matt MCLBYTES, NULL, BUS_DMA_READ|BUS_DMA_NOWAIT); 720 1.3 matt if (error) { 721 1.3 matt m_free(m); 722 1.3 matt gmac_mapcache_put(hqm->hqm_mc, map); 723 1.3 matt aprint_error("gmac0: " 724 1.3 matt "map %p(%zu): can't map rx mbuf(%p) wptr=%u: %d\n", 725 1.3 matt map, map->_dm_size, m, hwq->hwq_wptr, error); 726 1.3 matt Debugger(); 727 1.3 matt break; 728 1.3 matt } 729 1.3 matt bus_dmamap_sync(hqm->hqm_dmat, map, 0, map->dm_mapsize, 730 1.3 matt BUS_DMASYNC_PREREAD); 731 1.3 matt m->m_pkthdr.len = 0; 732 1.3 matt M_SETCTX(m, map); 733 1.3 matt #if 0 734 1.3 matt d->d_desc0 = htole32(map->dm_segs->ds_len); 735 1.3 matt #endif 736 1.3 matt d->d_bufaddr = htole32(map->dm_segs->ds_addr); 737 1.3 matt for (m0 = hwq->hwq_ifq.ifq_head; m0 != NULL; m0 = m0->m_nextpkt) 738 1.3 matt KASSERT(m0 != m); 739 1.12 ozaki m->m_len = d - hwq->hwq_base; 740 1.3 matt IF_ENQUEUE(&hwq->hwq_ifq, m); 741 1.3 matt aprint_debug( 742 1.3 matt "gmac_rxproduce(%p): m=%p %zu@%p=%#x/%#x/%#x/%#x\n", hwq, 743 1.3 matt m, d - hwq->hwq_base, d, d->d_desc0, d->d_desc1, 744 1.3 matt d->d_bufaddr, d->d_desc3); 745 1.3 matt gmac_hwqueue_produce(hwq, 1); 746 1.3 matt } 747 1.3 matt 748 1.3 matt aprint_debug("gmac_rxproduce(%p): exit free=%u(%u) free_min=%zu ifq_len=%d\n", 749 1.3 matt hwq, hwq->hwq_free, hwq->hwq_size - hwq->hwq_free - 1, 750 1.3 matt free_min, hwq->hwq_ifq.ifq_len); 751 1.3 matt 752 1.3 matt return i; 753 1.3 matt } 754 1.3 matt 755 1.3 matt static bool 756 1.1 matt gmac_hwqueue_rxconsume(gmac_hwqueue_t *hwq, const gmac_desc_t *d) 757 1.1 matt { 758 1.1 matt gmac_hwqmem_t * const hqm = hwq->hwq_hqm; 759 1.1 matt struct ifnet * const ifp = hwq->hwq_ifp; 760 1.3 matt size_t buflen = d->d_desc1 & 0xffff; 761 1.1 matt bus_dmamap_t map; 762 1.1 matt struct mbuf *m, *last_m, **mp; 763 1.3 matt size_t depth; 764 1.1 matt 765 1.1 matt KASSERT(ifp != NULL); 766 1.1 matt 767 1.3 matt aprint_debug("gmac_hwqueue_rxconsume(%p): entry\n", hwq); 768 1.3 matt 769 1.3 matt aprint_debug("gmac_hwqueue_rxconsume(%p): ifp=%p(%s): %#x/%#x/%#x/%#x\n", 770 1.3 matt hwq, hwq->hwq_ifp, hwq->hwq_ifp->if_xname, 771 1.3 matt d->d_desc0, d->d_desc1, d->d_bufaddr, d->d_desc3); 772 1.3 matt 773 1.3 matt if (d->d_bufaddr == 0 || d->d_bufaddr == 0xdeadbeef) 774 1.3 matt return false; 775 1.2 matt 776 1.1 matt /* 777 1.1 matt * First we have to find this mbuf in the software free queue 778 1.1 matt * (the producer of the mbufs) and remove it. 779 1.1 matt */ 780 1.3 matt KASSERT(hwq->hwq_producer->hwq_free != hwq->hwq_producer->hwq_size - 1); 781 1.3 matt for (mp = &hwq->hwq_producer->hwq_ifq.ifq_head, last_m = NULL, depth=0; 782 1.1 matt (m = *mp) != NULL; 783 1.3 matt last_m = m, mp = &m->m_nextpkt, depth++) { 784 1.1 matt map = M_GETCTX(m, bus_dmamap_t); 785 1.2 matt KASSERT(map != NULL); 786 1.1 matt KASSERT(map->dm_nsegs == 1); 787 1.3 matt aprint_debug("gmac_hwqueue_rxconsume(%p): ifq[%zu]=%p(@%#zx) %d@swfq\n", 788 1.3 matt hwq, depth, m, map->dm_segs->ds_addr, m->m_len); 789 1.3 matt if (le32toh(d->d_bufaddr) == map->dm_segs->ds_addr) { 790 1.1 matt *mp = m->m_nextpkt; 791 1.1 matt if (hwq->hwq_producer->hwq_ifq.ifq_tail == m) 792 1.1 matt hwq->hwq_producer->hwq_ifq.ifq_tail = last_m; 793 1.1 matt hwq->hwq_producer->hwq_ifq.ifq_len--; 794 1.1 matt break; 795 1.1 matt } 796 1.1 matt } 797 1.3 matt aprint_debug("gmac_hwqueue_rxconsume(%p): ifp=%p(%s) m=%p@%zu", 798 1.3 matt hwq, hwq->hwq_ifp, hwq->hwq_ifp->if_xname, m, depth); 799 1.3 matt if (m) 800 1.3 matt aprint_debug(" swfq[%d]=%#x\n", m->m_len, 801 1.3 matt hwq->hwq_producer->hwq_base[m->m_len].d_bufaddr); 802 1.3 matt aprint_debug("\n"); 803 1.1 matt KASSERT(m != NULL); 804 1.1 matt 805 1.3 matt { 806 1.3 matt struct mbuf *m0; 807 1.3 matt for (m0 = hwq->hwq_producer->hwq_ifq.ifq_head; m0 != NULL; m0 = m0->m_nextpkt) 808 1.3 matt KASSERT(m0 != m); 809 1.3 matt } 810 1.3 matt 811 1.3 matt KASSERT(hwq->hwq_producer->hwq_base[m->m_len].d_bufaddr == d->d_bufaddr); 812 1.3 matt hwq->hwq_producer->hwq_base[m->m_len].d_bufaddr = htole32(0xdead0000 | m->m_len); 813 1.3 matt 814 1.1 matt m->m_len = buflen; 815 1.1 matt if (d->d_desc3 & DESC3_SOF) { 816 1.3 matt KASSERT(hwq->hwq_rxmbuf == NULL); 817 1.3 matt m->m_pkthdr.len = buflen; 818 1.1 matt buflen += 2; /* account for the pad */ 819 1.3 matt /* only modify m->m_data after we know mbuf is good. */ 820 1.3 matt } else { 821 1.3 matt KASSERT(hwq->hwq_rxmbuf != NULL); 822 1.3 matt hwq->hwq_rxmbuf->m_pkthdr.len += buflen; 823 1.1 matt } 824 1.1 matt 825 1.1 matt map = M_GETCTX(m, bus_dmamap_t); 826 1.1 matt 827 1.1 matt /* 828 1.1 matt * Sync the buffer contents, unload the dmamap, and save it away. 829 1.1 matt */ 830 1.2 matt bus_dmamap_sync(hqm->hqm_dmat, map, 0, buflen, BUS_DMASYNC_POSTREAD); 831 1.1 matt bus_dmamap_unload(hqm->hqm_dmat, map); 832 1.1 matt M_SETCTX(m, NULL); 833 1.1 matt gmac_mapcache_put(hqm->hqm_mc, map); 834 1.1 matt 835 1.1 matt /* 836 1.1 matt * Now we build our new packet chain by tacking this on the end. 837 1.1 matt */ 838 1.1 matt *hwq->hwq_mp = m; 839 1.1 matt if ((d->d_desc3 & DESC3_EOF) == 0) { 840 1.1 matt /* 841 1.1 matt * Not last frame, so make sure the next gets appended right. 842 1.1 matt */ 843 1.1 matt hwq->hwq_mp = &m->m_next; 844 1.3 matt return true; 845 1.1 matt } 846 1.1 matt 847 1.3 matt #if 0 848 1.1 matt /* 849 1.1 matt * We have a complete frame, let's try to deliver it. 850 1.1 matt */ 851 1.1 matt m->m_len -= ETHER_CRC_LEN; /* remove the CRC from the end */ 852 1.3 matt #endif 853 1.1 matt 854 1.1 matt /* 855 1.1 matt * Now get the whole chain. 856 1.1 matt */ 857 1.1 matt m = hwq->hwq_rxmbuf; 858 1.9 ozaki m_set_rcvif(m, ifp); /* set receive interface */ 859 1.1 matt switch (DESC0_RXSTS_GET(d->d_desc0)) { 860 1.1 matt case DESC0_RXSTS_GOOD: 861 1.1 matt case DESC0_RXSTS_LONG: 862 1.1 matt m->m_data += 2; 863 1.10 ozaki if_percpuq_enqueue(ifp->if_percpuq, m); 864 1.1 matt break; 865 1.1 matt default: 866 1.19 skrll if_statinc(ifp, if_ierrors); 867 1.1 matt m_freem(m); 868 1.1 matt break; 869 1.1 matt } 870 1.1 matt hwq->hwq_rxmbuf = NULL; 871 1.1 matt hwq->hwq_mp = &hwq->hwq_rxmbuf; 872 1.3 matt 873 1.3 matt return true; 874 1.1 matt } 875 1.1 matt 876 1.3 matt size_t 877 1.3 matt gmac_hwqueue_consume(gmac_hwqueue_t *hwq, size_t free_min) 878 1.1 matt { 879 1.1 matt gmac_hwqmem_t * const hqm = hwq->hwq_hqm; 880 1.3 matt gmac_desc_t d; 881 1.3 matt uint32_t v; 882 1.3 matt uint16_t rptr; 883 1.3 matt size_t i; 884 1.1 matt 885 1.1 matt KASSERT((hqm->hqm_flags & HQM_PRODUCER) == 0); 886 1.1 matt 887 1.3 matt aprint_debug("gmac_hwqueue_consume(%p): entry\n", hwq); 888 1.3 matt 889 1.2 matt 890 1.3 matt v = bus_space_read_4(hwq->hwq_iot, hwq->hwq_qrwptr_ioh, 0); 891 1.20 skrll rptr = (v >> 0) & 0xffff; 892 1.20 skrll hwq->hwq_wptr = (v >> 16) & 0xffff; 893 1.3 matt KASSERT(rptr == hwq->hwq_rptr); 894 1.3 matt if (rptr == hwq->hwq_wptr) 895 1.3 matt return 0; 896 1.2 matt 897 1.3 matt i = 0; 898 1.3 matt for (; rptr != hwq->hwq_wptr; rptr = (rptr + 1) & (hwq->hwq_size - 1)) { 899 1.3 matt bus_dmamap_sync(hqm->hqm_dmat, hqm->hqm_dmamap, 900 1.3 matt sizeof(gmac_desc_t [hwq->hwq_qoff + rptr]), 901 1.3 matt sizeof(gmac_desc_t), 902 1.3 matt BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); 903 1.3 matt d.d_desc0 = le32toh(hwq->hwq_base[rptr].d_desc0); 904 1.3 matt d.d_desc1 = le32toh(hwq->hwq_base[rptr].d_desc1); 905 1.3 matt d.d_bufaddr = le32toh(hwq->hwq_base[rptr].d_bufaddr); 906 1.3 matt d.d_desc3 = le32toh(hwq->hwq_base[rptr].d_desc3); 907 1.3 matt hwq->hwq_base[rptr].d_desc0 = 0; 908 1.3 matt hwq->hwq_base[rptr].d_desc1 = 0; 909 1.3 matt hwq->hwq_base[rptr].d_bufaddr = 0xdeadbeef; 910 1.3 matt hwq->hwq_base[rptr].d_desc3 = 0; 911 1.3 matt bus_dmamap_sync(hqm->hqm_dmat, hqm->hqm_dmamap, 912 1.3 matt sizeof(gmac_desc_t [hwq->hwq_qoff + rptr]), 913 1.3 matt sizeof(gmac_desc_t), 914 1.3 matt BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 915 1.1 matt 916 1.3 matt aprint_debug("gmac_hwqueue_consume(%p): rptr=%u\n", 917 1.3 matt hwq, rptr); 918 1.3 matt if (!gmac_hwqueue_rxconsume(hwq, &d)) { 919 1.3 matt rptr = (rptr + 1) & (hwq->hwq_size - 1); 920 1.3 matt i += gmac_rxproduce(hwq->hwq_producer, free_min); 921 1.3 matt break; 922 1.1 matt } 923 1.3 matt } 924 1.2 matt 925 1.3 matt /* 926 1.3 matt * Update hardware's copy of rptr. (wptr is RO). 927 1.3 matt */ 928 1.3 matt aprint_debug("gmac_hwqueue_consume(%p): rptr old=%u new=%u wptr=%u\n", 929 1.3 matt hwq, hwq->hwq_rptr, rptr, hwq->hwq_wptr); 930 1.3 matt bus_space_write_4(hwq->hwq_iot, hwq->hwq_qrwptr_ioh, 0, rptr); 931 1.3 matt hwq->hwq_rptr = rptr; 932 1.2 matt 933 1.3 matt aprint_debug("gmac_hwqueue_consume(%p): exit\n", hwq); 934 1.2 matt 935 1.3 matt return i; 936 1.1 matt } 937 1.1 matt 938 1.1 matt void 939 1.1 matt gmac_hwqmem_destroy(gmac_hwqmem_t *hqm) 940 1.1 matt { 941 1.1 matt if (hqm->hqm_nsegs) { 942 1.1 matt if (hqm->hqm_base) { 943 1.1 matt if (hqm->hqm_dmamap) { 944 1.1 matt if (hqm->hqm_dmamap->dm_mapsize) { 945 1.1 matt bus_dmamap_unload(hqm->hqm_dmat, 946 1.1 matt hqm->hqm_dmamap); 947 1.1 matt } 948 1.1 matt bus_dmamap_destroy(hqm->hqm_dmat, 949 1.1 matt hqm->hqm_dmamap); 950 1.1 matt } 951 1.1 matt bus_dmamem_unmap(hqm->hqm_dmat, hqm->hqm_base, 952 1.1 matt hqm->hqm_memsize); 953 1.1 matt } 954 1.1 matt bus_dmamem_free(hqm->hqm_dmat, hqm->hqm_segs, hqm->hqm_nsegs); 955 1.1 matt } 956 1.1 matt 957 1.1 matt kmem_free(hqm, sizeof(*hqm)); 958 1.1 matt } 959 1.1 matt 960 1.1 matt gmac_hwqmem_t * 961 1.1 matt gmac_hwqmem_create(gmac_mapcache_t *mc, size_t ndesc, size_t nqueue, int flags) 962 1.1 matt { 963 1.20 skrll gmac_hwqmem_t *hqm; 964 1.1 matt int error; 965 1.1 matt 966 1.1 matt KASSERT(ndesc > 0 && ndesc <= 2048); 967 1.1 matt KASSERT((ndesc & (ndesc - 1)) == 0); 968 1.1 matt 969 1.1 matt hqm = kmem_zalloc(sizeof(*hqm), KM_SLEEP); 970 1.1 matt hqm->hqm_memsize = nqueue * sizeof(gmac_desc_t [ndesc]); 971 1.1 matt hqm->hqm_mc = mc; 972 1.1 matt hqm->hqm_dmat = mc->mc_dmat; 973 1.1 matt hqm->hqm_ndesc = ndesc; 974 1.1 matt hqm->hqm_nqueue = nqueue; 975 1.1 matt hqm->hqm_flags = flags; 976 1.1 matt 977 1.1 matt error = bus_dmamem_alloc(hqm->hqm_dmat, hqm->hqm_memsize, 0, 0, 978 1.1 matt hqm->hqm_segs, 1, &hqm->hqm_nsegs, BUS_DMA_WAITOK); 979 1.2 matt if (error) { 980 1.2 matt KASSERT(error == 0); 981 1.1 matt goto failed; 982 1.2 matt } 983 1.2 matt KASSERT(hqm->hqm_nsegs == 1); 984 1.1 matt error = bus_dmamem_map(hqm->hqm_dmat, hqm->hqm_segs, hqm->hqm_nsegs, 985 1.1 matt hqm->hqm_memsize, (void **)&hqm->hqm_base, BUS_DMA_WAITOK); 986 1.2 matt if (error) { 987 1.2 matt KASSERT(error == 0); 988 1.1 matt goto failed; 989 1.2 matt } 990 1.1 matt error = bus_dmamap_create(hqm->hqm_dmat, hqm->hqm_memsize, 991 1.2 matt hqm->hqm_nsegs, hqm->hqm_memsize, 0, 992 1.2 matt BUS_DMA_WAITOK|BUS_DMA_ALLOCNOW, &hqm->hqm_dmamap); 993 1.2 matt if (error) { 994 1.2 matt KASSERT(error == 0); 995 1.1 matt goto failed; 996 1.2 matt } 997 1.1 matt error = bus_dmamap_load(hqm->hqm_dmat, hqm->hqm_dmamap, hqm->hqm_base, 998 1.3 matt hqm->hqm_memsize, NULL, 999 1.20 skrll BUS_DMA_WAITOK|BUS_DMA_WRITE|BUS_DMA_READ|BUS_DMA_COHERENT); 1000 1.2 matt if (error) { 1001 1.3 matt aprint_debug("gmac_hwqmem_create: ds_addr=%zu ds_len=%zu\n", 1002 1.2 matt hqm->hqm_segs->ds_addr, hqm->hqm_segs->ds_len); 1003 1.3 matt aprint_debug("gmac_hwqmem_create: bus_dmamap_load: %d\n", error); 1004 1.2 matt KASSERT(error == 0); 1005 1.1 matt goto failed; 1006 1.2 matt } 1007 1.2 matt 1008 1.2 matt memset(hqm->hqm_base, 0, hqm->hqm_memsize); 1009 1.2 matt if ((flags & HQM_PRODUCER) == 0) 1010 1.2 matt bus_dmamap_sync(hqm->hqm_dmat, hqm->hqm_dmamap, 0, 1011 1.2 matt hqm->hqm_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD); 1012 1.1 matt 1013 1.1 matt return hqm; 1014 1.1 matt 1015 1.1 matt failed: 1016 1.1 matt gmac_hwqmem_destroy(hqm); 1017 1.1 matt return NULL; 1018 1.1 matt } 1019 1.1 matt 1020 1.1 matt void 1021 1.1 matt gmac_hwqueue_destroy(gmac_hwqueue_t *hwq) 1022 1.1 matt { 1023 1.1 matt gmac_hwqmem_t * const hqm = hwq->hwq_hqm; 1024 1.1 matt KASSERT(hqm->hqm_refs & hwq->hwq_ref); 1025 1.1 matt hqm->hqm_refs &= ~hwq->hwq_ref; 1026 1.1 matt for (;;) { 1027 1.1 matt struct mbuf *m; 1028 1.1 matt bus_dmamap_t map; 1029 1.1 matt IF_DEQUEUE(&hwq->hwq_ifq, m); 1030 1.1 matt if (m == NULL) 1031 1.1 matt break; 1032 1.1 matt map = M_GETCTX(m, bus_dmamap_t); 1033 1.1 matt bus_dmamap_unload(hqm->hqm_dmat, map); 1034 1.1 matt gmac_mapcache_put(hqm->hqm_mc, map); 1035 1.1 matt m_freem(m); 1036 1.1 matt } 1037 1.1 matt kmem_free(hwq, sizeof(*hwq)); 1038 1.1 matt } 1039 1.1 matt 1040 1.1 matt gmac_hwqueue_t * 1041 1.1 matt gmac_hwqueue_create(gmac_hwqmem_t *hqm, 1042 1.1 matt bus_space_tag_t iot, bus_space_handle_t ioh, 1043 1.1 matt bus_size_t qrwptr, bus_size_t qbase, 1044 1.1 matt size_t qno) 1045 1.1 matt { 1046 1.2 matt const size_t log2_memsize = ffs(hqm->hqm_ndesc) - 1; 1047 1.1 matt gmac_hwqueue_t *hwq; 1048 1.1 matt uint32_t v; 1049 1.1 matt 1050 1.1 matt KASSERT(qno < hqm->hqm_nqueue); 1051 1.1 matt KASSERT((hqm->hqm_refs & (1 << qno)) == 0); 1052 1.1 matt 1053 1.1 matt hwq = kmem_zalloc(sizeof(*hwq), KM_SLEEP); 1054 1.1 matt hwq->hwq_size = hqm->hqm_ndesc; 1055 1.1 matt hwq->hwq_iot = iot; 1056 1.1 matt bus_space_subregion(iot, ioh, qrwptr, sizeof(uint32_t), 1057 1.1 matt &hwq->hwq_qrwptr_ioh); 1058 1.1 matt 1059 1.1 matt hwq->hwq_hqm = hqm; 1060 1.1 matt hwq->hwq_ref = 1 << qno; 1061 1.1 matt hqm->hqm_refs |= hwq->hwq_ref; 1062 1.1 matt hwq->hwq_qoff = hqm->hqm_ndesc * qno; 1063 1.1 matt hwq->hwq_base = hqm->hqm_base + hwq->hwq_qoff; 1064 1.1 matt 1065 1.1 matt if (qno == 0) { 1066 1.1 matt bus_space_write_4(hwq->hwq_iot, ioh, qbase, 1067 1.1 matt hqm->hqm_dmamap->dm_segs[0].ds_addr | (log2_memsize)); 1068 1.1 matt } 1069 1.1 matt 1070 1.2 matt v = bus_space_read_4(hwq->hwq_iot, hwq->hwq_qrwptr_ioh, 0); 1071 1.2 matt hwq->hwq_rptr = (v >> 0) & 0xffff; 1072 1.2 matt hwq->hwq_wptr = (v >> 16) & 0xffff; 1073 1.2 matt 1074 1.3 matt aprint_debug("gmac_hwqueue_create: %p: qrwptr=%zu(%#zx) wptr=%u rptr=%u" 1075 1.2 matt " base=%p@%#zx(%#x) qno=%zu\n", 1076 1.2 matt hwq, qrwptr, hwq->hwq_qrwptr_ioh, hwq->hwq_wptr, hwq->hwq_rptr, 1077 1.2 matt hwq->hwq_base, 1078 1.2 matt hqm->hqm_segs->ds_addr + sizeof(gmac_desc_t [hwq->hwq_qoff]), 1079 1.2 matt bus_space_read_4(hwq->hwq_iot, ioh, qbase), qno); 1080 1.2 matt 1081 1.1 matt hwq->hwq_free = hwq->hwq_size - 1; 1082 1.1 matt hwq->hwq_ifq.ifq_maxlen = hwq->hwq_free; 1083 1.3 matt hwq->hwq_mp = &hwq->hwq_rxmbuf; 1084 1.1 matt 1085 1.1 matt return hwq; 1086 1.1 matt } 1087