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