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