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