1 /* $OpenBSD: cn30xxipd.c,v 1.9 2016/06/22 13:09:35 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/mbuf.h> 33 34 #include <machine/octeonvar.h> 35 36 #include <octeon/dev/cn30xxciureg.h> 37 #include <octeon/dev/cn30xxfpavar.h> 38 #include <octeon/dev/cn30xxgmxreg.h> 39 #include <octeon/dev/cn30xxpipreg.h> 40 #include <octeon/dev/cn30xxipdreg.h> 41 #include <octeon/dev/cn30xxipdvar.h> 42 43 #ifdef OCTEON_ETH_DEBUG 44 void cn30xxipd_intr_rml(void *); 45 int cn30xxipd_intr_drop(void *); 46 47 void cn30xxipd_dump(void); 48 49 void *cn30xxipd_intr_drop_ih; 50 51 struct cn30xxipd_softc *__cn30xxipd_softc[GMX_PORT_NUNITS]; 52 #endif 53 54 /* XXX */ 55 void 56 cn30xxipd_init(struct cn30xxipd_attach_args *aa, 57 struct cn30xxipd_softc **rsc) 58 { 59 struct cn30xxipd_softc *sc; 60 int status; 61 62 sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO); 63 if (sc == NULL) 64 panic("can't allocate memory: %s", __func__); 65 66 sc->sc_port = aa->aa_port; 67 sc->sc_regt = aa->aa_regt; 68 sc->sc_first_mbuff_skip = aa->aa_first_mbuff_skip; 69 sc->sc_not_first_mbuff_skip = aa->aa_not_first_mbuff_skip; 70 71 status = bus_space_map(sc->sc_regt, IPD_BASE, IPD_SIZE, 0, 72 &sc->sc_regh); 73 if (status != 0) 74 panic("can't map %s space", "ipd register"); 75 76 *rsc = sc; 77 78 #ifdef OCTEON_ETH_DEBUG 79 cn30xxipd_int_enable(sc, 1); 80 if (cn30xxipd_intr_drop_ih == NULL) 81 cn30xxipd_intr_drop_ih = octeon_intr_establish( 82 ffs64(CIU_INTX_SUM0_IPD_DRP) - 1, IPL_NET, 83 cn30xxipd_intr_drop, NULL, "cn30xxipd"); 84 __cn30xxipd_softc[sc->sc_port] = sc; 85 #endif /* OCTEON_ETH_DEBUG */ 86 } 87 88 #define _IPD_RD8(sc, off) \ 89 bus_space_read_8((sc)->sc_regt, (sc)->sc_regh, (off)) 90 #define _IPD_WR8(sc, off, v) \ 91 bus_space_write_8((sc)->sc_regt, (sc)->sc_regh, (off), (v)) 92 93 int 94 cn30xxipd_enable(struct cn30xxipd_softc *sc) 95 { 96 uint64_t ctl_status; 97 98 ctl_status = _IPD_RD8(sc, IPD_CTL_STATUS_OFFSET); 99 SET(ctl_status, IPD_CTL_STATUS_IPD_EN); 100 _IPD_WR8(sc, IPD_CTL_STATUS_OFFSET, ctl_status); 101 102 return 0; 103 } 104 105 int 106 cn30xxipd_config(struct cn30xxipd_softc *sc) 107 { 108 uint64_t first_mbuff_skip; 109 uint64_t not_first_mbuff_skip; 110 uint64_t packet_mbuff_size; 111 uint64_t first_next_ptr_back; 112 uint64_t second_next_ptr_back; 113 uint64_t sqe_fpa_queue; 114 uint64_t ctl_status; 115 116 /* XXX */ 117 first_mbuff_skip = 0; 118 SET(first_mbuff_skip, (sc->sc_first_mbuff_skip / 8) & IPD_1ST_MBUFF_SKIP_SZ); 119 _IPD_WR8(sc, IPD_1ST_MBUFF_SKIP_OFFSET, first_mbuff_skip); 120 /* XXX */ 121 122 /* XXX */ 123 not_first_mbuff_skip = 0; 124 SET(not_first_mbuff_skip, (sc->sc_not_first_mbuff_skip / 8) & 125 IPD_NOT_1ST_MBUFF_SKIP_SZ); 126 _IPD_WR8(sc, IPD_NOT_1ST_MBUFF_SKIP_OFFSET, not_first_mbuff_skip); 127 /* XXX */ 128 129 packet_mbuff_size = 0; 130 SET(packet_mbuff_size, (OCTEON_POOL_SIZE_PKT / 8) & 131 IPD_PACKET_MBUFF_SIZE_MB_SIZE); 132 _IPD_WR8(sc, IPD_PACKET_MBUFF_SIZE_OFFSET, packet_mbuff_size); 133 134 first_next_ptr_back = 0; 135 SET(first_next_ptr_back, (sc->sc_first_mbuff_skip / 128) & IPD_1ST_NEXT_PTR_BACK_BACK); 136 _IPD_WR8(sc, IPD_1ST_NEXT_PTR_BACK_OFFSET, first_next_ptr_back); 137 138 second_next_ptr_back = 0; 139 SET(second_next_ptr_back, (sc->sc_not_first_mbuff_skip / 128) & 140 IPD_2ND_NEXT_PTR_BACK_BACK); 141 _IPD_WR8(sc, IPD_2ND_NEXT_PTR_BACK_OFFSET, second_next_ptr_back); 142 143 sqe_fpa_queue = 0; 144 SET(sqe_fpa_queue, OCTEON_POOL_NO_WQE & IPD_WQE_FPA_QUEUE_WQE_QUE); 145 _IPD_WR8(sc, IPD_WQE_FPA_QUEUE_OFFSET, sqe_fpa_queue); 146 147 ctl_status = _IPD_RD8(sc, IPD_CTL_STATUS_OFFSET); 148 CLR(ctl_status, IPD_CTL_STATUS_OPC_MODE); 149 SET(ctl_status, IPD_CTL_STATUS_OPC_MODE_ALL); 150 SET(ctl_status, IPD_CTL_STATUS_PBP_EN); 151 152 _IPD_WR8(sc, IPD_CTL_STATUS_OFFSET, ctl_status); 153 154 return 0; 155 } 156 157 /* 158 * octeon work queue entry offload 159 * L3 error & L4 error 160 */ 161 void 162 cn30xxipd_offload(uint64_t word2, uint16_t *rcflags) 163 { 164 int cflags; 165 166 /* Skip if the packet is non-IP. */ 167 if (ISSET(word2, PIP_WQE_WORD2_IP_NI)) 168 return; 169 170 cflags = 0; 171 172 /* Check IP checksum status. */ 173 if (!ISSET(word2, PIP_WQE_WORD2_IP_V6) && 174 !ISSET(word2, PIP_WQE_WORD2_IP_IE)) 175 SET(cflags, M_IPV4_CSUM_IN_OK); 176 177 /* Check TCP/UDP checksum status. Skip if the packet is a fragment. */ 178 if (ISSET(word2, PIP_WQE_WORD2_IP_TU) && 179 !ISSET(word2, PIP_WQE_WORD2_IP_FR) && 180 !ISSET(word2, PIP_WQE_WORD2_IP_LE)) 181 SET(cflags, M_TCP_CSUM_IN_OK | M_UDP_CSUM_IN_OK); 182 183 *rcflags = cflags; 184 } 185 186 void 187 cn30xxipd_sub_port_fcs(struct cn30xxipd_softc *sc, int enable) 188 { 189 uint64_t sub_port_fcs; 190 191 sub_port_fcs = _IPD_RD8(sc, IPD_SUB_PORT_FCS_OFFSET); 192 if (enable == 0) 193 CLR(sub_port_fcs, 1 << sc->sc_port); 194 else 195 SET(sub_port_fcs, 1 << sc->sc_port); 196 _IPD_WR8(sc, IPD_SUB_PORT_FCS_OFFSET, sub_port_fcs); 197 } 198 199 #ifdef OCTEON_ETH_DEBUG 200 int cn30xxipd_intr_rml_verbose; 201 202 void 203 cn30xxipd_intr_rml(void *arg) 204 { 205 int i; 206 207 for (i = 0; i < 3/* XXX */; i++) { 208 struct cn30xxipd_softc *sc; 209 uint64_t reg; 210 211 sc = __cn30xxipd_softc[i]; 212 KASSERT(sc != NULL); 213 reg = cn30xxipd_int_summary(sc); 214 if (cn30xxipd_intr_rml_verbose) 215 printf("%s: IPD_INT_SUM=0x%016llx\n", __func__, reg); 216 } 217 } 218 219 void 220 cn30xxipd_int_enable(struct cn30xxipd_softc *sc, int enable) 221 { 222 uint64_t ipd_int_xxx = 0; 223 224 SET(ipd_int_xxx, 225 IPD_INT_SUM_BP_SUB | 226 IPD_INT_SUM_PRC_PAR3 | 227 IPD_INT_SUM_PRC_PAR2 | 228 IPD_INT_SUM_PRC_PAR1 | 229 IPD_INT_SUM_PRC_PAR0); 230 _IPD_WR8(sc, IPD_INT_SUM_OFFSET, ipd_int_xxx); 231 _IPD_WR8(sc, IPD_INT_ENB_OFFSET, enable ? ipd_int_xxx : 0); 232 } 233 234 uint64_t 235 cn30xxipd_int_summary(struct cn30xxipd_softc *sc) 236 { 237 uint64_t summary; 238 239 summary = _IPD_RD8(sc, IPD_INT_SUM_OFFSET); 240 _IPD_WR8(sc, IPD_INT_SUM_OFFSET, summary); 241 return summary; 242 } 243 244 int 245 cn30xxipd_intr_drop(void *arg) 246 { 247 octeon_xkphys_write_8(CIU_INT0_SUM0, CIU_INTX_SUM0_IPD_DRP); 248 return (1); 249 } 250 251 #define _ENTRY(x) { #x, x##_OFFSET } 252 253 struct cn30xxipd_dump_reg { 254 const char *name; 255 size_t offset; 256 }; 257 258 const struct cn30xxipd_dump_reg cn30xxipd_dump_regs[] = { 259 _ENTRY(IPD_1ST_MBUFF_SKIP), 260 _ENTRY(IPD_NOT_1ST_MBUFF_SKIP), 261 _ENTRY(IPD_PACKET_MBUFF_SIZE), 262 _ENTRY(IPD_CTL_STATUS), 263 _ENTRY(IPD_WQE_FPA_QUEUE), 264 _ENTRY(IPD_PORT0_BP_PAGE_CNT), 265 _ENTRY(IPD_PORT1_BP_PAGE_CNT), 266 _ENTRY(IPD_PORT2_BP_PAGE_CNT), 267 _ENTRY(IPD_PORT32_BP_PAGE_CNT), 268 _ENTRY(IPD_SUB_PORT_BP_PAGE_CNT), 269 _ENTRY(IPD_1ST_NEXT_PTR_BACK), 270 _ENTRY(IPD_2ND_NEXT_PTR_BACK), 271 _ENTRY(IPD_INT_ENB), 272 _ENTRY(IPD_INT_SUM), 273 _ENTRY(IPD_SUB_PORT_FCS), 274 _ENTRY(IPD_QOS0_RED_MARKS), 275 _ENTRY(IPD_QOS1_RED_MARKS), 276 _ENTRY(IPD_QOS2_RED_MARKS), 277 _ENTRY(IPD_QOS3_RED_MARKS), 278 _ENTRY(IPD_QOS4_RED_MARKS), 279 _ENTRY(IPD_QOS5_RED_MARKS), 280 _ENTRY(IPD_QOS6_RED_MARKS), 281 _ENTRY(IPD_QOS7_RED_MARKS), 282 _ENTRY(IPD_PORT_BP_COUNTERS_PAIR0), 283 _ENTRY(IPD_PORT_BP_COUNTERS_PAIR1), 284 _ENTRY(IPD_PORT_BP_COUNTERS_PAIR2), 285 _ENTRY(IPD_PORT_BP_COUNTERS_PAIR32), 286 _ENTRY(IPD_RED_PORT_ENABLE), 287 _ENTRY(IPD_RED_QUE0_PARAM), 288 _ENTRY(IPD_RED_QUE1_PARAM), 289 _ENTRY(IPD_RED_QUE2_PARAM), 290 _ENTRY(IPD_RED_QUE3_PARAM), 291 _ENTRY(IPD_RED_QUE4_PARAM), 292 _ENTRY(IPD_RED_QUE5_PARAM), 293 _ENTRY(IPD_RED_QUE6_PARAM), 294 _ENTRY(IPD_RED_QUE7_PARAM), 295 _ENTRY(IPD_PTR_COUNT), 296 _ENTRY(IPD_BP_PRT_RED_END), 297 _ENTRY(IPD_QUE0_FREE_PAGE_CNT), 298 _ENTRY(IPD_CLK_COUNT), 299 _ENTRY(IPD_PWP_PTR_FIFO_CTL), 300 _ENTRY(IPD_PRC_HOLD_PTR_FIFO_CTL), 301 _ENTRY(IPD_PRC_PORT_PTR_FIFO_CTL), 302 _ENTRY(IPD_PKT_PTR_VALID), 303 _ENTRY(IPD_WQE_PTR_VALID), 304 _ENTRY(IPD_BIST_STATUS), 305 }; 306 307 void 308 cn30xxipd_dump(void) 309 { 310 struct cn30xxipd_softc *sc; 311 const struct cn30xxipd_dump_reg *reg; 312 uint64_t tmp; 313 int i; 314 315 sc = __cn30xxipd_softc[0]; 316 for (i = 0; i < (int)nitems(cn30xxipd_dump_regs); i++) { 317 reg = &cn30xxipd_dump_regs[i]; 318 tmp = _IPD_RD8(sc, reg->offset); 319 printf("%-32s: %16llx\n", reg->name, tmp); 320 } 321 } 322 #endif /* OCTEON_ETH_DEBUG */ 323