1 /* $NetBSD: octeon_pip.c,v 1.2 2018/02/06 09:33:45 mrg 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/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: octeon_pip.c,v 1.2 2018/02/06 09:33:45 mrg Exp $"); 31 32 #include "opt_octeon.h" 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/malloc.h> 37 #include <sys/syslog.h> 38 #include <sys/time.h> 39 #include <net/if.h> 40 #include <mips/locore.h> 41 #include <mips/cavium/octeonvar.h> 42 #include <mips/cavium/dev/octeon_pipreg.h> 43 #include <mips/cavium/dev/octeon_pipvar.h> 44 45 #ifdef OCTEON_ETH_DEBUG 46 struct octeon_pip_softc *__octeon_pip_softc; 47 48 void octeon_pip_intr_evcnt_attach(struct octeon_pip_softc *); 49 void octeon_pip_intr_rml(void *); 50 51 void octeon_pip_dump(void); 52 void octeon_pip_int_enable(struct octeon_pip_softc *, int); 53 #endif 54 55 /* 56 * register definitions (for debug and statics) 57 */ 58 #define _ENTRY(x) { #x, x##_BITS, x##_OFFSET } 59 #define _ENTRY_0_3(x) \ 60 _ENTRY(x## 0), _ENTRY(x## 1), _ENTRY(x## 2), _ENTRY(x## 3) 61 #define _ENTRY_0_7(x) \ 62 _ENTRY(x## 0), _ENTRY(x## 1), _ENTRY(x## 2), _ENTRY(x## 3), \ 63 _ENTRY(x## 4), _ENTRY(x## 5), _ENTRY(x## 6), _ENTRY(x## 7) 64 #define _ENTRY_0_1_2_32(x) \ 65 _ENTRY(x## 0), _ENTRY(x## 1), _ENTRY(x## 2), _ENTRY(x##32) 66 67 struct octeon_pip_dump_reg_ { 68 const char *name; 69 const char *format; 70 size_t offset; 71 }; 72 73 static const struct octeon_pip_dump_reg_ octeon_pip_dump_stats_[] = { 74 /* PIP_QOS_DIFF[0-63] */ 75 _ENTRY_0_1_2_32 (PIP_STAT0_PRT), 76 _ENTRY_0_1_2_32 (PIP_STAT1_PRT), 77 _ENTRY_0_1_2_32 (PIP_STAT2_PRT), 78 _ENTRY_0_1_2_32 (PIP_STAT3_PRT), 79 _ENTRY_0_1_2_32 (PIP_STAT4_PRT), 80 _ENTRY_0_1_2_32 (PIP_STAT5_PRT), 81 _ENTRY_0_1_2_32 (PIP_STAT6_PRT), 82 _ENTRY_0_1_2_32 (PIP_STAT7_PRT), 83 _ENTRY_0_1_2_32 (PIP_STAT8_PRT), 84 _ENTRY_0_1_2_32 (PIP_STAT9_PRT), 85 /* PIP_TAG_INC[0-63] */ 86 _ENTRY_0_1_2_32 (PIP_STAT_INB_PKTS), 87 _ENTRY_0_1_2_32 (PIP_STAT_INB_OCTS), 88 _ENTRY_0_1_2_32 (PIP_STAT_INB_ERRS), 89 }; 90 91 #ifdef OCTEON_ETH_DEBUG 92 static const struct octeon_pip_dump_reg_ octeon_pip_dump_regs_[] = { 93 _ENTRY (PIP_BIST_STATUS), 94 _ENTRY (PIP_INT_REG), 95 _ENTRY (PIP_INT_EN), 96 _ENTRY (PIP_STAT_CTL), 97 _ENTRY (PIP_GBL_CTL), 98 _ENTRY (PIP_GBL_CFG), 99 _ENTRY (PIP_SOFT_RST), 100 _ENTRY (PIP_IP_OFFSET), 101 _ENTRY (PIP_TAG_SECRET), 102 _ENTRY (PIP_TAG_MASK), 103 _ENTRY_0_3 (PIP_DEC_IPSEC), 104 _ENTRY (PIP_RAW_WORD), 105 _ENTRY_0_7 (PIP_QOS_VLAN), 106 _ENTRY_0_3 (PIP_QOS_WATCH), 107 _ENTRY_0_1_2_32 (PIP_PRT_CFG), 108 _ENTRY_0_1_2_32 (PIP_PRT_TAG), 109 }; 110 #endif 111 112 #undef _ENTRY 113 #undef _ENTRY_0_3 114 #undef _ENTRY_0_7 115 #undef _ENTRY_0_1_2_32 116 117 /* XXX */ 118 void 119 octeon_pip_init(struct octeon_pip_attach_args *aa, 120 struct octeon_pip_softc **rsc) 121 { 122 struct octeon_pip_softc *sc; 123 int status; 124 125 sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO); 126 if (sc == NULL) 127 panic("can't allocate memory: %s", __func__); 128 129 sc->sc_port = aa->aa_port; 130 sc->sc_regt = aa->aa_regt; 131 sc->sc_tag_type = aa->aa_tag_type; 132 sc->sc_receive_group = aa->aa_receive_group; 133 sc->sc_ip_offset = aa->aa_ip_offset; 134 135 status = bus_space_map(sc->sc_regt, PIP_BASE, PIP_SIZE, 0, 136 &sc->sc_regh); 137 if (status != 0) 138 panic("can't map %s space", "pip register"); 139 140 *rsc = sc; 141 142 #ifdef OCTEON_ETH_DEBUG 143 octeon_pip_int_enable(sc, 1); 144 octeon_pip_intr_evcnt_attach(sc); 145 __octeon_pip_softc = sc; 146 printf("PIP Code initialized.\n"); 147 #endif 148 } 149 150 #define _PIP_RD8(sc, off) \ 151 bus_space_read_8((sc)->sc_regt, (sc)->sc_regh, (off)) 152 #define _PIP_WR8(sc, off, v) \ 153 bus_space_write_8((sc)->sc_regt, (sc)->sc_regh, (off), (v)) 154 155 int 156 octeon_pip_port_config(struct octeon_pip_softc *sc) 157 { 158 uint64_t prt_cfg; 159 uint64_t prt_tag; 160 uint64_t ip_offset; 161 162 /* 163 * Process the headers and place the IP header in the work queue 164 */ 165 prt_cfg = 0; 166 if (MIPS_PRID_IMPL(mips_options.mips_cpu_id) == MIPS_CN50XX) { 167 SET(prt_cfg, PIP_PRT_CFGN_LENERR_EN); 168 SET(prt_cfg, PIP_PRT_CFGN_MAXERR_EN); 169 SET(prt_cfg, PIP_PRT_CFGN_MINERR_EN); 170 } 171 /* RAWDRP=0; don't allow raw packet drop */ 172 /* TAGINC=0 */ 173 SET(prt_cfg, PIP_PRT_CFGN_DYN_RS); 174 /* INST_HDR=0 */ 175 /* GRP_WAT=0 */ 176 SET(prt_cfg, (sc->sc_port << 24) & PIP_PRT_CFGN_QOS); 177 /* QOS_WAT=0 */ 178 /* SPARE=0 */ 179 /* QOS_DIFF=0 */ 180 /* QOS_VLAN=0 */ 181 SET(prt_cfg, PIP_PRT_CFGN_CRC_EN); 182 /* SKIP=0 */ 183 184 prt_tag = 0; 185 SET(prt_tag, PIP_PRT_TAGN_INC_PRT); 186 CLR(prt_tag, PIP_PRT_TAGN_IP6_DPRT); 187 CLR(prt_tag, PIP_PRT_TAGN_IP4_DPRT); 188 CLR(prt_tag, PIP_PRT_TAGN_IP6_SPRT); 189 CLR(prt_tag, PIP_PRT_TAGN_IP4_SPRT); 190 CLR(prt_tag, PIP_PRT_TAGN_IP6_NXTH); 191 CLR(prt_tag, PIP_PRT_TAGN_IP4_PCTL); 192 CLR(prt_tag, PIP_PRT_TAGN_IP6_DST); 193 CLR(prt_tag, PIP_PRT_TAGN_IP4_SRC); 194 CLR(prt_tag, PIP_PRT_TAGN_IP6_SRC); 195 CLR(prt_tag, PIP_PRT_TAGN_IP4_DST); 196 SET(prt_tag, PIP_PRT_TAGN_TCP6_TAG_ORDERED); 197 SET(prt_tag, PIP_PRT_TAGN_TCP4_TAG_ORDERED); 198 SET(prt_tag, PIP_PRT_TAGN_IP6_TAG_ORDERED); 199 SET(prt_tag, PIP_PRT_TAGN_IP4_TAG_ORDERED); 200 SET(prt_tag, PIP_PRT_TAGN_NON_TAG_ORDERED); 201 SET(prt_tag, sc->sc_receive_group & PIP_PRT_TAGN_GRP); 202 203 ip_offset = 0; 204 SET(ip_offset, (sc->sc_ip_offset / 8) & PIP_IP_OFFSET_MASK_OFFSET); 205 206 _PIP_WR8(sc, PIP_PRT_CFG0_OFFSET + (8 * sc->sc_port), prt_cfg); 207 _PIP_WR8(sc, PIP_PRT_TAG0_OFFSET + (8 * sc->sc_port), prt_tag); 208 _PIP_WR8(sc, PIP_IP_OFFSET_OFFSET, ip_offset); 209 210 return 0; 211 } 212 213 void 214 octeon_pip_prt_cfg_enable(struct octeon_pip_softc *sc, uint64_t prt_cfg, 215 int enable) 216 { 217 uint64_t tmp; 218 219 tmp = _PIP_RD8(sc, PIP_PRT_CFG0_OFFSET + (8 * sc->sc_port)); 220 if (enable) 221 tmp |= prt_cfg; 222 else 223 tmp &= ~prt_cfg; 224 _PIP_WR8(sc, PIP_PRT_CFG0_OFFSET + (8 * sc->sc_port), tmp); 225 } 226 227 void 228 octeon_pip_stats(struct octeon_pip_softc *sc, struct ifnet *ifp, int gmx_port) 229 { 230 const struct octeon_pip_dump_reg_ *reg; 231 uint64_t tmp, pkts; 232 uint64_t pip_stat_ctl; 233 234 if (sc == NULL || ifp == NULL) 235 panic("%s: invalid argument. sc=%p, ifp=%p\n", __func__, 236 sc, ifp); 237 238 if (gmx_port < 0 || gmx_port > 2) { 239 printf("%s: invalid gmx_port %d\n", __func__, gmx_port); 240 return; 241 } 242 243 pip_stat_ctl = _PIP_RD8(sc, PIP_STAT_CTL_OFFSET); 244 _PIP_WR8(sc, PIP_STAT_CTL_OFFSET, pip_stat_ctl | PIP_STAT_CTL_RDCLR); 245 reg = &octeon_pip_dump_stats_[gmx_port]; 246 tmp = _PIP_RD8(sc, reg->offset); 247 pkts = (tmp & 0xffffffff00000000ULL) >> 32; 248 ifp->if_iqdrops += pkts; 249 250 _PIP_WR8(sc, PIP_STAT_CTL_OFFSET, pip_stat_ctl); 251 } 252 253 254 #ifdef OCTEON_ETH_DEBUG 255 int octeon_pip_intr_rml_verbose; 256 struct evcnt octeon_pip_intr_evcnt; 257 258 static const struct octeon_evcnt_entry octeon_pip_intr_evcnt_entries[] = { 259 #define _ENTRY(name, type, parent, descr) \ 260 OCTEON_EVCNT_ENTRY(struct octeon_pip_softc, name, type, parent, descr) 261 _ENTRY(pipbeperr, MISC, NULL, "pip parity error backend"), 262 _ENTRY(pipfeperr, MISC, NULL, "pip parity error frontend"), 263 _ENTRY(pipskprunt, MISC, NULL, "pip skiper"), 264 _ENTRY(pipbadtag, MISC, NULL, "pip bad tag"), 265 _ENTRY(pipprtnxa, MISC, NULL, "pip nonexistent port"), 266 _ENTRY(pippktdrp, MISC, NULL, "pip qos drop"), 267 #undef _ENTRY 268 }; 269 270 void 271 octeon_pip_intr_evcnt_attach(struct octeon_pip_softc *sc) 272 { 273 OCTEON_EVCNT_ATTACH_EVCNTS(sc, octeon_pip_intr_evcnt_entries, "pip0"); 274 } 275 276 void 277 octeon_pip_intr_rml(void *arg) 278 { 279 struct octeon_pip_softc *sc; 280 uint64_t reg; 281 282 octeon_pip_intr_evcnt.ev_count++; 283 sc = __octeon_pip_softc; 284 KASSERT(sc != NULL); 285 reg = octeon_pip_int_summary(sc); 286 if (octeon_pip_intr_rml_verbose) 287 printf("%s: PIP_INT_REG=0x%016" PRIx64 "\n", __func__, reg); 288 if (reg & PIP_INT_REG_BEPERR) 289 OCTEON_EVCNT_INC(sc, pipbeperr); 290 if (reg & PIP_INT_REG_FEPERR) 291 OCTEON_EVCNT_INC(sc, pipfeperr); 292 if (reg & PIP_INT_REG_SKPRUNT) 293 OCTEON_EVCNT_INC(sc, pipskprunt); 294 if (reg & PIP_INT_REG_BADTAG) 295 OCTEON_EVCNT_INC(sc, pipbadtag); 296 if (reg & PIP_INT_REG_PRTNXA) 297 OCTEON_EVCNT_INC(sc, pipprtnxa); 298 if (reg & PIP_INT_REG_PKTDRP) 299 OCTEON_EVCNT_INC(sc, pippktdrp); 300 } 301 302 void octeon_pip_dump_regs(void); 303 void octeon_pip_dump_stats(void); 304 305 void 306 octeon_pip_dump(void) 307 { 308 octeon_pip_dump_regs(); 309 octeon_pip_dump_stats(); 310 } 311 312 void 313 octeon_pip_dump_regs(void) 314 { 315 struct octeon_pip_softc *sc = __octeon_pip_softc; 316 const struct octeon_pip_dump_reg_ *reg; 317 uint64_t tmp; 318 char buf[512]; 319 int i; 320 321 for (i = 0; i < (int)__arraycount(octeon_pip_dump_regs_); i++) { 322 reg = &octeon_pip_dump_regs_[i]; 323 tmp = _PIP_RD8(sc, reg->offset); 324 if (reg->format == NULL) { 325 snprintf(buf, sizeof(buf), "%16" PRIx64, tmp); 326 } else { 327 snprintb(buf, sizeof(buf), reg->format, tmp); 328 } 329 printf("\t%-24s: %s\n", reg->name, buf); 330 } 331 } 332 333 void 334 octeon_pip_dump_stats(void) 335 { 336 struct octeon_pip_softc *sc = __octeon_pip_softc; 337 const struct octeon_pip_dump_reg_ *reg; 338 uint64_t tmp; 339 char buf[512]; 340 int i; 341 uint64_t pip_stat_ctl; 342 343 pip_stat_ctl = _PIP_RD8(sc, PIP_STAT_CTL_OFFSET); 344 _PIP_WR8(sc, PIP_STAT_CTL_OFFSET, pip_stat_ctl & ~PIP_STAT_CTL_RDCLR); 345 for (i = 0; i < (int)__arraycount(octeon_pip_dump_stats_); i++) { 346 reg = &octeon_pip_dump_stats_[i]; 347 tmp = _PIP_RD8(sc, reg->offset); 348 if (reg->format == NULL) { 349 snprintf(buf, sizeof(buf), "%16" PRIx64, tmp); 350 } else { 351 snprintb(buf, sizeof(buf), reg->format, tmp); 352 } 353 printf("\t%-24s: %s\n", reg->name, buf); 354 } 355 printf("\t%-24s:\n", "PIP_QOS_DIFF[0-63]"); 356 for (i = 0; i < 64; i++) { 357 tmp = _PIP_RD8(sc, PIP_QOS_DIFF0_OFFSET + sizeof(uint64_t) * i); 358 snprintf(buf, sizeof(buf), "%16" PRIx64, tmp); 359 printf("%s\t%s%s", 360 ((i % 4) == 0) ? "\t" : "", 361 buf, 362 ((i % 4) == 3) ? "\n" : ""); 363 } 364 printf("\t%-24s:\n", "PIP_TAG_INC[0-63]"); 365 for (i = 0; i < 64; i++) { 366 tmp = _PIP_RD8(sc, PIP_TAG_INC0_OFFSET + sizeof(uint64_t) * i); 367 snprintf(buf, sizeof(buf), "%16" PRIx64, tmp); 368 printf("%s\t%s%s", 369 ((i % 4) == 0) ? "\t" : "", 370 buf, 371 ((i % 4) == 3) ? "\n" : ""); 372 } 373 _PIP_WR8(sc, PIP_STAT_CTL_OFFSET, pip_stat_ctl); 374 } 375 376 void 377 octeon_pip_int_enable(struct octeon_pip_softc *sc, int enable) 378 { 379 uint64_t pip_int_xxx = 0; 380 381 SET(pip_int_xxx, 382 PIP_INT_EN_BEPERR | 383 PIP_INT_EN_FEPERR | 384 PIP_INT_EN_SKPRUNT | 385 PIP_INT_EN_BADTAG | 386 PIP_INT_EN_PRTNXA | 387 PIP_INT_EN_PKTDRP); 388 _PIP_WR8(sc, PIP_INT_REG_OFFSET, pip_int_xxx); 389 _PIP_WR8(sc, PIP_INT_EN_OFFSET, enable ? pip_int_xxx : 0); 390 } 391 uint64_t 392 octeon_pip_int_summary(struct octeon_pip_softc *sc) 393 { 394 uint64_t summary; 395 396 summary = _PIP_RD8(sc, PIP_INT_REG_OFFSET); 397 _PIP_WR8(sc, PIP_INT_REG_OFFSET, summary); 398 return summary; 399 } 400 #endif /* OCTEON_ETH_DEBUG */ 401