dwc_gmac.c revision 1.43.2.2 1 1.43.2.2 jdolecek /* $NetBSD: dwc_gmac.c,v 1.43.2.2 2017/12/03 11:37:03 jdolecek Exp $ */
2 1.43.2.2 jdolecek
3 1.43.2.2 jdolecek /*-
4 1.43.2.2 jdolecek * Copyright (c) 2013, 2014 The NetBSD Foundation, Inc.
5 1.43.2.2 jdolecek * All rights reserved.
6 1.43.2.2 jdolecek *
7 1.43.2.2 jdolecek * This code is derived from software contributed to The NetBSD Foundation
8 1.43.2.2 jdolecek * by Matt Thomas of 3am Software Foundry and Martin Husemann.
9 1.43.2.2 jdolecek *
10 1.43.2.2 jdolecek * Redistribution and use in source and binary forms, with or without
11 1.43.2.2 jdolecek * modification, are permitted provided that the following conditions
12 1.43.2.2 jdolecek * are met:
13 1.43.2.2 jdolecek * 1. Redistributions of source code must retain the above copyright
14 1.43.2.2 jdolecek * notice, this list of conditions and the following disclaimer.
15 1.43.2.2 jdolecek * 2. Redistributions in binary form must reproduce the above copyright
16 1.43.2.2 jdolecek * notice, this list of conditions and the following disclaimer in the
17 1.43.2.2 jdolecek * documentation and/or other materials provided with the distribution.
18 1.43.2.2 jdolecek *
19 1.43.2.2 jdolecek * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 1.43.2.2 jdolecek * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 1.43.2.2 jdolecek * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 1.43.2.2 jdolecek * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 1.43.2.2 jdolecek * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 1.43.2.2 jdolecek * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 1.43.2.2 jdolecek * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 1.43.2.2 jdolecek * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 1.43.2.2 jdolecek * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 1.43.2.2 jdolecek * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 1.43.2.2 jdolecek * POSSIBILITY OF SUCH DAMAGE.
30 1.43.2.2 jdolecek */
31 1.43.2.2 jdolecek
32 1.43.2.2 jdolecek /*
33 1.43.2.2 jdolecek * This driver supports the Synopsis Designware GMAC core, as found
34 1.43.2.2 jdolecek * on Allwinner A20 cores and others.
35 1.43.2.2 jdolecek *
36 1.43.2.2 jdolecek * Real documentation seems to not be available, the marketing product
37 1.43.2.2 jdolecek * documents could be found here:
38 1.43.2.2 jdolecek *
39 1.43.2.2 jdolecek * http://www.synopsys.com/dw/ipdir.php?ds=dwc_ether_mac10_100_1000_unive
40 1.43.2.2 jdolecek */
41 1.43.2.2 jdolecek
42 1.43.2.2 jdolecek #include <sys/cdefs.h>
43 1.43.2.2 jdolecek
44 1.43.2.2 jdolecek __KERNEL_RCSID(1, "$NetBSD: dwc_gmac.c,v 1.43.2.2 2017/12/03 11:37:03 jdolecek Exp $");
45 1.43.2.2 jdolecek
46 1.43.2.2 jdolecek /* #define DWC_GMAC_DEBUG 1 */
47 1.43.2.2 jdolecek
48 1.43.2.2 jdolecek #ifdef _KERNEL_OPT
49 1.43.2.2 jdolecek #include "opt_inet.h"
50 1.43.2.2 jdolecek #include "opt_net_mpsafe.h"
51 1.43.2.2 jdolecek #endif
52 1.43.2.2 jdolecek
53 1.43.2.2 jdolecek #include <sys/param.h>
54 1.43.2.2 jdolecek #include <sys/bus.h>
55 1.43.2.2 jdolecek #include <sys/device.h>
56 1.43.2.2 jdolecek #include <sys/intr.h>
57 1.43.2.2 jdolecek #include <sys/systm.h>
58 1.43.2.2 jdolecek #include <sys/sockio.h>
59 1.43.2.2 jdolecek #include <sys/cprng.h>
60 1.43.2.2 jdolecek
61 1.43.2.2 jdolecek #include <net/if.h>
62 1.43.2.2 jdolecek #include <net/if_ether.h>
63 1.43.2.2 jdolecek #include <net/if_media.h>
64 1.43.2.2 jdolecek #include <net/bpf.h>
65 1.43.2.2 jdolecek #ifdef INET
66 1.43.2.2 jdolecek #include <netinet/if_inarp.h>
67 1.43.2.2 jdolecek #endif
68 1.43.2.2 jdolecek
69 1.43.2.2 jdolecek #include <dev/mii/miivar.h>
70 1.43.2.2 jdolecek
71 1.43.2.2 jdolecek #include <dev/ic/dwc_gmac_reg.h>
72 1.43.2.2 jdolecek #include <dev/ic/dwc_gmac_var.h>
73 1.43.2.2 jdolecek
74 1.43.2.2 jdolecek static int dwc_gmac_miibus_read_reg(device_t, int, int);
75 1.43.2.2 jdolecek static void dwc_gmac_miibus_write_reg(device_t, int, int, int);
76 1.43.2.2 jdolecek static void dwc_gmac_miibus_statchg(struct ifnet *);
77 1.43.2.2 jdolecek
78 1.43.2.2 jdolecek static int dwc_gmac_reset(struct dwc_gmac_softc *sc);
79 1.43.2.2 jdolecek static void dwc_gmac_write_hwaddr(struct dwc_gmac_softc *sc,
80 1.43.2.2 jdolecek uint8_t enaddr[ETHER_ADDR_LEN]);
81 1.43.2.2 jdolecek static int dwc_gmac_alloc_dma_rings(struct dwc_gmac_softc *sc);
82 1.43.2.2 jdolecek static void dwc_gmac_free_dma_rings(struct dwc_gmac_softc *sc);
83 1.43.2.2 jdolecek static int dwc_gmac_alloc_rx_ring(struct dwc_gmac_softc *sc, struct dwc_gmac_rx_ring *);
84 1.43.2.2 jdolecek static void dwc_gmac_reset_rx_ring(struct dwc_gmac_softc *sc, struct dwc_gmac_rx_ring *);
85 1.43.2.2 jdolecek static void dwc_gmac_free_rx_ring(struct dwc_gmac_softc *sc, struct dwc_gmac_rx_ring *);
86 1.43.2.2 jdolecek static int dwc_gmac_alloc_tx_ring(struct dwc_gmac_softc *sc, struct dwc_gmac_tx_ring *);
87 1.43.2.2 jdolecek static void dwc_gmac_reset_tx_ring(struct dwc_gmac_softc *sc, struct dwc_gmac_tx_ring *);
88 1.43.2.2 jdolecek static void dwc_gmac_free_tx_ring(struct dwc_gmac_softc *sc, struct dwc_gmac_tx_ring *);
89 1.43.2.2 jdolecek static void dwc_gmac_txdesc_sync(struct dwc_gmac_softc *sc, int start, int end, int ops);
90 1.43.2.2 jdolecek static int dwc_gmac_init(struct ifnet *ifp);
91 1.43.2.2 jdolecek static int dwc_gmac_init_locked(struct ifnet *ifp);
92 1.43.2.2 jdolecek static void dwc_gmac_stop(struct ifnet *ifp, int disable);
93 1.43.2.2 jdolecek static void dwc_gmac_stop_locked(struct ifnet *ifp, int disable);
94 1.43.2.2 jdolecek static void dwc_gmac_start(struct ifnet *ifp);
95 1.43.2.2 jdolecek static void dwc_gmac_start_locked(struct ifnet *ifp);
96 1.43.2.2 jdolecek static int dwc_gmac_queue(struct dwc_gmac_softc *sc, struct mbuf *m0);
97 1.43.2.2 jdolecek static int dwc_gmac_ioctl(struct ifnet *, u_long, void *);
98 1.43.2.2 jdolecek static void dwc_gmac_tx_intr(struct dwc_gmac_softc *sc);
99 1.43.2.2 jdolecek static void dwc_gmac_rx_intr(struct dwc_gmac_softc *sc);
100 1.43.2.2 jdolecek static void dwc_gmac_setmulti(struct dwc_gmac_softc *sc);
101 1.43.2.2 jdolecek static int dwc_gmac_ifflags_cb(struct ethercom *);
102 1.43.2.2 jdolecek static uint32_t bitrev32(uint32_t x);
103 1.43.2.2 jdolecek
104 1.43.2.2 jdolecek #define TX_DESC_OFFSET(N) ((AWGE_RX_RING_COUNT+(N)) \
105 1.43.2.2 jdolecek *sizeof(struct dwc_gmac_dev_dmadesc))
106 1.43.2.2 jdolecek #define TX_NEXT(N) (((N)+1) & (AWGE_TX_RING_COUNT-1))
107 1.43.2.2 jdolecek
108 1.43.2.2 jdolecek #define RX_DESC_OFFSET(N) ((N)*sizeof(struct dwc_gmac_dev_dmadesc))
109 1.43.2.2 jdolecek #define RX_NEXT(N) (((N)+1) & (AWGE_RX_RING_COUNT-1))
110 1.43.2.2 jdolecek
111 1.43.2.2 jdolecek
112 1.43.2.2 jdolecek
113 1.43.2.2 jdolecek #define GMAC_DEF_DMA_INT_MASK (GMAC_DMA_INT_TIE|GMAC_DMA_INT_RIE| \
114 1.43.2.2 jdolecek GMAC_DMA_INT_NIE|GMAC_DMA_INT_AIE| \
115 1.43.2.2 jdolecek GMAC_DMA_INT_FBE|GMAC_DMA_INT_UNE)
116 1.43.2.2 jdolecek
117 1.43.2.2 jdolecek #define GMAC_DMA_INT_ERRORS (GMAC_DMA_INT_AIE|GMAC_DMA_INT_ERE| \
118 1.43.2.2 jdolecek GMAC_DMA_INT_FBE| \
119 1.43.2.2 jdolecek GMAC_DMA_INT_RWE|GMAC_DMA_INT_RUE| \
120 1.43.2.2 jdolecek GMAC_DMA_INT_UNE|GMAC_DMA_INT_OVE| \
121 1.43.2.2 jdolecek GMAC_DMA_INT_TJE)
122 1.43.2.2 jdolecek
123 1.43.2.2 jdolecek #define AWIN_DEF_MAC_INTRMASK \
124 1.43.2.2 jdolecek (AWIN_GMAC_MAC_INT_TSI | AWIN_GMAC_MAC_INT_ANEG | \
125 1.43.2.2 jdolecek AWIN_GMAC_MAC_INT_LINKCHG | AWIN_GMAC_MAC_INT_RGSMII)
126 1.43.2.2 jdolecek
127 1.43.2.2 jdolecek
128 1.43.2.2 jdolecek #ifdef DWC_GMAC_DEBUG
129 1.43.2.2 jdolecek static void dwc_gmac_dump_dma(struct dwc_gmac_softc *sc);
130 1.43.2.2 jdolecek static void dwc_gmac_dump_tx_desc(struct dwc_gmac_softc *sc);
131 1.43.2.2 jdolecek static void dwc_gmac_dump_rx_desc(struct dwc_gmac_softc *sc);
132 1.43.2.2 jdolecek static void dwc_dump_and_abort(struct dwc_gmac_softc *sc, const char *msg);
133 1.43.2.2 jdolecek static void dwc_dump_status(struct dwc_gmac_softc *sc);
134 1.43.2.2 jdolecek static void dwc_gmac_dump_ffilt(struct dwc_gmac_softc *sc, uint32_t ffilt);
135 1.43.2.2 jdolecek #endif
136 1.43.2.2 jdolecek
137 1.43.2.2 jdolecek #ifdef NET_MPSAFE
138 1.43.2.2 jdolecek #define DWCGMAC_MPSAFE 1
139 1.43.2.2 jdolecek #endif
140 1.43.2.2 jdolecek
141 1.43.2.2 jdolecek void
142 1.43.2.2 jdolecek dwc_gmac_attach(struct dwc_gmac_softc *sc, uint32_t mii_clk)
143 1.43.2.2 jdolecek {
144 1.43.2.2 jdolecek uint8_t enaddr[ETHER_ADDR_LEN];
145 1.43.2.2 jdolecek uint32_t maclo, machi;
146 1.43.2.2 jdolecek struct mii_data * const mii = &sc->sc_mii;
147 1.43.2.2 jdolecek struct ifnet * const ifp = &sc->sc_ec.ec_if;
148 1.43.2.2 jdolecek prop_dictionary_t dict;
149 1.43.2.2 jdolecek int rv;
150 1.43.2.2 jdolecek
151 1.43.2.2 jdolecek mutex_init(&sc->sc_mdio_lock, MUTEX_DEFAULT, IPL_NET);
152 1.43.2.2 jdolecek sc->sc_mii_clk = mii_clk & 7;
153 1.43.2.2 jdolecek
154 1.43.2.2 jdolecek dict = device_properties(sc->sc_dev);
155 1.43.2.2 jdolecek prop_data_t ea = dict ? prop_dictionary_get(dict, "mac-address") : NULL;
156 1.43.2.2 jdolecek if (ea != NULL) {
157 1.43.2.2 jdolecek /*
158 1.43.2.2 jdolecek * If the MAC address is overriden by a device property,
159 1.43.2.2 jdolecek * use that.
160 1.43.2.2 jdolecek */
161 1.43.2.2 jdolecek KASSERT(prop_object_type(ea) == PROP_TYPE_DATA);
162 1.43.2.2 jdolecek KASSERT(prop_data_size(ea) == ETHER_ADDR_LEN);
163 1.43.2.2 jdolecek memcpy(enaddr, prop_data_data_nocopy(ea), ETHER_ADDR_LEN);
164 1.43.2.2 jdolecek } else {
165 1.43.2.2 jdolecek /*
166 1.43.2.2 jdolecek * If we did not get an externaly configure address,
167 1.43.2.2 jdolecek * try to read one from the current filter setup,
168 1.43.2.2 jdolecek * before resetting the chip.
169 1.43.2.2 jdolecek */
170 1.43.2.2 jdolecek maclo = bus_space_read_4(sc->sc_bst, sc->sc_bsh,
171 1.43.2.2 jdolecek AWIN_GMAC_MAC_ADDR0LO);
172 1.43.2.2 jdolecek machi = bus_space_read_4(sc->sc_bst, sc->sc_bsh,
173 1.43.2.2 jdolecek AWIN_GMAC_MAC_ADDR0HI);
174 1.43.2.2 jdolecek
175 1.43.2.2 jdolecek if (maclo == 0xffffffff && (machi & 0xffff) == 0xffff) {
176 1.43.2.2 jdolecek /* fake MAC address */
177 1.43.2.2 jdolecek maclo = 0x00f2 | (cprng_strong32() << 16);
178 1.43.2.2 jdolecek machi = cprng_strong32();
179 1.43.2.2 jdolecek }
180 1.43.2.2 jdolecek
181 1.43.2.2 jdolecek enaddr[0] = maclo & 0x0ff;
182 1.43.2.2 jdolecek enaddr[1] = (maclo >> 8) & 0x0ff;
183 1.43.2.2 jdolecek enaddr[2] = (maclo >> 16) & 0x0ff;
184 1.43.2.2 jdolecek enaddr[3] = (maclo >> 24) & 0x0ff;
185 1.43.2.2 jdolecek enaddr[4] = machi & 0x0ff;
186 1.43.2.2 jdolecek enaddr[5] = (machi >> 8) & 0x0ff;
187 1.43.2.2 jdolecek }
188 1.43.2.2 jdolecek
189 1.43.2.2 jdolecek /*
190 1.43.2.2 jdolecek * Init chip and do initial setup
191 1.43.2.2 jdolecek */
192 1.43.2.2 jdolecek if (dwc_gmac_reset(sc) != 0)
193 1.43.2.2 jdolecek return; /* not much to cleanup, haven't attached yet */
194 1.43.2.2 jdolecek dwc_gmac_write_hwaddr(sc, enaddr);
195 1.43.2.2 jdolecek aprint_normal_dev(sc->sc_dev, "Ethernet address: %s\n",
196 1.43.2.2 jdolecek ether_sprintf(enaddr));
197 1.43.2.2 jdolecek
198 1.43.2.2 jdolecek /*
199 1.43.2.2 jdolecek * Allocate Tx and Rx rings
200 1.43.2.2 jdolecek */
201 1.43.2.2 jdolecek if (dwc_gmac_alloc_dma_rings(sc) != 0) {
202 1.43.2.2 jdolecek aprint_error_dev(sc->sc_dev, "could not allocate DMA rings\n");
203 1.43.2.2 jdolecek goto fail;
204 1.43.2.2 jdolecek }
205 1.43.2.2 jdolecek
206 1.43.2.2 jdolecek if (dwc_gmac_alloc_tx_ring(sc, &sc->sc_txq) != 0) {
207 1.43.2.2 jdolecek aprint_error_dev(sc->sc_dev, "could not allocate Tx ring\n");
208 1.43.2.2 jdolecek goto fail;
209 1.43.2.2 jdolecek }
210 1.43.2.2 jdolecek
211 1.43.2.2 jdolecek if (dwc_gmac_alloc_rx_ring(sc, &sc->sc_rxq) != 0) {
212 1.43.2.2 jdolecek aprint_error_dev(sc->sc_dev, "could not allocate Rx ring\n");
213 1.43.2.2 jdolecek goto fail;
214 1.43.2.2 jdolecek }
215 1.43.2.2 jdolecek
216 1.43.2.2 jdolecek sc->sc_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NET);
217 1.43.2.2 jdolecek mutex_init(&sc->sc_txq.t_mtx, MUTEX_DEFAULT, IPL_NET);
218 1.43.2.2 jdolecek mutex_init(&sc->sc_rxq.r_mtx, MUTEX_DEFAULT, IPL_NET);
219 1.43.2.2 jdolecek
220 1.43.2.2 jdolecek /*
221 1.43.2.2 jdolecek * Prepare interface data
222 1.43.2.2 jdolecek */
223 1.43.2.2 jdolecek ifp->if_softc = sc;
224 1.43.2.2 jdolecek strlcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ);
225 1.43.2.2 jdolecek ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
226 1.43.2.2 jdolecek ifp->if_extflags = IFEF_MPSAFE;
227 1.43.2.2 jdolecek ifp->if_ioctl = dwc_gmac_ioctl;
228 1.43.2.2 jdolecek ifp->if_start = dwc_gmac_start;
229 1.43.2.2 jdolecek ifp->if_init = dwc_gmac_init;
230 1.43.2.2 jdolecek ifp->if_stop = dwc_gmac_stop;
231 1.43.2.2 jdolecek IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
232 1.43.2.2 jdolecek IFQ_SET_READY(&ifp->if_snd);
233 1.43.2.2 jdolecek
234 1.43.2.2 jdolecek /*
235 1.43.2.2 jdolecek * Attach MII subdevices
236 1.43.2.2 jdolecek */
237 1.43.2.2 jdolecek sc->sc_ec.ec_mii = &sc->sc_mii;
238 1.43.2.2 jdolecek ifmedia_init(&mii->mii_media, 0, ether_mediachange, ether_mediastatus);
239 1.43.2.2 jdolecek mii->mii_ifp = ifp;
240 1.43.2.2 jdolecek mii->mii_readreg = dwc_gmac_miibus_read_reg;
241 1.43.2.2 jdolecek mii->mii_writereg = dwc_gmac_miibus_write_reg;
242 1.43.2.2 jdolecek mii->mii_statchg = dwc_gmac_miibus_statchg;
243 1.43.2.2 jdolecek mii_attach(sc->sc_dev, mii, 0xffffffff, MII_PHY_ANY, MII_OFFSET_ANY,
244 1.43.2.2 jdolecek MIIF_DOPAUSE);
245 1.43.2.2 jdolecek
246 1.43.2.2 jdolecek if (LIST_EMPTY(&mii->mii_phys)) {
247 1.43.2.2 jdolecek aprint_error_dev(sc->sc_dev, "no PHY found!\n");
248 1.43.2.2 jdolecek ifmedia_add(&mii->mii_media, IFM_ETHER|IFM_MANUAL, 0, NULL);
249 1.43.2.2 jdolecek ifmedia_set(&mii->mii_media, IFM_ETHER|IFM_MANUAL);
250 1.43.2.2 jdolecek } else {
251 1.43.2.2 jdolecek ifmedia_set(&mii->mii_media, IFM_ETHER|IFM_AUTO);
252 1.43.2.2 jdolecek }
253 1.43.2.2 jdolecek
254 1.43.2.2 jdolecek /*
255 1.43.2.2 jdolecek * We can support 802.1Q VLAN-sized frames.
256 1.43.2.2 jdolecek */
257 1.43.2.2 jdolecek sc->sc_ec.ec_capabilities |= ETHERCAP_VLAN_MTU;
258 1.43.2.2 jdolecek
259 1.43.2.2 jdolecek /*
260 1.43.2.2 jdolecek * Ready, attach interface
261 1.43.2.2 jdolecek */
262 1.43.2.2 jdolecek /* Attach the interface. */
263 1.43.2.2 jdolecek rv = if_initialize(ifp);
264 1.43.2.2 jdolecek if (rv != 0)
265 1.43.2.2 jdolecek goto fail_2;
266 1.43.2.2 jdolecek sc->sc_ipq = if_percpuq_create(&sc->sc_ec.ec_if);
267 1.43.2.2 jdolecek if_deferred_start_init(ifp, NULL);
268 1.43.2.2 jdolecek ether_ifattach(ifp, enaddr);
269 1.43.2.2 jdolecek ether_set_ifflags_cb(&sc->sc_ec, dwc_gmac_ifflags_cb);
270 1.43.2.2 jdolecek if_register(ifp);
271 1.43.2.2 jdolecek
272 1.43.2.2 jdolecek /*
273 1.43.2.2 jdolecek * Enable interrupts
274 1.43.2.2 jdolecek */
275 1.43.2.2 jdolecek mutex_enter(sc->sc_lock);
276 1.43.2.2 jdolecek bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_INTMASK,
277 1.43.2.2 jdolecek AWIN_DEF_MAC_INTRMASK);
278 1.43.2.2 jdolecek bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_INTENABLE,
279 1.43.2.2 jdolecek GMAC_DEF_DMA_INT_MASK);
280 1.43.2.2 jdolecek mutex_exit(sc->sc_lock);
281 1.43.2.2 jdolecek
282 1.43.2.2 jdolecek return;
283 1.43.2.2 jdolecek fail_2:
284 1.43.2.2 jdolecek ifmedia_removeall(&mii->mii_media);
285 1.43.2.2 jdolecek mii_detach(mii, MII_PHY_ANY, MII_OFFSET_ANY);
286 1.43.2.2 jdolecek mutex_destroy(&sc->sc_txq.t_mtx);
287 1.43.2.2 jdolecek mutex_destroy(&sc->sc_rxq.r_mtx);
288 1.43.2.2 jdolecek mutex_obj_free(sc->sc_lock);
289 1.43.2.2 jdolecek fail:
290 1.43.2.2 jdolecek dwc_gmac_free_rx_ring(sc, &sc->sc_rxq);
291 1.43.2.2 jdolecek dwc_gmac_free_tx_ring(sc, &sc->sc_txq);
292 1.43.2.2 jdolecek dwc_gmac_free_dma_rings(sc);
293 1.43.2.2 jdolecek mutex_destroy(&sc->sc_mdio_lock);
294 1.43.2.2 jdolecek }
295 1.43.2.2 jdolecek
296 1.43.2.2 jdolecek
297 1.43.2.2 jdolecek
298 1.43.2.2 jdolecek static int
299 1.43.2.2 jdolecek dwc_gmac_reset(struct dwc_gmac_softc *sc)
300 1.43.2.2 jdolecek {
301 1.43.2.2 jdolecek size_t cnt;
302 1.43.2.2 jdolecek bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_BUSMODE,
303 1.43.2.2 jdolecek bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_BUSMODE) | GMAC_BUSMODE_RESET);
304 1.43.2.2 jdolecek for (cnt = 0; cnt < 3000; cnt++) {
305 1.43.2.2 jdolecek if ((bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_BUSMODE)
306 1.43.2.2 jdolecek & GMAC_BUSMODE_RESET) == 0)
307 1.43.2.2 jdolecek return 0;
308 1.43.2.2 jdolecek delay(10);
309 1.43.2.2 jdolecek }
310 1.43.2.2 jdolecek
311 1.43.2.2 jdolecek aprint_error_dev(sc->sc_dev, "reset timed out\n");
312 1.43.2.2 jdolecek return EIO;
313 1.43.2.2 jdolecek }
314 1.43.2.2 jdolecek
315 1.43.2.2 jdolecek static void
316 1.43.2.2 jdolecek dwc_gmac_write_hwaddr(struct dwc_gmac_softc *sc,
317 1.43.2.2 jdolecek uint8_t enaddr[ETHER_ADDR_LEN])
318 1.43.2.2 jdolecek {
319 1.43.2.2 jdolecek uint32_t lo, hi;
320 1.43.2.2 jdolecek
321 1.43.2.2 jdolecek lo = enaddr[0] | (enaddr[1] << 8) | (enaddr[2] << 16)
322 1.43.2.2 jdolecek | (enaddr[3] << 24);
323 1.43.2.2 jdolecek hi = enaddr[4] | (enaddr[5] << 8);
324 1.43.2.2 jdolecek bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_ADDR0LO, lo);
325 1.43.2.2 jdolecek bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_ADDR0HI, hi);
326 1.43.2.2 jdolecek }
327 1.43.2.2 jdolecek
328 1.43.2.2 jdolecek static int
329 1.43.2.2 jdolecek dwc_gmac_miibus_read_reg(device_t self, int phy, int reg)
330 1.43.2.2 jdolecek {
331 1.43.2.2 jdolecek struct dwc_gmac_softc * const sc = device_private(self);
332 1.43.2.2 jdolecek uint16_t mii;
333 1.43.2.2 jdolecek size_t cnt;
334 1.43.2.2 jdolecek int rv = 0;
335 1.43.2.2 jdolecek
336 1.43.2.2 jdolecek mii = __SHIFTIN(phy,GMAC_MII_PHY_MASK)
337 1.43.2.2 jdolecek | __SHIFTIN(reg,GMAC_MII_REG_MASK)
338 1.43.2.2 jdolecek | __SHIFTIN(sc->sc_mii_clk,GMAC_MII_CLKMASK)
339 1.43.2.2 jdolecek | GMAC_MII_BUSY;
340 1.43.2.2 jdolecek
341 1.43.2.2 jdolecek mutex_enter(&sc->sc_mdio_lock);
342 1.43.2.2 jdolecek bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_MIIADDR, mii);
343 1.43.2.2 jdolecek
344 1.43.2.2 jdolecek for (cnt = 0; cnt < 1000; cnt++) {
345 1.43.2.2 jdolecek if (!(bus_space_read_4(sc->sc_bst, sc->sc_bsh,
346 1.43.2.2 jdolecek AWIN_GMAC_MAC_MIIADDR) & GMAC_MII_BUSY)) {
347 1.43.2.2 jdolecek rv = bus_space_read_4(sc->sc_bst, sc->sc_bsh,
348 1.43.2.2 jdolecek AWIN_GMAC_MAC_MIIDATA);
349 1.43.2.2 jdolecek break;
350 1.43.2.2 jdolecek }
351 1.43.2.2 jdolecek delay(10);
352 1.43.2.2 jdolecek }
353 1.43.2.2 jdolecek
354 1.43.2.2 jdolecek mutex_exit(&sc->sc_mdio_lock);
355 1.43.2.2 jdolecek
356 1.43.2.2 jdolecek return rv;
357 1.43.2.2 jdolecek }
358 1.43.2.2 jdolecek
359 1.43.2.2 jdolecek static void
360 1.43.2.2 jdolecek dwc_gmac_miibus_write_reg(device_t self, int phy, int reg, int val)
361 1.43.2.2 jdolecek {
362 1.43.2.2 jdolecek struct dwc_gmac_softc * const sc = device_private(self);
363 1.43.2.2 jdolecek uint16_t mii;
364 1.43.2.2 jdolecek size_t cnt;
365 1.43.2.2 jdolecek
366 1.43.2.2 jdolecek mii = __SHIFTIN(phy,GMAC_MII_PHY_MASK)
367 1.43.2.2 jdolecek | __SHIFTIN(reg,GMAC_MII_REG_MASK)
368 1.43.2.2 jdolecek | __SHIFTIN(sc->sc_mii_clk,GMAC_MII_CLKMASK)
369 1.43.2.2 jdolecek | GMAC_MII_BUSY | GMAC_MII_WRITE;
370 1.43.2.2 jdolecek
371 1.43.2.2 jdolecek mutex_enter(&sc->sc_mdio_lock);
372 1.43.2.2 jdolecek bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_MIIDATA, val);
373 1.43.2.2 jdolecek bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_MIIADDR, mii);
374 1.43.2.2 jdolecek
375 1.43.2.2 jdolecek for (cnt = 0; cnt < 1000; cnt++) {
376 1.43.2.2 jdolecek if (!(bus_space_read_4(sc->sc_bst, sc->sc_bsh,
377 1.43.2.2 jdolecek AWIN_GMAC_MAC_MIIADDR) & GMAC_MII_BUSY))
378 1.43.2.2 jdolecek break;
379 1.43.2.2 jdolecek delay(10);
380 1.43.2.2 jdolecek }
381 1.43.2.2 jdolecek
382 1.43.2.2 jdolecek mutex_exit(&sc->sc_mdio_lock);
383 1.43.2.2 jdolecek }
384 1.43.2.2 jdolecek
385 1.43.2.2 jdolecek static int
386 1.43.2.2 jdolecek dwc_gmac_alloc_rx_ring(struct dwc_gmac_softc *sc,
387 1.43.2.2 jdolecek struct dwc_gmac_rx_ring *ring)
388 1.43.2.2 jdolecek {
389 1.43.2.2 jdolecek struct dwc_gmac_rx_data *data;
390 1.43.2.2 jdolecek bus_addr_t physaddr;
391 1.43.2.2 jdolecek const size_t descsize = AWGE_RX_RING_COUNT * sizeof(*ring->r_desc);
392 1.43.2.2 jdolecek int error, i, next;
393 1.43.2.2 jdolecek
394 1.43.2.2 jdolecek ring->r_cur = ring->r_next = 0;
395 1.43.2.2 jdolecek memset(ring->r_desc, 0, descsize);
396 1.43.2.2 jdolecek
397 1.43.2.2 jdolecek /*
398 1.43.2.2 jdolecek * Pre-allocate Rx buffers and populate Rx ring.
399 1.43.2.2 jdolecek */
400 1.43.2.2 jdolecek for (i = 0; i < AWGE_RX_RING_COUNT; i++) {
401 1.43.2.2 jdolecek struct dwc_gmac_dev_dmadesc *desc;
402 1.43.2.2 jdolecek
403 1.43.2.2 jdolecek data = &sc->sc_rxq.r_data[i];
404 1.43.2.2 jdolecek
405 1.43.2.2 jdolecek MGETHDR(data->rd_m, M_DONTWAIT, MT_DATA);
406 1.43.2.2 jdolecek if (data->rd_m == NULL) {
407 1.43.2.2 jdolecek aprint_error_dev(sc->sc_dev,
408 1.43.2.2 jdolecek "could not allocate rx mbuf #%d\n", i);
409 1.43.2.2 jdolecek error = ENOMEM;
410 1.43.2.2 jdolecek goto fail;
411 1.43.2.2 jdolecek }
412 1.43.2.2 jdolecek error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1,
413 1.43.2.2 jdolecek MCLBYTES, 0, BUS_DMA_NOWAIT, &data->rd_map);
414 1.43.2.2 jdolecek if (error != 0) {
415 1.43.2.2 jdolecek aprint_error_dev(sc->sc_dev,
416 1.43.2.2 jdolecek "could not create DMA map\n");
417 1.43.2.2 jdolecek data->rd_map = NULL;
418 1.43.2.2 jdolecek goto fail;
419 1.43.2.2 jdolecek }
420 1.43.2.2 jdolecek MCLGET(data->rd_m, M_DONTWAIT);
421 1.43.2.2 jdolecek if (!(data->rd_m->m_flags & M_EXT)) {
422 1.43.2.2 jdolecek aprint_error_dev(sc->sc_dev,
423 1.43.2.2 jdolecek "could not allocate mbuf cluster #%d\n", i);
424 1.43.2.2 jdolecek error = ENOMEM;
425 1.43.2.2 jdolecek goto fail;
426 1.43.2.2 jdolecek }
427 1.43.2.2 jdolecek
428 1.43.2.2 jdolecek error = bus_dmamap_load(sc->sc_dmat, data->rd_map,
429 1.43.2.2 jdolecek mtod(data->rd_m, void *), MCLBYTES, NULL,
430 1.43.2.2 jdolecek BUS_DMA_READ | BUS_DMA_NOWAIT);
431 1.43.2.2 jdolecek if (error != 0) {
432 1.43.2.2 jdolecek aprint_error_dev(sc->sc_dev,
433 1.43.2.2 jdolecek "could not load rx buf DMA map #%d", i);
434 1.43.2.2 jdolecek goto fail;
435 1.43.2.2 jdolecek }
436 1.43.2.2 jdolecek physaddr = data->rd_map->dm_segs[0].ds_addr;
437 1.43.2.2 jdolecek
438 1.43.2.2 jdolecek desc = &sc->sc_rxq.r_desc[i];
439 1.43.2.2 jdolecek desc->ddesc_data = htole32(physaddr);
440 1.43.2.2 jdolecek next = RX_NEXT(i);
441 1.43.2.2 jdolecek desc->ddesc_next = htole32(ring->r_physaddr
442 1.43.2.2 jdolecek + next * sizeof(*desc));
443 1.43.2.2 jdolecek desc->ddesc_cntl = htole32(
444 1.43.2.2 jdolecek __SHIFTIN(AWGE_MAX_PACKET,DDESC_CNTL_SIZE1MASK) |
445 1.43.2.2 jdolecek DDESC_CNTL_RXCHAIN);
446 1.43.2.2 jdolecek desc->ddesc_status = htole32(DDESC_STATUS_OWNEDBYDEV);
447 1.43.2.2 jdolecek }
448 1.43.2.2 jdolecek
449 1.43.2.2 jdolecek bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map, 0,
450 1.43.2.2 jdolecek AWGE_RX_RING_COUNT*sizeof(struct dwc_gmac_dev_dmadesc),
451 1.43.2.2 jdolecek BUS_DMASYNC_PREWRITE|BUS_DMASYNC_PREREAD);
452 1.43.2.2 jdolecek bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_RX_ADDR,
453 1.43.2.2 jdolecek ring->r_physaddr);
454 1.43.2.2 jdolecek
455 1.43.2.2 jdolecek return 0;
456 1.43.2.2 jdolecek
457 1.43.2.2 jdolecek fail:
458 1.43.2.2 jdolecek dwc_gmac_free_rx_ring(sc, ring);
459 1.43.2.2 jdolecek return error;
460 1.43.2.2 jdolecek }
461 1.43.2.2 jdolecek
462 1.43.2.2 jdolecek static void
463 1.43.2.2 jdolecek dwc_gmac_reset_rx_ring(struct dwc_gmac_softc *sc,
464 1.43.2.2 jdolecek struct dwc_gmac_rx_ring *ring)
465 1.43.2.2 jdolecek {
466 1.43.2.2 jdolecek struct dwc_gmac_dev_dmadesc *desc;
467 1.43.2.2 jdolecek int i;
468 1.43.2.2 jdolecek
469 1.43.2.2 jdolecek mutex_enter(&ring->r_mtx);
470 1.43.2.2 jdolecek for (i = 0; i < AWGE_RX_RING_COUNT; i++) {
471 1.43.2.2 jdolecek desc = &sc->sc_rxq.r_desc[i];
472 1.43.2.2 jdolecek desc->ddesc_cntl = htole32(
473 1.43.2.2 jdolecek __SHIFTIN(AWGE_MAX_PACKET,DDESC_CNTL_SIZE1MASK) |
474 1.43.2.2 jdolecek DDESC_CNTL_RXCHAIN);
475 1.43.2.2 jdolecek desc->ddesc_status = htole32(DDESC_STATUS_OWNEDBYDEV);
476 1.43.2.2 jdolecek }
477 1.43.2.2 jdolecek
478 1.43.2.2 jdolecek bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map, 0,
479 1.43.2.2 jdolecek AWGE_RX_RING_COUNT*sizeof(struct dwc_gmac_dev_dmadesc),
480 1.43.2.2 jdolecek BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
481 1.43.2.2 jdolecek
482 1.43.2.2 jdolecek ring->r_cur = ring->r_next = 0;
483 1.43.2.2 jdolecek /* reset DMA address to start of ring */
484 1.43.2.2 jdolecek bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_RX_ADDR,
485 1.43.2.2 jdolecek sc->sc_rxq.r_physaddr);
486 1.43.2.2 jdolecek mutex_exit(&ring->r_mtx);
487 1.43.2.2 jdolecek }
488 1.43.2.2 jdolecek
489 1.43.2.2 jdolecek static int
490 1.43.2.2 jdolecek dwc_gmac_alloc_dma_rings(struct dwc_gmac_softc *sc)
491 1.43.2.2 jdolecek {
492 1.43.2.2 jdolecek const size_t descsize = AWGE_TOTAL_RING_COUNT *
493 1.43.2.2 jdolecek sizeof(struct dwc_gmac_dev_dmadesc);
494 1.43.2.2 jdolecek int error, nsegs;
495 1.43.2.2 jdolecek void *rings;
496 1.43.2.2 jdolecek
497 1.43.2.2 jdolecek error = bus_dmamap_create(sc->sc_dmat, descsize, 1, descsize, 0,
498 1.43.2.2 jdolecek BUS_DMA_NOWAIT, &sc->sc_dma_ring_map);
499 1.43.2.2 jdolecek if (error != 0) {
500 1.43.2.2 jdolecek aprint_error_dev(sc->sc_dev,
501 1.43.2.2 jdolecek "could not create desc DMA map\n");
502 1.43.2.2 jdolecek sc->sc_dma_ring_map = NULL;
503 1.43.2.2 jdolecek goto fail;
504 1.43.2.2 jdolecek }
505 1.43.2.2 jdolecek
506 1.43.2.2 jdolecek error = bus_dmamem_alloc(sc->sc_dmat, descsize, PAGE_SIZE, 0,
507 1.43.2.2 jdolecek &sc->sc_dma_ring_seg, 1, &nsegs, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
508 1.43.2.2 jdolecek if (error != 0) {
509 1.43.2.2 jdolecek aprint_error_dev(sc->sc_dev,
510 1.43.2.2 jdolecek "could not map DMA memory\n");
511 1.43.2.2 jdolecek goto fail;
512 1.43.2.2 jdolecek }
513 1.43.2.2 jdolecek
514 1.43.2.2 jdolecek error = bus_dmamem_map(sc->sc_dmat, &sc->sc_dma_ring_seg, nsegs,
515 1.43.2.2 jdolecek descsize, &rings, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
516 1.43.2.2 jdolecek if (error != 0) {
517 1.43.2.2 jdolecek aprint_error_dev(sc->sc_dev,
518 1.43.2.2 jdolecek "could not allocate DMA memory\n");
519 1.43.2.2 jdolecek goto fail;
520 1.43.2.2 jdolecek }
521 1.43.2.2 jdolecek
522 1.43.2.2 jdolecek error = bus_dmamap_load(sc->sc_dmat, sc->sc_dma_ring_map, rings,
523 1.43.2.2 jdolecek descsize, NULL, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
524 1.43.2.2 jdolecek if (error != 0) {
525 1.43.2.2 jdolecek aprint_error_dev(sc->sc_dev,
526 1.43.2.2 jdolecek "could not load desc DMA map\n");
527 1.43.2.2 jdolecek goto fail;
528 1.43.2.2 jdolecek }
529 1.43.2.2 jdolecek
530 1.43.2.2 jdolecek /* give first AWGE_RX_RING_COUNT to the RX side */
531 1.43.2.2 jdolecek sc->sc_rxq.r_desc = rings;
532 1.43.2.2 jdolecek sc->sc_rxq.r_physaddr = sc->sc_dma_ring_map->dm_segs[0].ds_addr;
533 1.43.2.2 jdolecek
534 1.43.2.2 jdolecek /* and next rings to the TX side */
535 1.43.2.2 jdolecek sc->sc_txq.t_desc = sc->sc_rxq.r_desc + AWGE_RX_RING_COUNT;
536 1.43.2.2 jdolecek sc->sc_txq.t_physaddr = sc->sc_rxq.r_physaddr +
537 1.43.2.2 jdolecek AWGE_RX_RING_COUNT*sizeof(struct dwc_gmac_dev_dmadesc);
538 1.43.2.2 jdolecek
539 1.43.2.2 jdolecek return 0;
540 1.43.2.2 jdolecek
541 1.43.2.2 jdolecek fail:
542 1.43.2.2 jdolecek dwc_gmac_free_dma_rings(sc);
543 1.43.2.2 jdolecek return error;
544 1.43.2.2 jdolecek }
545 1.43.2.2 jdolecek
546 1.43.2.2 jdolecek static void
547 1.43.2.2 jdolecek dwc_gmac_free_dma_rings(struct dwc_gmac_softc *sc)
548 1.43.2.2 jdolecek {
549 1.43.2.2 jdolecek bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map, 0,
550 1.43.2.2 jdolecek sc->sc_dma_ring_map->dm_mapsize, BUS_DMASYNC_POSTWRITE);
551 1.43.2.2 jdolecek bus_dmamap_unload(sc->sc_dmat, sc->sc_dma_ring_map);
552 1.43.2.2 jdolecek bus_dmamem_unmap(sc->sc_dmat, sc->sc_rxq.r_desc,
553 1.43.2.2 jdolecek AWGE_TOTAL_RING_COUNT * sizeof(struct dwc_gmac_dev_dmadesc));
554 1.43.2.2 jdolecek bus_dmamem_free(sc->sc_dmat, &sc->sc_dma_ring_seg, 1);
555 1.43.2.2 jdolecek }
556 1.43.2.2 jdolecek
557 1.43.2.2 jdolecek static void
558 1.43.2.2 jdolecek dwc_gmac_free_rx_ring(struct dwc_gmac_softc *sc, struct dwc_gmac_rx_ring *ring)
559 1.43.2.2 jdolecek {
560 1.43.2.2 jdolecek struct dwc_gmac_rx_data *data;
561 1.43.2.2 jdolecek int i;
562 1.43.2.2 jdolecek
563 1.43.2.2 jdolecek if (ring->r_desc == NULL)
564 1.43.2.2 jdolecek return;
565 1.43.2.2 jdolecek
566 1.43.2.2 jdolecek
567 1.43.2.2 jdolecek for (i = 0; i < AWGE_RX_RING_COUNT; i++) {
568 1.43.2.2 jdolecek data = &ring->r_data[i];
569 1.43.2.2 jdolecek
570 1.43.2.2 jdolecek if (data->rd_map != NULL) {
571 1.43.2.2 jdolecek bus_dmamap_sync(sc->sc_dmat, data->rd_map, 0,
572 1.43.2.2 jdolecek AWGE_RX_RING_COUNT
573 1.43.2.2 jdolecek *sizeof(struct dwc_gmac_dev_dmadesc),
574 1.43.2.2 jdolecek BUS_DMASYNC_POSTREAD);
575 1.43.2.2 jdolecek bus_dmamap_unload(sc->sc_dmat, data->rd_map);
576 1.43.2.2 jdolecek bus_dmamap_destroy(sc->sc_dmat, data->rd_map);
577 1.43.2.2 jdolecek }
578 1.43.2.2 jdolecek if (data->rd_m != NULL)
579 1.43.2.2 jdolecek m_freem(data->rd_m);
580 1.43.2.2 jdolecek }
581 1.43.2.2 jdolecek }
582 1.43.2.2 jdolecek
583 1.43.2.2 jdolecek static int
584 1.43.2.2 jdolecek dwc_gmac_alloc_tx_ring(struct dwc_gmac_softc *sc,
585 1.43.2.2 jdolecek struct dwc_gmac_tx_ring *ring)
586 1.43.2.2 jdolecek {
587 1.43.2.2 jdolecek int i, error = 0;
588 1.43.2.2 jdolecek
589 1.43.2.2 jdolecek ring->t_queued = 0;
590 1.43.2.2 jdolecek ring->t_cur = ring->t_next = 0;
591 1.43.2.2 jdolecek
592 1.43.2.2 jdolecek memset(ring->t_desc, 0, AWGE_TX_RING_COUNT*sizeof(*ring->t_desc));
593 1.43.2.2 jdolecek bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map,
594 1.43.2.2 jdolecek TX_DESC_OFFSET(0),
595 1.43.2.2 jdolecek AWGE_TX_RING_COUNT*sizeof(struct dwc_gmac_dev_dmadesc),
596 1.43.2.2 jdolecek BUS_DMASYNC_POSTWRITE);
597 1.43.2.2 jdolecek
598 1.43.2.2 jdolecek for (i = 0; i < AWGE_TX_RING_COUNT; i++) {
599 1.43.2.2 jdolecek error = bus_dmamap_create(sc->sc_dmat, MCLBYTES,
600 1.43.2.2 jdolecek AWGE_TX_RING_COUNT, MCLBYTES, 0,
601 1.43.2.2 jdolecek BUS_DMA_NOWAIT|BUS_DMA_COHERENT,
602 1.43.2.2 jdolecek &ring->t_data[i].td_map);
603 1.43.2.2 jdolecek if (error != 0) {
604 1.43.2.2 jdolecek aprint_error_dev(sc->sc_dev,
605 1.43.2.2 jdolecek "could not create TX DMA map #%d\n", i);
606 1.43.2.2 jdolecek ring->t_data[i].td_map = NULL;
607 1.43.2.2 jdolecek goto fail;
608 1.43.2.2 jdolecek }
609 1.43.2.2 jdolecek ring->t_desc[i].ddesc_next = htole32(
610 1.43.2.2 jdolecek ring->t_physaddr + sizeof(struct dwc_gmac_dev_dmadesc)
611 1.43.2.2 jdolecek *TX_NEXT(i));
612 1.43.2.2 jdolecek }
613 1.43.2.2 jdolecek
614 1.43.2.2 jdolecek return 0;
615 1.43.2.2 jdolecek
616 1.43.2.2 jdolecek fail:
617 1.43.2.2 jdolecek dwc_gmac_free_tx_ring(sc, ring);
618 1.43.2.2 jdolecek return error;
619 1.43.2.2 jdolecek }
620 1.43.2.2 jdolecek
621 1.43.2.2 jdolecek static void
622 1.43.2.2 jdolecek dwc_gmac_txdesc_sync(struct dwc_gmac_softc *sc, int start, int end, int ops)
623 1.43.2.2 jdolecek {
624 1.43.2.2 jdolecek /* 'end' is pointing one descriptor beyound the last we want to sync */
625 1.43.2.2 jdolecek if (end > start) {
626 1.43.2.2 jdolecek bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map,
627 1.43.2.2 jdolecek TX_DESC_OFFSET(start),
628 1.43.2.2 jdolecek TX_DESC_OFFSET(end)-TX_DESC_OFFSET(start),
629 1.43.2.2 jdolecek ops);
630 1.43.2.2 jdolecek return;
631 1.43.2.2 jdolecek }
632 1.43.2.2 jdolecek /* sync from 'start' to end of ring */
633 1.43.2.2 jdolecek bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map,
634 1.43.2.2 jdolecek TX_DESC_OFFSET(start),
635 1.43.2.2 jdolecek TX_DESC_OFFSET(AWGE_TX_RING_COUNT)-TX_DESC_OFFSET(start),
636 1.43.2.2 jdolecek ops);
637 1.43.2.2 jdolecek /* sync from start of ring to 'end' */
638 1.43.2.2 jdolecek bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map,
639 1.43.2.2 jdolecek TX_DESC_OFFSET(0),
640 1.43.2.2 jdolecek TX_DESC_OFFSET(end)-TX_DESC_OFFSET(0),
641 1.43.2.2 jdolecek ops);
642 1.43.2.2 jdolecek }
643 1.43.2.2 jdolecek
644 1.43.2.2 jdolecek static void
645 1.43.2.2 jdolecek dwc_gmac_reset_tx_ring(struct dwc_gmac_softc *sc,
646 1.43.2.2 jdolecek struct dwc_gmac_tx_ring *ring)
647 1.43.2.2 jdolecek {
648 1.43.2.2 jdolecek int i;
649 1.43.2.2 jdolecek
650 1.43.2.2 jdolecek mutex_enter(&ring->t_mtx);
651 1.43.2.2 jdolecek for (i = 0; i < AWGE_TX_RING_COUNT; i++) {
652 1.43.2.2 jdolecek struct dwc_gmac_tx_data *data = &ring->t_data[i];
653 1.43.2.2 jdolecek
654 1.43.2.2 jdolecek if (data->td_m != NULL) {
655 1.43.2.2 jdolecek bus_dmamap_sync(sc->sc_dmat, data->td_active,
656 1.43.2.2 jdolecek 0, data->td_active->dm_mapsize,
657 1.43.2.2 jdolecek BUS_DMASYNC_POSTWRITE);
658 1.43.2.2 jdolecek bus_dmamap_unload(sc->sc_dmat, data->td_active);
659 1.43.2.2 jdolecek m_freem(data->td_m);
660 1.43.2.2 jdolecek data->td_m = NULL;
661 1.43.2.2 jdolecek }
662 1.43.2.2 jdolecek }
663 1.43.2.2 jdolecek
664 1.43.2.2 jdolecek bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map,
665 1.43.2.2 jdolecek TX_DESC_OFFSET(0),
666 1.43.2.2 jdolecek AWGE_TX_RING_COUNT*sizeof(struct dwc_gmac_dev_dmadesc),
667 1.43.2.2 jdolecek BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
668 1.43.2.2 jdolecek bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_TX_ADDR,
669 1.43.2.2 jdolecek sc->sc_txq.t_physaddr);
670 1.43.2.2 jdolecek
671 1.43.2.2 jdolecek ring->t_queued = 0;
672 1.43.2.2 jdolecek ring->t_cur = ring->t_next = 0;
673 1.43.2.2 jdolecek mutex_exit(&ring->t_mtx);
674 1.43.2.2 jdolecek }
675 1.43.2.2 jdolecek
676 1.43.2.2 jdolecek static void
677 1.43.2.2 jdolecek dwc_gmac_free_tx_ring(struct dwc_gmac_softc *sc,
678 1.43.2.2 jdolecek struct dwc_gmac_tx_ring *ring)
679 1.43.2.2 jdolecek {
680 1.43.2.2 jdolecek int i;
681 1.43.2.2 jdolecek
682 1.43.2.2 jdolecek /* unload the maps */
683 1.43.2.2 jdolecek for (i = 0; i < AWGE_TX_RING_COUNT; i++) {
684 1.43.2.2 jdolecek struct dwc_gmac_tx_data *data = &ring->t_data[i];
685 1.43.2.2 jdolecek
686 1.43.2.2 jdolecek if (data->td_m != NULL) {
687 1.43.2.2 jdolecek bus_dmamap_sync(sc->sc_dmat, data->td_active,
688 1.43.2.2 jdolecek 0, data->td_map->dm_mapsize,
689 1.43.2.2 jdolecek BUS_DMASYNC_POSTWRITE);
690 1.43.2.2 jdolecek bus_dmamap_unload(sc->sc_dmat, data->td_active);
691 1.43.2.2 jdolecek m_freem(data->td_m);
692 1.43.2.2 jdolecek data->td_m = NULL;
693 1.43.2.2 jdolecek }
694 1.43.2.2 jdolecek }
695 1.43.2.2 jdolecek
696 1.43.2.2 jdolecek /* and actually free them */
697 1.43.2.2 jdolecek for (i = 0; i < AWGE_TX_RING_COUNT; i++) {
698 1.43.2.2 jdolecek struct dwc_gmac_tx_data *data = &ring->t_data[i];
699 1.43.2.2 jdolecek
700 1.43.2.2 jdolecek bus_dmamap_destroy(sc->sc_dmat, data->td_map);
701 1.43.2.2 jdolecek }
702 1.43.2.2 jdolecek }
703 1.43.2.2 jdolecek
704 1.43.2.2 jdolecek static void
705 1.43.2.2 jdolecek dwc_gmac_miibus_statchg(struct ifnet *ifp)
706 1.43.2.2 jdolecek {
707 1.43.2.2 jdolecek struct dwc_gmac_softc * const sc = ifp->if_softc;
708 1.43.2.2 jdolecek struct mii_data * const mii = &sc->sc_mii;
709 1.43.2.2 jdolecek uint32_t conf, flow;
710 1.43.2.2 jdolecek
711 1.43.2.2 jdolecek /*
712 1.43.2.2 jdolecek * Set MII or GMII interface based on the speed
713 1.43.2.2 jdolecek * negotiated by the PHY.
714 1.43.2.2 jdolecek */
715 1.43.2.2 jdolecek conf = bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_CONF);
716 1.43.2.2 jdolecek conf &= ~(AWIN_GMAC_MAC_CONF_FES100|AWIN_GMAC_MAC_CONF_MIISEL
717 1.43.2.2 jdolecek |AWIN_GMAC_MAC_CONF_FULLDPLX);
718 1.43.2.2 jdolecek conf |= AWIN_GMAC_MAC_CONF_FRAMEBURST
719 1.43.2.2 jdolecek | AWIN_GMAC_MAC_CONF_DISABLERXOWN
720 1.43.2.2 jdolecek | AWIN_GMAC_MAC_CONF_DISABLEJABBER
721 1.43.2.2 jdolecek | AWIN_GMAC_MAC_CONF_ACS
722 1.43.2.2 jdolecek | AWIN_GMAC_MAC_CONF_RXENABLE
723 1.43.2.2 jdolecek | AWIN_GMAC_MAC_CONF_TXENABLE;
724 1.43.2.2 jdolecek switch (IFM_SUBTYPE(mii->mii_media_active)) {
725 1.43.2.2 jdolecek case IFM_10_T:
726 1.43.2.2 jdolecek conf |= AWIN_GMAC_MAC_CONF_MIISEL;
727 1.43.2.2 jdolecek break;
728 1.43.2.2 jdolecek case IFM_100_TX:
729 1.43.2.2 jdolecek conf |= AWIN_GMAC_MAC_CONF_FES100 |
730 1.43.2.2 jdolecek AWIN_GMAC_MAC_CONF_MIISEL;
731 1.43.2.2 jdolecek break;
732 1.43.2.2 jdolecek case IFM_1000_T:
733 1.43.2.2 jdolecek break;
734 1.43.2.2 jdolecek }
735 1.43.2.2 jdolecek
736 1.43.2.2 jdolecek flow = 0;
737 1.43.2.2 jdolecek if (IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) {
738 1.43.2.2 jdolecek conf |= AWIN_GMAC_MAC_CONF_FULLDPLX;
739 1.43.2.2 jdolecek flow |= __SHIFTIN(0x200, AWIN_GMAC_MAC_FLOWCTRL_PAUSE);
740 1.43.2.2 jdolecek }
741 1.43.2.2 jdolecek if (mii->mii_media_active & IFM_ETH_TXPAUSE) {
742 1.43.2.2 jdolecek flow |= AWIN_GMAC_MAC_FLOWCTRL_TFE;
743 1.43.2.2 jdolecek }
744 1.43.2.2 jdolecek if (mii->mii_media_active & IFM_ETH_RXPAUSE) {
745 1.43.2.2 jdolecek flow |= AWIN_GMAC_MAC_FLOWCTRL_RFE;
746 1.43.2.2 jdolecek }
747 1.43.2.2 jdolecek bus_space_write_4(sc->sc_bst, sc->sc_bsh,
748 1.43.2.2 jdolecek AWIN_GMAC_MAC_FLOWCTRL, flow);
749 1.43.2.2 jdolecek
750 1.43.2.2 jdolecek #ifdef DWC_GMAC_DEBUG
751 1.43.2.2 jdolecek aprint_normal_dev(sc->sc_dev,
752 1.43.2.2 jdolecek "setting MAC conf register: %08x\n", conf);
753 1.43.2.2 jdolecek #endif
754 1.43.2.2 jdolecek
755 1.43.2.2 jdolecek bus_space_write_4(sc->sc_bst, sc->sc_bsh,
756 1.43.2.2 jdolecek AWIN_GMAC_MAC_CONF, conf);
757 1.43.2.2 jdolecek }
758 1.43.2.2 jdolecek
759 1.43.2.2 jdolecek static int
760 1.43.2.2 jdolecek dwc_gmac_init(struct ifnet *ifp)
761 1.43.2.2 jdolecek {
762 1.43.2.2 jdolecek struct dwc_gmac_softc *sc = ifp->if_softc;
763 1.43.2.2 jdolecek
764 1.43.2.2 jdolecek mutex_enter(sc->sc_lock);
765 1.43.2.2 jdolecek int ret = dwc_gmac_init_locked(ifp);
766 1.43.2.2 jdolecek mutex_exit(sc->sc_lock);
767 1.43.2.2 jdolecek
768 1.43.2.2 jdolecek return ret;
769 1.43.2.2 jdolecek }
770 1.43.2.2 jdolecek
771 1.43.2.2 jdolecek static int
772 1.43.2.2 jdolecek dwc_gmac_init_locked(struct ifnet *ifp)
773 1.43.2.2 jdolecek {
774 1.43.2.2 jdolecek struct dwc_gmac_softc *sc = ifp->if_softc;
775 1.43.2.2 jdolecek uint32_t ffilt;
776 1.43.2.2 jdolecek
777 1.43.2.2 jdolecek if (ifp->if_flags & IFF_RUNNING)
778 1.43.2.2 jdolecek return 0;
779 1.43.2.2 jdolecek
780 1.43.2.2 jdolecek dwc_gmac_stop_locked(ifp, 0);
781 1.43.2.2 jdolecek
782 1.43.2.2 jdolecek /*
783 1.43.2.2 jdolecek * Configure DMA burst/transfer mode and RX/TX priorities.
784 1.43.2.2 jdolecek * XXX - the GMAC_BUSMODE_PRIORXTX bits are undocumented.
785 1.43.2.2 jdolecek */
786 1.43.2.2 jdolecek bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_BUSMODE,
787 1.43.2.2 jdolecek GMAC_BUSMODE_FIXEDBURST | GMAC_BUSMODE_4PBL |
788 1.43.2.2 jdolecek __SHIFTIN(2, GMAC_BUSMODE_RPBL) |
789 1.43.2.2 jdolecek __SHIFTIN(2, GMAC_BUSMODE_PBL));
790 1.43.2.2 jdolecek
791 1.43.2.2 jdolecek /*
792 1.43.2.2 jdolecek * Set up address filter
793 1.43.2.2 jdolecek */
794 1.43.2.2 jdolecek ffilt = bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_FFILT);
795 1.43.2.2 jdolecek if (ifp->if_flags & IFF_PROMISC) {
796 1.43.2.2 jdolecek ffilt |= AWIN_GMAC_MAC_FFILT_PR;
797 1.43.2.2 jdolecek } else {
798 1.43.2.2 jdolecek ffilt &= ~AWIN_GMAC_MAC_FFILT_PR;
799 1.43.2.2 jdolecek }
800 1.43.2.2 jdolecek if (ifp->if_flags & IFF_BROADCAST) {
801 1.43.2.2 jdolecek ffilt &= ~AWIN_GMAC_MAC_FFILT_DBF;
802 1.43.2.2 jdolecek } else {
803 1.43.2.2 jdolecek ffilt |= AWIN_GMAC_MAC_FFILT_DBF;
804 1.43.2.2 jdolecek }
805 1.43.2.2 jdolecek bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_FFILT, ffilt);
806 1.43.2.2 jdolecek
807 1.43.2.2 jdolecek /*
808 1.43.2.2 jdolecek * Set up multicast filter
809 1.43.2.2 jdolecek */
810 1.43.2.2 jdolecek dwc_gmac_setmulti(sc);
811 1.43.2.2 jdolecek
812 1.43.2.2 jdolecek /*
813 1.43.2.2 jdolecek * Set up dma pointer for RX and TX ring
814 1.43.2.2 jdolecek */
815 1.43.2.2 jdolecek bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_RX_ADDR,
816 1.43.2.2 jdolecek sc->sc_rxq.r_physaddr);
817 1.43.2.2 jdolecek bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_TX_ADDR,
818 1.43.2.2 jdolecek sc->sc_txq.t_physaddr);
819 1.43.2.2 jdolecek
820 1.43.2.2 jdolecek /*
821 1.43.2.2 jdolecek * Start RX/TX part
822 1.43.2.2 jdolecek */
823 1.43.2.2 jdolecek bus_space_write_4(sc->sc_bst, sc->sc_bsh,
824 1.43.2.2 jdolecek AWIN_GMAC_DMA_OPMODE, GMAC_DMA_OP_RXSTART | GMAC_DMA_OP_TXSTART |
825 1.43.2.2 jdolecek GMAC_DMA_OP_RXSTOREFORWARD | GMAC_DMA_OP_TXSTOREFORWARD);
826 1.43.2.2 jdolecek
827 1.43.2.2 jdolecek sc->sc_stopping = false;
828 1.43.2.2 jdolecek
829 1.43.2.2 jdolecek ifp->if_flags |= IFF_RUNNING;
830 1.43.2.2 jdolecek ifp->if_flags &= ~IFF_OACTIVE;
831 1.43.2.2 jdolecek
832 1.43.2.2 jdolecek return 0;
833 1.43.2.2 jdolecek }
834 1.43.2.2 jdolecek
835 1.43.2.2 jdolecek static void
836 1.43.2.2 jdolecek dwc_gmac_start(struct ifnet *ifp)
837 1.43.2.2 jdolecek {
838 1.43.2.2 jdolecek struct dwc_gmac_softc *sc = ifp->if_softc;
839 1.43.2.2 jdolecek KASSERT(if_is_mpsafe(ifp));
840 1.43.2.2 jdolecek
841 1.43.2.2 jdolecek mutex_enter(sc->sc_lock);
842 1.43.2.2 jdolecek if (!sc->sc_stopping) {
843 1.43.2.2 jdolecek mutex_enter(&sc->sc_txq.t_mtx);
844 1.43.2.2 jdolecek dwc_gmac_start_locked(ifp);
845 1.43.2.2 jdolecek mutex_exit(&sc->sc_txq.t_mtx);
846 1.43.2.2 jdolecek }
847 1.43.2.2 jdolecek mutex_exit(sc->sc_lock);
848 1.43.2.2 jdolecek }
849 1.43.2.2 jdolecek
850 1.43.2.2 jdolecek static void
851 1.43.2.2 jdolecek dwc_gmac_start_locked(struct ifnet *ifp)
852 1.43.2.2 jdolecek {
853 1.43.2.2 jdolecek struct dwc_gmac_softc *sc = ifp->if_softc;
854 1.43.2.2 jdolecek int old = sc->sc_txq.t_queued;
855 1.43.2.2 jdolecek int start = sc->sc_txq.t_cur;
856 1.43.2.2 jdolecek struct mbuf *m0;
857 1.43.2.2 jdolecek
858 1.43.2.2 jdolecek if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
859 1.43.2.2 jdolecek return;
860 1.43.2.2 jdolecek
861 1.43.2.2 jdolecek for (;;) {
862 1.43.2.2 jdolecek IFQ_POLL(&ifp->if_snd, m0);
863 1.43.2.2 jdolecek if (m0 == NULL)
864 1.43.2.2 jdolecek break;
865 1.43.2.2 jdolecek if (dwc_gmac_queue(sc, m0) != 0) {
866 1.43.2.2 jdolecek ifp->if_flags |= IFF_OACTIVE;
867 1.43.2.2 jdolecek break;
868 1.43.2.2 jdolecek }
869 1.43.2.2 jdolecek IFQ_DEQUEUE(&ifp->if_snd, m0);
870 1.43.2.2 jdolecek bpf_mtap(ifp, m0);
871 1.43.2.2 jdolecek if (sc->sc_txq.t_queued == AWGE_TX_RING_COUNT) {
872 1.43.2.2 jdolecek ifp->if_flags |= IFF_OACTIVE;
873 1.43.2.2 jdolecek break;
874 1.43.2.2 jdolecek }
875 1.43.2.2 jdolecek }
876 1.43.2.2 jdolecek
877 1.43.2.2 jdolecek if (sc->sc_txq.t_queued != old) {
878 1.43.2.2 jdolecek /* packets have been queued, kick it off */
879 1.43.2.2 jdolecek dwc_gmac_txdesc_sync(sc, start, sc->sc_txq.t_cur,
880 1.43.2.2 jdolecek BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
881 1.43.2.2 jdolecek
882 1.43.2.2 jdolecek bus_space_write_4(sc->sc_bst, sc->sc_bsh,
883 1.43.2.2 jdolecek AWIN_GMAC_DMA_TXPOLL, ~0U);
884 1.43.2.2 jdolecek #ifdef DWC_GMAC_DEBUG
885 1.43.2.2 jdolecek dwc_dump_status(sc);
886 1.43.2.2 jdolecek #endif
887 1.43.2.2 jdolecek }
888 1.43.2.2 jdolecek }
889 1.43.2.2 jdolecek
890 1.43.2.2 jdolecek static void
891 1.43.2.2 jdolecek dwc_gmac_stop(struct ifnet *ifp, int disable)
892 1.43.2.2 jdolecek {
893 1.43.2.2 jdolecek struct dwc_gmac_softc *sc = ifp->if_softc;
894 1.43.2.2 jdolecek
895 1.43.2.2 jdolecek mutex_enter(sc->sc_lock);
896 1.43.2.2 jdolecek dwc_gmac_stop_locked(ifp, disable);
897 1.43.2.2 jdolecek mutex_exit(sc->sc_lock);
898 1.43.2.2 jdolecek }
899 1.43.2.2 jdolecek
900 1.43.2.2 jdolecek static void
901 1.43.2.2 jdolecek dwc_gmac_stop_locked(struct ifnet *ifp, int disable)
902 1.43.2.2 jdolecek {
903 1.43.2.2 jdolecek struct dwc_gmac_softc *sc = ifp->if_softc;
904 1.43.2.2 jdolecek
905 1.43.2.2 jdolecek sc->sc_stopping = true;
906 1.43.2.2 jdolecek
907 1.43.2.2 jdolecek bus_space_write_4(sc->sc_bst, sc->sc_bsh,
908 1.43.2.2 jdolecek AWIN_GMAC_DMA_OPMODE,
909 1.43.2.2 jdolecek bus_space_read_4(sc->sc_bst, sc->sc_bsh,
910 1.43.2.2 jdolecek AWIN_GMAC_DMA_OPMODE)
911 1.43.2.2 jdolecek & ~(GMAC_DMA_OP_TXSTART|GMAC_DMA_OP_RXSTART));
912 1.43.2.2 jdolecek bus_space_write_4(sc->sc_bst, sc->sc_bsh,
913 1.43.2.2 jdolecek AWIN_GMAC_DMA_OPMODE,
914 1.43.2.2 jdolecek bus_space_read_4(sc->sc_bst, sc->sc_bsh,
915 1.43.2.2 jdolecek AWIN_GMAC_DMA_OPMODE) | GMAC_DMA_OP_FLUSHTX);
916 1.43.2.2 jdolecek
917 1.43.2.2 jdolecek mii_down(&sc->sc_mii);
918 1.43.2.2 jdolecek dwc_gmac_reset_tx_ring(sc, &sc->sc_txq);
919 1.43.2.2 jdolecek dwc_gmac_reset_rx_ring(sc, &sc->sc_rxq);
920 1.43.2.2 jdolecek }
921 1.43.2.2 jdolecek
922 1.43.2.2 jdolecek /*
923 1.43.2.2 jdolecek * Add m0 to the TX ring
924 1.43.2.2 jdolecek */
925 1.43.2.2 jdolecek static int
926 1.43.2.2 jdolecek dwc_gmac_queue(struct dwc_gmac_softc *sc, struct mbuf *m0)
927 1.43.2.2 jdolecek {
928 1.43.2.2 jdolecek struct dwc_gmac_dev_dmadesc *desc = NULL;
929 1.43.2.2 jdolecek struct dwc_gmac_tx_data *data = NULL;
930 1.43.2.2 jdolecek bus_dmamap_t map;
931 1.43.2.2 jdolecek uint32_t flags, len, status;
932 1.43.2.2 jdolecek int error, i, first;
933 1.43.2.2 jdolecek
934 1.43.2.2 jdolecek #ifdef DWC_GMAC_DEBUG
935 1.43.2.2 jdolecek aprint_normal_dev(sc->sc_dev,
936 1.43.2.2 jdolecek "dwc_gmac_queue: adding mbuf chain %p\n", m0);
937 1.43.2.2 jdolecek #endif
938 1.43.2.2 jdolecek
939 1.43.2.2 jdolecek first = sc->sc_txq.t_cur;
940 1.43.2.2 jdolecek map = sc->sc_txq.t_data[first].td_map;
941 1.43.2.2 jdolecek
942 1.43.2.2 jdolecek error = bus_dmamap_load_mbuf(sc->sc_dmat, map, m0,
943 1.43.2.2 jdolecek BUS_DMA_WRITE|BUS_DMA_NOWAIT);
944 1.43.2.2 jdolecek if (error != 0) {
945 1.43.2.2 jdolecek aprint_error_dev(sc->sc_dev, "could not map mbuf "
946 1.43.2.2 jdolecek "(len: %d, error %d)\n", m0->m_pkthdr.len, error);
947 1.43.2.2 jdolecek return error;
948 1.43.2.2 jdolecek }
949 1.43.2.2 jdolecek
950 1.43.2.2 jdolecek if (sc->sc_txq.t_queued + map->dm_nsegs > AWGE_TX_RING_COUNT) {
951 1.43.2.2 jdolecek bus_dmamap_unload(sc->sc_dmat, map);
952 1.43.2.2 jdolecek return ENOBUFS;
953 1.43.2.2 jdolecek }
954 1.43.2.2 jdolecek
955 1.43.2.2 jdolecek flags = DDESC_CNTL_TXFIRST|DDESC_CNTL_TXCHAIN;
956 1.43.2.2 jdolecek status = 0;
957 1.43.2.2 jdolecek for (i = 0; i < map->dm_nsegs; i++) {
958 1.43.2.2 jdolecek data = &sc->sc_txq.t_data[sc->sc_txq.t_cur];
959 1.43.2.2 jdolecek desc = &sc->sc_txq.t_desc[sc->sc_txq.t_cur];
960 1.43.2.2 jdolecek
961 1.43.2.2 jdolecek desc->ddesc_data = htole32(map->dm_segs[i].ds_addr);
962 1.43.2.2 jdolecek len = __SHIFTIN(map->dm_segs[i].ds_len, DDESC_CNTL_SIZE1MASK);
963 1.43.2.2 jdolecek
964 1.43.2.2 jdolecek #ifdef DWC_GMAC_DEBUG
965 1.43.2.2 jdolecek aprint_normal_dev(sc->sc_dev, "enqueing desc #%d data %08lx "
966 1.43.2.2 jdolecek "len %lu (flags: %08x, len: %08x)\n", sc->sc_txq.t_cur,
967 1.43.2.2 jdolecek (unsigned long)map->dm_segs[i].ds_addr,
968 1.43.2.2 jdolecek (unsigned long)map->dm_segs[i].ds_len,
969 1.43.2.2 jdolecek flags, len);
970 1.43.2.2 jdolecek #endif
971 1.43.2.2 jdolecek
972 1.43.2.2 jdolecek desc->ddesc_cntl = htole32(len|flags);
973 1.43.2.2 jdolecek flags &= ~DDESC_CNTL_TXFIRST;
974 1.43.2.2 jdolecek
975 1.43.2.2 jdolecek /*
976 1.43.2.2 jdolecek * Defer passing ownership of the first descriptor
977 1.43.2.2 jdolecek * until we are done.
978 1.43.2.2 jdolecek */
979 1.43.2.2 jdolecek desc->ddesc_status = htole32(status);
980 1.43.2.2 jdolecek status |= DDESC_STATUS_OWNEDBYDEV;
981 1.43.2.2 jdolecek
982 1.43.2.2 jdolecek sc->sc_txq.t_queued++;
983 1.43.2.2 jdolecek sc->sc_txq.t_cur = TX_NEXT(sc->sc_txq.t_cur);
984 1.43.2.2 jdolecek }
985 1.43.2.2 jdolecek
986 1.43.2.2 jdolecek desc->ddesc_cntl |= htole32(DDESC_CNTL_TXLAST|DDESC_CNTL_TXINT);
987 1.43.2.2 jdolecek
988 1.43.2.2 jdolecek data->td_m = m0;
989 1.43.2.2 jdolecek data->td_active = map;
990 1.43.2.2 jdolecek
991 1.43.2.2 jdolecek bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
992 1.43.2.2 jdolecek BUS_DMASYNC_PREWRITE);
993 1.43.2.2 jdolecek
994 1.43.2.2 jdolecek /* Pass first to device */
995 1.43.2.2 jdolecek sc->sc_txq.t_desc[first].ddesc_status =
996 1.43.2.2 jdolecek htole32(DDESC_STATUS_OWNEDBYDEV);
997 1.43.2.2 jdolecek
998 1.43.2.2 jdolecek return 0;
999 1.43.2.2 jdolecek }
1000 1.43.2.2 jdolecek
1001 1.43.2.2 jdolecek /*
1002 1.43.2.2 jdolecek * If the interface is up and running, only modify the receive
1003 1.43.2.2 jdolecek * filter when setting promiscuous or debug mode. Otherwise fall
1004 1.43.2.2 jdolecek * through to ether_ioctl, which will reset the chip.
1005 1.43.2.2 jdolecek */
1006 1.43.2.2 jdolecek static int
1007 1.43.2.2 jdolecek dwc_gmac_ifflags_cb(struct ethercom *ec)
1008 1.43.2.2 jdolecek {
1009 1.43.2.2 jdolecek struct ifnet *ifp = &ec->ec_if;
1010 1.43.2.2 jdolecek struct dwc_gmac_softc *sc = ifp->if_softc;
1011 1.43.2.2 jdolecek int ret = 0;
1012 1.43.2.2 jdolecek
1013 1.43.2.2 jdolecek mutex_enter(sc->sc_lock);
1014 1.43.2.2 jdolecek int change = ifp->if_flags ^ sc->sc_if_flags;
1015 1.43.2.2 jdolecek sc->sc_if_flags = ifp->if_flags;
1016 1.43.2.2 jdolecek
1017 1.43.2.2 jdolecek if ((change & ~(IFF_CANTCHANGE|IFF_DEBUG)) != 0) {
1018 1.43.2.2 jdolecek ret = ENETRESET;
1019 1.43.2.2 jdolecek goto out;
1020 1.43.2.2 jdolecek }
1021 1.43.2.2 jdolecek if ((change & IFF_PROMISC) != 0) {
1022 1.43.2.2 jdolecek dwc_gmac_setmulti(sc);
1023 1.43.2.2 jdolecek }
1024 1.43.2.2 jdolecek out:
1025 1.43.2.2 jdolecek mutex_exit(sc->sc_lock);
1026 1.43.2.2 jdolecek
1027 1.43.2.2 jdolecek return ret;
1028 1.43.2.2 jdolecek }
1029 1.43.2.2 jdolecek
1030 1.43.2.2 jdolecek static int
1031 1.43.2.2 jdolecek dwc_gmac_ioctl(struct ifnet *ifp, u_long cmd, void *data)
1032 1.43.2.2 jdolecek {
1033 1.43.2.2 jdolecek struct dwc_gmac_softc *sc = ifp->if_softc;
1034 1.43.2.2 jdolecek int error = 0;
1035 1.43.2.2 jdolecek
1036 1.43.2.2 jdolecek int s = splnet();
1037 1.43.2.2 jdolecek error = ether_ioctl(ifp, cmd, data);
1038 1.43.2.2 jdolecek
1039 1.43.2.2 jdolecek #ifdef DWCGMAC_MPSAFE
1040 1.43.2.2 jdolecek splx(s);
1041 1.43.2.2 jdolecek #endif
1042 1.43.2.2 jdolecek
1043 1.43.2.2 jdolecek if (error == ENETRESET) {
1044 1.43.2.2 jdolecek error = 0;
1045 1.43.2.2 jdolecek if (cmd != SIOCADDMULTI && cmd != SIOCDELMULTI)
1046 1.43.2.2 jdolecek ;
1047 1.43.2.2 jdolecek else if (ifp->if_flags & IFF_RUNNING) {
1048 1.43.2.2 jdolecek /*
1049 1.43.2.2 jdolecek * Multicast list has changed; set the hardware filter
1050 1.43.2.2 jdolecek * accordingly.
1051 1.43.2.2 jdolecek */
1052 1.43.2.2 jdolecek mutex_enter(sc->sc_lock);
1053 1.43.2.2 jdolecek dwc_gmac_setmulti(sc);
1054 1.43.2.2 jdolecek mutex_exit(sc->sc_lock);
1055 1.43.2.2 jdolecek }
1056 1.43.2.2 jdolecek }
1057 1.43.2.2 jdolecek
1058 1.43.2.2 jdolecek /* Try to get things going again */
1059 1.43.2.2 jdolecek if (ifp->if_flags & IFF_UP)
1060 1.43.2.2 jdolecek dwc_gmac_start(ifp);
1061 1.43.2.2 jdolecek sc->sc_if_flags = sc->sc_ec.ec_if.if_flags;
1062 1.43.2.2 jdolecek
1063 1.43.2.2 jdolecek #ifndef DWCGMAC_MPSAFE
1064 1.43.2.2 jdolecek splx(s);
1065 1.43.2.2 jdolecek #endif
1066 1.43.2.2 jdolecek
1067 1.43.2.2 jdolecek return error;
1068 1.43.2.2 jdolecek }
1069 1.43.2.2 jdolecek
1070 1.43.2.2 jdolecek static void
1071 1.43.2.2 jdolecek dwc_gmac_tx_intr(struct dwc_gmac_softc *sc)
1072 1.43.2.2 jdolecek {
1073 1.43.2.2 jdolecek struct ifnet *ifp = &sc->sc_ec.ec_if;
1074 1.43.2.2 jdolecek struct dwc_gmac_tx_data *data;
1075 1.43.2.2 jdolecek struct dwc_gmac_dev_dmadesc *desc;
1076 1.43.2.2 jdolecek uint32_t status;
1077 1.43.2.2 jdolecek int i, nsegs;
1078 1.43.2.2 jdolecek
1079 1.43.2.2 jdolecek mutex_enter(&sc->sc_txq.t_mtx);
1080 1.43.2.2 jdolecek
1081 1.43.2.2 jdolecek for (i = sc->sc_txq.t_next; sc->sc_txq.t_queued > 0; i = TX_NEXT(i)) {
1082 1.43.2.2 jdolecek #ifdef DWC_GMAC_DEBUG
1083 1.43.2.2 jdolecek aprint_normal_dev(sc->sc_dev,
1084 1.43.2.2 jdolecek "dwc_gmac_tx_intr: checking desc #%d (t_queued: %d)\n",
1085 1.43.2.2 jdolecek i, sc->sc_txq.t_queued);
1086 1.43.2.2 jdolecek #endif
1087 1.43.2.2 jdolecek
1088 1.43.2.2 jdolecek /*
1089 1.43.2.2 jdolecek * i+1 does not need to be a valid descriptor,
1090 1.43.2.2 jdolecek * this is just a special notion to just sync
1091 1.43.2.2 jdolecek * a single tx descriptor (i)
1092 1.43.2.2 jdolecek */
1093 1.43.2.2 jdolecek dwc_gmac_txdesc_sync(sc, i, i+1,
1094 1.43.2.2 jdolecek BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
1095 1.43.2.2 jdolecek
1096 1.43.2.2 jdolecek desc = &sc->sc_txq.t_desc[i];
1097 1.43.2.2 jdolecek status = le32toh(desc->ddesc_status);
1098 1.43.2.2 jdolecek if (status & DDESC_STATUS_OWNEDBYDEV)
1099 1.43.2.2 jdolecek break;
1100 1.43.2.2 jdolecek
1101 1.43.2.2 jdolecek data = &sc->sc_txq.t_data[i];
1102 1.43.2.2 jdolecek if (data->td_m == NULL)
1103 1.43.2.2 jdolecek continue;
1104 1.43.2.2 jdolecek
1105 1.43.2.2 jdolecek ifp->if_opackets++;
1106 1.43.2.2 jdolecek nsegs = data->td_active->dm_nsegs;
1107 1.43.2.2 jdolecek bus_dmamap_sync(sc->sc_dmat, data->td_active, 0,
1108 1.43.2.2 jdolecek data->td_active->dm_mapsize, BUS_DMASYNC_POSTWRITE);
1109 1.43.2.2 jdolecek bus_dmamap_unload(sc->sc_dmat, data->td_active);
1110 1.43.2.2 jdolecek
1111 1.43.2.2 jdolecek #ifdef DWC_GMAC_DEBUG
1112 1.43.2.2 jdolecek aprint_normal_dev(sc->sc_dev,
1113 1.43.2.2 jdolecek "dwc_gmac_tx_intr: done with packet at desc #%d, "
1114 1.43.2.2 jdolecek "freeing mbuf %p\n", i, data->td_m);
1115 1.43.2.2 jdolecek #endif
1116 1.43.2.2 jdolecek
1117 1.43.2.2 jdolecek m_freem(data->td_m);
1118 1.43.2.2 jdolecek data->td_m = NULL;
1119 1.43.2.2 jdolecek
1120 1.43.2.2 jdolecek sc->sc_txq.t_queued -= nsegs;
1121 1.43.2.2 jdolecek }
1122 1.43.2.2 jdolecek
1123 1.43.2.2 jdolecek sc->sc_txq.t_next = i;
1124 1.43.2.2 jdolecek
1125 1.43.2.2 jdolecek if (sc->sc_txq.t_queued < AWGE_TX_RING_COUNT) {
1126 1.43.2.2 jdolecek ifp->if_flags &= ~IFF_OACTIVE;
1127 1.43.2.2 jdolecek }
1128 1.43.2.2 jdolecek mutex_exit(&sc->sc_txq.t_mtx);
1129 1.43.2.2 jdolecek }
1130 1.43.2.2 jdolecek
1131 1.43.2.2 jdolecek static void
1132 1.43.2.2 jdolecek dwc_gmac_rx_intr(struct dwc_gmac_softc *sc)
1133 1.43.2.2 jdolecek {
1134 1.43.2.2 jdolecek struct ifnet *ifp = &sc->sc_ec.ec_if;
1135 1.43.2.2 jdolecek struct dwc_gmac_dev_dmadesc *desc;
1136 1.43.2.2 jdolecek struct dwc_gmac_rx_data *data;
1137 1.43.2.2 jdolecek bus_addr_t physaddr;
1138 1.43.2.2 jdolecek uint32_t status;
1139 1.43.2.2 jdolecek struct mbuf *m, *mnew;
1140 1.43.2.2 jdolecek int i, len, error;
1141 1.43.2.2 jdolecek
1142 1.43.2.2 jdolecek mutex_enter(&sc->sc_rxq.r_mtx);
1143 1.43.2.2 jdolecek for (i = sc->sc_rxq.r_cur; ; i = RX_NEXT(i)) {
1144 1.43.2.2 jdolecek bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map,
1145 1.43.2.2 jdolecek RX_DESC_OFFSET(i), sizeof(*desc),
1146 1.43.2.2 jdolecek BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
1147 1.43.2.2 jdolecek desc = &sc->sc_rxq.r_desc[i];
1148 1.43.2.2 jdolecek data = &sc->sc_rxq.r_data[i];
1149 1.43.2.2 jdolecek
1150 1.43.2.2 jdolecek status = le32toh(desc->ddesc_status);
1151 1.43.2.2 jdolecek if (status & DDESC_STATUS_OWNEDBYDEV)
1152 1.43.2.2 jdolecek break;
1153 1.43.2.2 jdolecek
1154 1.43.2.2 jdolecek if (status & (DDESC_STATUS_RXERROR|DDESC_STATUS_RXTRUNCATED)) {
1155 1.43.2.2 jdolecek #ifdef DWC_GMAC_DEBUG
1156 1.43.2.2 jdolecek aprint_normal_dev(sc->sc_dev,
1157 1.43.2.2 jdolecek "RX error: descriptor status %08x, skipping\n",
1158 1.43.2.2 jdolecek status);
1159 1.43.2.2 jdolecek #endif
1160 1.43.2.2 jdolecek ifp->if_ierrors++;
1161 1.43.2.2 jdolecek goto skip;
1162 1.43.2.2 jdolecek }
1163 1.43.2.2 jdolecek
1164 1.43.2.2 jdolecek len = __SHIFTOUT(status, DDESC_STATUS_FRMLENMSK);
1165 1.43.2.2 jdolecek
1166 1.43.2.2 jdolecek #ifdef DWC_GMAC_DEBUG
1167 1.43.2.2 jdolecek aprint_normal_dev(sc->sc_dev,
1168 1.43.2.2 jdolecek "rx int: device is done with descriptor #%d, len: %d\n",
1169 1.43.2.2 jdolecek i, len);
1170 1.43.2.2 jdolecek #endif
1171 1.43.2.2 jdolecek
1172 1.43.2.2 jdolecek /*
1173 1.43.2.2 jdolecek * Try to get a new mbuf before passing this one
1174 1.43.2.2 jdolecek * up, if that fails, drop the packet and reuse
1175 1.43.2.2 jdolecek * the existing one.
1176 1.43.2.2 jdolecek */
1177 1.43.2.2 jdolecek MGETHDR(mnew, M_DONTWAIT, MT_DATA);
1178 1.43.2.2 jdolecek if (mnew == NULL) {
1179 1.43.2.2 jdolecek ifp->if_ierrors++;
1180 1.43.2.2 jdolecek goto skip;
1181 1.43.2.2 jdolecek }
1182 1.43.2.2 jdolecek MCLGET(mnew, M_DONTWAIT);
1183 1.43.2.2 jdolecek if ((mnew->m_flags & M_EXT) == 0) {
1184 1.43.2.2 jdolecek m_freem(mnew);
1185 1.43.2.2 jdolecek ifp->if_ierrors++;
1186 1.43.2.2 jdolecek goto skip;
1187 1.43.2.2 jdolecek }
1188 1.43.2.2 jdolecek
1189 1.43.2.2 jdolecek /* unload old DMA map */
1190 1.43.2.2 jdolecek bus_dmamap_sync(sc->sc_dmat, data->rd_map, 0,
1191 1.43.2.2 jdolecek data->rd_map->dm_mapsize, BUS_DMASYNC_POSTREAD);
1192 1.43.2.2 jdolecek bus_dmamap_unload(sc->sc_dmat, data->rd_map);
1193 1.43.2.2 jdolecek
1194 1.43.2.2 jdolecek /* and reload with new mbuf */
1195 1.43.2.2 jdolecek error = bus_dmamap_load(sc->sc_dmat, data->rd_map,
1196 1.43.2.2 jdolecek mtod(mnew, void*), MCLBYTES, NULL,
1197 1.43.2.2 jdolecek BUS_DMA_READ | BUS_DMA_NOWAIT);
1198 1.43.2.2 jdolecek if (error != 0) {
1199 1.43.2.2 jdolecek m_freem(mnew);
1200 1.43.2.2 jdolecek /* try to reload old mbuf */
1201 1.43.2.2 jdolecek error = bus_dmamap_load(sc->sc_dmat, data->rd_map,
1202 1.43.2.2 jdolecek mtod(data->rd_m, void*), MCLBYTES, NULL,
1203 1.43.2.2 jdolecek BUS_DMA_READ | BUS_DMA_NOWAIT);
1204 1.43.2.2 jdolecek if (error != 0) {
1205 1.43.2.2 jdolecek panic("%s: could not load old rx mbuf",
1206 1.43.2.2 jdolecek device_xname(sc->sc_dev));
1207 1.43.2.2 jdolecek }
1208 1.43.2.2 jdolecek ifp->if_ierrors++;
1209 1.43.2.2 jdolecek goto skip;
1210 1.43.2.2 jdolecek }
1211 1.43.2.2 jdolecek physaddr = data->rd_map->dm_segs[0].ds_addr;
1212 1.43.2.2 jdolecek
1213 1.43.2.2 jdolecek /*
1214 1.43.2.2 jdolecek * New mbuf loaded, update RX ring and continue
1215 1.43.2.2 jdolecek */
1216 1.43.2.2 jdolecek m = data->rd_m;
1217 1.43.2.2 jdolecek data->rd_m = mnew;
1218 1.43.2.2 jdolecek desc->ddesc_data = htole32(physaddr);
1219 1.43.2.2 jdolecek
1220 1.43.2.2 jdolecek /* finalize mbuf */
1221 1.43.2.2 jdolecek m->m_pkthdr.len = m->m_len = len;
1222 1.43.2.2 jdolecek m_set_rcvif(m, ifp);
1223 1.43.2.2 jdolecek m->m_flags |= M_HASFCS;
1224 1.43.2.2 jdolecek
1225 1.43.2.2 jdolecek if_percpuq_enqueue(sc->sc_ipq, m);
1226 1.43.2.2 jdolecek
1227 1.43.2.2 jdolecek skip:
1228 1.43.2.2 jdolecek bus_dmamap_sync(sc->sc_dmat, data->rd_map, 0,
1229 1.43.2.2 jdolecek data->rd_map->dm_mapsize, BUS_DMASYNC_PREREAD);
1230 1.43.2.2 jdolecek desc->ddesc_cntl = htole32(
1231 1.43.2.2 jdolecek __SHIFTIN(AWGE_MAX_PACKET,DDESC_CNTL_SIZE1MASK) |
1232 1.43.2.2 jdolecek DDESC_CNTL_RXCHAIN);
1233 1.43.2.2 jdolecek desc->ddesc_status = htole32(DDESC_STATUS_OWNEDBYDEV);
1234 1.43.2.2 jdolecek bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map,
1235 1.43.2.2 jdolecek RX_DESC_OFFSET(i), sizeof(*desc),
1236 1.43.2.2 jdolecek BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
1237 1.43.2.2 jdolecek }
1238 1.43.2.2 jdolecek
1239 1.43.2.2 jdolecek /* update RX pointer */
1240 1.43.2.2 jdolecek sc->sc_rxq.r_cur = i;
1241 1.43.2.2 jdolecek
1242 1.43.2.2 jdolecek mutex_exit(&sc->sc_rxq.r_mtx);
1243 1.43.2.2 jdolecek }
1244 1.43.2.2 jdolecek
1245 1.43.2.2 jdolecek /*
1246 1.43.2.2 jdolecek * Reverse order of bits - http://aggregate.org/MAGIC/#Bit%20Reversal
1247 1.43.2.2 jdolecek */
1248 1.43.2.2 jdolecek static uint32_t
1249 1.43.2.2 jdolecek bitrev32(uint32_t x)
1250 1.43.2.2 jdolecek {
1251 1.43.2.2 jdolecek x = (((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1));
1252 1.43.2.2 jdolecek x = (((x & 0xcccccccc) >> 2) | ((x & 0x33333333) << 2));
1253 1.43.2.2 jdolecek x = (((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4));
1254 1.43.2.2 jdolecek x = (((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8));
1255 1.43.2.2 jdolecek
1256 1.43.2.2 jdolecek return (x >> 16) | (x << 16);
1257 1.43.2.2 jdolecek }
1258 1.43.2.2 jdolecek
1259 1.43.2.2 jdolecek static void
1260 1.43.2.2 jdolecek dwc_gmac_setmulti(struct dwc_gmac_softc *sc)
1261 1.43.2.2 jdolecek {
1262 1.43.2.2 jdolecek struct ifnet * const ifp = &sc->sc_ec.ec_if;
1263 1.43.2.2 jdolecek struct ether_multi *enm;
1264 1.43.2.2 jdolecek struct ether_multistep step;
1265 1.43.2.2 jdolecek uint32_t hashes[2] = { 0, 0 };
1266 1.43.2.2 jdolecek uint32_t ffilt, h;
1267 1.43.2.2 jdolecek int mcnt;
1268 1.43.2.2 jdolecek
1269 1.43.2.2 jdolecek KASSERT(mutex_owned(sc->sc_lock));
1270 1.43.2.2 jdolecek
1271 1.43.2.2 jdolecek ffilt = bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_FFILT);
1272 1.43.2.2 jdolecek
1273 1.43.2.2 jdolecek if (ifp->if_flags & IFF_PROMISC) {
1274 1.43.2.2 jdolecek ffilt |= AWIN_GMAC_MAC_FFILT_PR;
1275 1.43.2.2 jdolecek goto special_filter;
1276 1.43.2.2 jdolecek }
1277 1.43.2.2 jdolecek
1278 1.43.2.2 jdolecek ifp->if_flags &= ~IFF_ALLMULTI;
1279 1.43.2.2 jdolecek ffilt &= ~(AWIN_GMAC_MAC_FFILT_PM|AWIN_GMAC_MAC_FFILT_PR);
1280 1.43.2.2 jdolecek
1281 1.43.2.2 jdolecek bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_HTLOW, 0);
1282 1.43.2.2 jdolecek bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_HTHIGH, 0);
1283 1.43.2.2 jdolecek
1284 1.43.2.2 jdolecek ETHER_FIRST_MULTI(step, &sc->sc_ec, enm);
1285 1.43.2.2 jdolecek mcnt = 0;
1286 1.43.2.2 jdolecek while (enm != NULL) {
1287 1.43.2.2 jdolecek if (memcmp(enm->enm_addrlo, enm->enm_addrhi,
1288 1.43.2.2 jdolecek ETHER_ADDR_LEN) != 0) {
1289 1.43.2.2 jdolecek ffilt |= AWIN_GMAC_MAC_FFILT_PM;
1290 1.43.2.2 jdolecek ifp->if_flags |= IFF_ALLMULTI;
1291 1.43.2.2 jdolecek goto special_filter;
1292 1.43.2.2 jdolecek }
1293 1.43.2.2 jdolecek
1294 1.43.2.2 jdolecek h = bitrev32(
1295 1.43.2.2 jdolecek ~ether_crc32_le(enm->enm_addrlo, ETHER_ADDR_LEN)
1296 1.43.2.2 jdolecek ) >> 26;
1297 1.43.2.2 jdolecek hashes[h >> 5] |= (1 << (h & 0x1f));
1298 1.43.2.2 jdolecek
1299 1.43.2.2 jdolecek mcnt++;
1300 1.43.2.2 jdolecek ETHER_NEXT_MULTI(step, enm);
1301 1.43.2.2 jdolecek }
1302 1.43.2.2 jdolecek
1303 1.43.2.2 jdolecek if (mcnt)
1304 1.43.2.2 jdolecek ffilt |= AWIN_GMAC_MAC_FFILT_HMC;
1305 1.43.2.2 jdolecek else
1306 1.43.2.2 jdolecek ffilt &= ~AWIN_GMAC_MAC_FFILT_HMC;
1307 1.43.2.2 jdolecek
1308 1.43.2.2 jdolecek bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_FFILT, ffilt);
1309 1.43.2.2 jdolecek bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_HTLOW,
1310 1.43.2.2 jdolecek hashes[0]);
1311 1.43.2.2 jdolecek bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_HTHIGH,
1312 1.43.2.2 jdolecek hashes[1]);
1313 1.43.2.2 jdolecek sc->sc_if_flags = sc->sc_ec.ec_if.if_flags;
1314 1.43.2.2 jdolecek
1315 1.43.2.2 jdolecek #ifdef DWC_GMAC_DEBUG
1316 1.43.2.2 jdolecek dwc_gmac_dump_ffilt(sc, ffilt);
1317 1.43.2.2 jdolecek #endif
1318 1.43.2.2 jdolecek return;
1319 1.43.2.2 jdolecek
1320 1.43.2.2 jdolecek special_filter:
1321 1.43.2.2 jdolecek #ifdef DWC_GMAC_DEBUG
1322 1.43.2.2 jdolecek dwc_gmac_dump_ffilt(sc, ffilt);
1323 1.43.2.2 jdolecek #endif
1324 1.43.2.2 jdolecek /* no MAC hashes, ALLMULTI or PROMISC */
1325 1.43.2.2 jdolecek bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_FFILT,
1326 1.43.2.2 jdolecek ffilt);
1327 1.43.2.2 jdolecek bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_HTLOW,
1328 1.43.2.2 jdolecek 0xffffffff);
1329 1.43.2.2 jdolecek bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_HTHIGH,
1330 1.43.2.2 jdolecek 0xffffffff);
1331 1.43.2.2 jdolecek sc->sc_if_flags = sc->sc_ec.ec_if.if_flags;
1332 1.43.2.2 jdolecek }
1333 1.43.2.2 jdolecek
1334 1.43.2.2 jdolecek int
1335 1.43.2.2 jdolecek dwc_gmac_intr(struct dwc_gmac_softc *sc)
1336 1.43.2.2 jdolecek {
1337 1.43.2.2 jdolecek uint32_t status, dma_status;
1338 1.43.2.2 jdolecek int rv = 0;
1339 1.43.2.2 jdolecek
1340 1.43.2.2 jdolecek if (sc->sc_stopping)
1341 1.43.2.2 jdolecek return 0;
1342 1.43.2.2 jdolecek
1343 1.43.2.2 jdolecek status = bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_INTR);
1344 1.43.2.2 jdolecek if (status & AWIN_GMAC_MII_IRQ) {
1345 1.43.2.2 jdolecek (void)bus_space_read_4(sc->sc_bst, sc->sc_bsh,
1346 1.43.2.2 jdolecek AWIN_GMAC_MII_STATUS);
1347 1.43.2.2 jdolecek rv = 1;
1348 1.43.2.2 jdolecek mii_pollstat(&sc->sc_mii);
1349 1.43.2.2 jdolecek }
1350 1.43.2.2 jdolecek
1351 1.43.2.2 jdolecek dma_status = bus_space_read_4(sc->sc_bst, sc->sc_bsh,
1352 1.43.2.2 jdolecek AWIN_GMAC_DMA_STATUS);
1353 1.43.2.2 jdolecek
1354 1.43.2.2 jdolecek if (dma_status & (GMAC_DMA_INT_NIE|GMAC_DMA_INT_AIE))
1355 1.43.2.2 jdolecek rv = 1;
1356 1.43.2.2 jdolecek
1357 1.43.2.2 jdolecek if (dma_status & GMAC_DMA_INT_TIE)
1358 1.43.2.2 jdolecek dwc_gmac_tx_intr(sc);
1359 1.43.2.2 jdolecek
1360 1.43.2.2 jdolecek if (dma_status & GMAC_DMA_INT_RIE)
1361 1.43.2.2 jdolecek dwc_gmac_rx_intr(sc);
1362 1.43.2.2 jdolecek
1363 1.43.2.2 jdolecek /*
1364 1.43.2.2 jdolecek * Check error conditions
1365 1.43.2.2 jdolecek */
1366 1.43.2.2 jdolecek if (dma_status & GMAC_DMA_INT_ERRORS) {
1367 1.43.2.2 jdolecek sc->sc_ec.ec_if.if_oerrors++;
1368 1.43.2.2 jdolecek #ifdef DWC_GMAC_DEBUG
1369 1.43.2.2 jdolecek dwc_dump_and_abort(sc, "interrupt error condition");
1370 1.43.2.2 jdolecek #endif
1371 1.43.2.2 jdolecek }
1372 1.43.2.2 jdolecek
1373 1.43.2.2 jdolecek /* ack interrupt */
1374 1.43.2.2 jdolecek if (dma_status)
1375 1.43.2.2 jdolecek bus_space_write_4(sc->sc_bst, sc->sc_bsh,
1376 1.43.2.2 jdolecek AWIN_GMAC_DMA_STATUS, dma_status & GMAC_DMA_INT_MASK);
1377 1.43.2.2 jdolecek
1378 1.43.2.2 jdolecek /*
1379 1.43.2.2 jdolecek * Get more packets
1380 1.43.2.2 jdolecek */
1381 1.43.2.2 jdolecek if (rv)
1382 1.43.2.2 jdolecek if_schedule_deferred_start(&sc->sc_ec.ec_if);
1383 1.43.2.2 jdolecek
1384 1.43.2.2 jdolecek return rv;
1385 1.43.2.2 jdolecek }
1386 1.43.2.2 jdolecek
1387 1.43.2.2 jdolecek #ifdef DWC_GMAC_DEBUG
1388 1.43.2.2 jdolecek static void
1389 1.43.2.2 jdolecek dwc_gmac_dump_dma(struct dwc_gmac_softc *sc)
1390 1.43.2.2 jdolecek {
1391 1.43.2.2 jdolecek aprint_normal_dev(sc->sc_dev, "busmode: %08x\n",
1392 1.43.2.2 jdolecek bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_BUSMODE));
1393 1.43.2.2 jdolecek aprint_normal_dev(sc->sc_dev, "tx poll: %08x\n",
1394 1.43.2.2 jdolecek bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_TXPOLL));
1395 1.43.2.2 jdolecek aprint_normal_dev(sc->sc_dev, "rx poll: %08x\n",
1396 1.43.2.2 jdolecek bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_RXPOLL));
1397 1.43.2.2 jdolecek aprint_normal_dev(sc->sc_dev, "rx descriptors: %08x\n",
1398 1.43.2.2 jdolecek bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_RX_ADDR));
1399 1.43.2.2 jdolecek aprint_normal_dev(sc->sc_dev, "tx descriptors: %08x\n",
1400 1.43.2.2 jdolecek bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_TX_ADDR));
1401 1.43.2.2 jdolecek aprint_normal_dev(sc->sc_dev, "status: %08x\n",
1402 1.43.2.2 jdolecek bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_STATUS));
1403 1.43.2.2 jdolecek aprint_normal_dev(sc->sc_dev, "op mode: %08x\n",
1404 1.43.2.2 jdolecek bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_OPMODE));
1405 1.43.2.2 jdolecek aprint_normal_dev(sc->sc_dev, "int enable: %08x\n",
1406 1.43.2.2 jdolecek bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_INTENABLE));
1407 1.43.2.2 jdolecek aprint_normal_dev(sc->sc_dev, "cur tx: %08x\n",
1408 1.43.2.2 jdolecek bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_CUR_TX_DESC));
1409 1.43.2.2 jdolecek aprint_normal_dev(sc->sc_dev, "cur rx: %08x\n",
1410 1.43.2.2 jdolecek bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_CUR_RX_DESC));
1411 1.43.2.2 jdolecek aprint_normal_dev(sc->sc_dev, "cur tx buffer: %08x\n",
1412 1.43.2.2 jdolecek bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_CUR_TX_BUFADDR));
1413 1.43.2.2 jdolecek aprint_normal_dev(sc->sc_dev, "cur rx buffer: %08x\n",
1414 1.43.2.2 jdolecek bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_CUR_RX_BUFADDR));
1415 1.43.2.2 jdolecek }
1416 1.43.2.2 jdolecek
1417 1.43.2.2 jdolecek static void
1418 1.43.2.2 jdolecek dwc_gmac_dump_tx_desc(struct dwc_gmac_softc *sc)
1419 1.43.2.2 jdolecek {
1420 1.43.2.2 jdolecek int i;
1421 1.43.2.2 jdolecek
1422 1.43.2.2 jdolecek aprint_normal_dev(sc->sc_dev, "TX queue: cur=%d, next=%d, queued=%d\n",
1423 1.43.2.2 jdolecek sc->sc_txq.t_cur, sc->sc_txq.t_next, sc->sc_txq.t_queued);
1424 1.43.2.2 jdolecek aprint_normal_dev(sc->sc_dev, "TX DMA descriptors:\n");
1425 1.43.2.2 jdolecek for (i = 0; i < AWGE_TX_RING_COUNT; i++) {
1426 1.43.2.2 jdolecek struct dwc_gmac_dev_dmadesc *desc = &sc->sc_txq.t_desc[i];
1427 1.43.2.2 jdolecek aprint_normal("#%d (%08lx): status: %08x cntl: %08x "
1428 1.43.2.2 jdolecek "data: %08x next: %08x\n",
1429 1.43.2.2 jdolecek i, sc->sc_txq.t_physaddr +
1430 1.43.2.2 jdolecek i*sizeof(struct dwc_gmac_dev_dmadesc),
1431 1.43.2.2 jdolecek le32toh(desc->ddesc_status), le32toh(desc->ddesc_cntl),
1432 1.43.2.2 jdolecek le32toh(desc->ddesc_data), le32toh(desc->ddesc_next));
1433 1.43.2.2 jdolecek }
1434 1.43.2.2 jdolecek }
1435 1.43.2.2 jdolecek
1436 1.43.2.2 jdolecek static void
1437 1.43.2.2 jdolecek dwc_gmac_dump_rx_desc(struct dwc_gmac_softc *sc)
1438 1.43.2.2 jdolecek {
1439 1.43.2.2 jdolecek int i;
1440 1.43.2.2 jdolecek
1441 1.43.2.2 jdolecek aprint_normal_dev(sc->sc_dev, "RX queue: cur=%d, next=%d\n",
1442 1.43.2.2 jdolecek sc->sc_rxq.r_cur, sc->sc_rxq.r_next);
1443 1.43.2.2 jdolecek aprint_normal_dev(sc->sc_dev, "RX DMA descriptors:\n");
1444 1.43.2.2 jdolecek for (i = 0; i < AWGE_RX_RING_COUNT; i++) {
1445 1.43.2.2 jdolecek struct dwc_gmac_dev_dmadesc *desc = &sc->sc_rxq.r_desc[i];
1446 1.43.2.2 jdolecek aprint_normal("#%d (%08lx): status: %08x cntl: %08x "
1447 1.43.2.2 jdolecek "data: %08x next: %08x\n",
1448 1.43.2.2 jdolecek i, sc->sc_rxq.r_physaddr +
1449 1.43.2.2 jdolecek i*sizeof(struct dwc_gmac_dev_dmadesc),
1450 1.43.2.2 jdolecek le32toh(desc->ddesc_status), le32toh(desc->ddesc_cntl),
1451 1.43.2.2 jdolecek le32toh(desc->ddesc_data), le32toh(desc->ddesc_next));
1452 1.43.2.2 jdolecek }
1453 1.43.2.2 jdolecek }
1454 1.43.2.2 jdolecek
1455 1.43.2.2 jdolecek static void
1456 1.43.2.2 jdolecek dwc_dump_status(struct dwc_gmac_softc *sc)
1457 1.43.2.2 jdolecek {
1458 1.43.2.2 jdolecek uint32_t status = bus_space_read_4(sc->sc_bst, sc->sc_bsh,
1459 1.43.2.2 jdolecek AWIN_GMAC_MAC_INTR);
1460 1.43.2.2 jdolecek uint32_t dma_status = bus_space_read_4(sc->sc_bst, sc->sc_bsh,
1461 1.43.2.2 jdolecek AWIN_GMAC_DMA_STATUS);
1462 1.43.2.2 jdolecek char buf[200];
1463 1.43.2.2 jdolecek
1464 1.43.2.2 jdolecek /* print interrupt state */
1465 1.43.2.2 jdolecek snprintb(buf, sizeof(buf), "\177\20"
1466 1.43.2.2 jdolecek "b\x10""NI\0"
1467 1.43.2.2 jdolecek "b\x0f""AI\0"
1468 1.43.2.2 jdolecek "b\x0e""ER\0"
1469 1.43.2.2 jdolecek "b\x0d""FB\0"
1470 1.43.2.2 jdolecek "b\x0a""ET\0"
1471 1.43.2.2 jdolecek "b\x09""RW\0"
1472 1.43.2.2 jdolecek "b\x08""RS\0"
1473 1.43.2.2 jdolecek "b\x07""RU\0"
1474 1.43.2.2 jdolecek "b\x06""RI\0"
1475 1.43.2.2 jdolecek "b\x05""UN\0"
1476 1.43.2.2 jdolecek "b\x04""OV\0"
1477 1.43.2.2 jdolecek "b\x03""TJ\0"
1478 1.43.2.2 jdolecek "b\x02""TU\0"
1479 1.43.2.2 jdolecek "b\x01""TS\0"
1480 1.43.2.2 jdolecek "b\x00""TI\0"
1481 1.43.2.2 jdolecek "\0", dma_status);
1482 1.43.2.2 jdolecek aprint_normal_dev(sc->sc_dev, "INTR status: %08x, DMA status: %s\n",
1483 1.43.2.2 jdolecek status, buf);
1484 1.43.2.2 jdolecek }
1485 1.43.2.2 jdolecek
1486 1.43.2.2 jdolecek static void
1487 1.43.2.2 jdolecek dwc_dump_and_abort(struct dwc_gmac_softc *sc, const char *msg)
1488 1.43.2.2 jdolecek {
1489 1.43.2.2 jdolecek dwc_dump_status(sc);
1490 1.43.2.2 jdolecek dwc_gmac_dump_ffilt(sc,
1491 1.43.2.2 jdolecek bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_FFILT));
1492 1.43.2.2 jdolecek dwc_gmac_dump_dma(sc);
1493 1.43.2.2 jdolecek dwc_gmac_dump_tx_desc(sc);
1494 1.43.2.2 jdolecek dwc_gmac_dump_rx_desc(sc);
1495 1.43.2.2 jdolecek
1496 1.43.2.2 jdolecek panic("%s", msg);
1497 1.43.2.2 jdolecek }
1498 1.43.2.2 jdolecek
1499 1.43.2.2 jdolecek static void dwc_gmac_dump_ffilt(struct dwc_gmac_softc *sc, uint32_t ffilt)
1500 1.43.2.2 jdolecek {
1501 1.43.2.2 jdolecek char buf[200];
1502 1.43.2.2 jdolecek
1503 1.43.2.2 jdolecek /* print filter setup */
1504 1.43.2.2 jdolecek snprintb(buf, sizeof(buf), "\177\20"
1505 1.43.2.2 jdolecek "b\x1f""RA\0"
1506 1.43.2.2 jdolecek "b\x0a""HPF\0"
1507 1.43.2.2 jdolecek "b\x09""SAF\0"
1508 1.43.2.2 jdolecek "b\x08""SAIF\0"
1509 1.43.2.2 jdolecek "b\x05""DBF\0"
1510 1.43.2.2 jdolecek "b\x04""PM\0"
1511 1.43.2.2 jdolecek "b\x03""DAIF\0"
1512 1.43.2.2 jdolecek "b\x02""HMC\0"
1513 1.43.2.2 jdolecek "b\x01""HUC\0"
1514 1.43.2.2 jdolecek "b\x00""PR\0"
1515 1.43.2.2 jdolecek "\0", ffilt);
1516 1.43.2.2 jdolecek aprint_normal_dev(sc->sc_dev, "FFILT: %s\n", buf);
1517 1.43.2.2 jdolecek }
1518 1.43.2.2 jdolecek #endif
1519