1 /* $OpenBSD: cn30xxpip.c,v 1.6 2016/06/09 15:29:22 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/malloc.h> 32 #include <sys/socket.h> 33 #include <sys/syslog.h> 34 #include <sys/time.h> 35 #include <net/if.h> 36 #include <net/if_var.h> 37 38 #include <machine/octeonvar.h> 39 40 #include <octeon/dev/cn30xxgmxreg.h> 41 #include <octeon/dev/cn30xxpipreg.h> 42 #include <octeon/dev/cn30xxpipvar.h> 43 44 #ifdef OCTEON_ETH_DEBUG 45 struct cn30xxpip_softc *__cn30xxpip_softc; 46 47 void cn30xxpip_intr_rml(void *); 48 49 void cn30xxpip_dump(void); 50 void cn30xxpip_int_enable(struct cn30xxpip_softc *, int); 51 #endif 52 53 /* 54 * register definitions 55 */ 56 #define _ENTRY(x) { #x, x##_OFFSET } 57 #define _ENTRY_0_3(x) \ 58 _ENTRY(x## 0), _ENTRY(x## 1), _ENTRY(x## 2), _ENTRY(x## 3) 59 #define _ENTRY_0_7(x) \ 60 _ENTRY(x## 0), _ENTRY(x## 1), _ENTRY(x## 2), _ENTRY(x## 3), \ 61 _ENTRY(x## 4), _ENTRY(x## 5), _ENTRY(x## 6), _ENTRY(x## 7) 62 #define _ENTRY_0_1_2_32(x) \ 63 _ENTRY(x## 0), _ENTRY(x## 1), _ENTRY(x## 2), _ENTRY(x##32) 64 65 struct cn30xxpip_dump_reg_ { 66 const char *name; 67 size_t offset; 68 }; 69 70 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 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_softc = sc; 139 printf("PIP Code initialized.\n"); 140 #endif 141 } 142 143 #define _PIP_RD8(sc, off) \ 144 bus_space_read_8((sc)->sc_regt, (sc)->sc_regh, (off)) 145 #define _PIP_WR8(sc, off, v) \ 146 bus_space_write_8((sc)->sc_regt, (sc)->sc_regh, (off), (v)) 147 148 int 149 cn30xxpip_port_config(struct cn30xxpip_softc *sc) 150 { 151 uint64_t prt_cfg; 152 uint64_t prt_tag; 153 uint64_t ip_offset; 154 155 /* 156 * Process the headers and place the IP header in the work queue 157 */ 158 prt_cfg = 0; 159 /* RAWDRP=0; don't allow raw packet drop */ 160 /* TAGINC=0 */ 161 /* DYN_RS=0; disable dynamic short buffering */ 162 /* INST_HDR=0 */ 163 /* GRP_WAT=0 */ 164 SET(prt_cfg, (sc->sc_port << 24) & PIP_PRT_CFGN_QOS); 165 /* QOS_WAT=0 */ 166 /* SPARE=0 */ 167 /* QOS_DIFF=0 */ 168 /* QOS_VLAN=0 */ 169 SET(prt_cfg, PIP_PRT_CFGN_CRC_EN); 170 SET(prt_cfg, (PIP_PORT_CFG_MODE_L2) & PIP_PRT_CFGN_MODE); 171 /* SKIP=0 */ 172 173 prt_tag = 0; 174 SET(prt_tag, PIP_PRT_TAGN_INC_PRT); 175 CLR(prt_tag, PIP_PRT_TAGN_IP6_DPRT); 176 CLR(prt_tag, PIP_PRT_TAGN_IP4_DPRT); 177 CLR(prt_tag, PIP_PRT_TAGN_IP6_SPRT); 178 CLR(prt_tag, PIP_PRT_TAGN_IP4_SPRT); 179 CLR(prt_tag, PIP_PRT_TAGN_IP6_NXTH); 180 CLR(prt_tag, PIP_PRT_TAGN_IP4_PCTL); 181 CLR(prt_tag, PIP_PRT_TAGN_IP6_DST); 182 CLR(prt_tag, PIP_PRT_TAGN_IP4_SRC); 183 CLR(prt_tag, PIP_PRT_TAGN_IP6_SRC); 184 CLR(prt_tag, PIP_PRT_TAGN_IP4_DST); 185 SET(prt_tag, PIP_PRT_TAGN_TCP6_TAG_ORDERED); 186 SET(prt_tag, PIP_PRT_TAGN_TCP4_TAG_ORDERED); 187 SET(prt_tag, PIP_PRT_TAGN_IP6_TAG_ORDERED); 188 SET(prt_tag, PIP_PRT_TAGN_IP4_TAG_ORDERED); 189 SET(prt_tag, PIP_PRT_TAGN_NON_TAG_ORDERED); 190 SET(prt_tag, sc->sc_receive_group & PIP_PRT_TAGN_GRP); 191 192 ip_offset = 0; 193 SET(ip_offset, (sc->sc_ip_offset / 8) & PIP_IP_OFFSET_MASK_OFFSET); 194 195 _PIP_WR8(sc, PIP_PRT_CFG0_OFFSET + (8 * sc->sc_port), prt_cfg); 196 _PIP_WR8(sc, PIP_PRT_TAG0_OFFSET + (8 * sc->sc_port), prt_tag); 197 _PIP_WR8(sc, PIP_IP_OFFSET_OFFSET, ip_offset); 198 199 return 0; 200 } 201 202 void 203 cn30xxpip_prt_cfg_enable(struct cn30xxpip_softc *sc, uint64_t prt_cfg, 204 int enable) 205 { 206 uint64_t tmp; 207 208 tmp = _PIP_RD8(sc, PIP_PRT_CFG0_OFFSET + (8 * sc->sc_port)); 209 if (enable) 210 tmp |= prt_cfg; 211 else 212 tmp &= ~prt_cfg; 213 _PIP_WR8(sc, PIP_PRT_CFG0_OFFSET + (8 * sc->sc_port), tmp); 214 } 215 216 void 217 cn30xxpip_stats(struct cn30xxpip_softc *sc, struct ifnet *ifp, int gmx_port) 218 { 219 const struct cn30xxpip_dump_reg_ *reg; 220 uint64_t tmp, pkts, octs; 221 uint64_t pip_stat_ctl; 222 223 if (sc == NULL || ifp == NULL) 224 panic("%s: invalid argument. sc=%p, ifp=%p\n", __func__, 225 sc, ifp); 226 227 if (gmx_port < 0 || gmx_port >= GMX_PORT_NUNITS) { 228 printf("%s: invalid gmx_port %d\n", __func__, gmx_port); 229 return; 230 } 231 232 pip_stat_ctl = _PIP_RD8(sc, PIP_STAT_CTL_OFFSET); 233 _PIP_WR8(sc, PIP_STAT_CTL_OFFSET, pip_stat_ctl | PIP_STAT_CTL_RDCLR); 234 reg = &cn30xxpip_dump_stats_[gmx_port]; 235 tmp = _PIP_RD8(sc, reg->offset); 236 octs = (tmp & 0x00000000ffffffffULL); /* XXX: no counter in ifp?? */ 237 pkts = (tmp & 0xffffffff00000000ULL) >> 32; 238 ifp->if_iqdrops += pkts; 239 240 _PIP_WR8(sc, PIP_STAT_CTL_OFFSET, pip_stat_ctl); 241 } 242 243 244 #ifdef OCTEON_ETH_DEBUG 245 int cn30xxpip_intr_rml_verbose; 246 247 void 248 cn30xxpip_intr_rml(void *arg) 249 { 250 struct cn30xxpip_softc *sc; 251 uint64_t reg; 252 253 sc = __cn30xxpip_softc; 254 KASSERT(sc != NULL); 255 reg = cn30xxpip_int_summary(sc); 256 if (cn30xxpip_intr_rml_verbose) 257 printf("%s: PIP_INT_REG=0x%016llx\n", __func__, reg); 258 } 259 260 void cn30xxpip_dump_regs(void); 261 void cn30xxpip_dump_stats(void); 262 263 void 264 cn30xxpip_dump(void) 265 { 266 cn30xxpip_dump_regs(); 267 cn30xxpip_dump_stats(); 268 } 269 270 void 271 cn30xxpip_dump_regs(void) 272 { 273 struct cn30xxpip_softc *sc = __cn30xxpip_softc; 274 const struct cn30xxpip_dump_reg_ *reg; 275 uint64_t tmp; 276 int i; 277 278 for (i = 0; i < (int)nitems(cn30xxpip_dump_regs_); i++) { 279 reg = &cn30xxpip_dump_regs_[i]; 280 tmp = _PIP_RD8(sc, reg->offset); 281 printf("\t%-24s: %16llx\n", reg->name, tmp); 282 } 283 } 284 285 void 286 cn30xxpip_dump_stats(void) 287 { 288 struct cn30xxpip_softc *sc = __cn30xxpip_softc; 289 const struct cn30xxpip_dump_reg_ *reg; 290 uint64_t tmp; 291 int i; 292 uint64_t pip_stat_ctl; 293 294 pip_stat_ctl = _PIP_RD8(sc, PIP_STAT_CTL_OFFSET); 295 _PIP_WR8(sc, PIP_STAT_CTL_OFFSET, pip_stat_ctl & ~PIP_STAT_CTL_RDCLR); 296 for (i = 0; i < (int)nitems(cn30xxpip_dump_stats_); i++) { 297 reg = &cn30xxpip_dump_stats_[i]; 298 tmp = _PIP_RD8(sc, reg->offset); 299 printf("\t%-24s: %16llx\n", reg->name, tmp); 300 } 301 printf("\t%-24s:\n", "PIP_QOS_DIFF[0-63]"); 302 for (i = 0; i < 64; i++) { 303 tmp = _PIP_RD8(sc, PIP_QOS_DIFF0_OFFSET + sizeof(uint64_t) * i); 304 printf("%s\t%16llx%s", 305 ((i % 4) == 0) ? "\t" : "", 306 tmp, 307 ((i % 4) == 3) ? "\n" : ""); 308 } 309 printf("\t%-24s:\n", "PIP_TAG_INC[0-63]"); 310 for (i = 0; i < 64; i++) { 311 tmp = _PIP_RD8(sc, PIP_TAG_INC0_OFFSET + sizeof(uint64_t) * i); 312 printf("%s\t%16llx%s", 313 ((i % 4) == 0) ? "\t" : "", 314 tmp, 315 ((i % 4) == 3) ? "\n" : ""); 316 } 317 _PIP_WR8(sc, PIP_STAT_CTL_OFFSET, pip_stat_ctl); 318 } 319 320 void 321 cn30xxpip_int_enable(struct cn30xxpip_softc *sc, int enable) 322 { 323 uint64_t pip_int_xxx = 0; 324 325 SET(pip_int_xxx, 326 PIP_INT_EN_BEPERR | 327 PIP_INT_EN_FEPERR | 328 PIP_INT_EN_SKPRUNT | 329 PIP_INT_EN_BADTAG | 330 PIP_INT_EN_PRTNXA | 331 PIP_INT_EN_PKTDRP); 332 _PIP_WR8(sc, PIP_INT_REG_OFFSET, pip_int_xxx); 333 _PIP_WR8(sc, PIP_INT_EN_OFFSET, enable ? pip_int_xxx : 0); 334 } 335 uint64_t 336 cn30xxpip_int_summary(struct cn30xxpip_softc *sc) 337 { 338 uint64_t summary; 339 340 summary = _PIP_RD8(sc, PIP_INT_REG_OFFSET); 341 _PIP_WR8(sc, PIP_INT_REG_OFFSET, summary); 342 return summary; 343 } 344 #endif /* OCTEON_ETH_DEBUG */ 345