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