xref: /openbsd-src/sys/arch/octeon/dev/cn30xxgmx.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /*	$OpenBSD: cn30xxgmx.c,v 1.26 2016/08/04 13:10:31 visa 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 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/types.h>
32 #include <sys/device.h>
33 #include <sys/malloc.h>
34 #include <sys/syslog.h>
35 
36 #include <machine/bus.h>
37 #include <machine/octeon_model.h>
38 #include <machine/octeonvar.h>
39 
40 #include <octeon/dev/iobusvar.h>
41 #include <octeon/dev/cn30xxciureg.h>
42 #include <octeon/dev/cn30xxgmxreg.h>
43 #include <octeon/dev/cn30xxipdvar.h>
44 #include <octeon/dev/cn30xxasxvar.h>
45 #include <octeon/dev/cn30xxgmxvar.h>
46 
47 #define	dprintf(...)
48 #define	OCTEON_ETH_KASSERT	KASSERT
49 
50 #define	ADDR2UINT64(u, a) \
51 	do { \
52 		u = \
53 		    (((uint64_t)a[0] << 40) | ((uint64_t)a[1] << 32) | \
54 		     ((uint64_t)a[2] << 24) | ((uint64_t)a[3] << 16) | \
55 		     ((uint64_t)a[4] <<  8) | ((uint64_t)a[5] <<  0)); \
56 	} while (0)
57 #define	UINT642ADDR(a, u) \
58 	do { \
59 		a[0] = (uint8_t)((u) >> 40); a[1] = (uint8_t)((u) >> 32); \
60 		a[2] = (uint8_t)((u) >> 24); a[3] = (uint8_t)((u) >> 16); \
61 		a[4] = (uint8_t)((u) >>  8); a[5] = (uint8_t)((u) >>  0); \
62 	} while (0)
63 
64 #define	_GMX_RD8(sc, off) \
65 	bus_space_read_8((sc)->sc_port_gmx->sc_regt, (sc)->sc_port_gmx->sc_regh, (off))
66 #define	_GMX_WR8(sc, off, v) \
67 	bus_space_write_8((sc)->sc_port_gmx->sc_regt, (sc)->sc_port_gmx->sc_regh, (off), (v))
68 #define	_GMX_PORT_RD8(sc, off) \
69 	bus_space_read_8((sc)->sc_port_gmx->sc_regt, (sc)->sc_port_regh, (off))
70 #define	_GMX_PORT_WR8(sc, off, v) \
71 	bus_space_write_8((sc)->sc_port_gmx->sc_regt, (sc)->sc_port_regh, (off), (v))
72 
73 #define PCS_READ_8(sc, reg) \
74 	bus_space_read_8((sc)->sc_port_gmx->sc_regt, (sc)->sc_port_pcs_regh, \
75 	    (reg))
76 #define PCS_WRITE_8(sc, reg, val) \
77 	bus_space_write_8((sc)->sc_port_gmx->sc_regt, (sc)->sc_port_pcs_regh, \
78 	    (reg), (val))
79 
80 struct cn30xxgmx_port_ops {
81 	int	(*port_ops_enable)(struct cn30xxgmx_port_softc *, int);
82 	int	(*port_ops_speed)(struct cn30xxgmx_port_softc *);
83 	int	(*port_ops_timing)(struct cn30xxgmx_port_softc *);
84 };
85 
86 int	cn30xxgmx_match(struct device *, void *, void *);
87 void	cn30xxgmx_attach(struct device *, struct device *, void *);
88 int	cn30xxgmx_print(void *, const char *);
89 int	cn30xxgmx_submatch(struct device *, void *, void *);
90 int	cn30xxgmx_port_phy_addr(int);
91 int	cn30xxgmx_init(struct cn30xxgmx_softc *);
92 int	cn30xxgmx_rx_frm_ctl_xable(struct cn30xxgmx_port_softc *,
93 	    uint64_t, int);
94 int	cn30xxgmx_rgmii_enable(struct cn30xxgmx_port_softc *, int);
95 int	cn30xxgmx_rgmii_speed(struct cn30xxgmx_port_softc *);
96 int	cn30xxgmx_rgmii_speed_newlink(struct cn30xxgmx_port_softc *,
97 	    uint64_t *);
98 int	cn30xxgmx_rgmii_speed_speed(struct cn30xxgmx_port_softc *);
99 int	cn30xxgmx_rgmii_timing(struct cn30xxgmx_port_softc *);
100 int	cn30xxgmx_sgmii_enable(struct cn30xxgmx_port_softc *, int);
101 int	cn30xxgmx_sgmii_speed(struct cn30xxgmx_port_softc *);
102 int	cn30xxgmx_sgmii_timing(struct cn30xxgmx_port_softc *);
103 int	cn30xxgmx_tx_ovr_bp_enable(struct cn30xxgmx_port_softc *, int);
104 int	cn30xxgmx_rx_pause_enable(struct cn30xxgmx_port_softc *, int);
105 
106 #ifdef OCTEON_ETH_DEBUG
107 void	cn30xxgmx_dump(void);
108 void	cn30xxgmx_debug_reset(void);
109 int	cn30xxgmx_intr_drop(void *);
110 int	cn30xxgmx_rgmii_speed_newlink_log(struct cn30xxgmx_port_softc *,
111 	    uint64_t);
112 #endif
113 
114 static const int	cn30xxgmx_rx_adr_cam_regs[] = {
115 	GMX0_RX0_ADR_CAM0, GMX0_RX0_ADR_CAM1, GMX0_RX0_ADR_CAM2,
116 	GMX0_RX0_ADR_CAM3, GMX0_RX0_ADR_CAM4, GMX0_RX0_ADR_CAM5
117 };
118 
119 struct cn30xxgmx_port_ops cn30xxgmx_port_ops_mii = {
120 	/* XXX not implemented */
121 };
122 
123 struct cn30xxgmx_port_ops cn30xxgmx_port_ops_gmii = {
124 	.port_ops_enable = cn30xxgmx_rgmii_enable,
125 	.port_ops_speed = cn30xxgmx_rgmii_speed,
126 	.port_ops_timing = cn30xxgmx_rgmii_timing,
127 };
128 
129 struct cn30xxgmx_port_ops cn30xxgmx_port_ops_rgmii = {
130 	.port_ops_enable = cn30xxgmx_rgmii_enable,
131 	.port_ops_speed = cn30xxgmx_rgmii_speed,
132 	.port_ops_timing = cn30xxgmx_rgmii_timing,
133 };
134 
135 struct cn30xxgmx_port_ops cn30xxgmx_port_ops_sgmii = {
136 	.port_ops_enable = cn30xxgmx_sgmii_enable,
137 	.port_ops_speed = cn30xxgmx_sgmii_speed,
138 	.port_ops_timing = cn30xxgmx_sgmii_timing,
139 };
140 
141 struct cn30xxgmx_port_ops cn30xxgmx_port_ops_spi42 = {
142 	/* XXX not implemented */
143 };
144 
145 struct cn30xxgmx_port_ops *cn30xxgmx_port_ops[] = {
146 	[GMX_MII_PORT] = &cn30xxgmx_port_ops_mii,
147 	[GMX_GMII_PORT] = &cn30xxgmx_port_ops_gmii,
148 	[GMX_RGMII_PORT] = &cn30xxgmx_port_ops_rgmii,
149 	[GMX_SGMII_PORT] = &cn30xxgmx_port_ops_sgmii,
150 	[GMX_SPI42_PORT] = &cn30xxgmx_port_ops_spi42
151 };
152 
153 #ifdef OCTEON_ETH_DEBUG
154 void	*cn30xxgmx_intr_drop_ih;
155 
156 struct cn30xxgmx_port_softc *__cn30xxgmx_port_softc[GMX_PORT_NUNITS];
157 #endif
158 
159 struct cfattach cn30xxgmx_ca = {sizeof(struct cn30xxgmx_softc),
160     cn30xxgmx_match, cn30xxgmx_attach, NULL, NULL};
161 
162 struct cfdriver cn30xxgmx_cd = {NULL, "cn30xxgmx", DV_DULL};
163 
164 int
165 cn30xxgmx_match(struct device *parent, void *match, void *aux)
166 {
167 	struct cfdata *cf = (struct cfdata *)match;
168 	struct iobus_attach_args *aa = aux;
169 
170 	if (strcmp(cf->cf_driver->cd_name, aa->aa_name) != 0)
171 		return 0;
172 	if (cf->cf_unit != aa->aa_unitno)
173 		return 0;
174 	return 1;
175 }
176 
177 int
178 cn30xxgmx_port_phy_addr(int port)
179 {
180 	static const int octeon_eth_phy_table[] = {
181 		/* portwell cam-0100 */
182 		0x02, 0x03, 0x22
183 	};
184 
185 	switch (octeon_boot_info->board_type) {
186 	case BOARD_TYPE_UBIQUITI_E100:	/* port 0: 7, port 1: 6 */
187 		if (port > 2)
188 			return -1;
189 		return 7 - port;
190 
191 	case BOARD_TYPE_UBIQUITI_E200:
192 		if (port >= 0 && port < 4)
193 			/* XXX RJ45/SFP combos use the second MDIO. */
194 			return port + 4;  /* GMX0: eth[4-7] */
195 		else if (port >= 16 && port < 20)
196 			return port - 16; /* GMX1: eth[0-3] */
197 		return -1;
198 
199 	default:
200 		if (port >= nitems(octeon_eth_phy_table))
201 			return -1;
202 		return octeon_eth_phy_table[port];
203 	}
204 }
205 
206 void
207 cn30xxgmx_attach(struct device *parent, struct device *self, void *aux)
208 {
209 	struct cn30xxgmx_softc *sc = (void *)self;
210 	struct iobus_attach_args *aa = aux;
211 	struct cn30xxgmx_attach_args gmx_aa;
212 	int status;
213 	int i;
214 	struct cn30xxgmx_port_softc *port_sc;
215 
216 	printf("\n");
217 
218 	sc->sc_regt = aa->aa_bust; /* XXX why there are iot? */
219 	sc->sc_unitno = aa->aa_unitno;
220 
221 	status = bus_space_map(sc->sc_regt, aa->aa_addr,
222 	    GMX0_BASE_IF_SIZE(sc->sc_nports), 0, &sc->sc_regh);
223 	if (status != 0)
224 		panic(": can't map register");
225 
226 	cn30xxgmx_init(sc);
227 
228 	sc->sc_ports = mallocarray(sc->sc_nports, sizeof(*sc->sc_ports),
229 	    M_DEVBUF, M_NOWAIT | M_ZERO);
230 
231 	for (i = 0; i < sc->sc_nports; i++) {
232 		port_sc = &sc->sc_ports[i];
233 		port_sc->sc_port_gmx = sc;
234 		port_sc->sc_port_no = GMX_PORT_NUM(sc->sc_unitno, i);
235 		port_sc->sc_port_type = sc->sc_port_types[i];
236 		port_sc->sc_port_ops = cn30xxgmx_port_ops[port_sc->sc_port_type];
237 		status = bus_space_map(sc->sc_regt,
238 		    aa->aa_addr + GMX0_BASE_PORT_SIZE * i,
239 		    GMX0_BASE_PORT_SIZE, 0, &port_sc->sc_port_regh);
240 		if (status != 0)
241 			panic(": can't map port register");
242 
243 		switch (port_sc->sc_port_type) {
244 		case GMX_MII_PORT:
245 		case GMX_GMII_PORT:
246 		case GMX_RGMII_PORT: {
247 			struct cn30xxasx_attach_args asx_aa;
248 
249 			asx_aa.aa_port = i;
250 			asx_aa.aa_regt = aa->aa_bust;
251 			cn30xxasx_init(&asx_aa, &port_sc->sc_port_asx);
252 			break;
253 		}
254 		case GMX_SGMII_PORT:
255 			if (bus_space_map(sc->sc_regt,
256 			    PCS_BASE(sc->sc_unitno, i), PCS_SIZE, 0,
257 			    &port_sc->sc_port_pcs_regh))
258 				panic("could not map PCS registers");
259 			break;
260 		default:
261 			/* nothing */
262 			break;
263 		}
264 
265 		(void)memset(&gmx_aa, 0, sizeof(gmx_aa));
266 		gmx_aa.ga_regt = aa->aa_bust;
267 		gmx_aa.ga_dmat = aa->aa_dmat;
268 		gmx_aa.ga_addr = aa->aa_addr;
269 		gmx_aa.ga_name = "cnmac";
270 		gmx_aa.ga_portno = port_sc->sc_port_no;
271 		gmx_aa.ga_port_type = sc->sc_port_types[i];
272 		gmx_aa.ga_gmx = sc;
273 		gmx_aa.ga_gmx_port = port_sc;
274 		gmx_aa.ga_phy_addr = cn30xxgmx_port_phy_addr(
275 		    port_sc->sc_port_no);
276 		if (gmx_aa.ga_phy_addr == -1)
277 			panic(": don't know phy address for port %d",
278 			    port_sc->sc_port_no);
279 
280 		config_found_sm(self, &gmx_aa,
281 		    cn30xxgmx_print, cn30xxgmx_submatch);
282 
283 #ifdef OCTEON_ETH_DEBUG
284 		__cn30xxgmx_port_softc[port_sc->sc_port_no] = port_sc;
285 #endif
286 	}
287 
288 #ifdef OCTEON_ETH_DEBUG
289 	if (cn30xxgmx_intr_drop_ih == NULL)
290 		cn30xxgmx_intr_drop_ih = octeon_intr_establish(
291 		   ffs64(CIU_INTX_SUM0_GMX_DRP) - 1, IPL_NET,
292 		   cn30xxgmx_intr_drop, NULL, "cn30xxgmx");
293 #endif
294 }
295 
296 int
297 cn30xxgmx_print(void *aux, const char *pnp)
298 {
299 	struct cn30xxgmx_attach_args *ga = aux;
300 	static const char *types[] = {
301 		[GMX_MII_PORT] = "MII",
302 		[GMX_GMII_PORT] = "GMII",
303 		[GMX_RGMII_PORT] = "RGMII",
304 		[GMX_SGMII_PORT] = "SGMII"
305 	};
306 
307 #if DEBUG
308 	if (pnp)
309 		printf("%s at %s", ga->ga_name, pnp);
310 #endif
311 
312 	printf(": %s", types[ga->ga_port_type]);
313 
314 	return UNCONF;
315 }
316 
317 int
318 cn30xxgmx_submatch(struct device *parent, void *vcf, void *aux)
319 {
320 	struct cfdata *cf = vcf;
321 
322 	return (*cf->cf_attach->ca_match)(parent, vcf, aux);
323 }
324 
325 int
326 cn30xxgmx_init(struct cn30xxgmx_softc *sc)
327 {
328 	int result = 0;
329 	uint64_t inf_mode;
330 	int i, id;
331 
332 	inf_mode = bus_space_read_8(sc->sc_regt, sc->sc_regh, GMX0_INF_MODE);
333 	if ((inf_mode & INF_MODE_EN) == 0) {
334 		printf("port are disable\n");
335 		sc->sc_nports = 0;
336 		result = 1;
337 		return result;
338 	}
339 
340 	id = octeon_get_chipid();
341 
342 	switch (octeon_model_family(id)) {
343 	case OCTEON_MODEL_FAMILY_CN31XX:
344 		/*
345 		 * CN31XX-HM-1.01
346 		 * 14.1 Packet Interface Introduction
347 		 * Table 14-1 Packet Interface Configuration
348 		 * 14.8 GMX Registers, Interface Mode Register, GMX0_INF_MODE
349 		 */
350 		if ((inf_mode & INF_MODE_TYPE) == 0) {
351 			/* all three ports configured as RGMII */
352 			sc->sc_nports = 3;
353 			sc->sc_port_types[0] = GMX_RGMII_PORT;
354 			sc->sc_port_types[1] = GMX_RGMII_PORT;
355 			sc->sc_port_types[2] = GMX_RGMII_PORT;
356 		} else {
357 			/* port 0: RGMII, port 1: GMII, port 2: disabled */
358 			/* XXX CN31XX-HM-1.01 says "Port 3: disabled"; typo? */
359 			sc->sc_nports = 2;
360 			sc->sc_port_types[0] = GMX_RGMII_PORT;
361 			sc->sc_port_types[1] = GMX_GMII_PORT;
362 		}
363 		break;
364 	case OCTEON_MODEL_FAMILY_CN30XX:
365 	case OCTEON_MODEL_FAMILY_CN50XX:
366 		/*
367 		 * CN30XX-HM-1.0
368 		 * 13.1 Packet Interface Introduction
369 		 * Table 13-1 Packet Interface Configuration
370 		 * 13.8 GMX Registers, Interface Mode Register, GMX0_INF_MODE
371 		 */
372 		if ((inf_mode & INF_MODE_P0MII) == 0)
373 			sc->sc_port_types[0] = GMX_RGMII_PORT;
374 		else
375 			sc->sc_port_types[0] = GMX_MII_PORT;
376 		if ((inf_mode & INF_MODE_TYPE) == 0) {
377 			/* port 1 and 2 are configred as RGMII ports */
378 			sc->sc_nports = 3;
379 			sc->sc_port_types[1] = GMX_RGMII_PORT;
380 			sc->sc_port_types[2] = GMX_RGMII_PORT;
381 		} else {
382 			/* port 1: GMII/MII, port 2: disabled */
383 			/* GMII or MII port is slected by GMX_PRT1_CFG[SPEED] */
384 			sc->sc_nports = 2;
385 			sc->sc_port_types[1] = GMX_GMII_PORT;
386 		}
387 		/* port 2 is in CN3010/CN5010 only */
388 		if ((octeon_model(id) != OCTEON_MODEL_CN3010) &&
389 		    (octeon_model(id) != OCTEON_MODEL_CN5010))
390 			if (sc->sc_nports == 3)
391 				sc->sc_nports = 2;
392 		break;
393 	case OCTEON_MODEL_FAMILY_CN61XX: {
394 		uint64_t qlm_cfg;
395 
396 		if (sc->sc_unitno == 0)
397 			qlm_cfg = octeon_xkphys_read_8(MIO_QLM_CFG(2));
398 		else
399 			qlm_cfg = octeon_xkphys_read_8(MIO_QLM_CFG(0));
400 		if ((qlm_cfg & MIO_QLM_CFG_CFG) == 2) {
401 			sc->sc_nports = 4;
402 			for (i = 0; i < sc->sc_nports; i++)
403 				sc->sc_port_types[i] = GMX_SGMII_PORT;
404 		} else if ((qlm_cfg & MIO_QLM_CFG_CFG) == 3) {
405 			printf("XAUI interface is not supported\n");
406 			sc->sc_nports = 0;
407 			result = 1;
408 		} else {
409 			/* The interface is disabled. */
410 			sc->sc_nports = 0;
411 			result = 1;
412 		}
413 		break;
414 	}
415 	case OCTEON_MODEL_FAMILY_CN38XX:
416 	case OCTEON_MODEL_FAMILY_CN56XX:
417 	case OCTEON_MODEL_FAMILY_CN58XX:
418 	default:
419 		printf("unsupported octeon model: 0x%x\n", octeon_get_chipid());
420 		sc->sc_nports = 0;
421 		result = 1;
422 		break;
423 	}
424 
425 	return result;
426 }
427 
428 /* XXX RGMII specific */
429 int
430 cn30xxgmx_link_enable(struct cn30xxgmx_port_softc *sc, int enable)
431 {
432 	uint64_t prt_cfg;
433 
434 	cn30xxgmx_tx_int_enable(sc, enable);
435 	cn30xxgmx_rx_int_enable(sc, enable);
436 
437 	prt_cfg = _GMX_PORT_RD8(sc, GMX0_PRT0_CFG);
438 	if (enable) {
439 		if (cn30xxgmx_link_status(sc)) {
440 			SET(prt_cfg, PRTN_CFG_EN);
441 		}
442 	} else {
443 		CLR(prt_cfg, PRTN_CFG_EN);
444 	}
445 	_GMX_PORT_WR8(sc, GMX0_PRT0_CFG, prt_cfg);
446 	/*
447 	 * According to CN30XX-HM-1.0, 13.4.2 Link Status Changes:
448 	 * > software should read back to flush the write operation.
449 	 */
450 	(void)_GMX_PORT_RD8(sc, GMX0_PRT0_CFG);
451 
452 	return 0;
453 }
454 
455 /* XXX RGMII specific */
456 int
457 cn30xxgmx_stats_init(struct cn30xxgmx_port_softc *sc)
458 {
459         _GMX_PORT_WR8(sc, GMX0_RX0_STATS_PKTS, 0x0ULL);
460         _GMX_PORT_WR8(sc, GMX0_RX0_STATS_PKTS_DRP, 0x0ULL);
461         _GMX_PORT_WR8(sc, GMX0_RX0_STATS_PKTS_BAD, 0x0ULL);
462         _GMX_PORT_WR8(sc, GMX0_TX0_STAT0, 0x0ULL);
463         _GMX_PORT_WR8(sc, GMX0_TX0_STAT1, 0x0ULL);
464         _GMX_PORT_WR8(sc, GMX0_TX0_STAT3, 0x0ULL);
465         _GMX_PORT_WR8(sc, GMX0_TX0_STAT9, 0x0ULL);
466 	return 0;
467 }
468 
469 int
470 cn30xxgmx_tx_stats_rd_clr(struct cn30xxgmx_port_softc *sc, int enable)
471 {
472 	_GMX_PORT_WR8(sc, GMX0_TX0_STATS_CTL, enable ? 0x1ULL : 0x0ULL);
473 	return 0;
474 }
475 
476 int
477 cn30xxgmx_rx_stats_rd_clr(struct cn30xxgmx_port_softc *sc, int enable)
478 {
479 	_GMX_PORT_WR8(sc, GMX0_RX0_STATS_CTL, enable ? 0x1ULL : 0x0ULL);
480 	return 0;
481 }
482 
483 void
484 cn30xxgmx_rx_stats_dec_bad(struct cn30xxgmx_port_softc *sc)
485 {
486 	uint64_t tmp;
487 
488         tmp = _GMX_PORT_RD8(sc, GMX0_RX0_STATS_PKTS_BAD);
489 	_GMX_PORT_WR8(sc, GMX0_RX0_STATS_PKTS_BAD, tmp - 1);
490 }
491 
492 int
493 cn30xxgmx_tx_ovr_bp_enable(struct cn30xxgmx_port_softc *sc, int enable)
494 {
495 	uint64_t ovr_bp;
496 	int index = GMX_PORT_INDEX(sc->sc_port_no);
497 
498 	ovr_bp = _GMX_RD8(sc, GMX0_TX_OVR_BP);
499 	if (enable) {
500 		CLR(ovr_bp, (1 << index) << TX_OVR_BP_EN_SHIFT);
501 		SET(ovr_bp, (1 << index) << TX_OVR_BP_BP_SHIFT);
502 		/* XXX really??? */
503 		SET(ovr_bp, (1 << index) << TX_OVR_BP_IGN_FULL_SHIFT);
504 	} else {
505 		SET(ovr_bp, (1 << index) << TX_OVR_BP_EN_SHIFT);
506 		CLR(ovr_bp, (1 << index) << TX_OVR_BP_BP_SHIFT);
507 		/* XXX really??? */
508 		SET(ovr_bp, (1 << index) << TX_OVR_BP_IGN_FULL_SHIFT);
509 	}
510 	_GMX_WR8(sc, GMX0_TX_OVR_BP, ovr_bp);
511 	return 0;
512 }
513 
514 int
515 cn30xxgmx_rx_pause_enable(struct cn30xxgmx_port_softc *sc, int enable)
516 {
517 	if (enable) {
518 		cn30xxgmx_rx_frm_ctl_enable(sc, RXN_FRM_CTL_CTL_BCK);
519 	} else {
520 		cn30xxgmx_rx_frm_ctl_disable(sc, RXN_FRM_CTL_CTL_BCK);
521 	}
522 
523 	return 0;
524 }
525 
526 void
527 cn30xxgmx_tx_int_enable(struct cn30xxgmx_port_softc *sc, int enable)
528 {
529 	uint64_t tx_int_xxx = 0;
530 
531 	SET(tx_int_xxx,
532 	    TX_INT_REG_LATE_COL |
533 	    TX_INT_REG_XSDEF |
534 	    TX_INT_REG_XSCOL |
535 	    TX_INT_REG_UNDFLW |
536 	    TX_INT_REG_PKO_NXA);
537 	_GMX_WR8(sc, GMX0_TX_INT_REG, tx_int_xxx);
538 	_GMX_WR8(sc, GMX0_TX_INT_EN, enable ? tx_int_xxx : 0);
539 }
540 
541 void
542 cn30xxgmx_rx_int_enable(struct cn30xxgmx_port_softc *sc, int enable)
543 {
544 	uint64_t rx_int_xxx = 0;
545 
546 	SET(rx_int_xxx, 0 |
547 	    RXN_INT_REG_PHY_DUPX |
548 	    RXN_INT_REG_PHY_SPD |
549 	    RXN_INT_REG_PHY_LINK |
550 	    RXN_INT_REG_IFGERR |
551 	    RXN_INT_REG_COLDET |
552 	    RXN_INT_REG_FALERR |
553 	    RXN_INT_REG_RSVERR |
554 	    RXN_INT_REG_PCTERR |
555 	    RXN_INT_REG_OVRERR |
556 	    RXN_INT_REG_NIBERR |
557 	    RXN_INT_REG_SKPERR |
558 	    RXN_INT_REG_RCVERR |
559 	    RXN_INT_REG_LENERR |
560 	    RXN_INT_REG_ALNERR |
561 	    RXN_INT_REG_FCSERR |
562 	    RXN_INT_REG_JABBER |
563 	    RXN_INT_REG_MAXERR |
564 	    RXN_INT_REG_CAREXT |
565 	    RXN_INT_REG_MINERR);
566 	_GMX_PORT_WR8(sc, GMX0_RX0_INT_REG, rx_int_xxx);
567 	_GMX_PORT_WR8(sc, GMX0_RX0_INT_EN, enable ? rx_int_xxx : 0);
568 }
569 
570 int
571 cn30xxgmx_rx_frm_ctl_enable(struct cn30xxgmx_port_softc *sc,
572     uint64_t rx_frm_ctl)
573 {
574 	struct ifnet *ifp = &sc->sc_port_ac->ac_if;
575 	unsigned int maxlen;
576 
577 	maxlen = roundup(ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN +
578 	    ETHER_VLAN_ENCAP_LEN, 8);
579 	_GMX_PORT_WR8(sc, GMX0_RX0_JABBER, maxlen);
580 
581 	return cn30xxgmx_rx_frm_ctl_xable(sc, rx_frm_ctl, 1);
582 }
583 
584 int
585 cn30xxgmx_rx_frm_ctl_disable(struct cn30xxgmx_port_softc *sc,
586     uint64_t rx_frm_ctl)
587 {
588 	return cn30xxgmx_rx_frm_ctl_xable(sc, rx_frm_ctl, 0);
589 }
590 
591 int
592 cn30xxgmx_rx_frm_ctl_xable(struct cn30xxgmx_port_softc *sc,
593     uint64_t rx_frm_ctl, int enable)
594 {
595 	uint64_t tmp;
596 
597 	tmp = _GMX_PORT_RD8(sc, GMX0_RX0_FRM_CTL);
598 	if (enable)
599 		SET(tmp, rx_frm_ctl);
600 	else
601 		CLR(tmp, rx_frm_ctl);
602 	_GMX_PORT_WR8(sc, GMX0_RX0_FRM_CTL, tmp);
603 
604 	return 0;
605 }
606 
607 int
608 cn30xxgmx_tx_thresh(struct cn30xxgmx_port_softc *sc, int cnt)
609 {
610 	_GMX_PORT_WR8(sc, GMX0_TX0_THRESH, cnt);
611 	return 0;
612 }
613 
614 int
615 cn30xxgmx_set_mac_addr(struct cn30xxgmx_port_softc *sc, uint8_t *addr)
616 {
617 	uint64_t mac;
618 	int i;
619 
620 	ADDR2UINT64(mac, addr);
621 
622 	cn30xxgmx_link_enable(sc, 0);
623 
624 	sc->sc_mac = mac;
625 	_GMX_PORT_WR8(sc, GMX0_SMAC0, mac);
626 	for (i = 0; i < 6; i++)
627 		_GMX_PORT_WR8(sc, cn30xxgmx_rx_adr_cam_regs[i], addr[i]);
628 
629 	cn30xxgmx_link_enable(sc, 1);
630 
631 	return 0;
632 }
633 
634 #define	OCTEON_ETH_USE_GMX_CAM
635 
636 int
637 cn30xxgmx_set_filter(struct cn30xxgmx_port_softc *sc)
638 {
639 	struct ifnet *ifp = &sc->sc_port_ac->ac_if;
640 	struct arpcom *ac = sc->sc_port_ac;
641 #ifdef OCTEON_ETH_USE_GMX_CAM
642 	struct ether_multi *enm;
643 	struct ether_multistep step;
644 #endif
645 	uint64_t cam_en = 0x01ULL;
646 	uint64_t ctl = 0;
647 	int multi = 0;
648 
649 	cn30xxgmx_link_enable(sc, 0);
650 
651 	SET(ctl, RXN_ADR_CTL_CAM_MODE);
652 	CLR(ctl, RXN_ADR_CTL_MCST_ACCEPT | RXN_ADR_CTL_MCST_AFCAM |
653 	    RXN_ADR_CTL_MCST_REJECT);
654 	CLR(ifp->if_flags, IFF_ALLMULTI);
655 
656 	/*
657 	 * Always accept broadcast frames.
658 	 */
659 	SET(ctl, RXN_ADR_CTL_BCST);
660 
661 	if (ISSET(ifp->if_flags, IFF_PROMISC)) {
662 		SET(ifp->if_flags, IFF_ALLMULTI);
663 		CLR(ctl, RXN_ADR_CTL_CAM_MODE);
664 		SET(ctl, RXN_ADR_CTL_MCST_ACCEPT);
665 		cam_en = 0x00ULL;
666 	} else if (ac->ac_multirangecnt > 0 || ac->ac_multicnt > 7) {
667 		SET(ifp->if_flags, IFF_ALLMULTI);
668 		SET(ctl, RXN_ADR_CTL_MCST_ACCEPT);
669 	} else {
670 #ifdef OCTEON_ETH_USE_GMX_CAM
671 		/*
672 		 * Note first entry is self MAC address; other 7 entires are
673 		 * available for multicast addresses.
674 		 */
675 		ETHER_FIRST_MULTI(step, sc->sc_port_ac, enm);
676 		while (enm != NULL) {
677 			int i;
678 
679 			dprintf("%d: %02x:%02x:%02x:%02x:%02x:%02x\n"
680 			    multi + 1,
681 			    enm->enm_addrlo[0], enm->enm_addrlo[1],
682 			    enm->enm_addrlo[2], enm->enm_addrlo[3],
683 			    enm->enm_addrlo[4], enm->enm_addrlo[5]);
684 			multi++;
685 
686 			SET(cam_en, 1ULL << multi); /* XXX */
687 
688 			for (i = 0; i < 6; i++) {
689 				uint64_t tmp;
690 
691 				/* XXX */
692 				tmp = _GMX_PORT_RD8(sc,
693 				    cn30xxgmx_rx_adr_cam_regs[i]);
694 				CLR(tmp, 0xffULL << (8 * multi));
695 				SET(tmp, (uint64_t)enm->enm_addrlo[i] <<
696 				    (8 * multi));
697 				_GMX_PORT_WR8(sc, cn30xxgmx_rx_adr_cam_regs[i],
698 				    tmp);
699 			}
700 
701 			for (i = 0; i < 6; i++)
702 				dprintf("cam%d = %016llx\n", i,
703 				    _GMX_PORT_RD8(sc,
704 				    cn30xxgmx_rx_adr_cam_regs[i]));
705 
706 			ETHER_NEXT_MULTI(step, enm);
707 		}
708 
709 		if (multi)
710 			SET(ctl, RXN_ADR_CTL_MCST_AFCAM);
711 		else
712 			SET(ctl, RXN_ADR_CTL_MCST_REJECT);
713 
714 		OCTEON_ETH_KASSERT(enm == NULL);
715 #else
716 		/*
717 		 * XXX
718 		 * Never use DMAC filter for multicast addresses, but register
719 		 * only single entry for self address.  FreeBSD code do so.
720 		 */
721 		SET(ifp->if_flags, IFF_ALLMULTI);
722 		SET(ctl, RXN_ADR_CTL_MCST_ACCEPT);
723 #endif
724 	}
725 
726 	dprintf("ctl = %llx, cam_en = %llx\n", ctl, cam_en);
727 	_GMX_PORT_WR8(sc, GMX0_RX0_ADR_CTL, ctl);
728 	_GMX_PORT_WR8(sc, GMX0_RX0_ADR_CAM_EN, cam_en);
729 
730 	cn30xxgmx_link_enable(sc, 1);
731 
732 	return 0;
733 }
734 
735 int
736 cn30xxgmx_port_enable(struct cn30xxgmx_port_softc *sc, int enable)
737 {
738 	(*sc->sc_port_ops->port_ops_enable)(sc, enable);
739 	return 0;
740 }
741 
742 int
743 cn30xxgmx_reset_speed(struct cn30xxgmx_port_softc *sc)
744 {
745 	struct ifnet *ifp = &sc->sc_port_ac->ac_if;
746 	if (ISSET(sc->sc_port_mii->mii_flags, MIIF_DOINGAUTO)) {
747 		log(LOG_WARNING,
748 		    "%s: autonegotiation has not been completed yet\n",
749 		    ifp->if_xname);
750 		return 1;
751 	}
752 	(*sc->sc_port_ops->port_ops_speed)(sc);
753 	return 0;
754 }
755 
756 int
757 cn30xxgmx_reset_timing(struct cn30xxgmx_port_softc *sc)
758 {
759 	(*sc->sc_port_ops->port_ops_timing)(sc);
760 	return 0;
761 }
762 
763 int
764 cn30xxgmx_reset_board(struct cn30xxgmx_port_softc *sc)
765 {
766 
767 	return 0;
768 }
769 
770 int
771 cn30xxgmx_reset_flowctl(struct cn30xxgmx_port_softc *sc)
772 {
773 	struct ifmedia_entry *ife = sc->sc_port_mii->mii_media.ifm_cur;
774 
775 	/*
776 	 * Get flow control negotiation result.
777 	 */
778 #ifdef GMX_802_3X_DISABLE_AUTONEG
779 	/* Tentative support for SEIL-compat.. */
780 	if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) {
781 		sc->sc_port_flowflags &= ~IFM_ETH_FMASK;
782 	}
783 #else
784 	/* Default configuration of NetBSD */
785 	if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO &&
786 	    (sc->sc_port_mii->mii_media_active & IFM_ETH_FMASK) !=
787 			sc->sc_port_flowflags) {
788 		sc->sc_port_flowflags =
789 			sc->sc_port_mii->mii_media_active & IFM_ETH_FMASK;
790 		sc->sc_port_mii->mii_media_active &= ~IFM_ETH_FMASK;
791 	}
792 #endif /* GMX_802_3X_DISABLE_AUTONEG */
793 
794 	/*
795 	 * 802.3x Flow Control Capabilities
796 	 */
797 	if (sc->sc_port_flowflags & IFM_ETH_TXPAUSE) {
798 		cn30xxgmx_tx_ovr_bp_enable(sc, 1);
799 	} else {
800 		cn30xxgmx_tx_ovr_bp_enable(sc, 0);
801 	}
802 	if (sc->sc_port_flowflags & IFM_ETH_RXPAUSE) {
803 		cn30xxgmx_rx_pause_enable(sc, 1);
804 	} else {
805 		cn30xxgmx_rx_pause_enable(sc, 0);
806 	}
807 
808 	return 0;
809 }
810 
811 int
812 cn30xxgmx_rgmii_enable(struct cn30xxgmx_port_softc *sc, int enable)
813 {
814 	uint64_t mode;
815 
816 	/* XXX */
817 	mode = _GMX_RD8(sc, GMX0_INF_MODE);
818 	if (ISSET(mode, INF_MODE_EN)) {
819 		cn30xxasx_enable(sc->sc_port_asx, 1);
820 	}
821 
822 	return 0;
823 }
824 
825 int
826 cn30xxgmx_rgmii_speed(struct cn30xxgmx_port_softc *sc)
827 {
828 	struct ifnet *ifp = &sc->sc_port_ac->ac_if;
829 	uint64_t newlink;
830 	int baudrate;
831 
832 	/* XXX */
833 	cn30xxgmx_link_enable(sc, 1);
834 
835 	cn30xxgmx_rgmii_speed_newlink(sc, &newlink);
836 	if (sc->sc_link == newlink) {
837 		return 0;
838 	}
839 #ifdef OCTEON_ETH_DEBUG
840 	cn30xxgmx_rgmii_speed_newlink_log(sc, newlink);
841 #endif
842 	sc->sc_link = newlink;
843 
844 	switch (sc->sc_link & RXN_RX_INBND_SPEED) {
845 	case RXN_RX_INBND_SPEED_2_5:
846 		baudrate = IF_Mbps(10);
847 		break;
848 	case RXN_RX_INBND_SPEED_25:
849 		baudrate = IF_Mbps(100);
850 		break;
851 	case RXN_RX_INBND_SPEED_125:
852 		baudrate = IF_Gbps(1);
853 		break;
854 	default:
855 		baudrate = 0/* XXX */;
856 		break;
857 	}
858 	ifp->if_baudrate = baudrate;
859 
860 	cn30xxgmx_link_enable(sc, 0);
861 
862 	/*
863 	 * According to CN30XX-HM-1.0, 13.4.2 Link Status Changes:
864 	 * wait a max_packet_time
865 	 * max_packet_time(us) = (max_packet_size(bytes) * 8) / link_speed(Mbps)
866 	 */
867 	delay((GMX_FRM_MAX_SIZ * 8) / (baudrate / 1000000));
868 
869 	cn30xxgmx_rgmii_speed_speed(sc);
870 
871 	cn30xxgmx_link_enable(sc, 1);
872 	cn30xxasx_enable(sc->sc_port_asx, 1);
873 
874 	return 0;
875 }
876 
877 int
878 cn30xxgmx_rgmii_speed_newlink(struct cn30xxgmx_port_softc *sc,
879     uint64_t *rnewlink)
880 {
881 	uint64_t newlink;
882 
883 	/* Inband status does not seem to work */
884 	newlink = _GMX_PORT_RD8(sc, GMX0_RX0_RX_INBND);
885 
886 	*rnewlink = newlink;
887 	return 0;
888 }
889 
890 #ifdef OCTEON_ETH_DEBUG
891 int
892 cn30xxgmx_rgmii_speed_newlink_log(struct cn30xxgmx_port_softc *sc,
893     uint64_t newlink)
894 {
895 	struct ifnet *ifp = &sc->sc_port_ac->ac_if;
896 	const char *status_str;
897 	const char *speed_str;
898 	const char *duplex_str;
899 	int is_status_changed;
900 	int is_speed_changed;
901 	int is_linked;
902 	char status_buf[80/* XXX */];
903 	char speed_buf[80/* XXX */];
904 
905 	is_status_changed = (newlink & RXN_RX_INBND_STATUS) !=
906 	    (sc->sc_link & RXN_RX_INBND_STATUS);
907 	is_speed_changed = (newlink & RXN_RX_INBND_SPEED) !=
908 	    (sc->sc_link & RXN_RX_INBND_SPEED);
909 	is_linked = ISSET(newlink, RXN_RX_INBND_STATUS);
910 	if (is_status_changed) {
911 		if (is_linked)
912 			status_str = "link up";
913 		else
914 			status_str = "link down";
915 	} else {
916 		if (is_linked) {
917 			/* any other conditions? */
918 			if (is_speed_changed)
919 				status_str = "link change";
920 			else
921 				status_str = NULL;
922 		} else {
923 			status_str = NULL;
924 		}
925 	}
926 
927 	if (status_str != NULL) {
928 		if ((is_speed_changed && is_linked) || is_linked) {
929 			switch (newlink & RXN_RX_INBND_SPEED) {
930 			case RXN_RX_INBND_SPEED_2_5:
931 				speed_str = "10baseT";
932 				break;
933 			case RXN_RX_INBND_SPEED_25:
934 				speed_str = "100baseTX";
935 				break;
936 			case RXN_RX_INBND_SPEED_125:
937 				speed_str = "1000baseT";
938 				break;
939 			default:
940 				panic("Unknown link speed");
941 				break;
942 			}
943 
944 			if (ISSET(newlink, RXN_RX_INBND_DUPLEX))
945 				duplex_str = "-FDX";
946 			else
947 				duplex_str = "";
948 
949 			(void)snprintf(speed_buf, sizeof(speed_buf), "(%s%s)",
950 			    speed_str, duplex_str);
951 		} else {
952 			speed_buf[0] = '\0';
953 		}
954 		(void)snprintf(status_buf, sizeof(status_buf), "%s: %s%s%s\n",
955 		    ifp->if_xname, status_str, (is_speed_changed | is_linked) ? " " : "",
956 		    speed_buf);
957 		log(LOG_CRIT, status_buf);
958 	}
959 
960 	return 0;
961 }
962 #endif
963 
964 int
965 cn30xxgmx_rgmii_speed_speed(struct cn30xxgmx_port_softc *sc)
966 {
967 	uint64_t prt_cfg;
968 	uint64_t tx_clk, tx_slot, tx_burst;
969 
970 	prt_cfg = _GMX_PORT_RD8(sc, GMX0_PRT0_CFG);
971 
972 	switch (sc->sc_link & RXN_RX_INBND_SPEED) {
973 	case RXN_RX_INBND_SPEED_2_5:
974 		/* 10Mbps */
975 		/*
976 		 * "GMX Tx Clock Generation Registers", CN30XX-HM-1.0;
977 		 * > 8ns x 50 = 400ns (2.5MHz TXC clock)
978 		 */
979 		tx_clk = 50;
980 		/*
981 		 * "TX Slottime Counter Registers", CN30XX-HM-1.0;
982 		 * > 10/100Mbps: set SLOT to 0x40
983 		 */
984 		tx_slot = 0x40;
985 		/*
986 		 * "TX Burst-Counter Registers", CN30XX-HM-1.0;
987 		 * > 10/100Mbps: set BURST to 0x0
988 		 */
989 		tx_burst = 0;
990 		/*
991 		 * "GMX Tx Port Configuration Registers", CN30XX-HM-1.0;
992 		 * > Slot time for half-duplex operation
993 		 * >   0 = 512 bittimes (10/100Mbps operation)
994 		 */
995 		CLR(prt_cfg, PRTN_CFG_SLOTTIME);
996 		/*
997 		 * "GMX Port Configuration Registers", CN30XX-HM-1.0;
998 		 * > Link speed
999 		 * >   0 = 10/100Mbps operation
1000 		 * >     in RGMII mode: GMX0_TX(0..2)_CLK[CLK_CNT] > 1
1001 		 */
1002 		CLR(prt_cfg, PRTN_CFG_SPEED);
1003 		break;
1004 	case RXN_RX_INBND_SPEED_25:
1005 		/* 100Mbps */
1006 		/*
1007 		 * "GMX Tx Clock Generation Registers", CN30XX-HM-1.0;
1008 		 * > 8ns x 5 = 40ns (25.0MHz TXC clock)
1009 		 */
1010 		tx_clk = 5;
1011 		/*
1012 		 * "TX Slottime Counter Registers", CN30XX-HM-1.0;
1013 		 * > 10/100Mbps: set SLOT to 0x40
1014 		 */
1015 		tx_slot = 0x40;
1016 		/*
1017 		 * "TX Burst-Counter Registers", CN30XX-HM-1.0;
1018 		 * > 10/100Mbps: set BURST to 0x0
1019 		 */
1020 		tx_burst = 0;
1021 		/*
1022 		 * "GMX Tx Port Configuration Registers", CN30XX-HM-1.0;
1023 		 * > Slot time for half-duplex operation
1024 		 * >   0 = 512 bittimes (10/100Mbps operation)
1025 		 */
1026 		CLR(prt_cfg, PRTN_CFG_SLOTTIME);
1027 		/*
1028 		 * "GMX Port Configuration Registers", CN30XX-HM-1.0;
1029 		 * > Link speed
1030 		 * >   0 = 10/100Mbps operation
1031 		 * >     in RGMII mode: GMX0_TX(0..2)_CLK[CLK_CNT] > 1
1032 		 */
1033 		CLR(prt_cfg, PRTN_CFG_SPEED);
1034 		break;
1035 	case RXN_RX_INBND_SPEED_125:
1036 		/* 1000Mbps */
1037 		/*
1038 		 * "GMX Tx Clock Generation Registers", CN30XX-HM-1.0;
1039 		 * > 8ns x 1 = 8ns (125.0MHz TXC clock)
1040 		 */
1041 		tx_clk = 1;
1042 		/*
1043 		 * "TX Slottime Counter Registers", CN30XX-HM-1.0;
1044 		 * > 1000Mbps: set SLOT to 0x200
1045 		 */
1046 		tx_slot = 0x200;
1047 		/*
1048 		 * "TX Burst-Counter Registers", CN30XX-HM-1.0;
1049 		 * > 1000Mbps: set BURST to 0x2000
1050 		 */
1051 		tx_burst = 0x2000;
1052 		/*
1053 		 * "GMX Tx Port Configuration Registers", CN30XX-HM-1.0;
1054 		 * > Slot time for half-duplex operation
1055 		 * >   1 = 4096 bittimes (1000Mbps operation)
1056 		 */
1057 		SET(prt_cfg, PRTN_CFG_SLOTTIME);
1058 		/*
1059 		 * "GMX Port Configuration Registers", CN30XX-HM-1.0;
1060 		 * > Link speed
1061 		 * >   1 = 1000Mbps operation
1062 		 */
1063 		SET(prt_cfg, PRTN_CFG_SPEED);
1064 		break;
1065 	default:
1066 		/* NOT REACHED! */
1067 		/* Following configuration is default value of system.
1068 		*/
1069 		tx_clk = 1;
1070 		tx_slot = 0x200;
1071 		tx_burst = 0x2000;
1072 		SET(prt_cfg, PRTN_CFG_SLOTTIME);
1073 		SET(prt_cfg, PRTN_CFG_SPEED);
1074 		break;
1075 	}
1076 
1077 	/* Setup Duplex mode(negotiated) */
1078 	/*
1079 	 * "GMX Port Configuration Registers", CN30XX-HM-1.0;
1080 	 * > Duplex mode: 0 = half-duplex mode, 1=full-duplex
1081 	 */
1082 	if (ISSET(sc->sc_link, RXN_RX_INBND_DUPLEX)) {
1083 		/* Full-Duplex */
1084 		SET(prt_cfg, PRTN_CFG_DUPLEX);
1085 	} else {
1086 		/* Half-Duplex */
1087 		CLR(prt_cfg, PRTN_CFG_DUPLEX);
1088 	}
1089 
1090 	_GMX_PORT_WR8(sc, GMX0_TX0_CLK, tx_clk);
1091 	_GMX_PORT_WR8(sc, GMX0_TX0_SLOT, tx_slot);
1092 	_GMX_PORT_WR8(sc, GMX0_TX0_BURST, tx_burst);
1093 	_GMX_PORT_WR8(sc, GMX0_PRT0_CFG, prt_cfg);
1094 
1095 	return 0;
1096 }
1097 
1098 int
1099 cn30xxgmx_rgmii_timing(struct cn30xxgmx_port_softc *sc)
1100 {
1101 	int clk_tx_setting;
1102 	int clk_rx_setting;
1103 	uint64_t rx_frm_ctl;
1104 
1105 	/* RGMII TX Threshold Registers, CN30XX-HM-1.0;
1106 	 * > Number of 16-byte ticks to accumulate in the TX FIFO before
1107 	 * > sending on the RGMII interface. This field should be large
1108 	 * > enough to prevent underflow on the RGMII interface and must
1109 	 * > never be set to less than 0x4. This register cannot exceed
1110 	 * > the TX FIFO depth of 0x40 words.
1111 	 */
1112 	/* Default parameter of CN30XX */
1113 	cn30xxgmx_tx_thresh(sc, 32);
1114 
1115 	rx_frm_ctl = 0 |
1116 	    /* RXN_FRM_CTL_NULL_DIS |	(cn5xxx only) */
1117 	    /* RXN_FRM_CTL_PRE_ALIGN |	(cn5xxx only) */
1118 	    /* RXN_FRM_CTL_PAD_LEN |	(cn3xxx only) */
1119 	    /* RXN_FRM_CTL_VLAN_LEN |	(cn3xxx only) */
1120 	    RXN_FRM_CTL_PRE_FREE |
1121 	    RXN_FRM_CTL_CTL_SMAC |
1122 	    RXN_FRM_CTL_CTL_MCST |
1123 	    RXN_FRM_CTL_CTL_DRP |
1124 	    RXN_FRM_CTL_PRE_STRP |
1125 	    RXN_FRM_CTL_PRE_CHK;
1126 	cn30xxgmx_rx_frm_ctl_enable(sc, rx_frm_ctl);
1127 
1128 	/* XXX PHY-dependent parameter */
1129 	/* RGMII RX Clock-Delay Registers, CN30XX-HM-1.0;
1130 	 * > Delay setting to place n RXC (RGMII receive clock) delay line.
1131 	 * > The intrinsic delay can range from 50ps to 80ps per tap,
1132 	 * > which corresponds to skews of 1.25ns to 2.00ns at 25 taps(CSR+1).
1133 	 * > This is the best match for the RGMII specification which wants
1134 	 * > 1ns - 2.6ns of skew.
1135 	 */
1136 	/* RGMII TX Clock-Delay Registers, CN30XX-HM-1.0;
1137 	 * > Delay setting to place n TXC (RGMII transmit clock) delay line.
1138 	 * > ...
1139 	 */
1140 
1141 	switch (octeon_boot_info->board_type) {
1142 	default:
1143 		/* Default parameter of CN30XX */
1144 		clk_tx_setting = 24;
1145 		clk_rx_setting = 24;
1146 		break;
1147 	case BOARD_TYPE_UBIQUITI_E100:
1148 		clk_tx_setting = 16;
1149 		clk_rx_setting = 0;
1150 		break;
1151 	}
1152 
1153 	cn30xxasx_clk_set(sc->sc_port_asx, clk_tx_setting, clk_rx_setting);
1154 
1155 	return 0;
1156 }
1157 
1158 int
1159 cn30xxgmx_sgmii_enable(struct cn30xxgmx_port_softc *sc, int enable)
1160 {
1161 	uint64_t ctl_reg, status, timer_count;
1162 	uint64_t cpu_freq = octeon_boot_info->eclock / 1000000;
1163 	int done;
1164 	int i;
1165 
1166 	if (!enable)
1167 		return 0;
1168 
1169 	/* Set link timer interval to 1.6ms. */
1170 	timer_count = PCS_READ_8(sc, PCS_LINK_TIMER_COUNT);
1171 	CLR(timer_count, PCS_LINK_TIMER_COUNT_MASK);
1172 	SET(timer_count, ((1600 * cpu_freq) >> 10) & PCS_LINK_TIMER_COUNT_MASK);
1173 	PCS_WRITE_8(sc, PCS_LINK_TIMER_COUNT, timer_count);
1174 
1175 	/* Reset the PCS. */
1176 	ctl_reg = PCS_READ_8(sc, PCS_MR_CONTROL);
1177 	SET(ctl_reg, PCS_MR_CONTROL_RESET);
1178 	PCS_WRITE_8(sc, PCS_MR_CONTROL, ctl_reg);
1179 
1180 	/* Wait for the reset to complete. */
1181 	done = 0;
1182 	for (i = 0; i < 1000000; i++) {
1183 		ctl_reg = PCS_READ_8(sc, PCS_MR_CONTROL);
1184 		if (!ISSET(ctl_reg, PCS_MR_CONTROL_RESET)) {
1185 			done = 1;
1186 			break;
1187 		}
1188 	}
1189 	if (!done) {
1190 		printf("SGMII reset timeout on port %d\n", sc->sc_port_no);
1191 		return 1;
1192 	}
1193 
1194 	/* Start a new SGMII autonegotiation. */
1195 	SET(ctl_reg, PCS_MR_CONTROL_AN_EN);
1196 	SET(ctl_reg, PCS_MR_CONTROL_RST_AN);
1197 	CLR(ctl_reg, PCS_MR_CONTROL_PWR_DN);
1198 	PCS_WRITE_8(sc, PCS_MR_CONTROL, ctl_reg);
1199 
1200 	/* Wait for the SGMII autonegotiation to complete. */
1201 	done = 0;
1202 	for (i = 0; i < 1000000; i++) {
1203 		status = PCS_READ_8(sc, PCS_MR_STATUS);
1204 		if (ISSET(status, PCS_MR_STATUS_AN_CPT)) {
1205 			done = 1;
1206 			break;
1207 		}
1208 	}
1209 	if (!done) {
1210 		printf("SGMII autonegotiation timeout on port %d\n",
1211 		    sc->sc_port_no);
1212 		return 1;
1213 	}
1214 
1215 	return 0;
1216 }
1217 
1218 int
1219 cn30xxgmx_sgmii_speed(struct cn30xxgmx_port_softc *sc)
1220 {
1221 	uint64_t misc_ctl, prt_cfg;
1222 	int tx_burst, tx_slot;
1223 
1224 	cn30xxgmx_link_enable(sc, 0);
1225 
1226 	prt_cfg = _GMX_PORT_RD8(sc, GMX0_PRT0_CFG);
1227 
1228 	if (ISSET(sc->sc_port_mii->mii_media_active, IFM_FDX))
1229 		SET(prt_cfg, PRTN_CFG_DUPLEX);
1230 	else
1231 		CLR(prt_cfg, PRTN_CFG_DUPLEX);
1232 
1233 	misc_ctl = PCS_READ_8(sc, PCS_MISC_CTL);
1234 	CLR(misc_ctl, PCS_MISC_CTL_SAMP_PT);
1235 
1236 	/* Disable the GMX port if the link is down. */
1237 	if (cn30xxgmx_link_status(sc))
1238 		CLR(misc_ctl, PCS_MISC_CTL_GMXENO);
1239 	else
1240 		SET(misc_ctl, PCS_MISC_CTL_GMXENO);
1241 
1242 	switch (sc->sc_port_ac->ac_if.if_baudrate) {
1243 	case IF_Mbps(10):
1244 		tx_slot = 0x40;
1245 		tx_burst = 0;
1246 		CLR(prt_cfg, PRTN_CFG_SPEED);
1247 		SET(prt_cfg, PRTN_CFG_SPEED_MSB);
1248 		CLR(prt_cfg, PRTN_CFG_SLOTTIME);
1249 		misc_ctl |= 25 & PCS_MISC_CTL_SAMP_PT;
1250 		break;
1251 	case IF_Mbps(100):
1252 		tx_slot = 0x40;
1253 		tx_burst = 0;
1254 		CLR(prt_cfg, PRTN_CFG_SPEED);
1255 		CLR(prt_cfg, PRTN_CFG_SPEED_MSB);
1256 		CLR(prt_cfg, PRTN_CFG_SLOTTIME);
1257 		misc_ctl |= 5 & PCS_MISC_CTL_SAMP_PT;
1258 		break;
1259 	case IF_Gbps(1):
1260 	default:
1261 		tx_slot = 0x200;
1262 		tx_burst = 0x2000;
1263 		SET(prt_cfg, PRTN_CFG_SPEED);
1264 		CLR(prt_cfg, PRTN_CFG_SPEED_MSB);
1265 		SET(prt_cfg, PRTN_CFG_SLOTTIME);
1266 		misc_ctl |= 1 & PCS_MISC_CTL_SAMP_PT;
1267 		break;
1268 	}
1269 
1270 	PCS_WRITE_8(sc, PCS_MISC_CTL, misc_ctl);
1271 
1272 	_GMX_PORT_WR8(sc, GMX0_TX0_SLOT, tx_slot);
1273 	_GMX_PORT_WR8(sc, GMX0_TX0_BURST, tx_burst);
1274 	_GMX_PORT_WR8(sc, GMX0_PRT0_CFG, prt_cfg);
1275 
1276 	cn30xxgmx_link_enable(sc, 1);
1277 
1278 	return 0;
1279 }
1280 
1281 int
1282 cn30xxgmx_sgmii_timing(struct cn30xxgmx_port_softc *sc)
1283 {
1284 	uint64_t rx_frm_ctl;
1285 
1286 	cn30xxgmx_tx_thresh(sc, 32);
1287 
1288 	rx_frm_ctl =
1289 	    RXN_FRM_CTL_PRE_FREE |
1290 	    RXN_FRM_CTL_CTL_SMAC |
1291 	    RXN_FRM_CTL_CTL_MCST |
1292 	    RXN_FRM_CTL_CTL_DRP |
1293 	    RXN_FRM_CTL_PRE_STRP |
1294 	    RXN_FRM_CTL_PRE_CHK;
1295 	cn30xxgmx_rx_frm_ctl_enable(sc, rx_frm_ctl);
1296 
1297 	return 0;
1298 }
1299 
1300 void
1301 cn30xxgmx_stats(struct cn30xxgmx_port_softc *sc)
1302 {
1303 	struct ifnet *ifp = &sc->sc_port_ac->ac_if;
1304 	uint64_t tmp;
1305 
1306 	ifp->if_ierrors +=
1307 	    (uint32_t)_GMX_PORT_RD8(sc, GMX0_RX0_STATS_PKTS_BAD);
1308 	ifp->if_iqdrops +=
1309 	    (uint32_t)_GMX_PORT_RD8(sc, GMX0_RX0_STATS_PKTS_DRP);
1310 	ifp->if_opackets +=
1311 	    (uint32_t)_GMX_PORT_RD8(sc, GMX0_TX0_STAT3);
1312 	tmp = _GMX_PORT_RD8(sc, GMX0_TX0_STAT0);
1313 	ifp->if_oerrors +=
1314 	    (uint32_t)tmp + ((uint32_t)(tmp >> 32) * 16);
1315 	ifp->if_collisions += ((uint32_t)tmp) * 16;
1316 	tmp = _GMX_PORT_RD8(sc, GMX0_TX0_STAT1);
1317 	ifp->if_collisions +=
1318 	    ((uint32_t)tmp * 2) + (uint32_t)(tmp >> 32);
1319 	tmp = _GMX_PORT_RD8(sc, GMX0_TX0_STAT9);
1320 	ifp->if_oerrors += (uint32_t)(tmp >> 32);
1321 }
1322 
1323 /* ---- DMAC filter */
1324 
1325 #ifdef notyet
1326 /*
1327  * DMAC filter configuration
1328  *	accept all
1329  *	reject 0 addrs (virtually accept all?)
1330  *	reject N addrs
1331  *	accept N addrs
1332  *	accept 0 addrs (virtually reject all?)
1333  *	reject all
1334  */
1335 
1336 /* XXX local namespace */
1337 #define	_POLICY			CN30XXGMX_FILTER_POLICY
1338 #define	_POLICY_ACCEPT_ALL	CN30XXGMX_FILTER_POLICY_ACCEPT_ALL
1339 #define	_POLICY_ACCEPT		CN30XXGMX_FILTER_POLICY_ACCEPT
1340 #define	_POLICY_REJECT		CN30XXGMX_FILTER_POLICY_REJECT
1341 #define	_POLICY_REJECT_ALL	CN30XXGMX_FILTER_POLICY_REJECT_ALL
1342 
1343 int	cn30xxgmx_setfilt_addrs(struct cn30xxgmx_port_softc *,
1344 	    size_t, uint8_t **);
1345 
1346 int
1347 cn30xxgmx_setfilt(struct cn30xxgmx_port_softc *sc, enum _POLICY policy,
1348     size_t naddrs, uint8_t **addrs)
1349 {
1350 	uint64_t rx_adr_ctl;
1351 
1352 	KASSERT(policy >= _POLICY_ACCEPT_ALL);
1353 	KASSERT(policy <= _POLICY_REJECT_ALL);
1354 
1355 	rx_adr_ctl = _GMX_PORT_RD8(sc, GMX0_RX0_ADR_CTL);
1356 	CLR(rx_adr_ctl, RXN_ADR_CTL_CAM_MODE | RXN_ADR_CTL_MCST);
1357 
1358 	switch (policy) {
1359 	case _POLICY_ACCEPT_ALL:
1360 	case _POLICY_REJECT_ALL:
1361 		KASSERT(naddrs == 0);
1362 		KASSERT(addrs == NULL);
1363 
1364 		SET(rx_adr_ctl, (policy == _POLICY_ACCEPT_ALL) ?
1365 		    RXN_ADR_CTL_MCST_ACCEPT : RXN_ADR_CTL_MCST_REJECT);
1366 		break;
1367 	case _POLICY_ACCEPT:
1368 	case _POLICY_REJECT:
1369 		if (naddrs > CN30XXGMX_FILTER_NADDRS_MAX)
1370 			return E2BIG;
1371 		SET(rx_adr_ctl, (policy == _POLICY_ACCEPT) ?
1372 		    RXN_ADR_CTL_CAM_MODE : 0);
1373 		SET(rx_adr_ctl, RXN_ADR_CTL_MCST_AFCAM);
1374 		/* set GMX0_RXN_ADR_CAM_EN, GMX0_RXN_ADR_CAM[0-5] */
1375 		cn30xxgmx_setfilt_addrs(sc, naddrs, addrs);
1376 		break;
1377 	}
1378 
1379 	/* set GMX0_RXN_ADR_CTL[MCST] */
1380 	_GMX_PORT_WR8(sc, GMX0_RX0_ADR_CTL, rx_adr_ctl);
1381 
1382 	return 0;
1383 }
1384 
1385 int
1386 cn30xxgmx_setfilt_addrs(struct cn30xxgmx_port_softc *sc, size_t naddrs,
1387     uint8_t **addrs)
1388 {
1389 	uint64_t rx_adr_cam_en;
1390 	uint64_t rx_adr_cam_addrs[CN30XXGMX_FILTER_NADDRS_MAX];
1391 	int i, j;
1392 
1393 	KASSERT(naddrs <= CN30XXGMX_FILTER_NADDRS_MAX);
1394 
1395 	rx_adr_cam_en = 0;
1396 	(void)memset(rx_adr_cam_addrs, 0, sizeof(rx_adr_cam_addrs));
1397 
1398 	for (i = 0; i < naddrs; i++) {
1399 		SET(rx_adr_cam_en, 1ULL << i);
1400 		for (j = 0; j < 6; j++)
1401 			SET(rx_adr_cam_addrs[j],
1402 			    (uint64_t)addrs[i][j] << (8 * i));
1403 	}
1404 
1405 	/* set GMX0_RXN_ADR_CAM_EN, GMX0_RXN_ADR_CAM[0-5] */
1406 	_GMX_PORT_WR8(sc, GMX0_RX0_ADR_CAM_EN, rx_adr_cam_en);
1407 	for (j = 0; j < 6; j++)
1408 		_GMX_PORT_WR8(sc, cn30xxgmx_rx_adr_cam_regs[j],
1409 		    rx_adr_cam_addrs[j]);
1410 
1411 	return 0;
1412 }
1413 #endif
1414 
1415 /* ---- interrupt */
1416 
1417 #ifdef OCTEON_ETH_DEBUG
1418 void	cn30xxgmx_intr_rml_gmx0(void);
1419 
1420 int	cn30xxgmx_intr_rml_verbose;
1421 
1422 void
1423 cn30xxgmx_intr_rml_gmx0(void)
1424 {
1425 	struct cn30xxgmx_port_softc *sc;
1426 	int i;
1427 	uint64_t reg;
1428 
1429 	sc = __cn30xxgmx_port_softc[0];
1430 	if (sc == NULL)
1431 		return;
1432 
1433 	/* GMX0_RXn_INT_REG or GMX0_TXn_INT_REG */
1434 	reg = cn30xxgmx_get_tx_int_reg(sc);
1435 	if (cn30xxgmx_intr_rml_verbose && reg != 0)
1436 		printf("%s: GMX_TX_INT_REG=0x%016llx\n", __func__, reg);
1437 
1438 	for (i = 0; i < GMX_PORT_NUNITS; i++) {
1439 		sc = __cn30xxgmx_port_softc[i];
1440 		if (sc == NULL)
1441 			continue;
1442 		reg = cn30xxgmx_get_rx_int_reg(sc);
1443 		if (cn30xxgmx_intr_rml_verbose)
1444 			printf("%s: GMX_RX_INT_REG=0x%016llx\n", __func__, reg);
1445 	}
1446 }
1447 
1448 int
1449 cn30xxgmx_intr_drop(void *arg)
1450 {
1451 	octeon_xkphys_write_8(CIU_INT0_SUM0, CIU_INTX_SUM0_GMX_DRP);
1452 	return (1);
1453 }
1454 
1455 uint64_t
1456 cn30xxgmx_get_rx_int_reg(struct cn30xxgmx_port_softc *sc)
1457 {
1458 	uint64_t reg;
1459 	uint64_t rx_int_reg = 0;
1460 
1461 	reg = _GMX_PORT_RD8(sc, GMX0_RX0_INT_REG);
1462 	/* clear */
1463 	SET(rx_int_reg, 0 |
1464 	    RXN_INT_REG_PHY_DUPX |
1465 	    RXN_INT_REG_PHY_SPD |
1466 	    RXN_INT_REG_PHY_LINK |
1467 	    RXN_INT_REG_IFGERR |
1468 	    RXN_INT_REG_COLDET |
1469 	    RXN_INT_REG_FALERR |
1470 	    RXN_INT_REG_RSVERR |
1471 	    RXN_INT_REG_PCTERR |
1472 	    RXN_INT_REG_OVRERR |
1473 	    RXN_INT_REG_NIBERR |
1474 	    RXN_INT_REG_SKPERR |
1475 	    RXN_INT_REG_RCVERR |
1476 	    RXN_INT_REG_LENERR |
1477 	    RXN_INT_REG_ALNERR |
1478 	    RXN_INT_REG_FCSERR |
1479 	    RXN_INT_REG_JABBER |
1480 	    RXN_INT_REG_MAXERR |
1481 	    RXN_INT_REG_CAREXT |
1482 	    RXN_INT_REG_MINERR);
1483 	_GMX_PORT_WR8(sc, GMX0_RX0_INT_REG, rx_int_reg);
1484 
1485 	return reg;
1486 }
1487 
1488 uint64_t
1489 cn30xxgmx_get_tx_int_reg(struct cn30xxgmx_port_softc *sc)
1490 {
1491 	uint64_t reg;
1492 	uint64_t tx_int_reg = 0;
1493 
1494 	reg = _GMX_PORT_RD8(sc, GMX0_TX_INT_REG);
1495 	/* clear */
1496 	SET(tx_int_reg, 0 |
1497 	    TX_INT_REG_LATE_COL |
1498 	    TX_INT_REG_XSDEF |
1499 	    TX_INT_REG_XSCOL |
1500 	    TX_INT_REG_UNDFLW |
1501 	    TX_INT_REG_PKO_NXA);
1502 	_GMX_PORT_WR8(sc, GMX0_TX_INT_REG, tx_int_reg);
1503 
1504 	return reg;
1505 }
1506 #endif	/* OCTEON_ETH_DEBUG */
1507 
1508 /* ---- debug */
1509 
1510 #ifdef OCTEON_ETH_DEBUG
1511 #define	_ENTRY(x)	{ #x, x }
1512 
1513 struct cn30xxgmx_dump_reg_ {
1514 	const char *name;
1515 	size_t	offset;
1516 };
1517 
1518 const struct cn30xxgmx_dump_reg_ cn30xxgmx_dump_regs_[] = {
1519 	_ENTRY(GMX0_SMAC0),
1520 	_ENTRY(GMX0_BIST0),
1521 	_ENTRY(GMX0_RX_PRTS),
1522 	_ENTRY(GMX0_RX_BP_DROP0),
1523 	_ENTRY(GMX0_RX_BP_DROP1),
1524 	_ENTRY(GMX0_RX_BP_DROP2),
1525 	_ENTRY(GMX0_RX_BP_ON0),
1526 	_ENTRY(GMX0_RX_BP_ON1),
1527 	_ENTRY(GMX0_RX_BP_ON2),
1528 	_ENTRY(GMX0_RX_BP_OFF0),
1529 	_ENTRY(GMX0_RX_BP_OFF1),
1530 	_ENTRY(GMX0_RX_BP_OFF2),
1531 	_ENTRY(GMX0_TX_PRTS),
1532 	_ENTRY(GMX0_TX_IFG),
1533 	_ENTRY(GMX0_TX_JAM),
1534 	_ENTRY(GMX0_TX_COL_ATTEMPT),
1535 	_ENTRY(GMX0_TX_PAUSE_PKT_DMAC),
1536 	_ENTRY(GMX0_TX_PAUSE_PKT_TYPE),
1537 	_ENTRY(GMX0_TX_OVR_BP),
1538 	_ENTRY(GMX0_TX_BP),
1539 	_ENTRY(GMX0_TX_CORRUPT),
1540 	_ENTRY(GMX0_RX_PRT_INFO),
1541 	_ENTRY(GMX0_TX_LFSR),
1542 	_ENTRY(GMX0_TX_INT_REG),
1543 	_ENTRY(GMX0_TX_INT_EN),
1544 	_ENTRY(GMX0_NXA_ADR),
1545 	_ENTRY(GMX0_BAD_REG),
1546 	_ENTRY(GMX0_STAT_BP),
1547 	_ENTRY(GMX0_TX_CLK_MSK0),
1548 	_ENTRY(GMX0_TX_CLK_MSK1),
1549 	_ENTRY(GMX0_RX_TX_STATUS),
1550 	_ENTRY(GMX0_INF_MODE),
1551 };
1552 
1553 const struct cn30xxgmx_dump_reg_ cn30xxgmx_dump_port_regs_[] = {
1554 	_ENTRY(GMX0_RX0_INT_REG),
1555 	_ENTRY(GMX0_RX0_INT_EN),
1556 	_ENTRY(GMX0_PRT0_CFG),
1557 	_ENTRY(GMX0_RX0_FRM_CTL),
1558 	_ENTRY(GMX0_RX0_FRM_CHK),
1559 	_ENTRY(GMX0_RX0_FRM_MIN),
1560 	_ENTRY(GMX0_RX0_FRM_MAX),
1561 	_ENTRY(GMX0_RX0_JABBER),
1562 	_ENTRY(GMX0_RX0_DECISION),
1563 	_ENTRY(GMX0_RX0_UDD_SKP),
1564 	_ENTRY(GMX0_RX0_STATS_CTL),
1565 	_ENTRY(GMX0_RX0_IFG),
1566 	_ENTRY(GMX0_RX0_RX_INBND),
1567 	_ENTRY(GMX0_RX0_ADR_CTL),
1568 	_ENTRY(GMX0_RX0_ADR_CAM_EN),
1569 	_ENTRY(GMX0_RX0_ADR_CAM0),
1570 	_ENTRY(GMX0_RX0_ADR_CAM1),
1571 	_ENTRY(GMX0_RX0_ADR_CAM2),
1572 	_ENTRY(GMX0_RX0_ADR_CAM3),
1573 	_ENTRY(GMX0_RX0_ADR_CAM4),
1574 	_ENTRY(GMX0_RX0_ADR_CAM5),
1575 	_ENTRY(GMX0_TX0_CLK),
1576 	_ENTRY(GMX0_TX0_THRESH),
1577 	_ENTRY(GMX0_TX0_APPEND),
1578 	_ENTRY(GMX0_TX0_SLOT),
1579 	_ENTRY(GMX0_TX0_BURST),
1580 	_ENTRY(GMX0_TX0_PAUSE_PKT_TIME),
1581 	_ENTRY(GMX0_TX0_MIN_PKT),
1582 	_ENTRY(GMX0_TX0_PAUSE_PKT_INTERVAL),
1583 	_ENTRY(GMX0_TX0_SOFT_PAUSE),
1584 	_ENTRY(GMX0_TX0_PAUSE_TOGO),
1585 	_ENTRY(GMX0_TX0_PAUSE_ZERO),
1586 	_ENTRY(GMX0_TX0_STATS_CTL),
1587 	_ENTRY(GMX0_TX0_CTL),
1588 };
1589 
1590 const struct cn30xxgmx_dump_reg_ cn30xxgmx_dump_port_stats_[] = {
1591 	_ENTRY(GMX0_RX0_STATS_PKTS),
1592 	_ENTRY(GMX0_RX0_STATS_OCTS),
1593 	_ENTRY(GMX0_RX0_STATS_PKTS_CTL),
1594 	_ENTRY(GMX0_RX0_STATS_OCTS_CTL),
1595 	_ENTRY(GMX0_RX0_STATS_PKTS_DMAC),
1596 	_ENTRY(GMX0_RX0_STATS_OCTS_DMAC),
1597 	_ENTRY(GMX0_RX0_STATS_PKTS_DRP),
1598 	_ENTRY(GMX0_RX0_STATS_OCTS_DRP),
1599 	_ENTRY(GMX0_RX0_STATS_PKTS_BAD),
1600 	_ENTRY(GMX0_TX0_STAT0),
1601 	_ENTRY(GMX0_TX0_STAT1),
1602 	_ENTRY(GMX0_TX0_STAT2),
1603 	_ENTRY(GMX0_TX0_STAT3),
1604 	_ENTRY(GMX0_TX0_STAT4),
1605 	_ENTRY(GMX0_TX0_STAT5),
1606 	_ENTRY(GMX0_TX0_STAT6),
1607 	_ENTRY(GMX0_TX0_STAT7),
1608 	_ENTRY(GMX0_TX0_STAT8),
1609 	_ENTRY(GMX0_TX0_STAT9),
1610 };
1611 
1612 void	cn30xxgmx_dump_common(void);
1613 void	cn30xxgmx_dump_port0(void);
1614 void	cn30xxgmx_dump_port1(void);
1615 void	cn30xxgmx_dump_port2(void);
1616 void	cn30xxgmx_dump_port0_regs(void);
1617 void	cn30xxgmx_dump_port1_regs(void);
1618 void	cn30xxgmx_dump_port2_regs(void);
1619 void	cn30xxgmx_dump_port0_stats(void);
1620 void	cn30xxgmx_dump_port1_stats(void);
1621 void	cn30xxgmx_dump_port2_stats(void);
1622 void	cn30xxgmx_dump_port_regs(int);
1623 void	cn30xxgmx_dump_port_stats(int);
1624 void	cn30xxgmx_dump_common_x(int, const struct cn30xxgmx_dump_reg_ *, size_t);
1625 void	cn30xxgmx_dump_port_x(int, const struct cn30xxgmx_dump_reg_ *, size_t);
1626 void	cn30xxgmx_dump_x(int, const struct cn30xxgmx_dump_reg_ *, size_t, size_t, int);
1627 void	cn30xxgmx_dump_x_index(char *, size_t, int);
1628 
1629 void
1630 cn30xxgmx_dump(void)
1631 {
1632 	cn30xxgmx_dump_common();
1633 	cn30xxgmx_dump_port0();
1634 	cn30xxgmx_dump_port1();
1635 	cn30xxgmx_dump_port2();
1636 }
1637 
1638 void
1639 cn30xxgmx_dump_common(void)
1640 {
1641 	cn30xxgmx_dump_common_x(0, cn30xxgmx_dump_regs_,
1642 	    nitems(cn30xxgmx_dump_regs_));
1643 }
1644 
1645 void
1646 cn30xxgmx_dump_port0(void)
1647 {
1648 	cn30xxgmx_dump_port_regs(0);
1649 	cn30xxgmx_dump_port_stats(0);
1650 }
1651 
1652 void
1653 cn30xxgmx_dump_port1(void)
1654 {
1655 	cn30xxgmx_dump_port_regs(1);
1656 	cn30xxgmx_dump_port_stats(1);
1657 }
1658 
1659 void
1660 cn30xxgmx_dump_port2(void)
1661 {
1662 	cn30xxgmx_dump_port_regs(2);
1663 	cn30xxgmx_dump_port_stats(2);
1664 }
1665 
1666 void
1667 cn30xxgmx_dump_port_regs(int portno)
1668 {
1669 	cn30xxgmx_dump_port_x(portno, cn30xxgmx_dump_port_regs_,
1670 	    nitems(cn30xxgmx_dump_port_regs_));
1671 }
1672 
1673 void
1674 cn30xxgmx_dump_port_stats(int portno)
1675 {
1676 	struct cn30xxgmx_port_softc *sc = __cn30xxgmx_port_softc[0];
1677 	uint64_t rx_stats_ctl;
1678 	uint64_t tx_stats_ctl;
1679 
1680 	rx_stats_ctl = _GMX_RD8(sc, GMX0_BASE_PORT_SIZE * portno + GMX0_RX0_STATS_CTL);
1681 	_GMX_WR8(sc, GMX0_BASE_PORT_SIZE * portno + GMX0_RX0_STATS_CTL,
1682 	    rx_stats_ctl & ~RXN_STATS_CTL_RD_CLR);
1683 	tx_stats_ctl = _GMX_RD8(sc, GMX0_BASE_PORT_SIZE * portno + GMX0_TX0_STATS_CTL);
1684 	_GMX_WR8(sc, GMX0_BASE_PORT_SIZE * portno + GMX0_TX0_STATS_CTL,
1685 	    tx_stats_ctl & ~TXN_STATS_CTL_RD_CLR);
1686 	cn30xxgmx_dump_port_x(portno, cn30xxgmx_dump_port_stats_,
1687 	    nitems(cn30xxgmx_dump_port_stats_));
1688 	_GMX_WR8(sc, GMX0_BASE_PORT_SIZE * portno + GMX0_RX0_STATS_CTL, rx_stats_ctl);
1689 	_GMX_WR8(sc, GMX0_BASE_PORT_SIZE * portno + GMX0_TX0_STATS_CTL, tx_stats_ctl);
1690 }
1691 
1692 void
1693 cn30xxgmx_dump_common_x(int portno, const struct cn30xxgmx_dump_reg_ *regs, size_t size)
1694 {
1695 	cn30xxgmx_dump_x(portno, regs, size, 0, 0);
1696 }
1697 
1698 void
1699 cn30xxgmx_dump_port_x(int portno, const struct cn30xxgmx_dump_reg_ *regs, size_t size)
1700 {
1701 	cn30xxgmx_dump_x(portno, regs, size, GMX0_BASE_PORT_SIZE * portno, 1);
1702 }
1703 
1704 void
1705 cn30xxgmx_dump_x(int portno, const struct cn30xxgmx_dump_reg_ *regs, size_t size, size_t base, int index)
1706 {
1707 	struct cn30xxgmx_port_softc *sc = __cn30xxgmx_port_softc[0];
1708 	const struct cn30xxgmx_dump_reg_ *reg;
1709 	uint64_t tmp;
1710 	char name[64];
1711 	int i;
1712 
1713 	for (i = 0; i < (int)size; i++) {
1714 		reg = &regs[i];
1715 		tmp = _GMX_RD8(sc, base + reg->offset);
1716 
1717 		snprintf(name, sizeof(name), "%s", reg->name);
1718 		if (index > 0)
1719 			cn30xxgmx_dump_x_index(name, sizeof(name), portno);
1720 
1721 		printf("\t%-24s: %016llx\n", name, tmp);
1722 	}
1723 }
1724 
1725 /* not in libkern */
1726 static char *strstr(const char *, const char *);
1727 static char *
1728 strstr(const char *s, const char *find)
1729 {
1730         char c, sc;
1731         size_t len;
1732 
1733         if ((c = *find++) != 0) {
1734                 len = strlen(find);
1735                 do {
1736                         do {
1737                                 if ((sc = *s++) == 0)
1738                                         return (NULL);
1739                         } while (sc != c);
1740                 } while (strncmp(s, find, len) != 0);
1741                 s--;
1742         }
1743         return (char *)s;
1744 }
1745 
1746 void
1747 cn30xxgmx_dump_x_index(char *buf, size_t len, int index)
1748 {
1749 	static const char *patterns[] = { "_TX0_", "_RX0_", "_PRT0_" };
1750 	int i;
1751 
1752 	for (i = 0; i < (int)nitems(patterns); i++) {
1753 		char *p;
1754 
1755 		p = strstr(buf, patterns[i]);
1756 		if (p == NULL)
1757 			continue;
1758 		p = strchr(p, '0');
1759 		KASSERT(p != NULL);
1760 		*p = '0' + index;
1761 		return;
1762 	}
1763 }
1764 
1765 void
1766 cn30xxgmx_debug_reset(void)
1767 {
1768 	int i;
1769 
1770 	for (i = 0; i < 3; i++)
1771 		cn30xxgmx_link_enable(__cn30xxgmx_port_softc[i], 0);
1772 	for (i = 0; i < 3; i++)
1773 		cn30xxgmx_link_enable(__cn30xxgmx_port_softc[i], 1);
1774 }
1775 #endif
1776