1 /* $NetBSD: octeon_pip.c,v 1.9 2020/07/16 11:49:37 jmcneill 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.9 2020/07/16 11:49:37 jmcneill Exp $"); 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/malloc.h> 35 #include <sys/syslog.h> 36 #include <sys/time.h> 37 #include <net/if.h> 38 39 #include <mips/locore.h> 40 41 #include <mips/cavium/octeonvar.h> 42 #include <mips/cavium/dev/octeon_gmxreg.h> 43 #include <mips/cavium/dev/octeon_pipreg.h> 44 #include <mips/cavium/dev/octeon_pipvar.h> 45 #include <mips/cavium/include/iobusvar.h> 46 47 #include <dev/fdt/fdtvar.h> 48 49 static int octpip_iobus_match(device_t, struct cfdata *, void *); 50 static void octpip_iobus_attach(device_t, device_t, void *); 51 52 static int octpip_fdt_match(device_t, struct cfdata *, void *); 53 static void octpip_fdt_attach(device_t, device_t, void *); 54 55 CFATTACH_DECL_NEW(octpip_iobus, sizeof(struct octpip_softc), 56 octpip_iobus_match, octpip_iobus_attach, NULL, NULL); 57 58 CFATTACH_DECL_NEW(octpip_fdt, sizeof(struct octpip_softc), 59 octpip_fdt_match, octpip_fdt_attach, NULL, NULL); 60 61 static const char * compatible[] = { 62 "cavium,octeon-3860-pip", 63 NULL 64 }; 65 66 static const char * pip_interface_compatible[] = { 67 "cavium,octeon-3860-pip-interface", 68 NULL 69 }; 70 71 static int 72 octpip_iobus_match(device_t parent, struct cfdata *cf, void *aux) 73 { 74 struct iobus_attach_args *aa = aux; 75 76 if (strcmp(cf->cf_name, aa->aa_name) != 0) 77 return 0; 78 return 1; 79 } 80 81 static void 82 octpip_iobus_attach(device_t parent, device_t self, void *aux) 83 { 84 struct octpip_softc *sc = device_private(self); 85 struct iobus_attach_args *aa = aux; 86 struct iobus_attach_args gmxaa; 87 struct iobus_unit gmxiu; 88 int i, ndevs; 89 90 sc->sc_dev = self; 91 92 aprint_normal("\n"); 93 94 /* 95 * XXX: In a non-FDT world, should allow for the configuration 96 * of multple GMX devices. 97 */ 98 ndevs = 1; 99 100 for (i = 0; i < ndevs; i++) { 101 memcpy(&gmxaa, aa, sizeof(gmxaa)); 102 memset(&gmxiu, 0, sizeof(gmxiu)); 103 104 gmxaa.aa_name = "octgmx"; 105 gmxaa.aa_unitno = i; 106 gmxaa.aa_unit = &gmxiu; 107 gmxaa.aa_bust = aa->aa_bust; 108 gmxaa.aa_dmat = aa->aa_dmat; 109 110 if (MIPS_PRID_IMPL(mips_options.mips_cpu_id) == MIPS_CN68XX) 111 gmxiu.addr = GMX_CN68XX_BASE_PORT(i, 0); 112 else 113 gmxiu.addr = GMX_BASE_PORT(i, 0); 114 115 config_found(self, &gmxaa, NULL); 116 } 117 } 118 119 static int 120 octpip_fdt_match(device_t parent, struct cfdata *cf, void *aux) 121 { 122 struct fdt_attach_args * const faa = aux; 123 124 return of_match_compatible(faa->faa_phandle, compatible); 125 } 126 127 static void 128 octpip_fdt_attach(device_t parent, device_t self, void *aux) 129 { 130 struct octpip_softc *sc = device_private(self); 131 struct fdt_attach_args * const faa = aux; 132 const int phandle = faa->faa_phandle; 133 struct iobus_attach_args gmxaa; 134 struct iobus_unit gmxiu; 135 bus_addr_t intno; 136 int child; 137 138 sc->sc_dev = self; 139 140 aprint_normal("\n"); 141 142 for (child = OF_child(phandle); child; child = OF_peer(child)) { 143 if (!of_match_compatible(child, pip_interface_compatible)) 144 continue; 145 146 if (fdtbus_get_reg(child, 0, &intno, NULL) != 0) { 147 aprint_error_dev(self, "couldn't get interface number for %s\n", 148 fdtbus_get_string(child, "name")); 149 continue; 150 } 151 152 memset(&gmxaa, 0, sizeof(gmxaa)); 153 memset(&gmxiu, 0, sizeof(gmxiu)); 154 155 gmxaa.aa_name = "octgmx"; 156 gmxaa.aa_unitno = (int)intno; 157 gmxaa.aa_unit = &gmxiu; 158 gmxaa.aa_bust = faa->faa_bst; 159 gmxaa.aa_dmat = faa->faa_dmat; 160 161 if (MIPS_PRID_IMPL(mips_options.mips_cpu_id) == MIPS_CN68XX) 162 gmxiu.addr = GMX_CN68XX_BASE_PORT(intno, 0); 163 else 164 gmxiu.addr = GMX_BASE_PORT(intno, 0); 165 166 config_found(self, &gmxaa, NULL); 167 168 /* XXX only one interface supported by octgmx */ 169 return; 170 } 171 } 172 173 /* XXX */ 174 void 175 octpip_init(struct octpip_attach_args *aa, struct octpip_softc **rsc) 176 { 177 struct octpip_softc *sc; 178 int status; 179 180 sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO); 181 if (sc == NULL) 182 panic("can't allocate memory: %s", __func__); 183 184 sc->sc_port = aa->aa_port; 185 sc->sc_regt = aa->aa_regt; 186 sc->sc_tag_type = aa->aa_tag_type; 187 sc->sc_receive_group = aa->aa_receive_group; 188 sc->sc_ip_offset = aa->aa_ip_offset; 189 190 status = bus_space_map(sc->sc_regt, PIP_BASE, PIP_SIZE, 0, 191 &sc->sc_regh); 192 if (status != 0) 193 panic("can't map %s space", "pip register"); 194 195 *rsc = sc; 196 } 197 198 #define _PIP_RD8(sc, off) \ 199 bus_space_read_8((sc)->sc_regt, (sc)->sc_regh, (off)) 200 #define _PIP_WR8(sc, off, v) \ 201 bus_space_write_8((sc)->sc_regt, (sc)->sc_regh, (off), (v)) 202 203 int 204 octpip_port_config(struct octpip_softc *sc) 205 { 206 uint64_t prt_cfg; 207 uint64_t prt_tag; 208 uint64_t ip_offset; 209 210 /* 211 * Process the headers and place the IP header in the work queue 212 */ 213 prt_cfg = 0; 214 if (MIPS_PRID_IMPL(mips_options.mips_cpu_id) == MIPS_CN50XX) { 215 SET(prt_cfg, PIP_PRT_CFGN_LENERR_EN); 216 SET(prt_cfg, PIP_PRT_CFGN_MAXERR_EN); 217 SET(prt_cfg, PIP_PRT_CFGN_MINERR_EN); 218 } 219 /* RAWDRP=0; don't allow raw packet drop */ 220 /* TAGINC=0 */ 221 /* DYN_RS=0; disable dynamic short buffering */ 222 /* INST_HDR=0 */ 223 /* GRP_WAT=0 */ 224 SET(prt_cfg, __SHIFTIN(sc->sc_port, PIP_PRT_CFGN_QOS)); 225 /* QOS_WAT=0 */ 226 /* SPARE=0 */ 227 /* QOS_DIFF=0 */ 228 /* QOS_VLAN=0 */ 229 SET(prt_cfg, PIP_PRT_CFGN_CRC_EN); 230 /* SKIP=0 */ 231 232 prt_tag = 0; 233 SET(prt_tag, PIP_PRT_TAGN_INC_PRT); 234 CLR(prt_tag, PIP_PRT_TAGN_IP6_DPRT); 235 CLR(prt_tag, PIP_PRT_TAGN_IP4_DPRT); 236 CLR(prt_tag, PIP_PRT_TAGN_IP6_SPRT); 237 CLR(prt_tag, PIP_PRT_TAGN_IP4_SPRT); 238 CLR(prt_tag, PIP_PRT_TAGN_IP6_NXTH); 239 CLR(prt_tag, PIP_PRT_TAGN_IP4_PCTL); 240 CLR(prt_tag, PIP_PRT_TAGN_IP6_DST); 241 CLR(prt_tag, PIP_PRT_TAGN_IP4_SRC); 242 CLR(prt_tag, PIP_PRT_TAGN_IP6_SRC); 243 CLR(prt_tag, PIP_PRT_TAGN_IP4_DST); 244 SET(prt_tag, __SHIFTIN(PIP_PRT_TAGN_TCP6_TAG_ORDERED, PIP_PRT_TAGN_TCP6_TAG)); 245 SET(prt_tag, __SHIFTIN(PIP_PRT_TAGN_TCP4_TAG_ORDERED, PIP_PRT_TAGN_TCP4_TAG)); 246 SET(prt_tag, __SHIFTIN(PIP_PRT_TAGN_IP6_TAG_ORDERED, PIP_PRT_TAGN_IP6_TAG)); 247 SET(prt_tag, __SHIFTIN(PIP_PRT_TAGN_IP4_TAG_ORDERED, PIP_PRT_TAGN_IP4_TAG)); 248 SET(prt_tag, __SHIFTIN(PIP_PRT_TAGN_NON_TAG_ORDERED, PIP_PRT_TAGN_NON_TAG)); 249 SET(prt_tag, sc->sc_receive_group & PIP_PRT_TAGN_GRP); 250 251 ip_offset = 0; 252 SET(ip_offset, (sc->sc_ip_offset / 8) & PIP_IP_OFFSET_MASK_OFFSET); 253 254 _PIP_WR8(sc, PIP_PRT_CFG0_OFFSET + (8 * sc->sc_port), prt_cfg); 255 _PIP_WR8(sc, PIP_PRT_TAG0_OFFSET + (8 * sc->sc_port), prt_tag); 256 _PIP_WR8(sc, PIP_IP_OFFSET_OFFSET, ip_offset); 257 258 return 0; 259 } 260 261 void 262 octpip_prt_cfg_enable(struct octpip_softc *sc, uint64_t prt_cfg, int enable) 263 { 264 uint64_t tmp; 265 266 tmp = _PIP_RD8(sc, PIP_PRT_CFG0_OFFSET + (8 * sc->sc_port)); 267 if (enable) 268 tmp |= prt_cfg; 269 else 270 tmp &= ~prt_cfg; 271 _PIP_WR8(sc, PIP_PRT_CFG0_OFFSET + (8 * sc->sc_port), tmp); 272 } 273 274 void 275 octpip_stats(struct octpip_softc *sc, struct ifnet *ifp, int gmx_port) 276 { 277 uint64_t tmp, pkts; 278 uint64_t pip_stat_ctl; 279 280 if (sc == NULL || ifp == NULL) 281 panic("%s: invalid argument. sc=%p, ifp=%p\n", __func__, 282 sc, ifp); 283 284 if (gmx_port < 0 || gmx_port > GMX_PORT_NUNITS) { 285 printf("%s: invalid gmx_port %d\n", __func__, gmx_port); 286 return; 287 } 288 289 pip_stat_ctl = _PIP_RD8(sc, PIP_STAT_CTL_OFFSET); 290 _PIP_WR8(sc, PIP_STAT_CTL_OFFSET, pip_stat_ctl | PIP_STAT_CTL_RDCLR); 291 tmp = _PIP_RD8(sc, PIP_STAT0_PRT_OFFSET(gmx_port)); 292 pkts = __SHIFTOUT(tmp, PIP_STAT0_PRTN_DRP_PKTS); 293 if_statadd(ifp, if_iqdrops, pkts); 294 295 _PIP_WR8(sc, PIP_STAT_CTL_OFFSET, pip_stat_ctl); 296 } 297