xref: /freebsd/sys/dev/dwc/dwc1000_core.c (revision 4b7975ec)
1 /*-
2  * Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com>
3  *
4  * This software was developed by SRI International and the University of
5  * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
6  * ("CTSRD"), as part of the DARPA CRASH research programme.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 /*
31  * Ethernet media access controller (EMAC)
32  * Chapter 17, Altera Cyclone V Device Handbook (CV-5V2 2014.07.22)
33  *
34  * EMAC is an instance of the Synopsys DesignWare 3504-0
35  * Universal 10/100/1000 Ethernet MAC (DWC_gmac).
36  */
37 
38 #include <sys/cdefs.h>
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/bus.h>
42 #include <sys/kernel.h>
43 #include <sys/lock.h>
44 #include <sys/malloc.h>
45 #include <sys/mbuf.h>
46 #include <sys/module.h>
47 #include <sys/mutex.h>
48 #include <sys/rman.h>
49 #include <sys/socket.h>
50 
51 #include <net/if.h>
52 #include <net/ethernet.h>
53 #include <net/if_dl.h>
54 #include <net/if_media.h>
55 
56 #include <machine/bus.h>
57 
58 #include <dev/extres/clk/clk.h>
59 #include <dev/extres/hwreset/hwreset.h>
60 
61 #include <dev/mii/mii.h>
62 #include <dev/mii/miivar.h>
63 #include <dev/ofw/ofw_bus.h>
64 #include <dev/ofw/ofw_bus_subr.h>
65 #include <dev/mii/mii_fdt.h>
66 
67 #include <dev/dwc/if_dwcvar.h>
68 #include <dev/dwc/dwc1000_reg.h>
69 #include <dev/dwc/dwc1000_core.h>
70 #include <dev/dwc/dwc1000_dma.h>
71 
72 #include "if_dwc_if.h"
73 
74 struct dwc_hash_maddr_ctx {
75 	struct dwc_softc *sc;
76 	uint32_t hash[8];
77 };
78 
79 #define	STATS_HARVEST_INTERVAL	2
80 
81 /* Pause time field in the transmitted control frame */
82 static int dwc_pause_time = 0xffff;
83 TUNABLE_INT("hw.dwc.pause_time", &dwc_pause_time);
84 
85 /*
86  * MIIBUS functions
87  */
88 
89 int
90 dwc1000_miibus_read_reg(device_t dev, int phy, int reg)
91 {
92 	struct dwc_softc *sc;
93 	uint16_t mii;
94 	size_t cnt;
95 	int rv = 0;
96 
97 	sc = device_get_softc(dev);
98 
99 	mii = ((phy & GMII_ADDRESS_PA_MASK) << GMII_ADDRESS_PA_SHIFT)
100 	    | ((reg & GMII_ADDRESS_GR_MASK) << GMII_ADDRESS_GR_SHIFT)
101 	    | (sc->mii_clk << GMII_ADDRESS_CR_SHIFT)
102 	    | GMII_ADDRESS_GB; /* Busy flag */
103 
104 	WRITE4(sc, GMII_ADDRESS, mii);
105 
106 	for (cnt = 0; cnt < 1000; cnt++) {
107 		if (!(READ4(sc, GMII_ADDRESS) & GMII_ADDRESS_GB)) {
108 			rv = READ4(sc, GMII_DATA);
109 			break;
110 		}
111 		DELAY(10);
112 	}
113 
114 	return rv;
115 }
116 
117 int
118 dwc1000_miibus_write_reg(device_t dev, int phy, int reg, int val)
119 {
120 	struct dwc_softc *sc;
121 	uint16_t mii;
122 	size_t cnt;
123 
124 	sc = device_get_softc(dev);
125 
126 	mii = ((phy & GMII_ADDRESS_PA_MASK) << GMII_ADDRESS_PA_SHIFT)
127 	    | ((reg & GMII_ADDRESS_GR_MASK) << GMII_ADDRESS_GR_SHIFT)
128 	    | (sc->mii_clk << GMII_ADDRESS_CR_SHIFT)
129 	    | GMII_ADDRESS_GB | GMII_ADDRESS_GW;
130 
131 	WRITE4(sc, GMII_DATA, val);
132 	WRITE4(sc, GMII_ADDRESS, mii);
133 
134 	for (cnt = 0; cnt < 1000; cnt++) {
135 		if (!(READ4(sc, GMII_ADDRESS) & GMII_ADDRESS_GB)) {
136 			break;
137                 }
138 		DELAY(10);
139 	}
140 
141 	return (0);
142 }
143 
144 void
145 dwc1000_miibus_statchg(device_t dev)
146 {
147 	struct dwc_softc *sc;
148 	struct mii_data *mii;
149 	uint32_t reg;
150 
151 	/*
152 	 * Called by the MII bus driver when the PHY establishes
153 	 * link to set the MAC interface registers.
154 	 */
155 
156 	sc = device_get_softc(dev);
157 
158 	DWC_ASSERT_LOCKED(sc);
159 
160 	mii = sc->mii_softc;
161 
162 	if (mii->mii_media_status & IFM_ACTIVE)
163 		sc->link_is_up = true;
164 	else
165 		sc->link_is_up = false;
166 
167 	reg = READ4(sc, MAC_CONFIGURATION);
168 	switch (IFM_SUBTYPE(mii->mii_media_active)) {
169 	case IFM_1000_T:
170 	case IFM_1000_SX:
171 		reg &= ~(CONF_FES | CONF_PS);
172 		break;
173 	case IFM_100_TX:
174 		reg |= (CONF_FES | CONF_PS);
175 		break;
176 	case IFM_10_T:
177 		reg &= ~(CONF_FES);
178 		reg |= (CONF_PS);
179 		break;
180 	case IFM_NONE:
181 		sc->link_is_up = false;
182 		return;
183 	default:
184 		sc->link_is_up = false;
185 		device_printf(dev, "Unsupported media %u\n",
186 		    IFM_SUBTYPE(mii->mii_media_active));
187 		return;
188 	}
189 	if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0)
190 		reg |= (CONF_DM);
191 	else
192 		reg &= ~(CONF_DM);
193 	WRITE4(sc, MAC_CONFIGURATION, reg);
194 
195 	reg = FLOW_CONTROL_UP;
196 	if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_TXPAUSE) != 0)
197 		reg |= FLOW_CONTROL_TX;
198 	if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_RXPAUSE) != 0)
199 		reg |= FLOW_CONTROL_RX;
200 	if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0)
201 		reg |= dwc_pause_time << FLOW_CONTROL_PT_SHIFT;
202 	WRITE4(sc, FLOW_CONTROL, reg);
203 
204 	IF_DWC_SET_SPEED(dev, IFM_SUBTYPE(mii->mii_media_active));
205 
206 }
207 
208 void
209 dwc1000_core_setup(struct dwc_softc *sc)
210 {
211 	uint32_t reg;
212 
213 	DWC_ASSERT_LOCKED(sc);
214 
215 	/* Enable core */
216 	reg = READ4(sc, MAC_CONFIGURATION);
217 	reg |= (CONF_JD | CONF_ACS | CONF_BE);
218 	WRITE4(sc, MAC_CONFIGURATION, reg);
219 }
220 
221 void
222 dwc1000_enable_mac(struct dwc_softc *sc, bool enable)
223 {
224 	uint32_t reg;
225 
226 	DWC_ASSERT_LOCKED(sc);
227 	reg = READ4(sc, MAC_CONFIGURATION);
228 	if (enable)
229 		reg |= CONF_TE | CONF_RE;
230 	else
231 		reg &= ~(CONF_TE | CONF_RE);
232 	WRITE4(sc, MAC_CONFIGURATION, reg);
233 }
234 
235 void
236 dwc1000_enable_csum_offload(struct dwc_softc *sc)
237 {
238 	uint32_t reg;
239 
240 	DWC_ASSERT_LOCKED(sc);
241 	reg = READ4(sc, MAC_CONFIGURATION);
242 	if ((if_getcapenable(sc->ifp) & IFCAP_RXCSUM) != 0)
243 		reg |= CONF_IPC;
244 	else
245 		reg &= ~CONF_IPC;
246 	WRITE4(sc, MAC_CONFIGURATION, reg);
247 }
248 
249 static const uint8_t nibbletab[] = {
250 	/* 0x0 0000 -> 0000 */  0x0,
251 	/* 0x1 0001 -> 1000 */  0x8,
252 	/* 0x2 0010 -> 0100 */  0x4,
253 	/* 0x3 0011 -> 1100 */  0xc,
254 	/* 0x4 0100 -> 0010 */  0x2,
255 	/* 0x5 0101 -> 1010 */  0xa,
256 	/* 0x6 0110 -> 0110 */  0x6,
257 	/* 0x7 0111 -> 1110 */  0xe,
258 	/* 0x8 1000 -> 0001 */  0x1,
259 	/* 0x9 1001 -> 1001 */  0x9,
260 	/* 0xa 1010 -> 0101 */  0x5,
261 	/* 0xb 1011 -> 1101 */  0xd,
262 	/* 0xc 1100 -> 0011 */  0x3,
263 	/* 0xd 1101 -> 1011 */  0xb,
264 	/* 0xe 1110 -> 0111 */  0x7,
265 	/* 0xf 1111 -> 1111 */  0xf, };
266 
267 static uint8_t
268 bitreverse(uint8_t x)
269 {
270 
271 	return (nibbletab[x & 0xf] << 4) | nibbletab[x >> 4];
272 }
273 
274 static u_int
275 dwc_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt)
276 {
277 	struct dwc_hash_maddr_ctx *ctx = arg;
278 	uint32_t crc, hashbit, hashreg;
279 	uint8_t val;
280 
281 	crc = ether_crc32_le(LLADDR(sdl), ETHER_ADDR_LEN);
282 	/* Take lower 8 bits and reverse it */
283 	val = bitreverse(~crc & 0xff);
284 	/*
285 	 * TODO: There is probably a HW_FEATURES bit which isn't
286 	 * related to the extended descriptors that describe this
287 	 */
288 	if (!ctx->sc->dma_ext_desc)
289 		val >>= 2; /* Only need lower 6 bits */
290 	hashreg = (val >> 5);
291 	hashbit = (val & 31);
292 	ctx->hash[hashreg] |= (1 << hashbit);
293 
294 	return (1);
295 }
296 
297 void
298 dwc1000_setup_rxfilter(struct dwc_softc *sc)
299 {
300 	struct dwc_hash_maddr_ctx ctx;
301 	if_t ifp;
302 	uint8_t *eaddr;
303 	uint32_t ffval, hi, lo;
304 	int nhash, i;
305 
306 	DWC_ASSERT_LOCKED(sc);
307 
308 	ifp = sc->ifp;
309 	/*
310 	 * TODO: There is probably a HW_FEATURES bit which isn't
311 	 * related to the extended descriptors that describe this
312 	 */
313 	nhash = sc->dma_ext_desc == false ? 2 : 8;
314 
315 	/*
316 	 * Set the multicast (group) filter hash.
317 	 */
318 	if ((if_getflags(ifp) & IFF_ALLMULTI) != 0) {
319 		ffval = (FRAME_FILTER_PM);
320 		for (i = 0; i < nhash; i++)
321 			ctx.hash[i] = ~0;
322 	} else {
323 		ffval = (FRAME_FILTER_HMC);
324 		for (i = 0; i < nhash; i++)
325 			ctx.hash[i] = 0;
326 		ctx.sc = sc;
327 		if_foreach_llmaddr(ifp, dwc_hash_maddr, &ctx);
328 	}
329 
330 	/*
331 	 * Set the individual address filter hash.
332 	 */
333 	if ((if_getflags(ifp) & IFF_PROMISC) != 0)
334 		ffval |= (FRAME_FILTER_PR);
335 
336 	/*
337 	 * Set the primary address.
338 	 */
339 	eaddr = if_getlladdr(ifp);
340 	lo = eaddr[0] | (eaddr[1] << 8) | (eaddr[2] << 16) |
341 	    (eaddr[3] << 24);
342 	hi = eaddr[4] | (eaddr[5] << 8);
343 	WRITE4(sc, MAC_ADDRESS_LOW(0), lo);
344 	WRITE4(sc, MAC_ADDRESS_HIGH(0), hi);
345 	WRITE4(sc, MAC_FRAME_FILTER, ffval);
346 	if (!sc->dma_ext_desc) {
347 		WRITE4(sc, GMAC_MAC_HTLOW, ctx.hash[0]);
348 		WRITE4(sc, GMAC_MAC_HTHIGH, ctx.hash[1]);
349 	} else {
350 		for (i = 0; i < nhash; i++)
351 			WRITE4(sc, HASH_TABLE_REG(i), ctx.hash[i]);
352 	}
353 }
354 
355 void
356 dwc1000_get_hwaddr(struct dwc_softc *sc, uint8_t *hwaddr)
357 {
358 	uint32_t hi, lo, rnd;
359 
360 	/*
361 	 * Try to recover a MAC address from the running hardware. If there's
362 	 * something non-zero there, assume the bootloader did the right thing
363 	 * and just use it.
364 	 *
365 	 * Otherwise, set the address to a convenient locally assigned address,
366 	 * 'bsd' + random 24 low-order bits.  'b' is 0x62, which has the locally
367 	 * assigned bit set, and the broadcast/multicast bit clear.
368 	 */
369 	lo = READ4(sc, MAC_ADDRESS_LOW(0));
370 	hi = READ4(sc, MAC_ADDRESS_HIGH(0)) & 0xffff;
371 	if ((lo != 0xffffffff) || (hi != 0xffff)) {
372 		hwaddr[0] = (lo >>  0) & 0xff;
373 		hwaddr[1] = (lo >>  8) & 0xff;
374 		hwaddr[2] = (lo >> 16) & 0xff;
375 		hwaddr[3] = (lo >> 24) & 0xff;
376 		hwaddr[4] = (hi >>  0) & 0xff;
377 		hwaddr[5] = (hi >>  8) & 0xff;
378 	} else {
379 		rnd = arc4random() & 0x00ffffff;
380 		hwaddr[0] = 'b';
381 		hwaddr[1] = 's';
382 		hwaddr[2] = 'd';
383 		hwaddr[3] = rnd >> 16;
384 		hwaddr[4] = rnd >>  8;
385 		hwaddr[5] = rnd >>  0;
386 	}
387 }
388 
389 /*
390  * Stats
391  */
392 
393 static void
394 dwc1000_clear_stats(struct dwc_softc *sc)
395 {
396 	uint32_t reg;
397 
398 	reg = READ4(sc, MMC_CONTROL);
399 	reg |= (MMC_CONTROL_CNTRST);
400 	WRITE4(sc, MMC_CONTROL, reg);
401 }
402 
403 void
404 dwc1000_harvest_stats(struct dwc_softc *sc)
405 {
406 	if_t ifp;
407 
408 	/* We don't need to harvest too often. */
409 	if (++sc->stats_harvest_count < STATS_HARVEST_INTERVAL)
410 		return;
411 
412 	sc->stats_harvest_count = 0;
413 	ifp = sc->ifp;
414 
415 	if_inc_counter(ifp, IFCOUNTER_IERRORS,
416 	    READ4(sc, RXOVERSIZE_G) + READ4(sc, RXUNDERSIZE_G) +
417 	    READ4(sc, RXCRCERROR) + READ4(sc, RXALIGNMENTERROR) +
418 	    READ4(sc, RXRUNTERROR) + READ4(sc, RXJABBERERROR) +
419 	    READ4(sc, RXLENGTHERROR));
420 
421 	if_inc_counter(ifp, IFCOUNTER_OERRORS,
422 	    READ4(sc, TXOVERSIZE_G) + READ4(sc, TXEXCESSDEF) +
423 	    READ4(sc, TXCARRIERERR) + READ4(sc, TXUNDERFLOWERROR));
424 
425 	if_inc_counter(ifp, IFCOUNTER_COLLISIONS,
426 	    READ4(sc, TXEXESSCOL) + READ4(sc, TXLATECOL));
427 
428 	dwc1000_clear_stats(sc);
429 }
430 
431 void
432 dwc1000_intr(struct dwc_softc *sc)
433 {
434 	uint32_t reg;
435 
436 	DWC_ASSERT_LOCKED(sc);
437 
438 	reg = READ4(sc, INTERRUPT_STATUS);
439 	if (reg)
440 		READ4(sc, SGMII_RGMII_SMII_CTRL_STATUS);
441 }
442 
443 void
444 dwc1000_intr_disable(struct dwc_softc *sc)
445 {
446 
447 	WRITE4(sc, INTERRUPT_ENABLE, 0);
448 }
449