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