xref: /netbsd-src/sys/arch/mips/cavium/dev/octeon_gmx.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
1 /*	$NetBSD: octeon_gmx.c,v 1.3 2017/08/20 11:05:24 maxv Exp $	*/
2 
3 /*
4  * Copyright (c) 2007 Internet Initiative Japan, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 /*
30  *  support GMX0 interface only
31  *  take no thought for other GMX interface
32  */
33 
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: octeon_gmx.c,v 1.3 2017/08/20 11:05:24 maxv Exp $");
36 
37 #include "opt_octeon.h"
38 
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/types.h>
42 #include <sys/cpu.h>
43 #include <sys/device.h>
44 #include <sys/lock.h>
45 #include <sys/cdefs.h>
46 #include <sys/malloc.h>
47 #include <sys/syslog.h>
48 
49 #include <mips/locore.h>
50 #include <mips/include/cpuregs.h>
51 #include <sys/bus.h>
52 
53 #include <mips/cavium/dev/octeon_ciureg.h>
54 #include <mips/cavium/dev/octeon_gmxreg.h>
55 #include <mips/cavium/include/iobusvar.h>
56 #include <mips/cavium/dev/octeon_ipdvar.h>
57 #include <mips/cavium/dev/octeon_asxvar.h>
58 #include <mips/cavium/dev/octeon_gmxvar.h>
59 
60 #define	dprintf(...)
61 #define	OCTEON_ETH_KASSERT	KASSERT
62 
63 #define	ADDR2UINT64(u, a) \
64 	do { \
65 		u = \
66 		    (((uint64_t)a[0] << 40) | ((uint64_t)a[1] << 32) | \
67 		     ((uint64_t)a[2] << 24) | ((uint64_t)a[3] << 16) | \
68 		     ((uint64_t)a[4] <<  8) | ((uint64_t)a[5] <<  0)); \
69 	} while (0)
70 #define	UINT642ADDR(a, u) \
71 	do { \
72 		a[0] = (uint8_t)((u) >> 40); a[1] = (uint8_t)((u) >> 32); \
73 		a[2] = (uint8_t)((u) >> 24); a[3] = (uint8_t)((u) >> 16); \
74 		a[4] = (uint8_t)((u) >>  8); a[5] = (uint8_t)((u) >>  0); \
75 	} while (0)
76 
77 #define	_GMX_RD8(sc, off) \
78 	bus_space_read_8((sc)->sc_port_gmx->sc_regt, (sc)->sc_port_gmx->sc_regh, (off))
79 #define	_GMX_WR8(sc, off, v) \
80 	bus_space_write_8((sc)->sc_port_gmx->sc_regt, (sc)->sc_port_gmx->sc_regh, (off), (v))
81 #define	_GMX_PORT_RD8(sc, off) \
82 	bus_space_read_8((sc)->sc_port_gmx->sc_regt, (sc)->sc_port_regh, (off))
83 #define	_GMX_PORT_WR8(sc, off, v) \
84 	bus_space_write_8((sc)->sc_port_gmx->sc_regt, (sc)->sc_port_regh, (off), (v))
85 
86 struct octeon_gmx_port_ops {
87 	int	(*port_ops_enable)(struct octeon_gmx_port_softc *, int);
88 	int	(*port_ops_speed)(struct octeon_gmx_port_softc *);
89 	int	(*port_ops_timing)(struct octeon_gmx_port_softc *);
90 	int	(*port_ops_set_mac_addr)(struct octeon_gmx_port_softc *,
91 		    uint8_t *, uint64_t);
92 	int	(*port_ops_set_filter)(struct octeon_gmx_port_softc *);
93 };
94 
95 static int	octeon_gmx_match(device_t, struct cfdata *, void *);
96 static void	octeon_gmx_attach(device_t, device_t, void *);
97 static int	octeon_gmx_print(void *, const char *);
98 static int      octeon_gmx_submatch(device_t, struct cfdata *,
99 		    const int *, void *);
100 static int	octeon_gmx_init(struct octeon_gmx_softc *);
101 static int	octeon_gmx_rx_frm_ctl_xable(struct octeon_gmx_port_softc *,
102 		    uint64_t, int);
103 
104 static int	octeon_gmx_rgmii_enable(struct octeon_gmx_port_softc *, int);
105 static int	octeon_gmx_rgmii_speed(struct octeon_gmx_port_softc *);
106 static int	octeon_gmx_rgmii_speed_newlink(struct octeon_gmx_port_softc *,
107 		    uint64_t *);
108 static int	octeon_gmx_rgmii_speed_speed(struct octeon_gmx_port_softc *);
109 static int	octeon_gmx_rgmii_timing(struct octeon_gmx_port_softc *);
110 static int	octeon_gmx_rgmii_set_mac_addr(struct octeon_gmx_port_softc *,
111 		    uint8_t *, uint64_t);
112 static int	octeon_gmx_rgmii_set_filter(struct octeon_gmx_port_softc *);
113 
114 #ifdef OCTEON_ETH_DEBUG
115 void		octeon_gmx_intr_evcnt_attach(struct octeon_gmx_softc *);
116 void		octeon_gmx_dump(void);
117 void		octeon_gmx_debug_reset(void);
118 int		octeon_gmx_intr_drop(void *);
119 #endif
120 
121 static const int	octeon_gmx_rx_adr_cam_regs[] = {
122 	GMX0_RX0_ADR_CAM0, GMX0_RX0_ADR_CAM1, GMX0_RX0_ADR_CAM2,
123 	GMX0_RX0_ADR_CAM3, GMX0_RX0_ADR_CAM4, GMX0_RX0_ADR_CAM5
124 };
125 
126 struct octeon_gmx_port_ops octeon_gmx_port_ops_mii = {
127 	/* XXX not implemented */
128 };
129 
130 struct octeon_gmx_port_ops octeon_gmx_port_ops_gmii = {
131 	.port_ops_enable = octeon_gmx_rgmii_enable,
132 	.port_ops_speed = octeon_gmx_rgmii_speed,
133 	.port_ops_timing = octeon_gmx_rgmii_timing,
134 	.port_ops_set_mac_addr = octeon_gmx_rgmii_set_mac_addr,
135 	.port_ops_set_filter = octeon_gmx_rgmii_set_filter
136 };
137 
138 struct octeon_gmx_port_ops octeon_gmx_port_ops_rgmii = {
139 	.port_ops_enable = octeon_gmx_rgmii_enable,
140 	.port_ops_speed = octeon_gmx_rgmii_speed,
141 	.port_ops_timing = octeon_gmx_rgmii_timing,
142 	.port_ops_set_mac_addr = octeon_gmx_rgmii_set_mac_addr,
143 	.port_ops_set_filter = octeon_gmx_rgmii_set_filter
144 };
145 
146 struct octeon_gmx_port_ops octeon_gmx_port_ops_spi42 = {
147 	/* XXX not implemented */
148 };
149 
150 struct octeon_gmx_port_ops *octeon_gmx_port_ops[] = {
151 	[GMX_MII_PORT] = &octeon_gmx_port_ops_mii,
152 	[GMX_GMII_PORT] = &octeon_gmx_port_ops_gmii,
153 	[GMX_RGMII_PORT] = &octeon_gmx_port_ops_rgmii,
154 	[GMX_SPI42_PORT] = &octeon_gmx_port_ops_spi42
155 };
156 
157 #ifdef OCTEON_ETH_DEBUG
158 static void		*octeon_gmx_intr_drop_ih;
159 struct evcnt		octeon_gmx_intr_drop_evcnt =
160 			    EVCNT_INITIALIZER(EVCNT_TYPE_INTR, NULL, "octeon",
161 			    "gmx drop intr");
162 struct evcnt		octeon_gmx_intr_evcnt =
163 			    EVCNT_INITIALIZER(EVCNT_TYPE_INTR, NULL, "octeon",
164 			    "gmx intr");
165 EVCNT_ATTACH_STATIC(octeon_gmx_intr_drop_evcnt);
166 EVCNT_ATTACH_STATIC(octeon_gmx_intr_evcnt);
167 
168 struct octeon_gmx_port_softc *__octeon_gmx_port_softc[3/* XXX */];
169 #endif
170 
171 CFATTACH_DECL_NEW(octeon_gmx, sizeof(struct octeon_gmx_softc),
172     octeon_gmx_match, octeon_gmx_attach, NULL, NULL);
173 
174 static int
175 octeon_gmx_match(device_t parent, struct cfdata *cf, void *aux)
176 {
177 	struct iobus_attach_args *aa = aux;
178 
179 	if (strcmp(cf->cf_name, aa->aa_name) != 0)
180 		return 0;
181 	if (cf->cf_unit != aa->aa_unitno)
182 		return 0;
183 	return 1;
184 }
185 
186 static void
187 octeon_gmx_attach(device_t parent, device_t self, void *aux)
188 {
189 	struct octeon_gmx_softc *sc = device_private(self);
190 	struct iobus_attach_args *aa = aux;
191 	struct octeon_gmx_attach_args gmx_aa;
192 	int status;
193 	int i;
194 	struct octeon_gmx_port_softc *port_sc;
195 
196 	sc->sc_dev = self;
197 	sc->sc_regt = aa->aa_bust;
198 	sc->sc_unitno = aa->aa_unitno;
199 
200 	aprint_normal("\n");
201 
202 	status = bus_space_map(sc->sc_regt, aa->aa_unit->addr,
203 	    GMX0_BASE_IF_SIZE, 0, &sc->sc_regh);
204 	if (status != 0)
205 		panic(": can't map register");
206 
207 	octeon_gmx_init(sc);
208 
209 	sc->sc_ports = malloc(sizeof(*sc->sc_ports) * sc->sc_nports, M_DEVBUF,
210 	    M_NOWAIT | M_ZERO);
211 
212 	for (i = 0; i < sc->sc_nports; i++) {
213 		port_sc = &sc->sc_ports[i];
214 		port_sc->sc_port_gmx = sc;
215 		port_sc->sc_port_no = i;
216 		port_sc->sc_port_type = sc->sc_port_types[i];
217 		port_sc->sc_port_ops = octeon_gmx_port_ops[port_sc->sc_port_type];
218 		status = bus_space_map(sc->sc_regt,
219 		    aa->aa_unit->addr + GMX0_BASE_PORT_SIZE * i,
220 		    GMX0_BASE_PORT_SIZE, 0, &port_sc->sc_port_regh);
221 		if (status != 0)
222 			panic(": can't map port register");
223 
224 		(void)memset(&gmx_aa, 0, sizeof(gmx_aa));
225 		gmx_aa.ga_regt = aa->aa_bust;
226 		gmx_aa.ga_addr = aa->aa_unit->addr;
227 		gmx_aa.ga_name = "cnmac";
228 		gmx_aa.ga_portno = i;
229 		gmx_aa.ga_port_type = sc->sc_port_types[i];
230 		gmx_aa.ga_gmx = sc;
231 		gmx_aa.ga_gmx_port = port_sc;
232 		config_found_sm_loc(self, "octeon_gmx", NULL, &gmx_aa,
233 		    octeon_gmx_print, octeon_gmx_submatch);
234 
235 #ifdef OCTEON_ETH_DEBUG
236 		__octeon_gmx_port_softc[i] = port_sc;
237 #endif
238 	}
239 
240 #ifdef OCTEON_ETH_DEBUG
241 	octeon_gmx_intr_evcnt_attach(sc);
242 	if (octeon_gmx_intr_drop_ih == NULL)
243 		octeon_gmx_intr_drop_ih = octeon_intr_establish(
244 		   ffs64(CIU_INTX_SUM0_GMX_DRP) - 1, IPL_NET,
245 		   octeon_gmx_intr_drop, NULL);
246 #endif
247 }
248 
249 static int
250 octeon_gmx_print(void *aux, const char *pnp)
251 {
252 	struct octeon_gmx_attach_args *ga = aux;
253 	static const char *types[] = {
254 		[GMX_MII_PORT] = "MII",
255 		[GMX_GMII_PORT] = "GMII",
256 		[GMX_RGMII_PORT] = "RGMII"
257 	};
258 
259 #if DEBUG
260 	if (pnp)
261 		aprint_normal("%s at %s\n", ga->ga_name, pnp);
262 #endif
263 
264 	aprint_normal(": address=0x%016" PRIx64 ": %s\n", ga->ga_addr,
265 	    types[ga->ga_port_type]);
266 
267 	return UNCONF;
268 }
269 
270 static int
271 octeon_gmx_submatch(device_t parent, struct cfdata *cf,
272     const int *ldesc, void *aux)
273 {
274 	return config_match(parent, cf, aux);
275 }
276 
277 static int
278 octeon_gmx_init(struct octeon_gmx_softc *sc)
279 {
280 	int result = 0;
281 	uint64_t inf_mode;
282 	/* XXX */
283 	const mips_prid_t cpu_id = mips_options.mips_cpu_id;
284 
285 	inf_mode = bus_space_read_8(sc->sc_regt, sc->sc_regh, GMX0_INF_MODE);
286 	if ((inf_mode & INF_MODE_EN) == 0) {
287 		aprint_normal("port are disable\n");
288 		sc->sc_nports = 0;
289 		return 1;
290 	}
291 
292 	if (MIPS_PRID_CID(cpu_id) != MIPS_PRID_CID_CAVIUM)
293 		return 1;
294 
295 	switch (MIPS_PRID_IMPL(cpu_id)) {
296 	case MIPS_CN31XX:
297 		/*
298 		 * Packet Interface Configuration
299 		 * GMX Registers, Interface Mode Register, GMX0_INF_MODE
300 		 */
301 		if ((inf_mode & INF_MODE_TYPE) == 0) {
302 			/* all three ports configured as RGMII */
303 			sc->sc_nports = 3;
304 			sc->sc_port_types[0] = GMX_RGMII_PORT;
305 			sc->sc_port_types[1] = GMX_RGMII_PORT;
306 			sc->sc_port_types[2] = GMX_RGMII_PORT;
307 		} else {
308 			/* port 0: RGMII, port 1: GMII, port 2: disabled */
309 			sc->sc_nports = 2;
310 			sc->sc_port_types[0] = GMX_RGMII_PORT;
311 			sc->sc_port_types[1] = GMX_GMII_PORT;
312 		}
313 		break;
314 	case MIPS_CN30XX:
315 	case MIPS_CN50XX:
316 		/*
317 		 * Packet Interface Configuration
318 		 * GMX Registers, Interface Mode Register, GMX0_INF_MODE
319 		 */
320 		if ((inf_mode & INF_MODE_P0MII) == 0)
321 			sc->sc_port_types[0] = GMX_RGMII_PORT;
322 		else
323 			sc->sc_port_types[0] = GMX_MII_PORT;
324 		if ((inf_mode & INF_MODE_TYPE) == 0) {
325 			/* port 1 and 2 are configred as RGMII ports */
326 			sc->sc_nports = 3;
327 			sc->sc_port_types[1] = GMX_RGMII_PORT;
328 			sc->sc_port_types[2] = GMX_RGMII_PORT;
329 		} else {
330 			/* port 1: GMII/MII, port 2: disabled */
331 			/* GMII or MII port is slected by GMX_PRT1_CFG[SPEED] */
332 			sc->sc_nports = 2;
333 			sc->sc_port_types[1] = GMX_GMII_PORT;
334 		}
335 #if 0 /* XXX XXX XXX */
336 		/* port 2 is in CN3010/CN5010 only */
337 		if ((octeon_model(id) != OCTEON_MODEL_CN3010) &&
338 		    (octeon_model(id) != OCTEON_MODEL_CN5010))
339 			if (sc->sc_nports == 3)
340 				sc->sc_nports = 2;
341 #endif
342 		break;
343 	default:
344 		aprint_normal("unsupported octeon model: 0x%x\n", cpu_id);
345 		sc->sc_nports = 0;
346 		result = 1;
347 		break;
348 	}
349 
350 	return result;
351 }
352 
353 /* XXX RGMII specific */
354 int
355 octeon_gmx_link_enable(struct octeon_gmx_port_softc *sc, int enable)
356 {
357 	uint64_t prt_cfg;
358 
359 	octeon_gmx_tx_int_enable(sc, enable);
360 	octeon_gmx_rx_int_enable(sc, enable);
361 
362 	prt_cfg = _GMX_PORT_RD8(sc, GMX0_PRT0_CFG);
363 	if (enable) {
364 		if (octeon_gmx_link_status(sc)) {
365 			SET(prt_cfg, PRTN_CFG_EN);
366 		}
367 	} else {
368 		CLR(prt_cfg, PRTN_CFG_EN);
369 	}
370 	_GMX_PORT_WR8(sc, GMX0_PRT0_CFG, prt_cfg);
371 	/* software should read back to flush the write operation. */
372 	(void)_GMX_PORT_RD8(sc, GMX0_PRT0_CFG);
373 
374 	return 0;
375 }
376 
377 /* XXX RGMII specific */
378 int
379 octeon_gmx_stats_init(struct octeon_gmx_port_softc *sc)
380 {
381         _GMX_PORT_WR8(sc, GMX0_RX0_STATS_PKTS, 0x0ULL);
382         _GMX_PORT_WR8(sc, GMX0_RX0_STATS_PKTS_DRP, 0x0ULL);
383         _GMX_PORT_WR8(sc, GMX0_RX0_STATS_PKTS_BAD, 0x0ULL);
384         _GMX_PORT_WR8(sc, GMX0_TX0_STAT0, 0x0ULL);
385         _GMX_PORT_WR8(sc, GMX0_TX0_STAT1, 0x0ULL);
386         _GMX_PORT_WR8(sc, GMX0_TX0_STAT3, 0x0ULL);
387         _GMX_PORT_WR8(sc, GMX0_TX0_STAT9, 0x0ULL);
388 
389 	return 0;
390 }
391 
392 int
393 octeon_gmx_tx_stats_rd_clr(struct octeon_gmx_port_softc *sc, int enable)
394 {
395 	_GMX_PORT_WR8(sc, GMX0_TX0_STATS_CTL, enable ? 0x1ULL : 0x0ULL);
396 	return 0;
397 }
398 
399 int
400 octeon_gmx_rx_stats_rd_clr(struct octeon_gmx_port_softc *sc, int enable)
401 {
402 	_GMX_PORT_WR8(sc, GMX0_RX0_STATS_CTL, enable ? 0x1ULL : 0x0ULL);
403 	return 0;
404 }
405 
406 void
407 octeon_gmx_rx_stats_dec_bad(struct octeon_gmx_port_softc *sc)
408 {
409 	uint64_t tmp;
410 
411         tmp = _GMX_PORT_RD8(sc, GMX0_RX0_STATS_PKTS_BAD);
412 	_GMX_PORT_WR8(sc, GMX0_RX0_STATS_PKTS_BAD, tmp - 1);
413 }
414 
415 static int
416 octeon_gmx_tx_ovr_bp_enable(struct octeon_gmx_port_softc *sc, int enable)
417 {
418 	uint64_t ovr_bp;
419 
420 	ovr_bp = _GMX_RD8(sc, GMX0_TX_OVR_BP);
421 	if (enable) {
422 		CLR(ovr_bp, (1 << sc->sc_port_no) << TX_OVR_BP_EN_SHIFT);
423 		SET(ovr_bp, (1 << sc->sc_port_no) << TX_OVR_BP_BP_SHIFT);
424 		/* XXX really??? */
425 		SET(ovr_bp, (1 << sc->sc_port_no) << TX_OVR_BP_IGN_FULL_SHIFT);
426 	} else {
427 		SET(ovr_bp, (1 << sc->sc_port_no) << TX_OVR_BP_EN_SHIFT);
428 		CLR(ovr_bp, (1 << sc->sc_port_no) << TX_OVR_BP_BP_SHIFT);
429 		/* XXX really??? */
430 		SET(ovr_bp, (1 << sc->sc_port_no) << TX_OVR_BP_IGN_FULL_SHIFT);
431 	}
432 	_GMX_WR8(sc, GMX0_TX_OVR_BP, ovr_bp);
433 	return 0;
434 }
435 
436 static int
437 octeon_gmx_rx_pause_enable(struct octeon_gmx_port_softc *sc, int enable)
438 {
439 	if (enable) {
440 		octeon_gmx_rx_frm_ctl_enable(sc, RXN_FRM_CTL_CTL_BCK);
441 	} else {
442 		octeon_gmx_rx_frm_ctl_disable(sc, RXN_FRM_CTL_CTL_BCK);
443 	}
444 
445 	return 0;
446 }
447 
448 void
449 octeon_gmx_tx_int_enable(struct octeon_gmx_port_softc *sc, int enable)
450 {
451 	uint64_t tx_int_xxx = 0;
452 
453 	SET(tx_int_xxx,
454 	    TX_INT_REG_LATE_COL |
455 	    TX_INT_REG_XSDEF |
456 	    TX_INT_REG_XSCOL |
457 	    TX_INT_REG_UNDFLW |
458 	    TX_INT_REG_PKO_NXA);
459 	_GMX_WR8(sc, GMX0_TX_INT_REG, tx_int_xxx);
460 	_GMX_WR8(sc, GMX0_TX_INT_EN, enable ? tx_int_xxx : 0);
461 }
462 
463 void
464 octeon_gmx_rx_int_enable(struct octeon_gmx_port_softc *sc, int enable)
465 {
466 	uint64_t rx_int_xxx = 0;
467 
468 	SET(rx_int_xxx, 0 |
469 	    RXN_INT_REG_PHY_DUPX |
470 	    RXN_INT_REG_PHY_SPD |
471 	    RXN_INT_REG_PHY_LINK |
472 	    RXN_INT_REG_IFGERR |
473 	    RXN_INT_REG_COLDET |
474 	    RXN_INT_REG_FALERR |
475 	    RXN_INT_REG_RSVERR |
476 	    RXN_INT_REG_PCTERR |
477 	    RXN_INT_REG_OVRERR |
478 	    RXN_INT_REG_NIBERR |
479 	    RXN_INT_REG_SKPERR |
480 	    RXN_INT_REG_RCVERR |
481 	    RXN_INT_REG_LENERR |
482 	    RXN_INT_REG_ALNERR |
483 	    RXN_INT_REG_FCSERR |
484 	    RXN_INT_REG_JABBER |
485 	    RXN_INT_REG_MAXERR |
486 	    RXN_INT_REG_CAREXT |
487 	    RXN_INT_REG_MINERR);
488 	_GMX_PORT_WR8(sc, GMX0_RX0_INT_REG, rx_int_xxx);
489 	_GMX_PORT_WR8(sc, GMX0_RX0_INT_EN, enable ? rx_int_xxx : 0);
490 }
491 
492 int
493 octeon_gmx_rx_frm_ctl_enable(struct octeon_gmx_port_softc *sc,
494     uint64_t rx_frm_ctl)
495 {
496 	/*
497 	 * XXX Jumbo-frame Workarounds
498 	 *     Current implementation of cnmac is required to
499 	 *     configure GMX0_RX0_JABBER[CNT] as follows:
500 	 *	RX0_FRM_MAX(1536) <= GMX0_RX0_JABBER <= 1536(0x600)
501 	 */
502 	_GMX_PORT_WR8(sc, GMX0_RX0_JABBER, GMX_FRM_MAX_SIZ);
503 
504 	return octeon_gmx_rx_frm_ctl_xable(sc, rx_frm_ctl, 1);
505 }
506 
507 int
508 octeon_gmx_rx_frm_ctl_disable(struct octeon_gmx_port_softc *sc,
509     uint64_t rx_frm_ctl)
510 {
511 	return octeon_gmx_rx_frm_ctl_xable(sc, rx_frm_ctl, 0);
512 }
513 
514 static int
515 octeon_gmx_rx_frm_ctl_xable(struct octeon_gmx_port_softc *sc,
516     uint64_t rx_frm_ctl, int enable)
517 {
518 	uint64_t tmp;
519 
520 	tmp = _GMX_PORT_RD8(sc, GMX0_RX0_FRM_CTL);
521 	if (enable)
522 		SET(tmp, rx_frm_ctl);
523 	else
524 		CLR(tmp, rx_frm_ctl);
525 	_GMX_PORT_WR8(sc, GMX0_RX0_FRM_CTL, tmp);
526 
527 	return 0;
528 }
529 
530 int
531 octeon_gmx_tx_thresh(struct octeon_gmx_port_softc *sc, int cnt)
532 {
533 	_GMX_PORT_WR8(sc, GMX0_TX0_THRESH, cnt);
534 	return 0;
535 }
536 
537 int
538 octeon_gmx_set_mac_addr(struct octeon_gmx_port_softc *sc, uint8_t *addr)
539 {
540 	uint64_t mac = 0;
541 
542 	ADDR2UINT64(mac, addr);
543 	(*sc->sc_port_ops->port_ops_set_mac_addr)(sc, addr, mac);
544 	return 0;
545 }
546 
547 int
548 octeon_gmx_set_filter(struct octeon_gmx_port_softc *sc)
549 {
550 	(*sc->sc_port_ops->port_ops_set_filter)(sc);
551 	return 0;
552 }
553 
554 int
555 octeon_gmx_port_enable(struct octeon_gmx_port_softc *sc, int enable)
556 {
557 	(*sc->sc_port_ops->port_ops_enable)(sc, enable);
558 	return 0;
559 }
560 
561 int
562 octeon_gmx_reset_speed(struct octeon_gmx_port_softc *sc)
563 {
564 	struct ifnet *ifp = &sc->sc_port_ec->ec_if;
565 	if (ISSET(sc->sc_port_mii->mii_flags, MIIF_DOINGAUTO)) {
566 		log(LOG_WARNING,
567 		    "%s: autonegotiation has not been completed yet\n",
568 		    ifp->if_xname);
569 		return 1;
570 	}
571 	(*sc->sc_port_ops->port_ops_speed)(sc);
572 	return 0;
573 }
574 
575 int
576 octeon_gmx_reset_timing(struct octeon_gmx_port_softc *sc)
577 {
578 	(*sc->sc_port_ops->port_ops_timing)(sc);
579 	return 0;
580 }
581 
582 int
583 octeon_gmx_reset_flowctl(struct octeon_gmx_port_softc *sc)
584 {
585 	struct ifmedia_entry *ife = sc->sc_port_mii->mii_media.ifm_cur;
586 
587 	/*
588 	 * Get flow control negotiation result.
589 	 */
590 	if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO &&
591 	    (sc->sc_port_mii->mii_media_active & IFM_ETH_FMASK) !=
592 			sc->sc_port_flowflags) {
593 		sc->sc_port_flowflags =
594 			sc->sc_port_mii->mii_media_active & IFM_ETH_FMASK;
595 		sc->sc_port_mii->mii_media_active &= ~IFM_ETH_FMASK;
596 	}
597 
598 	/*
599 	 * 802.3x Flow Control Capabilities
600 	 */
601 	if (sc->sc_port_flowflags & IFM_ETH_TXPAUSE) {
602 		octeon_gmx_tx_ovr_bp_enable(sc, 1);
603 	} else {
604 		octeon_gmx_tx_ovr_bp_enable(sc, 0);
605 	}
606 	if (sc->sc_port_flowflags & IFM_ETH_RXPAUSE) {
607 		octeon_gmx_rx_pause_enable(sc, 1);
608 	} else {
609 		octeon_gmx_rx_pause_enable(sc, 0);
610 	}
611 
612 	return 0;
613 }
614 
615 static int
616 octeon_gmx_rgmii_enable(struct octeon_gmx_port_softc *sc, int enable)
617 {
618 	uint64_t mode;
619 
620 	/* XXX XXX XXX */
621 	mode = _GMX_RD8(sc, GMX0_INF_MODE);
622 	if (ISSET(mode, INF_MODE_EN)) {
623 		octeon_asx_enable(sc->sc_port_asx, 1);
624 	}
625 	/* XXX XXX XXX */
626 	return 0;
627 }
628 
629 static int
630 octeon_gmx_rgmii_speed(struct octeon_gmx_port_softc *sc)
631 {
632 	struct ifnet *ifp = &sc->sc_port_ec->ec_if;
633 	uint64_t newlink;
634 	int baudrate;
635 
636 	/* XXX XXX XXX */
637 	octeon_gmx_link_enable(sc, 1);
638 
639 	octeon_gmx_rgmii_speed_newlink(sc, &newlink);
640 	if (sc->sc_link == newlink) {
641 		return 0;
642 	}
643 	sc->sc_link = newlink;
644 
645 	switch (sc->sc_link & RXN_RX_INBND_SPEED) {
646 	case RXN_RX_INBND_SPEED_2_5:
647 		baudrate = IF_Mbps(10);
648 		break;
649 	case RXN_RX_INBND_SPEED_25:
650 		baudrate = IF_Mbps(100);
651 		break;
652 	case RXN_RX_INBND_SPEED_125:
653 		baudrate = IF_Mbps(1000);
654 		break;
655 	default:
656 		baudrate = 0/* XXX */;
657 		panic("unable to get baudrate");
658 		break;
659 	}
660 	ifp->if_baudrate = baudrate;
661 
662 	/* XXX XXX XXX */
663 
664 	octeon_gmx_link_enable(sc, 0);
665 
666 	/*
667 	 * wait a max_packet_time
668 	 * max_packet_time(us) = (max_packet_size(bytes) * 8) / link_speed(Mbps)
669 	 */
670 	delay((GMX_FRM_MAX_SIZ * 8) / (baudrate / 1000000));
671 
672 	octeon_gmx_rgmii_speed_speed(sc);
673 
674 	octeon_gmx_link_enable(sc, 1);
675 	octeon_asx_enable(sc->sc_port_asx, 1);
676 
677 	return 0;
678 }
679 
680 static int
681 octeon_gmx_rgmii_speed_newlink(struct octeon_gmx_port_softc *sc,
682     uint64_t *rnewlink)
683 {
684 	uint64_t newlink = 0;
685 
686 	if (sc->sc_quirks & OCTEON_ETH_QUIRKS_NO_RX_INBND) {
687 		newlink = 0;
688 		switch (IFM_SUBTYPE(sc->sc_port_mii->mii_media_active)) {
689 		default:
690 			SET(newlink, RXN_RX_INBND_SPEED_125);
691 			break;
692 		case IFM_100_TX:
693 			SET(newlink, RXN_RX_INBND_SPEED_25);
694 			break;
695 		case IFM_10_T:
696 			SET(newlink, RXN_RX_INBND_SPEED_2_5);
697 			break;
698 		}
699 		SET(newlink,
700 		    ISSET(sc->sc_port_mii->mii_media_active, IFM_FDX) ?
701 		    RXN_RX_INBND_DUPLEX : 0);
702 		SET(newlink,
703 		    ISSET(sc->sc_port_mii->mii_media_status, IFM_ACTIVE) ?
704 		    RXN_RX_INBND_STATUS : 0);
705 	} else {
706 		newlink = _GMX_PORT_RD8(sc, GMX0_RX0_RX_INBND);
707 	}
708 
709 	*rnewlink = newlink;
710 	return 0;
711 }
712 
713 static int
714 octeon_gmx_rgmii_speed_speed(struct octeon_gmx_port_softc *sc)
715 {
716 	uint64_t prt_cfg;
717 	uint64_t tx_clk, tx_slot, tx_burst;
718 
719 	prt_cfg = _GMX_PORT_RD8(sc, GMX0_PRT0_CFG);
720 
721 	switch (sc->sc_link & RXN_RX_INBND_SPEED) {
722 	case RXN_RX_INBND_SPEED_2_5:
723 		/* 10Mbps */
724 		/*
725 		 * GMX Tx Clock Generation Registers
726 		 * 8ns x 50 = 400ns (2.5MHz TXC clock)
727 		 */
728 		tx_clk = 50;
729 		/*
730 		 * TX Slottime Counter Registers
731 		 * 10/100Mbps: set SLOT to 0x40
732 		 */
733 		tx_slot = 0x40;
734 		/*
735 		 * TX Burst-Counter Registers
736 		 * 10/100Mbps: set BURST to 0x0
737 		 */
738 		tx_burst = 0;
739 		/*
740 		 * GMX Tx Port Configuration Registers
741 		 * Slot time for half-duplex operation
742 		 *   0 = 512 bittimes (10/100Mbps operation)
743 		 */
744 		CLR(prt_cfg, PRTN_CFG_SLOTTIME);
745 		/*
746 		 * GMX Port Configuration Registers
747 		 * Link speed
748 		 *   0 = 10/100Mbps operation
749 		 *     in RGMII mode: GMX0_TX(0..2)_CLK[CLK_CNT] > 1
750 		 */
751 		CLR(prt_cfg, PRTN_CFG_SPEED);
752 		break;
753 	case RXN_RX_INBND_SPEED_25:
754 		/* 100Mbps */
755 		/*
756 		 * GMX Tx Clock Generation Registers
757 		 *  8ns x 5 = 40ns (25.0MHz TXC clock)
758 		 */
759 		tx_clk = 5;
760 		/*
761 		 * TX Slottime Counter Registers
762 		 *  10/100Mbps: set SLOT to 0x40
763 		 */
764 		tx_slot = 0x40;
765 		/*
766 		 * TX Burst-Counter Registers
767 		 *  10/100Mbps: set BURST to 0x0
768 		 */
769 		tx_burst = 0;
770 		/*
771 		 * GMX Tx Port Configuration Registers
772 		 *  Slot time for half-duplex operation
773 		 *    0 = 512 bittimes (10/100Mbps operation)
774 		 */
775 		CLR(prt_cfg, PRTN_CFG_SLOTTIME);
776 		/*
777 		 * GMX Port Configuration Registers
778 		 *  Link speed
779 		 *    0 = 10/100Mbps operation
780 		 *      in RGMII mode: GMX0_TX(0..2)_CLK[CLK_CNT] > 1
781 		 */
782 		CLR(prt_cfg, PRTN_CFG_SPEED);
783 		break;
784 	case RXN_RX_INBND_SPEED_125:
785 		/* 1000Mbps */
786 		/*
787 		 * GMX Tx Clock Generation Registers
788 		 *  8ns x 1 = 8ns (125.0MHz TXC clock)
789 		 */
790 		tx_clk = 1;
791 		/*
792 		 * TX Slottime Counter Registers
793 		 * > 1000Mbps: set SLOT to 0x200
794 		 */
795 		tx_slot = 0x200;
796 		/*
797 		 * "TX Burst-Counter Registers
798 		 * > 1000Mbps: set BURST to 0x2000
799 		 */
800 		tx_burst = 0x2000;
801 		/*
802 		 * GMX Tx Port Configuration Registers
803 		 *  Slot time for half-duplex operation
804 		 *    1 = 4096 bittimes (1000Mbps operation)
805 		 */
806 		SET(prt_cfg, PRTN_CFG_SLOTTIME);
807 		/*
808 		 * GMX Port Configuration Registers
809 		 *  Link speed
810 		 *    1 = 1000Mbps operation
811 		 */
812 		SET(prt_cfg, PRTN_CFG_SPEED);
813 		break;
814 	default:
815 		/* NOT REACHED! */
816 		/* Following configuration is default value of system.
817 		*/
818 		tx_clk = 1;
819 		tx_slot = 0x200;
820 		tx_burst = 0x2000;
821 		SET(prt_cfg, PRTN_CFG_SLOTTIME);
822 		SET(prt_cfg, PRTN_CFG_SPEED);
823 		break;
824 	}
825 
826 	/* Setup Duplex mode(negotiated) */
827 	/*
828 	 * GMX Port Configuration Registers
829 	 *  Duplex mode: 0 = half-duplex mode, 1=full-duplex
830 	 */
831 	if (ISSET(sc->sc_link, RXN_RX_INBND_DUPLEX)) {
832 		/* Full-Duplex */
833 		SET(prt_cfg, PRTN_CFG_DUPLEX);
834 	} else {
835 		/* Half-Duplex */
836 		CLR(prt_cfg, PRTN_CFG_DUPLEX);
837 	}
838 
839 	_GMX_PORT_WR8(sc, GMX0_TX0_CLK, tx_clk);
840 	_GMX_PORT_WR8(sc, GMX0_TX0_SLOT, tx_slot);
841 	_GMX_PORT_WR8(sc, GMX0_TX0_BURST, tx_burst);
842 	_GMX_PORT_WR8(sc, GMX0_PRT0_CFG, prt_cfg);
843 
844 	return 0;
845 }
846 
847 static int
848 octeon_gmx_rgmii_timing(struct octeon_gmx_port_softc *sc)
849 {
850 	prop_dictionary_t dict = device_properties(sc->sc_port_gmx->sc_dev);
851 	prop_object_t clk;
852 	int clk_tx_setting, clk_rx_setting;
853 	uint64_t rx_frm_ctl;
854 
855 	/* RGMII TX Threshold Registers
856 	 * Number of 16-byte ticks to accumulate in the TX FIFO before
857 	 * sending on the RGMII interface. This field should be large
858 	 * enough to prevent underflow on the RGMII interface and must
859 	 * never be set to less than 0x4. This register cannot exceed
860 	 * the TX FIFO depth of 0x40 words.
861 	 */
862 	/* Default parameter of CN30XX */
863 	octeon_gmx_tx_thresh(sc, 32);
864 
865 	rx_frm_ctl = 0 |
866 	    /* RXN_FRM_CTL_NULL_DIS |	(cn5xxx only) */
867 	    /* RXN_FRM_CTL_PRE_ALIGN |	(cn5xxx only) */
868 	    /* RXN_FRM_CTL_PAD_LEN |	(cn3xxx only) */
869 	    /* RXN_FRM_CTL_VLAN_LEN |	(cn3xxx only) */
870 	    RXN_FRM_CTL_PRE_FREE |
871 	    RXN_FRM_CTL_CTL_SMAC |
872 	    RXN_FRM_CTL_CTL_MCST |
873 	    RXN_FRM_CTL_CTL_DRP |
874 	    RXN_FRM_CTL_PRE_STRP |
875 	    RXN_FRM_CTL_PRE_CHK;
876 	if (!(sc->sc_quirks & OCTEON_ETH_QUIRKS_NO_PRE_ALIGN))
877 		rx_frm_ctl |= RXN_FRM_CTL_PRE_ALIGN;
878 	octeon_gmx_rx_frm_ctl_enable(sc, rx_frm_ctl);
879 
880 	/* RGMII RX Clock-Delay Registers
881 	 * Delay setting to place n RXC (RGMII receive clock) delay line.
882 	 * The intrinsic delay can range from 50ps to 80ps per tap,
883 	 * which corresponds to skews of 1.25ns to 2.00ns at 25 taps(CSR+1).
884 	 * This is the best match for the RGMII specification which wants
885 	 * 1ns - 2.6ns of skew.
886 	 */
887 	/* RGMII TX Clock-Delay Registers
888 	 * Delay setting to place n TXC (RGMII transmit clock) delay line.
889 	 */
890 	clk = prop_dictionary_get(dict, "rgmii-tx");
891 	KASSERT(clk != NULL);
892 	clk_tx_setting = prop_number_integer_value(clk);
893 	clk = prop_dictionary_get(dict, "rgmii-rx");
894 	KASSERT(clk != NULL);
895 	clk_rx_setting = prop_number_integer_value(clk);
896 
897 	octeon_asx_clk_set(sc->sc_port_asx, clk_tx_setting, clk_rx_setting);
898 
899 	return 0;
900 }
901 
902 static int
903 octeon_gmx_rgmii_set_mac_addr(struct octeon_gmx_port_softc *sc, uint8_t *addr,
904     uint64_t mac)
905 {
906 	int i;
907 
908 	octeon_gmx_link_enable(sc, 0);
909 
910 	sc->sc_mac = mac;
911 	_GMX_PORT_WR8(sc, GMX0_SMAC0, mac);
912 	for (i = 0; i < 6; i++)
913 		_GMX_PORT_WR8(sc, octeon_gmx_rx_adr_cam_regs[i], addr[i]);
914 
915 	octeon_gmx_link_enable(sc, 1);
916 
917 	return 0;
918 }
919 
920 #define	OCTEON_ETH_USE_GMX_CAM
921 
922 static int
923 octeon_gmx_rgmii_set_filter(struct octeon_gmx_port_softc *sc)
924 {
925 	struct ifnet *ifp = &sc->sc_port_ec->ec_if;
926 #ifdef OCTEON_ETH_USE_GMX_CAM
927 	struct ether_multi *enm;
928 	struct ether_multistep step;
929 #endif
930 	uint64_t ctl = 0;
931 	int multi = 0;
932 	/* XXX XXX XXX */
933 	uint64_t cam_en = 0x01ULL;
934 	/* XXX XXX XXX */
935 
936 	octeon_gmx_link_enable(sc, 0);
937 
938 	if (ISSET(ifp->if_flags, IFF_BROADCAST)) {
939 		dprintf("accept broadcast\n");
940 		SET(ctl, RXN_ADR_CTL_BCST);
941 	}
942 	if (ISSET(ifp->if_flags, IFF_PROMISC)) {
943 		dprintf("promiscas(reject cam)\n");
944 		CLR(ctl, RXN_ADR_CTL_CAM_MODE);
945 	} else {
946 		dprintf("not promiscas(accept cam)\n");
947 		SET(ctl, RXN_ADR_CTL_CAM_MODE);
948 	}
949 
950 #ifdef OCTEON_ETH_USE_GMX_CAM
951 	/*
952 	 * Note first entry is self MAC address; other 7 entires are available
953 	 * for multicast addresses.
954 	 */
955 
956 	ETHER_FIRST_MULTI(step, sc->sc_port_ec, enm);
957 	while (enm != NULL) {
958 		int i;
959 
960 		dprintf("%d: lo(%02x:%02x:%02x:%02x:%02x:%02x) - "
961 		    "hi(%02x:%02x:%02x:%02x:%02x:%02x)\n",
962 		    multi + 1,
963 		    enm->enm_addrlo[0], enm->enm_addrlo[1],
964 		    enm->enm_addrlo[2], enm->enm_addrlo[3],
965 		    enm->enm_addrlo[4], enm->enm_addrlo[5],
966 		    enm->enm_addrhi[0], enm->enm_addrhi[1],
967 		    enm->enm_addrhi[2], enm->enm_addrhi[3],
968 		    enm->enm_addrhi[4], enm->enm_addrhi[5]);
969 		if (bcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) {
970 			dprintf("all multicast\n");
971 			SET(ifp->if_flags, IFF_ALLMULTI);
972 			goto setmulti;
973 		}
974 		multi++;
975 
976 		/* XXX XXX XXX */
977 		if (multi >= 8) {
978 			SET(ifp->if_flags, IFF_ALLMULTI);
979 			goto setmulti;
980 		}
981 		/* XXX XXX XXX */
982 
983 		/* XXX XXX XXX */
984 		SET(cam_en, 1ULL << multi);
985 		/* XXX XXX XXX */
986 
987 		for (i = 0; i < 6; i++) {
988 			uint64_t tmp;
989 
990 			/* XXX XXX XXX */
991 			tmp = _GMX_PORT_RD8(sc, octeon_gmx_rx_adr_cam_regs[i]);
992 			CLR(tmp, 0xffULL << (8 * multi));
993 			SET(tmp, (uint64_t)enm->enm_addrlo[i] << (8 * multi));
994 			_GMX_PORT_WR8(sc, octeon_gmx_rx_adr_cam_regs[i], tmp);
995 			/* XXX XXX XXX */
996 
997 		}
998 		for (i = 0; i < 6; i++)
999 			dprintf("cam%d = %016llx\n", i,
1000 			    _GMX_PORT_RD8(sc, octeon_gmx_rx_adr_cam_regs[i]));
1001 		ETHER_NEXT_MULTI(step, enm);
1002 	}
1003 	CLR(ifp->if_flags, IFF_ALLMULTI);
1004 
1005 	OCTEON_ETH_KASSERT(enm == NULL);
1006 #else
1007 	/*
1008 	 * XXX
1009 	 * Never use DMAC filter for multicast addresses, but register only
1010 	 * single entry for self address. FreeBSD code do so.
1011 	 */
1012 	SET(ifp->if_flags, IFF_ALLMULTI);
1013 	goto setmulti;
1014 #endif
1015 
1016 setmulti:
1017 	/* XXX XXX XXX */
1018 	if (ISSET(ifp->if_flags, IFF_ALLMULTI) ||
1019 	    ISSET(ifp->if_flags, IFF_PROMISC)) {
1020 		/* XXX XXX XXX */
1021 		dprintf("accept all multicast\n");
1022 		SET(ctl, RXN_ADR_CTL_MCST_ACCEPT);
1023 		/* XXX XXX XXX */
1024 	} else if (multi) {
1025 		/* XXX XXX XXX */
1026 		dprintf("use cam\n");
1027 		SET(ctl, RXN_ADR_CTL_MCST_AFCAM);
1028 		/* XXX XXX XXX */
1029 	} else {
1030 		/* XXX XXX XXX */
1031 		dprintf("reject all multicast\n");
1032 		SET(ctl, RXN_ADR_CTL_MCST_REJECT);
1033 		/* XXX XXX XXX */
1034 	}
1035 	/* XXX XXX XXX */
1036 
1037 	/* XXX XXX XXX */
1038 	if (ISSET(ifp->if_flags, IFF_PROMISC)) {
1039 		cam_en = 0x00ULL;
1040 	} else if (ISSET(ifp->if_flags, IFF_ALLMULTI)) {
1041 		cam_en = 0x01ULL;
1042 	}
1043 	/* XXX XXX XXX */
1044 
1045 	dprintf("ctl = %llx, cam_en = %llx\n", ctl, cam_en);
1046 	_GMX_PORT_WR8(sc, GMX0_RX0_ADR_CTL, ctl);
1047 	_GMX_PORT_WR8(sc, GMX0_RX0_ADR_CAM_EN, cam_en);
1048 
1049 	octeon_gmx_link_enable(sc, 1);
1050 
1051 	return 0;
1052 }
1053 
1054 void
1055 octeon_gmx_stats(struct octeon_gmx_port_softc *sc)
1056 {
1057 	struct ifnet *ifp = &sc->sc_port_ec->ec_if;
1058 	uint64_t tmp;
1059 
1060 	/*
1061 	 *  GMX0_RX0_STATS_PKTS is not count.
1062          *  input packet is counted when recepted packet in if_cnmac.
1063          */
1064 	/*
1065          *  GMX0_RX0_STATS_PKTS_BAD count is included
1066          *  receive error of work queue entry.
1067          *  this is not add to input packet errors of interface.
1068          */
1069 	ifp->if_iqdrops +=
1070 	    (uint32_t)_GMX_PORT_RD8(sc, GMX0_RX0_STATS_PKTS_DRP);
1071 	ifp->if_opackets +=
1072 	    (uint32_t)_GMX_PORT_RD8(sc, GMX0_TX0_STAT3);
1073 
1074 	tmp = _GMX_PORT_RD8(sc, GMX0_TX0_STAT0);
1075 	ifp->if_oerrors +=
1076 	    (uint32_t)tmp + ((uint32_t)(tmp >> 32) * 16);
1077 	ifp->if_collisions += (uint32_t)tmp;
1078 #if IFETHER_DOT3STATS
1079 	/* dot3StatsExcessiveCollisions */
1080 	ifp->if_data.ifi_dot3stats.if_oexsvcols += (uint32_t)tmp;
1081 #endif
1082 
1083 	tmp = _GMX_PORT_RD8(sc, GMX0_TX0_STAT1);
1084 	ifp->if_collisions +=
1085 	    (uint32_t)tmp + (uint32_t)(tmp >> 32);
1086 #if IFETHER_DOT3STATS
1087 	/* dot3StatsSingleCollisionFrames */
1088 	ifp->if_data.ifi_dot3stats.if_oscols += (uint32_t)(tmp >> 32);
1089 	/* dot3StatsMultipleCollisionFrames */
1090 	ifp->if_data.ifi_dot3stats.if_omcols += (uint32_t)tmp;
1091 #endif
1092 
1093 	tmp = _GMX_PORT_RD8(sc, GMX0_TX0_STAT9);
1094 	ifp->if_oerrors += (uint32_t)(tmp >> 32);
1095 }
1096 
1097 /* ---- DMAC filter */
1098 
1099 #ifdef notyet
1100 /*
1101  * DMAC filter configuration
1102  *	accept all
1103  *	reject 0 addrs (virtually accept all?)
1104  *	reject N addrs
1105  *	accept N addrs
1106  *	accept 0 addrs (virtually reject all?)
1107  *	reject all
1108  */
1109 
1110 /* XXX local namespace */
1111 #define	_POLICY			CN30XXGMX_FILTER_POLICY
1112 #define	_POLICY_ACCEPT_ALL	CN30XXGMX_FILTER_POLICY_ACCEPT_ALL
1113 #define	_POLICY_ACCEPT		CN30XXGMX_FILTER_POLICY_ACCEPT
1114 #define	_POLICY_REJECT		CN30XXGMX_FILTER_POLICY_REJECT
1115 #define	_POLICY_REJECT_ALL	CN30XXGMX_FILTER_POLICY_REJECT_ALL
1116 
1117 static int	octeon_gmx_setfilt_addrs(struct octeon_gmx_port_softc *,
1118 		    size_t, uint8_t **);
1119 
1120 int
1121 octeon_gmx_setfilt(struct octeon_gmx_port_softc *sc, enum _POLICY policy,
1122     size_t naddrs, uint8_t **addrs)
1123 {
1124 	uint64_t rx_adr_ctl;
1125 
1126 	KASSERT(policy >= _POLICY_ACCEPT_ALL);
1127 	KASSERT(policy <= _POLICY_REJECT_ALL);
1128 
1129 	rx_adr_ctl = _GMX_PORT_RD8(sc, GMX0_RX0_ADR_CTL);
1130 	CLR(rx_adr_ctl, RXN_ADR_CTL_CAM_MODE | RXN_ADR_CTL_MCST);
1131 
1132 	switch (policy) {
1133 	case _POLICY_ACCEPT_ALL:
1134 	case _POLICY_REJECT_ALL:
1135 		KASSERT(naddrs == 0);
1136 		KASSERT(addrs == NULL);
1137 
1138 		SET(rx_adr_ctl, (policy == _POLICY_ACCEPT_ALL) ?
1139 		    RXN_ADR_CTL_MCST_ACCEPT : RXN_ADR_CTL_MCST_REJECT);
1140 		break;
1141 	case _POLICY_ACCEPT:
1142 	case _POLICY_REJECT:
1143 		if (naddrs > CN30XXGMX_FILTER_NADDRS_MAX)
1144 			return E2BIG;
1145 		SET(rx_adr_ctl, (policy == _POLICY_ACCEPT) ?
1146 		    RXN_ADR_CTL_CAM_MODE : 0);
1147 		SET(rx_adr_ctl, RXN_ADR_CTL_MCST_AFCAM);
1148 		/* set GMX0_RXN_ADR_CAM_EN, GMX0_RXN_ADR_CAM[0-5] */
1149 		octeon_gmx_setfilt_addrs(sc, naddrs, addrs);
1150 		break;
1151 	}
1152 
1153 	/* set GMX0_RXN_ADR_CTL[MCST] */
1154 	_GMX_PORT_WR8(sc, GMX0_RX0_ADR_CTL, rx_adr_ctl);
1155 
1156 	return 0;
1157 }
1158 
1159 static int
1160 octeon_gmx_setfilt_addrs(struct octeon_gmx_port_softc *sc, size_t naddrs,
1161     uint8_t **addrs)
1162 {
1163 	uint64_t rx_adr_cam_en;
1164 	uint64_t rx_adr_cam_addrs[CN30XXGMX_FILTER_NADDRS_MAX];
1165 	int i, j;
1166 
1167 	KASSERT(naddrs <= CN30XXGMX_FILTER_NADDRS_MAX);
1168 
1169 	rx_adr_cam_en = 0;
1170 	(void)memset(rx_adr_cam_addrs, 0, sizeof(rx_adr_cam_addrs));
1171 
1172 	for (i = 0; i < naddrs; i++) {
1173 		SET(rx_adr_cam_en, 1ULL << i);
1174 		for (j = 0; j < 6; j++)
1175 			SET(rx_adr_cam_addrs[j],
1176 			    (uint64_t)addrs[i][j] << (8 * i));
1177 	}
1178 
1179 	/* set GMX0_RXN_ADR_CAM_EN, GMX0_RXN_ADR_CAM[0-5] */
1180 	_GMX_PORT_WR8(sc, GMX0_RX0_ADR_CAM_EN, rx_adr_cam_en);
1181 	for (j = 0; j < 6; j++)
1182 		_GMX_PORT_WR8(sc, octeon_gmx_rx_adr_cam_regs[j],
1183 		    rx_adr_cam_addrs[j]);
1184 
1185 	return 0;
1186 }
1187 #endif
1188 
1189 /* ---- interrupt */
1190 
1191 #ifdef OCTEON_ETH_DEBUG
1192 void			octeon_gmx_intr_rml_gmx0(void);
1193 
1194 int			octeon_gmx_intr_rml_verbose;
1195 
1196 /* tx - per unit (gmx0, gmx1, ...) */
1197 static const struct octeon_evcnt_entry octeon_gmx_intr_evcnt_tx_entries[] = {
1198 #define	_ENTRY(name, type, parent, descr) \
1199 	OCTEON_EVCNT_ENTRY(struct octeon_gmx_softc, name, type, parent, descr)
1200 	_ENTRY(latecol,		MISC, NULL, "tx late collision"),
1201 	_ENTRY(xsdef,		MISC, NULL, "tx excessive deferral"),
1202 	_ENTRY(xscol,		MISC, NULL, "tx excessive collision"),
1203 	_ENTRY(undflw,		MISC, NULL, "tx underflow"),
1204 	_ENTRY(pkonxa,		MISC, NULL, "tx port addr out-of-range")
1205 #undef	_ENTRY
1206 };
1207 
1208 /* rx - per port (gmx0:0, gmx0:1, ...) */
1209 static const struct octeon_evcnt_entry octeon_gmx_intr_evcnt_rx_entries[] = {
1210 #define	_ENTRY(name, type, parent, descr) \
1211 	OCTEON_EVCNT_ENTRY(struct octeon_gmx_port_softc, name, type, parent, descr)
1212 	_ENTRY(minerr,		MISC, NULL, "rx min error"),
1213 	_ENTRY(carext,		MISC, NULL, "rx carrier error"),
1214 	_ENTRY(maxerr,		MISC, NULL, "rx max error"),
1215 	_ENTRY(jabber,		MISC, NULL, "rx jabber error"),
1216 	_ENTRY(fcserr,		MISC, NULL, "rx fcs error"),
1217 	_ENTRY(alnerr,		MISC, NULL, "rx align error"),
1218 	_ENTRY(lenerr,		MISC, NULL, "rx length error"),
1219 	_ENTRY(rcverr,		MISC, NULL, "rx receive error"),
1220 	_ENTRY(skperr,		MISC, NULL, "rx skip error"),
1221 	_ENTRY(niberr,		MISC, NULL, "rx nibble error"),
1222 	_ENTRY(ovrerr,		MISC, NULL, "rx overflow error"),
1223 	_ENTRY(pckterr,		MISC, NULL, "rx packet error"),
1224 	_ENTRY(rsverr,		MISC, NULL, "rx reserved opcode error"),
1225 	_ENTRY(falerr,		MISC, NULL, "rx false carrier error"),
1226 	_ENTRY(coldet,		MISC, NULL, "rx collision detect"),
1227 	_ENTRY(ifgerr,		MISC, NULL, "rx ifg error")
1228 #undef	_ENTRY
1229 };
1230 
1231 void
1232 octeon_gmx_intr_evcnt_attach(struct octeon_gmx_softc *sc)
1233 {
1234 	struct octeon_gmx_port_softc *port_sc;
1235 	int i;
1236 
1237 	OCTEON_EVCNT_ATTACH_EVCNTS(sc, octeon_gmx_intr_evcnt_tx_entries,
1238 	    device_xname(sc->sc_dev));
1239 	for (i = 0; i < sc->sc_nports; i++) {
1240 		port_sc = &sc->sc_ports[i];
1241 		OCTEON_EVCNT_ATTACH_EVCNTS(port_sc, octeon_gmx_intr_evcnt_rx_entries,
1242 		    device_xname(sc->sc_dev));
1243 	}
1244 }
1245 
1246 void
1247 octeon_gmx_intr_rml_gmx0(void)
1248 {
1249 	struct octeon_gmx_port_softc *sc = NULL/* XXX gcc */;
1250 	int i;
1251 	uint64_t reg = 0/* XXX gcc */;
1252 
1253 	octeon_gmx_intr_evcnt.ev_count++;
1254 
1255 	sc = __octeon_gmx_port_softc[0];
1256 	if (sc == NULL)
1257 		return;
1258 
1259 	/* GMX0_RXn_INT_REG or GMX0_TXn_INT_REG */
1260 	reg = octeon_gmx_get_tx_int_reg(sc);
1261 	if (octeon_gmx_intr_rml_verbose && reg != 0)
1262 		printf("%s: GMX_TX_INT_REG=0x%016" PRIx64 "\n", __func__, reg);
1263 	if (reg & TX_INT_REG_LATE_COL)
1264 		OCTEON_EVCNT_INC(sc->sc_port_gmx, latecol);
1265 	if (reg & TX_INT_REG_XSDEF)
1266 		OCTEON_EVCNT_INC(sc->sc_port_gmx, xsdef);
1267 	if (reg & TX_INT_REG_XSCOL)
1268 		OCTEON_EVCNT_INC(sc->sc_port_gmx, xscol);
1269 	if (reg & TX_INT_REG_UNDFLW)
1270 		OCTEON_EVCNT_INC(sc->sc_port_gmx, undflw);
1271 	if (reg & TX_INT_REG_PKO_NXA)
1272 		OCTEON_EVCNT_INC(sc->sc_port_gmx, pkonxa);
1273 
1274 	for (i = 0; i < GMX_PORT_NUNITS; i++) {
1275 		sc = __octeon_gmx_port_softc[i];
1276 		if (sc == NULL)
1277 			continue;
1278 		reg = octeon_gmx_get_rx_int_reg(sc);
1279 		if (octeon_gmx_intr_rml_verbose)
1280 			printf("%s: GMX_RX_INT_REG=0x%016" PRIx64 "\n", __func__, reg);
1281 		if (reg & RXN_INT_REG_MINERR)
1282 			OCTEON_EVCNT_INC(sc, minerr);
1283 		if (reg & RXN_INT_REG_CAREXT)
1284 			OCTEON_EVCNT_INC(sc, carext);
1285 		if (reg & RXN_INT_REG_JABBER)
1286 			OCTEON_EVCNT_INC(sc, jabber);
1287 		if (reg & RXN_INT_REG_FCSERR)
1288 			OCTEON_EVCNT_INC(sc, fcserr);
1289 		if (reg & RXN_INT_REG_ALNERR)
1290 			OCTEON_EVCNT_INC(sc, alnerr);
1291 		if (reg & RXN_INT_REG_LENERR)
1292 			OCTEON_EVCNT_INC(sc, lenerr);
1293 		if (reg & RXN_INT_REG_RCVERR)
1294 			OCTEON_EVCNT_INC(sc, rcverr);
1295 		if (reg & RXN_INT_REG_SKPERR)
1296 			OCTEON_EVCNT_INC(sc, skperr);
1297 		if (reg & RXN_INT_REG_NIBERR)
1298 			OCTEON_EVCNT_INC(sc, niberr);
1299 		if (reg & RXN_INT_REG_OVRERR)
1300 			OCTEON_EVCNT_INC(sc, ovrerr);
1301 		if (reg & RXN_INT_REG_PCTERR)
1302 			OCTEON_EVCNT_INC(sc, pckterr);
1303 		if (reg & RXN_INT_REG_RSVERR)
1304 			OCTEON_EVCNT_INC(sc, rsverr);
1305 		if (reg & RXN_INT_REG_FALERR)
1306 			OCTEON_EVCNT_INC(sc, falerr);
1307 		if (reg & RXN_INT_REG_COLDET)
1308 			OCTEON_EVCNT_INC(sc, coldet);
1309 		if (reg & RXN_INT_REG_IFGERR)
1310 			OCTEON_EVCNT_INC(sc, ifgerr);
1311 	}
1312 }
1313 
1314 #ifdef notyet
1315 void
1316 octeon_gmx_intr_rml_gmx1(void)
1317 {
1318 	uint64_t reg = 0/* XXX gcc */;
1319 
1320 		/* GMX1_RXn_INT_REG or GMX1_TXn_INT_REG */
1321 }
1322 #endif
1323 
1324 int
1325 octeon_gmx_intr_drop(void *arg)
1326 {
1327 	octeon_write_csr(CIU_INT0_SUM0, CIU_INTX_SUM0_GMX_DRP);
1328 	octeon_gmx_intr_drop_evcnt.ev_count++;
1329 	return (1);
1330 }
1331 
1332 uint64_t
1333 octeon_gmx_get_rx_int_reg(struct octeon_gmx_port_softc *sc)
1334 {
1335 	uint64_t reg;
1336 	uint64_t rx_int_reg = 0;
1337 
1338 	reg = _GMX_PORT_RD8(sc, GMX0_RX0_INT_REG);
1339 	/* clear */
1340 	SET(rx_int_reg, 0 |
1341 	    RXN_INT_REG_PHY_DUPX |
1342 	    RXN_INT_REG_PHY_SPD |
1343 	    RXN_INT_REG_PHY_LINK |
1344 	    RXN_INT_REG_IFGERR |
1345 	    RXN_INT_REG_COLDET |
1346 	    RXN_INT_REG_FALERR |
1347 	    RXN_INT_REG_RSVERR |
1348 	    RXN_INT_REG_PCTERR |
1349 	    RXN_INT_REG_OVRERR |
1350 	    RXN_INT_REG_NIBERR |
1351 	    RXN_INT_REG_SKPERR |
1352 	    RXN_INT_REG_RCVERR |
1353 	    RXN_INT_REG_LENERR |
1354 	    RXN_INT_REG_ALNERR |
1355 	    RXN_INT_REG_FCSERR |
1356 	    RXN_INT_REG_JABBER |
1357 	    RXN_INT_REG_MAXERR |
1358 	    RXN_INT_REG_CAREXT |
1359 	    RXN_INT_REG_MINERR);
1360 	_GMX_PORT_WR8(sc, GMX0_RX0_INT_REG, rx_int_reg);
1361 
1362 	return reg;
1363 }
1364 
1365 uint64_t
1366 octeon_gmx_get_tx_int_reg(struct octeon_gmx_port_softc *sc)
1367 {
1368 	uint64_t reg;
1369 	uint64_t tx_int_reg = 0;
1370 
1371 	reg = _GMX_PORT_RD8(sc, GMX0_TX_INT_REG);
1372 	/* clear */
1373 	SET(tx_int_reg, 0 |
1374 	    TX_INT_REG_LATE_COL |
1375 	    TX_INT_REG_XSDEF |
1376 	    TX_INT_REG_XSCOL |
1377 	    TX_INT_REG_UNDFLW |
1378 	    TX_INT_REG_PKO_NXA);
1379 	_GMX_PORT_WR8(sc, GMX0_TX_INT_REG, tx_int_reg);
1380 
1381 	return reg;
1382 }
1383 #endif	/* OCTEON_ETH_DEBUG */
1384 
1385 /* ---- debug */
1386 
1387 #ifdef OCTEON_ETH_DEBUG
1388 #define	_ENTRY(x)	{ #x, x##_BITS, x }
1389 
1390 struct octeon_gmx_dump_reg_ {
1391 	const char *name;
1392 	const char *format;
1393 	size_t	offset;
1394 };
1395 
1396 static const struct octeon_gmx_dump_reg_ octeon_gmx_dump_regs_[] = {
1397 	_ENTRY(GMX0_SMAC0),
1398 	_ENTRY(GMX0_BIST0),
1399 	_ENTRY(GMX0_RX_PRTS),
1400 	_ENTRY(GMX0_RX_BP_DROP0),
1401 	_ENTRY(GMX0_RX_BP_DROP1),
1402 	_ENTRY(GMX0_RX_BP_DROP2),
1403 	_ENTRY(GMX0_RX_BP_ON0),
1404 	_ENTRY(GMX0_RX_BP_ON1),
1405 	_ENTRY(GMX0_RX_BP_ON2),
1406 	_ENTRY(GMX0_RX_BP_OFF0),
1407 	_ENTRY(GMX0_RX_BP_OFF1),
1408 	_ENTRY(GMX0_RX_BP_OFF2),
1409 	_ENTRY(GMX0_TX_PRTS),
1410 	_ENTRY(GMX0_TX_IFG),
1411 	_ENTRY(GMX0_TX_JAM),
1412 	_ENTRY(GMX0_TX_COL_ATTEMPT),
1413 	_ENTRY(GMX0_TX_PAUSE_PKT_DMAC),
1414 	_ENTRY(GMX0_TX_PAUSE_PKT_TYPE),
1415 	_ENTRY(GMX0_TX_OVR_BP),
1416 	_ENTRY(GMX0_TX_BP),
1417 	_ENTRY(GMX0_TX_CORRUPT),
1418 	_ENTRY(GMX0_RX_PRT_INFO),
1419 	_ENTRY(GMX0_TX_LFSR),
1420 	_ENTRY(GMX0_TX_INT_REG),
1421 	_ENTRY(GMX0_TX_INT_EN),
1422 	_ENTRY(GMX0_NXA_ADR),
1423 	_ENTRY(GMX0_BAD_REG),
1424 	_ENTRY(GMX0_STAT_BP),
1425 	_ENTRY(GMX0_TX_CLK_MSK0),
1426 	_ENTRY(GMX0_TX_CLK_MSK1),
1427 	_ENTRY(GMX0_RX_TX_STATUS),
1428 	_ENTRY(GMX0_INF_MODE),
1429 };
1430 
1431 static const struct octeon_gmx_dump_reg_ octeon_gmx_dump_port_regs_[] = {
1432 	_ENTRY(GMX0_RX0_INT_REG),
1433 	_ENTRY(GMX0_RX0_INT_EN),
1434 	_ENTRY(GMX0_PRT0_CFG),
1435 	_ENTRY(GMX0_RX0_FRM_CTL),
1436 	_ENTRY(GMX0_RX0_FRM_CHK),
1437 	_ENTRY(GMX0_RX0_FRM_MIN),
1438 	_ENTRY(GMX0_RX0_FRM_MAX),
1439 	_ENTRY(GMX0_RX0_JABBER),
1440 	_ENTRY(GMX0_RX0_DECISION),
1441 	_ENTRY(GMX0_RX0_UDD_SKP),
1442 	_ENTRY(GMX0_RX0_STATS_CTL),
1443 	_ENTRY(GMX0_RX0_IFG),
1444 	_ENTRY(GMX0_RX0_RX_INBND),
1445 	_ENTRY(GMX0_RX0_ADR_CTL),
1446 	_ENTRY(GMX0_RX0_ADR_CAM_EN),
1447 	_ENTRY(GMX0_RX0_ADR_CAM0),
1448 	_ENTRY(GMX0_RX0_ADR_CAM1),
1449 	_ENTRY(GMX0_RX0_ADR_CAM2),
1450 	_ENTRY(GMX0_RX0_ADR_CAM3),
1451 	_ENTRY(GMX0_RX0_ADR_CAM4),
1452 	_ENTRY(GMX0_RX0_ADR_CAM5),
1453 	_ENTRY(GMX0_TX0_CLK),
1454 	_ENTRY(GMX0_TX0_THRESH),
1455 	_ENTRY(GMX0_TX0_APPEND),
1456 	_ENTRY(GMX0_TX0_SLOT),
1457 	_ENTRY(GMX0_TX0_BURST),
1458 	_ENTRY(GMX0_TX0_PAUSE_PKT_TIME),
1459 	_ENTRY(GMX0_TX0_MIN_PKT),
1460 	_ENTRY(GMX0_TX0_PAUSE_PKT_INTERVAL),
1461 	_ENTRY(GMX0_TX0_SOFT_PAUSE),
1462 	_ENTRY(GMX0_TX0_PAUSE_TOGO),
1463 	_ENTRY(GMX0_TX0_PAUSE_ZERO),
1464 	_ENTRY(GMX0_TX0_STATS_CTL),
1465 	_ENTRY(GMX0_TX0_CTL),
1466 };
1467 
1468 static const struct octeon_gmx_dump_reg_ octeon_gmx_dump_port_stats_[] = {
1469 	_ENTRY(GMX0_RX0_STATS_PKTS),
1470 	_ENTRY(GMX0_RX0_STATS_OCTS),
1471 	_ENTRY(GMX0_RX0_STATS_PKTS_CTL),
1472 	_ENTRY(GMX0_RX0_STATS_OCTS_CTL),
1473 	_ENTRY(GMX0_RX0_STATS_PKTS_DMAC),
1474 	_ENTRY(GMX0_RX0_STATS_OCTS_DMAC),
1475 	_ENTRY(GMX0_RX0_STATS_PKTS_DRP),
1476 	_ENTRY(GMX0_RX0_STATS_OCTS_DRP),
1477 	_ENTRY(GMX0_RX0_STATS_PKTS_BAD),
1478 	_ENTRY(GMX0_TX0_STAT0),
1479 	_ENTRY(GMX0_TX0_STAT1),
1480 	_ENTRY(GMX0_TX0_STAT2),
1481 	_ENTRY(GMX0_TX0_STAT3),
1482 	_ENTRY(GMX0_TX0_STAT4),
1483 	_ENTRY(GMX0_TX0_STAT5),
1484 	_ENTRY(GMX0_TX0_STAT6),
1485 	_ENTRY(GMX0_TX0_STAT7),
1486 	_ENTRY(GMX0_TX0_STAT8),
1487 	_ENTRY(GMX0_TX0_STAT9),
1488 };
1489 
1490 void		octeon_gmx_dump_common(void);
1491 void		octeon_gmx_dump_port0(void);
1492 void		octeon_gmx_dump_port1(void);
1493 void		octeon_gmx_dump_port2(void);
1494 void		octeon_gmx_dump_port0_regs(void);
1495 void		octeon_gmx_dump_port1_regs(void);
1496 void		octeon_gmx_dump_port2_regs(void);
1497 void		octeon_gmx_dump_port0_stats(void);
1498 void		octeon_gmx_dump_port1_stats(void);
1499 void		octeon_gmx_dump_port2_stats(void);
1500 void		octeon_gmx_dump_port_regs(int);
1501 void		octeon_gmx_dump_port_stats(int);
1502 void		octeon_gmx_dump_common_x(int, const struct octeon_gmx_dump_reg_ *, size_t);
1503 void		octeon_gmx_dump_port_x(int, const struct octeon_gmx_dump_reg_ *, size_t);
1504 void		octeon_gmx_dump_x(int, const struct octeon_gmx_dump_reg_ *, size_t, size_t, int);
1505 void		octeon_gmx_dump_x_index(char *, size_t, int);
1506 
1507 void
1508 octeon_gmx_dump(void)
1509 {
1510 	octeon_gmx_dump_common();
1511 	octeon_gmx_dump_port0();
1512 	octeon_gmx_dump_port1();
1513 	octeon_gmx_dump_port2();
1514 }
1515 
1516 void
1517 octeon_gmx_dump_common(void)
1518 {
1519 	octeon_gmx_dump_common_x(0, octeon_gmx_dump_regs_,
1520 	    __arraycount(octeon_gmx_dump_regs_));
1521 }
1522 
1523 void
1524 octeon_gmx_dump_port0(void)
1525 {
1526 	octeon_gmx_dump_port_regs(0);
1527 	octeon_gmx_dump_port_stats(0);
1528 }
1529 
1530 void
1531 octeon_gmx_dump_port1(void)
1532 {
1533 	octeon_gmx_dump_port_regs(1);
1534 	octeon_gmx_dump_port_stats(1);
1535 }
1536 
1537 void
1538 octeon_gmx_dump_port2(void)
1539 {
1540 	octeon_gmx_dump_port_regs(2);
1541 	octeon_gmx_dump_port_stats(2);
1542 }
1543 
1544 void
1545 octeon_gmx_dump_port_regs(int portno)
1546 {
1547 	octeon_gmx_dump_port_x(portno, octeon_gmx_dump_port_regs_,
1548 	    __arraycount(octeon_gmx_dump_port_regs_));
1549 }
1550 
1551 void
1552 octeon_gmx_dump_port_stats(int portno)
1553 {
1554 	struct octeon_gmx_port_softc *sc = __octeon_gmx_port_softc[0];
1555 	uint64_t rx_stats_ctl;
1556 	uint64_t tx_stats_ctl;
1557 
1558 	rx_stats_ctl = _GMX_RD8(sc, GMX0_BASE_PORT_SIZE * portno + GMX0_RX0_STATS_CTL);
1559 	_GMX_WR8(sc, GMX0_BASE_PORT_SIZE * portno + GMX0_RX0_STATS_CTL,
1560 	    rx_stats_ctl & ~RXN_STATS_CTL_RD_CLR);
1561 	tx_stats_ctl = _GMX_RD8(sc, GMX0_BASE_PORT_SIZE * portno + GMX0_TX0_STATS_CTL);
1562 	_GMX_WR8(sc, GMX0_BASE_PORT_SIZE * portno + GMX0_TX0_STATS_CTL,
1563 	    tx_stats_ctl & ~TXN_STATS_CTL_RD_CLR);
1564 	octeon_gmx_dump_port_x(portno, octeon_gmx_dump_port_stats_,
1565 	    __arraycount(octeon_gmx_dump_port_stats_));
1566 	_GMX_WR8(sc, GMX0_BASE_PORT_SIZE * portno + GMX0_RX0_STATS_CTL, rx_stats_ctl);
1567 	_GMX_WR8(sc, GMX0_BASE_PORT_SIZE * portno + GMX0_TX0_STATS_CTL, tx_stats_ctl);
1568 }
1569 
1570 void
1571 octeon_gmx_dump_common_x(int portno, const struct octeon_gmx_dump_reg_ *regs, size_t size)
1572 {
1573 	octeon_gmx_dump_x(portno, regs, size, 0, 0);
1574 }
1575 
1576 void
1577 octeon_gmx_dump_port_x(int portno, const struct octeon_gmx_dump_reg_ *regs, size_t size)
1578 {
1579 	octeon_gmx_dump_x(portno, regs, size, GMX0_BASE_PORT_SIZE * portno, 1);
1580 }
1581 
1582 void
1583 octeon_gmx_dump_x(int portno, const struct octeon_gmx_dump_reg_ *regs, size_t size, size_t base, int index)
1584 {
1585 	struct octeon_gmx_port_softc *sc = __octeon_gmx_port_softc[0];
1586 	const struct octeon_gmx_dump_reg_ *reg;
1587 	uint64_t tmp;
1588 	char name[64];
1589 	char buf[512];
1590 	int i;
1591 
1592 	for (i = 0; i < (int)size; i++) {
1593 		reg = &regs[i];
1594 		tmp = _GMX_RD8(sc, base + reg->offset);
1595 
1596 		if (reg->format == NULL)
1597 			snprintf(buf, sizeof(buf), "%016" PRIx64, tmp);
1598 		else
1599 			snprintb(buf, sizeof(buf), reg->format, tmp);
1600 
1601 		snprintf(name, sizeof(name), "%s", reg->name);
1602 		if (index > 0)
1603 			octeon_gmx_dump_x_index(name, sizeof(name), portno);
1604 
1605 		printf("\t%-24s: %s\n", name, buf);
1606 	}
1607 }
1608 
1609 void
1610 octeon_gmx_dump_x_index(char *buf, size_t len, int index)
1611 {
1612 	static const char *patterns[] = { "_TX0_", "_RX0_", "_PRT0_" };
1613 	int i;
1614 
1615 	for (i = 0; i < (int)__arraycount(patterns); i++) {
1616 		char *p;
1617 
1618 		p = strstr(buf, patterns[i]);
1619 		if (p == NULL)
1620 			continue;
1621 		p = strchr(p, '0');
1622 		KASSERT(p != NULL);
1623 		*p = '0' + index;
1624 		return;
1625 	}
1626 }
1627 
1628 void
1629 octeon_gmx_debug_reset(void)
1630 {
1631 	int i;
1632 
1633 	for (i = 0; i < 3; i++)
1634 		octeon_gmx_link_enable(__octeon_gmx_port_softc[i], 0);
1635 	for (i = 0; i < 3; i++)
1636 		octeon_gmx_link_enable(__octeon_gmx_port_softc[i], 1);
1637 }
1638 #endif
1639