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