xref: /openbsd-src/sys/arch/octeon/dev/cn30xxipd.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
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