xref: /openbsd/sys/arch/octeon/dev/cn30xxgmx.c (revision 293800bd)
1 /*	$OpenBSD: cn30xxgmx.c,v 1.55 2024/07/08 08:07:45 landry 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 AUTHORS 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 AUTHORS 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/device.h>
32 #include <sys/malloc.h>
33 #include <sys/syslog.h>
34 
35 #include <dev/ofw/openfirm.h>
36 
37 #include <machine/bus.h>
38 #include <machine/octeon_model.h>
39 #include <machine/octeonvar.h>
40 
41 #include <octeon/dev/iobusvar.h>
42 #include <octeon/dev/cn30xxasxvar.h>
43 #include <octeon/dev/cn30xxciureg.h>
44 #include <octeon/dev/cn30xxgmxreg.h>
45 #include <octeon/dev/cn30xxgmxvar.h>
46 #include <octeon/dev/cn30xxipdvar.h>
47 #include <octeon/dev/cn30xxpipvar.h>
48 #include <octeon/dev/cn30xxsmivar.h>
49 
50 #define GMX_NCAM	8
51 
52 #define	_GMX_RD8(sc, off) \
53 	bus_space_read_8((sc)->sc_port_gmx->sc_regt, (sc)->sc_port_gmx->sc_regh, (off))
54 #define	_GMX_WR8(sc, off, v) \
55 	bus_space_write_8((sc)->sc_port_gmx->sc_regt, (sc)->sc_port_gmx->sc_regh, (off), (v))
56 #define	_GMX_PORT_RD8(sc, off) \
57 	bus_space_read_8((sc)->sc_port_gmx->sc_regt, (sc)->sc_port_regh, (off))
58 #define	_GMX_PORT_WR8(sc, off, v) \
59 	bus_space_write_8((sc)->sc_port_gmx->sc_regt, (sc)->sc_port_regh, (off), (v))
60 
61 #define AGL_GMX_RD8(sc, reg) \
62 	bus_space_read_8((sc)->sc_port_gmx->sc_regt, \
63 	    (sc)->sc_port_gmx->sc_regh, (reg))
64 #define AGL_GMX_WR8(sc, reg, val) \
65 	bus_space_write_8((sc)->sc_port_gmx->sc_regt, \
66 	    (sc)->sc_port_gmx->sc_regh, (reg), (val))
67 #define AGL_GMX_PORT_RD8(sc, reg) \
68 	bus_space_read_8((sc)->sc_port_gmx->sc_regt, \
69 	    (sc)->sc_port_regh, (reg))
70 #define AGL_GMX_PORT_WR8(sc, reg, val) \
71 	bus_space_write_8((sc)->sc_port_gmx->sc_regt, \
72 	    (sc)->sc_port_regh, (reg), (val))
73 
74 #define PCS_READ_8(sc, reg) \
75 	bus_space_read_8((sc)->sc_port_gmx->sc_regt, (sc)->sc_port_pcs_regh, \
76 	    (reg))
77 #define PCS_WRITE_8(sc, reg, val) \
78 	bus_space_write_8((sc)->sc_port_gmx->sc_regt, (sc)->sc_port_pcs_regh, \
79 	    (reg), (val))
80 
81 struct cn30xxgmx_port_ops {
82 	int	(*port_ops_enable)(struct cn30xxgmx_port_softc *, int);
83 	int	(*port_ops_speed)(struct cn30xxgmx_port_softc *);
84 	int	(*port_ops_timing)(struct cn30xxgmx_port_softc *);
85 };
86 
87 int	cn30xxgmx_match(struct device *, void *, void *);
88 void	cn30xxgmx_attach(struct device *, struct device *, void *);
89 int	cn30xxgmx_print(void *, const char *);
90 void	cn30xxgmx_init(struct cn30xxgmx_softc *);
91 int	cn30xxgmx_rx_frm_ctl_xable(struct cn30xxgmx_port_softc *,
92 	    uint64_t, int);
93 void	cn30xxgmx_agl_init(struct cn30xxgmx_port_softc *);
94 int	cn30xxgmx_agl_enable(struct cn30xxgmx_port_softc *, int);
95 int	cn30xxgmx_agl_speed(struct cn30xxgmx_port_softc *);
96 int	cn30xxgmx_agl_timing(struct cn30xxgmx_port_softc *);
97 int	cn30xxgmx_rgmii_enable(struct cn30xxgmx_port_softc *, int);
98 int	cn30xxgmx_rgmii_speed(struct cn30xxgmx_port_softc *);
99 int	cn30xxgmx_rgmii_speed_newlink(struct cn30xxgmx_port_softc *,
100 	    uint64_t *);
101 int	cn30xxgmx_rgmii_speed_speed(struct cn30xxgmx_port_softc *);
102 int	cn30xxgmx_rgmii_timing(struct cn30xxgmx_port_softc *);
103 int	cn30xxgmx_sgmii_enable(struct cn30xxgmx_port_softc *, int);
104 int	cn30xxgmx_sgmii_speed(struct cn30xxgmx_port_softc *);
105 int	cn30xxgmx_sgmii_timing(struct cn30xxgmx_port_softc *);
106 int	cn30xxgmx_tx_ovr_bp_enable(struct cn30xxgmx_port_softc *, int);
107 int	cn30xxgmx_rx_pause_enable(struct cn30xxgmx_port_softc *, int);
108 
109 #ifdef OCTEON_ETH_DEBUG
110 int	cn30xxgmx_rgmii_speed_newlink_log(struct cn30xxgmx_port_softc *,
111 	    uint64_t);
112 #endif
113 
114 struct cn30xxgmx_port_ops cn30xxgmx_port_ops_agl = {
115 	.port_ops_enable = cn30xxgmx_agl_enable,
116 	.port_ops_speed = cn30xxgmx_agl_speed,
117 	.port_ops_timing = cn30xxgmx_agl_timing,
118 };
119 
120 struct cn30xxgmx_port_ops cn30xxgmx_port_ops_mii = {
121 	/* XXX not implemented */
122 };
123 
124 struct cn30xxgmx_port_ops cn30xxgmx_port_ops_gmii = {
125 	.port_ops_enable = cn30xxgmx_rgmii_enable,
126 	.port_ops_speed = cn30xxgmx_rgmii_speed,
127 	.port_ops_timing = cn30xxgmx_rgmii_timing,
128 };
129 
130 struct cn30xxgmx_port_ops cn30xxgmx_port_ops_rgmii = {
131 	.port_ops_enable = cn30xxgmx_rgmii_enable,
132 	.port_ops_speed = cn30xxgmx_rgmii_speed,
133 	.port_ops_timing = cn30xxgmx_rgmii_timing,
134 };
135 
136 struct cn30xxgmx_port_ops cn30xxgmx_port_ops_sgmii = {
137 	.port_ops_enable = cn30xxgmx_sgmii_enable,
138 	.port_ops_speed = cn30xxgmx_sgmii_speed,
139 	.port_ops_timing = cn30xxgmx_sgmii_timing,
140 };
141 
142 struct cn30xxgmx_port_ops cn30xxgmx_port_ops_spi42 = {
143 	/* XXX not implemented */
144 };
145 
146 struct cn30xxgmx_port_ops *cn30xxgmx_port_ops[] = {
147 	[GMX_MII_PORT] = &cn30xxgmx_port_ops_mii,
148 	[GMX_GMII_PORT] = &cn30xxgmx_port_ops_gmii,
149 	[GMX_RGMII_PORT] = &cn30xxgmx_port_ops_rgmii,
150 	[GMX_SGMII_PORT] = &cn30xxgmx_port_ops_sgmii,
151 	[GMX_SPI42_PORT] = &cn30xxgmx_port_ops_spi42,
152 	[GMX_AGL_PORT] = &cn30xxgmx_port_ops_agl,
153 };
154 
155 const struct cfattach octgmx_ca = {sizeof(struct cn30xxgmx_softc),
156     cn30xxgmx_match, cn30xxgmx_attach, NULL, NULL};
157 
158 struct cfdriver octgmx_cd = {NULL, "octgmx", DV_DULL};
159 
160 int
cn30xxgmx_match(struct device * parent,void * match,void * aux)161 cn30xxgmx_match(struct device *parent, void *match, void *aux)
162 {
163 	struct cfdata *cf = (struct cfdata *)match;
164 	struct iobus_attach_args *aa = aux;
165 
166 	if (strcmp(cf->cf_driver->cd_name, aa->aa_name) != 0)
167 		return 0;
168 	return 1;
169 }
170 
171 int
cn30xxgmx_get_phy_phandle(int interface,int port)172 cn30xxgmx_get_phy_phandle(int interface, int port)
173 {
174 	char name[64];
175 	int node;
176 	int phandle = 0;
177 
178 	snprintf(name, sizeof(name),
179 	    "/soc/pip@11800a0000000/interface@%x/ethernet@%x",
180 	    interface, port);
181 	node = OF_finddevice(name);
182 	if (node != - 1)
183 		phandle = OF_getpropint(node, "phy-handle", 0);
184 	return phandle;
185 }
186 
187 void
cn30xxgmx_attach(struct device * parent,struct device * self,void * aux)188 cn30xxgmx_attach(struct device *parent, struct device *self, void *aux)
189 {
190 	struct cn30xxgmx_attach_args gmx_aa;
191 	struct iobus_attach_args *aa = aux;
192 	struct cn30xxgmx_port_softc *port_sc;
193 	struct cn30xxgmx_softc *sc = (void *)self;
194 	struct cn30xxsmi_softc *smi;
195 	int i;
196 	int phy_addr;
197 	int port;
198 	int status;
199 
200 	sc->sc_regt = aa->aa_bust; /* XXX why there are iot? */
201 	sc->sc_unitno = aa->aa_unitno;
202 
203 	status = bus_space_map(sc->sc_regt, aa->aa_addr, GMX_BLOCK_SIZE,
204 	    0, &sc->sc_regh);
205 	if (status != 0) {
206 		printf(": can't map registers\n");
207 		return;
208 	}
209 
210 	cn30xxgmx_init(sc);
211 
212 	if (sc->sc_nports == 0) {
213 		printf(": no active ports found\n");
214 		goto error;
215 	}
216 
217 	sc->sc_ports = mallocarray(sc->sc_nports, sizeof(*sc->sc_ports),
218 	    M_DEVBUF, M_NOWAIT | M_ZERO);
219 	if (sc->sc_ports == NULL) {
220 		printf(": out of memory\n");
221 		goto error;
222 	}
223 
224 	printf("\n");
225 
226 	for (i = 0; i < sc->sc_nports; i++) {
227 		if (sc->sc_port_types[i] == GMX_AGL_PORT)
228 			port = 24;
229 		else
230 			port = GMX_PORT_NUM(sc->sc_unitno, i);
231 		if (cn30xxsmi_get_phy(cn30xxgmx_get_phy_phandle(sc->sc_unitno,
232 		    i), port, &smi, &phy_addr))
233 			continue;
234 
235 		port_sc = &sc->sc_ports[i];
236 		port_sc->sc_port_gmx = sc;
237 		port_sc->sc_port_no = port;
238 		port_sc->sc_port_type = sc->sc_port_types[i];
239 		port_sc->sc_port_ops = cn30xxgmx_port_ops[port_sc->sc_port_type];
240 		status = bus_space_map(sc->sc_regt,
241 		    aa->aa_addr + GMX0_BASE_PORT_SIZE * i,
242 		    GMX0_BASE_PORT_SIZE, 0, &port_sc->sc_port_regh);
243 		if (status != 0) {
244 			printf("%s port %d: can't map registers\n",
245 			    sc->sc_dev.dv_xname, port);
246 			continue;
247 		}
248 
249 		switch (port_sc->sc_port_type) {
250 		case GMX_AGL_PORT:
251 			cn30xxgmx_agl_init(port_sc);
252 			break;
253 
254 		case GMX_MII_PORT:
255 		case GMX_GMII_PORT:
256 		case GMX_RGMII_PORT: {
257 			struct cn30xxasx_attach_args asx_aa;
258 
259 			asx_aa.aa_port = i;
260 			asx_aa.aa_regt = aa->aa_bust;
261 			cn30xxasx_init(&asx_aa, &port_sc->sc_port_asx);
262 			break;
263 		}
264 		case GMX_SGMII_PORT:
265 			if (bus_space_map(sc->sc_regt,
266 			    PCS_BASE(sc->sc_unitno, i), PCS_SIZE, 0,
267 			    &port_sc->sc_port_pcs_regh)) {
268 				printf("%s port %d: can't map PCS registers\n",
269 				    sc->sc_dev.dv_xname, port);
270 				continue;
271 			}
272 			break;
273 		default:
274 			/* nothing */
275 			break;
276 		}
277 
278 		(void)memset(&gmx_aa, 0, sizeof(gmx_aa));
279 		gmx_aa.ga_regt = aa->aa_bust;
280 		gmx_aa.ga_dmat = aa->aa_dmat;
281 		gmx_aa.ga_addr = aa->aa_addr;
282 		gmx_aa.ga_name = "cnmac";
283 		gmx_aa.ga_portno = port_sc->sc_port_no;
284 		gmx_aa.ga_port_type = sc->sc_port_types[i];
285 		gmx_aa.ga_gmx = sc;
286 		gmx_aa.ga_gmx_port = port_sc;
287 		gmx_aa.ga_phy_addr = phy_addr;
288 		gmx_aa.ga_smi = smi;
289 
290 		config_found(self, &gmx_aa, cn30xxgmx_print);
291 	}
292 	return;
293 
294 error:
295 	bus_space_unmap(sc->sc_regt, sc->sc_regh, GMX_BLOCK_SIZE);
296 }
297 
298 int
cn30xxgmx_print(void * aux,const char * pnp)299 cn30xxgmx_print(void *aux, const char *pnp)
300 {
301 	struct cn30xxgmx_attach_args *ga = aux;
302 	static const char *types[] = {
303 		[GMX_AGL_PORT] = "AGL",
304 		[GMX_MII_PORT] = "MII",
305 		[GMX_GMII_PORT] = "GMII",
306 		[GMX_RGMII_PORT] = "RGMII",
307 		[GMX_SGMII_PORT] = "SGMII"
308 	};
309 
310 #if DEBUG
311 	if (pnp)
312 		printf("%s at %s", ga->ga_name, pnp);
313 #endif
314 
315 	printf(": port %d %s", ga->ga_portno, types[ga->ga_port_type]);
316 
317 	return UNCONF;
318 }
319 
320 void
cn30xxgmx_init(struct cn30xxgmx_softc * sc)321 cn30xxgmx_init(struct cn30xxgmx_softc *sc)
322 {
323 	uint64_t inf_mode;
324 	int i, id;
325 
326 	id = octeon_get_chipid();
327 
328 	switch (octeon_model_family(id)) {
329 	case OCTEON_MODEL_FAMILY_CN31XX:
330 		inf_mode = bus_space_read_8(sc->sc_regt, sc->sc_regh,
331 		    GMX0_INF_MODE);
332 		if ((inf_mode & INF_MODE_EN) == 0)
333 			break;
334 		/*
335 		 * CN31XX-HM-1.01
336 		 * 14.1 Packet Interface Introduction
337 		 * Table 14-1 Packet Interface Configuration
338 		 * 14.8 GMX Registers, Interface Mode Register, GMX0_INF_MODE
339 		 */
340 		if ((inf_mode & INF_MODE_TYPE) == 0) {
341 			/* all three ports configured as RGMII */
342 			sc->sc_nports = 3;
343 			sc->sc_port_types[0] = GMX_RGMII_PORT;
344 			sc->sc_port_types[1] = GMX_RGMII_PORT;
345 			sc->sc_port_types[2] = GMX_RGMII_PORT;
346 		} else {
347 			/* port 0: RGMII, port 1: GMII, port 2: disabled */
348 			/* XXX CN31XX-HM-1.01 says "Port 3: disabled"; typo? */
349 			sc->sc_nports = 2;
350 			sc->sc_port_types[0] = GMX_RGMII_PORT;
351 			sc->sc_port_types[1] = GMX_GMII_PORT;
352 		}
353 		break;
354 	case OCTEON_MODEL_FAMILY_CN30XX:
355 	case OCTEON_MODEL_FAMILY_CN50XX:
356 		inf_mode = bus_space_read_8(sc->sc_regt, sc->sc_regh,
357 		    GMX0_INF_MODE);
358 		if ((inf_mode & INF_MODE_EN) == 0)
359 			break;
360 		/*
361 		 * CN30XX-HM-1.0
362 		 * 13.1 Packet Interface Introduction
363 		 * Table 13-1 Packet Interface Configuration
364 		 * 13.8 GMX Registers, Interface Mode Register, GMX0_INF_MODE
365 		 */
366 		if ((inf_mode & INF_MODE_P0MII) == 0)
367 			sc->sc_port_types[0] = GMX_RGMII_PORT;
368 		else
369 			sc->sc_port_types[0] = GMX_MII_PORT;
370 		if ((inf_mode & INF_MODE_TYPE) == 0) {
371 			/* port 1 and 2 are configured as RGMII ports */
372 			sc->sc_nports = 3;
373 			sc->sc_port_types[1] = GMX_RGMII_PORT;
374 			sc->sc_port_types[2] = GMX_RGMII_PORT;
375 		} else {
376 			/* port 1: GMII/MII, port 2: disabled */
377 			/* GMII or MII port is selected by GMX_PRT1_CFG[SPEED] */
378 			sc->sc_nports = 2;
379 			sc->sc_port_types[1] = GMX_GMII_PORT;
380 		}
381 		/* port 2 is in CN3010/CN5010 only */
382 		if ((octeon_model(id) != OCTEON_MODEL_CN3010) &&
383 		    (octeon_model(id) != OCTEON_MODEL_CN5010))
384 			if (sc->sc_nports == 3)
385 				sc->sc_nports = 2;
386 		break;
387 	case OCTEON_MODEL_FAMILY_CN61XX: {
388 		uint64_t qlm_cfg;
389 
390 		inf_mode = bus_space_read_8(sc->sc_regt, sc->sc_regh,
391 		    GMX0_INF_MODE);
392 		if ((inf_mode & INF_MODE_EN) == 0)
393 			break;
394 
395 		if (sc->sc_unitno == 0)
396 			qlm_cfg = octeon_xkphys_read_8(MIO_QLM_CFG(2));
397 		else
398 			qlm_cfg = octeon_xkphys_read_8(MIO_QLM_CFG(0));
399 		if ((qlm_cfg & MIO_QLM_CFG_CFG) == 2) {
400 			sc->sc_nports = 4;
401 			for (i = 0; i < sc->sc_nports; i++)
402 				sc->sc_port_types[i] = GMX_SGMII_PORT;
403 		} else if ((qlm_cfg & MIO_QLM_CFG_CFG) == 3) {
404 			printf(": XAUI interface is not supported");
405 		} else {
406 			/* The interface is disabled. */
407 		}
408 		break;
409 	}
410 	case OCTEON_MODEL_FAMILY_CN71XX:
411 		if (sc->sc_unitno == 4) {
412 			uint64_t val;
413 
414 			val = bus_space_read_8(sc->sc_regt, sc->sc_regh,
415 			    AGL_PRT_CTL(0));
416 			if ((val & AGL_PRT_CTL_MODE_M) ==
417 			    AGL_PRT_CTL_MODE_RGMII) {
418 				sc->sc_nports = 1;
419 				sc->sc_port_types[0] = GMX_AGL_PORT;
420 			}
421 			break;
422 		}
423 
424 		inf_mode = bus_space_read_8(sc->sc_regt, sc->sc_regh,
425 		    GMX0_INF_MODE);
426 		if ((inf_mode & INF_MODE_EN) == 0)
427 			break;
428 
429 		switch (inf_mode & INF_MODE_MODE) {
430 		case INF_MODE_MODE_SGMII:
431 			sc->sc_nports = 4;
432 			for (i = 0; i < sc->sc_nports; i++)
433 				sc->sc_port_types[i] = GMX_SGMII_PORT;
434 			break;
435 #ifdef notyet
436 		case INF_MODE_MODE_XAUI:
437 #endif
438 		default:
439 			break;
440 		}
441 		break;
442 	case OCTEON_MODEL_FAMILY_CN38XX:
443 	case OCTEON_MODEL_FAMILY_CN56XX:
444 	case OCTEON_MODEL_FAMILY_CN58XX:
445 	default:
446 		printf(": unsupported octeon model: 0x%x", id);
447 		break;
448 	}
449 }
450 
451 /* XXX RGMII specific */
452 int
cn30xxgmx_link_enable(struct cn30xxgmx_port_softc * sc,int enable)453 cn30xxgmx_link_enable(struct cn30xxgmx_port_softc *sc, int enable)
454 {
455 	uint64_t prt_cfg;
456 
457 	cn30xxgmx_tx_int_enable(sc, enable);
458 	cn30xxgmx_rx_int_enable(sc, enable);
459 
460 	prt_cfg = _GMX_PORT_RD8(sc, GMX0_PRT0_CFG);
461 	if (enable) {
462 		if (cn30xxgmx_link_status(sc)) {
463 			SET(prt_cfg, PRTN_CFG_EN);
464 		}
465 	} else {
466 		CLR(prt_cfg, PRTN_CFG_EN);
467 	}
468 	_GMX_PORT_WR8(sc, GMX0_PRT0_CFG, prt_cfg);
469 	/*
470 	 * According to CN30XX-HM-1.0, 13.4.2 Link Status Changes:
471 	 * > software should read back to flush the write operation.
472 	 */
473 	(void)_GMX_PORT_RD8(sc, GMX0_PRT0_CFG);
474 
475 	return 0;
476 }
477 
478 void
cn30xxgmx_stats_init(struct cn30xxgmx_port_softc * sc)479 cn30xxgmx_stats_init(struct cn30xxgmx_port_softc *sc)
480 {
481 	_GMX_PORT_WR8(sc, GMX0_RX0_STATS_CTL, 1);
482 	_GMX_PORT_WR8(sc, GMX0_TX0_STATS_CTL, 1);
483 
484 	_GMX_PORT_WR8(sc, GMX0_RX0_STATS_PKTS, 0);
485 	_GMX_PORT_WR8(sc, GMX0_RX0_STATS_OCTS, 0);
486 	_GMX_PORT_WR8(sc, GMX0_RX0_STATS_PKTS_CTL, 0);
487 	_GMX_PORT_WR8(sc, GMX0_RX0_STATS_PKTS_DMAC, 0);
488 	_GMX_PORT_WR8(sc, GMX0_RX0_STATS_PKTS_DRP, 0);
489 	_GMX_PORT_WR8(sc, GMX0_RX0_STATS_PKTS_BAD, 0);
490 	_GMX_PORT_WR8(sc, GMX0_TX0_STAT0, 0);
491 	_GMX_PORT_WR8(sc, GMX0_TX0_STAT1, 0);
492 	_GMX_PORT_WR8(sc, GMX0_TX0_STAT2, 0);
493 	_GMX_PORT_WR8(sc, GMX0_TX0_STAT3, 0);
494 	_GMX_PORT_WR8(sc, GMX0_TX0_STAT4, 0);
495 	_GMX_PORT_WR8(sc, GMX0_TX0_STAT5, 0);
496 	_GMX_PORT_WR8(sc, GMX0_TX0_STAT6, 0);
497 	_GMX_PORT_WR8(sc, GMX0_TX0_STAT7, 0);
498 	_GMX_PORT_WR8(sc, GMX0_TX0_STAT8, 0);
499 	_GMX_PORT_WR8(sc, GMX0_TX0_STAT9, 0);
500 }
501 
502 int
cn30xxgmx_tx_ovr_bp_enable(struct cn30xxgmx_port_softc * sc,int enable)503 cn30xxgmx_tx_ovr_bp_enable(struct cn30xxgmx_port_softc *sc, int enable)
504 {
505 	uint64_t ovr_bp;
506 	int index = GMX_PORT_INDEX(sc->sc_port_no);
507 
508 	ovr_bp = _GMX_RD8(sc, GMX0_TX_OVR_BP);
509 	if (enable) {
510 		CLR(ovr_bp, (1 << index) << TX_OVR_BP_EN_SHIFT);
511 		SET(ovr_bp, (1 << index) << TX_OVR_BP_BP_SHIFT);
512 		/* XXX really??? */
513 		SET(ovr_bp, (1 << index) << TX_OVR_BP_IGN_FULL_SHIFT);
514 	} else {
515 		SET(ovr_bp, (1 << index) << TX_OVR_BP_EN_SHIFT);
516 		CLR(ovr_bp, (1 << index) << TX_OVR_BP_BP_SHIFT);
517 		/* XXX really??? */
518 		SET(ovr_bp, (1 << index) << TX_OVR_BP_IGN_FULL_SHIFT);
519 	}
520 	_GMX_WR8(sc, GMX0_TX_OVR_BP, ovr_bp);
521 	return 0;
522 }
523 
524 int
cn30xxgmx_rx_pause_enable(struct cn30xxgmx_port_softc * sc,int enable)525 cn30xxgmx_rx_pause_enable(struct cn30xxgmx_port_softc *sc, int enable)
526 {
527 	if (enable) {
528 		cn30xxgmx_rx_frm_ctl_enable(sc, RXN_FRM_CTL_CTL_BCK);
529 	} else {
530 		cn30xxgmx_rx_frm_ctl_disable(sc, RXN_FRM_CTL_CTL_BCK);
531 	}
532 
533 	return 0;
534 }
535 
536 void
cn30xxgmx_tx_int_enable(struct cn30xxgmx_port_softc * sc,int enable)537 cn30xxgmx_tx_int_enable(struct cn30xxgmx_port_softc *sc, int enable)
538 {
539 	uint64_t tx_int_xxx = 0;
540 
541 	SET(tx_int_xxx,
542 	    TX_INT_REG_LATE_COL |
543 	    TX_INT_REG_XSDEF |
544 	    TX_INT_REG_XSCOL |
545 	    TX_INT_REG_UNDFLW |
546 	    TX_INT_REG_PKO_NXA);
547 	_GMX_WR8(sc, GMX0_TX_INT_REG, tx_int_xxx);
548 	_GMX_WR8(sc, GMX0_TX_INT_EN, enable ? tx_int_xxx : 0);
549 }
550 
551 void
cn30xxgmx_rx_int_enable(struct cn30xxgmx_port_softc * sc,int enable)552 cn30xxgmx_rx_int_enable(struct cn30xxgmx_port_softc *sc, int enable)
553 {
554 	uint64_t rx_int_xxx = 0;
555 
556 	SET(rx_int_xxx, 0 |
557 	    RXN_INT_REG_PHY_DUPX |
558 	    RXN_INT_REG_PHY_SPD |
559 	    RXN_INT_REG_PHY_LINK |
560 	    RXN_INT_REG_IFGERR |
561 	    RXN_INT_REG_COLDET |
562 	    RXN_INT_REG_FALERR |
563 	    RXN_INT_REG_RSVERR |
564 	    RXN_INT_REG_PCTERR |
565 	    RXN_INT_REG_OVRERR |
566 	    RXN_INT_REG_NIBERR |
567 	    RXN_INT_REG_SKPERR |
568 	    RXN_INT_REG_RCVERR |
569 	    RXN_INT_REG_LENERR |
570 	    RXN_INT_REG_ALNERR |
571 	    RXN_INT_REG_FCSERR |
572 	    RXN_INT_REG_JABBER |
573 	    RXN_INT_REG_MAXERR |
574 	    RXN_INT_REG_CAREXT |
575 	    RXN_INT_REG_MINERR);
576 	_GMX_PORT_WR8(sc, GMX0_RX0_INT_REG, rx_int_xxx);
577 	_GMX_PORT_WR8(sc, GMX0_RX0_INT_EN, enable ? rx_int_xxx : 0);
578 }
579 
580 int
cn30xxgmx_rx_frm_ctl_enable(struct cn30xxgmx_port_softc * sc,uint64_t rx_frm_ctl)581 cn30xxgmx_rx_frm_ctl_enable(struct cn30xxgmx_port_softc *sc,
582     uint64_t rx_frm_ctl)
583 {
584 	struct ifnet *ifp = &sc->sc_port_ac->ac_if;
585 	unsigned int maxlen;
586 
587 	maxlen = roundup(ifp->if_hardmtu + ETHER_HDR_LEN + ETHER_CRC_LEN +
588 	    ETHER_VLAN_ENCAP_LEN, 8);
589 	_GMX_PORT_WR8(sc, GMX0_RX0_JABBER, maxlen);
590 
591 	return cn30xxgmx_rx_frm_ctl_xable(sc, rx_frm_ctl, 1);
592 }
593 
594 int
cn30xxgmx_rx_frm_ctl_disable(struct cn30xxgmx_port_softc * sc,uint64_t rx_frm_ctl)595 cn30xxgmx_rx_frm_ctl_disable(struct cn30xxgmx_port_softc *sc,
596     uint64_t rx_frm_ctl)
597 {
598 	return cn30xxgmx_rx_frm_ctl_xable(sc, rx_frm_ctl, 0);
599 }
600 
601 int
cn30xxgmx_rx_frm_ctl_xable(struct cn30xxgmx_port_softc * sc,uint64_t rx_frm_ctl,int enable)602 cn30xxgmx_rx_frm_ctl_xable(struct cn30xxgmx_port_softc *sc,
603     uint64_t rx_frm_ctl, int enable)
604 {
605 	uint64_t tmp;
606 
607 	tmp = _GMX_PORT_RD8(sc, GMX0_RX0_FRM_CTL);
608 	if (enable)
609 		SET(tmp, rx_frm_ctl);
610 	else
611 		CLR(tmp, rx_frm_ctl);
612 	_GMX_PORT_WR8(sc, GMX0_RX0_FRM_CTL, tmp);
613 
614 	return 0;
615 }
616 
617 int
cn30xxgmx_tx_thresh(struct cn30xxgmx_port_softc * sc,int cnt)618 cn30xxgmx_tx_thresh(struct cn30xxgmx_port_softc *sc, int cnt)
619 {
620 	_GMX_PORT_WR8(sc, GMX0_TX0_THRESH, cnt);
621 	return 0;
622 }
623 
624 int
cn30xxgmx_set_filter(struct cn30xxgmx_port_softc * sc)625 cn30xxgmx_set_filter(struct cn30xxgmx_port_softc *sc)
626 {
627 	struct ifnet *ifp = &sc->sc_port_ac->ac_if;
628 	struct arpcom *ac = sc->sc_port_ac;
629 	struct ether_multi *enm;
630 	struct ether_multistep step;
631 	uint64_t cam[ETHER_ADDR_LEN];
632 	uint64_t cam_en = 0;
633 	uint64_t ctl = 0;
634 	uint64_t mac;
635 	int i, cidx;
636 
637 	/*
638 	 * Always accept broadcast frames.
639 	 */
640 	SET(ctl, RXN_ADR_CTL_BCST);
641 
642 	if (ISSET(ifp->if_flags, IFF_PROMISC)) {
643 		SET(ifp->if_flags, IFF_ALLMULTI);
644 		SET(ctl, RXN_ADR_CTL_MCST_ACCEPT);
645 	} else if (ac->ac_multirangecnt > 0 || ac->ac_multicnt >= GMX_NCAM) {
646 		SET(ifp->if_flags, IFF_ALLMULTI);
647 		SET(ctl, RXN_ADR_CTL_CAM_MODE);
648 		SET(ctl, RXN_ADR_CTL_MCST_ACCEPT);
649 	} else {
650 		CLR(ifp->if_flags, IFF_ALLMULTI);
651 		SET(ctl, RXN_ADR_CTL_CAM_MODE);
652 		SET(ctl, RXN_ADR_CTL_MCST_AFCAM);
653 	}
654 
655 	mac = 0;
656 	for (i = 0; i < ETHER_ADDR_LEN; i++)
657 		mac |= (uint64_t)ac->ac_enaddr[i] <<
658 		    ((ETHER_ADDR_LEN - 1 - i) * 8);
659 
660 	/*
661 	 * The first CAM entry is used for the local unicast MAC.
662 	 * The remaining entries are used for multicast MACs.
663 	 */
664 	memset(cam, 0, sizeof(cam));
665 	cidx = 0;
666 	if (!ISSET(ifp->if_flags, IFF_PROMISC)) {
667 		for (i = 0; i < ETHER_ADDR_LEN; i++)
668 			cam[i] |= (uint64_t)ac->ac_enaddr[i] << (cidx * 8);
669 		cam_en |= 1U << cidx;
670 		cidx++;
671 	}
672 	if (!ISSET(ifp->if_flags, IFF_ALLMULTI)) {
673 		ETHER_FIRST_MULTI(step, ac, enm);
674 		while (enm != NULL && cidx < GMX_NCAM) {
675 			for (i = 0; i < ETHER_ADDR_LEN; i++)
676 				cam[i] |= (uint64_t)enm->enm_addrlo[i] <<
677 				    (cidx * 8);
678 			cam_en |= 1U << cidx;
679 			cidx++;
680 			ETHER_NEXT_MULTI(step, enm);
681 		}
682 	}
683 
684 	cn30xxgmx_link_enable(sc, 0);
685 	_GMX_PORT_WR8(sc, GMX0_SMAC0, mac);
686 	_GMX_PORT_WR8(sc, GMX0_RX0_ADR_CTL, ctl);
687 	for (i = 0; i < ETHER_ADDR_LEN; i++)
688 		_GMX_PORT_WR8(sc, GMX0_RX0_ADR_CAM(i), cam[i]);
689 	_GMX_PORT_WR8(sc, GMX0_RX0_ADR_CAM_EN, cam_en);
690 	(void)_GMX_PORT_RD8(sc, GMX0_RX0_ADR_CAM_EN);
691 	cn30xxgmx_link_enable(sc, 1);
692 
693 	return 0;
694 }
695 
696 int
cn30xxgmx_port_enable(struct cn30xxgmx_port_softc * sc,int enable)697 cn30xxgmx_port_enable(struct cn30xxgmx_port_softc *sc, int enable)
698 {
699 	(*sc->sc_port_ops->port_ops_enable)(sc, enable);
700 	return 0;
701 }
702 
703 int
cn30xxgmx_reset_speed(struct cn30xxgmx_port_softc * sc)704 cn30xxgmx_reset_speed(struct cn30xxgmx_port_softc *sc)
705 {
706 	struct ifnet *ifp = &sc->sc_port_ac->ac_if;
707 	if (ISSET(sc->sc_port_mii->mii_flags, MIIF_DOINGAUTO)) {
708 		log(LOG_WARNING,
709 		    "%s: autonegotiation has not been completed yet\n",
710 		    ifp->if_xname);
711 		return 1;
712 	}
713 	(*sc->sc_port_ops->port_ops_speed)(sc);
714 	return 0;
715 }
716 
717 int
cn30xxgmx_reset_timing(struct cn30xxgmx_port_softc * sc)718 cn30xxgmx_reset_timing(struct cn30xxgmx_port_softc *sc)
719 {
720 	(*sc->sc_port_ops->port_ops_timing)(sc);
721 	return 0;
722 }
723 
724 int
cn30xxgmx_reset_flowctl(struct cn30xxgmx_port_softc * sc)725 cn30xxgmx_reset_flowctl(struct cn30xxgmx_port_softc *sc)
726 {
727 	struct ifmedia_entry *ife = sc->sc_port_mii->mii_media.ifm_cur;
728 
729 	/*
730 	 * Get flow control negotiation result.
731 	 */
732 #ifdef GMX_802_3X_DISABLE_AUTONEG
733 	/* Tentative support for SEIL-compat.. */
734 	if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) {
735 		sc->sc_port_flowflags &= ~IFM_ETH_FMASK;
736 	}
737 #else
738 	/* Default configuration of NetBSD */
739 	if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO &&
740 	    (sc->sc_port_mii->mii_media_active & IFM_ETH_FMASK) !=
741 			sc->sc_port_flowflags) {
742 		sc->sc_port_flowflags =
743 			sc->sc_port_mii->mii_media_active & IFM_ETH_FMASK;
744 		sc->sc_port_mii->mii_media_active &= ~IFM_ETH_FMASK;
745 	}
746 #endif /* GMX_802_3X_DISABLE_AUTONEG */
747 
748 	/*
749 	 * 802.3x Flow Control Capabilities
750 	 */
751 	if (sc->sc_port_flowflags & IFM_ETH_TXPAUSE) {
752 		cn30xxgmx_tx_ovr_bp_enable(sc, 1);
753 	} else {
754 		cn30xxgmx_tx_ovr_bp_enable(sc, 0);
755 	}
756 	if (sc->sc_port_flowflags & IFM_ETH_RXPAUSE) {
757 		cn30xxgmx_rx_pause_enable(sc, 1);
758 	} else {
759 		cn30xxgmx_rx_pause_enable(sc, 0);
760 	}
761 
762 	return 0;
763 }
764 
765 void
cn30xxgmx_agl_init(struct cn30xxgmx_port_softc * sc)766 cn30xxgmx_agl_init(struct cn30xxgmx_port_softc *sc)
767 {
768 	uint64_t val;
769 	int port = 0;
770 
771 	/* Disable link for initialization. */
772 	val = AGL_GMX_PORT_RD8(sc, AGL_GMX_PRT_CFG);
773 	CLR(val, AGL_GMX_PRT_CFG_EN);
774 	AGL_GMX_PORT_WR8(sc, AGL_GMX_PRT_CFG, val);
775 	(void)AGL_GMX_PORT_RD8(sc, AGL_GMX_PRT_CFG);
776 
777 	val = AGL_GMX_RD8(sc, AGL_PRT_CTL(port));
778 	CLR(val, AGL_PRT_CTL_CLKRST);
779 	CLR(val, AGL_PRT_CTL_DLLRST);
780 	CLR(val, AGL_PRT_CTL_CLKTX_BYP);
781 	CLR(val, AGL_PRT_CTL_CLKTX_SET_M);
782 	CLR(val, AGL_PRT_CTL_CLKRX_BYP);
783 	CLR(val, AGL_PRT_CTL_CLKRX_SET_M);
784 	CLR(val, AGL_PRT_CTL_REFCLK_SEL_M);
785 	AGL_GMX_WR8(sc, AGL_PRT_CTL(port), val);
786 	(void)AGL_GMX_RD8(sc, AGL_PRT_CTL(port));
787 
788 	/* Let the DLL settle. */
789 	delay(5);
790 
791 	val = AGL_GMX_RD8(sc, AGL_PRT_CTL(port));
792 	CLR(val, AGL_PRT_CTL_DRV_BYP);
793 	AGL_GMX_WR8(sc, AGL_PRT_CTL(port), val);
794 	(void)AGL_GMX_RD8(sc, AGL_PRT_CTL(port));
795 
796 	val = AGL_GMX_RD8(sc, AGL_PRT_CTL(port));
797 	SET(val, AGL_PRT_CTL_COMP);
798 	AGL_GMX_WR8(sc, AGL_PRT_CTL(port), val);
799 	(void)AGL_GMX_RD8(sc, AGL_PRT_CTL(port));
800 
801 	/* Let the compensation controller settle. */
802 	delay(20);
803 
804 	val = AGL_GMX_RX_FRM_CTL_PRE_ALIGN
805 	    | AGL_GMX_RX_FRM_CTL_PAD_LEN
806 	    | AGL_GMX_RX_FRM_CTL_VLAN_LEN
807 	    | AGL_GMX_RX_FRM_CTL_PRE_FREE
808 	    | AGL_GMX_RX_FRM_CTL_MCST
809 	    | AGL_GMX_RX_FRM_CTL_BCK
810 	    | AGL_GMX_RX_FRM_CTL_DRP
811 	    | AGL_GMX_RX_FRM_CTL_PRE_STRP
812 	    | AGL_GMX_RX_FRM_CTL_PRE_CHK;
813 	AGL_GMX_PORT_WR8(sc, AGL_GMX_RX_FRM_CTL, val);
814 	(void)AGL_GMX_PORT_RD8(sc, AGL_GMX_RX_FRM_CTL);
815 }
816 
817 void
cn30xxgmx_agl_up(struct cn30xxgmx_port_softc * sc)818 cn30xxgmx_agl_up(struct cn30xxgmx_port_softc *sc)
819 {
820 	uint64_t val;
821 
822 	val = AGL_GMX_PORT_RD8(sc, AGL_GMX_PRT_CFG);
823 	SET(val, AGL_GMX_PRT_CFG_RX_EN);
824 	SET(val, AGL_GMX_PRT_CFG_TX_EN);
825 	AGL_GMX_PORT_WR8(sc, AGL_GMX_PRT_CFG, val);
826 
827 	val = AGL_GMX_PORT_RD8(sc, AGL_GMX_PRT_CFG);
828 	SET(val, AGL_GMX_PRT_CFG_EN);
829 	AGL_GMX_PORT_WR8(sc, AGL_GMX_PRT_CFG, val);
830 	(void)AGL_GMX_PORT_RD8(sc, AGL_GMX_PRT_CFG);
831 }
832 
833 void
cn30xxgmx_agl_down(struct cn30xxgmx_port_softc * sc)834 cn30xxgmx_agl_down(struct cn30xxgmx_port_softc *sc)
835 {
836 	uint64_t val;
837 	int timeout;
838 
839 	val = AGL_GMX_PORT_RD8(sc, AGL_GMX_PRT_CFG);
840 	CLR(val, AGL_GMX_PRT_CFG_EN);
841 	AGL_GMX_PORT_WR8(sc, AGL_GMX_PRT_CFG, val);
842 
843 	val = AGL_GMX_PORT_RD8(sc, AGL_GMX_PRT_CFG);
844 	CLR(val, AGL_GMX_PRT_CFG_RX_EN);
845 	CLR(val, AGL_GMX_PRT_CFG_TX_EN);
846 	AGL_GMX_PORT_WR8(sc, AGL_GMX_PRT_CFG, val);
847 	(void)AGL_GMX_PORT_RD8(sc, AGL_GMX_PRT_CFG);
848 
849 	/* Wait until the port is idle. */
850 	for (timeout = 1000; timeout > 0; timeout--) {
851 		const uint64_t idlemask = AGL_GMX_PRT_CFG_RX_IDLE |
852 		    AGL_GMX_PRT_CFG_TX_IDLE;
853 		val = AGL_GMX_PORT_RD8(sc, AGL_GMX_PRT_CFG);
854 		if ((val & idlemask) == idlemask)
855 			break;
856 		delay(1000);
857 	}
858 }
859 
860 int
cn30xxgmx_agl_enable(struct cn30xxgmx_port_softc * sc,int enable)861 cn30xxgmx_agl_enable(struct cn30xxgmx_port_softc *sc, int enable)
862 {
863 	if (enable)
864 		cn30xxgmx_agl_up(sc);
865 	else
866 		cn30xxgmx_agl_down(sc);
867 	return 0;
868 }
869 
870 int
cn30xxgmx_agl_speed(struct cn30xxgmx_port_softc * sc)871 cn30xxgmx_agl_speed(struct cn30xxgmx_port_softc *sc)
872 {
873 	struct ifnet *ifp = &sc->sc_port_ac->ac_if;
874 	uint64_t clk_cnt, prt_cfg, val;
875 	unsigned int maxlen;
876 	int port = 0;
877 
878 	cn30xxgmx_agl_down(sc);
879 
880 	prt_cfg = AGL_GMX_PORT_RD8(sc, AGL_GMX_PRT_CFG);
881 
882 	if (ISSET(sc->sc_port_mii->mii_media_active, IFM_FDX))
883 		SET(prt_cfg, AGL_GMX_PRT_CFG_DUPLEX);
884 	else
885 		CLR(prt_cfg, AGL_GMX_PRT_CFG_DUPLEX);
886 
887 	switch (ifp->if_baudrate) {
888 	case IF_Mbps(10):
889 		CLR(prt_cfg, AGL_GMX_PRT_CFG_SPEED);
890 		SET(prt_cfg, AGL_GMX_PRT_CFG_SPEED_MSB);
891 		CLR(prt_cfg, AGL_GMX_PRT_CFG_SLOTTIME);
892 		SET(prt_cfg, AGL_GMX_PRT_CFG_BURST);
893 		clk_cnt = 50;
894 		break;
895 	case IF_Mbps(100):
896 		CLR(prt_cfg, AGL_GMX_PRT_CFG_SPEED);
897 		CLR(prt_cfg, AGL_GMX_PRT_CFG_SPEED_MSB);
898 		CLR(prt_cfg, AGL_GMX_PRT_CFG_SLOTTIME);
899 		SET(prt_cfg, AGL_GMX_PRT_CFG_BURST);
900 		clk_cnt = 5;
901 		break;
902 	case IF_Gbps(1):
903 	default:
904 		SET(prt_cfg, AGL_GMX_PRT_CFG_SPEED);
905 		CLR(prt_cfg, AGL_GMX_PRT_CFG_SPEED_MSB);
906 		SET(prt_cfg, AGL_GMX_PRT_CFG_SLOTTIME);
907 		if (ISSET(sc->sc_port_mii->mii_media_active, IFM_FDX))
908 			SET(prt_cfg, AGL_GMX_PRT_CFG_BURST);
909 		else
910 			CLR(prt_cfg, AGL_GMX_PRT_CFG_BURST);
911 		clk_cnt = 1;
912 		break;
913 	}
914 
915 	AGL_GMX_PORT_WR8(sc, AGL_GMX_PRT_CFG, prt_cfg);
916 	(void)AGL_GMX_PORT_RD8(sc, AGL_GMX_PRT_CFG);
917 
918 	val = AGL_GMX_PORT_RD8(sc, AGL_GMX_TX_CLK);
919 	CLR(val, AGL_GMX_TX_CLK_CLK_CNT_M);
920 	SET(val, clk_cnt << AGL_GMX_TX_CLK_CLK_CNT_S);
921 	AGL_GMX_PORT_WR8(sc, AGL_GMX_TX_CLK, val);
922 	(void)AGL_GMX_PORT_RD8(sc, AGL_GMX_TX_CLK);
923 
924 	maxlen = roundup(ifp->if_hardmtu + ETHER_HDR_LEN + ETHER_CRC_LEN +
925 	    ETHER_VLAN_ENCAP_LEN, 8);
926 	AGL_GMX_PORT_WR8(sc, AGL_GMX_RX_JABBER, maxlen);
927 	AGL_GMX_PORT_WR8(sc, AGL_GMX_RX_FRM_MAX, maxlen);
928 	(void)AGL_GMX_PORT_RD8(sc, AGL_GMX_RX_FRM_MAX);
929 
930 	cn30xxgmx_agl_up(sc);
931 
932 	val = AGL_GMX_RD8(sc, AGL_PRT_CTL(port));
933 	SET(val, AGL_PRT_CTL_CLKRST);
934 	AGL_GMX_WR8(sc, AGL_PRT_CTL(port), val);
935 
936 	val = AGL_GMX_RD8(sc, AGL_PRT_CTL(port));
937 	SET(val, AGL_PRT_CTL_ENABLE);
938 	AGL_GMX_WR8(sc, AGL_PRT_CTL(port), val);
939 	(void)AGL_GMX_RD8(sc, AGL_PRT_CTL(port));
940 
941 	return 0;
942 }
943 
944 int
cn30xxgmx_agl_timing(struct cn30xxgmx_port_softc * sc)945 cn30xxgmx_agl_timing(struct cn30xxgmx_port_softc *sc)
946 {
947 	return 0;
948 }
949 
950 int
cn30xxgmx_rgmii_enable(struct cn30xxgmx_port_softc * sc,int enable)951 cn30xxgmx_rgmii_enable(struct cn30xxgmx_port_softc *sc, int enable)
952 {
953 	uint64_t mode;
954 
955 	/* XXX */
956 	mode = _GMX_RD8(sc, GMX0_INF_MODE);
957 	if (ISSET(mode, INF_MODE_EN)) {
958 		cn30xxasx_enable(sc->sc_port_asx, 1);
959 	}
960 
961 	return 0;
962 }
963 
964 int
cn30xxgmx_rgmii_speed(struct cn30xxgmx_port_softc * sc)965 cn30xxgmx_rgmii_speed(struct cn30xxgmx_port_softc *sc)
966 {
967 	struct ifnet *ifp = &sc->sc_port_ac->ac_if;
968 	uint64_t newlink;
969 	int baudrate;
970 
971 	/* XXX */
972 	cn30xxgmx_link_enable(sc, 1);
973 
974 	cn30xxgmx_rgmii_speed_newlink(sc, &newlink);
975 	if (sc->sc_link == newlink) {
976 		return 0;
977 	}
978 #ifdef OCTEON_ETH_DEBUG
979 	cn30xxgmx_rgmii_speed_newlink_log(sc, newlink);
980 #endif
981 	sc->sc_link = newlink;
982 
983 	switch (sc->sc_link & RXN_RX_INBND_SPEED) {
984 	case RXN_RX_INBND_SPEED_2_5:
985 		baudrate = IF_Mbps(10);
986 		break;
987 	case RXN_RX_INBND_SPEED_25:
988 		baudrate = IF_Mbps(100);
989 		break;
990 	case RXN_RX_INBND_SPEED_125:
991 		baudrate = IF_Gbps(1);
992 		break;
993 	default:
994 		/* Assume 1Gbps for now */
995 		baudrate = IF_Gbps(1); /* XXX */
996 		break;
997 	}
998 	ifp->if_baudrate = baudrate;
999 
1000 	cn30xxgmx_link_enable(sc, 0);
1001 
1002 	/*
1003 	 * According to CN30XX-HM-1.0, 13.4.2 Link Status Changes:
1004 	 * wait a max_packet_time
1005 	 * max_packet_time(us) = (max_packet_size(bytes) * 8) / link_speed(Mbps)
1006 	 */
1007 	delay((GMX_FRM_MAX_SIZ * 8) / (baudrate / 1000000));
1008 
1009 	cn30xxgmx_rgmii_speed_speed(sc);
1010 
1011 	cn30xxgmx_link_enable(sc, 1);
1012 	cn30xxasx_enable(sc->sc_port_asx, 1);
1013 
1014 	return 0;
1015 }
1016 
1017 int
cn30xxgmx_rgmii_speed_newlink(struct cn30xxgmx_port_softc * sc,uint64_t * rnewlink)1018 cn30xxgmx_rgmii_speed_newlink(struct cn30xxgmx_port_softc *sc,
1019     uint64_t *rnewlink)
1020 {
1021 	uint64_t newlink;
1022 
1023 	/* Inband status does not seem to work */
1024 	newlink = _GMX_PORT_RD8(sc, GMX0_RX0_RX_INBND);
1025 
1026 	*rnewlink = newlink;
1027 	return 0;
1028 }
1029 
1030 #ifdef OCTEON_ETH_DEBUG
1031 int
cn30xxgmx_rgmii_speed_newlink_log(struct cn30xxgmx_port_softc * sc,uint64_t newlink)1032 cn30xxgmx_rgmii_speed_newlink_log(struct cn30xxgmx_port_softc *sc,
1033     uint64_t newlink)
1034 {
1035 	struct ifnet *ifp = &sc->sc_port_ac->ac_if;
1036 	const char *status_str;
1037 	const char *speed_str;
1038 	const char *duplex_str;
1039 	int is_status_changed;
1040 	int is_speed_changed;
1041 	int is_linked;
1042 	char status_buf[80/* XXX */];
1043 	char speed_buf[80/* XXX */];
1044 
1045 	is_status_changed = (newlink & RXN_RX_INBND_STATUS) !=
1046 	    (sc->sc_link & RXN_RX_INBND_STATUS);
1047 	is_speed_changed = (newlink & RXN_RX_INBND_SPEED) !=
1048 	    (sc->sc_link & RXN_RX_INBND_SPEED);
1049 	is_linked = ISSET(newlink, RXN_RX_INBND_STATUS);
1050 	if (is_status_changed) {
1051 		if (is_linked)
1052 			status_str = "link up";
1053 		else
1054 			status_str = "link down";
1055 	} else {
1056 		if (is_linked) {
1057 			/* any other conditions? */
1058 			if (is_speed_changed)
1059 				status_str = "link change";
1060 			else
1061 				status_str = NULL;
1062 		} else {
1063 			status_str = NULL;
1064 		}
1065 	}
1066 
1067 	if (status_str != NULL) {
1068 		if ((is_speed_changed && is_linked) || is_linked) {
1069 			switch (newlink & RXN_RX_INBND_SPEED) {
1070 			case RXN_RX_INBND_SPEED_2_5:
1071 				speed_str = "10baseT";
1072 				break;
1073 			case RXN_RX_INBND_SPEED_25:
1074 				speed_str = "100baseTX";
1075 				break;
1076 			case RXN_RX_INBND_SPEED_125:
1077 				speed_str = "1000baseT";
1078 				break;
1079 			default:
1080 				panic("Unknown link speed");
1081 				break;
1082 			}
1083 
1084 			if (ISSET(newlink, RXN_RX_INBND_DUPLEX))
1085 				duplex_str = "-FDX";
1086 			else
1087 				duplex_str = "";
1088 
1089 			(void)snprintf(speed_buf, sizeof(speed_buf), "(%s%s)",
1090 			    speed_str, duplex_str);
1091 		} else {
1092 			speed_buf[0] = '\0';
1093 		}
1094 		(void)snprintf(status_buf, sizeof(status_buf), "%s: %s%s%s\n",
1095 		    ifp->if_xname, status_str, (is_speed_changed | is_linked) ? " " : "",
1096 		    speed_buf);
1097 		log(LOG_CRIT, status_buf);
1098 	}
1099 
1100 	return 0;
1101 }
1102 #endif
1103 
1104 int
cn30xxgmx_rgmii_speed_speed(struct cn30xxgmx_port_softc * sc)1105 cn30xxgmx_rgmii_speed_speed(struct cn30xxgmx_port_softc *sc)
1106 {
1107 	uint64_t prt_cfg;
1108 	uint64_t tx_clk, tx_slot, tx_burst;
1109 
1110 	prt_cfg = _GMX_PORT_RD8(sc, GMX0_PRT0_CFG);
1111 
1112 	switch (sc->sc_link & RXN_RX_INBND_SPEED) {
1113 	case RXN_RX_INBND_SPEED_2_5:
1114 		/* 10Mbps */
1115 		/*
1116 		 * "GMX Tx Clock Generation Registers", CN30XX-HM-1.0;
1117 		 * > 8ns x 50 = 400ns (2.5MHz TXC clock)
1118 		 */
1119 		tx_clk = 50;
1120 		/*
1121 		 * "TX Slottime Counter Registers", CN30XX-HM-1.0;
1122 		 * > 10/100Mbps: set SLOT to 0x40
1123 		 */
1124 		tx_slot = 0x40;
1125 		/*
1126 		 * "TX Burst-Counter Registers", CN30XX-HM-1.0;
1127 		 * > 10/100Mbps: set BURST to 0x0
1128 		 */
1129 		tx_burst = 0;
1130 		/*
1131 		 * "GMX Tx Port Configuration Registers", CN30XX-HM-1.0;
1132 		 * > Slot time for half-duplex operation
1133 		 * >   0 = 512 bittimes (10/100Mbps operation)
1134 		 */
1135 		CLR(prt_cfg, PRTN_CFG_SLOTTIME);
1136 		/*
1137 		 * "GMX Port Configuration Registers", CN30XX-HM-1.0;
1138 		 * > Link speed
1139 		 * >   0 = 10/100Mbps operation
1140 		 * >     in RGMII mode: GMX0_TX(0..2)_CLK[CLK_CNT] > 1
1141 		 */
1142 		CLR(prt_cfg, PRTN_CFG_SPEED);
1143 		break;
1144 	case RXN_RX_INBND_SPEED_25:
1145 		/* 100Mbps */
1146 		/*
1147 		 * "GMX Tx Clock Generation Registers", CN30XX-HM-1.0;
1148 		 * > 8ns x 5 = 40ns (25.0MHz TXC clock)
1149 		 */
1150 		tx_clk = 5;
1151 		/*
1152 		 * "TX Slottime Counter Registers", CN30XX-HM-1.0;
1153 		 * > 10/100Mbps: set SLOT to 0x40
1154 		 */
1155 		tx_slot = 0x40;
1156 		/*
1157 		 * "TX Burst-Counter Registers", CN30XX-HM-1.0;
1158 		 * > 10/100Mbps: set BURST to 0x0
1159 		 */
1160 		tx_burst = 0;
1161 		/*
1162 		 * "GMX Tx Port Configuration Registers", CN30XX-HM-1.0;
1163 		 * > Slot time for half-duplex operation
1164 		 * >   0 = 512 bittimes (10/100Mbps operation)
1165 		 */
1166 		CLR(prt_cfg, PRTN_CFG_SLOTTIME);
1167 		/*
1168 		 * "GMX Port Configuration Registers", CN30XX-HM-1.0;
1169 		 * > Link speed
1170 		 * >   0 = 10/100Mbps operation
1171 		 * >     in RGMII mode: GMX0_TX(0..2)_CLK[CLK_CNT] > 1
1172 		 */
1173 		CLR(prt_cfg, PRTN_CFG_SPEED);
1174 		break;
1175 	case RXN_RX_INBND_SPEED_125:
1176 		/* 1000Mbps */
1177 		/*
1178 		 * "GMX Tx Clock Generation Registers", CN30XX-HM-1.0;
1179 		 * > 8ns x 1 = 8ns (125.0MHz TXC clock)
1180 		 */
1181 		tx_clk = 1;
1182 		/*
1183 		 * "TX Slottime Counter Registers", CN30XX-HM-1.0;
1184 		 * > 1000Mbps: set SLOT to 0x200
1185 		 */
1186 		tx_slot = 0x200;
1187 		/*
1188 		 * "TX Burst-Counter Registers", CN30XX-HM-1.0;
1189 		 * > 1000Mbps: set BURST to 0x2000
1190 		 */
1191 		tx_burst = 0x2000;
1192 		/*
1193 		 * "GMX Tx Port Configuration Registers", CN30XX-HM-1.0;
1194 		 * > Slot time for half-duplex operation
1195 		 * >   1 = 4096 bittimes (1000Mbps operation)
1196 		 */
1197 		SET(prt_cfg, PRTN_CFG_SLOTTIME);
1198 		/*
1199 		 * "GMX Port Configuration Registers", CN30XX-HM-1.0;
1200 		 * > Link speed
1201 		 * >   1 = 1000Mbps operation
1202 		 */
1203 		SET(prt_cfg, PRTN_CFG_SPEED);
1204 		break;
1205 	default:
1206 		/* THEORETICALLY NOT REACHED! */
1207 		/* Following configuration is default value of system.
1208 		*/
1209 		tx_clk = 1;
1210 		tx_slot = 0x200;
1211 		tx_burst = 0x2000;
1212 		SET(prt_cfg, PRTN_CFG_SLOTTIME);
1213 		SET(prt_cfg, PRTN_CFG_SPEED);
1214 		break;
1215 	}
1216 
1217 	/* Setup Duplex mode(negotiated) */
1218 	/*
1219 	 * "GMX Port Configuration Registers", CN30XX-HM-1.0;
1220 	 * > Duplex mode: 0 = half-duplex mode, 1=full-duplex
1221 	 */
1222 	if (ISSET(sc->sc_link, RXN_RX_INBND_DUPLEX)) {
1223 		/* Full-Duplex */
1224 		SET(prt_cfg, PRTN_CFG_DUPLEX);
1225 	} else {
1226 		/* Half-Duplex */
1227 		CLR(prt_cfg, PRTN_CFG_DUPLEX);
1228 	}
1229 
1230 	_GMX_PORT_WR8(sc, GMX0_TX0_CLK, tx_clk);
1231 	_GMX_PORT_WR8(sc, GMX0_TX0_SLOT, tx_slot);
1232 	_GMX_PORT_WR8(sc, GMX0_TX0_BURST, tx_burst);
1233 	_GMX_PORT_WR8(sc, GMX0_PRT0_CFG, prt_cfg);
1234 
1235 	return 0;
1236 }
1237 
1238 int
cn30xxgmx_rgmii_timing(struct cn30xxgmx_port_softc * sc)1239 cn30xxgmx_rgmii_timing(struct cn30xxgmx_port_softc *sc)
1240 {
1241 	int clk_tx_setting;
1242 	int clk_rx_setting;
1243 	uint64_t rx_frm_ctl;
1244 
1245 	/* RGMII TX Threshold Registers, CN30XX-HM-1.0;
1246 	 * > Number of 16-byte ticks to accumulate in the TX FIFO before
1247 	 * > sending on the RGMII interface. This field should be large
1248 	 * > enough to prevent underflow on the RGMII interface and must
1249 	 * > never be set to less than 0x4. This register cannot exceed
1250 	 * > the TX FIFO depth of 0x40 words.
1251 	 */
1252 	/* Default parameter of CN30XX */
1253 	cn30xxgmx_tx_thresh(sc, 32);
1254 
1255 	rx_frm_ctl = 0 |
1256 	    /* RXN_FRM_CTL_NULL_DIS |	(cn5xxx only) */
1257 	    /* RXN_FRM_CTL_PRE_ALIGN |	(cn5xxx only) */
1258 	    /* RXN_FRM_CTL_PAD_LEN |	(cn3xxx only) */
1259 	    /* RXN_FRM_CTL_VLAN_LEN |	(cn3xxx only) */
1260 	    RXN_FRM_CTL_PRE_FREE |
1261 	    RXN_FRM_CTL_CTL_SMAC |
1262 	    RXN_FRM_CTL_CTL_MCST |
1263 	    RXN_FRM_CTL_CTL_DRP |
1264 	    RXN_FRM_CTL_PRE_STRP |
1265 	    RXN_FRM_CTL_PRE_CHK;
1266 	cn30xxgmx_rx_frm_ctl_enable(sc, rx_frm_ctl);
1267 
1268 	/* XXX PHY-dependent parameter */
1269 	/* RGMII RX Clock-Delay Registers, CN30XX-HM-1.0;
1270 	 * > Delay setting to place n RXC (RGMII receive clock) delay line.
1271 	 * > The intrinsic delay can range from 50ps to 80ps per tap,
1272 	 * > which corresponds to skews of 1.25ns to 2.00ns at 25 taps(CSR+1).
1273 	 * > This is the best match for the RGMII specification which wants
1274 	 * > 1ns - 2.6ns of skew.
1275 	 */
1276 	/* RGMII TX Clock-Delay Registers, CN30XX-HM-1.0;
1277 	 * > Delay setting to place n TXC (RGMII transmit clock) delay line.
1278 	 * > ...
1279 	 */
1280 
1281 	switch (octeon_board) {
1282 	default:
1283 		/* Default parameter of CN30XX */
1284 		clk_tx_setting = 24;
1285 		clk_rx_setting = 24;
1286 		break;
1287 	case BOARD_NETGEAR_UTM25:
1288 		if (sc->sc_port_no == 0) {
1289 			clk_tx_setting = 9;
1290 			clk_rx_setting = 9;
1291 		} else {
1292 			clk_tx_setting = 24;
1293 			clk_rx_setting = 24;
1294 		}
1295 		break;
1296 	case BOARD_UBIQUITI_E100:
1297 	case BOARD_UBIQUITI_E120:
1298 		clk_tx_setting = 16;
1299 		clk_rx_setting = 0;
1300 		break;
1301 	}
1302 
1303 	cn30xxasx_clk_set(sc->sc_port_asx, clk_tx_setting, clk_rx_setting);
1304 
1305 	return 0;
1306 }
1307 
1308 int
cn30xxgmx_sgmii_enable(struct cn30xxgmx_port_softc * sc,int enable)1309 cn30xxgmx_sgmii_enable(struct cn30xxgmx_port_softc *sc, int enable)
1310 {
1311 	uint64_t ctl_reg, status, timer_count;
1312 	uint64_t cpu_freq = octeon_boot_info->eclock / 1000000;
1313 	int done;
1314 	int i;
1315 
1316 	if (!enable)
1317 		return 0;
1318 
1319 	/* Set link timer interval to 1.6ms. */
1320 	timer_count = PCS_READ_8(sc, PCS_LINK_TIMER_COUNT);
1321 	CLR(timer_count, PCS_LINK_TIMER_COUNT_MASK);
1322 	SET(timer_count, ((1600 * cpu_freq) >> 10) & PCS_LINK_TIMER_COUNT_MASK);
1323 	PCS_WRITE_8(sc, PCS_LINK_TIMER_COUNT, timer_count);
1324 
1325 	/* Reset the PCS. */
1326 	ctl_reg = PCS_READ_8(sc, PCS_MR_CONTROL);
1327 	SET(ctl_reg, PCS_MR_CONTROL_RESET);
1328 	PCS_WRITE_8(sc, PCS_MR_CONTROL, ctl_reg);
1329 
1330 	/* Wait for the reset to complete. */
1331 	done = 0;
1332 	for (i = 0; i < 1000000; i++) {
1333 		ctl_reg = PCS_READ_8(sc, PCS_MR_CONTROL);
1334 		if (!ISSET(ctl_reg, PCS_MR_CONTROL_RESET)) {
1335 			done = 1;
1336 			break;
1337 		}
1338 	}
1339 	if (!done) {
1340 		printf("SGMII reset timeout on port %d\n", sc->sc_port_no);
1341 		return 1;
1342 	}
1343 
1344 	/* Start a new SGMII autonegotiation. */
1345 	SET(ctl_reg, PCS_MR_CONTROL_AN_EN);
1346 	SET(ctl_reg, PCS_MR_CONTROL_RST_AN);
1347 	CLR(ctl_reg, PCS_MR_CONTROL_PWR_DN);
1348 	PCS_WRITE_8(sc, PCS_MR_CONTROL, ctl_reg);
1349 
1350 	/* Wait for the SGMII autonegotiation to complete. */
1351 	done = 0;
1352 	for (i = 0; i < 1000000; i++) {
1353 		status = PCS_READ_8(sc, PCS_MR_STATUS);
1354 		if (ISSET(status, PCS_MR_STATUS_AN_CPT)) {
1355 			done = 1;
1356 			break;
1357 		}
1358 	}
1359 	if (!done) {
1360 		printf("SGMII autonegotiation timeout on port %d\n",
1361 		    sc->sc_port_no);
1362 		return 1;
1363 	}
1364 
1365 	return 0;
1366 }
1367 
1368 int
cn30xxgmx_sgmii_speed(struct cn30xxgmx_port_softc * sc)1369 cn30xxgmx_sgmii_speed(struct cn30xxgmx_port_softc *sc)
1370 {
1371 	uint64_t misc_ctl, prt_cfg;
1372 	int tx_burst, tx_slot;
1373 
1374 	cn30xxgmx_link_enable(sc, 0);
1375 
1376 	prt_cfg = _GMX_PORT_RD8(sc, GMX0_PRT0_CFG);
1377 
1378 	if (ISSET(sc->sc_port_mii->mii_media_active, IFM_FDX))
1379 		SET(prt_cfg, PRTN_CFG_DUPLEX);
1380 	else
1381 		CLR(prt_cfg, PRTN_CFG_DUPLEX);
1382 
1383 	misc_ctl = PCS_READ_8(sc, PCS_MISC_CTL);
1384 	CLR(misc_ctl, PCS_MISC_CTL_SAMP_PT);
1385 
1386 	/* Disable the GMX port if the link is down. */
1387 	if (cn30xxgmx_link_status(sc))
1388 		CLR(misc_ctl, PCS_MISC_CTL_GMXENO);
1389 	else
1390 		SET(misc_ctl, PCS_MISC_CTL_GMXENO);
1391 
1392 	switch (sc->sc_port_ac->ac_if.if_baudrate) {
1393 	case IF_Mbps(10):
1394 		tx_slot = 0x40;
1395 		tx_burst = 0;
1396 		CLR(prt_cfg, PRTN_CFG_SPEED);
1397 		SET(prt_cfg, PRTN_CFG_SPEED_MSB);
1398 		CLR(prt_cfg, PRTN_CFG_SLOTTIME);
1399 		misc_ctl |= 25 & PCS_MISC_CTL_SAMP_PT;
1400 		break;
1401 	case IF_Mbps(100):
1402 		tx_slot = 0x40;
1403 		tx_burst = 0;
1404 		CLR(prt_cfg, PRTN_CFG_SPEED);
1405 		CLR(prt_cfg, PRTN_CFG_SPEED_MSB);
1406 		CLR(prt_cfg, PRTN_CFG_SLOTTIME);
1407 		misc_ctl |= 5 & PCS_MISC_CTL_SAMP_PT;
1408 		break;
1409 	case IF_Gbps(1):
1410 	default:
1411 		tx_slot = 0x200;
1412 		tx_burst = 0x2000;
1413 		SET(prt_cfg, PRTN_CFG_SPEED);
1414 		CLR(prt_cfg, PRTN_CFG_SPEED_MSB);
1415 		SET(prt_cfg, PRTN_CFG_SLOTTIME);
1416 		misc_ctl |= 1 & PCS_MISC_CTL_SAMP_PT;
1417 		break;
1418 	}
1419 
1420 	PCS_WRITE_8(sc, PCS_MISC_CTL, misc_ctl);
1421 
1422 	_GMX_PORT_WR8(sc, GMX0_TX0_SLOT, tx_slot);
1423 	_GMX_PORT_WR8(sc, GMX0_TX0_BURST, tx_burst);
1424 	_GMX_PORT_WR8(sc, GMX0_PRT0_CFG, prt_cfg);
1425 
1426 	cn30xxgmx_link_enable(sc, 1);
1427 
1428 	return 0;
1429 }
1430 
1431 int
cn30xxgmx_sgmii_timing(struct cn30xxgmx_port_softc * sc)1432 cn30xxgmx_sgmii_timing(struct cn30xxgmx_port_softc *sc)
1433 {
1434 	uint64_t rx_frm_ctl;
1435 
1436 	cn30xxgmx_tx_thresh(sc, 32);
1437 
1438 	rx_frm_ctl =
1439 	    RXN_FRM_CTL_PRE_FREE |
1440 	    RXN_FRM_CTL_CTL_SMAC |
1441 	    RXN_FRM_CTL_CTL_MCST |
1442 	    RXN_FRM_CTL_CTL_DRP |
1443 	    RXN_FRM_CTL_PRE_STRP |
1444 	    RXN_FRM_CTL_PRE_CHK;
1445 	cn30xxgmx_rx_frm_ctl_enable(sc, rx_frm_ctl);
1446 
1447 	return 0;
1448 }
1449 
1450 #if NKSTAT > 0
1451 void
cn30xxgmx_kstat_read(struct cn30xxgmx_port_softc * sc,struct kstat_kv * kvs)1452 cn30xxgmx_kstat_read(struct cn30xxgmx_port_softc *sc, struct kstat_kv *kvs)
1453 {
1454 	uint64_t val;
1455 
1456 	kstat_kv_u64(&kvs[cnmac_stat_rx_totp_gmx]) +=
1457 	    (uint32_t)_GMX_PORT_RD8(sc, GMX0_RX0_STATS_PKTS);
1458 	kstat_kv_u64(&kvs[cnmac_stat_rx_toto_gmx]) +=
1459 	    (uint32_t)_GMX_PORT_RD8(sc, GMX0_RX0_STATS_OCTS);
1460 	kstat_kv_u64(&kvs[cnmac_stat_rx_ctl]) +=
1461 	    (uint32_t)_GMX_PORT_RD8(sc, GMX0_RX0_STATS_PKTS_CTL);
1462 	kstat_kv_u64(&kvs[cnmac_stat_rx_dmac]) +=
1463 	    (uint32_t)_GMX_PORT_RD8(sc, GMX0_RX0_STATS_PKTS_DMAC);
1464 	kstat_kv_u64(&kvs[cnmac_stat_rx_drop]) +=
1465 	    (uint32_t)_GMX_PORT_RD8(sc, GMX0_RX0_STATS_PKTS_DRP);
1466 	kstat_kv_u64(&kvs[cnmac_stat_rx_bad]) +=
1467 	    (uint32_t)_GMX_PORT_RD8(sc, GMX0_RX0_STATS_PKTS_BAD);
1468 
1469 	val = _GMX_PORT_RD8(sc, GMX0_TX0_STAT0);
1470 	kstat_kv_u64(&kvs[cnmac_stat_tx_coll]) += (uint32_t)val;
1471 	kstat_kv_u64(&kvs[cnmac_stat_tx_defer]) += val >> 32;
1472 
1473 	val = _GMX_PORT_RD8(sc, GMX0_TX0_STAT1);
1474 	kstat_kv_u64(&kvs[cnmac_stat_tx_mcol]) += (uint32_t)val;
1475 	kstat_kv_u64(&kvs[cnmac_stat_tx_scol]) += val >> 32;
1476 
1477 	kstat_kv_u64(&kvs[cnmac_stat_tx_toto]) +=
1478 	    (uint32_t)_GMX_PORT_RD8(sc, GMX0_TX0_STAT2);
1479 	kstat_kv_u64(&kvs[cnmac_stat_tx_totp]) +=
1480 	    (uint32_t)_GMX_PORT_RD8(sc, GMX0_TX0_STAT3);
1481 
1482 	val = _GMX_PORT_RD8(sc, GMX0_TX0_STAT4);
1483 	kstat_kv_u64(&kvs[cnmac_stat_tx_hmin]) += (uint32_t)val;
1484 	kstat_kv_u64(&kvs[cnmac_stat_tx_h64]) += val >> 32;
1485 
1486 	val = _GMX_PORT_RD8(sc, GMX0_TX0_STAT5);
1487 	kstat_kv_u64(&kvs[cnmac_stat_tx_h127]) += (uint32_t)val;
1488 	kstat_kv_u64(&kvs[cnmac_stat_tx_h255]) += val >> 32;
1489 
1490 	val = _GMX_PORT_RD8(sc, GMX0_TX0_STAT6);
1491 	kstat_kv_u64(&kvs[cnmac_stat_tx_h511]) += (uint32_t)val;
1492 	kstat_kv_u64(&kvs[cnmac_stat_tx_h1023]) += val >> 32;
1493 
1494 	val = _GMX_PORT_RD8(sc, GMX0_TX0_STAT7);
1495 	kstat_kv_u64(&kvs[cnmac_stat_tx_h1518]) += (uint32_t)val;
1496 	kstat_kv_u64(&kvs[cnmac_stat_tx_hmax]) += val >> 32;
1497 
1498 	val = _GMX_PORT_RD8(sc, GMX0_TX0_STAT8);
1499 	kstat_kv_u64(&kvs[cnmac_stat_tx_bcast]) += (uint32_t)val;
1500 	kstat_kv_u64(&kvs[cnmac_stat_tx_mcast]) += val >> 32;
1501 
1502 	val = _GMX_PORT_RD8(sc, GMX0_TX0_STAT9);
1503 	kstat_kv_u64(&kvs[cnmac_stat_tx_ctl]) += (uint32_t)val;
1504 	kstat_kv_u64(&kvs[cnmac_stat_tx_uflow]) += val >> 32;
1505 }
1506 #endif
1507