1 /* $NetBSD: gemini_gmac.c,v 1.2 2008/12/15 04:44:27 matt Exp $ */
3 * Copyright (c) 2008 The NetBSD Foundation, Inc.
6 * This code is derived from software contributed to The NetBSD Foundation
7 * by Matt Thomas <matt@3am-software.com>
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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.
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.
32 #include <sys/param.h>
33 #include <sys/device.h>
38 #include <net/if_ether.h>
40 #include <machine/bus.h>
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>
47 #include <dev/mii/mii.h>
48 #include <dev/mii/mii_bitbang.h>
52 __KERNEL_RCSID(0, "$NetBSD: gemini_gmac.c,v 1.2 2008/12/15 04:44:27 matt Exp $");
54 #define SWFREEQ_DESCS 256 /* one page worth */
55 #define HWFREEQ_DESCS 256 /* one page worth */
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
);
62 static int geminigmac_mii_readreg(device_t
, int, int);
63 static void geminigmac_mii_writereg(device_t
, int, int, int);
69 #define MDOUT __BIT(2)
70 #define MDCLK __BIT(1)
71 #define MDTOPHY __BIT(0)
73 CFATTACH_DECL_NEW(geminigmac
, sizeof(struct gmac_softc
),
74 geminigmac_match
, geminigmac_attach
, NULL
, NULL
);
76 extern struct cfdriver geminigmac_cd
;
77 extern struct cfdriver geminigpio_cd
;
80 gmac_swfree_min_update(struct gmac_softc
*sc
)
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;
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
);
95 gmac_intr_update(struct gmac_softc
*sc
)
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]);
110 gmac_init(struct gmac_softc
*sc
)
115 * This shouldn't be needed.
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);
123 bus_space_handle_t global_ioh
;
126 error
= bus_space_map(sc
->sc_iot
, GEMINI_GLOBAL_BASE
, 4, 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
);
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);
141 sc
->sc_swfree_min
= 4; /* MIN_RXMAPS; */
143 gmac_swfree_min_update(sc
);
145 bus_space_write_4(sc
->sc_iot
, sc
->sc_ioh
, GMAC_SKBSIZE
,
146 SKB_SIZE_SET(PAGE_SIZE
, MCLBYTES
));
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
;
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
);
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);
166 gmac_intr_update(sc
);
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
));
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
));
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
));
189 aprint_debug_dev(sc
->sc_dev
, "gmac_init: create rx dmamap cache\n");
191 * Allocate the cache for receive dmamaps.
193 sc
->sc_rxmaps
= gmac_mapcache_create(sc
->sc_dmat
, MAX_RXMAPS
,
195 KASSERT(sc
->sc_rxmaps
!= NULL
);
197 aprint_debug_dev(sc
->sc_dev
, "gmac_init: create tx dmamap cache\n");
199 * Allocate the cache for transmit dmamaps.
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
);
205 aprint_debug_dev(sc
->sc_dev
, "gmac_init: create sw freeq\n");
207 * Allocate the memory for sw (receive) free queue
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
);
215 aprint_debug_dev(sc
->sc_dev
, "gmac_init: create hw freeq\n");
217 * Allocate the memory for hw (receive) free queue
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
);
225 aprint_debug_dev(sc
->sc_dev
, "gmac_init: done\n");
229 geminigmac_match(device_t parent
, cfdata_t cf
, void *aux
)
231 struct obio_attach_args
*obio
= aux
;
233 if (obio
->obio_addr
!= GEMINI_GMAC_BASE
)
240 geminigmac_attach(device_t parent
, device_t self
, void *aux
)
242 struct gmac_softc
*sc
= device_private(self
);
243 struct obio_attach_args
*obio
= aux
;
244 struct gmac_attach_args gma
;
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
);
258 error
= bus_space_map(sc
->sc_iot
, obio
->obio_addr
, obio
->obio_size
, 0,
261 aprint_error(": error mapping registers: %d", error
);
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
),
270 mutex_init(&sc
->sc_mdiolock
, MUTEX_DEFAULT
, IPL_NET
);
273 * Initialize the GPIO pins
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
,
282 * Set the MDIO GPIO pins to a known state.
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
;
290 gma
.gma_iot
= sc
->sc_iot
;
291 gma
.gma_ioh
= sc
->sc_ioh
;
292 gma
.gma_dmat
= sc
->sc_dmat
;
294 gma
.gma_mii_readreg
= geminigmac_mii_readreg
;
295 gma
.gma_mii_writereg
= geminigmac_mii_writereg
;
301 cf
= config_search_ia(geminigmac_find
, sc
->sc_dev
,
302 geminigmac_cd
.cd_name
, &gma
);
304 config_attach(sc
->sc_dev
, cf
, &gma
, geminigmac_print
);
310 cf
= config_search_ia(geminigmac_find
, sc
->sc_dev
,
311 geminigmac_cd
.cd_name
, &gma
);
313 config_attach(sc
->sc_dev
, cf
, &gma
, geminigmac_print
);
317 geminigmac_find(device_t parent
, cfdata_t cf
, const int *ldesc
, void *aux
)
319 struct gmac_attach_args
* const gma
= aux
;
321 if (gma
->gma_port
!= cf
->cf_loc
[GEMINIGMACCF_PORT
])
323 if (gma
->gma_intr
!= cf
->cf_loc
[GEMINIGMACCF_INTR
])
326 gma
->gma_phy
= cf
->cf_loc
[GEMINIGMACCF_PHY
];
327 gma
->gma_intr
= cf
->cf_loc
[GEMINIGMACCF_INTR
];
329 return config_match(parent
, cf
, gma
);
333 geminigmac_print(void *aux
, const char *name
)
335 struct gmac_attach_args
* const gma
= aux
;
337 aprint_normal(" port %d", gma
->gma_port
);
338 aprint_normal(" phy %d", gma
->gma_phy
);
339 aprint_normal(" intr %d", gma
->gma_intr
);
345 gemini_gmac_gpio_read(device_t dv
)
347 struct gmac_softc
* const sc
= device_private(dv
);
348 int value
= geminigpio_pin_read(sc
->sc_gpio_dev
, GPIO_MDIO
);
350 KASSERT((sc
->sc_mdiobits
& MDTOPHY
) == 0);
352 return value
? MDIN
: 0;
356 gemini_gmac_gpio_write(device_t dv
, uint32_t bits
)
358 struct gmac_softc
* const sc
= device_private(dv
);
360 if ((sc
->sc_mdiobits
^ bits
) & MDTOPHY
) {
361 int flags
= (bits
& MDTOPHY
) ? GPIO_PIN_OUTPUT
: GPIO_PIN_INPUT
;
362 geminigpio_pin_ctl(sc
->sc_gpio_dev
, GPIO_MDIO
, flags
);
365 if ((sc
->sc_mdiobits
^ bits
) & MDOUT
) {
366 int flags
= ((bits
& MDOUT
) != 0);
367 geminigpio_pin_write(sc
->sc_gpio_dev
, GPIO_MDIO
, flags
);
370 if ((sc
->sc_mdiobits
^ bits
) & MDCLK
) {
371 int flags
= ((bits
& MDCLK
) != 0);
372 geminigpio_pin_write(sc
->sc_gpio_dev
, GPIO_MDCLK
, flags
);
375 sc
->sc_mdiobits
= bits
;
378 static const struct mii_bitbang_ops geminigmac_mii_bitbang_ops
= {
379 .mbo_read
= gemini_gmac_gpio_read
,
380 .mbo_write
= gemini_gmac_gpio_write
,
381 .mbo_bits
[MII_BIT_MDO
] = MDOUT
,
382 .mbo_bits
[MII_BIT_MDI
] = MDIN
,
383 .mbo_bits
[MII_BIT_MDC
] = MDCLK
,
384 .mbo_bits
[MII_BIT_DIR_HOST_PHY
] = MDTOPHY
,
388 geminigmac_mii_readreg(device_t dv
, int phy
, int reg
)
390 device_t parent
= device_parent(dv
);
391 struct gmac_softc
* const sc
= device_private(parent
);
394 mutex_enter(&sc
->sc_mdiolock
);
395 rv
= mii_bitbang_readreg(parent
, &geminigmac_mii_bitbang_ops
, phy
, reg
);
396 mutex_exit(&sc
->sc_mdiolock
);
398 //aprint_debug_dev(dv, "mii_readreg(%d, %d): %#x\n", phy, reg, rv);
404 geminigmac_mii_writereg(device_t dv
, int phy
, int reg
, int val
)
406 device_t parent
= device_parent(dv
);
407 struct gmac_softc
* const sc
= device_private(parent
);
409 //aprint_debug_dev(dv, "mii_writereg(%d, %d, %#x)\n", phy, reg, val);
411 mutex_enter(&sc
->sc_mdiolock
);
412 mii_bitbang_writereg(parent
, &geminigmac_mii_bitbang_ops
, phy
, reg
, val
);
413 mutex_exit(&sc
->sc_mdiolock
);
418 gmac_mapcache_create(bus_dma_tag_t dmat
, size_t maxmaps
, bus_size_t mapsize
,
423 mc
= kmem_zalloc(offsetof(gmac_mapcache_t
, mc_maps
[maxmaps
]),
428 mc
->mc_max
= maxmaps
;
430 mc
->mc_mapsize
= mapsize
;
431 mc
->mc_nsegs
= nsegs
;
436 gmac_mapcache_destroy(gmac_mapcache_t
**mc_p
)
438 gmac_mapcache_t
*mc
= *mc_p
;
443 KASSERT(mc
->mc_used
== 0);
444 while (mc
->mc_free
-- > 0) {
445 KASSERT(mc
->mc_maps
[mc
->mc_free
] != NULL
);
446 bus_dmamap_destroy(mc
->mc_dmat
, mc
->mc_maps
[mc
->mc_free
]);
447 mc
->mc_maps
[mc
->mc_free
] = NULL
;
450 kmem_free(mc
, offsetof(gmac_mapcache_t
, mc_maps
[mc
->mc_max
]));
455 gmac_mapcache_fill(gmac_mapcache_t
*mc
, size_t limit
)
459 KASSERT(limit
<= mc
->mc_max
);
460 aprint_debug("gmac_mapcache_fill(%p): limit=%zu used=%zu free=%zu\n",
461 mc
, limit
, mc
->mc_used
, mc
->mc_free
);
463 for (error
= 0; mc
->mc_free
+ mc
->mc_used
< limit
; mc
->mc_free
++) {
464 KASSERT(mc
->mc_maps
[mc
->mc_free
] == NULL
);
465 error
= bus_dmamap_create(mc
->mc_dmat
, mc
->mc_mapsize
,
466 mc
->mc_nsegs
, mc
->mc_mapsize
, 0,
467 BUS_DMA_ALLOCNOW
|BUS_DMA_WAITOK
,
468 &mc
->mc_maps
[mc
->mc_free
]);
472 aprint_debug("gmac_mapcache_fill(%p): limit=%zu used=%zu free=%zu\n",
473 mc
, limit
, mc
->mc_used
, mc
->mc_free
);
479 gmac_mapcache_get(gmac_mapcache_t
*mc
)
485 if (mc
->mc_free
== 0) {
487 if (mc
->mc_used
== mc
->mc_max
)
489 error
= bus_dmamap_create(mc
->mc_dmat
, mc
->mc_mapsize
,
490 mc
->mc_nsegs
, mc
->mc_mapsize
, 0,
491 BUS_DMA_ALLOCNOW
|BUS_DMA_NOWAIT
,
495 KASSERT(mc
->mc_maps
[mc
->mc_free
] == NULL
);
497 KASSERT(mc
->mc_free
<= mc
->mc_max
);
498 map
= mc
->mc_maps
[--mc
->mc_free
];
499 mc
->mc_maps
[mc
->mc_free
] = NULL
;
502 KASSERT(map
!= NULL
);
508 gmac_mapcache_put(gmac_mapcache_t
*mc
, bus_dmamap_t map
)
510 KASSERT(mc
->mc_free
+ mc
->mc_used
< mc
->mc_max
);
511 KASSERT(mc
->mc_maps
[mc
->mc_free
] == NULL
);
513 mc
->mc_maps
[mc
->mc_free
++] = map
;
518 gmac_hwqueue_desc(gmac_hwqueue_t
*hwq
, size_t i
)
521 if (i
>= hwq
->hwq_size
)
523 return hwq
->hwq_base
+ i
;
527 gmac_hwqueue_txconsume(gmac_hwqueue_t
*hwq
, const gmac_desc_t
*d
)
529 gmac_hwqmem_t
* const hqm
= hwq
->hwq_hqm
;
534 IF_DEQUEUE(&hwq
->hwq_ifq
, m
);
536 map
= M_GETCTX(m
, bus_dmamap_t
);
538 bus_dmamap_sync(hqm
->hqm_dmat
, map
, 0, map
->dm_mapsize
,
539 BUS_DMASYNC_POSTWRITE
);
540 bus_dmamap_unload(hqm
->hqm_dmat
, map
);
542 gmac_mapcache_put(hqm
->hqm_mc
, map
);
546 ifp
->if_obytes
+= m
->m_pkthdr
.len
;
548 aprint_debug("gmac_hwqueue_txconsume(%p): %zu@%p: %s m=%p\n",
549 hwq
, d
- hwq
->hwq_base
, d
, ifp
->if_xname
, m
);
559 gmac_hwqueue_sync(gmac_hwqueue_t
*hwq
)
561 gmac_hwqmem_t
* const hqm
= hwq
->hwq_hqm
;
566 KASSERT(hqm
->hqm_flags
& HQM_PRODUCER
);
568 old_rptr
= hwq
->hwq_rptr
;
569 v
= bus_space_read_4(hwq
->hwq_iot
, hwq
->hwq_qrwptr_ioh
, 0);
570 hwq
->hwq_rptr
= (v
>> 0) & 0xffff;
571 hwq
->hwq_wptr
= (v
>> 16) & 0xffff;
573 if (old_rptr
== hwq
->hwq_rptr
)
576 aprint_debug("gmac_hwqueue_sync(%p): entry rptr old=%u new=%u free=%u(%u)\n",
577 hwq
, old_rptr
, hwq
->hwq_rptr
, hwq
->hwq_free
,
578 hwq
->hwq_size
- hwq
->hwq_free
- 1);
580 hwq
->hwq_free
+= (hwq
->hwq_rptr
- old_rptr
) & (hwq
->hwq_size
- 1);
581 for (rptr
= old_rptr
;
582 rptr
!= hwq
->hwq_rptr
;
583 rptr
= (rptr
+ 1) & (hwq
->hwq_size
- 1)) {
584 gmac_desc_t
* const d
= hwq
->hwq_base
+ rptr
;
585 if (hqm
->hqm_flags
& HQM_TX
) {
586 bus_dmamap_sync(hqm
->hqm_dmat
, hqm
->hqm_dmamap
,
587 sizeof(gmac_desc_t
[hwq
->hwq_qoff
+ rptr
]),
589 BUS_DMASYNC_POSTREAD
|BUS_DMASYNC_POSTWRITE
);
590 if (d
->d_desc3
& htole32(DESC3_EOF
))
591 gmac_hwqueue_txconsume(hwq
, d
);
593 bus_dmamap_sync(hqm
->hqm_dmat
, hqm
->hqm_dmamap
,
594 sizeof(gmac_desc_t
[hwq
->hwq_qoff
+ rptr
]),
596 BUS_DMASYNC_POSTWRITE
);
598 aprint_debug("gmac_hwqueue_sync(%p): %zu@%p=%#x/%#x/%#x/%#x\n",
599 hwq
, rptr
, d
, d
->d_desc0
, d
->d_desc1
,
600 d
->d_bufaddr
, d
->d_desc3
);
601 bus_dmamap_sync(hqm
->hqm_dmat
, hqm
->hqm_dmamap
,
602 sizeof(gmac_desc_t
[hwq
->hwq_qoff
+ rptr
]),
604 BUS_DMASYNC_PREWRITE
);
608 aprint_debug("gmac_hwqueue_sync(%p): exit rptr old=%u new=%u free=%u(%u)\n",
609 hwq
, old_rptr
, hwq
->hwq_rptr
, hwq
->hwq_free
,
610 hwq
->hwq_size
- hwq
->hwq_free
- 1);
614 gmac_hwqueue_produce(gmac_hwqueue_t
*hwq
, size_t count
)
616 gmac_hwqmem_t
* const hqm
= hwq
->hwq_hqm
;
618 uint16_t rptr
= bus_space_read_4(hwq
->hwq_iot
, hwq
->hwq_qrwptr_ioh
, 0);
620 KASSERT(count
< hwq
->hwq_free
);
621 KASSERT(hqm
->hqm_flags
& HQM_PRODUCER
);
622 KASSERT(hwq
->hwq_wptr
== bus_space_read_4(hwq
->hwq_iot
, hwq
->hwq_qrwptr_ioh
, 0) >> 16);
624 aprint_debug("gmac_hwqueue_produce(%p, %zu): rptr=%u(%u) wptr old=%u",
625 hwq
, count
, hwq
->hwq_rptr
, rptr
, hwq
->hwq_wptr
);
627 hwq
->hwq_free
-= count
;
629 for (wptr
= hwq
->hwq_wptr
;
631 count
--, wptr
= (wptr
+ 1) & (hwq
->hwq_size
- 1)) {
632 KASSERT(((wptr
+ 1) & (hwq
->hwq_size
- 1)) != hwq
->hwq_rptr
);
633 bus_dmamap_sync(hqm
->hqm_dmat
, hqm
->hqm_dmamap
,
634 sizeof(gmac_desc_t
[hwq
->hwq_qoff
+ wptr
]),
636 BUS_DMASYNC_PREWRITE
);
639 hwq
->hwq_wptr
= wptr
;
641 if (hwq
->hwq_wptr
+ count
>= hwq
->hwq_size
) {
642 bus_dmamap_sync(hqm
->hqm_dmat
, hqm
->hqm_dmamap
,
643 sizeof(gmac_desc_t
[hwq
->hwq_qoff
+ hwq
->hwq_wptr
]),
644 sizeof(gmac_desc_t
[hwq
->hwq_size
- hwq
->hwq_wptr
]),
645 BUS_DMASYNC_PREWRITE
);
646 count
-= hwq
->hwq_size
- hwq
->hwq_wptr
;
650 bus_dmamap_sync(hqm
->hqm_dmat
, hqm
->hqm_dmamap
,
651 sizeof(gmac_desc_t
[hwq
->hwq_qoff
+ hwq
->hwq_wptr
]),
652 sizeof(gmac_desc_t
[count
]),
653 BUS_DMASYNC_PREWRITE
);
654 hwq
->hwq_wptr
+= count
;
655 hwq
->hwq_wptr
&= (hwq
->hwq_size
- 1);
660 * Tell the h/w we've produced a few more descriptors.
661 * (don't bother writing the rptr since it's RO).
663 bus_space_write_4(hwq
->hwq_iot
, hwq
->hwq_qrwptr_ioh
, 0,
664 hwq
->hwq_wptr
<< 16);
666 aprint_debug(" new=%u\n", hwq
->hwq_wptr
);
670 gmac_rxproduce(gmac_hwqueue_t
*hwq
, size_t free_min
)
672 gmac_hwqmem_t
* const hqm
= hwq
->hwq_hqm
;
675 aprint_debug("gmac_rxproduce(%p): entry free=%u(%u) free_min=%zu ifq_len=%d\n",
676 hwq
, hwq
->hwq_free
, hwq
->hwq_size
- hwq
->hwq_free
- 1,
677 free_min
, hwq
->hwq_ifq
.ifq_len
);
679 gmac_hwqueue_sync(hwq
);
681 aprint_debug("gmac_rxproduce(%p): postsync free=%u(%u)\n",
682 hwq
, hwq
->hwq_free
, hwq
->hwq_size
- hwq
->hwq_free
- 1);
684 for (i
= 0; hwq
->hwq_free
> 0 && hwq
->hwq_size
- hwq
->hwq_free
- 1 < free_min
; i
++) {
686 gmac_desc_t
* const d
= gmac_hwqueue_desc(hwq
, 0);
690 if (d
->d_bufaddr
&& (le32toh(d
->d_bufaddr
) >> 16) != 0xdead) {
691 gmac_hwqueue_produce(hwq
, 1);
695 map
= gmac_mapcache_get(hqm
->hqm_mc
);
699 KASSERT(map
->dm_mapsize
== 0);
701 m
= m_gethdr(MT_DATA
, M_DONTWAIT
);
703 gmac_mapcache_put(hqm
->hqm_mc
, map
);
707 MCLGET(m
, M_DONTWAIT
);
708 if ((m
->m_flags
& M_EXT
) == 0) {
710 gmac_mapcache_put(hqm
->hqm_mc
, map
);
713 error
= bus_dmamap_load(hqm
->hqm_dmat
, map
, m
->m_data
,
714 MCLBYTES
, NULL
, BUS_DMA_READ
|BUS_DMA_NOWAIT
);
717 gmac_mapcache_put(hqm
->hqm_mc
, map
);
718 aprint_error("gmac0: "
719 "map %p(%zu): can't map rx mbuf(%p) wptr=%u: %d\n",
720 map
, map
->_dm_size
, m
, hwq
->hwq_wptr
, error
);
724 bus_dmamap_sync(hqm
->hqm_dmat
, map
, 0, map
->dm_mapsize
,
725 BUS_DMASYNC_PREREAD
);
729 d
->d_desc0
= htole32(map
->dm_segs
->ds_len
);
731 d
->d_bufaddr
= htole32(map
->dm_segs
->ds_addr
);
732 for (m0
= hwq
->hwq_ifq
.ifq_head
; m0
!= NULL
; m0
= m0
->m_nextpkt
)
734 IF_ENQUEUE(&hwq
->hwq_ifq
, m
);
735 m
->m_len
= d
- hwq
->hwq_base
;
737 "gmac_rxproduce(%p): m=%p %zu@%p=%#x/%#x/%#x/%#x\n", hwq
,
738 m
, d
- hwq
->hwq_base
, d
, d
->d_desc0
, d
->d_desc1
,
739 d
->d_bufaddr
, d
->d_desc3
);
740 gmac_hwqueue_produce(hwq
, 1);
743 aprint_debug("gmac_rxproduce(%p): exit free=%u(%u) free_min=%zu ifq_len=%d\n",
744 hwq
, hwq
->hwq_free
, hwq
->hwq_size
- hwq
->hwq_free
- 1,
745 free_min
, hwq
->hwq_ifq
.ifq_len
);
751 gmac_hwqueue_rxconsume(gmac_hwqueue_t
*hwq
, const gmac_desc_t
*d
)
753 gmac_hwqmem_t
* const hqm
= hwq
->hwq_hqm
;
754 struct ifnet
* const ifp
= hwq
->hwq_ifp
;
755 size_t buflen
= d
->d_desc1
& 0xffff;
757 struct mbuf
*m
, *last_m
, **mp
;
760 KASSERT(ifp
!= NULL
);
762 aprint_debug("gmac_hwqueue_rxconsume(%p): entry\n", hwq
);
764 aprint_debug("gmac_hwqueue_rxconsume(%p): ifp=%p(%s): %#x/%#x/%#x/%#x\n",
765 hwq
, hwq
->hwq_ifp
, hwq
->hwq_ifp
->if_xname
,
766 d
->d_desc0
, d
->d_desc1
, d
->d_bufaddr
, d
->d_desc3
);
768 if (d
->d_bufaddr
== 0 || d
->d_bufaddr
== 0xdeadbeef)
772 * First we have to find this mbuf in the software free queue
773 * (the producer of the mbufs) and remove it.
775 KASSERT(hwq
->hwq_producer
->hwq_free
!= hwq
->hwq_producer
->hwq_size
- 1);
776 for (mp
= &hwq
->hwq_producer
->hwq_ifq
.ifq_head
, last_m
= NULL
, depth
=0;
778 last_m
= m
, mp
= &m
->m_nextpkt
, depth
++) {
779 map
= M_GETCTX(m
, bus_dmamap_t
);
780 KASSERT(map
!= NULL
);
781 KASSERT(map
->dm_nsegs
== 1);
782 aprint_debug("gmac_hwqueue_rxconsume(%p): ifq[%zu]=%p(@%#zx) %d@swfq\n",
783 hwq
, depth
, m
, map
->dm_segs
->ds_addr
, m
->m_len
);
784 if (le32toh(d
->d_bufaddr
) == map
->dm_segs
->ds_addr
) {
786 if (hwq
->hwq_producer
->hwq_ifq
.ifq_tail
== m
)
787 hwq
->hwq_producer
->hwq_ifq
.ifq_tail
= last_m
;
788 hwq
->hwq_producer
->hwq_ifq
.ifq_len
--;
792 aprint_debug("gmac_hwqueue_rxconsume(%p): ifp=%p(%s) m=%p@%zu",
793 hwq
, hwq
->hwq_ifp
, hwq
->hwq_ifp
->if_xname
, m
, depth
);
795 aprint_debug(" swfq[%d]=%#x\n", m
->m_len
,
796 hwq
->hwq_producer
->hwq_base
[m
->m_len
].d_bufaddr
);
802 for (m0
= hwq
->hwq_producer
->hwq_ifq
.ifq_head
; m0
!= NULL
; m0
= m0
->m_nextpkt
)
806 KASSERT(hwq
->hwq_producer
->hwq_base
[m
->m_len
].d_bufaddr
== d
->d_bufaddr
);
807 hwq
->hwq_producer
->hwq_base
[m
->m_len
].d_bufaddr
= htole32(0xdead0000 | m
->m_len
);
810 if (d
->d_desc3
& DESC3_SOF
) {
811 KASSERT(hwq
->hwq_rxmbuf
== NULL
);
812 m
->m_pkthdr
.len
= buflen
;
813 buflen
+= 2; /* account for the pad */
814 /* only modify m->m_data after we know mbuf is good. */
816 KASSERT(hwq
->hwq_rxmbuf
!= NULL
);
817 hwq
->hwq_rxmbuf
->m_pkthdr
.len
+= buflen
;
820 map
= M_GETCTX(m
, bus_dmamap_t
);
823 * Sync the buffer contents, unload the dmamap, and save it away.
825 bus_dmamap_sync(hqm
->hqm_dmat
, map
, 0, buflen
, BUS_DMASYNC_POSTREAD
);
826 bus_dmamap_unload(hqm
->hqm_dmat
, map
);
828 gmac_mapcache_put(hqm
->hqm_mc
, map
);
831 * Now we build our new packet chain by tacking this on the end.
834 if ((d
->d_desc3
& DESC3_EOF
) == 0) {
836 * Not last frame, so make sure the next gets appended right.
838 hwq
->hwq_mp
= &m
->m_next
;
844 * We have a complete frame, let's try to deliver it.
846 m
->m_len
-= ETHER_CRC_LEN
; /* remove the CRC from the end */
850 * Now get the whole chain.
853 m
->m_pkthdr
.rcvif
= ifp
; /* set receive interface */
855 ifp
->if_ibytes
+= m
->m_pkthdr
.len
;
856 switch (DESC0_RXSTS_GET(d
->d_desc0
)) {
857 case DESC0_RXSTS_GOOD
:
858 case DESC0_RXSTS_LONG
:
860 KASSERT(m_length(m
) == m
->m_pkthdr
.len
);
865 (*ifp
->if_input
)(ifp
, m
);
872 hwq
->hwq_rxmbuf
= NULL
;
873 hwq
->hwq_mp
= &hwq
->hwq_rxmbuf
;
879 gmac_hwqueue_consume(gmac_hwqueue_t
*hwq
, size_t free_min
)
881 gmac_hwqmem_t
* const hqm
= hwq
->hwq_hqm
;
887 KASSERT((hqm
->hqm_flags
& HQM_PRODUCER
) == 0);
889 aprint_debug("gmac_hwqueue_consume(%p): entry\n", hwq
);
892 v
= bus_space_read_4(hwq
->hwq_iot
, hwq
->hwq_qrwptr_ioh
, 0);
893 rptr
= (v
>> 0) & 0xffff;
894 hwq
->hwq_wptr
= (v
>> 16) & 0xffff;
895 KASSERT(rptr
== hwq
->hwq_rptr
);
896 if (rptr
== hwq
->hwq_wptr
)
900 for (; rptr
!= hwq
->hwq_wptr
; rptr
= (rptr
+ 1) & (hwq
->hwq_size
- 1)) {
901 bus_dmamap_sync(hqm
->hqm_dmat
, hqm
->hqm_dmamap
,
902 sizeof(gmac_desc_t
[hwq
->hwq_qoff
+ rptr
]),
904 BUS_DMASYNC_POSTREAD
|BUS_DMASYNC_POSTWRITE
);
905 d
.d_desc0
= le32toh(hwq
->hwq_base
[rptr
].d_desc0
);
906 d
.d_desc1
= le32toh(hwq
->hwq_base
[rptr
].d_desc1
);
907 d
.d_bufaddr
= le32toh(hwq
->hwq_base
[rptr
].d_bufaddr
);
908 d
.d_desc3
= le32toh(hwq
->hwq_base
[rptr
].d_desc3
);
909 hwq
->hwq_base
[rptr
].d_desc0
= 0;
910 hwq
->hwq_base
[rptr
].d_desc1
= 0;
911 hwq
->hwq_base
[rptr
].d_bufaddr
= 0xdeadbeef;
912 hwq
->hwq_base
[rptr
].d_desc3
= 0;
913 bus_dmamap_sync(hqm
->hqm_dmat
, hqm
->hqm_dmamap
,
914 sizeof(gmac_desc_t
[hwq
->hwq_qoff
+ rptr
]),
916 BUS_DMASYNC_PREREAD
|BUS_DMASYNC_PREWRITE
);
918 aprint_debug("gmac_hwqueue_consume(%p): rptr=%u\n",
920 if (!gmac_hwqueue_rxconsume(hwq
, &d
)) {
921 rptr
= (rptr
+ 1) & (hwq
->hwq_size
- 1);
922 i
+= gmac_rxproduce(hwq
->hwq_producer
, free_min
);
928 * Update hardware's copy of rptr. (wptr is RO).
930 aprint_debug("gmac_hwqueue_consume(%p): rptr old=%u new=%u wptr=%u\n",
931 hwq
, hwq
->hwq_rptr
, rptr
, hwq
->hwq_wptr
);
932 bus_space_write_4(hwq
->hwq_iot
, hwq
->hwq_qrwptr_ioh
, 0, rptr
);
933 hwq
->hwq_rptr
= rptr
;
935 aprint_debug("gmac_hwqueue_consume(%p): exit\n", hwq
);
941 gmac_hwqmem_destroy(gmac_hwqmem_t
*hqm
)
943 if (hqm
->hqm_nsegs
) {
945 if (hqm
->hqm_dmamap
) {
946 if (hqm
->hqm_dmamap
->dm_mapsize
) {
947 bus_dmamap_unload(hqm
->hqm_dmat
,
950 bus_dmamap_destroy(hqm
->hqm_dmat
,
953 bus_dmamem_unmap(hqm
->hqm_dmat
, hqm
->hqm_base
,
956 bus_dmamem_free(hqm
->hqm_dmat
, hqm
->hqm_segs
, hqm
->hqm_nsegs
);
959 kmem_free(hqm
, sizeof(*hqm
));
963 gmac_hwqmem_create(gmac_mapcache_t
*mc
, size_t ndesc
, size_t nqueue
, int flags
)
968 KASSERT(ndesc
> 0 && ndesc
<= 2048);
969 KASSERT((ndesc
& (ndesc
- 1)) == 0);
971 hqm
= kmem_zalloc(sizeof(*hqm
), KM_SLEEP
);
975 hqm
->hqm_memsize
= nqueue
* sizeof(gmac_desc_t
[ndesc
]);
977 hqm
->hqm_dmat
= mc
->mc_dmat
;
978 hqm
->hqm_ndesc
= ndesc
;
979 hqm
->hqm_nqueue
= nqueue
;
980 hqm
->hqm_flags
= flags
;
982 error
= bus_dmamem_alloc(hqm
->hqm_dmat
, hqm
->hqm_memsize
, 0, 0,
983 hqm
->hqm_segs
, 1, &hqm
->hqm_nsegs
, BUS_DMA_WAITOK
);
988 KASSERT(hqm
->hqm_nsegs
== 1);
989 error
= bus_dmamem_map(hqm
->hqm_dmat
, hqm
->hqm_segs
, hqm
->hqm_nsegs
,
990 hqm
->hqm_memsize
, (void **)&hqm
->hqm_base
, BUS_DMA_WAITOK
);
995 error
= bus_dmamap_create(hqm
->hqm_dmat
, hqm
->hqm_memsize
,
996 hqm
->hqm_nsegs
, hqm
->hqm_memsize
, 0,
997 BUS_DMA_WAITOK
|BUS_DMA_ALLOCNOW
, &hqm
->hqm_dmamap
);
1002 error
= bus_dmamap_load(hqm
->hqm_dmat
, hqm
->hqm_dmamap
, hqm
->hqm_base
,
1003 hqm
->hqm_memsize
, NULL
,
1004 BUS_DMA_WAITOK
|BUS_DMA_WRITE
|BUS_DMA_READ
|BUS_DMA_COHERENT
);
1006 aprint_debug("gmac_hwqmem_create: ds_addr=%zu ds_len=%zu\n",
1007 hqm
->hqm_segs
->ds_addr
, hqm
->hqm_segs
->ds_len
);
1008 aprint_debug("gmac_hwqmem_create: bus_dmamap_load: %d\n", error
);
1009 KASSERT(error
== 0);
1013 memset(hqm
->hqm_base
, 0, hqm
->hqm_memsize
);
1014 if ((flags
& HQM_PRODUCER
) == 0)
1015 bus_dmamap_sync(hqm
->hqm_dmat
, hqm
->hqm_dmamap
, 0,
1016 hqm
->hqm_dmamap
->dm_mapsize
, BUS_DMASYNC_PREREAD
);
1021 gmac_hwqmem_destroy(hqm
);
1026 gmac_hwqueue_destroy(gmac_hwqueue_t
*hwq
)
1028 gmac_hwqmem_t
* const hqm
= hwq
->hwq_hqm
;
1029 KASSERT(hqm
->hqm_refs
& hwq
->hwq_ref
);
1030 hqm
->hqm_refs
&= ~hwq
->hwq_ref
;
1034 IF_DEQUEUE(&hwq
->hwq_ifq
, m
);
1037 map
= M_GETCTX(m
, bus_dmamap_t
);
1038 bus_dmamap_unload(hqm
->hqm_dmat
, map
);
1039 gmac_mapcache_put(hqm
->hqm_mc
, map
);
1042 kmem_free(hwq
, sizeof(*hwq
));
1046 gmac_hwqueue_create(gmac_hwqmem_t
*hqm
,
1047 bus_space_tag_t iot
, bus_space_handle_t ioh
,
1048 bus_size_t qrwptr
, bus_size_t qbase
,
1051 const size_t log2_memsize
= ffs(hqm
->hqm_ndesc
) - 1;
1052 gmac_hwqueue_t
*hwq
;
1055 KASSERT(qno
< hqm
->hqm_nqueue
);
1056 KASSERT((hqm
->hqm_refs
& (1 << qno
)) == 0);
1058 hwq
= kmem_zalloc(sizeof(*hwq
), KM_SLEEP
);
1062 hwq
->hwq_size
= hqm
->hqm_ndesc
;
1065 bus_space_subregion(iot
, ioh
, qrwptr
, sizeof(uint32_t),
1066 &hwq
->hwq_qrwptr_ioh
);
1069 hwq
->hwq_ref
= 1 << qno
;
1070 hqm
->hqm_refs
|= hwq
->hwq_ref
;
1071 hwq
->hwq_qoff
= hqm
->hqm_ndesc
* qno
;
1072 hwq
->hwq_base
= hqm
->hqm_base
+ hwq
->hwq_qoff
;
1075 bus_space_write_4(hwq
->hwq_iot
, ioh
, qbase
,
1076 hqm
->hqm_dmamap
->dm_segs
[0].ds_addr
| (log2_memsize
));
1079 v
= bus_space_read_4(hwq
->hwq_iot
, hwq
->hwq_qrwptr_ioh
, 0);
1080 hwq
->hwq_rptr
= (v
>> 0) & 0xffff;
1081 hwq
->hwq_wptr
= (v
>> 16) & 0xffff;
1083 aprint_debug("gmac_hwqueue_create: %p: qrwptr=%zu(%#zx) wptr=%u rptr=%u"
1084 " base=%p@%#zx(%#x) qno=%zu\n",
1085 hwq
, qrwptr
, hwq
->hwq_qrwptr_ioh
, hwq
->hwq_wptr
, hwq
->hwq_rptr
,
1087 hqm
->hqm_segs
->ds_addr
+ sizeof(gmac_desc_t
[hwq
->hwq_qoff
]),
1088 bus_space_read_4(hwq
->hwq_iot
, ioh
, qbase
), qno
);
1090 hwq
->hwq_free
= hwq
->hwq_size
- 1;
1091 hwq
->hwq_ifq
.ifq_maxlen
= hwq
->hwq_free
;
1092 hwq
->hwq_mp
= &hwq
->hwq_rxmbuf
;