1 /* $NetBSD: octeon_pip.c,v 1.14 2021/12/05 03:12:14 msaitoh 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.14 2021/12/05 03:12:14 msaitoh Exp $"); 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/kmem.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 struct device_compatible_entry compat_data[] = { 62 { .compat = "cavium,octeon-3860-pip" }, 63 DEVICE_COMPAT_EOL 64 }; 65 66 static const struct device_compatible_entry pip_compat_data[] = { 67 { .compat = "cavium,octeon-3860-pip-interface" }, 68 DEVICE_COMPAT_EOL 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 multiple 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, CFARGS_NONE); 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_compatible_match(faa->faa_phandle, compat_data); 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_compatible_match(child, pip_compat_data)) 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, CFARGS_NONE); 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 = kmem_zalloc(sizeof(*sc), KM_SLEEP); 181 sc->sc_port = aa->aa_port; 182 sc->sc_regt = aa->aa_regt; 183 sc->sc_tag_type = aa->aa_tag_type; 184 sc->sc_receive_group = aa->aa_receive_group; 185 sc->sc_ip_offset = aa->aa_ip_offset; 186 187 status = bus_space_map(sc->sc_regt, PIP_BASE, PIP_SIZE, 0, 188 &sc->sc_regh); 189 if (status != 0) 190 panic("can't map %s space", "pip register"); 191 192 *rsc = sc; 193 } 194 195 #define _PIP_RD8(sc, off) \ 196 bus_space_read_8((sc)->sc_regt, (sc)->sc_regh, (off)) 197 #define _PIP_WR8(sc, off, v) \ 198 bus_space_write_8((sc)->sc_regt, (sc)->sc_regh, (off), (v)) 199 200 int 201 octpip_port_config(struct octpip_softc *sc) 202 { 203 uint64_t prt_cfg; 204 uint64_t prt_tag; 205 uint64_t ip_offset; 206 207 /* 208 * Process the headers and place the IP header in the work queue 209 */ 210 prt_cfg = 0; 211 if (MIPS_PRID_IMPL(mips_options.mips_cpu_id) == MIPS_CN50XX) { 212 SET(prt_cfg, PIP_PRT_CFGN_LENERR_EN); 213 SET(prt_cfg, PIP_PRT_CFGN_MAXERR_EN); 214 SET(prt_cfg, PIP_PRT_CFGN_MINERR_EN); 215 } 216 /* RAWDRP=0; don't allow raw packet drop */ 217 /* TAGINC=0 */ 218 /* DYN_RS=0; disable dynamic short buffering */ 219 /* INST_HDR=0 */ 220 /* GRP_WAT=0 */ 221 SET(prt_cfg, __SHIFTIN(sc->sc_port, PIP_PRT_CFGN_QOS)); 222 /* QOS_WAT=0 */ 223 /* SPARE=0 */ 224 /* QOS_DIFF=0 */ 225 /* QOS_VLAN=0 */ 226 SET(prt_cfg, PIP_PRT_CFGN_CRC_EN); 227 /* SKIP=0 */ 228 229 prt_tag = 0; 230 SET(prt_tag, PIP_PRT_TAGN_INC_PRT); 231 CLR(prt_tag, PIP_PRT_TAGN_IP6_DPRT); 232 CLR(prt_tag, PIP_PRT_TAGN_IP4_DPRT); 233 CLR(prt_tag, PIP_PRT_TAGN_IP6_SPRT); 234 CLR(prt_tag, PIP_PRT_TAGN_IP4_SPRT); 235 CLR(prt_tag, PIP_PRT_TAGN_IP6_NXTH); 236 CLR(prt_tag, PIP_PRT_TAGN_IP4_PCTL); 237 CLR(prt_tag, PIP_PRT_TAGN_IP6_DST); 238 CLR(prt_tag, PIP_PRT_TAGN_IP4_SRC); 239 CLR(prt_tag, PIP_PRT_TAGN_IP6_SRC); 240 CLR(prt_tag, PIP_PRT_TAGN_IP4_DST); 241 SET(prt_tag, __SHIFTIN(PIP_PRT_TAGN_TCP6_TAG_ORDERED, PIP_PRT_TAGN_TCP6_TAG)); 242 SET(prt_tag, __SHIFTIN(PIP_PRT_TAGN_TCP4_TAG_ORDERED, PIP_PRT_TAGN_TCP4_TAG)); 243 SET(prt_tag, __SHIFTIN(PIP_PRT_TAGN_IP6_TAG_ORDERED, PIP_PRT_TAGN_IP6_TAG)); 244 SET(prt_tag, __SHIFTIN(PIP_PRT_TAGN_IP4_TAG_ORDERED, PIP_PRT_TAGN_IP4_TAG)); 245 SET(prt_tag, __SHIFTIN(PIP_PRT_TAGN_NON_TAG_ORDERED, PIP_PRT_TAGN_NON_TAG)); 246 SET(prt_tag, sc->sc_receive_group & PIP_PRT_TAGN_GRP); 247 248 ip_offset = 0; 249 SET(ip_offset, (sc->sc_ip_offset / 8) & PIP_IP_OFFSET_MASK_OFFSET); 250 251 _PIP_WR8(sc, PIP_PRT_CFG0_OFFSET + (8 * sc->sc_port), prt_cfg); 252 _PIP_WR8(sc, PIP_PRT_TAG0_OFFSET + (8 * sc->sc_port), prt_tag); 253 _PIP_WR8(sc, PIP_IP_OFFSET_OFFSET, ip_offset); 254 255 return 0; 256 } 257 258 void 259 octpip_prt_cfg_enable(struct octpip_softc *sc, uint64_t prt_cfg, int enable) 260 { 261 uint64_t tmp; 262 263 tmp = _PIP_RD8(sc, PIP_PRT_CFG0_OFFSET + (8 * sc->sc_port)); 264 if (enable) 265 tmp |= prt_cfg; 266 else 267 tmp &= ~prt_cfg; 268 _PIP_WR8(sc, PIP_PRT_CFG0_OFFSET + (8 * sc->sc_port), tmp); 269 } 270 271 void 272 octpip_stats(struct octpip_softc *sc, struct ifnet *ifp, int gmx_port) 273 { 274 uint64_t tmp, pkts; 275 uint64_t pip_stat_ctl; 276 277 if (sc == NULL || ifp == NULL) 278 panic("%s: invalid argument. sc=%p, ifp=%p\n", __func__, 279 sc, ifp); 280 281 if (gmx_port < 0 || gmx_port > GMX_PORT_NUNITS) { 282 printf("%s: invalid gmx_port %d\n", __func__, gmx_port); 283 return; 284 } 285 286 pip_stat_ctl = _PIP_RD8(sc, PIP_STAT_CTL_OFFSET); 287 _PIP_WR8(sc, PIP_STAT_CTL_OFFSET, pip_stat_ctl | PIP_STAT_CTL_RDCLR); 288 tmp = _PIP_RD8(sc, PIP_STAT0_PRT_OFFSET(gmx_port)); 289 pkts = __SHIFTOUT(tmp, PIP_STAT0_PRTN_DRP_PKTS); 290 if_statadd(ifp, if_iqdrops, pkts); 291 292 _PIP_WR8(sc, PIP_STAT_CTL_OFFSET, pip_stat_ctl); 293 } 294