xref: /netbsd-src/sys/arch/mips/cavium/dev/octeon_powvar.h (revision 7cfbdc5be92d87a593315a9b8f4d90200afdf934)
1 /*	$NetBSD: octeon_powvar.h,v 1.7 2020/06/23 05:15:33 simonb 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 #ifndef _OCTEON_POWVAR_H_
30 #define _OCTEON_POWVAR_H_
31 
32 #include <sys/cpu.h>
33 
34 #include <mips/cavium/octeonreg.h>
35 
36 #define POW_TAG_TYPE_ORDERED	0
37 #define POW_TAG_TYPE_ATOMIC	1
38 #define POW_TAG_TYPE_NULL	2
39 #define POW_TAG_TYPE_NULL_NULL	3
40 
41 #define POW_TAG_OP_SWTAG		0
42 #define POW_TAG_OP_SWTAG_FULL		1
43 #define POW_TAG_OP_SWTAG_DESCHED	2
44 #define POW_TAG_OP_DESCHED		3
45 #define POW_TAG_OP_ADDWQ		4
46 #define POW_TAG_OP_UPD_WQP_GRP		5
47 #define POW_TAG_OP_CLR_NSCHED		7
48 #define POW_TAG_OP_NOP			15
49 
50 #define POW_WAIT	1
51 #define POW_NO_WAIT	0
52 
53 #define	POW_WORKQ_IRQ(group)		(group)
54 
55 /* XXX */
56 struct octpow_softc {
57 	device_t		sc_dev;
58 	bus_space_tag_t		sc_regt;
59 	bus_space_handle_t	sc_regh;
60 	int			sc_port;
61 	int			sc_int_pc_base;
62 };
63 
64 /* XXX */
65 struct octpow_attach_args {
66 	int			aa_port;
67 	bus_space_tag_t		aa_regt;
68 };
69 
70 void		octpow_config(struct octpow_softc *, int);
71 void		octpow_error_int_enable(void *, int);
72 uint64_t	octpow_error_int_summary(void *);
73 int		octpow_ring_reduce(void *);
74 int		octpow_ring_grow(void *);
75 int		octpow_ring_size(void);
76 int		octpow_ring_intr(void);
77 
78 #define	_POW_RD8(sc, off) \
79 	bus_space_read_8((sc)->sc_regt, (sc)->sc_regh, (off))
80 #define	_POW_WR8(sc, off, v) \
81 	bus_space_write_8((sc)->sc_regt, (sc)->sc_regh, (off), (v))
82 #define	_POW_GROUP_RD8(sc, pi, off) \
83 	bus_space_read_8((sc)->sc_regt, (sc)->sc_regh, \
84 	    (off) + sizeof(uint64_t) * (pi)->pi_group)
85 #define	_POW_GROUP_WR8(sc, pi, off, v) \
86 	bus_space_write_8((sc)->sc_regt, (sc)->sc_regh, \
87 	    (off) + sizeof(uint64_t) * (pi)->pi_group, (v))
88 
89 extern struct octpow_softc	octpow_softc;
90 
91 /* -------------------------------------------------------------------------- */
92 
93 /* Load Operations */
94 
95 /* GET_WORK Loads */
96 
97 static __inline uint64_t
octpow_ops_get_work_load(int wait)98 octpow_ops_get_work_load(
99 	int wait)			/* 0-1 */
100 {
101 	uint64_t ptr =
102 	    OCTEON_ADDR_IO_DID(POW_MAJOR_DID, POW_OP_SUBDID_GET_WORK) |
103 	    (wait ? POW_GET_WORK_LOAD_WAIT : 0);
104 
105 	return octeon_xkphys_read_8(ptr);
106 }
107 
108 /* IOBDMA Operations */
109 
110 /* ``subdid'' values are inverted between ``get_work_addr'' and ``null_read_id'' */
111 
112 /* The ``scraddr'' part is index in 8 byte words, not address. */
113 
114 /* GET_WORK IOBDMAs */
115 
116 static __inline void
octpow_ops_get_work_iobdma(int scraddr,int wait)117 octpow_ops_get_work_iobdma(
118 	int scraddr,			/* 0-2047 */
119 	int wait)			/* 0-1 */
120 {
121  	/* ``scraddr'' part is index in 64-bit words, not address */
122 	const int scrindex = scraddr / sizeof(uint64_t);
123 
124 	uint64_t value = IOBDMA_CREATE(POW_MAJOR_DID,
125 	    POW_IOBDMA_SUBDID_GET_WORK, scrindex, POW_IOBDMA_LEN,
126 	    wait ? POW_IOBDMA_GET_WORK_WAIT : 0);
127 
128         octeon_iobdma_write_8(value);
129 }
130 
131 /* NULL_RD IOBDMAs */
132 
133 static __inline void
octpow_ops_null_rd_iobdma(int scraddr)134 octpow_ops_null_rd_iobdma(
135 	int scraddr)			/* 0-2047 */
136 {
137  	/* ``scraddr'' part is index in 64-bit words, not address */
138 	const int scrindex = scraddr / sizeof(uint64_t);
139 
140 	uint64_t value = IOBDMA_CREATE(POW_MAJOR_DID,
141 	    POW_IOBDMA_SUBDID_NULL_RD, scrindex, POW_IOBDMA_LEN, 0);
142 
143         octeon_iobdma_write_8(value);
144 }
145 
146 /* Store Operations */
147 
148 static __inline void
octpow_store(int subdid,uint64_t addr,int no_sched,int index,int op,int qos,int grp,int type,uint32_t tag)149 octpow_store(
150 	int subdid,			/* 0, 1, 3 */
151 	uint64_t addr,			/* 0-0x0000.000f.ffff.ffff */
152 	int no_sched,			/* 0, 1 */
153 	int index,			/* 0-8191 */
154 	int op,				/* 0-15 */
155 	int qos,			/* 0-7 */
156 	int grp,			/* 0-7 */
157 	int type,			/* 0-7 */
158 	uint32_t tag)			/* 0-0xffff.ffff */
159 {
160 	/* Physical Address to Store to POW */
161 	uint64_t ptr = OCTEON_ADDR_IO_DID(POW_MAJOR_DID, subdid) |
162 	    __SHIFTIN(addr, POW_PHY_ADDR_STORE_ADDR);
163 
164 	/* Store Data on Store to POW */
165 	uint64_t args =
166 	    __SHIFTIN(no_sched, POW_STORE_DATA_NO_SCHED) |
167 	    __SHIFTIN(index, POW_STORE_DATA_INDEX) |
168 	    __SHIFTIN(op, POW_STORE_DATA_OP) |
169 	    __SHIFTIN(qos, POW_STORE_DATA_QOS) |
170 	    __SHIFTIN(grp, POW_STORE_DATA_GRP) |
171 	    __SHIFTIN(type, POW_STORE_DATA_TYPE) |
172 	    __SHIFTIN(tag, POW_STORE_DATA_TAG);
173 
174 	octeon_xkphys_write_8(ptr, args);
175 }
176 
177 /* SWTAG */
178 
179 static __inline void
octpow_ops_swtag(int type,uint32_t tag)180 octpow_ops_swtag(int type, uint32_t tag)
181 {
182 
183 	octpow_store(
184 		POW_STORE_SUBDID_OTHER,
185 		0, 			/* addr (not used for SWTAG) */
186 		0,			/* no_sched (not used for SWTAG) */
187 		0,			/* index (not used for SWTAG) */
188 		POW_TAG_OP_SWTAG,	/* op == SWTAG */
189 		0,			/* qos (not used for SWTAG) */
190 		0,			/* grp (not used for SWTAG) */
191 		type,
192 		tag);
193 	/* switch to NULL completes immediately */
194 }
195 
196 /* SWTAG_FULL */
197 
198 static __inline void
octpow_ops_swtag_full(paddr_t addr,int grp,int type,uint32_t tag)199 octpow_ops_swtag_full(paddr_t addr, int grp, int type, uint32_t tag)
200 {
201 
202 	octpow_store(
203 		POW_STORE_SUBDID_SWTAG_FULL,
204 		addr,
205 		0,			/* no_sched (not used for SWTAG_FULL) */
206 		0,			/* index (not used for SWTAG_FULL) */
207 		POW_TAG_OP_SWTAG_FULL,	/* op == SWTAG_FULL */
208 		0,			/* qos (not used for SWTAG_FULL) */
209 		grp,
210 		type,
211 		tag);
212 }
213 
214 /* SWTAG_DESCHED */
215 
216 static __inline void
octpow_ops_swtag_desched(int no_sched,int grp,int type,uint32_t tag)217 octpow_ops_swtag_desched(int no_sched, int grp, int type, uint32_t tag)
218 {
219 
220 	octpow_store(
221 		POW_STORE_SUBDID_DESCHED,
222 		0,			/* addr (not used for SWTAG_DESCHED) */
223 		no_sched,
224 		0,			/* index (not used for SWTAG_DESCHED) */
225 		POW_TAG_OP_SWTAG_DESCHED, /* op == SWTAG_DESCHED */
226 		0,			/* qos (not used for SWTAG_DESCHED) */
227 		grp,
228 		type,
229 		tag);
230 }
231 
232 /* DESCHED */
233 
234 static __inline void
octpow_ops_desched(int no_sched)235 octpow_ops_desched(int no_sched)
236 {
237 
238 	octpow_store(
239 		POW_STORE_SUBDID_DESCHED,
240 		0,			/* addr (not used for DESCHED) */
241 		no_sched,
242 		0,			/* index (not used for DESCHED) */
243 		POW_TAG_OP_DESCHED,	/* op == DESCHED */
244 		0,			/* qos (not used for DESCHED) */
245 		0,			/* grp (not used for DESCHED) */
246 		0,			/* type (not used for DESCHED) */
247 		0);			/* tag (not used for DESCHED) */
248 }
249 
250 /* ADDWQ */
251 
252 static __inline void
octpow_ops_addwq(paddr_t addr,int qos,int grp,int type,uint32_t tag)253 octpow_ops_addwq(paddr_t addr, int qos, int grp, int type, uint32_t tag)
254 {
255 
256 	octpow_store(
257 		POW_STORE_SUBDID_OTHER,
258 		addr,
259 		0,			/* no_sched (not used for ADDWQ) */
260 		0,			/* index (not used for ADDWQ) */
261 		POW_TAG_OP_ADDWQ,	/* op == ADDWQ */
262 		qos,
263 		grp,
264 		type,
265 		tag);
266 }
267 
268 /* UPD_WQP_GRP */
269 
270 static __inline void
octpow_ops_upd_wqp_grp(paddr_t addr,int grp)271 octpow_ops_upd_wqp_grp(paddr_t addr, int grp)
272 {
273 
274 	octpow_store(
275 		POW_STORE_SUBDID_OTHER,
276 		addr,
277 		0,			/* no_sched (not used for UPD_WQP_GRP) */
278 		0,			/* index (not used for UPD_WQP_GRP) */
279 		POW_TAG_OP_UPD_WQP_GRP,	/* op == UPD_WQP_GRP */
280 		0,			/* qos (not used for UPD_WQP_GRP) */
281 		grp,
282 		0,			/* type (not used for UPD_WQP_GRP) */
283 		0);			/* tag (not used for UPD_WQP_GRP) */
284 }
285 
286 /* CLR_NSCHED */
287 
288 static __inline void
octpow_ops_clr_nsched(paddr_t addr,int index)289 octpow_ops_clr_nsched(paddr_t addr, int index)
290 {
291 
292 	octpow_store(
293 		POW_STORE_SUBDID_OTHER,
294 		addr,
295 		0,			/* no_sched (not used for CLR_NSCHED) */
296 		index,
297 		POW_TAG_OP_CLR_NSCHED,	/* op == CLR_NSCHED */
298 		0,			/* qos (not used for CLR_NSCHED) */
299 		0,			/* grp (not used for CLR_NSCHED) */
300 		0,			/* type (not used for CLR_NSCHED) */
301 		0);			/* tag (not used for CLR_NSCHED) */
302 }
303 
304 /* NOP */
305 
306 static __inline void
octpow_ops_nop(void)307 octpow_ops_nop(void)
308 {
309 
310 	octpow_store(
311 		POW_STORE_SUBDID_OTHER,
312 		0,			/* addr (not used for NOP) */
313 		0,			/* no_sched (not used for NOP) */
314 		0,			/* index (not used for NOP) */
315 		POW_TAG_OP_NOP,		/* op == NOP */
316 		0,			/* qos (not used for NOP) */
317 		0,			/* grp (not used for NOP) */
318 		0,			/* type (not used for NOP) */
319 		0);			/* tag (not used for NOP) */
320 }
321 
322 /*
323  * Check if there is a pending POW tag switch.
324  */
325 static __inline int
octpow_tag_sw_pending(void)326 octpow_tag_sw_pending(void)
327 {
328 	int result;
329 
330 	/*
331 	 * "RDHWR rt, $30" returns:
332 	 *	0 => pending bit is set
333 	 *	1 => pending bit is clear
334 	 */
335 
336 	__asm volatile (
337 		"	.set	push\n"
338 		"	.set	noreorder\n"
339 		"	.set	arch=mips64r2\n"
340 		"	rdhwr	%0, $30\n"
341 		"	.set	pop\n"
342 		: "=r" (result));
343 	return result == 0;
344 }
345 
346 /*
347  * Wait until there is no pending POW tag switch.
348  */
349 static inline void
octpow_tag_sw_wait(void)350 octpow_tag_sw_wait(void)
351 {
352 	while (octpow_tag_sw_pending())
353 		continue;
354 }
355 
356 /* -------------------------------------------------------------------------- */
357 
358 /*
359  * global functions
360  */
361 static __inline void
octpow_work_request_async(uint64_t scraddr,uint64_t wait)362 octpow_work_request_async(uint64_t scraddr, uint64_t wait)
363 {
364 
365         octpow_ops_get_work_iobdma(scraddr, wait);
366 }
367 
368 static __inline uint64_t *
octpow_work_response_async(uint64_t scraddr)369 octpow_work_response_async(uint64_t scraddr)
370 {
371 	uint64_t result;
372 
373 	OCTEON_SYNCIOBDMA;
374 	result = octeon_cvmseg_read_8(scraddr);
375 
376 	paddr_t addr = result & POW_IOBDMA_GET_WORK_RESULT_ADDR;
377 
378 	if (result & POW_IOBDMA_GET_WORK_RESULT_NO_WORK)
379 	    return NULL;
380 #ifdef __mips_n32
381 	KASSERT(addr < MIPS_PHYS_MASK);
382 	return (uint64_t *)MIPS_PHYS_TO_KSEG0(addr);
383 #else
384 	return (uint64_t *)MIPS_PHYS_TO_XKPHYS_CACHED(addr);
385 #endif
386 }
387 
388 static __inline void
octpow_config_int_pc(struct octpow_softc * sc,int unit)389 octpow_config_int_pc(struct octpow_softc *sc, int unit)
390 {
391 	uint64_t wq_int_pc;
392 	uint64_t pc_thr;
393 	static uint64_t cpu_clock_hz;
394 
395 	if (cpu_clock_hz == 0)
396 		cpu_clock_hz  = curcpu()->ci_cpu_freq;
397 
398 	/* from SDK */
399 	pc_thr = (cpu_clock_hz) / (unit * 16 * 256);
400 
401 	wq_int_pc = __SHIFTIN(pc_thr, POW_WQ_INT_PC_PC_THR);
402 	_POW_WR8(sc, POW_WQ_INT_PC_OFFSET, wq_int_pc);
403 }
404 
405 static __inline void
octpow_config_int_pc_rate(struct octpow_softc * sc,int rate)406 octpow_config_int_pc_rate(struct octpow_softc *sc, int rate)
407 {
408 
409 	octpow_config_int_pc(sc, sc->sc_int_pc_base / rate);
410 }
411 
412 #endif /* !_OCTEON_POWVAR_H_ */
413