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